Skip to content

Commit 06948ba

Browse files
Merge pull request #3685 from opral/lixdk-458-make-working-commit-lazy
Lixdk-458-make-working-commit-lazy
2 parents b5101a3 + 8c9493c commit 06948ba

22 files changed

+787
-621
lines changed

packages/lix-sdk/src/change/schema.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -298,8 +298,8 @@ test("changes in transaction can be accessed via change view", async () => {
298298
})
299299
.execute();
300300

301-
// This should create a change in internal_change_in_transaction
302-
// The change view should include changes from both internal_change and internal_change_in_transaction
301+
// This should create a change in internal_transaction_state
302+
// The change view should include changes from both internal_change and internal_transaction_state
303303

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

312-
// This should find the change that was created in internal_change_in_transaction
312+
// This should find the change that was created in internal_transaction_state
313313
expect(changesInTransaction).toHaveLength(1);
314314
expect(changesInTransaction[0]).toMatchObject({
315315
entity_id: "test_key_in_transaction",

packages/lix-sdk/src/change/schema.ts

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,6 @@ export function applyChangeDatabaseSchema(
1919
FOREIGN KEY(snapshot_id) REFERENCES internal_snapshot(id)
2020
) STRICT;
2121
22-
-- add a table we use within the transaction
23-
-- which is used by the state logic
24-
-- defined here to avoid circular dependencies
25-
CREATE TABLE IF NOT EXISTS internal_change_in_transaction (
26-
id TEXT PRIMARY KEY DEFAULT (lix_uuid_v7()),
27-
entity_id TEXT NOT NULL,
28-
schema_key TEXT NOT NULL,
29-
schema_version TEXT NOT NULL,
30-
file_id TEXT NOT NULL,
31-
plugin_key TEXT NOT NULL,
32-
version_id TEXT NOT NULL,
33-
snapshot_content BLOB,
34-
created_at TEXT NOT NULL CHECK (created_at LIKE '%Z'),
35-
--- NOTE schena_key must be unique per entity_id and file_id in the transaction
36-
UNIQUE(entity_id, file_id, schema_key, version_id)
37-
) STRICT;
38-
3922
CREATE VIEW IF NOT EXISTS change AS
4023
SELECT
4124
c.id,
@@ -63,8 +46,8 @@ export function applyChangeDatabaseSchema(
6346
t.created_at,
6447
json(t.snapshot_content) AS snapshot_content
6548
FROM
66-
internal_change_in_transaction AS t
67-
WHERE t.untracked = 0;
49+
internal_transaction_state AS t
50+
WHERE t.lixcol_untracked = 0;
6851
6952
CREATE TRIGGER IF NOT EXISTS change_insert
7053
INSTEAD OF INSERT ON change

packages/lix-sdk/src/database/schema.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ import type { InternalResolvedStateAllView } from "../state/resolved-state-view.
3939
import type { InternalStateAllUntrackedTable } from "../state/untracked/schema.js";
4040
import type { InternalFileDataCacheTable } from "../file/cache/schema.js";
4141
import type { InternalFileLixcolCacheTable } from "../file/cache/lixcol-schema.js";
42-
import type { InternalChangeInTransactionTable } from "../state/transaction/schema.js";
42+
import type { InternalTransactionStateTable } from "../state/transaction/schema.js";
4343
import type { InternalStateVTable } from "../state/vtable/vtable.js";
4444

4545
export const LixDatabaseSchemaJsonColumns = {
@@ -48,7 +48,7 @@ export const LixDatabaseSchemaJsonColumns = {
4848
} as const;
4949

5050
export type LixInternalDatabaseSchema = LixDatabaseSchema & {
51-
internal_change_in_transaction: InternalChangeInTransactionTable;
51+
internal_transaction_state: InternalTransactionStateTable;
5252
internal_change: InternalChangeTable;
5353
internal_snapshot: InternalSnapshotTable;
5454
internal_state_cache: InternalStateCacheTable;

packages/lix-sdk/src/deterministic/random.ts

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -248,17 +248,19 @@ export function commitDeterministicRngState(args: {
248248
} satisfies LixKeyValue);
249249

250250
const now = args.timestamp ?? timestamp({ lix: args.lix });
251-
updateUntrackedState({
252-
lix: args.lix,
253-
change: {
254-
entity_id: "lix_deterministic_rng_state",
255-
schema_key: LixKeyValueSchema["x-lix-key"],
256-
file_id: "lix",
257-
plugin_key: "lix_own_entity",
258-
snapshot_content: newValue,
259-
schema_version: LixKeyValueSchema["x-lix-version"],
260-
created_at: now,
261-
},
262-
version_id: "global",
263-
});
251+
updateUntrackedState({
252+
lix: args.lix,
253+
changes: [
254+
{
255+
entity_id: "lix_deterministic_rng_state",
256+
schema_key: LixKeyValueSchema["x-lix-key"],
257+
file_id: "lix",
258+
plugin_key: "lix_own_entity",
259+
snapshot_content: newValue,
260+
schema_version: LixKeyValueSchema["x-lix-version"],
261+
created_at: now,
262+
lixcol_version_id: "global",
263+
},
264+
],
265+
});
264266
}

packages/lix-sdk/src/deterministic/sequence.ts

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -119,17 +119,19 @@ export function commitDeterministicSequenceNumber(args: {
119119
} satisfies LixKeyValue);
120120

121121
const now = args.timestamp ?? timestamp({ lix: args.lix });
122-
updateUntrackedState({
123-
lix: args.lix,
124-
change: {
125-
entity_id: "lix_deterministic_sequence_number",
126-
schema_key: LixKeyValueSchema["x-lix-key"],
127-
file_id: "lix",
128-
plugin_key: "lix_own_entity",
129-
snapshot_content: newValue,
130-
schema_version: LixKeyValueSchema["x-lix-version"],
131-
created_at: now,
132-
},
133-
version_id: "global",
134-
});
122+
updateUntrackedState({
123+
lix: args.lix,
124+
changes: [
125+
{
126+
entity_id: "lix_deterministic_sequence_number",
127+
schema_key: LixKeyValueSchema["x-lix-key"],
128+
file_id: "lix",
129+
plugin_key: "lix_own_entity",
130+
snapshot_content: newValue,
131+
schema_version: LixKeyValueSchema["x-lix-version"],
132+
created_at: now,
133+
lixcol_version_id: "global",
134+
},
135+
],
136+
});
135137
}

packages/lix-sdk/src/lix/new-lix.ts

Lines changed: 71 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -218,19 +218,21 @@ export async function newLixFile(args?: {
218218
)?.entity_id;
219219

220220
// Set active version using updateUntrackedState for proper inheritance handling
221-
updateUntrackedState({
222-
lix: { sqlite, db },
223-
change: {
224-
entity_id: "active",
225-
schema_key: "lix_active_version",
226-
file_id: "lix",
227-
plugin_key: "lix_own_entity",
228-
snapshot_content: JSON.stringify({ version_id: initialVersionId }),
229-
schema_version: "1.0",
230-
created_at: created_at,
231-
},
232-
version_id: "global",
233-
});
221+
updateUntrackedState({
222+
lix: { sqlite, db },
223+
changes: [
224+
{
225+
entity_id: "active",
226+
schema_key: "lix_active_version",
227+
file_id: "lix",
228+
plugin_key: "lix_own_entity",
229+
snapshot_content: JSON.stringify({ version_id: initialVersionId }),
230+
schema_version: "1.0",
231+
created_at: created_at,
232+
lixcol_version_id: "global",
233+
},
234+
],
235+
});
234236

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

242244
// Create the anonymous account as untracked
243-
updateUntrackedState({
244-
lix: { sqlite, db },
245-
change: {
246-
entity_id: activeAccountId,
247-
schema_key: LixAccountSchema["x-lix-key"],
248-
file_id: "lix",
249-
plugin_key: "lix_own_entity",
250-
snapshot_content: JSON.stringify({
251-
id: activeAccountId,
252-
name: anonymousAccountName,
253-
} satisfies LixAccount),
254-
schema_version: LixAccountSchema["x-lix-version"],
255-
created_at: created_at,
256-
},
257-
version_id: "global",
258-
});
245+
updateUntrackedState({
246+
lix: { sqlite, db },
247+
changes: [
248+
{
249+
entity_id: activeAccountId,
250+
schema_key: LixAccountSchema["x-lix-key"],
251+
file_id: "lix",
252+
plugin_key: "lix_own_entity",
253+
snapshot_content: JSON.stringify({
254+
id: activeAccountId,
255+
name: anonymousAccountName,
256+
} satisfies LixAccount),
257+
schema_version: LixAccountSchema["x-lix-version"],
258+
created_at: created_at,
259+
lixcol_version_id: "global",
260+
},
261+
],
262+
});
259263

260264
// Set it as the active account
261-
updateUntrackedState({
262-
lix: { sqlite, db },
263-
change: {
264-
entity_id: `active_${activeAccountId}`,
265-
schema_key: LixActiveAccountSchema["x-lix-key"],
266-
file_id: "lix",
267-
plugin_key: "lix_own_entity",
268-
snapshot_content: JSON.stringify({
269-
account_id: activeAccountId,
270-
} satisfies LixActiveAccount),
271-
schema_version: LixActiveAccountSchema["x-lix-version"],
272-
created_at: created_at,
273-
},
274-
version_id: "global",
275-
});
265+
updateUntrackedState({
266+
lix: { sqlite, db },
267+
changes: [
268+
{
269+
entity_id: `active_${activeAccountId}`,
270+
schema_key: LixActiveAccountSchema["x-lix-key"],
271+
file_id: "lix",
272+
plugin_key: "lix_own_entity",
273+
snapshot_content: JSON.stringify({
274+
account_id: activeAccountId,
275+
} satisfies LixActiveAccount),
276+
schema_version: LixActiveAccountSchema["x-lix-version"],
277+
created_at: created_at,
278+
lixcol_version_id: "global",
279+
},
280+
],
281+
});
276282

277283
// Handle other untracked key values
278284
const untrackedKeyValues = args?.keyValues?.filter(
279285
(kv) => kv.lixcol_untracked === true
280286
);
281287
if (untrackedKeyValues) {
282-
for (const kv of untrackedKeyValues) {
283-
const versionId = kv.lixcol_version_id ?? "global";
284-
updateUntrackedState({
285-
lix: { sqlite, db },
286-
change: {
287-
entity_id: kv.key,
288-
schema_key: "lix_key_value",
289-
file_id: "lix",
290-
plugin_key: "lix_own_entity",
291-
snapshot_content: JSON.stringify({
292-
key: kv.key,
293-
value: kv.value,
294-
}),
295-
schema_version: LixKeyValueSchema["x-lix-version"],
296-
created_at: created_at,
297-
},
298-
version_id: versionId,
299-
});
300-
}
288+
for (const kv of untrackedKeyValues) {
289+
const versionId = kv.lixcol_version_id ?? "global";
290+
updateUntrackedState({
291+
lix: { sqlite, db },
292+
changes: [
293+
{
294+
entity_id: kv.key,
295+
schema_key: "lix_key_value",
296+
file_id: "lix",
297+
plugin_key: "lix_own_entity",
298+
snapshot_content: JSON.stringify({
299+
key: kv.key,
300+
value: kv.value,
301+
}),
302+
schema_version: LixKeyValueSchema["x-lix-version"],
303+
created_at: created_at,
304+
lixcol_version_id: versionId,
305+
},
306+
],
307+
});
308+
}
301309
}
302310

303311
try {

packages/lix-sdk/src/state/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ The virtual table:
4646

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

5252
#### 3. COMMIT Stage
@@ -80,7 +80,7 @@ The virtual table acts as a facade over the actual storage mechanism:
8080
┌─────────────────────────────────────────────────┐
8181
│ Regular SQLite Tables │
8282
│ │
83-
│ • internal_change_in_transaction
83+
│ • internal_transaction_state
8484
│ • internal_state_cache │
8585
│ • internal_change │
8686
│ • internal_snapshot │

packages/lix-sdk/src/state/cache/mark-state-cache-as-stale.ts

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,21 @@ export function markStateCacheAsStale(args: {
1414

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

17-
updateUntrackedState({
18-
lix: args.lix,
19-
change: {
20-
entity_id: CACHE_STALE_KEY,
21-
schema_key: LixKeyValueSchema["x-lix-key"],
22-
file_id: "lix",
23-
plugin_key: "lix_own_entity",
24-
snapshot_content: snapshotContent,
25-
schema_version: LixKeyValueSchema["x-lix-version"],
26-
created_at: ts,
27-
},
28-
version_id: "global",
29-
});
17+
updateUntrackedState({
18+
lix: args.lix,
19+
changes: [
20+
{
21+
entity_id: CACHE_STALE_KEY,
22+
schema_key: LixKeyValueSchema["x-lix-key"],
23+
file_id: "lix",
24+
plugin_key: "lix_own_entity",
25+
snapshot_content: snapshotContent,
26+
schema_version: LixKeyValueSchema["x-lix-version"],
27+
created_at: ts,
28+
lixcol_version_id: "global",
29+
},
30+
],
31+
});
3032
}
3133

3234
export function markStateCacheAsFresh(args: {
@@ -41,17 +43,19 @@ export function markStateCacheAsFresh(args: {
4143

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

44-
updateUntrackedState({
45-
lix: args.lix,
46-
change: {
47-
entity_id: CACHE_STALE_KEY,
48-
schema_key: LixKeyValueSchema["x-lix-key"],
49-
file_id: "lix",
50-
plugin_key: "lix_own_entity",
51-
snapshot_content: snapshotContent,
52-
schema_version: LixKeyValueSchema["x-lix-version"],
53-
created_at: ts,
54-
},
55-
version_id: "global",
56-
});
46+
updateUntrackedState({
47+
lix: args.lix,
48+
changes: [
49+
{
50+
entity_id: CACHE_STALE_KEY,
51+
schema_key: LixKeyValueSchema["x-lix-key"],
52+
file_id: "lix",
53+
plugin_key: "lix_own_entity",
54+
snapshot_content: snapshotContent,
55+
schema_version: LixKeyValueSchema["x-lix-version"],
56+
created_at: ts,
57+
lixcol_version_id: "global",
58+
},
59+
],
60+
});
5761
}

0 commit comments

Comments
 (0)