Skip to content

Commit c755321

Browse files
ryanrasticlaude
andcommitted
live: collapse capture to a single image column, drop the side map
The before/after naming was cosmetic — the matcher only consumes the union of (col, value) pairs, so one __typegres_live_image column serves the mutation RETURNING and the update pre-select alike. imageReturning takes just the table name; RETURNING_SIDE is gone; the strip/push loop unifies into one pushImage helper. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent d857c35 commit c755321

1 file changed

Lines changed: 14 additions & 20 deletions

File tree

src/live/sqlite/capture.ts

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,10 @@ import { Text } from "../../types/sqlite";
3131
// extractor emits, so the bus's string matching lines up. Keep the two
3232
// aligned (see ../canonical.ts).
3333

34-
export const T_LIVE_BEFORE = "__typegres_live_before";
35-
export const T_LIVE_AFTER = "__typegres_live_after";
34+
// One column name serves every image: the matcher only consumes the
35+
// union of (col, value) pairs, so which state a JSON image snapshots
36+
// (before vs after) never needs to be distinguishable downstream.
37+
const T_LIVE_IMAGE = "__typegres_live_image";
3638

3739
// `json_object('col', <canonical text of ref>, ...)` over every column
3840
// field of the row instance. SqlValue is the shared base of the sqlite
@@ -44,16 +46,15 @@ const buildImageJson = (tableInstance: { [c: string]: unknown }): Sql => {
4446
return sql`json_object(${sql.join(args)})`;
4547
};
4648

47-
// returningMerge callback adding `__typegres_live_<side>` to the mutation's
49+
// returningMerge callback adding the image column to the mutation's
4850
// RETURNING. executeMutationWithCapture strips the column from result rows
4951
// before they reach deserializeRows (which throws on keys missing from the
5052
// row type).
5153
const imageReturning =
52-
(tableName: string, side: "before" | "after") =>
54+
(tableName: string) =>
5355
(ns: object): RowType => {
5456
const tableInstance = (ns as { [k: string]: object })[tableName] as { [c: string]: unknown };
55-
const key = side === "before" ? T_LIVE_BEFORE : T_LIVE_AFTER;
56-
return { [key]: Text.from(buildImageJson(tableInstance)) };
57+
return { [T_LIVE_IMAGE]: Text.from(buildImageJson(tableInstance)) };
5758
};
5859

5960
// The UPDATE before-image: select the image of every row the UPDATE's
@@ -82,7 +83,7 @@ const buildUpdatePreImageSelect = (builder: UpdateBuilder<any, any, any>): Sql =
8283
const whereClause = where ? where.toSql() : sql`TRUE`;
8384
return sql.withScope(
8485
[alias],
85-
sql`SELECT ${buildImageJson(instance as { [c: string]: unknown })} AS ${new Ident(T_LIVE_BEFORE)} FROM ${database.scopedIdent(builder.tableName)} AS ${alias} WHERE ${whereClause}`,
86+
sql`SELECT ${buildImageJson(instance as { [c: string]: unknown })} AS ${new Ident(T_LIVE_IMAGE)} FROM ${database.scopedIdent(builder.tableName)} AS ${alias} WHERE ${whereClause}`,
8687
);
8788
};
8889

@@ -92,13 +93,6 @@ export type MutationBuilder =
9293
| UpdateBuilder<any, any, any>
9394
| DeleteBuilder<any, any, any>;
9495

95-
// Which image the mutation's own RETURNING can carry.
96-
const RETURNING_SIDE: { [K in MutationOp]: "before" | "after" } = {
97-
insert: "after",
98-
delete: "before",
99-
update: "after",
100-
};
101-
10296
// A mutation's change events: (col, canonical-text value) pairs from the
10397
// before/after images, unstamped — the caller assigns xids when it pushes
10498
// them into the bus.
@@ -126,24 +120,24 @@ export const executeMutationWithCapture = (
126120
const table = builder.tableName;
127121
// returningMerge has the same shape on all three builders; pick one
128122
// overload rather than writing a generic structural type.
129-
const merged = (builder as InsertBuilder<any, any, any>).returningMerge(
130-
imageReturning(table, RETURNING_SIDE[op]),
131-
);
123+
const merged = (builder as InsertBuilder<any, any, any>).returningMerge(imageReturning(table));
132124
const compiled: CompiledSql = compile(merged, { database });
133125
const preCompiled =
134126
op === "update"
135127
? compile(buildUpdatePreImageSelect(builder as UpdateBuilder<any, any, any>), { database })
136128
: undefined;
137129

138130
const events: CapturedEvent[] = [];
131+
const pushImage = (image: string | null | undefined) =>
132+
events.push({ table, pairs: parseEventPairs(image ?? null, null) });
139133
const preRows = preCompiled ? executeSync(preCompiled).rows : [];
140134
for (const row of preRows) {
141-
events.push({ table, pairs: parseEventPairs(row[T_LIVE_BEFORE] ?? null, null) });
135+
pushImage(row[T_LIVE_IMAGE]);
142136
}
143137
const result = executeSync(compiled);
144138
const rows = result.rows.map((row) => {
145-
const { [T_LIVE_BEFORE]: before, [T_LIVE_AFTER]: after, ...rest } = row;
146-
events.push({ table, pairs: parseEventPairs(before ?? null, after ?? null) });
139+
const { [T_LIVE_IMAGE]: image, ...rest } = row;
140+
pushImage(image);
147141
return rest;
148142
});
149143
return { rows, events };

0 commit comments

Comments
 (0)