Triggers: support managing columns for data iteration#7541
Triggers: support managing columns for data iteration#7541labkey-nicka merged 23 commits intodevelopfrom
Conversation
labkey-matthewb
left a comment
There was a problem hiding this comment.
Considerations for additional features (do we want to do now or never)?
- Support different managed columns for insert/update
- Support in JavaScript triggers
1d28e80 to
3e9e24f
Compare
Implemented both of these. |
7096977 to
5ff3f06
Compare
61286bc to
3e70d27
Compare
labkey-matthewb
left a comment
There was a problem hiding this comment.
I like the error checking, and merging in the values for the managed columns early is an interesting idea that probably greatly reduces the chance of losing data.
labkey-matthewb
left a comment
There was a problem hiding this comment.
One small suggestion. I like the strict error checking.
3e70d27 to
faf395c
Compare
|
@labkey-nicka: Got it thank you. And that explains this failure (https://teamcity.labkey.org/buildConfiguration/bt310/3924189). Is the structure of what manageColumns() returns defined anywhere? Merging the examples on this thread, one could imagine: That implies that some of the time time a list of columns is scoped to one operation (e.g., update) and some of the time it's global (e.g., ignored). I assume 'insert', 'delete', and possibly 'merge' will also be supported? As a dev, I bet the columns for 'insert' and 'update' will overlap with one another a lot. I suppose one could do the following, but it might be worth considering if there should be a 'global' or 'all' property (if you havent already): |
It is defined in code but not yet documented. I was waiting for this feature to be merged before adding documentation (likely here). That said, you did determine the structure. /**
* Declares the columns this script intends to manage for insert, merge, and update operations.
* * The server invokes this function to validate the integrity of row objects manipulated
* by `beforeInsert` and `beforeUpdate`. Because the server needs to know which columns
* are being modified before executing the operation, manipulating unmanaged columns
* could lead to data loss. If a managed column is not present in the row object, the server
* will throw an error.
* * If this returns `false`, managed columns are disabled for this script, and the server
* will not attempt to validate row integrity after the trigger has run.
* * If it returns an object, it can include any of the following optional properties:
* - `insert`: Array of column/property names managed during inserts and merges.
* - `update`: Array of column/property names managed during updates.
* - `ignored`: Array of column/property names explicitly excluded from validation.
* * @returns {{insert?: string[], update?: string[], ignored?: string[]} | false}
*/
function managedColumns() {
return {
insert: ['columnA'],
update: ['columnB'],
ignored: ['myFlag'],
};
}
Yes,
Managed columns does not affect delete operations. Merge is intended to be supported by way of calling
I don't have plans to make any further changes to the JS interface at the moment. In Java there are utilities for these kinds of things (e.g., |
- no longer process non-data iterator pathway for managed columns
846c2c9 to
8625910
Compare
| if (insertOption != null && insertOption.mergeRows && existingRecord == null) | ||
| throw new IllegalArgumentException("An existing record must be supplied for all MERGE triggers"); | ||
|
|
||
| setManagedColumns(newRow, null, TableInfo.TriggerType.INSERT); |
There was a problem hiding this comment.
Should pass through existingRecord?
| if (managedColumns == null) | ||
| continue; | ||
|
|
||
| if (insertOption.updateOnly) |
There was a problem hiding this comment.
Probably worth adding a comment about why this is correct/consistent
Rationale
When query triggers are called within data iterators they are allowed to manipulate the data of the row that is being procured. However, if a trigger modifies the columns (i.e., the keys of the row map) it can result in data being mismanaged due to the columns in the row not aligning with what the data iterator specified.
This introduces the notion of "managed" columns to triggers. Triggers can, at the outset, declare which columns they are going to manage. Any managed columns are then picked up by the data iterator during initialization to ensure they are persisted correctly. To enforce this management more strictly, and to avoid mismanagement of null values, triggers are required to fulfill all managed column values by either clearing the value or setting the value. After the trigger has fired the resulting row will be validated and checked. The result is consistent enforcement and acknowledgement of triggers that manipulate the shape of the data.
Related Pull Requests
Changes
TableInfo.getTriggerManagedColumns()to allow for data iterator to gather all managed columnssetInsertManagedColumns()andsetUpdateManagedColumns())Tasks
Manual Testing notes (in progress)