Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions packages/lix-sdk/src/change/schema.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -298,8 +298,8 @@ test("changes in transaction can be accessed via change view", async () => {
})
.execute();

// This should create a change in internal_change_in_transaction
// The change view should include changes from both internal_change and internal_change_in_transaction
// This should create a change in internal_transaction_state
// The change view should include changes from both internal_change and internal_transaction_state

// Try to find the change within the transaction via the change view
const changesInTransaction = await trx
Expand All @@ -309,7 +309,7 @@ test("changes in transaction can be accessed via change view", async () => {
.selectAll()
.execute();

// This should find the change that was created in internal_change_in_transaction
// This should find the change that was created in internal_transaction_state
expect(changesInTransaction).toHaveLength(1);
expect(changesInTransaction[0]).toMatchObject({
entity_id: "test_key_in_transaction",
Expand Down
21 changes: 2 additions & 19 deletions packages/lix-sdk/src/change/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,6 @@ export function applyChangeDatabaseSchema(
FOREIGN KEY(snapshot_id) REFERENCES internal_snapshot(id)
) STRICT;

-- add a table we use within the transaction
-- which is used by the state logic
-- defined here to avoid circular dependencies
CREATE TABLE IF NOT EXISTS internal_change_in_transaction (
id TEXT PRIMARY KEY DEFAULT (lix_uuid_v7()),
entity_id TEXT NOT NULL,
schema_key TEXT NOT NULL,
schema_version TEXT NOT NULL,
file_id TEXT NOT NULL,
plugin_key TEXT NOT NULL,
version_id TEXT NOT NULL,
snapshot_content BLOB,
created_at TEXT NOT NULL CHECK (created_at LIKE '%Z'),
--- NOTE schena_key must be unique per entity_id and file_id in the transaction
UNIQUE(entity_id, file_id, schema_key, version_id)
) STRICT;

CREATE VIEW IF NOT EXISTS change AS
SELECT
c.id,
Expand Down Expand Up @@ -63,8 +46,8 @@ export function applyChangeDatabaseSchema(
t.created_at,
json(t.snapshot_content) AS snapshot_content
FROM
internal_change_in_transaction AS t
WHERE t.untracked = 0;
internal_transaction_state AS t
WHERE t.lixcol_untracked = 0;

CREATE TRIGGER IF NOT EXISTS change_insert
INSTEAD OF INSERT ON change
Expand Down
4 changes: 2 additions & 2 deletions packages/lix-sdk/src/database/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import type { InternalResolvedStateAllView } from "../state/resolved-state-view.
import type { InternalStateAllUntrackedTable } from "../state/untracked/schema.js";
import type { InternalFileDataCacheTable } from "../file/cache/schema.js";
import type { InternalFileLixcolCacheTable } from "../file/cache/lixcol-schema.js";
import type { InternalChangeInTransactionTable } from "../state/transaction/schema.js";
import type { InternalTransactionStateTable } from "../state/transaction/schema.js";
import type { InternalStateVTable } from "../state/vtable/vtable.js";

export const LixDatabaseSchemaJsonColumns = {
Expand All @@ -48,7 +48,7 @@ export const LixDatabaseSchemaJsonColumns = {
} as const;

export type LixInternalDatabaseSchema = LixDatabaseSchema & {
internal_change_in_transaction: InternalChangeInTransactionTable;
internal_transaction_state: InternalTransactionStateTable;
internal_change: InternalChangeTable;
internal_snapshot: InternalSnapshotTable;
internal_state_cache: InternalStateCacheTable;
Expand Down
28 changes: 15 additions & 13 deletions packages/lix-sdk/src/deterministic/random.ts
Original file line number Diff line number Diff line change
Expand Up @@ -248,17 +248,19 @@ export function commitDeterministicRngState(args: {
} satisfies LixKeyValue);

const now = args.timestamp ?? timestamp({ lix: args.lix });
updateUntrackedState({
lix: args.lix,
change: {
entity_id: "lix_deterministic_rng_state",
schema_key: LixKeyValueSchema["x-lix-key"],
file_id: "lix",
plugin_key: "lix_own_entity",
snapshot_content: newValue,
schema_version: LixKeyValueSchema["x-lix-version"],
created_at: now,
},
version_id: "global",
});
updateUntrackedState({
lix: args.lix,
changes: [
{
entity_id: "lix_deterministic_rng_state",
schema_key: LixKeyValueSchema["x-lix-key"],
file_id: "lix",
plugin_key: "lix_own_entity",
snapshot_content: newValue,
schema_version: LixKeyValueSchema["x-lix-version"],
created_at: now,
lixcol_version_id: "global",
},
],
});
}
28 changes: 15 additions & 13 deletions packages/lix-sdk/src/deterministic/sequence.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,17 +119,19 @@ export function commitDeterministicSequenceNumber(args: {
} satisfies LixKeyValue);

const now = args.timestamp ?? timestamp({ lix: args.lix });
updateUntrackedState({
lix: args.lix,
change: {
entity_id: "lix_deterministic_sequence_number",
schema_key: LixKeyValueSchema["x-lix-key"],
file_id: "lix",
plugin_key: "lix_own_entity",
snapshot_content: newValue,
schema_version: LixKeyValueSchema["x-lix-version"],
created_at: now,
},
version_id: "global",
});
updateUntrackedState({
lix: args.lix,
changes: [
{
entity_id: "lix_deterministic_sequence_number",
schema_key: LixKeyValueSchema["x-lix-key"],
file_id: "lix",
plugin_key: "lix_own_entity",
snapshot_content: newValue,
schema_version: LixKeyValueSchema["x-lix-version"],
created_at: now,
lixcol_version_id: "global",
},
],
});
}
134 changes: 71 additions & 63 deletions packages/lix-sdk/src/lix/new-lix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,19 +218,21 @@ export async function newLixFile(args?: {
)?.entity_id;

// Set active version using updateUntrackedState for proper inheritance handling
updateUntrackedState({
lix: { sqlite, db },
change: {
entity_id: "active",
schema_key: "lix_active_version",
file_id: "lix",
plugin_key: "lix_own_entity",
snapshot_content: JSON.stringify({ version_id: initialVersionId }),
schema_version: "1.0",
created_at: created_at,
},
version_id: "global",
});
updateUntrackedState({
lix: { sqlite, db },
changes: [
{
entity_id: "active",
schema_key: "lix_active_version",
file_id: "lix",
plugin_key: "lix_own_entity",
snapshot_content: JSON.stringify({ version_id: initialVersionId }),
schema_version: "1.0",
created_at: created_at,
lixcol_version_id: "global",
},
],
});

// Create anonymous account as untracked for deterministic behavior
const activeAccountId = generateNanoid();
Expand All @@ -240,64 +242,70 @@ export async function newLixFile(args?: {
const anonymousAccountName = `Anonymous ${humanName}`;

// Create the anonymous account as untracked
updateUntrackedState({
lix: { sqlite, db },
change: {
entity_id: activeAccountId,
schema_key: LixAccountSchema["x-lix-key"],
file_id: "lix",
plugin_key: "lix_own_entity",
snapshot_content: JSON.stringify({
id: activeAccountId,
name: anonymousAccountName,
} satisfies LixAccount),
schema_version: LixAccountSchema["x-lix-version"],
created_at: created_at,
},
version_id: "global",
});
updateUntrackedState({
lix: { sqlite, db },
changes: [
{
entity_id: activeAccountId,
schema_key: LixAccountSchema["x-lix-key"],
file_id: "lix",
plugin_key: "lix_own_entity",
snapshot_content: JSON.stringify({
id: activeAccountId,
name: anonymousAccountName,
} satisfies LixAccount),
schema_version: LixAccountSchema["x-lix-version"],
created_at: created_at,
lixcol_version_id: "global",
},
],
});

// Set it as the active account
updateUntrackedState({
lix: { sqlite, db },
change: {
entity_id: `active_${activeAccountId}`,
schema_key: LixActiveAccountSchema["x-lix-key"],
file_id: "lix",
plugin_key: "lix_own_entity",
snapshot_content: JSON.stringify({
account_id: activeAccountId,
} satisfies LixActiveAccount),
schema_version: LixActiveAccountSchema["x-lix-version"],
created_at: created_at,
},
version_id: "global",
});
updateUntrackedState({
lix: { sqlite, db },
changes: [
{
entity_id: `active_${activeAccountId}`,
schema_key: LixActiveAccountSchema["x-lix-key"],
file_id: "lix",
plugin_key: "lix_own_entity",
snapshot_content: JSON.stringify({
account_id: activeAccountId,
} satisfies LixActiveAccount),
schema_version: LixActiveAccountSchema["x-lix-version"],
created_at: created_at,
lixcol_version_id: "global",
},
],
});

// Handle other untracked key values
const untrackedKeyValues = args?.keyValues?.filter(
(kv) => kv.lixcol_untracked === true
);
if (untrackedKeyValues) {
for (const kv of untrackedKeyValues) {
const versionId = kv.lixcol_version_id ?? "global";
updateUntrackedState({
lix: { sqlite, db },
change: {
entity_id: kv.key,
schema_key: "lix_key_value",
file_id: "lix",
plugin_key: "lix_own_entity",
snapshot_content: JSON.stringify({
key: kv.key,
value: kv.value,
}),
schema_version: LixKeyValueSchema["x-lix-version"],
created_at: created_at,
},
version_id: versionId,
});
}
for (const kv of untrackedKeyValues) {
const versionId = kv.lixcol_version_id ?? "global";
updateUntrackedState({
lix: { sqlite, db },
changes: [
{
entity_id: kv.key,
schema_key: "lix_key_value",
file_id: "lix",
plugin_key: "lix_own_entity",
snapshot_content: JSON.stringify({
key: kv.key,
value: kv.value,
}),
schema_version: LixKeyValueSchema["x-lix-version"],
created_at: created_at,
lixcol_version_id: versionId,
},
],
});
}
}

try {
Expand Down
4 changes: 2 additions & 2 deletions packages/lix-sdk/src/state/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ The virtual table:

- **Purpose**: Accumulate multiple mutations
- **Scope**: Multiple entities, single version
- **Storage**: Temporary (`internal_change_in_transaction`)
- **Storage**: Temporary (`internal_transaction_state`)
- **Rollback**: Automatic on error or explicit rollback

#### 3. COMMIT Stage
Expand Down Expand Up @@ -80,7 +80,7 @@ The virtual table acts as a facade over the actual storage mechanism:
┌─────────────────────────────────────────────────┐
│ Regular SQLite Tables │
│ │
│ • internal_change_in_transaction
│ • internal_transaction_state
│ • internal_state_cache │
│ • internal_change │
│ • internal_snapshot │
Expand Down
56 changes: 30 additions & 26 deletions packages/lix-sdk/src/state/cache/mark-state-cache-as-stale.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,21 @@ export function markStateCacheAsStale(args: {

const ts = args.timestamp ?? timestamp({ lix: args.lix });

updateUntrackedState({
lix: args.lix,
change: {
entity_id: CACHE_STALE_KEY,
schema_key: LixKeyValueSchema["x-lix-key"],
file_id: "lix",
plugin_key: "lix_own_entity",
snapshot_content: snapshotContent,
schema_version: LixKeyValueSchema["x-lix-version"],
created_at: ts,
},
version_id: "global",
});
updateUntrackedState({
lix: args.lix,
changes: [
{
entity_id: CACHE_STALE_KEY,
schema_key: LixKeyValueSchema["x-lix-key"],
file_id: "lix",
plugin_key: "lix_own_entity",
snapshot_content: snapshotContent,
schema_version: LixKeyValueSchema["x-lix-version"],
created_at: ts,
lixcol_version_id: "global",
},
],
});
}

export function markStateCacheAsFresh(args: {
Expand All @@ -41,17 +43,19 @@ export function markStateCacheAsFresh(args: {

const ts = args.timestamp ?? timestamp({ lix: args.lix });

updateUntrackedState({
lix: args.lix,
change: {
entity_id: CACHE_STALE_KEY,
schema_key: LixKeyValueSchema["x-lix-key"],
file_id: "lix",
plugin_key: "lix_own_entity",
snapshot_content: snapshotContent,
schema_version: LixKeyValueSchema["x-lix-version"],
created_at: ts,
},
version_id: "global",
});
updateUntrackedState({
lix: args.lix,
changes: [
{
entity_id: CACHE_STALE_KEY,
schema_key: LixKeyValueSchema["x-lix-key"],
file_id: "lix",
plugin_key: "lix_own_entity",
snapshot_content: snapshotContent,
schema_version: LixKeyValueSchema["x-lix-version"],
created_at: ts,
lixcol_version_id: "global",
},
],
});
}
Loading
Loading