import { IIdentityMap } from './interfaces.js'; import type { ModelBase } from './model.js'; import { Subject, SubjectSet } from './subject.js'; /** * Turns a mutated object graph into a `SubjectSet` — the complete, unordered description of * what one `save()` must do. * * Traversal rules: * * - a `belongsTo` is followed whenever its `Value` is set, populated or not, because * attaching a model to it is an explicit act; * - a `hasMany` or `manyToMany` is followed **only when `Populated` is true**, so a relation * the caller never loaded is invisible and `Items: OrderItem[] = []` on a freshly * constructed model deletes nothing; * - `Query` and `Virtual` relations are read-only projections and are never followed. */ export declare class SubjectBuilder { protected identityMap: IIdentityMap; private _visited; constructor(identityMap: IIdentityMap); build(root: ModelBase): SubjectSet; /** * Walks the graph breadth-first from `root`, canonicalizing every model through the * identity map so a row reached by two paths yields one instance. * * @param root - the model `save()` was called on */ collect(root: ModelBase): ModelBase[]; /** * Models directly reachable from `model` under the traversal rules. */ protected relatedOf(model: ModelBase): ModelBase[]; /** * Diffs each collected model against its snapshot and records its `belongsTo` foreign keys. * hasMany, manyToMany and orphan handling are layered on by later passes. * * @param models - output of `collect()` */ buildFrom(models: ModelBase[]): SubjectSet; /** * Records, for every `belongsTo` with a `Value`, that this subject's foreign-key column * takes the target's join-column value — `Relation.PrimaryKey`, the target's own primary key * unless `@BelongsTo` names another column. The value is *not* read here — the target may not * have been inserted yet; the executor resolves it immediately before the statement. */ protected buildBelongsTo(subject: Subject): void; /** * Diffs each populated `hasMany` on `subject` against the owner's relation snapshot and * records the owner's foreign key as pending on every member that stays. * * A relation with `Populated === false` is skipped entirely — that is the anti-footgun * guarantee, and it is why a freshly constructed model with `Items: OrderItem[] = []` * deletes nothing. * * Both new *and* kept members get the pending foreign key. That is what makes re-parenting * work: a clean child moved to another owner has its key rewritten and is promoted from a * no-op to an UPDATE, instead of keeping its old owner id in the database ( B20 ). */ protected buildHasMany(subject: Subject, set: SubjectSet): void; /** * Diffs each populated `manyToMany` against the owner's relation snapshot into junction * rows to create and destroy. * * Only the *junction* row is created or destroyed. A target that is new gets its own insert * subject from `collect()` so its key exists before the junction row references it; a target * that is merely unlinked is left completely alone — removing a tag from an order must * never delete the tag. */ protected buildManyToMany(subject: Subject, set: SubjectSet): void; /** * Turns every `hasMany` removal recorded during the diff into an orphan action. * * Runs once over the whole set rather than per relation, because the decision needs global * information: a child removed from one owner and pushed onto another is a re-parent, not * an orphan, and only a set-wide view can tell the two apart. Every key that has a live * subject of the same target model in this graph is therefore subtracted. */ protected buildOrphans(set: SubjectSet): void; } //# sourceMappingURL=subject-builder.d.ts.map