@agentshouse/mdruntime 0.1.0-ccbb89b0ca151 → 0.1.0-ccc0e3407f107
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/README.md +1 -1
- package/dist/adapter.d.ts +74 -57
- package/dist/adapter.d.ts.map +1 -1
- package/dist/attached-model.d.ts +3 -10
- package/dist/attached-model.d.ts.map +1 -1
- package/dist/attached-model.js +29 -47
- package/dist/bootstrap.d.ts +11 -18
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +85 -108
- package/dist/chain.d.ts +2 -1
- package/dist/chain.d.ts.map +1 -1
- package/dist/client.d.ts +9 -5
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +2 -1
- package/dist/collection.d.ts +7 -4
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +23 -17
- package/dist/compile.d.ts +1 -6
- package/dist/compile.d.ts.map +1 -1
- package/dist/compile.js +91 -270
- package/dist/connection.d.ts +10 -9
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +1009 -1063
- package/dist/context.d.ts +2 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +7 -0
- package/dist/conversation.d.ts +16 -13
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +229 -155
- package/dist/durability.d.ts +6 -1
- package/dist/durability.d.ts.map +1 -1
- package/dist/entry.d.ts +3 -2
- package/dist/entry.d.ts.map +1 -1
- package/dist/entry.js +17 -8
- package/dist/host.d.ts +3 -7
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +22 -27
- package/dist/identity.d.ts +0 -1
- package/dist/identity.d.ts.map +1 -1
- package/dist/identity.js +0 -3
- package/dist/index.d.ts +11 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/job.d.ts +14 -0
- package/dist/job.d.ts.map +1 -0
- package/dist/job.js +28 -0
- package/dist/live.d.ts +2 -1
- package/dist/live.d.ts.map +1 -1
- package/dist/live.js +10 -7
- package/dist/media.d.ts +1 -1
- package/dist/media.d.ts.map +1 -1
- package/dist/media.js +27 -4
- package/dist/memory.d.ts +11 -5
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +167 -84
- package/dist/messages.d.ts +2 -2
- package/dist/messages.d.ts.map +1 -1
- package/dist/messages.js +15 -16
- package/dist/model.d.ts +8 -8
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +6 -12
- package/dist/observation.d.ts +3 -2
- package/dist/observation.d.ts.map +1 -1
- package/dist/observation.js +8 -3
- package/dist/outcome.d.ts +0 -3
- package/dist/outcome.d.ts.map +1 -1
- package/dist/outcome.js +3 -1
- package/dist/paths.d.ts +1 -0
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +4 -0
- package/dist/query.d.ts +4 -209
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +3 -505
- package/dist/reach.d.ts +9 -8
- package/dist/reach.d.ts.map +1 -1
- package/dist/reach.js +37 -48
- package/dist/react.d.ts +3 -1
- package/dist/react.d.ts.map +1 -1
- package/dist/readiness.d.ts +3 -17
- package/dist/readiness.d.ts.map +1 -1
- package/dist/readiness.js +4 -10
- package/dist/recovery.d.ts +1 -0
- package/dist/recovery.d.ts.map +1 -1
- package/dist/recovery.js +26 -0
- package/dist/refresh.d.ts +7 -5
- package/dist/refresh.d.ts.map +1 -1
- package/dist/refresh.js +29 -5
- package/dist/replica.d.ts +10 -8
- package/dist/replica.d.ts.map +1 -1
- package/dist/replica.js +29 -14
- package/dist/room-draft.d.ts +21 -5
- package/dist/room-draft.d.ts.map +1 -1
- package/dist/room-draft.js +98 -51
- package/dist/rows.d.ts +14 -21
- package/dist/rows.d.ts.map +1 -1
- package/dist/rows.js +48 -184
- package/dist/save.d.ts +2 -0
- package/dist/save.d.ts.map +1 -1
- package/dist/save.js +20 -12
- package/dist/search.d.ts +12 -63
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +9 -52
- package/dist/shared.d.ts +0 -1
- package/dist/shared.d.ts.map +1 -1
- package/dist/shared.js +0 -10
- package/dist/status.d.ts +4 -3
- package/dist/status.d.ts.map +1 -1
- package/dist/status.js +3 -1
- package/dist/store.d.ts +21 -34
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +34 -77
- package/dist/stored.d.ts +11 -34
- package/dist/stored.d.ts.map +1 -1
- package/dist/stored.js +158 -241
- package/dist/tables.d.ts +23 -48
- package/dist/tables.d.ts.map +1 -1
- package/dist/tables.js +29 -66
- package/dist/transfer.d.ts +0 -5
- package/dist/transfer.d.ts.map +1 -1
- package/dist/validation.d.ts +3 -4
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +42 -100
- package/dist/windows.d.ts +1 -12
- package/dist/windows.d.ts.map +1 -1
- package/dist/windows.js +2 -75
- package/dist/wire.d.ts +9 -4
- package/dist/wire.d.ts.map +1 -1
- package/dist/wire.js +3 -1
- package/package.json +2 -2
- package/dist/fulltext.d.ts +0 -27
- package/dist/fulltext.d.ts.map +0 -1
- package/dist/fulltext.js +0 -368
- package/dist/reads.d.ts +0 -11
- package/dist/reads.d.ts.map +0 -1
- package/dist/reads.js +0 -100
- package/dist/words.d.ts +0 -19
- package/dist/words.d.ts.map +0 -1
- package/dist/words.js +0 -150
package/dist/compile.js
CHANGED
|
@@ -1,119 +1,36 @@
|
|
|
1
|
-
import { ARRAY_INDEX, parse, pointerSegments } from '@agentshouse/mdmodel';
|
|
1
|
+
import { ARRAY_INDEX, bodied, byCodePoint, compared, cursorOf, heldKind, parse, pointerSegments, sql, } from '@agentshouse/mdmodel';
|
|
2
2
|
import { binaryRecord } from './binary.js';
|
|
3
|
-
import { documentKey,
|
|
4
|
-
import {
|
|
3
|
+
import { documentKey, pathOfKey, roomOfKey } from './rows.js';
|
|
4
|
+
import { FROM_START, MAXIMUM_WINDOW } from './windows.js';
|
|
5
|
+
const { all, any, exists, fragment, grouped, joined, listed } = sql;
|
|
5
6
|
const VISIBLE = (alias) => `${alias}.visible = 1 AND ${alias}.present = 1 AND ${alias}.queried = 1`;
|
|
6
|
-
function
|
|
7
|
-
return
|
|
7
|
+
function located(alias) {
|
|
8
|
+
return fragment(`(SELECT k.locator FROM replica_keys k WHERE k.key = ${alias}.key)`);
|
|
8
9
|
}
|
|
9
|
-
function
|
|
10
|
-
return {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
function all(parts) {
|
|
16
|
-
return parts.length === 0 ? fragment('1') : joined(parts.map(grouped), ' AND ');
|
|
17
|
-
}
|
|
18
|
-
function any(parts) {
|
|
19
|
-
return parts.length === 0 ? fragment('0') : joined(parts.map(grouped), ' OR ');
|
|
20
|
-
}
|
|
21
|
-
function grouped(part) {
|
|
22
|
-
return { sql: `(${part.sql})`, bind: part.bind };
|
|
23
|
-
}
|
|
24
|
-
function list(values) {
|
|
25
|
-
return fragment(`(${values.map(() => '?').join(', ')})`, values);
|
|
26
|
-
}
|
|
27
|
-
function sqlValue(value) {
|
|
28
|
-
if (value === null)
|
|
29
|
-
return { kind: 'null', value: null };
|
|
30
|
-
if (typeof value === 'boolean')
|
|
31
|
-
return { kind: 'boolean', value: value ? 1 : 0 };
|
|
32
|
-
if (typeof value === 'number')
|
|
33
|
-
return { kind: 'number', value };
|
|
34
|
-
return { kind: 'string', value };
|
|
35
|
-
}
|
|
36
|
-
function same(alias, value) {
|
|
37
|
-
const held = sqlValue(value);
|
|
38
|
-
return held.kind === 'null'
|
|
39
|
-
? fragment(`${alias}.kind = 'null'`)
|
|
40
|
-
: fragment(`${alias}.kind = ? AND ${alias}.value = ?`, [held.kind, held.value]);
|
|
41
|
-
}
|
|
42
|
-
const BOUNDS = { gt: '>', gte: '>=', lt: '<', lte: '<=' };
|
|
43
|
-
function pointed(alias, field, reach) {
|
|
44
|
-
const { keys, places, glob } = placedOf(field, reach);
|
|
45
|
-
return fragment(`${alias}.keys = ? AND ${alias}.places ${glob ? 'GLOB' : '='} ?`, [keys, places]);
|
|
46
|
-
}
|
|
47
|
-
function heldValues(doc, field, alias, where) {
|
|
48
|
-
return joined([
|
|
49
|
-
fragment(`SELECT 1 FROM replica_values ${alias} WHERE ${alias}.doc = ${doc}.id AND `),
|
|
50
|
-
grouped(pointed(alias, field, 'value')),
|
|
51
|
-
fragment(' AND '),
|
|
52
|
-
grouped(where),
|
|
53
|
-
], '');
|
|
54
|
-
}
|
|
55
|
-
function exists(part) {
|
|
56
|
-
return { sql: `EXISTS (${part.sql})`, bind: part.bind };
|
|
57
|
-
}
|
|
58
|
-
function itemOf(held, where) {
|
|
59
|
-
return exists(joined([
|
|
60
|
-
fragment(`SELECT 1 FROM replica_values i WHERE i.doc = ${held}.doc AND i.keys = ${held}.keys AND i.places = ${held}.places AND i.item >= 0 AND `),
|
|
61
|
-
grouped(where),
|
|
62
|
-
], ''));
|
|
63
|
-
}
|
|
64
|
-
function matching(held, values) {
|
|
65
|
-
return any(values.map((value) => any([
|
|
66
|
-
same(held, value),
|
|
67
|
-
all([fragment(`${held}.kind = 'array'`), itemOf(held, same('i', value))]),
|
|
68
|
-
])));
|
|
69
|
-
}
|
|
70
|
-
function tested(doc, field, test) {
|
|
71
|
-
const reached = exists(heldValues(doc, field, 'r', fragment('r.item = -1')));
|
|
72
|
-
if (test.op === 'exists')
|
|
73
|
-
return test.exists ? reached : fragment(`NOT ${reached.sql}`, reached.bind);
|
|
74
|
-
if (test.op === 'eq' || test.op === 'in') {
|
|
75
|
-
const values = test.op === 'eq' ? [test.value] : test.values;
|
|
76
|
-
return exists(heldValues(doc, field, 'v', any(values.map((value) => same('v', value)))));
|
|
77
|
-
}
|
|
78
|
-
if (test.op === 'ne' || test.op === 'nin') {
|
|
79
|
-
const values = test.op === 'ne' ? [test.value] : test.values;
|
|
80
|
-
const unmatched = matching('h', values);
|
|
81
|
-
return any([
|
|
82
|
-
fragment(`NOT ${reached.sql}`, reached.bind),
|
|
83
|
-
exists(heldValues(doc, field, 'h', all([fragment('h.item = -1'), fragment(`NOT (${unmatched.sql})`, unmatched.bind)]))),
|
|
84
|
-
]);
|
|
85
|
-
}
|
|
86
|
-
if (test.op === 'range') {
|
|
87
|
-
return exists(heldValues(doc, field, 'v', all([
|
|
88
|
-
fragment('v.item = -1'),
|
|
89
|
-
...test.bounds.map(([operator, bound]) => {
|
|
90
|
-
const held = sqlValue(bound);
|
|
91
|
-
return fragment(`v.kind = ? AND v.value ${BOUNDS[operator]} ?`, [
|
|
92
|
-
held.kind,
|
|
93
|
-
held.value,
|
|
94
|
-
]);
|
|
95
|
-
}),
|
|
96
|
-
])));
|
|
97
|
-
}
|
|
98
|
-
if (test.op === 'all') {
|
|
99
|
-
return exists(heldValues(doc, field, 'h', all([
|
|
100
|
-
fragment("h.item = -1 AND h.kind = 'array'"),
|
|
101
|
-
...test.values.map((value) => itemOf('h', same('i', value))),
|
|
102
|
-
])));
|
|
103
|
-
}
|
|
104
|
-
return exists(heldValues(doc, field, 'v', fragment("v.item = -1 AND v.kind = 'array' AND v.size = ?", [test.size])));
|
|
10
|
+
function within(alias, path) {
|
|
11
|
+
return fragment(`(${alias}.path = ? OR (${alias}.path >= ? AND ${alias}.path < ?))`, [
|
|
12
|
+
path,
|
|
13
|
+
`${path}/`,
|
|
14
|
+
`${path}0`,
|
|
15
|
+
]);
|
|
105
16
|
}
|
|
106
|
-
function
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
return
|
|
111
|
-
|
|
17
|
+
function ancestors(area) {
|
|
18
|
+
const depth = area.path.split('/').length;
|
|
19
|
+
return area.open.flatMap((open) => {
|
|
20
|
+
const segments = open.split('/');
|
|
21
|
+
return segments.slice(depth - 1, -1).map((_, at) => segments.slice(0, depth + at).join('/'));
|
|
22
|
+
});
|
|
112
23
|
}
|
|
113
|
-
function
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
24
|
+
function fenced(alias, key, area, folders) {
|
|
25
|
+
const opened = any([
|
|
26
|
+
...area.open.map((open) => within(alias, open)),
|
|
27
|
+
...(folders ? ancestors(area).map((path) => fragment(`${alias}.path = ?`, [path])) : []),
|
|
28
|
+
]);
|
|
29
|
+
return all([
|
|
30
|
+
fragment(`${alias}.key = ?`, [key]),
|
|
31
|
+
within(alias, area.path),
|
|
32
|
+
fragment(`NOT ${grouped(opened).sql}`, opened.bind),
|
|
33
|
+
]);
|
|
117
34
|
}
|
|
118
35
|
function reached(bound, alias) {
|
|
119
36
|
const reach = bound.reach;
|
|
@@ -127,42 +44,20 @@ function reached(bound, alias) {
|
|
|
127
44
|
const key = bound.keys.get(roomOfKey(held));
|
|
128
45
|
return key === undefined ? [] : [[key, pathOfKey(held)]];
|
|
129
46
|
});
|
|
130
|
-
const
|
|
47
|
+
const outside = any(reach.areas.flatMap((area) => {
|
|
131
48
|
const key = bound.keys.get(area.room);
|
|
132
|
-
return key === undefined ? [] : [
|
|
133
|
-
});
|
|
134
|
-
const beneath = (area) => fragment(`${alias}.key = ? AND (${alias}.path = ? OR (${alias}.path >= ? AND ${alias}.path < ?))`, [area.key, area.path, `${area.path}/`, `${area.path}0`]);
|
|
135
|
-
const typed = (types) => fragment(`${alias}.type IN ${list(types).sql}`, types);
|
|
136
|
-
const outside = any(areas.map((area) => area.types.length === 0
|
|
137
|
-
? beneath(area)
|
|
138
|
-
: all([beneath(area), fragment(`NOT ${grouped(typed(area.types)).sql}`, area.types)])));
|
|
49
|
+
return key === undefined ? [] : [fenced(alias, key, area, false)];
|
|
50
|
+
}));
|
|
139
51
|
return all([
|
|
140
52
|
any([
|
|
141
|
-
...(rooms.length === 0 ? [] : [fragment(`${alias}.key IN ${
|
|
53
|
+
...(rooms.length === 0 ? [] : [fragment(`${alias}.key IN ${listed(rooms).sql}`, rooms)]),
|
|
142
54
|
...(documents.length === 0
|
|
143
55
|
? []
|
|
144
56
|
: [
|
|
145
57
|
fragment(`EXISTS (SELECT 1 FROM json_each(?) j WHERE j.value ->> 0 = ${alias}.key AND j.value ->> 1 = ${alias}.path)`, [JSON.stringify(documents)]),
|
|
146
58
|
]),
|
|
147
|
-
...areas.flatMap((area) => area.types.length === 0 ? [] : [all([beneath(area), typed(area.types)])]),
|
|
148
59
|
]),
|
|
149
|
-
...(areas.length === 0 ? [] : [fragment(`NOT ${grouped(outside).sql}`, outside.bind)]),
|
|
150
|
-
]);
|
|
151
|
-
}
|
|
152
|
-
function scoped(alias, scope) {
|
|
153
|
-
return all([
|
|
154
|
-
...(scope.types === null
|
|
155
|
-
? []
|
|
156
|
-
: [fragment(`${alias}.type IN ${list(scope.types).sql}`, scope.types)]),
|
|
157
|
-
...(scope.pathPrefix === null || scope.pathPrefix === ''
|
|
158
|
-
? []
|
|
159
|
-
: [
|
|
160
|
-
fragment(`${alias}.path >= ? AND ${alias}.path < ?`, [
|
|
161
|
-
`${scope.pathPrefix}/`,
|
|
162
|
-
`${scope.pathPrefix}0`,
|
|
163
|
-
]),
|
|
164
|
-
]),
|
|
165
|
-
...(scope.where === null ? [] : [conditioned(alias, scope.where)]),
|
|
60
|
+
...(reach.areas.length === 0 ? [] : [fragment(`NOT ${grouped(outside).sql}`, outside.bind)]),
|
|
166
61
|
]);
|
|
167
62
|
}
|
|
168
63
|
function related(bound, plan) {
|
|
@@ -170,17 +65,17 @@ function related(bound, plan) {
|
|
|
170
65
|
if (plan.hop !== null) {
|
|
171
66
|
parts.push(exists(joined([
|
|
172
67
|
fragment(`SELECT 1 FROM replica_links l JOIN replica_entries m ON m.key = d.key AND m.path = l.target AND ${VISIBLE('m')} WHERE l.doc = d.id AND l.kind = 'field' AND`),
|
|
173
|
-
grouped(
|
|
68
|
+
grouped(sql.placed('l', plan.hop.field, 'link')),
|
|
174
69
|
fragment('AND'),
|
|
175
|
-
grouped(all([scoped('m', plan.hop), reached(bound, 'm')])),
|
|
70
|
+
grouped(all([sql.scoped('m', plan.hop), reached(bound, 'm')])),
|
|
176
71
|
], ' ')));
|
|
177
72
|
}
|
|
178
73
|
if (plan.backlinks !== null) {
|
|
179
74
|
const field = plan.backlinks.field;
|
|
180
75
|
parts.push(exists(joined([
|
|
181
76
|
fragment(`SELECT 1 FROM replica_links l JOIN replica_entries s ON s.id = l.doc AND ${VISIBLE('s')} WHERE l.key = d.key AND l.target = d.path AND l.kind = 'field' AND`),
|
|
182
|
-
...(field === null ? [] : [grouped(
|
|
183
|
-
grouped(all([scoped('s', plan.backlinks), reached(bound, 's')])),
|
|
77
|
+
...(field === null ? [] : [grouped(sql.placed('l', field, 'link')), fragment('AND')]),
|
|
78
|
+
grouped(all([sql.scoped('s', plan.backlinks), reached(bound, 's')])),
|
|
184
79
|
], ' ')));
|
|
185
80
|
}
|
|
186
81
|
return parts;
|
|
@@ -188,11 +83,9 @@ function related(bound, plan) {
|
|
|
188
83
|
function filtered(bound, plan) {
|
|
189
84
|
const keys = bound.rooms.map(({ key }) => key);
|
|
190
85
|
return all([
|
|
191
|
-
fragment(`d.key IN ${
|
|
192
|
-
...(plan.paths === null ? [] : [fragment(`d.path IN ${list(plan.paths).sql}`, plan.paths)]),
|
|
193
|
-
...(plan.folder === null ? [] : [fragment('d.folder = ?', [plan.folder])]),
|
|
86
|
+
fragment(`d.key IN ${listed(keys).sql} AND ${VISIBLE('d')}`, keys),
|
|
194
87
|
reached(bound, 'd'),
|
|
195
|
-
|
|
88
|
+
sql.tests('d', plan),
|
|
196
89
|
...related(bound, plan),
|
|
197
90
|
]);
|
|
198
91
|
}
|
|
@@ -223,103 +116,25 @@ const GROUP_TIES = {
|
|
|
223
116
|
locale: undefined,
|
|
224
117
|
localeOptions: undefined,
|
|
225
118
|
};
|
|
226
|
-
function
|
|
227
|
-
if (value === null || value === undefined) {
|
|
228
|
-
return { placement: ordering.nulls === 'first' ? 0 : 2, klass: 0, scalar: null };
|
|
229
|
-
}
|
|
230
|
-
if (typeof value === 'boolean')
|
|
231
|
-
return { placement: 1, klass: 1, scalar: value ? 1 : 0 };
|
|
232
|
-
if (typeof value === 'number')
|
|
233
|
-
return { placement: 1, klass: 1, scalar: value };
|
|
234
|
-
if (typeof value === 'string')
|
|
235
|
-
return { placement: 1, klass: 2, scalar: value };
|
|
236
|
-
return { placement: 1, klass: 3, scalar: JSON.stringify(value) };
|
|
237
|
-
}
|
|
238
|
-
function placement(term) {
|
|
239
|
-
const nulls = term.ordering.nulls === 'first' ? 0 : 2;
|
|
240
|
-
return fragment(`CASE WHEN ${term.kind.sql} IS NULL OR ${term.kind.sql} = 'null' THEN ${nulls} ELSE 1 END`, [...term.kind.bind, ...term.kind.bind]);
|
|
241
|
-
}
|
|
242
|
-
function klass(term) {
|
|
243
|
-
return fragment(`CASE ${term.kind.sql} WHEN 'boolean' THEN 1 WHEN 'number' THEN 1 WHEN 'string' THEN 2 WHEN 'array' THEN 3 ELSE 4 END`, term.kind.bind);
|
|
244
|
-
}
|
|
245
|
-
function classed(term, which) {
|
|
246
|
-
const kinds = which === 1 ? "('boolean', 'number')" : which === 2 ? "('string')" : "('array')";
|
|
247
|
-
return fragment(`(CASE WHEN ${term.kind.sql} IN ${kinds} THEN ${term.value.sql} END)`, [
|
|
248
|
-
...term.kind.bind,
|
|
249
|
-
...term.value.bind,
|
|
250
|
-
]);
|
|
251
|
-
}
|
|
252
|
-
function collated(bound, term, which) {
|
|
253
|
-
if (which === 1)
|
|
254
|
-
return '';
|
|
255
|
-
const name = bound.collate(term.ordering, which === 3, term.total === true);
|
|
256
|
-
return name === null ? '' : ` COLLATE ${name}`;
|
|
257
|
-
}
|
|
258
|
-
function sorted(bound, term) {
|
|
259
|
-
const direction = term.ordering.direction === 'desc' ? 'DESC' : 'ASC';
|
|
260
|
-
return joined([
|
|
261
|
-
placement(term),
|
|
262
|
-
fragment(`${klass(term).sql} ${direction}`, klass(term).bind),
|
|
263
|
-
...[1, 2, 3].map((which) => {
|
|
264
|
-
const value = classed(term, which);
|
|
265
|
-
return fragment(`${value.sql}${collated(bound, term, which)} ${direction}`, value.bind);
|
|
266
|
-
}),
|
|
267
|
-
], ', ');
|
|
268
|
-
}
|
|
269
|
-
function beyond(bound, term, value) {
|
|
270
|
-
const held = classOf(value, term.ordering);
|
|
271
|
-
const place = placement(term);
|
|
272
|
-
if (held.placement !== 1) {
|
|
273
|
-
return {
|
|
274
|
-
beyond: fragment(`${place.sql} > ${held.placement}`, place.bind),
|
|
275
|
-
equal: fragment(`${place.sql} = ${held.placement}`, place.bind),
|
|
276
|
-
};
|
|
277
|
-
}
|
|
278
|
-
const after = term.ordering.direction === 'desc' ? '<' : '>';
|
|
279
|
-
const kind = klass(term);
|
|
280
|
-
const scalar = classed(term, held.klass);
|
|
281
|
-
const collation = collated(bound, term, held.klass);
|
|
282
|
-
return {
|
|
283
|
-
beyond: any([
|
|
284
|
-
fragment(`${place.sql} > 1`, place.bind),
|
|
285
|
-
all([
|
|
286
|
-
fragment(`${place.sql} = 1`, place.bind),
|
|
287
|
-
any([
|
|
288
|
-
fragment(`${kind.sql} ${after} ${held.klass}`, kind.bind),
|
|
289
|
-
all([
|
|
290
|
-
fragment(`${kind.sql} = ${held.klass}`, kind.bind),
|
|
291
|
-
fragment(`${scalar.sql} ${after} ?${collation}`, [...scalar.bind, held.scalar]),
|
|
292
|
-
]),
|
|
293
|
-
]),
|
|
294
|
-
]),
|
|
295
|
-
]),
|
|
296
|
-
equal: all([
|
|
297
|
-
fragment(`${place.sql} = 1 AND ${kind.sql} = ${held.klass}`, [...place.bind, ...kind.bind]),
|
|
298
|
-
fragment(`${scalar.sql} = ?${collation}`, [...scalar.bind, held.scalar]),
|
|
299
|
-
]),
|
|
300
|
-
};
|
|
301
|
-
}
|
|
302
|
-
function following(parts, tie) {
|
|
303
|
-
let condition = tie;
|
|
304
|
-
for (const part of [...parts].reverse()) {
|
|
305
|
-
condition = any([part.beyond, all([part.equal, condition])]);
|
|
306
|
-
}
|
|
307
|
-
return condition;
|
|
308
|
-
}
|
|
309
|
-
function keyTerm(bound, key, ordering, index) {
|
|
119
|
+
function keyTerm(key, ordering, index) {
|
|
310
120
|
if (key.of === 'field') {
|
|
311
121
|
const alias = `o${index}`;
|
|
312
122
|
return {
|
|
313
|
-
term: {
|
|
123
|
+
term: {
|
|
124
|
+
ordering,
|
|
125
|
+
kind: fragment(`${alias}.kind`),
|
|
126
|
+
value: fragment(`${alias}.value`),
|
|
127
|
+
instant: fragment(`${alias}.instant`),
|
|
128
|
+
},
|
|
314
129
|
join: joined([
|
|
315
130
|
fragment(`LEFT JOIN replica_values ${alias} ON ${alias}.doc = d.id AND `),
|
|
316
|
-
grouped(
|
|
131
|
+
grouped(sql.placed(alias, key.field, 'exact')),
|
|
317
132
|
fragment(` AND ${alias}.item = -1 AND ${alias}.kind NOT IN ('object', 'undefined')`),
|
|
318
133
|
], ''),
|
|
319
134
|
};
|
|
320
135
|
}
|
|
321
136
|
const expression = key.of === 'room'
|
|
322
|
-
? located(
|
|
137
|
+
? located('d')
|
|
323
138
|
: key.of === 'path'
|
|
324
139
|
? fragment('d.path')
|
|
325
140
|
: key.of === 'type'
|
|
@@ -345,13 +160,20 @@ function decoded(kind, value) {
|
|
|
345
160
|
return JSON.parse(value);
|
|
346
161
|
return null;
|
|
347
162
|
}
|
|
163
|
+
function sortedValue(row, index) {
|
|
164
|
+
const kind = row[`k${index}`];
|
|
165
|
+
return sql.sortValue(kind, decoded(kind, row[`v${index}`]), row[`i${index}`]);
|
|
166
|
+
}
|
|
348
167
|
function decodedKey(key, row, index) {
|
|
349
168
|
if (key.of === 'field') {
|
|
350
169
|
const kind = row[`k${index}`];
|
|
351
|
-
return kind === null || kind === undefined ? undefined :
|
|
170
|
+
return kind === null || kind === undefined ? undefined : sortedValue(row, index);
|
|
352
171
|
}
|
|
353
172
|
return row[`v${index}`] ?? null;
|
|
354
173
|
}
|
|
174
|
+
function instantOf(term) {
|
|
175
|
+
return term.instant ?? fragment('NULL');
|
|
176
|
+
}
|
|
355
177
|
const registered = new WeakMap();
|
|
356
178
|
function hashed(text) {
|
|
357
179
|
let hash = 0x811c9dc5;
|
|
@@ -401,9 +223,6 @@ function collating(connection) {
|
|
|
401
223
|
return name;
|
|
402
224
|
};
|
|
403
225
|
}
|
|
404
|
-
function bodied(shape) {
|
|
405
|
-
return shape.sections !== null || shape.preamble || shape.markdown;
|
|
406
|
-
}
|
|
407
226
|
function masked(pointers) {
|
|
408
227
|
const root = { whole: false, members: new Map() };
|
|
409
228
|
for (const pointer of pointers) {
|
|
@@ -494,7 +313,7 @@ function documentOf(shape, room, row, linked) {
|
|
|
494
313
|
? {}
|
|
495
314
|
: { sections: sectionsOf(body.sections, shape.sections) }),
|
|
496
315
|
...(shape.preamble && body !== null ? { preamble: body.preamble } : {}),
|
|
497
|
-
...(shape.markdown
|
|
316
|
+
...(shape.markdown ? { markdown: row.content } : {}),
|
|
498
317
|
...(shape.backlinks ? { backlinks: linked.get(documentKey(room, path)) ?? [] } : {}),
|
|
499
318
|
...(shape.change
|
|
500
319
|
? {
|
|
@@ -528,10 +347,10 @@ function backlinksOf(connection, bound, rows) {
|
|
|
528
347
|
return linked;
|
|
529
348
|
}
|
|
530
349
|
function documents(connection, bound, plan, shape, budget) {
|
|
531
|
-
const terms = shape.orderBy.map(({ key, options }, index) => keyTerm(
|
|
350
|
+
const terms = shape.orderBy.map(({ key, options }, index) => keyTerm(key, orderingOf(options), index));
|
|
532
351
|
const filter = filtered(bound, plan);
|
|
533
352
|
const cursor = plan.after?.values ?? null;
|
|
534
|
-
const room = located(
|
|
353
|
+
const room = located('d');
|
|
535
354
|
const tie = cursor === null
|
|
536
355
|
? null
|
|
537
356
|
: (() => {
|
|
@@ -547,19 +366,20 @@ function documents(connection, bound, plan, shape, budget) {
|
|
|
547
366
|
})();
|
|
548
367
|
const after = cursor === null || tie === null
|
|
549
368
|
? null
|
|
550
|
-
: following(terms.map(({ term }, index) => beyond(bound, term, cursor[index])), tie);
|
|
369
|
+
: sql.following(terms.map(({ term }, index) => sql.beyond(bound.collate, term, cursor[index])), tie);
|
|
551
370
|
const selected = joined([
|
|
552
371
|
fragment('SELECT d.id, d.key, d.path, d.type, d.binary, d.revision, d.fields, d.change, d.file_id'),
|
|
553
372
|
...terms.map(({ term }, index) => joined([
|
|
554
373
|
fragment(`, ${term.kind.sql} AS k${index}`, term.kind.bind),
|
|
555
374
|
fragment(`, ${term.value.sql} AS v${index}`, term.value.bind),
|
|
375
|
+
fragment(`, ${instantOf(term).sql} AS i${index}`, instantOf(term).bind),
|
|
556
376
|
], '')),
|
|
557
377
|
fragment(' FROM replica_entries d'),
|
|
558
378
|
...terms.flatMap(({ join }) => (join === null ? [] : [fragment(' '), join])),
|
|
559
379
|
fragment(' WHERE '),
|
|
560
380
|
after === null ? filter : all([filter, after]),
|
|
561
381
|
fragment(' ORDER BY '),
|
|
562
|
-
joined([...terms.map(({ term }) => sorted(bound, term)), room, fragment('d.path')], ', '),
|
|
382
|
+
joined([...terms.map(({ term }) => sql.sorted(bound.collate, term)), room, fragment('d.path')], ', '),
|
|
563
383
|
...(plan.limit === null ? [] : [fragment(' LIMIT ?', [plan.limit + 1])]),
|
|
564
384
|
], '');
|
|
565
385
|
const rows = connection.rows(selected.sql, selected.bind);
|
|
@@ -598,7 +418,7 @@ function withContent(connection, rows, budget) {
|
|
|
598
418
|
return rows;
|
|
599
419
|
const ids = rows.map((row) => row.id);
|
|
600
420
|
const sizes = new Map(connection
|
|
601
|
-
.rows(`SELECT id, octet_length(content) AS size FROM replica_entries WHERE id IN ${
|
|
421
|
+
.rows(`SELECT id, octet_length(content) AS size FROM replica_entries WHERE id IN ${listed(ids).sql}`, ids)
|
|
602
422
|
.map((row) => [row.id, Number(row.size ?? 0)]));
|
|
603
423
|
let cut = rows.length;
|
|
604
424
|
let spent = 0;
|
|
@@ -613,34 +433,30 @@ function withContent(connection, rows, budget) {
|
|
|
613
433
|
const kept = rows.slice(0, cut);
|
|
614
434
|
const read = kept.map((row) => row.id);
|
|
615
435
|
const held = new Map(connection
|
|
616
|
-
.rows(`SELECT id, content FROM replica_entries WHERE id IN ${
|
|
436
|
+
.rows(`SELECT id, content FROM replica_entries WHERE id IN ${listed(read).sql}`, read)
|
|
617
437
|
.map((row) => [row.id, row.content]));
|
|
618
438
|
return kept.map((row) => ({ ...row, content: held.get(row.id) ?? null }));
|
|
619
439
|
}
|
|
620
440
|
function storedFolders(bound, plan) {
|
|
621
|
-
if (plan.paths !== null || plan.
|
|
441
|
+
if (plan.paths !== null || plan.fileIds !== null)
|
|
442
|
+
return null;
|
|
443
|
+
if (plan.hop !== null || plan.backlinks !== null)
|
|
622
444
|
return null;
|
|
623
445
|
const whole = bound.rooms.filter(({ locator }) => bound.reach === null || bound.reach.rooms.includes(locator));
|
|
624
446
|
if (whole.length === 0)
|
|
625
447
|
return null;
|
|
626
448
|
const keys = whole.map(({ key }) => key);
|
|
627
449
|
const prefix = plan.root.pathPrefix;
|
|
628
|
-
const
|
|
450
|
+
const outside = (bound.reach?.areas ?? []).flatMap((area) => {
|
|
629
451
|
const key = bound.keys.get(area.room);
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
key,
|
|
635
|
-
area.path,
|
|
636
|
-
`${area.path}/`,
|
|
637
|
-
`${area.path}0`,
|
|
638
|
-
]),
|
|
639
|
-
];
|
|
452
|
+
if (key === undefined)
|
|
453
|
+
return [];
|
|
454
|
+
const fence = fenced('f', key, area, true);
|
|
455
|
+
return [fragment(`NOT ${grouped(fence).sql}`, fence.bind)];
|
|
640
456
|
});
|
|
641
457
|
return all([
|
|
642
|
-
fragment(`f.key IN ${
|
|
643
|
-
...
|
|
458
|
+
fragment(`f.key IN ${listed(keys).sql} AND f.layer = 0 AND f.present = 1`, keys),
|
|
459
|
+
...outside,
|
|
644
460
|
...(prefix === null || prefix === ''
|
|
645
461
|
? []
|
|
646
462
|
: [
|
|
@@ -655,7 +471,7 @@ function storedFolders(bound, plan) {
|
|
|
655
471
|
}
|
|
656
472
|
function groups(connection, bound, plan, shape) {
|
|
657
473
|
const keyed = shape.groupBy.map((key, index) => {
|
|
658
|
-
const { term, join } = keyTerm(
|
|
474
|
+
const { term, join } = keyTerm(key, GROUP_ORDER, index);
|
|
659
475
|
const kind = fragment(`COALESCE(${term.kind.sql}, 'null')`, term.kind.bind);
|
|
660
476
|
return { term: { ...term, kind }, join };
|
|
661
477
|
});
|
|
@@ -665,6 +481,7 @@ function groups(connection, bound, plan, shape) {
|
|
|
665
481
|
joined(keyed.map(({ term }, index) => joined([
|
|
666
482
|
fragment(`${term.kind.sql} AS k${index}`, term.kind.bind),
|
|
667
483
|
fragment(`, ${term.value.sql} AS v${index}`, term.value.bind),
|
|
484
|
+
fragment(`, ${instantOf(term).sql} AS i${index}`, instantOf(term).bind),
|
|
668
485
|
], '')), ', '),
|
|
669
486
|
fragment(', 1 AS n FROM replica_entries d'),
|
|
670
487
|
...keyed.flatMap(({ join }) => (join === null ? [] : [fragment(' '), join])),
|
|
@@ -678,10 +495,15 @@ function groups(connection, bound, plan, shape) {
|
|
|
678
495
|
? inner
|
|
679
496
|
: joined([
|
|
680
497
|
inner,
|
|
681
|
-
fragment(" UNION ALL SELECT 'string' AS k0, f.path AS v0, 0 AS n FROM replica_folders f WHERE "),
|
|
498
|
+
fragment(" UNION ALL SELECT 'string' AS k0, f.path AS v0, NULL AS i0, 0 AS n FROM replica_folders f WHERE "),
|
|
682
499
|
folders,
|
|
683
500
|
], '');
|
|
684
|
-
const columns = keyed
|
|
501
|
+
const columns = keyed
|
|
502
|
+
.map((_, index) => `k${index}, min(v${index}) AS v${index}, i${index}`)
|
|
503
|
+
.join(', ');
|
|
504
|
+
const held = keyed
|
|
505
|
+
.map((_, index) => `k${index}, i${index}, CASE WHEN i${index} IS NULL THEN v${index} END`)
|
|
506
|
+
.join(', ');
|
|
685
507
|
const counted = {
|
|
686
508
|
ordering: { ...GROUP_ORDER },
|
|
687
509
|
kind: fragment("'number'"),
|
|
@@ -694,7 +516,7 @@ function groups(connection, bound, plan, shape) {
|
|
|
694
516
|
});
|
|
695
517
|
const ordered = shape.orderBy.map(({ by, direction }) => by === 'count'
|
|
696
518
|
? { ...counted, ordering: { ...GROUP_ORDER, direction } }
|
|
697
|
-
: outer(by, { ...GROUP_ORDER, direction }));
|
|
519
|
+
: { ...outer(by, { ...GROUP_ORDER, direction }), instant: fragment(`i${by}`) });
|
|
698
520
|
const ties = keyed.flatMap((_, index) => [
|
|
699
521
|
{ ...outer(index, GROUP_TIES), total: true },
|
|
700
522
|
{ ordering: GROUP_TIES, kind: fragment("'string'"), value: fragment(`k${index}`) },
|
|
@@ -704,19 +526,21 @@ function groups(connection, bound, plan, shape) {
|
|
|
704
526
|
? null
|
|
705
527
|
: cursor[shape.orderBy.length].flatMap((value) => [
|
|
706
528
|
value,
|
|
707
|
-
|
|
529
|
+
heldKind(value ?? null),
|
|
708
530
|
]);
|
|
709
531
|
const after = cursor === null || tieValues === null
|
|
710
532
|
? null
|
|
711
|
-
: following(ordered.map((term, index) => beyond(bound, term, cursor[index])), following(ties
|
|
712
|
-
|
|
533
|
+
: sql.following(ordered.map((term, index) => sql.beyond(bound.collate, term, cursor[index])), sql.following(ties
|
|
534
|
+
.slice(0, -1)
|
|
535
|
+
.map((term, index) => sql.beyond(bound.collate, term, tieValues[index])), sql.beyond(bound.collate, ties.at(-1), tieValues.at(-1)).beyond));
|
|
536
|
+
const grouping = joined([fragment(`SELECT ${columns}, sum(n) AS n FROM (`), source, fragment(`) GROUP BY ${held}`)], '');
|
|
713
537
|
const windowed = joined([
|
|
714
538
|
fragment('SELECT * FROM ('),
|
|
715
539
|
grouping,
|
|
716
540
|
fragment(')'),
|
|
717
541
|
...(after === null ? [] : [fragment(' WHERE '), after]),
|
|
718
542
|
fragment(' ORDER BY '),
|
|
719
|
-
joined([...ordered, ...ties].map((term) => sorted(bound, term)), ', '),
|
|
543
|
+
joined([...ordered, ...ties].map((term) => sql.sorted(bound.collate, term)), ', '),
|
|
720
544
|
...(plan.limit === null ? [] : [fragment(' LIMIT ?', [plan.limit + 1])]),
|
|
721
545
|
], '');
|
|
722
546
|
const rows = connection.rows(windowed.sql, windowed.bind);
|
|
@@ -729,7 +553,7 @@ function groups(connection, bound, plan, shape) {
|
|
|
729
553
|
: last === undefined
|
|
730
554
|
? (plan.after?.text ?? FROM_START)
|
|
731
555
|
: cursorOf([
|
|
732
|
-
...shape.orderBy.map(({ by }) => by === 'count' ? Number(last.n) :
|
|
556
|
+
...shape.orderBy.map(({ by }) => by === 'count' ? Number(last.n) : sortedValue(last, by)),
|
|
733
557
|
keyOf(last),
|
|
734
558
|
]);
|
|
735
559
|
const total = plan.total
|
|
@@ -749,9 +573,6 @@ function boundOf(connection, plan, rooms) {
|
|
|
749
573
|
collate: collating(connection),
|
|
750
574
|
};
|
|
751
575
|
}
|
|
752
|
-
export function selected(connection, plan, rooms) {
|
|
753
|
-
return filtered(boundOf(connection, plan, rooms), plan);
|
|
754
|
-
}
|
|
755
576
|
export function answerQuery(connection, plan, rooms, budget = null) {
|
|
756
577
|
const bound = boundOf(connection, plan, rooms);
|
|
757
578
|
if (rooms.length === 0) {
|
package/dist/connection.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { type DocumentQuery, type GroupQuery } from '@agentshouse/mdmodel';
|
|
1
2
|
import { type TypesResult } from './model.js';
|
|
2
3
|
import { type Observation } from './observation.js';
|
|
3
|
-
import { type
|
|
4
|
+
import { type DocumentResult, type GroupResult, type PendingResult } from './query.js';
|
|
4
5
|
import { type EntrySeed } from './seed.js';
|
|
5
6
|
import { type SearchRequest, type SearchResult } from './search.js';
|
|
6
7
|
import { type Adapter, type Authorization, type Member, type ProviderRefusal, type ServiceMode } from './adapter.js';
|
|
@@ -12,8 +13,8 @@ import { type Recovery } from './recovery.js';
|
|
|
12
13
|
import { type SaveRefusal } from './save.js';
|
|
13
14
|
import { type RoomDraft, type RoomDraftParts, type RoomDraftWrite } from './room-draft.js';
|
|
14
15
|
import { type SyncStatus } from './status.js';
|
|
15
|
-
import { type RuntimeShell } from './durability.js';
|
|
16
|
-
import { type CodeAvailability, type Persistence, type Readiness
|
|
16
|
+
import { type RuntimeShell, type UnsentWork } from './durability.js';
|
|
17
|
+
import { type CodeAvailability, type Persistence, type Readiness } from './readiness.js';
|
|
17
18
|
import type { RuntimeDatabase } from './tables.js';
|
|
18
19
|
import { type NarrowedView, type PortReach, type RuntimeView } from './reach.js';
|
|
19
20
|
export type AppTypedSelection = {
|
|
@@ -54,6 +55,7 @@ export type MdRuntimeOptions = {
|
|
|
54
55
|
authorization?: Authorization;
|
|
55
56
|
signal?: AbortSignal;
|
|
56
57
|
recovery?: Recovery;
|
|
58
|
+
usableWhenHeld?: readonly string[];
|
|
57
59
|
};
|
|
58
60
|
export type SaveResult = {
|
|
59
61
|
outcome: 'saved';
|
|
@@ -93,7 +95,7 @@ export type HistoryQuery = {
|
|
|
93
95
|
};
|
|
94
96
|
export type MdRuntime = {
|
|
95
97
|
loaded(): Promise<void>;
|
|
96
|
-
rooms(): readonly AppRoom[]
|
|
98
|
+
rooms(): Promise<readonly AppRoom[]>;
|
|
97
99
|
query: {
|
|
98
100
|
(query: DocumentQuery): Promise<DocumentResult | PendingResult>;
|
|
99
101
|
(query: GroupQuery): Promise<GroupResult | PendingResult>;
|
|
@@ -115,6 +117,8 @@ export type MdRuntime = {
|
|
|
115
117
|
persistence(): boolean;
|
|
116
118
|
retry(): Promise<void>;
|
|
117
119
|
cleanUp(): Promise<number>;
|
|
120
|
+
unsent(): Promise<readonly UnsentWork[]>;
|
|
121
|
+
reset(): Promise<void>;
|
|
118
122
|
observe: {
|
|
119
123
|
(topic: 'rooms'): Promise<Observation<readonly AppRoom[]>>;
|
|
120
124
|
(topic: 'readiness'): Promise<Observation<Readiness>>;
|
|
@@ -123,6 +127,7 @@ export type MdRuntime = {
|
|
|
123
127
|
(topic: 'sync-status'): Promise<Observation<SyncStatus>>;
|
|
124
128
|
(topic: 'service-mode'): Promise<Observation<ServiceMode>>;
|
|
125
129
|
(topic: 'member'): Promise<Observation<Member | null>>;
|
|
130
|
+
(topic: 'authority-changes'): Promise<Observation<number>>;
|
|
126
131
|
(topic: 'query', query: DocumentQuery): Promise<Observation<DocumentResult | PendingResult>>;
|
|
127
132
|
(topic: 'query', query: GroupQuery): Promise<Observation<GroupResult | PendingResult>>;
|
|
128
133
|
(topic: 'queue', locator: string): Promise<Observation<readonly QueueEntry[]>>;
|
|
@@ -134,19 +139,15 @@ export type MdRuntime = {
|
|
|
134
139
|
};
|
|
135
140
|
reauthorize(): Promise<void>;
|
|
136
141
|
};
|
|
137
|
-
export type RuntimeTopic = 'rooms' | 'readiness' | 'connection-refusal' | 'storage-loss' | 'sync-status' | 'service-mode' | 'member' | 'query' | 'queue' | 'room-drafts' | 'presentation' | 'conversation' | 'conversations' | 'agents';
|
|
142
|
+
export type RuntimeTopic = 'rooms' | 'readiness' | 'connection-refusal' | 'storage-loss' | 'sync-status' | 'service-mode' | 'member' | 'authority-changes' | 'query' | 'queue' | 'room-drafts' | 'presentation' | 'conversation' | 'conversations' | 'agents';
|
|
138
143
|
export type ReadinessPort = {
|
|
139
144
|
readonly target: string;
|
|
140
145
|
readonly code: CodeAvailability;
|
|
141
|
-
readonly space: Space | null;
|
|
142
|
-
readonly search: SearchObligation;
|
|
143
146
|
};
|
|
144
147
|
export type ComposedRuntime = RuntimeView & {
|
|
145
148
|
seed(entry: EntrySeed): void;
|
|
146
149
|
stop(): Promise<void>;
|
|
147
|
-
lose(locators: readonly string[]): Promise<void>;
|
|
148
150
|
persisted(answer: Persistence): void;
|
|
149
|
-
shown(onScreen: boolean): void;
|
|
150
151
|
within(reach: PortReach | null, port: ReadinessPort): NarrowedView;
|
|
151
152
|
};
|
|
152
153
|
export declare function composeRuntime(options: MdRuntimeOptions): ComposedRuntime;
|