CodamAIDocs
Topicdone

Hooks for nested objects and cascades

Hooks also fire for children and for objects deleted by a cascade. How they are collected, in which order they run, and when no hooks fire.

Variants
child createdchild changedchild deleted by cascadechild only unlinked (no hook)child only linked (no hook)order: operations, parents and childrenREAD hooks for expanded references

What this is about

A request often writes more than one object: a company with new employees, an invoice with its line items, a delete that takes dependent children along. Each of these objects gets its own hooks, that is the hooks of its model, with its operation.

CDMS does not run these hooks right away. During the recursion it puts each object into two queues, one for the before hooks and one for the after hooks. A queue is a list that is processed in the order the entries were added. Only when the whole tree has been walked through does CDMS process them.

Which child gets which hooks

A child in a nested write

When: child without id, the relation has CREATE

  1. 1
    CDMS
    creates the child through the system layer of its model
  2. 2
    Hook
    before and after hooks of the child model with CREATE

Result: This is the same for create, PUT and PATCH of the parent: the new child always gets CREATE.

When: child with id, the relation has UPDATE; with PATCH also every list entry with id

  1. 1
    CDMS
    transfers the sent values to the child
  2. 2
    Hook
    before and after hooks of the child model with UPDATE (for create and PUT) or PATCH (for PATCH)

Result: Which children are changed along is described in The four cases in nested writing.

When: dependent child (relation with DELETE), when the parent is deleted or because it drops out of the relation with PUT or PATCH

  1. 1
    CDMS
    checks the delete role of the child and takes it up for removal
  2. 2
    Hook
    before and after hooks of the child model with DELETE
  3. 3
    CDMS
    walks through the relations of the child in the same way, across any number of levels

Result: See Dependent objects (cascades) and Deleting by changing.

When: relation without DELETE: the child drops out of the relation or the parent is deleted

  1. 1
    CDMS→Database
    only clears the reference between the two objects
  2. 2
    Hook
    no hooks for the child

Result: The child stays. For CDMS this is not an operation on the child.

When: child with id, the relation has no UPDATE (with create, PUT and PATCH single references)

  1. 1
    CDMS
    only sets the reference to the existing child
  2. 2
    Hook
    no hooks for the child

Result: The child itself is not changed.

The queue in an example

A department has a list employees. The relation has the flags CREATE, UPDATE and DELETE. Before the request, Anna and Ben belong to the department. The client sends a PUT:

PUT with one changed, one new and one omitted employee
Request
PUT /api/rest/org/department/update/d-1
{
  "data": {
    "id": "d-1",
    "name": "Vertrieb Nord",
    "employees": [
      { "id": "e-anna", "name": "Anna Berg" },
      { "name": "Cem" }
    ]
  },
  "response": ["id"]
}
Response
200, { "data": { "id": "d-1" }, … }
flowchart TB
    D["Department d-1<br/>UPDATE"] --> A["Anna<br/>UPDATE"]
    D --> C["Cem, new<br/>CREATE"]
    D -.-> B["Ben, omitted<br/>DELETE"]

CDMS walks through the department and adds these entries to the queues:

Recursion: entries in the queues
  1. 1
    CDMS
    department: before entry UPDATE
  2. 2
    CDMS
    Ben is missing from the list and is dependent: before and after entry DELETE, Ben is marked for removal
  3. 3
    CDMS
    Anna: before entry UPDATE, transfer values, after entry UPDATE
  4. 4
    CDMS
    Cem: before entry CREATE, transfer values, after entry CREATE
  5. 5
    CDMS
    department done: after entry UPDATE

Then CDMS processes the queues, per operation in the fixed order CREATE, UPDATE, PATCH, DELETE:

StepBefore hooksAfter hooks
1 · CREATECemCem
2 · UPDATEdepartment, then AnnaAnna, then department
3 · DELETEBenBen

Validation and saving lie between the two columns, see The order within a write operation. Within one operation, the before hooks run in the order the entries were added, so the parent before its children. CDMS adds the after entries only once an object and its children are done. That is why the children run before the parent there.

The order of the operations takes precedence over the tree structure. In the example, the before hook of the new child Cem runs before the before hook of the department, because CREATE comes before UPDATE.

Cascade on delete

With DELETE there is only one operation. Here the tree alone decides the order:

flowchart TB
    F["Company<br/>before 1 · after 5"] --> A1["Department North<br/>before 2 · after 3"]
    A1 --> P1["Team N-1<br/>before 3 · after 1"]
    A1 --> P2["Team N-2<br/>before 4 · after 2"]
    F --> A2["Department South<br/>before 5 · after 4"]
    F -.-> K["Customer, only unlinked<br/>no hook"]

The before hooks run from top to bottom, the after hooks from bottom to top. So in its after hook, the parent sees that all children have already been handled.

When the before hooks run, CDMS has already finished the recursion:

  • Every dependent child has been taken out of the relation fields of its parent and marked for removal. The before hook of the company no longer finds its departments in its list. Instead, each department gets its own hook, with all its fields.
  • The roles of all objects have been checked. If the delete role is missing for one child, not a single hook runs.
  • A before hook that throws an exception prevents the deletion of the whole tree, no matter on which level it sits.

Decision table

Does a connected object get hooks?
What happens to the objectFlag on the relationHooks of the object
new, without idCREATECREATE
with id, values sentUPDATEUPDATE for create and PUT, PATCH for PATCH
with id, only linkedno UPDATEnone
drops out of the relation or parent is deletedDELETEDELETE, also for its own dependent children
drops out of the relation or parent is deletedno DELETEnone, only the reference is cleared

When reading back: READ hooks

After a create, PUT or PATCH, CDMS reads the object back with the response of the request. Every expanded reference and every entry of an expanded list is a separate read through its own model, with its own READ hook. If the response in the example also requests employees, the READ hooks of the department and of every employee run. See Expanding references and lists.

Pitfalls

Where to go next

Sources in the code and the knowledge base
  • CDMS/cdms-system-layer – AbstractLayer (recursiveCreate, setModel, recursiveUpdate, recursivePatch, recursivePrepare (_reference), reduceToTargetState, detachOrDeleteModel, detachOrDeleteMember, recursiveDelete, fetchAndSetModel, fetchAndSetList)
  • CDMS/cdms-system-layer – session/HookRequestContext (addHookBefore, addHookAfter, take, runAllBefore, runAllAfter: CREATE, UPDATE, PATCH, DELETE, ROLLBACK)
  • CDMS/cdms-system-layer – HookManagementSystem (hooks per concrete entity class)
  • CDMS/cdms-integrationtest – TestHookManagement, AbstractRecursiveDelete, AbstractRecursivePatch
  • documentation/60-erweiterung/01-hooks.md
Search