-
Notifications
You must be signed in to change notification settings - Fork 7
Add audit detail change for dataclass lineage events #7032
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR adds audit detail change functionality for dataclass lineage events by refactoring parent field population logic and improving audit comparison for experimental inputs.
- Refactored parent field population methods from SampleTypeUpdateServiceDI to ExperimentServiceImpl for reuse
- Enhanced audit handling to treat parent input values as sets rather than ordered lists
- Added permission checks and lineage field population for dataclass operations
Reviewed Changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| SampleTypeUpdateServiceDI.java | Removed duplicate parent field logic and delegated to ExperimentServiceImpl |
| ExperimentServiceImpl.java | Added centralized parent field population methods and updated parent lookup signatures |
| ExpDataClassDataTableImpl.java | Added parent field population and permission checks for dataclass operations |
| ExperimentService.java | Removed deprecated parent lookup method signatures from API |
| AuditHandler.java | Enhanced audit comparison to treat parent inputs as unordered sets |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| if (isExpInput && oldValue != null && newValue != null) | ||
| { | ||
| // For parent inputs, the order of the values does not matter, so compare as sets | ||
| Set<String> oldSet = new HashSet<>(Arrays.asList(oldValue.toString().split(","))); | ||
| Set<String> newSet = new HashSet<>(Arrays.asList(newValue.toString().split(","))); | ||
| if (oldSet.equals(newSet) && !isExtraAuditField) | ||
| continue; | ||
| } |
Copilot
AI
Sep 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The split operation on comma-separated values doesn't handle quoted values correctly. Names containing commas are quoted (as seen in line 2555-2556 of ExperimentServiceImpl.java), but this split will break quoted entries. Consider using a CSV parser or the same quoting logic used when creating the values.
| Map<String, String> importAliases = _dataClass.getImportAliases(); | ||
| for (String col : columns) | ||
| { | ||
| if (ExperimentService.isInputOutputColumn(col) || Strings.CI.equals("parent",col) || importAliases.containsKey(col)) |
Copilot
AI
Sep 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The method call Strings.CI.equals("parent",col) has the parameters in an unusual order. Typically the expected value comes first: Strings.CI.equals(col, "parent"). This current order could be confusing and inconsistent with common patterns.
| if (ExperimentService.isInputOutputColumn(col) || Strings.CI.equals("parent",col) || importAliases.containsKey(col)) | |
| if (ExperimentService.isInputOutputColumn(col) || Strings.CI.equals(col, "parent") || importAliases.containsKey(col)) |
| List<Map<String, Object>> result = new ArrayList<>(keys.size()); | ||
| for (Map<String, Object> row : keys) | ||
| { | ||
| Map<String, Object> materialMap = getDataMap(row, user, container, true,false); |
Copilot
AI
Sep 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The boolean parameters true,false are unclear without parameter names. Consider using named parameters or constants to make the intent clear, especially since this pattern appears to indicate allowCrossContainer=true, addInputs=false.
| } | ||
| else | ||
| { | ||
| if (isExpInput && oldValue != null && newValue != null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isExpInput related logic does not seem appropriate for the AuditHandler interface. Is there a way that this can be registered as a part of a current or new audit handler that is only invoked for the necessary tables?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. This has been brought up a few times but hasn't been done due to difficulty. I added a TODO comment as a reminder.
| } | ||
|
|
||
| protected Map<String, Object> _select(Container container, Long rowId, String lsid, String name, Long classId, boolean allowCrossContainer) throws SQLException | ||
| protected Map<String, Object> getDataMap(Map<String, Object> keys, User user, Container container, boolean allowCrossContainer, boolean addInputs) throws SQLException |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Annotate as @Nullable
| throw new InvalidKeyException("Value must be supplied for key field 'rowid' or 'lsid' or 'name'", keys); | ||
|
|
||
| return _select(container, rowId, lsid, name, classId, allowCrossContainer); | ||
| return getDataMap(keys, user, container, allowCrossContainer, true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
classId no longer needs to be computed since it is not being handed through.
|
|
||
| public void addRowsParentsFields(Set<Identifiable> seeds, Map<Integer, Map<String, Object>> dataRows, User user, Container container) | ||
| { | ||
| Map<String, Pair<Set<ExpMaterial>, Set<ExpData>>> parents = ExperimentServiceImpl.get().getParentMaterialAndDataMap(container, user, new HashSet<>(seeds)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why new up a HashSet here?
Rationale
Allowing sources to have parents in Apps is a relatively new feature, compared with sample's parent. Sample lineage change details are needed for Timeline display, and that's backed by audit event's old/new record map. Sources, however, lacked such detailed audit. A recent refactor of audit added source lineage audit for some scenarios. This PR ensures all insert/update/delete of sources' lineage have proper audit details.
Related Pull Requests
Changes