import type { Lix } from "../lix/open-lix.js"; import type { LixVersion } from "./schema-definition.js"; import { type SelectQueryBuilder } from "kysely"; export type DiffRow = { entity_id: string; schema_key: string; file_id: string; before_version_id: string | null; before_change_id: string | null; before_commit_id: string | null; after_version_id: string | null; after_change_id: string | null; after_commit_id: string | null; status: "added" | "modified" | "removed" | "unchanged"; }; /** * Compares two versions and returns differences between their entities. * * This function is modeled for merging a source version into a target version, * which is why the source always wins in conflict scenarios (when both versions * modified the same entity). It performs a full outer join between source and * target versions to identify added, modified, removed, and unchanged entities. * * Note: More sophisticated diff strategies and proper conflict handling are * planned for the future. Please upvote https://github.com/opral/lix-sdk/issues/368 * if you need conflict detection and resolution capabilities. * * The returned query builder allows for flexible filtering and composition * before executing the diff. When no target is specified, compares against * the active version. * * Diff status meanings: * - `added`: Entity exists only in source version (new addition) * - `removed`: Entity explicitly deleted in source (tombstone present) * - `modified`: Entity exists in both but with different change_ids (source wins) * - `unchanged`: Entity has same change_id in both OR exists only in target without explicit deletion * * Visual representation (source → target): * ``` * Status | Source | Target | before_version_id | after_version_id | before_* | after_* * ------------|--------|--------|-------------------|------------------|----------|---------- * added | ✓ | ✗ | null | source.id | null | source * removed | ✓* | ✓ | target.id | source.id | target | tombstone * modified | ✓ | ✓ | target.id | source.id | target | source * unchanged | ✓ | ✓ | target.id | source.id | same | same * unchanged | ✗ | ✓ | target.id | target.id | target | target * ``` * * Source ✓* indicates a tombstone (explicit deletion) * * Performance tips: * - Filter by status to exclude unchanged entities (most common) * - Filter by file_id when diffing specific documents * - Filter by schema_key when interested in specific entity types * * @example * // Get all changes between two versions * const changes = await selectVersionDiff({ lix, source, target }) * .where('diff.status', '!=', 'unchanged') * .execute(); * * @example * // Compare specific file between source and active version * const fileDiff = await selectVersionDiff({ lix, source }) * .where('diff.file_id', '=', 'file1.json') * .where('diff.status', '!=', 'unchanged') * .orderBy('diff.entity_id') * .execute(); * * @example * // Get only entities of a specific schema that were modified * const schemaDiff = await selectVersionDiff({ lix, source, target }) * .where('diff.schema_key', '=', 'message') * .where('diff.status', 'in', ['added', 'modified', 'removed']) * .execute(); * * @example * // Find entities that exist only in target (no explicit delete in source) * const targetOnly = await selectVersionDiff({ lix, source, target }) * .where('diff.status', '=', 'unchanged') * .whereRef('diff.after_version_id', '=', 'diff.before_version_id') * .execute(); * * @example * // Check if specific entities changed * const entityDiff = await selectVersionDiff({ lix, source, target }) * .where('diff.entity_id', 'in', ['entity1', 'entity2', 'entity3']) * .where('diff.status', '!=', 'unchanged') * .execute(); * * if (entityDiff.length > 0) { * // Some entities changed * } * * ## Understanding Common Ancestor Behavior * * Imagine you and a colleague both start from the same document (common ancestor): * - You create a "source" version and make changes * - Your colleague creates a "target" version and makes different changes * * When comparing these versions, the diff needs to know: * 1. What did YOU intentionally delete? (will be removed from target) * 2. What did your colleague add that you never knew about? (will be kept) * * The system tracks deletions using "tombstones" - special markers that say * "this entity was deleted". When you delete something, a tombstone is created. * * This means: * - If you deleted "entity A" that existed in the common ancestor → * Status: "deleted" (tombstone present, will be removed from target) * - If "entity B" only exists in target (added after you created your version) → * Status: "unchanged" (no tombstone, you never knew about it, so it stays) * * Without this logic, the system couldn't tell the difference between * "I deleted this" and "I never had this". */ export declare function selectVersionDiff(args: { lix: Lix; source: Pick; target?: Pick; }): SelectQueryBuilder; //# sourceMappingURL=select-version-diff.d.ts.map