@agentshouse/mdruntime 0.1.0-cba6f2439bb25 → 0.1.0-cbe358f60d1d3
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 +66 -52
- package/dist/adapter.d.ts.map +1 -1
- package/dist/bootstrap.d.ts +6 -9
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +28 -22
- 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 +2 -4
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +1 -17
- package/dist/compile.d.ts +1 -6
- package/dist/compile.d.ts.map +1 -1
- package/dist/compile.js +91 -276
- package/dist/connection.d.ts +8 -8
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +738 -968
- 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 +15 -14
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +141 -167
- package/dist/durability.d.ts +6 -1
- package/dist/durability.d.ts.map +1 -1
- package/dist/entry.d.ts +2 -2
- package/dist/entry.d.ts.map +1 -1
- package/dist/entry.js +13 -5
- 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 +19 -9
- package/dist/memory.d.ts +9 -4
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +132 -82
- 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 +1 -3
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +0 -12
- package/dist/observation.d.ts +2 -2
- package/dist/observation.d.ts.map +1 -1
- package/dist/observation.js +7 -2
- package/dist/outcome.d.ts +0 -3
- package/dist/outcome.d.ts.map +1 -1
- 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 +7 -7
- package/dist/reach.d.ts.map +1 -1
- package/dist/reach.js +34 -45
- package/dist/react.d.ts +3 -1
- package/dist/react.d.ts.map +1 -1
- package/dist/readiness.d.ts +2 -15
- 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 +6 -4
- package/dist/refresh.d.ts.map +1 -1
- package/dist/refresh.js +26 -5
- package/dist/replica.d.ts +2 -2
- package/dist/replica.d.ts.map +1 -1
- package/dist/replica.js +2 -5
- package/dist/room-draft.d.ts +4 -3
- package/dist/room-draft.d.ts.map +1 -1
- package/dist/room-draft.js +65 -52
- package/dist/rows.d.ts +1 -17
- package/dist/rows.d.ts.map +1 -1
- package/dist/rows.js +4 -137
- 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 +0 -4
- package/dist/status.d.ts.map +1 -1
- package/dist/store.d.ts +5 -20
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +10 -44
- package/dist/stored.d.ts +0 -6
- package/dist/stored.d.ts.map +1 -1
- package/dist/stored.js +42 -115
- package/dist/tables.d.ts +10 -34
- package/dist/tables.d.ts.map +1 -1
- package/dist/tables.js +23 -57
- 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 +39 -97
- 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 -370
- package/dist/reads.d.ts +0 -11
- package/dist/reads.d.ts.map +0 -1
- package/dist/reads.js +0 -91
- package/dist/words.d.ts +0 -19
- package/dist/words.d.ts.map +0 -1
- package/dist/words.js +0 -156
package/dist/collection.d.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import { type Document } from '@agentshouse/mdmodel';
|
|
1
|
+
import { type Document, type TypedPath } from '@agentshouse/mdmodel';
|
|
2
2
|
import type { ModelState } from './model.js';
|
|
3
3
|
import type { MdModelIdentity } from './adapter.js';
|
|
4
|
-
import { type Paths } from './shared.js';
|
|
5
|
-
import type { Refused } from './transfer.js';
|
|
6
4
|
export declare const MD_MODEL: MdModelIdentity;
|
|
7
5
|
export type Collection = {
|
|
8
6
|
text: Readonly<Record<string, string>>;
|
|
@@ -15,6 +13,7 @@ export type Composition = {
|
|
|
15
13
|
roots: readonly string[];
|
|
16
14
|
model: ModelState;
|
|
17
15
|
} | null;
|
|
16
|
+
typedPaths: readonly TypedPath[];
|
|
18
17
|
};
|
|
19
18
|
export type Composed = {
|
|
20
19
|
readonly composition: Composition;
|
|
@@ -25,7 +24,6 @@ export declare function selected(composition: Composition, path: string): boolea
|
|
|
25
24
|
export declare function governing(composition: Composition, path: string): ModelState;
|
|
26
25
|
export declare function collectionOf(text: Readonly<Record<string, string>>, composition: Composition): Collection;
|
|
27
26
|
export declare function documentsOf(collection: Collection): Generator<number, Iterable<readonly [string, Document]>, void>;
|
|
28
|
-
export declare function unreadable(text: Paths<string>, paths?: Iterable<string> | null): Generator<number, Refused | null, void>;
|
|
29
27
|
export declare function validRoot(root: unknown): root is string;
|
|
30
28
|
export declare function available(composition: Composition): boolean;
|
|
31
29
|
//# sourceMappingURL=collection.d.ts.map
|
package/dist/collection.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collection.d.ts","sourceRoot":"","sources":["../src/collection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"collection.d.ts","sourceRoot":"","sources":["../src/collection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,QAAQ,EAAE,KAAK,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAErF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAIpD,eAAO,MAAM,QAAQ,EAAE,eAAwE,CAAC;AAEhG,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACvC,WAAW,EAAE,WAAW,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC;CAC9C,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,UAAU,CAAC;IAClB,SAAS,EAAE;QAAE,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;QAAC,KAAK,EAAE,UAAU,CAAA;KAAE,GAAG,IAAI,CAAC;IAClE,UAAU,EAAE,SAAS,SAAS,EAAE,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IAAE,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC;AAc3F,wBAAgB,UAAU,CAAC,WAAW,EAAE,WAAW,GAAG,QAAQ,CAS7D;AAED,wBAAgB,QAAQ,CAAC,WAAW,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAKxE;AAED,wBAAgB,SAAS,CAAC,WAAW,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,CAI5E;AAED,wBAAgB,YAAY,CAC1B,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EACtC,WAAW,EAAE,WAAW,GACvB,UAAU,CAcZ;AAED,wBAAiB,WAAW,CAC1B,UAAU,EAAE,UAAU,GACrB,SAAS,CAAC,MAAM,EAAE,QAAQ,CAAC,SAAS,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,CAQhE;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,MAAM,CAEvD;AAED,wBAAgB,SAAS,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAE3D"}
|
package/dist/collection.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { parse, VERSION } from '@agentshouse/mdmodel';
|
|
2
2
|
import { beneath, normalize } from './paths.js';
|
|
3
3
|
import { hashed } from './observation.js';
|
|
4
|
-
import {
|
|
5
|
-
import { ROW_WEIGHT } from './turn.js';
|
|
4
|
+
import { sortedKeys } from './shared.js';
|
|
6
5
|
export const MD_MODEL = { identity: '@agentshouse/mdmodel', version: VERSION };
|
|
7
6
|
const typesPrinted = new WeakMap();
|
|
8
7
|
function typesPrint(model) {
|
|
@@ -61,21 +60,6 @@ export function* documentsOf(collection) {
|
|
|
61
60
|
}
|
|
62
61
|
})();
|
|
63
62
|
}
|
|
64
|
-
export function* unreadable(text, paths = null) {
|
|
65
|
-
const named = paths ?? (yield* keysIn(text));
|
|
66
|
-
let least = null;
|
|
67
|
-
for (const path of named) {
|
|
68
|
-
const content = Object.hasOwn(text, path) ? text[path] : undefined;
|
|
69
|
-
if (content === undefined)
|
|
70
|
-
continue;
|
|
71
|
-
const read = parse(content, path);
|
|
72
|
-
if (!read.ok && (least === null || path < least.path)) {
|
|
73
|
-
least = { path, refused: { kind: 'refused', refusal: read.refusal } };
|
|
74
|
-
}
|
|
75
|
-
yield ROW_WEIGHT + content.length;
|
|
76
|
-
}
|
|
77
|
-
return least?.refused ?? null;
|
|
78
|
-
}
|
|
79
63
|
export function validRoot(root) {
|
|
80
64
|
return typeof root === 'string' && normalize(root) === root;
|
|
81
65
|
}
|
package/dist/compile.d.ts
CHANGED
|
@@ -1,16 +1,11 @@
|
|
|
1
1
|
import type { Plan, QueryRows } from './query.js';
|
|
2
|
-
import type { Connection
|
|
2
|
+
import type { Connection } from './tables.js';
|
|
3
3
|
export type QueryRoom = {
|
|
4
4
|
readonly locator: string;
|
|
5
5
|
readonly key: number;
|
|
6
6
|
};
|
|
7
|
-
export type Fragment = {
|
|
8
|
-
readonly sql: string;
|
|
9
|
-
readonly bind: readonly Value[];
|
|
10
|
-
};
|
|
11
7
|
export type QueryAnswer = QueryRows & {
|
|
12
8
|
readonly more?: string;
|
|
13
9
|
};
|
|
14
|
-
export declare function selected(connection: Connection, plan: Plan, rooms: readonly QueryRoom[]): Fragment;
|
|
15
10
|
export declare function answerQuery(connection: Connection, plan: Plan, rooms: readonly QueryRoom[], budget?: number | null): QueryAnswer;
|
|
16
11
|
//# sourceMappingURL=compile.d.ts.map
|
package/dist/compile.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../src/compile.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../src/compile.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,IAAI,EAAuC,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvF,OAAO,KAAK,EAAE,UAAU,EAAc,MAAM,aAAa,CAAC;AAG1D,MAAM,MAAM,SAAS,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AA+a3E,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG;IAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAkUjE,wBAAgB,WAAW,CACzB,UAAU,EAAE,UAAU,EACtB,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,SAAS,SAAS,EAAE,EAC3B,MAAM,GAAE,MAAM,GAAG,IAAW,GAC3B,WAAW,CAUb"}
|
package/dist/compile.js
CHANGED
|
@@ -1,125 +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 balanced(parts, separator) {
|
|
16
|
-
if (parts.length === 1)
|
|
17
|
-
return grouped(parts[0]);
|
|
18
|
-
const half = Math.ceil(parts.length / 2);
|
|
19
|
-
return grouped(joined([balanced(parts.slice(0, half), separator), balanced(parts.slice(half), separator)], separator));
|
|
20
|
-
}
|
|
21
|
-
function all(parts) {
|
|
22
|
-
return parts.length === 0 ? fragment('1') : balanced(parts, ' AND ');
|
|
23
|
-
}
|
|
24
|
-
function any(parts) {
|
|
25
|
-
return parts.length === 0 ? fragment('0') : balanced(parts, ' OR ');
|
|
26
|
-
}
|
|
27
|
-
function grouped(part) {
|
|
28
|
-
return { sql: `(${part.sql})`, bind: part.bind };
|
|
29
|
-
}
|
|
30
|
-
function list(values) {
|
|
31
|
-
return fragment(`(${values.map(() => '?').join(', ')})`, values);
|
|
32
|
-
}
|
|
33
|
-
function sqlValue(value) {
|
|
34
|
-
if (value === null)
|
|
35
|
-
return { kind: 'null', value: null };
|
|
36
|
-
if (typeof value === 'boolean')
|
|
37
|
-
return { kind: 'boolean', value: value ? 1 : 0 };
|
|
38
|
-
if (typeof value === 'number')
|
|
39
|
-
return { kind: 'number', value };
|
|
40
|
-
return { kind: 'string', value };
|
|
41
|
-
}
|
|
42
|
-
function same(alias, value) {
|
|
43
|
-
const held = sqlValue(value);
|
|
44
|
-
return held.kind === 'null'
|
|
45
|
-
? fragment(`${alias}.kind = 'null'`)
|
|
46
|
-
: fragment(`${alias}.kind = ? AND ${alias}.value = ?`, [held.kind, held.value]);
|
|
47
|
-
}
|
|
48
|
-
const BOUNDS = { gt: '>', gte: '>=', lt: '<', lte: '<=' };
|
|
49
|
-
function pointed(alias, field, reach) {
|
|
50
|
-
const { keys, places, glob } = placedOf(field, reach);
|
|
51
|
-
return fragment(`${alias}.keys = ? AND ${alias}.places ${glob ? 'GLOB' : '='} ?`, [keys, places]);
|
|
52
|
-
}
|
|
53
|
-
function heldValues(doc, field, alias, where) {
|
|
54
|
-
return joined([
|
|
55
|
-
fragment(`SELECT 1 FROM replica_values ${alias} WHERE ${alias}.doc = ${doc}.id AND `),
|
|
56
|
-
grouped(pointed(alias, field, 'value')),
|
|
57
|
-
fragment(' AND '),
|
|
58
|
-
grouped(where),
|
|
59
|
-
], '');
|
|
60
|
-
}
|
|
61
|
-
function exists(part) {
|
|
62
|
-
return { sql: `EXISTS (${part.sql})`, bind: part.bind };
|
|
63
|
-
}
|
|
64
|
-
function itemOf(held, where) {
|
|
65
|
-
return exists(joined([
|
|
66
|
-
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 `),
|
|
67
|
-
grouped(where),
|
|
68
|
-
], ''));
|
|
69
|
-
}
|
|
70
|
-
function matching(held, values) {
|
|
71
|
-
return any(values.map((value) => any([
|
|
72
|
-
same(held, value),
|
|
73
|
-
all([fragment(`${held}.kind = 'array'`), itemOf(held, same('i', value))]),
|
|
74
|
-
])));
|
|
75
|
-
}
|
|
76
|
-
function tested(doc, field, test) {
|
|
77
|
-
const reached = exists(heldValues(doc, field, 'r', fragment('r.item = -1')));
|
|
78
|
-
if (test.op === 'exists')
|
|
79
|
-
return test.exists ? reached : fragment(`NOT ${reached.sql}`, reached.bind);
|
|
80
|
-
if (test.op === 'eq' || test.op === 'in') {
|
|
81
|
-
const values = test.op === 'eq' ? [test.value] : test.values;
|
|
82
|
-
return exists(heldValues(doc, field, 'v', any(values.map((value) => same('v', value)))));
|
|
83
|
-
}
|
|
84
|
-
if (test.op === 'ne' || test.op === 'nin') {
|
|
85
|
-
const values = test.op === 'ne' ? [test.value] : test.values;
|
|
86
|
-
const unmatched = matching('h', values);
|
|
87
|
-
return any([
|
|
88
|
-
fragment(`NOT ${reached.sql}`, reached.bind),
|
|
89
|
-
exists(heldValues(doc, field, 'h', all([fragment('h.item = -1'), fragment(`NOT (${unmatched.sql})`, unmatched.bind)]))),
|
|
90
|
-
]);
|
|
91
|
-
}
|
|
92
|
-
if (test.op === 'range') {
|
|
93
|
-
return exists(heldValues(doc, field, 'v', all([
|
|
94
|
-
fragment('v.item = -1'),
|
|
95
|
-
...test.bounds.map(([operator, bound]) => {
|
|
96
|
-
const held = sqlValue(bound);
|
|
97
|
-
return fragment(`v.kind = ? AND v.value ${BOUNDS[operator]} ?`, [
|
|
98
|
-
held.kind,
|
|
99
|
-
held.value,
|
|
100
|
-
]);
|
|
101
|
-
}),
|
|
102
|
-
])));
|
|
103
|
-
}
|
|
104
|
-
if (test.op === 'all') {
|
|
105
|
-
return exists(heldValues(doc, field, 'h', all([
|
|
106
|
-
fragment("h.item = -1 AND h.kind = 'array'"),
|
|
107
|
-
...test.values.map((value) => itemOf('h', same('i', value))),
|
|
108
|
-
])));
|
|
109
|
-
}
|
|
110
|
-
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
|
+
]);
|
|
111
16
|
}
|
|
112
|
-
function
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
return
|
|
117
|
-
|
|
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
|
+
});
|
|
118
23
|
}
|
|
119
|
-
function
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
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
|
+
]);
|
|
123
34
|
}
|
|
124
35
|
function reached(bound, alias) {
|
|
125
36
|
const reach = bound.reach;
|
|
@@ -133,42 +44,20 @@ function reached(bound, alias) {
|
|
|
133
44
|
const key = bound.keys.get(roomOfKey(held));
|
|
134
45
|
return key === undefined ? [] : [[key, pathOfKey(held)]];
|
|
135
46
|
});
|
|
136
|
-
const
|
|
47
|
+
const outside = any(reach.areas.flatMap((area) => {
|
|
137
48
|
const key = bound.keys.get(area.room);
|
|
138
|
-
return key === undefined ? [] : [
|
|
139
|
-
});
|
|
140
|
-
const beneath = (area) => fragment(`${alias}.key = ? AND (${alias}.path = ? OR (${alias}.path >= ? AND ${alias}.path < ?))`, [area.key, area.path, `${area.path}/`, `${area.path}0`]);
|
|
141
|
-
const typed = (types) => fragment(`${alias}.type IN ${list(types).sql}`, types);
|
|
142
|
-
const outside = any(areas.map((area) => area.types.length === 0
|
|
143
|
-
? beneath(area)
|
|
144
|
-
: all([beneath(area), fragment(`NOT ${grouped(typed(area.types)).sql}`, area.types)])));
|
|
49
|
+
return key === undefined ? [] : [fenced(alias, key, area, false)];
|
|
50
|
+
}));
|
|
145
51
|
return all([
|
|
146
52
|
any([
|
|
147
|
-
...(rooms.length === 0 ? [] : [fragment(`${alias}.key IN ${
|
|
53
|
+
...(rooms.length === 0 ? [] : [fragment(`${alias}.key IN ${listed(rooms).sql}`, rooms)]),
|
|
148
54
|
...(documents.length === 0
|
|
149
55
|
? []
|
|
150
56
|
: [
|
|
151
57
|
fragment(`EXISTS (SELECT 1 FROM json_each(?) j WHERE j.value ->> 0 = ${alias}.key AND j.value ->> 1 = ${alias}.path)`, [JSON.stringify(documents)]),
|
|
152
58
|
]),
|
|
153
|
-
...areas.flatMap((area) => area.types.length === 0 ? [] : [all([beneath(area), typed(area.types)])]),
|
|
154
59
|
]),
|
|
155
|
-
...(areas.length === 0 ? [] : [fragment(`NOT ${grouped(outside).sql}`, outside.bind)]),
|
|
156
|
-
]);
|
|
157
|
-
}
|
|
158
|
-
function scoped(alias, scope) {
|
|
159
|
-
return all([
|
|
160
|
-
...(scope.types === null
|
|
161
|
-
? []
|
|
162
|
-
: [fragment(`${alias}.type IN ${list(scope.types).sql}`, scope.types)]),
|
|
163
|
-
...(scope.pathPrefix === null || scope.pathPrefix === ''
|
|
164
|
-
? []
|
|
165
|
-
: [
|
|
166
|
-
fragment(`${alias}.path >= ? AND ${alias}.path < ?`, [
|
|
167
|
-
`${scope.pathPrefix}/`,
|
|
168
|
-
`${scope.pathPrefix}0`,
|
|
169
|
-
]),
|
|
170
|
-
]),
|
|
171
|
-
...(scope.where === null ? [] : [conditioned(alias, scope.where)]),
|
|
60
|
+
...(reach.areas.length === 0 ? [] : [fragment(`NOT ${grouped(outside).sql}`, outside.bind)]),
|
|
172
61
|
]);
|
|
173
62
|
}
|
|
174
63
|
function related(bound, plan) {
|
|
@@ -176,17 +65,17 @@ function related(bound, plan) {
|
|
|
176
65
|
if (plan.hop !== null) {
|
|
177
66
|
parts.push(exists(joined([
|
|
178
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`),
|
|
179
|
-
grouped(
|
|
68
|
+
grouped(sql.placed('l', plan.hop.field, 'link')),
|
|
180
69
|
fragment('AND'),
|
|
181
|
-
grouped(all([scoped('m', plan.hop), reached(bound, 'm')])),
|
|
70
|
+
grouped(all([sql.scoped('m', plan.hop), reached(bound, 'm')])),
|
|
182
71
|
], ' ')));
|
|
183
72
|
}
|
|
184
73
|
if (plan.backlinks !== null) {
|
|
185
74
|
const field = plan.backlinks.field;
|
|
186
75
|
parts.push(exists(joined([
|
|
187
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`),
|
|
188
|
-
...(field === null ? [] : [grouped(
|
|
189
|
-
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')])),
|
|
190
79
|
], ' ')));
|
|
191
80
|
}
|
|
192
81
|
return parts;
|
|
@@ -194,11 +83,9 @@ function related(bound, plan) {
|
|
|
194
83
|
function filtered(bound, plan) {
|
|
195
84
|
const keys = bound.rooms.map(({ key }) => key);
|
|
196
85
|
return all([
|
|
197
|
-
fragment(`d.key IN ${
|
|
198
|
-
...(plan.paths === null ? [] : [fragment(`d.path IN ${list(plan.paths).sql}`, plan.paths)]),
|
|
199
|
-
...(plan.folder === null ? [] : [fragment('d.folder = ?', [plan.folder])]),
|
|
86
|
+
fragment(`d.key IN ${listed(keys).sql} AND ${VISIBLE('d')}`, keys),
|
|
200
87
|
reached(bound, 'd'),
|
|
201
|
-
|
|
88
|
+
sql.tests('d', plan),
|
|
202
89
|
...related(bound, plan),
|
|
203
90
|
]);
|
|
204
91
|
}
|
|
@@ -229,103 +116,25 @@ const GROUP_TIES = {
|
|
|
229
116
|
locale: undefined,
|
|
230
117
|
localeOptions: undefined,
|
|
231
118
|
};
|
|
232
|
-
function
|
|
233
|
-
if (value === null || value === undefined) {
|
|
234
|
-
return { placement: ordering.nulls === 'first' ? 0 : 2, klass: 0, scalar: null };
|
|
235
|
-
}
|
|
236
|
-
if (typeof value === 'boolean')
|
|
237
|
-
return { placement: 1, klass: 1, scalar: value ? 1 : 0 };
|
|
238
|
-
if (typeof value === 'number')
|
|
239
|
-
return { placement: 1, klass: 1, scalar: value };
|
|
240
|
-
if (typeof value === 'string')
|
|
241
|
-
return { placement: 1, klass: 2, scalar: value };
|
|
242
|
-
return { placement: 1, klass: 3, scalar: JSON.stringify(value) };
|
|
243
|
-
}
|
|
244
|
-
function placement(term) {
|
|
245
|
-
const nulls = term.ordering.nulls === 'first' ? 0 : 2;
|
|
246
|
-
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]);
|
|
247
|
-
}
|
|
248
|
-
function klass(term) {
|
|
249
|
-
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);
|
|
250
|
-
}
|
|
251
|
-
function classed(term, which) {
|
|
252
|
-
const kinds = which === 1 ? "('boolean', 'number')" : which === 2 ? "('string')" : "('array')";
|
|
253
|
-
return fragment(`(CASE WHEN ${term.kind.sql} IN ${kinds} THEN ${term.value.sql} END)`, [
|
|
254
|
-
...term.kind.bind,
|
|
255
|
-
...term.value.bind,
|
|
256
|
-
]);
|
|
257
|
-
}
|
|
258
|
-
function collated(bound, term, which) {
|
|
259
|
-
if (which === 1)
|
|
260
|
-
return '';
|
|
261
|
-
const name = bound.collate(term.ordering, which === 3, term.total === true);
|
|
262
|
-
return name === null ? '' : ` COLLATE ${name}`;
|
|
263
|
-
}
|
|
264
|
-
function sorted(bound, term) {
|
|
265
|
-
const direction = term.ordering.direction === 'desc' ? 'DESC' : 'ASC';
|
|
266
|
-
return joined([
|
|
267
|
-
placement(term),
|
|
268
|
-
fragment(`${klass(term).sql} ${direction}`, klass(term).bind),
|
|
269
|
-
...[1, 2, 3].map((which) => {
|
|
270
|
-
const value = classed(term, which);
|
|
271
|
-
return fragment(`${value.sql}${collated(bound, term, which)} ${direction}`, value.bind);
|
|
272
|
-
}),
|
|
273
|
-
], ', ');
|
|
274
|
-
}
|
|
275
|
-
function beyond(bound, term, value) {
|
|
276
|
-
const held = classOf(value, term.ordering);
|
|
277
|
-
const place = placement(term);
|
|
278
|
-
if (held.placement !== 1) {
|
|
279
|
-
return {
|
|
280
|
-
beyond: fragment(`${place.sql} > ${held.placement}`, place.bind),
|
|
281
|
-
equal: fragment(`${place.sql} = ${held.placement}`, place.bind),
|
|
282
|
-
};
|
|
283
|
-
}
|
|
284
|
-
const after = term.ordering.direction === 'desc' ? '<' : '>';
|
|
285
|
-
const kind = klass(term);
|
|
286
|
-
const scalar = classed(term, held.klass);
|
|
287
|
-
const collation = collated(bound, term, held.klass);
|
|
288
|
-
return {
|
|
289
|
-
beyond: any([
|
|
290
|
-
fragment(`${place.sql} > 1`, place.bind),
|
|
291
|
-
all([
|
|
292
|
-
fragment(`${place.sql} = 1`, place.bind),
|
|
293
|
-
any([
|
|
294
|
-
fragment(`${kind.sql} ${after} ${held.klass}`, kind.bind),
|
|
295
|
-
all([
|
|
296
|
-
fragment(`${kind.sql} = ${held.klass}`, kind.bind),
|
|
297
|
-
fragment(`${scalar.sql} ${after} ?${collation}`, [...scalar.bind, held.scalar]),
|
|
298
|
-
]),
|
|
299
|
-
]),
|
|
300
|
-
]),
|
|
301
|
-
]),
|
|
302
|
-
equal: all([
|
|
303
|
-
fragment(`${place.sql} = 1 AND ${kind.sql} = ${held.klass}`, [...place.bind, ...kind.bind]),
|
|
304
|
-
fragment(`${scalar.sql} = ?${collation}`, [...scalar.bind, held.scalar]),
|
|
305
|
-
]),
|
|
306
|
-
};
|
|
307
|
-
}
|
|
308
|
-
function following(parts, tie) {
|
|
309
|
-
let condition = tie;
|
|
310
|
-
for (const part of [...parts].reverse()) {
|
|
311
|
-
condition = any([part.beyond, all([part.equal, condition])]);
|
|
312
|
-
}
|
|
313
|
-
return condition;
|
|
314
|
-
}
|
|
315
|
-
function keyTerm(bound, key, ordering, index) {
|
|
119
|
+
function keyTerm(key, ordering, index) {
|
|
316
120
|
if (key.of === 'field') {
|
|
317
121
|
const alias = `o${index}`;
|
|
318
122
|
return {
|
|
319
|
-
term: {
|
|
123
|
+
term: {
|
|
124
|
+
ordering,
|
|
125
|
+
kind: fragment(`${alias}.kind`),
|
|
126
|
+
value: fragment(`${alias}.value`),
|
|
127
|
+
instant: fragment(`${alias}.instant`),
|
|
128
|
+
},
|
|
320
129
|
join: joined([
|
|
321
130
|
fragment(`LEFT JOIN replica_values ${alias} ON ${alias}.doc = d.id AND `),
|
|
322
|
-
grouped(
|
|
131
|
+
grouped(sql.placed(alias, key.field, 'exact')),
|
|
323
132
|
fragment(` AND ${alias}.item = -1 AND ${alias}.kind NOT IN ('object', 'undefined')`),
|
|
324
133
|
], ''),
|
|
325
134
|
};
|
|
326
135
|
}
|
|
327
136
|
const expression = key.of === 'room'
|
|
328
|
-
? located(
|
|
137
|
+
? located('d')
|
|
329
138
|
: key.of === 'path'
|
|
330
139
|
? fragment('d.path')
|
|
331
140
|
: key.of === 'type'
|
|
@@ -351,13 +160,20 @@ function decoded(kind, value) {
|
|
|
351
160
|
return JSON.parse(value);
|
|
352
161
|
return null;
|
|
353
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
|
+
}
|
|
354
167
|
function decodedKey(key, row, index) {
|
|
355
168
|
if (key.of === 'field') {
|
|
356
169
|
const kind = row[`k${index}`];
|
|
357
|
-
return kind === null || kind === undefined ? undefined :
|
|
170
|
+
return kind === null || kind === undefined ? undefined : sortedValue(row, index);
|
|
358
171
|
}
|
|
359
172
|
return row[`v${index}`] ?? null;
|
|
360
173
|
}
|
|
174
|
+
function instantOf(term) {
|
|
175
|
+
return term.instant ?? fragment('NULL');
|
|
176
|
+
}
|
|
361
177
|
const registered = new WeakMap();
|
|
362
178
|
function hashed(text) {
|
|
363
179
|
let hash = 0x811c9dc5;
|
|
@@ -407,9 +223,6 @@ function collating(connection) {
|
|
|
407
223
|
return name;
|
|
408
224
|
};
|
|
409
225
|
}
|
|
410
|
-
function bodied(shape) {
|
|
411
|
-
return shape.sections !== null || shape.preamble || shape.markdown;
|
|
412
|
-
}
|
|
413
226
|
function masked(pointers) {
|
|
414
227
|
const root = { whole: false, members: new Map() };
|
|
415
228
|
for (const pointer of pointers) {
|
|
@@ -500,7 +313,7 @@ function documentOf(shape, room, row, linked) {
|
|
|
500
313
|
? {}
|
|
501
314
|
: { sections: sectionsOf(body.sections, shape.sections) }),
|
|
502
315
|
...(shape.preamble && body !== null ? { preamble: body.preamble } : {}),
|
|
503
|
-
...(shape.markdown
|
|
316
|
+
...(shape.markdown ? { markdown: row.content } : {}),
|
|
504
317
|
...(shape.backlinks ? { backlinks: linked.get(documentKey(room, path)) ?? [] } : {}),
|
|
505
318
|
...(shape.change
|
|
506
319
|
? {
|
|
@@ -534,10 +347,10 @@ function backlinksOf(connection, bound, rows) {
|
|
|
534
347
|
return linked;
|
|
535
348
|
}
|
|
536
349
|
function documents(connection, bound, plan, shape, budget) {
|
|
537
|
-
const terms = shape.orderBy.map(({ key, options }, index) => keyTerm(
|
|
350
|
+
const terms = shape.orderBy.map(({ key, options }, index) => keyTerm(key, orderingOf(options), index));
|
|
538
351
|
const filter = filtered(bound, plan);
|
|
539
352
|
const cursor = plan.after?.values ?? null;
|
|
540
|
-
const room = located(
|
|
353
|
+
const room = located('d');
|
|
541
354
|
const tie = cursor === null
|
|
542
355
|
? null
|
|
543
356
|
: (() => {
|
|
@@ -553,19 +366,20 @@ function documents(connection, bound, plan, shape, budget) {
|
|
|
553
366
|
})();
|
|
554
367
|
const after = cursor === null || tie === null
|
|
555
368
|
? null
|
|
556
|
-
: 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);
|
|
557
370
|
const selected = joined([
|
|
558
371
|
fragment('SELECT d.id, d.key, d.path, d.type, d.binary, d.revision, d.fields, d.change, d.file_id'),
|
|
559
372
|
...terms.map(({ term }, index) => joined([
|
|
560
373
|
fragment(`, ${term.kind.sql} AS k${index}`, term.kind.bind),
|
|
561
374
|
fragment(`, ${term.value.sql} AS v${index}`, term.value.bind),
|
|
375
|
+
fragment(`, ${instantOf(term).sql} AS i${index}`, instantOf(term).bind),
|
|
562
376
|
], '')),
|
|
563
377
|
fragment(' FROM replica_entries d'),
|
|
564
378
|
...terms.flatMap(({ join }) => (join === null ? [] : [fragment(' '), join])),
|
|
565
379
|
fragment(' WHERE '),
|
|
566
380
|
after === null ? filter : all([filter, after]),
|
|
567
381
|
fragment(' ORDER BY '),
|
|
568
|
-
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')], ', '),
|
|
569
383
|
...(plan.limit === null ? [] : [fragment(' LIMIT ?', [plan.limit + 1])]),
|
|
570
384
|
], '');
|
|
571
385
|
const rows = connection.rows(selected.sql, selected.bind);
|
|
@@ -604,7 +418,7 @@ function withContent(connection, rows, budget) {
|
|
|
604
418
|
return rows;
|
|
605
419
|
const ids = rows.map((row) => row.id);
|
|
606
420
|
const sizes = new Map(connection
|
|
607
|
-
.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)
|
|
608
422
|
.map((row) => [row.id, Number(row.size ?? 0)]));
|
|
609
423
|
let cut = rows.length;
|
|
610
424
|
let spent = 0;
|
|
@@ -619,34 +433,30 @@ function withContent(connection, rows, budget) {
|
|
|
619
433
|
const kept = rows.slice(0, cut);
|
|
620
434
|
const read = kept.map((row) => row.id);
|
|
621
435
|
const held = new Map(connection
|
|
622
|
-
.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)
|
|
623
437
|
.map((row) => [row.id, row.content]));
|
|
624
438
|
return kept.map((row) => ({ ...row, content: held.get(row.id) ?? null }));
|
|
625
439
|
}
|
|
626
440
|
function storedFolders(bound, plan) {
|
|
627
|
-
if (plan.paths !== null || plan.
|
|
441
|
+
if (plan.paths !== null || plan.fileIds !== null)
|
|
442
|
+
return null;
|
|
443
|
+
if (plan.hop !== null || plan.backlinks !== null)
|
|
628
444
|
return null;
|
|
629
445
|
const whole = bound.rooms.filter(({ locator }) => bound.reach === null || bound.reach.rooms.includes(locator));
|
|
630
446
|
if (whole.length === 0)
|
|
631
447
|
return null;
|
|
632
448
|
const keys = whole.map(({ key }) => key);
|
|
633
449
|
const prefix = plan.root.pathPrefix;
|
|
634
|
-
const
|
|
450
|
+
const outside = (bound.reach?.areas ?? []).flatMap((area) => {
|
|
635
451
|
const key = bound.keys.get(area.room);
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
key,
|
|
641
|
-
area.path,
|
|
642
|
-
`${area.path}/`,
|
|
643
|
-
`${area.path}0`,
|
|
644
|
-
]),
|
|
645
|
-
];
|
|
452
|
+
if (key === undefined)
|
|
453
|
+
return [];
|
|
454
|
+
const fence = fenced('f', key, area, true);
|
|
455
|
+
return [fragment(`NOT ${grouped(fence).sql}`, fence.bind)];
|
|
646
456
|
});
|
|
647
457
|
return all([
|
|
648
|
-
fragment(`f.key IN ${
|
|
649
|
-
...
|
|
458
|
+
fragment(`f.key IN ${listed(keys).sql} AND f.layer = 0 AND f.present = 1`, keys),
|
|
459
|
+
...outside,
|
|
650
460
|
...(prefix === null || prefix === ''
|
|
651
461
|
? []
|
|
652
462
|
: [
|
|
@@ -661,7 +471,7 @@ function storedFolders(bound, plan) {
|
|
|
661
471
|
}
|
|
662
472
|
function groups(connection, bound, plan, shape) {
|
|
663
473
|
const keyed = shape.groupBy.map((key, index) => {
|
|
664
|
-
const { term, join } = keyTerm(
|
|
474
|
+
const { term, join } = keyTerm(key, GROUP_ORDER, index);
|
|
665
475
|
const kind = fragment(`COALESCE(${term.kind.sql}, 'null')`, term.kind.bind);
|
|
666
476
|
return { term: { ...term, kind }, join };
|
|
667
477
|
});
|
|
@@ -671,6 +481,7 @@ function groups(connection, bound, plan, shape) {
|
|
|
671
481
|
joined(keyed.map(({ term }, index) => joined([
|
|
672
482
|
fragment(`${term.kind.sql} AS k${index}`, term.kind.bind),
|
|
673
483
|
fragment(`, ${term.value.sql} AS v${index}`, term.value.bind),
|
|
484
|
+
fragment(`, ${instantOf(term).sql} AS i${index}`, instantOf(term).bind),
|
|
674
485
|
], '')), ', '),
|
|
675
486
|
fragment(', 1 AS n FROM replica_entries d'),
|
|
676
487
|
...keyed.flatMap(({ join }) => (join === null ? [] : [fragment(' '), join])),
|
|
@@ -684,10 +495,15 @@ function groups(connection, bound, plan, shape) {
|
|
|
684
495
|
? inner
|
|
685
496
|
: joined([
|
|
686
497
|
inner,
|
|
687
|
-
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 "),
|
|
688
499
|
folders,
|
|
689
500
|
], '');
|
|
690
|
-
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(', ');
|
|
691
507
|
const counted = {
|
|
692
508
|
ordering: { ...GROUP_ORDER },
|
|
693
509
|
kind: fragment("'number'"),
|
|
@@ -700,7 +516,7 @@ function groups(connection, bound, plan, shape) {
|
|
|
700
516
|
});
|
|
701
517
|
const ordered = shape.orderBy.map(({ by, direction }) => by === 'count'
|
|
702
518
|
? { ...counted, ordering: { ...GROUP_ORDER, direction } }
|
|
703
|
-
: outer(by, { ...GROUP_ORDER, direction }));
|
|
519
|
+
: { ...outer(by, { ...GROUP_ORDER, direction }), instant: fragment(`i${by}`) });
|
|
704
520
|
const ties = keyed.flatMap((_, index) => [
|
|
705
521
|
{ ...outer(index, GROUP_TIES), total: true },
|
|
706
522
|
{ ordering: GROUP_TIES, kind: fragment("'string'"), value: fragment(`k${index}`) },
|
|
@@ -710,19 +526,21 @@ function groups(connection, bound, plan, shape) {
|
|
|
710
526
|
? null
|
|
711
527
|
: cursor[shape.orderBy.length].flatMap((value) => [
|
|
712
528
|
value,
|
|
713
|
-
|
|
529
|
+
heldKind(value ?? null),
|
|
714
530
|
]);
|
|
715
531
|
const after = cursor === null || tieValues === null
|
|
716
532
|
? null
|
|
717
|
-
: following(ordered.map((term, index) => beyond(bound, term, cursor[index])), following(ties
|
|
718
|
-
|
|
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}`)], '');
|
|
719
537
|
const windowed = joined([
|
|
720
538
|
fragment('SELECT * FROM ('),
|
|
721
539
|
grouping,
|
|
722
540
|
fragment(')'),
|
|
723
541
|
...(after === null ? [] : [fragment(' WHERE '), after]),
|
|
724
542
|
fragment(' ORDER BY '),
|
|
725
|
-
joined([...ordered, ...ties].map((term) => sorted(bound, term)), ', '),
|
|
543
|
+
joined([...ordered, ...ties].map((term) => sql.sorted(bound.collate, term)), ', '),
|
|
726
544
|
...(plan.limit === null ? [] : [fragment(' LIMIT ?', [plan.limit + 1])]),
|
|
727
545
|
], '');
|
|
728
546
|
const rows = connection.rows(windowed.sql, windowed.bind);
|
|
@@ -735,7 +553,7 @@ function groups(connection, bound, plan, shape) {
|
|
|
735
553
|
: last === undefined
|
|
736
554
|
? (plan.after?.text ?? FROM_START)
|
|
737
555
|
: cursorOf([
|
|
738
|
-
...shape.orderBy.map(({ by }) => by === 'count' ? Number(last.n) :
|
|
556
|
+
...shape.orderBy.map(({ by }) => by === 'count' ? Number(last.n) : sortedValue(last, by)),
|
|
739
557
|
keyOf(last),
|
|
740
558
|
]);
|
|
741
559
|
const total = plan.total
|
|
@@ -755,9 +573,6 @@ function boundOf(connection, plan, rooms) {
|
|
|
755
573
|
collate: collating(connection),
|
|
756
574
|
};
|
|
757
575
|
}
|
|
758
|
-
export function selected(connection, plan, rooms) {
|
|
759
|
-
return filtered(boundOf(connection, plan, rooms), plan);
|
|
760
|
-
}
|
|
761
576
|
export function answerQuery(connection, plan, rooms, budget = null) {
|
|
762
577
|
const bound = boundOf(connection, plan, rooms);
|
|
763
578
|
if (rooms.length === 0) {
|