Skip to content

spec: resolves - fill a relation from a register valid on a date - #15

Open
delchev wants to merge 1 commit into
mainfrom
spec/register-lookup
Open

spec: resolves - fill a relation from a register valid on a date#15
delchev wants to merge 1 commit into
mainfrom
spec/register-lookup

Conversation

@delchev

@delchev delchev commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

The gap

A very common enterprise shape has no declarative form in the format today: resolve a relation by consulting a register with a validity period. The register rows say "X applied to Y from A to B"; an incoming record carries the match key(s) and a date, and a to-one must be set from the row whose period covers that date.

The same pattern under many names:

  • a fine carries a vehicle and a violation date; the driver comes from a vehicle-assignment register;
  • a price comes from the price list valid on the order date;
  • a rate from the contract in force on the booking date;
  • an approver from an org assignment on the request date.

Nothing reaches it: dependsOn is an authoring-time copy matched by equality, a decision condition is a single comparison, and a setField step writes a constant. Every application hand-writes the same code — query the register, apply the between-dates predicate, classify the result.

What this adds

A resolves section in the declarative-glue chapter of 1.2:

resolves:
  - name: identifyDriver
    event: { onCreate: Fine }
    set: driver
    from: VehicleAssignment
    match: { vehicle: vehicle }
    between: { start: validFrom, end: validTo, value: violationAt }
    outcome: resolution
    found:     { setStatus: IDENTIFIED }
    notFound:  { setStatus: UNRESOLVED }
    ambiguous: { setStatus: UNRESOLVED }

The normative content is deliberately about the two properties that make this a construct rather than a query helper:

  1. All three outcomes are distinguished. Exactly one covering row fills the relation; no covering row and more than one covering row both leave it unset, and a conforming generator MUST NOT choose between candidate rows. An automation that silently picks one of two candidates is worse than none.
  2. The attempt is observable. outcome: stamps found / notFound / ambiguous into a string field, so the unresolved records form a worklist a person can finish and a process decision can branch on the result.

Plus the constraints that keep it unambiguous: the register MUST carry exactly one to-one relation to the entity set points at (that relation is the copied value — zero or two is a modelling ambiguity, not something to guess); a record that already carries the relation MUST be skipped, so a manual correction is never overwritten; and the relation, outcome and status MUST be written as one targeted update leaving every other column alone. Period bounds may be open on either side, the end is inclusive, and a date-only bound covers its whole day.

Also updates the 1.2 change list, the construct index and the README version row.

Implemented in Eclipse Dirigible (eclipse-dirigible/dirigible#6712, PR eclipse-dirigible/dirigible#6732) — the implementation and this text were written together.

A register says "X applied to Y from A to B" - a vehicle assignment, a price
list, a contract in force, an org assignment - and a record carries the match
key(s) and a date. Setting the to-one from the row whose period covers that date
had no declarative form: dependsOn is an authoring-time copy matched by
equality, a decision condition is a single comparison, and a setField step
writes a constant, so every application hand-writes the same
query-and-classify code.

The section specifies the shape and, normatively, the two properties that make
it worth having as a construct rather than a query helper:

- all three outcomes are distinguished - exactly one covering row fills the
  relation, while none and more-than-one both leave it unset, and a conforming
  generator MUST NOT choose between candidate rows;
- the attempt is observable - `outcome:` stamps found/notFound/ambiguous into a
  string field, so the unresolved records form a worklist a person can finish
  and a decision can branch on.

Plus the constraints that keep it unambiguous: the register must carry exactly
one to-one to the target, an already-filled relation is skipped, and the write
is targeted to the resolved column, the outcome and the status.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant