proposit-core
    Preparing search index...

    Function orderChangeset

    • Converts a changeset into a flat, ordered array of persistence operations that is safe to execute sequentially against a relational store with foreign-key constraints.

      The FK dependency chain is:

      • expression.premiseId → premise.id
      • expression.variableId → variable.id (for variable-type expressions)
      • expression.parentId → expression.id (self-FK for tree structure)
      • variable.boundPremiseId → premise.id (for premise-bound variables)
      • variable.argumentId → argument.id
      • premise.argumentId → argument.id

      The resulting order guarantees that every referenced row exists before any row that depends on it is inserted, and that every dependent row is removed before the row it references is deleted.

      It does so without knowing what the store holds. A removed expression's entry carries its parent at removal time, and a change in the same changeset may have moved it first, so the stored row can still point at a different parent. Every removed expression is therefore detached before any expression is deleted, by an update that carries only its id, parentId: null and position POSITION_INITIAL. Two conditions follow for the store:

      • Write only the fields an update carries. A detach is not a whole row; the rest of the removed entry may be stale, and can name a variable this changeset has not inserted yet.
      • Until the deletes run, a premise can briefly have more than one root, so a rule allowing one root per premise must be checked at the end of the transaction, not per statement.

      An expression updated to point at a parent, a variable or a premise that the same changeset inserts is moved to the root in phase 2 and updated in full after the inserts. In phase 2, one late only for its new parent is written whole with the parent cleared, since its variable and premise are not new ones, so it leaves its old variable before that can be deleted. One that names a new variable or premise can only be detached (id, parentId, position), so the variable and premise deletes (phases 4 and 5) wait until after its full update: the stored row still names its old variable and premise, which may be among them, and a store whose keys cascade would otherwise delete the row.

      Variable updates run between the variable and premise deletes, so a rebound variable leaves its old premise before that premise is deleted, and a rename can take a symbol a removed variable frees. One bound to a premise the same changeset inserts runs after that insert instead, and the premise deletes wait for it. A changeset with no variable update and no expression update that needs an insert first keeps its previous order exactly: the phase list below with every step for those two left out.

      Known exceptions, only when deletes wait, for a store that checks the rule per statement. The inserts then run while the removed rows still exist, so:

      • a variable inserted with the symbol of one being removed breaks a rule that symbols are unique per argument, and so does one inserted with the symbol a variable is being renamed off (both only when the variable deletes wait, for an expression update: the renames then run after the inserts);
      • a premise inserted as the conclusion while the removed conclusion premise still exists breaks a rule of one conclusion per argument.

      Ordering phases:

      1. Update premises — ensure premise rows have correct metadata before dependent deletes run.
      2. Reparent expressions — update expressions whose IDs are NOT in the removed set. This detaches reparented children from doomed parents before ON DELETE CASCADE runs. Expressions that appear in both modified and removed are skipped (the row is about to be deleted). Then detach every removed expression (see above), so no stored row points at an expression about to be deleted. A detach carries only id, parentId and position. An update that needs an insert first is written early here too (see above).
      3. Delete expressions — expression rows hold FKs to variables and premises, so they must be removed first. Every one is detached by now, so their order does not matter; children still come before parents.
      4. Delete variables — safe after expression deletes (no remaining FK references from expressions). Then update variables, except one bound to a new premise; one that is also removed is skipped, as an expression is in phase 2. Held until after phase 8 when an expression update names a new variable or premise (see above).
      5. Delete premises — safe after all child rows are removed. Held with phase 4, or until after phase 6 for a variable bound to a new premise.
      6. Insert premises — new premises must exist before their expressions and variables can be inserted. Then update the variables bound to them, and delete premises if phase 5 waited for those.
      7. Insert variables — new variables must exist before variable-type expressions can reference them.
      8. Insert expressions — topologically sorted so parent expressions are inserted before their children (satisfies the parentId self-FK). Then the updates held back in phase 2, then phases 4 and 5 if held.
      9. (No-op — variable updates are emitted with phase 4 or 6, or after phase 8 when the deletes are held.)
      10. (No-op — expression updates are emitted in phase 2 or after phase 8.)
      11. Update argument metadata — if present.
      12. Update role state — if present.

      Type Parameters

      • TExpr extends TCorePropositionalExpression = TCorePropositionalExpression
      • TVar extends
            | {
                argumentId: string;
                argumentVersion: number;
                checksum: string;
                claimId: string;
                claimVersion: number;
                id: string;
                symbol: string;
            }
            | {
                argumentId: string;
                argumentVersion: number;
                boundArgumentId: string;
                boundArgumentVersion: number;
                boundPremiseId: string;
                checksum: string;
                id: string;
                symbol: string;
            }
            | {
                argumentId: string;
                argumentVersion: number;
                boundArgumentId: string;
                boundArgumentVersion: number;
                boundAspect: "statement"
                | "inference";
                boundExpressionId: string;
                checksum: string;
                id: string;
                symbol: string;
            } =
            | {
                argumentId: string;
                argumentVersion: number;
                checksum: string;
                claimId: string;
                claimVersion: number;
                id: string;
                symbol: string;
            }
            | {
                argumentId: string;
                argumentVersion: number;
                boundArgumentId: string;
                boundArgumentVersion: number;
                boundPremiseId: string;
                checksum: string;
                id: string;
                symbol: string;
            }
            | {
                argumentId: string;
                argumentVersion: number;
                boundArgumentId: string;
                boundArgumentVersion: number;
                boundAspect: "statement"
                | "inference";
                boundExpressionId: string;
                checksum: string;
                id: string;
                symbol: string;
            }
      • TPremise extends
            | {
                argumentId: string;
                argumentVersion: number;
                checksum: string;
                combinedChecksum: string;
                descendantChecksum: string
                | null;
                id: string;
                type: "freeform";
            }
            | {
                argumentId: string;
                argumentVersion: number;
                checksum: string;
                combinedChecksum: string;
                derivedClaimId: string;
                descendantChecksum: string
                | null;
                id: string;
                type: "derivation";
            } =
            | {
                argumentId: string;
                argumentVersion: number;
                checksum: string;
                combinedChecksum: string;
                descendantChecksum: string
                | null;
                id: string;
                type: "freeform";
            }
            | {
                argumentId: string;
                argumentVersion: number;
                checksum: string;
                combinedChecksum: string;
                derivedClaimId: string;
                descendantChecksum: string
                | null;
                id: string;
                type: "derivation";
            }
      • TArg extends {
            checksum: string;
            combinedChecksum: string;
            descendantChecksum: string | null;
            id: string;
            respondsTo?: { argumentId: string; argumentVersion: number };
            version: number;
        } = {
            checksum: string;
            combinedChecksum: string;
            descendantChecksum: string | null;
            id: string;
            respondsTo?: { argumentId: string; argumentVersion: number };
            version: number;
        }

      Parameters

      Returns TOrderedOperation<TExpr, TVar, TPremise, TArg>[]

      A flat array of TOrderedOperation entries in FK-safe execution order. Returns an empty array if the changeset is empty.