logo
  • Docs
  • API Reference
    Overview
    Functions
    acceptChangeProposal
    applyChangeSet
    attachConversation
    attachLabel
    commitIsAncestorOf
    commitIsDescendantOf
    createAccount
    createChangeProposal
    createChangeSet
    createCheckpoint
    createConversation
    createConversationMessage
    createHooks
    createLabel
    createLog
    createLspInMemoryEnvironment
    createQuerySync
    createServerProtocolHandler
    createVersion
    createVersionFromCommit
    detachConversation
    detachLabel
    ebEntity
    getTimestamp
    humanId
    mergeVersion
    nanoId
    newLixFile
    nextSequenceNumber
    normalizeDirectoryPath
    normalizeFilePath
    normalizePathSegment
    openLix
    random
    rejectChangeProposal
    selectCommitDiff
    selectVersionDiff
    selectWorkingDiff
    switchAccount
    switchVersion
    transition
    uuidV7
    uuidV7Sync
    validateLixSchema
    validateLixSchemaDefinition
    withWriterKey
    Type Aliases
    Account
    ActiveAccount
    Change
    ChangeAuthor
    DetectedChange
    EntityStateByVersionView
    EntityStateHistoryView
    EntityStateView
    EnvironmentActorHandle
    FromLixSchemaDefinition
    JSONType
    Lix
    LixActiveVersion
    LixChangeProposal
    LixChangeSet
    LixChangeSetElement
    LixCommit
    LixCommitEdge
    LixConversation
    LixConversationMessage
    LixDatabaseSchema
    LixDirectoryDescriptor
    LixEntity
    LixEntityCanonical
    LixEntityConversation
    LixEntityLabel
    LixFile
    LixFileDescriptor
    LixGenerated
    LixHooks
    LixInsertable
    LixKeyValue
    LixLabel
    LixLog
    LixPlugin
    LixSchemaDefinition
    LixSelectable
    LixServerProtocolHandlerContext
    LixUpdateable
    LixVersion
    LixVersionDescriptor
    LixVersionTip
    NewChange
    NewState
    NewStateByVersion
    NewStateByVersionRow
    NewStateRow
    QuerySync
    RenderDiffArgs
    SpawnActorOptions
    State
    StateByVersion
    StateByVersionRow
    StateByVersionRowUpdate
    StateByVersionUpdate
    StateByVersionView
    StateCommitChange
    StateHistory
    StateRow
    StateRowUpdate
    StateUpdate
    StateView
    StateWithTombstonesRow
    StateWithTombstonesView
    StoredSchema
    ToKysely
    Variables
    JSONTypeSchema
    LixAccountSchema
    LixActiveAccountSchema
    LixActiveVersionSchema
    LixChangeAuthorSchema
    LixChangeProposalSchema
    LixChangeSetElementSchema
    LixChangeSetSchema
    LixCommitEdgeSchema
    LixCommitSchema
    LixConversationMessageSchema
    LixConversationSchema
    LixDirectoryDescriptorSchema
    LixFileDescriptorSchema
    LixKeyValueSchema
    LixLabelSchema
    LixLogSchema
    LixSchemaDefinition
    LixStoredSchemaSchema
    LixVersionDescriptorSchema
    LixVersionTipSchema
    mockJsonPlugin
    Classes
    InMemoryEnvironment
    LixObservable
    OpfsSahEnvironment
    Interfaces
    LixEnvironment
    Previous pageselectCommitDiffNext pageselectWorkingDiff

    #Function: selectVersionDiff()

    selectVersionDiff(args: { lix: Lix; source: Pick<LixVersion, "id">; target?: Pick<LixVersion, "id">; }): SelectQueryBuilder<any, "diff", DiffRow>

    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

    #Examples

    // Get all changes between two versions
    const changes = await selectVersionDiff({ lix, source, target })
      .where('diff.status', '!=', 'unchanged')
      .execute();
    // 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();
    // 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();
    // 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();
    // 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".

    #Parameters

    ParameterType
    args{ lix: Lix; source: Pick<LixVersion, "id">; target?: Pick<LixVersion, "id">; }
    args.lixLix
    args.sourcePick<LixVersion, "id">
    args.target?Pick<LixVersion, "id">

    #Returns

    SelectQueryBuilder<any, "diff", DiffRow>