@syncular/client 0.0.6-240 → 0.0.6-241
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/query-public.d.ts.map +1 -1
- package/dist/query-public.js +34 -12
- package/dist/query-public.js.map +1 -1
- package/package.json +3 -3
- package/src/query-public.test.ts +162 -0
- package/src/query-public.ts +43 -26
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query-public.d.ts","sourceRoot":"","sources":["../src/query-public.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"query-public.d.ts","sourceRoot":"","sources":["../src/query-public.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAGL,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EAGvB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,MAAM,EAAqB,MAAM,QAAQ,CAAC;AACxD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACzE,OAAO,EAIL,KAAK,uBAAuB,EAC7B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE7C,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EACL,cAAc,EACd,kBAAkB,GACnB,MAAM,qBAAqB,CAAC;AAE7B,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,OAAO,CAAC;AAE/C,KAAK,iBAAiB,CAAC,EAAE,IAAI,MAAM,CAAC,EAAE,CAAC,CAAC,YAAY,CAAC,CAAC;AAiTtD,MAAM,WAAW,YAAY,CAAC,EAAE,SAAS,YAAY,GAAG,YAAY;IAClE,UAAU,EAAE,iBAAiB,CAAC,EAAE,CAAC,CAAC;CACnC;AAED,wBAAgB,kBAAkB,CAAC,EAAE,SAAS,YAAY,EACxD,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC,EACd,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,EAC3B,oBAAoB,EAAE,oBAAoB,EAC1C,MAAM,EAAE,uBAAuB,EAC/B,QAAQ,SAAO,EACf,eAAe,GAAE,eAAwB,EACzC,WAAW,CAAC,EAAE,iBAAiB,EAC/B,YAAY,GAAE,kBAA6B,GAC1C,YAAY,CAAC,EAAE,CAAC,CAalB"}
|
package/dist/query-public.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* This wrapper keeps query-builder tracking isolated per chain so branching a
|
|
5
5
|
* base Kysely builder does not leak joined tables into sibling branches.
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
7
|
+
import { applyQueryResultPlan, buildQueryResultPlan, createTableColumnCodecsResolver, } from '@syncular/core';
|
|
8
8
|
import { computeRowFingerprint, computeValueFingerprint, hasKeyField, } from './query/fingerprint.js';
|
|
9
9
|
export { FingerprintCollector } from './query/FingerprintCollector.js';
|
|
10
10
|
export { canFingerprint, computeFingerprint, } from './query/fingerprint.js';
|
|
@@ -63,26 +63,48 @@ function addTrackedTablesToScopeCollector(scopeCollector, trackedTables) {
|
|
|
63
63
|
scopeCollector.add(trackedTable);
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
|
-
function
|
|
67
|
-
if (!isRecord(
|
|
68
|
-
return
|
|
69
|
-
return
|
|
66
|
+
function isOperationNodeSource(value) {
|
|
67
|
+
if (!isRecord(value))
|
|
68
|
+
return false;
|
|
69
|
+
return typeof Reflect.get(value, 'toOperationNode') === 'function';
|
|
70
70
|
}
|
|
71
|
-
function decodeRows(rows,
|
|
72
|
-
if (!resolveCodecs || !
|
|
71
|
+
function decodeRows(rows, builder, resolveCodecs, codecDialect) {
|
|
72
|
+
if (!resolveCodecs || !builder)
|
|
73
|
+
return rows;
|
|
74
|
+
const plan = buildQueryResultPlan(builder.toOperationNode());
|
|
75
|
+
if (!plan)
|
|
73
76
|
return rows;
|
|
74
77
|
if (Array.isArray(rows)) {
|
|
75
|
-
return rows.map((row) =>
|
|
78
|
+
return rows.map((row) => {
|
|
79
|
+
if (!isRecord(row))
|
|
80
|
+
return row;
|
|
81
|
+
return applyQueryResultPlan({
|
|
82
|
+
row,
|
|
83
|
+
plan,
|
|
84
|
+
resolveTableCodecs: resolveCodecs,
|
|
85
|
+
dialect: codecDialect,
|
|
86
|
+
});
|
|
87
|
+
});
|
|
76
88
|
}
|
|
77
|
-
|
|
89
|
+
if (!isRecord(rows))
|
|
90
|
+
return rows;
|
|
91
|
+
return applyQueryResultPlan({
|
|
92
|
+
row: rows,
|
|
93
|
+
plan,
|
|
94
|
+
resolveTableCodecs: resolveCodecs,
|
|
95
|
+
dialect: codecDialect,
|
|
96
|
+
});
|
|
78
97
|
}
|
|
79
98
|
function createExecuteProxy(builder, primaryTable, trackedTables, scopeCollector, collector, engine, keyField, fingerprintMode, resolveCodecs, codecDialect) {
|
|
99
|
+
const operationNodeSource = isOperationNodeSource(builder)
|
|
100
|
+
? builder
|
|
101
|
+
: undefined;
|
|
80
102
|
return new Proxy(builder, {
|
|
81
103
|
get(target, prop, receiver) {
|
|
82
104
|
if (prop === 'execute') {
|
|
83
105
|
return async () => {
|
|
84
106
|
const rows = await target.execute();
|
|
85
|
-
const decoded = decodeRows(rows,
|
|
107
|
+
const decoded = decodeRows(rows, operationNodeSource, resolveCodecs, codecDialect);
|
|
86
108
|
addTrackedTablesToScopeCollector(scopeCollector, trackedTables);
|
|
87
109
|
addFingerprint({
|
|
88
110
|
rows: decoded,
|
|
@@ -99,7 +121,7 @@ function createExecuteProxy(builder, primaryTable, trackedTables, scopeCollector
|
|
|
99
121
|
if (prop === 'executeTakeFirst') {
|
|
100
122
|
return async () => {
|
|
101
123
|
const row = await target.executeTakeFirst();
|
|
102
|
-
const decoded = decodeRows(row,
|
|
124
|
+
const decoded = decodeRows(row, operationNodeSource, resolveCodecs, codecDialect);
|
|
103
125
|
addTrackedTablesToScopeCollector(scopeCollector, trackedTables);
|
|
104
126
|
addFingerprint({
|
|
105
127
|
rows: decoded,
|
|
@@ -116,7 +138,7 @@ function createExecuteProxy(builder, primaryTable, trackedTables, scopeCollector
|
|
|
116
138
|
if (prop === 'executeTakeFirstOrThrow') {
|
|
117
139
|
return async () => {
|
|
118
140
|
const row = await target.executeTakeFirstOrThrow();
|
|
119
|
-
const decoded = decodeRows(row,
|
|
141
|
+
const decoded = decodeRows(row, operationNodeSource, resolveCodecs, codecDialect);
|
|
120
142
|
addTrackedTablesToScopeCollector(scopeCollector, trackedTables);
|
|
121
143
|
addFingerprint({
|
|
122
144
|
rows: decoded,
|
package/dist/query-public.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query-public.js","sourceRoot":"","sources":["../src/query-public.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,oBAAoB,EAGpB,+BAA+B,GAEhC,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EACL,qBAAqB,EACrB,uBAAuB,EACvB,WAAW,GAEZ,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EACL,cAAc,EACd,kBAAkB,GACnB,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"query-public.js","sourceRoot":"","sources":["../src/query-public.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@syncular/client",
|
|
3
|
-
"version": "0.0.6-
|
|
3
|
+
"version": "0.0.6-241",
|
|
4
4
|
"description": "Client-side sync engine with offline-first support, outbox, and conflict resolution",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Benjamin Kniffler",
|
|
@@ -119,8 +119,8 @@
|
|
|
119
119
|
"release": "bunx syncular-publish"
|
|
120
120
|
},
|
|
121
121
|
"dependencies": {
|
|
122
|
-
"@syncular/core": "0.0.6-
|
|
123
|
-
"@syncular/transport-http": "0.0.6-
|
|
122
|
+
"@syncular/core": "0.0.6-241",
|
|
123
|
+
"@syncular/transport-http": "0.0.6-241"
|
|
124
124
|
},
|
|
125
125
|
"peerDependencies": {
|
|
126
126
|
"kysely": "*"
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it } from 'bun:test';
|
|
2
|
+
import { codecs, createDatabase } from '@syncular/core';
|
|
3
|
+
import type { Kysely } from 'kysely';
|
|
4
|
+
import { createBunSqliteDialect } from '../../dialect-bun-sqlite/src';
|
|
5
|
+
import { createQueryContext, FingerprintCollector } from './query-public';
|
|
6
|
+
import type { SyncClientDb } from './schema';
|
|
7
|
+
|
|
8
|
+
interface TasksTable {
|
|
9
|
+
id: string;
|
|
10
|
+
enabled: number | boolean;
|
|
11
|
+
metadata: string | { tags: string[] };
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface FlagsTable {
|
|
15
|
+
id: string;
|
|
16
|
+
enabled: number | boolean;
|
|
17
|
+
metadata: string | { tags: string[] };
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface TestDb extends SyncClientDb {
|
|
21
|
+
tasks: TasksTable;
|
|
22
|
+
flags: FlagsTable;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const engine = {
|
|
26
|
+
getMutationTimestamp(): number {
|
|
27
|
+
return 0;
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
function createCodecs() {
|
|
32
|
+
return (column: { table: string; column: string }) => {
|
|
33
|
+
if (column.column === 'enabled') {
|
|
34
|
+
return codecs.numberBoolean();
|
|
35
|
+
}
|
|
36
|
+
if (column.column === 'metadata') {
|
|
37
|
+
return codecs.stringJson<{ tags: string[] }>();
|
|
38
|
+
}
|
|
39
|
+
return undefined;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
describe('createQueryContext codec decoding', () => {
|
|
44
|
+
let db: Kysely<TestDb>;
|
|
45
|
+
|
|
46
|
+
beforeEach(async () => {
|
|
47
|
+
db = createDatabase<TestDb>({
|
|
48
|
+
dialect: createBunSqliteDialect({ path: ':memory:' }),
|
|
49
|
+
family: 'sqlite',
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
await db.schema
|
|
53
|
+
.createTable('tasks')
|
|
54
|
+
.addColumn('id', 'text', (col) => col.primaryKey())
|
|
55
|
+
.addColumn('enabled', 'integer', (col) => col.notNull())
|
|
56
|
+
.addColumn('metadata', 'text', (col) => col.notNull())
|
|
57
|
+
.execute();
|
|
58
|
+
|
|
59
|
+
await db.schema
|
|
60
|
+
.createTable('flags')
|
|
61
|
+
.addColumn('id', 'text', (col) => col.primaryKey())
|
|
62
|
+
.addColumn('enabled', 'integer', (col) => col.notNull())
|
|
63
|
+
.addColumn('metadata', 'text', (col) => col.notNull())
|
|
64
|
+
.execute();
|
|
65
|
+
|
|
66
|
+
await db
|
|
67
|
+
.insertInto('tasks')
|
|
68
|
+
.values({
|
|
69
|
+
id: 'task-1',
|
|
70
|
+
enabled: 1,
|
|
71
|
+
metadata: JSON.stringify({ tags: ['task'] }),
|
|
72
|
+
})
|
|
73
|
+
.execute();
|
|
74
|
+
|
|
75
|
+
await db
|
|
76
|
+
.insertInto('flags')
|
|
77
|
+
.values({
|
|
78
|
+
id: 'task-1',
|
|
79
|
+
enabled: 0,
|
|
80
|
+
metadata: JSON.stringify({ tags: ['flag'] }),
|
|
81
|
+
})
|
|
82
|
+
.execute();
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
afterEach(async () => {
|
|
86
|
+
await db.destroy();
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('decodes non-aliased columns from the primary table', async () => {
|
|
90
|
+
const ctx = createQueryContext(
|
|
91
|
+
db,
|
|
92
|
+
new Set(),
|
|
93
|
+
new FingerprintCollector(),
|
|
94
|
+
engine,
|
|
95
|
+
'id',
|
|
96
|
+
'value',
|
|
97
|
+
createCodecs(),
|
|
98
|
+
'sqlite'
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
const row = await ctx
|
|
102
|
+
.selectFrom('tasks')
|
|
103
|
+
.selectAll()
|
|
104
|
+
.where('id', '=', 'task-1')
|
|
105
|
+
.executeTakeFirstOrThrow();
|
|
106
|
+
|
|
107
|
+
expect(row).toEqual({
|
|
108
|
+
id: 'task-1',
|
|
109
|
+
enabled: true,
|
|
110
|
+
metadata: { tags: ['task'] },
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('decodes aliased columns selected from the primary table', async () => {
|
|
115
|
+
const ctx = createQueryContext(
|
|
116
|
+
db,
|
|
117
|
+
new Set(),
|
|
118
|
+
new FingerprintCollector(),
|
|
119
|
+
engine,
|
|
120
|
+
'id',
|
|
121
|
+
'value',
|
|
122
|
+
createCodecs(),
|
|
123
|
+
'sqlite'
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
const row = await ctx
|
|
127
|
+
.selectFrom('tasks as t')
|
|
128
|
+
.select(['t.enabled as isEnabled', 't.metadata as meta'])
|
|
129
|
+
.where('t.id', '=', 'task-1')
|
|
130
|
+
.executeTakeFirstOrThrow();
|
|
131
|
+
|
|
132
|
+
expect(row).toEqual({
|
|
133
|
+
isEnabled: true,
|
|
134
|
+
meta: { tags: ['task'] },
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('decodes aliased columns selected from joined tables', async () => {
|
|
139
|
+
const ctx = createQueryContext(
|
|
140
|
+
db,
|
|
141
|
+
new Set(),
|
|
142
|
+
new FingerprintCollector(),
|
|
143
|
+
engine,
|
|
144
|
+
'id',
|
|
145
|
+
'value',
|
|
146
|
+
createCodecs(),
|
|
147
|
+
'sqlite'
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
const row = await ctx
|
|
151
|
+
.selectFrom('tasks')
|
|
152
|
+
.innerJoin('flags', 'flags.id', 'tasks.id')
|
|
153
|
+
.select(['flags.enabled as flagEnabled', 'flags.metadata as flagMeta'])
|
|
154
|
+
.where('tasks.id', '=', 'task-1')
|
|
155
|
+
.executeTakeFirstOrThrow();
|
|
156
|
+
|
|
157
|
+
expect(row).toEqual({
|
|
158
|
+
flagEnabled: false,
|
|
159
|
+
flagMeta: { tags: ['flag'] },
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
});
|
package/src/query-public.ts
CHANGED
|
@@ -6,13 +6,14 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import {
|
|
9
|
-
|
|
9
|
+
applyQueryResultPlan,
|
|
10
|
+
buildQueryResultPlan,
|
|
10
11
|
type ColumnCodecDialect,
|
|
11
12
|
type ColumnCodecSource,
|
|
12
13
|
createTableColumnCodecsResolver,
|
|
13
14
|
type TableColumnCodecs,
|
|
14
15
|
} from '@syncular/core';
|
|
15
|
-
import type { Kysely } from 'kysely';
|
|
16
|
+
import type { Kysely, RootOperationNode } from 'kysely';
|
|
16
17
|
import type { FingerprintCollector } from './query/FingerprintCollector';
|
|
17
18
|
import {
|
|
18
19
|
computeRowFingerprint,
|
|
@@ -40,6 +41,10 @@ type ExecutableQuery = {
|
|
|
40
41
|
executeTakeFirstOrThrow: () => Promise<unknown>;
|
|
41
42
|
};
|
|
42
43
|
|
|
44
|
+
type OperationNodeSource = {
|
|
45
|
+
toOperationNode: () => RootOperationNode;
|
|
46
|
+
};
|
|
47
|
+
|
|
43
48
|
const JOIN_METHODS = new Set([
|
|
44
49
|
'innerJoin',
|
|
45
50
|
'leftJoin',
|
|
@@ -130,34 +135,40 @@ function addTrackedTablesToScopeCollector(
|
|
|
130
135
|
}
|
|
131
136
|
}
|
|
132
137
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
) => TableColumnCodecs;
|
|
137
|
-
|
|
138
|
-
function decodeRow(
|
|
139
|
-
row: unknown,
|
|
140
|
-
table: string,
|
|
141
|
-
resolveCodecs: CodecsResolver,
|
|
142
|
-
codecDialect: ColumnCodecDialect
|
|
143
|
-
): unknown {
|
|
144
|
-
if (!isRecord(row)) return row;
|
|
145
|
-
return applyCodecsFromDbRow(row, resolveCodecs(table, row), codecDialect);
|
|
138
|
+
function isOperationNodeSource(value: unknown): value is OperationNodeSource {
|
|
139
|
+
if (!isRecord(value)) return false;
|
|
140
|
+
return typeof Reflect.get(value, 'toOperationNode') === 'function';
|
|
146
141
|
}
|
|
147
142
|
|
|
148
143
|
function decodeRows(
|
|
149
144
|
rows: unknown,
|
|
150
|
-
|
|
151
|
-
resolveCodecs:
|
|
145
|
+
builder: OperationNodeSource | undefined,
|
|
146
|
+
resolveCodecs:
|
|
147
|
+
| ((table: string, row: Record<string, unknown>) => TableColumnCodecs)
|
|
148
|
+
| undefined,
|
|
152
149
|
codecDialect: ColumnCodecDialect
|
|
153
150
|
): unknown {
|
|
154
|
-
if (!resolveCodecs || !
|
|
151
|
+
if (!resolveCodecs || !builder) return rows;
|
|
152
|
+
const plan = buildQueryResultPlan(builder.toOperationNode());
|
|
153
|
+
if (!plan) return rows;
|
|
155
154
|
if (Array.isArray(rows)) {
|
|
156
|
-
return rows.map((row) =>
|
|
157
|
-
|
|
158
|
-
|
|
155
|
+
return rows.map((row) => {
|
|
156
|
+
if (!isRecord(row)) return row;
|
|
157
|
+
return applyQueryResultPlan({
|
|
158
|
+
row,
|
|
159
|
+
plan,
|
|
160
|
+
resolveTableCodecs: resolveCodecs,
|
|
161
|
+
dialect: codecDialect,
|
|
162
|
+
});
|
|
163
|
+
});
|
|
159
164
|
}
|
|
160
|
-
|
|
165
|
+
if (!isRecord(rows)) return rows;
|
|
166
|
+
return applyQueryResultPlan({
|
|
167
|
+
row: rows,
|
|
168
|
+
plan,
|
|
169
|
+
resolveTableCodecs: resolveCodecs,
|
|
170
|
+
dialect: codecDialect,
|
|
171
|
+
});
|
|
161
172
|
}
|
|
162
173
|
|
|
163
174
|
function createExecuteProxy<B extends ExecutableQuery>(
|
|
@@ -169,9 +180,15 @@ function createExecuteProxy<B extends ExecutableQuery>(
|
|
|
169
180
|
engine: MutationTimestampSource,
|
|
170
181
|
keyField: string,
|
|
171
182
|
fingerprintMode: FingerprintMode,
|
|
172
|
-
resolveCodecs:
|
|
183
|
+
resolveCodecs:
|
|
184
|
+
| ((table: string, row: Record<string, unknown>) => TableColumnCodecs)
|
|
185
|
+
| undefined,
|
|
173
186
|
codecDialect: ColumnCodecDialect
|
|
174
187
|
): B {
|
|
188
|
+
const operationNodeSource = isOperationNodeSource(builder)
|
|
189
|
+
? builder
|
|
190
|
+
: undefined;
|
|
191
|
+
|
|
175
192
|
return new Proxy(builder, {
|
|
176
193
|
get(target, prop, receiver) {
|
|
177
194
|
if (prop === 'execute') {
|
|
@@ -179,7 +196,7 @@ function createExecuteProxy<B extends ExecutableQuery>(
|
|
|
179
196
|
const rows = await target.execute();
|
|
180
197
|
const decoded = decodeRows(
|
|
181
198
|
rows,
|
|
182
|
-
|
|
199
|
+
operationNodeSource,
|
|
183
200
|
resolveCodecs,
|
|
184
201
|
codecDialect
|
|
185
202
|
);
|
|
@@ -202,7 +219,7 @@ function createExecuteProxy<B extends ExecutableQuery>(
|
|
|
202
219
|
const row = await target.executeTakeFirst();
|
|
203
220
|
const decoded = decodeRows(
|
|
204
221
|
row,
|
|
205
|
-
|
|
222
|
+
operationNodeSource,
|
|
206
223
|
resolveCodecs,
|
|
207
224
|
codecDialect
|
|
208
225
|
);
|
|
@@ -225,7 +242,7 @@ function createExecuteProxy<B extends ExecutableQuery>(
|
|
|
225
242
|
const row = await target.executeTakeFirstOrThrow();
|
|
226
243
|
const decoded = decodeRows(
|
|
227
244
|
row,
|
|
228
|
-
|
|
245
|
+
operationNodeSource,
|
|
229
246
|
resolveCodecs,
|
|
230
247
|
codecDialect
|
|
231
248
|
);
|