@spooky-sync/core 0.0.1-canary.124 → 0.0.1-canary.126
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/index.js
CHANGED
|
@@ -1178,7 +1178,8 @@ function bind(ctx, value) {
|
|
|
1178
1178
|
return `$${name}`;
|
|
1179
1179
|
}
|
|
1180
1180
|
function renderComparisonSurql(c, ctx) {
|
|
1181
|
-
const
|
|
1181
|
+
const rawRight = c.paramRef ? `$${c.paramRef}` : bind(ctx, c.value);
|
|
1182
|
+
const right = c.field === "id" ? `type::record(<string> ${rawRight})` : rawRight;
|
|
1182
1183
|
return c.swap ? `${right} ${c.op} ${c.field}` : `${c.field} ${c.op} ${right}`;
|
|
1183
1184
|
}
|
|
1184
1185
|
/** Render a WHERE conjunction (AND of comparisons / OR-groups) to SurrealQL. */
|
|
@@ -5100,8 +5101,8 @@ function parseBackendInfo(raw) {
|
|
|
5100
5101
|
|
|
5101
5102
|
//#endregion
|
|
5102
5103
|
//#region src/modules/devtools/index.ts
|
|
5103
|
-
const CORE_VERSION = "0.0.1-canary.
|
|
5104
|
-
const WASM_VERSION = "0.0.1-canary.
|
|
5104
|
+
const CORE_VERSION = "0.0.1-canary.126";
|
|
5105
|
+
const WASM_VERSION = "0.0.1-canary.126";
|
|
5105
5106
|
const SURREAL_VERSION = "3.0.3";
|
|
5106
5107
|
var DevToolsService = class {
|
|
5107
5108
|
eventsHistory = [];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spooky-sync/core",
|
|
3
|
-
"version": "0.0.1-canary.
|
|
3
|
+
"version": "0.0.1-canary.126",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -59,8 +59,8 @@
|
|
|
59
59
|
}
|
|
60
60
|
},
|
|
61
61
|
"dependencies": {
|
|
62
|
-
"@spooky-sync/query-builder": "0.0.1-canary.
|
|
63
|
-
"@spooky-sync/ssp-wasm": "0.0.1-canary.
|
|
62
|
+
"@spooky-sync/query-builder": "0.0.1-canary.126",
|
|
63
|
+
"@spooky-sync/ssp-wasm": "0.0.1-canary.126",
|
|
64
64
|
"@sqlite.org/sqlite-wasm": "3.53.0-build1",
|
|
65
65
|
"@surrealdb/wasm": "^3.0.3",
|
|
66
66
|
"fast-json-patch": "^3.1.1",
|
|
@@ -42,6 +42,54 @@ describe('renderBaseSelectSurql', () => {
|
|
|
42
42
|
});
|
|
43
43
|
});
|
|
44
44
|
|
|
45
|
+
// Regression guard for the "authors + comments don't load" class: any filter on
|
|
46
|
+
// a RecordId column (`id`) must coerce its string value with
|
|
47
|
+
// `type::record(<string> …)`. On SurrealDB `id = "thread:x"` (string) never
|
|
48
|
+
// matches a RecordId, so a base select filtered by id resolves EMPTY and its
|
|
49
|
+
// whole `.related()` subtree (author, comments) loads nothing. The string-based
|
|
50
|
+
// MemStore in relation-resolver.test.ts can't catch this (it compares keys as
|
|
51
|
+
// strings), so these assert the rendered SurrealQL directly — both the parent
|
|
52
|
+
// (base select) and child (relation fetch) sides.
|
|
53
|
+
describe('record-id coercion (authors/comments loading regression)', () => {
|
|
54
|
+
it('coerces a base-select `id = <value>` filter to a record id', () => {
|
|
55
|
+
const plan: QueryPlan = { table: 'thread', where: [{ field: 'id', op: '=', value: 'thread:abc' }] };
|
|
56
|
+
const { sql, vars } = renderBaseSelectSurql(plan);
|
|
57
|
+
expect(sql).toBe('SELECT * FROM thread WHERE id = type::record(<string> $__p0);');
|
|
58
|
+
expect(vars).toEqual({ __p0: 'thread:abc' });
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('coerces a base-select `id = $paramRef` filter (the ThreadDetail path)', () => {
|
|
62
|
+
const plan: QueryPlan = { table: 'thread', where: [{ field: 'id', op: '=', value: undefined, paramRef: 'id' }] };
|
|
63
|
+
const { sql } = renderBaseSelectSurql(plan, { id: 'thread:abc' });
|
|
64
|
+
expect(sql).toBe('SELECT * FROM thread WHERE id = type::record(<string> $id);');
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('does NOT coerce non-id fields (plain string/bool columns stay literal)', () => {
|
|
68
|
+
const plan: QueryPlan = {
|
|
69
|
+
table: 'thread',
|
|
70
|
+
where: [{ field: 'title', op: '=', value: 'hi' }, { field: 'published', op: '=', value: true }],
|
|
71
|
+
};
|
|
72
|
+
const { sql } = renderBaseSelectSurql(plan);
|
|
73
|
+
expect(sql).toBe('SELECT * FROM thread WHERE title = $__p0 AND published = $__p1;');
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('coerces `id` inside an OR group too', () => {
|
|
77
|
+
const plan: QueryPlan = {
|
|
78
|
+
table: 'thread',
|
|
79
|
+
where: [{ or: [{ field: 'id', op: '=', value: 'thread:a' }, { field: 'id', op: '=', value: 'thread:b' }] }],
|
|
80
|
+
};
|
|
81
|
+
const { sql } = renderBaseSelectSurql(plan);
|
|
82
|
+
expect(sql).toBe(
|
|
83
|
+
'SELECT * FROM thread WHERE (id = type::record(<string> $__p0) OR id = type::record(<string> $__p1));'
|
|
84
|
+
);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('relation fetch coerces its matchField keys (the .118 fix — kept locked)', () => {
|
|
88
|
+
const { sql } = renderRelationFetchSurql({ table: 'user', matchField: 'id', keys: ['user:1'] });
|
|
89
|
+
expect(sql).toContain('id IN $__keys.map(|$__k| type::record(<string> $__k))');
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
45
93
|
describe('renderRelationFetchSurql', () => {
|
|
46
94
|
it('builds a WHERE ... IN $__keys batch fetch, omitting LIMIT', () => {
|
|
47
95
|
const { sql, vars } = renderRelationFetchSurql({
|
|
@@ -26,7 +26,16 @@ function bind(ctx: RenderCtx, value: unknown): string {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
function renderComparisonSurql(c: WhereComparison, ctx: RenderCtx): string {
|
|
29
|
-
const
|
|
29
|
+
const rawRight = c.paramRef ? `$${c.paramRef}` : bind(ctx, c.value);
|
|
30
|
+
// `id` is a RecordId, but correlation/filter values arrive as record-id
|
|
31
|
+
// STRINGS (e.g. "thread:abc"). On SurrealDB `id = "thread:abc"` never matches
|
|
32
|
+
// (string ≠ record), so a base select filtered by id (e.g. the ThreadDetail
|
|
33
|
+
// query `… FROM thread WHERE id = $id`) resolves empty — and its whole
|
|
34
|
+
// `.related()` subtree (author, comments) then loads nothing. Coerce with
|
|
35
|
+
// `type::record(<string> …)` (idempotent if already a RecordId), mirroring
|
|
36
|
+
// renderRelationFetchSurql's matchField coercion.
|
|
37
|
+
const right =
|
|
38
|
+
c.field === 'id' ? `type::record(<string> ${rawRight})` : rawRight;
|
|
30
39
|
return c.swap ? `${right} ${c.op} ${c.field}` : `${c.field} ${c.op} ${right}`;
|
|
31
40
|
}
|
|
32
41
|
|