@agentshouse/mdruntime 0.1.0-cd9e28a590f84 → 0.1.0-cdded6c080913
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/acceptance.d.ts +6 -0
- package/dist/acceptance.d.ts.map +1 -0
- package/dist/acceptance.js +389 -0
- package/dist/actions.d.ts +20 -0
- package/dist/actions.d.ts.map +1 -0
- package/dist/actions.js +250 -0
- package/dist/adapter.d.ts +23 -25
- 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 +21 -56
- package/dist/bootstrap.d.ts +8 -4
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +209 -78
- package/dist/cell.d.ts +6 -0
- package/dist/cell.d.ts.map +1 -0
- package/dist/cell.js +9 -0
- package/dist/chain.d.ts +2 -1
- package/dist/chain.d.ts.map +1 -1
- package/dist/change.d.ts +1 -0
- package/dist/change.d.ts.map +1 -1
- package/dist/chat-types.d.ts +5 -0
- package/dist/chat-types.d.ts.map +1 -0
- package/dist/chat-types.js +13 -0
- package/dist/client.d.ts +17 -2
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +3 -0
- package/dist/collection.d.ts +2 -1
- package/dist/collection.d.ts.map +1 -1
- package/dist/compile.d.ts +7 -7
- package/dist/compile.d.ts.map +1 -1
- package/dist/compile.js +229 -301
- package/dist/connection.d.ts +5 -141
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +98 -5279
- package/dist/context.d.ts +2 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +7 -0
- package/dist/conversation-row.d.ts +33 -0
- package/dist/conversation-row.d.ts.map +1 -0
- package/dist/conversation-row.js +53 -0
- package/dist/conversation.d.ts +16 -6
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +366 -216
- package/dist/discovery.d.ts +10 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +175 -0
- package/dist/durability.d.ts +15 -0
- 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 +17 -8
- package/dist/figures.d.ts +48 -0
- package/dist/figures.d.ts.map +1 -0
- package/dist/figures.js +197 -0
- package/dist/holdings.d.ts +29 -0
- package/dist/holdings.d.ts.map +1 -0
- package/dist/holdings.js +95 -0
- package/dist/host.d.ts +2 -2
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +22 -15
- 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 +19 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/install.d.ts +56 -0
- package/dist/install.d.ts.map +1 -0
- package/dist/install.js +560 -0
- package/dist/job.d.ts +33 -0
- package/dist/job.d.ts.map +1 -0
- package/dist/job.js +54 -0
- package/dist/lifecycle.d.ts +7 -0
- package/dist/lifecycle.d.ts.map +1 -0
- package/dist/lifecycle.js +267 -0
- package/dist/listing.d.ts +53 -0
- package/dist/listing.d.ts.map +1 -0
- package/dist/listing.js +175 -0
- package/dist/live.d.ts +5 -4
- package/dist/live.d.ts.map +1 -1
- package/dist/live.js +62 -20
- package/dist/locks.d.ts +9 -0
- package/dist/locks.d.ts.map +1 -0
- package/dist/locks.js +61 -0
- package/dist/log.d.ts +1 -0
- package/dist/log.d.ts.map +1 -1
- package/dist/lost.d.ts +5 -0
- package/dist/lost.d.ts.map +1 -0
- package/dist/lost.js +61 -0
- package/dist/memory.d.ts +4 -1
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +43 -4
- package/dist/messages.d.ts +25 -1
- package/dist/messages.d.ts.map +1 -1
- package/dist/messages.js +84 -5
- package/dist/model.d.ts +2 -9
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +0 -9
- package/dist/models.d.ts +14 -0
- package/dist/models.d.ts.map +1 -0
- package/dist/models.js +193 -0
- package/dist/observation.d.ts +2 -2
- package/dist/observation.d.ts.map +1 -1
- package/dist/observation.js +7 -2
- package/dist/opening.d.ts +4 -0
- package/dist/opening.d.ts.map +1 -0
- package/dist/opening.js +56 -0
- package/dist/outcome.d.ts +4 -1
- package/dist/outcome.d.ts.map +1 -1
- package/dist/outcome.js +3 -0
- package/dist/overlay.d.ts +1 -0
- package/dist/overlay.d.ts.map +1 -1
- package/dist/overlay.js +11 -0
- package/dist/parts.d.ts +59 -0
- package/dist/parts.d.ts.map +1 -0
- package/dist/parts.js +118 -0
- package/dist/preparation.d.ts +20 -0
- package/dist/preparation.d.ts.map +1 -0
- package/dist/preparation.js +226 -0
- package/dist/queries.d.ts +16 -0
- package/dist/queries.d.ts.map +1 -0
- package/dist/queries.js +272 -0
- package/dist/query.d.ts +13 -212
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +3 -524
- package/dist/questions.d.ts +34 -0
- package/dist/questions.d.ts.map +1 -0
- package/dist/questions.js +122 -0
- package/dist/reach.d.ts +12 -10
- package/dist/reach.d.ts.map +1 -1
- package/dist/reach.js +165 -109
- package/dist/react.d.ts +9 -2
- package/dist/react.d.ts.map +1 -1
- package/dist/read.d.ts +7 -0
- package/dist/read.d.ts.map +1 -0
- package/dist/read.js +17 -0
- package/dist/reads.d.ts +36 -0
- package/dist/reads.d.ts.map +1 -0
- package/dist/reads.js +150 -0
- package/dist/recovery.d.ts.map +1 -1
- package/dist/recovery.js +9 -1
- package/dist/refresh.d.ts +1 -1
- package/dist/refresh.d.ts.map +1 -1
- package/dist/refresh.js +8 -20
- package/dist/refusal.d.ts +5 -0
- package/dist/refusal.d.ts.map +1 -0
- package/dist/refusal.js +56 -0
- package/dist/replica.d.ts +8 -8
- package/dist/replica.d.ts.map +1 -1
- package/dist/replica.js +50 -18
- package/dist/room-draft.d.ts +2 -2
- package/dist/room-draft.d.ts.map +1 -1
- package/dist/room-drafts.d.ts +24 -0
- package/dist/room-drafts.d.ts.map +1 -0
- package/dist/room-drafts.js +216 -0
- package/dist/rows.d.ts +14 -22
- package/dist/rows.d.ts.map +1 -1
- package/dist/rows.js +48 -189
- package/dist/runtime.d.ts +42 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +1 -0
- package/dist/save.d.ts.map +1 -1
- package/dist/save.js +11 -8
- package/dist/saves.d.ts +70 -0
- package/dist/saves.d.ts.map +1 -0
- package/dist/saves.js +1004 -0
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +1 -1
- package/dist/seed.d.ts +11 -2
- package/dist/seed.d.ts.map +1 -1
- package/dist/seed.js +71 -0
- package/dist/shown.d.ts +31 -0
- package/dist/shown.d.ts.map +1 -0
- package/dist/shown.js +294 -0
- package/dist/socket/admission.d.ts +7 -0
- package/dist/socket/admission.d.ts.map +1 -0
- package/dist/socket/admission.js +39 -0
- package/dist/socket/answers.d.ts +6 -0
- package/dist/socket/answers.d.ts.map +1 -0
- package/dist/socket/answers.js +20 -0
- package/dist/socket/lanes.d.ts +20 -0
- package/dist/socket/lanes.d.ts.map +1 -0
- package/dist/socket/lanes.js +77 -0
- package/dist/socket/reads.d.ts +10 -0
- package/dist/socket/reads.d.ts.map +1 -0
- package/dist/socket/reads.js +31 -0
- package/dist/socket/rooms.d.ts +43 -0
- package/dist/socket/rooms.d.ts.map +1 -0
- package/dist/socket/rooms.js +90 -0
- package/dist/socket/session.d.ts +39 -0
- package/dist/socket/session.d.ts.map +1 -0
- package/dist/socket/session.js +23 -0
- package/dist/socket.d.ts +70 -0
- package/dist/socket.d.ts.map +1 -0
- package/dist/socket.js +175 -0
- package/dist/source.d.ts +61 -0
- package/dist/source.d.ts.map +1 -0
- package/dist/source.js +81 -0
- package/dist/status.d.ts +0 -2
- package/dist/status.d.ts.map +1 -1
- package/dist/status.js +0 -6
- package/dist/store/fences.d.ts +16 -0
- package/dist/store/fences.d.ts.map +1 -0
- package/dist/store/fences.js +26 -0
- package/dist/store/installs.d.ts +30 -0
- package/dist/store/installs.d.ts.map +1 -0
- package/dist/store/installs.js +34 -0
- package/dist/store/readiness.d.ts +10 -0
- package/dist/store/readiness.d.ts.map +1 -0
- package/dist/store/readiness.js +52 -0
- package/dist/store/records.d.ts +212 -0
- package/dist/store/records.d.ts.map +1 -0
- package/dist/store/records.js +408 -0
- package/dist/store/room-held.d.ts +8 -0
- package/dist/store/room-held.d.ts.map +1 -0
- package/dist/store/room-held.js +17 -0
- package/dist/store/space.d.ts +11 -0
- package/dist/store/space.d.ts.map +1 -0
- package/dist/store/space.js +43 -0
- package/dist/store/watchers.d.ts +17 -0
- package/dist/store/watchers.d.ts.map +1 -0
- package/dist/store/watchers.js +57 -0
- package/dist/store/writes.d.ts +24 -0
- package/dist/store/writes.d.ts.map +1 -0
- package/dist/store/writes.js +125 -0
- package/dist/store.d.ts +107 -153
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +143 -396
- package/dist/stored.d.ts +58 -64
- package/dist/stored.d.ts.map +1 -1
- package/dist/stored.js +244 -156
- package/dist/surface.d.ts +88 -0
- package/dist/surface.d.ts.map +1 -0
- package/dist/surface.js +222 -0
- package/dist/sync.d.ts +20 -0
- package/dist/sync.d.ts.map +1 -0
- package/dist/sync.js +531 -0
- package/dist/tables.d.ts +110 -48
- package/dist/tables.d.ts.map +1 -1
- package/dist/tables.js +209 -54
- package/dist/tallies.d.ts +18 -0
- package/dist/tallies.d.ts.map +1 -0
- package/dist/tallies.js +129 -0
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +7 -4
- 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 +16 -1
- package/dist/wire.d.ts.map +1 -1
- package/dist/wire.js +6 -0
- package/package.json +2 -2
- package/dist/fence.d.ts +0 -6
- package/dist/fence.d.ts.map +0 -1
- package/dist/fence.js +0 -10
- package/dist/phrase.d.ts +0 -3
- package/dist/phrase.d.ts.map +0 -1
- package/dist/phrase.js +0 -8
package/dist/stored.js
CHANGED
|
@@ -1,20 +1,21 @@
|
|
|
1
|
+
import { instantKey, sql } from '@agentshouse/mdmodel';
|
|
1
2
|
import { composedOf } from './collection.js';
|
|
2
|
-
import { described, derived } from './rows.js';
|
|
3
|
+
import { described, derived, heldOf } from './rows.js';
|
|
3
4
|
export const REPLICA_TABLES = [
|
|
4
5
|
'CREATE TABLE replica_keys (key INTEGER PRIMARY KEY AUTOINCREMENT, locator TEXT NOT NULL, transfer TEXT NOT NULL, fingerprint TEXT NOT NULL, rederiving INTEGER)',
|
|
5
|
-
'CREATE TABLE replica_rooms (locator TEXT PRIMARY KEY, key INTEGER NOT NULL, record TEXT NOT NULL) WITHOUT ROWID',
|
|
6
|
-
'CREATE TABLE
|
|
6
|
+
'CREATE TABLE replica_rooms (locator TEXT PRIMARY KEY, key INTEGER NOT NULL, record TEXT NOT NULL, documents INTEGER NOT NULL DEFAULT 0) WITHOUT ROWID',
|
|
7
|
+
'CREATE TABLE replica_models (identity TEXT NOT NULL, version TEXT NOT NULL, schema TEXT NOT NULL, PRIMARY KEY (identity, version)) WITHOUT ROWID',
|
|
8
|
+
"CREATE TABLE replica_entries (id INTEGER PRIMARY KEY, key INTEGER NOT NULL, layer INTEGER NOT NULL, path TEXT NOT NULL, visible INTEGER NOT NULL, present INTEGER NOT NULL, queried INTEGER NOT NULL, binary TEXT, revision TEXT, file_id TEXT, change TEXT, written TEXT, type TEXT, declared TEXT, folder TEXT NOT NULL, fields TEXT, links TEXT, part TEXT, created TEXT, created_instant TEXT, changed_instant TEXT, bytes INTEGER GENERATED ALWAYS AS (CASE WHEN binary IS NULL THEN length(CAST(content AS BLOB)) ELSE binary ->> '$.byteLength' END) STORED, content TEXT)",
|
|
7
9
|
'CREATE UNIQUE INDEX replica_entries_path ON replica_entries (key, layer, path)',
|
|
8
10
|
'CREATE INDEX replica_entries_visible ON replica_entries (key, visible, present, path, binary)',
|
|
9
11
|
'CREATE INDEX replica_entries_folder ON replica_entries (key, folder, path)',
|
|
10
12
|
'CREATE INDEX replica_entries_type ON replica_entries (key, type, visible, present, queried, folder)',
|
|
11
13
|
'CREATE INDEX replica_entries_key ON replica_entries (key)',
|
|
12
|
-
|
|
14
|
+
sql.VALUE_TABLE,
|
|
13
15
|
'CREATE TABLE replica_links (doc INTEGER NOT NULL, key INTEGER NOT NULL, kind TEXT NOT NULL, keys TEXT NOT NULL, places TEXT NOT NULL, target TEXT NOT NULL, field TEXT NOT NULL, PRIMARY KEY (doc, kind, keys, places, target)) WITHOUT ROWID',
|
|
14
16
|
'CREATE INDEX replica_links_target ON replica_links (key, target, kind, keys)',
|
|
15
|
-
'CREATE TABLE replica_folders (key INTEGER NOT NULL, layer INTEGER NOT NULL, path TEXT NOT NULL, present INTEGER NOT NULL, PRIMARY KEY (key, layer, path)) WITHOUT ROWID',
|
|
17
|
+
'CREATE TABLE replica_folders (key INTEGER NOT NULL, layer INTEGER NOT NULL, path TEXT NOT NULL, present INTEGER NOT NULL, part TEXT, PRIMARY KEY (key, layer, path)) WITHOUT ROWID',
|
|
16
18
|
'CREATE TABLE replica_erasing (key INTEGER PRIMARY KEY, locator TEXT NOT NULL)',
|
|
17
|
-
'CREATE TABLE replica_opened (locator TEXT NOT NULL, path TEXT NOT NULL, PRIMARY KEY (locator, path)) WITHOUT ROWID',
|
|
18
19
|
'CREATE TABLE replica_facts (name TEXT PRIMARY KEY, value TEXT NOT NULL) WITHOUT ROWID',
|
|
19
20
|
'CREATE TABLE replica_presentation (app TEXT PRIMARY KEY, value TEXT NOT NULL) WITHOUT ROWID',
|
|
20
21
|
];
|
|
@@ -29,8 +30,7 @@ const ABSENT = {
|
|
|
29
30
|
queried: false,
|
|
30
31
|
folder: '',
|
|
31
32
|
fields: null,
|
|
32
|
-
|
|
33
|
-
links: [],
|
|
33
|
+
links: null,
|
|
34
34
|
};
|
|
35
35
|
function text(value) {
|
|
36
36
|
return typeof value === 'string' ? value : null;
|
|
@@ -51,17 +51,11 @@ function dropDerived(connection, doc) {
|
|
|
51
51
|
connection.run('DELETE FROM replica_values WHERE doc = ?', [doc]);
|
|
52
52
|
connection.run('DELETE FROM replica_links WHERE doc = ?', [doc]);
|
|
53
53
|
}
|
|
54
|
-
function
|
|
55
|
-
|
|
56
|
-
return 'Infinity';
|
|
57
|
-
if (value === -Infinity)
|
|
58
|
-
return '-Infinity';
|
|
59
|
-
return JSON.stringify(value);
|
|
60
|
-
}
|
|
61
|
-
function writeDerived(connection, doc, key, made) {
|
|
54
|
+
function writeDerived(connection, doc, key, path, held, composition) {
|
|
55
|
+
const made = derived(path, held, composition);
|
|
62
56
|
if (made.values.length > 0) {
|
|
63
|
-
const
|
|
64
|
-
connection.run(
|
|
57
|
+
const inserted = sql.insertedValues(doc, made.values);
|
|
58
|
+
connection.run(inserted.sql, inserted.bind);
|
|
65
59
|
}
|
|
66
60
|
if (made.links.length > 0) {
|
|
67
61
|
connection.run('INSERT OR IGNORE INTO replica_links (doc, key, kind, keys, places, target, field) SELECT ?, ?, value ->> 0, value ->> 1, value ->> 2, value ->> 3, value ->> 4 FROM json_each(?)', [
|
|
@@ -82,8 +76,8 @@ function removeEntry(connection, key, layer, path) {
|
|
|
82
76
|
dropDerived(connection, id);
|
|
83
77
|
connection.run('DELETE FROM replica_entries WHERE id = ?', [id]);
|
|
84
78
|
}
|
|
85
|
-
function insertEntry(connection, key, layer, entry, present, made) {
|
|
86
|
-
connection.run('INSERT INTO replica_entries (key, layer, path, visible, present, queried, content,
|
|
79
|
+
function insertEntry(connection, key, layer, entry, present, made, part = null) {
|
|
80
|
+
connection.run('INSERT INTO replica_entries (key, layer, path, visible, present, queried, content, binary, revision, file_id, created, created_instant, change, changed_instant, written, type, declared, folder, fields, links, part) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', [
|
|
87
81
|
key,
|
|
88
82
|
layer,
|
|
89
83
|
entry.path,
|
|
@@ -91,16 +85,20 @@ function insertEntry(connection, key, layer, entry, present, made) {
|
|
|
91
85
|
flag(present),
|
|
92
86
|
flag(made.queried),
|
|
93
87
|
entry.binary === null ? entry.content : null,
|
|
94
|
-
entry.binary === null && entry.outline !== null ? JSON.stringify(entry.outline) : null,
|
|
95
88
|
entry.binary === null ? null : JSON.stringify(entry.binary),
|
|
96
89
|
entry.revision,
|
|
97
90
|
entry.fileId,
|
|
91
|
+
entry.created,
|
|
92
|
+
instantKey(entry.created),
|
|
98
93
|
entry.change === null ? null : JSON.stringify(entry.change),
|
|
94
|
+
instantKey(entry.change?.time),
|
|
99
95
|
entry.written,
|
|
100
96
|
made.type,
|
|
101
97
|
made.declared,
|
|
102
98
|
made.folder,
|
|
103
99
|
made.fields,
|
|
100
|
+
made.links,
|
|
101
|
+
part,
|
|
104
102
|
]);
|
|
105
103
|
}
|
|
106
104
|
function textOf(entry) {
|
|
@@ -109,16 +107,15 @@ function textOf(entry) {
|
|
|
109
107
|
function putEntry(connection, key, layer, entry, present, composition) {
|
|
110
108
|
removeEntry(connection, key, layer, entry.path);
|
|
111
109
|
const content = textOf(entry);
|
|
112
|
-
|
|
113
|
-
insertEntry(connection, key, layer, entry, present, made);
|
|
110
|
+
insertEntry(connection, key, layer, entry, present, present ? described(entry.path, content, entry.facts) : ABSENT);
|
|
114
111
|
if (!present)
|
|
115
112
|
return;
|
|
116
113
|
const id = entryId(connection, key, layer, entry.path);
|
|
117
|
-
writeDerived(connection, id, key,
|
|
114
|
+
writeDerived(connection, id, key, entry.path, heldOf(entry.path, content, entry.facts), composition);
|
|
118
115
|
}
|
|
119
|
-
function placeEntry(connection, key, entry) {
|
|
116
|
+
function placeEntry(connection, key, entry, part) {
|
|
120
117
|
removeEntry(connection, key, CONFIRMED, entry.path);
|
|
121
|
-
insertEntry(connection, key, CONFIRMED, entry, true, described(entry.path, textOf(entry), entry.
|
|
118
|
+
insertEntry(connection, key, CONFIRMED, entry, true, described(entry.path, textOf(entry), entry.facts), part);
|
|
122
119
|
}
|
|
123
120
|
function revealed(connection, key, touched) {
|
|
124
121
|
if (touched.length === 0)
|
|
@@ -145,17 +142,83 @@ export function entered(connection, locator, composition, rows) {
|
|
|
145
142
|
return key;
|
|
146
143
|
}
|
|
147
144
|
export function stage(connection, request) {
|
|
145
|
+
if (request.key === null) {
|
|
146
|
+
for (const row of connection.rows(STAGED_KEYS, [request.locator])) {
|
|
147
|
+
erasing(connection, number(row.key), request.locator);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
148
150
|
const key = request.key ??
|
|
149
151
|
newKey(connection, request.locator, request.transfer, request.fingerprint, false);
|
|
150
152
|
recomposed(connection, key, request.fingerprint);
|
|
151
|
-
connection
|
|
153
|
+
owing(connection, key);
|
|
152
154
|
for (const entry of request.entries)
|
|
153
|
-
placeEntry(connection, key, entry);
|
|
155
|
+
placeEntry(connection, key, entry, request.part);
|
|
154
156
|
for (const path of request.folders) {
|
|
155
|
-
connection.run('INSERT OR REPLACE INTO replica_folders (key, layer, path, present) VALUES (?, ?, ?, 1)', [key, CONFIRMED, path]);
|
|
157
|
+
connection.run('INSERT OR REPLACE INTO replica_folders (key, layer, path, present, part) VALUES (?, ?, ?, 1, ?)', [key, CONFIRMED, path, request.part]);
|
|
156
158
|
}
|
|
157
159
|
return key;
|
|
158
160
|
}
|
|
161
|
+
function owing(connection, key) {
|
|
162
|
+
connection.run('UPDATE replica_keys SET rederiving = coalesce(rederiving, last) FROM (SELECT coalesce(max(id), 0) AS last FROM replica_entries) WHERE key = ?', [key]);
|
|
163
|
+
}
|
|
164
|
+
const STAGED_KEYS = `SELECT k.key, k.transfer FROM replica_keys k WHERE k.locator = ?
|
|
165
|
+
AND NOT EXISTS (SELECT 1 FROM replica_rooms r WHERE r.key = k.key)
|
|
166
|
+
AND NOT EXISTS (SELECT 1 FROM replica_erasing e WHERE e.key = k.key)
|
|
167
|
+
ORDER BY k.key DESC`;
|
|
168
|
+
const UNPARTED = `EXISTS (SELECT 1 FROM replica_entries e WHERE e.key = k.key AND e.part IS NULL)
|
|
169
|
+
OR EXISTS (SELECT 1 FROM replica_folders f WHERE f.key = k.key AND f.part IS NULL)`;
|
|
170
|
+
function partsOf(connection, key, layer) {
|
|
171
|
+
const scoped = layer === null ? '' : ` AND layer = ${layer}`;
|
|
172
|
+
return new Set(connection
|
|
173
|
+
.rows(`SELECT part FROM replica_entries WHERE key = ?${scoped} AND part IS NOT NULL UNION SELECT part FROM replica_folders WHERE key = ?${scoped} AND part IS NOT NULL`, [key, key])
|
|
174
|
+
.map((row) => text(row.part)));
|
|
175
|
+
}
|
|
176
|
+
function resumable(connection, locator) {
|
|
177
|
+
let kept = null;
|
|
178
|
+
for (const row of connection.rows(STAGED_KEYS, [locator])) {
|
|
179
|
+
const key = number(row.key);
|
|
180
|
+
const parted = kept === null &&
|
|
181
|
+
connection.rows(`SELECT 1 FROM replica_keys k WHERE k.key = ? AND NOT (${UNPARTED})`, [key])
|
|
182
|
+
.length > 0;
|
|
183
|
+
if (parted)
|
|
184
|
+
kept = { key, transfer: text(row.transfer) };
|
|
185
|
+
else
|
|
186
|
+
erasing(connection, key, locator);
|
|
187
|
+
}
|
|
188
|
+
return kept;
|
|
189
|
+
}
|
|
190
|
+
export function resume(connection, request) {
|
|
191
|
+
const wanted = new Set(request.parts);
|
|
192
|
+
const held = resumable(connection, request.locator);
|
|
193
|
+
const staged = held === null ? new Set() : partsOf(connection, held.key, null);
|
|
194
|
+
const dropped = [...staged].filter((part) => !wanted.has(part));
|
|
195
|
+
if (held !== null && dropped.length > 0) {
|
|
196
|
+
const named = JSON.stringify(dropped);
|
|
197
|
+
const rows = `SELECT id FROM replica_entries WHERE key = ? AND part IN (SELECT value FROM json_each(?))`;
|
|
198
|
+
for (const table of ['replica_values', 'replica_links']) {
|
|
199
|
+
connection.run(`DELETE FROM ${table} WHERE doc IN (${rows})`, [held.key, named]);
|
|
200
|
+
}
|
|
201
|
+
connection.run(`DELETE FROM replica_entries WHERE id IN (${rows})`, [held.key, named]);
|
|
202
|
+
connection.run('DELETE FROM replica_folders WHERE key = ? AND part IN (SELECT value FROM json_each(?))', [held.key, named]);
|
|
203
|
+
}
|
|
204
|
+
const kept = [...staged].filter((part) => wanted.has(part));
|
|
205
|
+
const publishedParts = request.published === null
|
|
206
|
+
? new Set()
|
|
207
|
+
: partsOf(connection, request.published, CONFIRMED);
|
|
208
|
+
const copied = request.parts.filter((part) => !staged.has(part) && publishedParts.has(part));
|
|
209
|
+
if (held === null && copied.length === 0) {
|
|
210
|
+
return { key: null, transfer: request.transfer, staged: [] };
|
|
211
|
+
}
|
|
212
|
+
const key = held?.key ?? newKey(connection, request.locator, request.transfer, request.fingerprint, false);
|
|
213
|
+
recomposed(connection, key, request.fingerprint);
|
|
214
|
+
if (copied.length > 0 && request.published !== null) {
|
|
215
|
+
owing(connection, key);
|
|
216
|
+
const named = JSON.stringify(copied);
|
|
217
|
+
connection.run(`INSERT INTO replica_entries (key, layer, path, visible, present, queried, content, binary, revision, file_id, created, created_instant, change, changed_instant, written, type, declared, folder, fields, links, part) SELECT ?, ${CONFIRMED}, path, 1, 1, queried, content, binary, revision, file_id, created, created_instant, change, changed_instant, written, type, declared, folder, fields, links, part FROM replica_entries WHERE key = ? AND layer = ${CONFIRMED} AND present = 1 AND part IN (SELECT value FROM json_each(?)) ORDER BY path`, [key, request.published, named]);
|
|
218
|
+
connection.run(`INSERT OR REPLACE INTO replica_folders (key, layer, path, present, part) SELECT ?, ${CONFIRMED}, path, 1, part FROM replica_folders WHERE key = ? AND layer = ${CONFIRMED} AND present = 1 AND part IN (SELECT value FROM json_each(?))`, [key, request.published, named]);
|
|
219
|
+
}
|
|
220
|
+
return { key, transfer: held?.transfer ?? request.transfer, staged: [...kept, ...copied] };
|
|
221
|
+
}
|
|
159
222
|
export function refreshing(connection, request) {
|
|
160
223
|
const held = connection.rows('SELECT 1 FROM replica_keys k WHERE k.key = ? AND NOT EXISTS (SELECT 1 FROM replica_erasing e WHERE e.key = k.key)', [request.key]);
|
|
161
224
|
if (held.length === 0)
|
|
@@ -169,12 +232,13 @@ export function refreshing(connection, request) {
|
|
|
169
232
|
putEntry(connection, request.key, REFRESHED, {
|
|
170
233
|
path,
|
|
171
234
|
content: null,
|
|
172
|
-
outline: null,
|
|
173
235
|
binary: null,
|
|
174
236
|
revision: null,
|
|
175
237
|
fileId: null,
|
|
238
|
+
created: null,
|
|
176
239
|
change: null,
|
|
177
240
|
written: null,
|
|
241
|
+
facts: null,
|
|
178
242
|
}, false, composition);
|
|
179
243
|
}
|
|
180
244
|
for (const [list, present] of [
|
|
@@ -231,15 +295,18 @@ function counted(connection, key, roots) {
|
|
|
231
295
|
const [row] = connection.rows(`SELECT count(*) AS held FROM replica_entries WHERE key = ? AND visible = 1 AND present = 1 AND (binary IS NOT NULL OR substr(path, -3) = '.md') AND NOT ${beneathRoots('replica_entries.path')}`, [key, JSON.stringify(roots)]);
|
|
232
296
|
return number(row.held);
|
|
233
297
|
}
|
|
234
|
-
export function counts(connection, rooms) {
|
|
235
|
-
return rooms.map(({ key, roots }) => counted(connection, key, roots));
|
|
236
|
-
}
|
|
237
298
|
function erasing(connection, key, locator) {
|
|
238
299
|
connection.run('INSERT OR REPLACE INTO replica_erasing (key, locator) VALUES (?, ?)', [
|
|
239
300
|
key,
|
|
240
301
|
locator,
|
|
241
302
|
]);
|
|
242
303
|
}
|
|
304
|
+
function saved(connection, key, entry, at) {
|
|
305
|
+
if (!entry.present || entry.created !== null)
|
|
306
|
+
return entry;
|
|
307
|
+
const [held] = connection.rows(`SELECT created FROM replica_entries WHERE key = ? AND layer = ${OVERLAY} AND path = ? AND present = 1`, [key, entry.path]);
|
|
308
|
+
return { ...entry, created: text(held?.created) ?? at };
|
|
309
|
+
}
|
|
243
310
|
function commitRoom(connection, room) {
|
|
244
311
|
const touched = new Set();
|
|
245
312
|
recomposed(connection, room.key, room.composed.fingerprint);
|
|
@@ -261,8 +328,9 @@ function commitRoom(connection, room) {
|
|
|
261
328
|
removeEntry(connection, room.key, CONFIRMED, path);
|
|
262
329
|
touched.add(path);
|
|
263
330
|
}
|
|
331
|
+
const savedAt = new Date().toISOString();
|
|
264
332
|
for (const entry of room.overlay?.set ?? []) {
|
|
265
|
-
putEntry(connection, room.key, OVERLAY, entry, entry.present, composition);
|
|
333
|
+
putEntry(connection, room.key, OVERLAY, saved(connection, room.key, entry, savedAt), entry.present, composition);
|
|
266
334
|
touched.add(entry.path);
|
|
267
335
|
}
|
|
268
336
|
for (const path of room.overlay?.cleared ?? []) {
|
|
@@ -272,27 +340,44 @@ function commitRoom(connection, room) {
|
|
|
272
340
|
const changed = [...touched];
|
|
273
341
|
revealed(connection, room.key, changed);
|
|
274
342
|
if (room.record !== undefined) {
|
|
275
|
-
connection.run(
|
|
276
|
-
|
|
277
|
-
room.key,
|
|
278
|
-
room.record,
|
|
279
|
-
]);
|
|
343
|
+
connection.run(KEEP_MODEL, [room.record, room.record, room.record, room.record]);
|
|
344
|
+
connection.run(`INSERT OR REPLACE INTO replica_rooms (locator, key, record) VALUES (?, ?, ${MODEL_LEFT})`, [room.locator, room.key, room.record, room.record, room.record]);
|
|
280
345
|
}
|
|
281
346
|
return room.published === undefined ? changed : null;
|
|
282
347
|
}
|
|
348
|
+
const SCHEMA = '$.model.snapshot.schema';
|
|
349
|
+
const KEEP_MODEL = `INSERT OR IGNORE INTO replica_models (identity, version, schema)
|
|
350
|
+
SELECT json_extract(?, '$.model.snapshot.identity'), json_extract(?, '$.model.snapshot.version'),
|
|
351
|
+
json_extract(?, '${SCHEMA}')
|
|
352
|
+
WHERE json_type(?, '${SCHEMA}') = 'text'`;
|
|
353
|
+
const MODEL_LEFT = `CASE WHEN json_type(?, '${SCHEMA}') = 'text' THEN json_set(?, '${SCHEMA}', json('null')) ELSE ? END`;
|
|
354
|
+
const UNHELD_MODELS = `DELETE FROM replica_models WHERE NOT EXISTS (
|
|
355
|
+
SELECT 1 FROM replica_rooms r
|
|
356
|
+
WHERE json_extract(r.record, '$.model.snapshot.identity') = replica_models.identity
|
|
357
|
+
AND json_extract(r.record, '$.model.snapshot.version') = replica_models.version
|
|
358
|
+
)`;
|
|
359
|
+
const HELD_RECORDS = `SELECT r.locator, r.key, CASE WHEN m.schema IS NULL THEN r.record
|
|
360
|
+
ELSE json_set(r.record, '${SCHEMA}', m.schema) END AS record
|
|
361
|
+
FROM replica_rooms r
|
|
362
|
+
LEFT JOIN replica_models m
|
|
363
|
+
ON m.identity = json_extract(r.record, '$.model.snapshot.identity')
|
|
364
|
+
AND m.version = json_extract(r.record, '$.model.snapshot.version')`;
|
|
283
365
|
export function commit(connection, rooms) {
|
|
284
|
-
const counted = {};
|
|
285
366
|
const changed = {};
|
|
286
367
|
const indexed = {};
|
|
287
368
|
for (const room of rooms) {
|
|
288
369
|
changed[room.locator] = commitRoom(connection, room);
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
370
|
+
connection.run('UPDATE replica_rooms SET documents = ? WHERE locator = ? AND key = ?', [
|
|
371
|
+
counted(connection, room.key, room.roots ?? rootsOf(connection, room.locator)),
|
|
372
|
+
room.locator,
|
|
373
|
+
room.key,
|
|
374
|
+
]);
|
|
292
375
|
const [held] = connection.rows('SELECT rederiving FROM replica_keys WHERE key = ?', [room.key]);
|
|
293
376
|
indexed[room.locator] = held !== undefined && held.rederiving === null;
|
|
294
377
|
}
|
|
295
|
-
|
|
378
|
+
if (rooms.some((room) => room.record !== undefined))
|
|
379
|
+
connection.run(UNHELD_MODELS);
|
|
380
|
+
return { changed, indexed };
|
|
296
381
|
}
|
|
297
382
|
function rootsOf(connection, locator) {
|
|
298
383
|
const [row] = connection.rows('SELECT record FROM replica_rooms WHERE locator = ?', [locator]);
|
|
@@ -305,8 +390,8 @@ export function fenceRooms(connection, locators) {
|
|
|
305
390
|
erasing(connection, number(row.key), locator);
|
|
306
391
|
}
|
|
307
392
|
connection.run('DELETE FROM replica_rooms WHERE locator = ?', [locator]);
|
|
308
|
-
connection.run('DELETE FROM replica_opened WHERE locator = ?', [locator]);
|
|
309
393
|
}
|
|
394
|
+
connection.run(UNHELD_MODELS);
|
|
310
395
|
return null;
|
|
311
396
|
}
|
|
312
397
|
export function abandon(connection, locator) {
|
|
@@ -359,17 +444,20 @@ export function rederive(connection, key, composed, bytes, ms, floor) {
|
|
|
359
444
|
let built = 0;
|
|
360
445
|
let read = false;
|
|
361
446
|
reading: for (;;) {
|
|
362
|
-
const rows = connection.rows('SELECT id, path,
|
|
447
|
+
const rows = connection.rows('SELECT id, path, type, fields, links, octet_length(content) AS size FROM replica_entries WHERE key = ? AND present = 1 AND id > ? ORDER BY id LIMIT ?', [key, last, DERIVED_ROWS]);
|
|
363
448
|
for (const row of rows) {
|
|
364
449
|
const id = number(row.id);
|
|
365
450
|
const path = text(row.path);
|
|
366
|
-
const
|
|
367
|
-
const made = derived(path, content, json(row.outline), composition);
|
|
451
|
+
const size = row.size === null ? 0 : number(row.size);
|
|
368
452
|
dropDerived(connection, id);
|
|
369
|
-
writeDerived(connection, id, key,
|
|
370
|
-
|
|
453
|
+
writeDerived(connection, id, key, path, {
|
|
454
|
+
type: text(row.type),
|
|
455
|
+
fields: json(row.fields),
|
|
456
|
+
links: json(row.links) ?? [],
|
|
457
|
+
}, composition);
|
|
458
|
+
built += size;
|
|
371
459
|
last = id;
|
|
372
|
-
spent += ENTRY_WEIGHT +
|
|
460
|
+
spent += ENTRY_WEIGHT + size;
|
|
373
461
|
if (spent >= bytes || (spent >= floor && performance.now() - started >= ms))
|
|
374
462
|
break reading;
|
|
375
463
|
}
|
|
@@ -381,63 +469,31 @@ export function rederive(connection, key, composed, bytes, ms, floor) {
|
|
|
381
469
|
connection.run('UPDATE replica_keys SET rederiving = ? WHERE key = ?', [read ? null : last, key]);
|
|
382
470
|
return { done: read, text: built };
|
|
383
471
|
}
|
|
384
|
-
function outlinedAgain(connection, row, key, content, composition) {
|
|
385
|
-
const id = number(row.id);
|
|
386
|
-
const path = text(row.path);
|
|
387
|
-
const made = derived(path, content, json(row.outline), composition);
|
|
388
|
-
connection.run('UPDATE replica_entries SET content = ?, type = ?, declared = ?, queried = ?, folder = ?, fields = ? WHERE id = ?', [content, made.type, made.declared, flag(made.queried), made.folder, made.fields, id]);
|
|
389
|
-
dropDerived(connection, id);
|
|
390
|
-
writeDerived(connection, id, key, made);
|
|
391
|
-
}
|
|
392
|
-
export function holdTexts(connection, request) {
|
|
393
|
-
const held = [];
|
|
394
|
-
for (const { path, revision, content } of request.texts) {
|
|
395
|
-
const [row] = connection.rows(`SELECT id, path, outline FROM replica_entries WHERE key = ? AND layer = ${CONFIRMED} AND path = ? AND revision = ? AND content IS NULL AND outline IS NOT NULL`, [request.key, path, revision]);
|
|
396
|
-
if (row === undefined)
|
|
397
|
-
continue;
|
|
398
|
-
outlinedAgain(connection, row, request.key, content, request.composed.composition);
|
|
399
|
-
connection.run('INSERT OR IGNORE INTO replica_opened (locator, path) VALUES (?, ?)', [
|
|
400
|
-
request.locator,
|
|
401
|
-
path,
|
|
402
|
-
]);
|
|
403
|
-
held.push(path);
|
|
404
|
-
}
|
|
405
|
-
return held;
|
|
406
|
-
}
|
|
407
|
-
export function unholdTexts(connection, request) {
|
|
408
|
-
connection.run('DELETE FROM replica_opened WHERE locator = ?', [request.locator]);
|
|
409
|
-
const rows = connection.rows(`SELECT id, path, outline, octet_length(content) AS bytes FROM replica_entries WHERE key = ? AND layer = ${CONFIRMED} AND visible = 1 AND content IS NOT NULL AND outline IS NOT NULL`, [request.key]);
|
|
410
|
-
for (const row of rows) {
|
|
411
|
-
outlinedAgain(connection, row, request.key, null, request.composed.composition);
|
|
412
|
-
}
|
|
413
|
-
return {
|
|
414
|
-
paths: rows.map((row) => text(row.path)),
|
|
415
|
-
bytes: rows.reduce((total, row) => total + number(row.bytes), 0),
|
|
416
|
-
};
|
|
417
|
-
}
|
|
418
|
-
export function remembered(connection, request) {
|
|
419
|
-
connection.run(`INSERT OR IGNORE INTO replica_opened (locator, path) SELECT ?, path FROM replica_entries WHERE key = ? AND layer = ${CONFIRMED} AND content IS NOT NULL AND binary IS NULL AND path IN (SELECT value FROM json_each(?))`, [request.locator, request.key, paths(request.paths)]);
|
|
420
|
-
return null;
|
|
421
|
-
}
|
|
422
|
-
export function wanted(connection, request) {
|
|
423
|
-
return connection
|
|
424
|
-
.rows(`SELECT e.path, e.revision FROM replica_opened o JOIN replica_entries e ON e.key = ? AND e.layer = ${CONFIRMED} AND e.path = o.path WHERE o.locator = ? AND e.content IS NULL AND e.outline IS NOT NULL AND e.revision IS NOT NULL`, [request.key, request.locator])
|
|
425
|
-
.map((row) => ({ path: text(row.path), revision: text(row.revision) }));
|
|
426
|
-
}
|
|
427
472
|
function heldEntry(row) {
|
|
428
473
|
return {
|
|
429
474
|
path: text(row.path),
|
|
430
475
|
content: text(row.content),
|
|
431
|
-
outline: json(row.outline),
|
|
432
476
|
binary: json(row.binary),
|
|
433
477
|
revision: text(row.revision),
|
|
434
478
|
fileId: text(row.file_id),
|
|
479
|
+
created: text(row.created),
|
|
435
480
|
change: json(row.change),
|
|
436
481
|
written: text(row.written),
|
|
437
482
|
type: text(row.type),
|
|
483
|
+
facts: factsHeld(row),
|
|
438
484
|
};
|
|
439
485
|
}
|
|
440
|
-
|
|
486
|
+
function factsHeld(row) {
|
|
487
|
+
const type = text(row.declared);
|
|
488
|
+
if (type === null)
|
|
489
|
+
return null;
|
|
490
|
+
return {
|
|
491
|
+
type,
|
|
492
|
+
fields: json(row.fields) ?? {},
|
|
493
|
+
links: json(row.links) ?? [],
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
const ENTRY_COLUMNS = 'e.path, e.content, e.binary, e.revision, e.file_id, e.created, e.change, e.written, e.type, e.declared, e.fields, e.links';
|
|
441
497
|
function unrefreshed(alias) {
|
|
442
498
|
return `NOT EXISTS (SELECT 1 FROM replica_entries r WHERE r.key = ${alias}.key AND r.layer = ${REFRESHED} AND r.path = ${alias}.path)`;
|
|
443
499
|
}
|
|
@@ -448,22 +504,6 @@ function viewed(view, alias) {
|
|
|
448
504
|
return `${alias}.layer = ${CONFIRMED}`;
|
|
449
505
|
return `${alias}.present = 1 AND (${alias}.layer = ${REFRESHED} OR (${alias}.layer = ${CONFIRMED} AND ${unrefreshed(alias)}))`;
|
|
450
506
|
}
|
|
451
|
-
function layers(view) {
|
|
452
|
-
if (view !== 'refreshed')
|
|
453
|
-
return [viewed(view, 'e')];
|
|
454
|
-
return [
|
|
455
|
-
`e.layer = ${REFRESHED} AND e.present = 1`,
|
|
456
|
-
`e.layer = ${CONFIRMED} AND e.present = 1 AND ${unrefreshed('e')}`,
|
|
457
|
-
];
|
|
458
|
-
}
|
|
459
|
-
function pathOrdered(connection, columns, key, view, condition, after, limit) {
|
|
460
|
-
const beyond = after === null ? '' : ' AND e.path > ?';
|
|
461
|
-
const parts = layers(view).map((layer) => `SELECT ${columns} FROM replica_entries e WHERE e.key = ? AND ${layer}${condition}${beyond}`);
|
|
462
|
-
return connection.rows(`${parts.join(' UNION ALL ')} ORDER BY path LIMIT ?`, [
|
|
463
|
-
...parts.flatMap(() => (after === null ? [key] : [key, after])),
|
|
464
|
-
limit,
|
|
465
|
-
]);
|
|
466
|
-
}
|
|
467
507
|
export function entries(connection, key, view, list) {
|
|
468
508
|
if (list.length === 0)
|
|
469
509
|
return [];
|
|
@@ -482,19 +522,12 @@ export function typed(connection, key, view, list) {
|
|
|
482
522
|
binary: number(row.binary) === 1,
|
|
483
523
|
}));
|
|
484
524
|
}
|
|
485
|
-
export function referrers(connection, key, view, targets
|
|
525
|
+
export function referrers(connection, key, view, targets) {
|
|
486
526
|
if (targets.length === 0)
|
|
487
527
|
return [];
|
|
488
528
|
return connection
|
|
489
|
-
.rows(`SELECT DISTINCT e.path, l.target
|
|
490
|
-
.map((row) => ({
|
|
491
|
-
path: text(row.path),
|
|
492
|
-
target: text(row.target),
|
|
493
|
-
kind: text(row.kind),
|
|
494
|
-
}));
|
|
495
|
-
}
|
|
496
|
-
export function files(connection, key, view, after, limit) {
|
|
497
|
-
return pathOrdered(connection, 'e.path, e.revision', key, view, ' AND e.content IS NOT NULL AND e.revision IS NOT NULL', after, limit).map((row) => ({ path: text(row.path), revision: text(row.revision) }));
|
|
529
|
+
.rows(`SELECT DISTINCT e.path, l.target FROM replica_links l JOIN replica_entries e ON e.id = l.doc WHERE l.key = ? AND l.target IN (SELECT value FROM json_each(?)) AND ${viewed(view, 'e')}`, [key, paths(targets)])
|
|
530
|
+
.map((row) => ({ path: text(row.path), target: text(row.target) }));
|
|
498
531
|
}
|
|
499
532
|
export function folders(connection, key, view, list) {
|
|
500
533
|
return list.filter((path) => connection.rows(`SELECT 1 FROM replica_folders f WHERE f.key = ? AND f.layer = ${CONFIRMED} AND f.present = 1 AND f.path = ? UNION ALL SELECT 1 FROM replica_entries e WHERE e.key = ? AND ${viewed(view, 'e')} AND e.path >= ? AND e.path < ? LIMIT 1`, [key, path, key, `${path}/`, `${path}0`]).length > 0);
|
|
@@ -502,44 +535,99 @@ export function folders(connection, key, view, list) {
|
|
|
502
535
|
export function typedWithin(connection, key, view, roots, within) {
|
|
503
536
|
return (connection.rows(`SELECT 1 FROM replica_entries e WHERE e.key = ? AND ${viewed(view, 'e')} AND e.declared IS NOT NULL AND e.declared <> 'any' AND ${within ? '' : 'NOT '}${beneathRoots('e.path')} LIMIT 1`, [key, JSON.stringify(roots)]).length > 0);
|
|
504
537
|
}
|
|
538
|
+
const ORPHANS = `SELECT k.key FROM replica_keys k
|
|
539
|
+
WHERE NOT EXISTS (SELECT 1 FROM replica_rooms r WHERE r.key = k.key)
|
|
540
|
+
AND NOT EXISTS (SELECT 1 FROM replica_erasing e WHERE e.key = k.key)
|
|
541
|
+
AND (${UNPARTED} OR NOT EXISTS (
|
|
542
|
+
SELECT 1 FROM replica_entries e WHERE e.key = k.key
|
|
543
|
+
UNION ALL SELECT 1 FROM replica_folders f WHERE f.key = k.key
|
|
544
|
+
))`;
|
|
545
|
+
const STAGED = `SELECT DISTINCT k.locator FROM replica_keys k
|
|
546
|
+
WHERE NOT EXISTS (SELECT 1 FROM replica_rooms r WHERE r.key = k.key)
|
|
547
|
+
AND NOT EXISTS (SELECT 1 FROM replica_erasing e WHERE e.key = k.key)
|
|
548
|
+
AND k.key NOT IN (${ORPHANS})`;
|
|
505
549
|
export function opened(connection) {
|
|
506
|
-
const facts = {};
|
|
507
|
-
for (const row of connection.rows('SELECT name, value FROM replica_facts')) {
|
|
508
|
-
facts[text(row.name)] = text(row.value);
|
|
509
|
-
}
|
|
510
550
|
return {
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
app: text(row.app),
|
|
527
|
-
value: text(row.value),
|
|
528
|
-
})),
|
|
529
|
-
overlaid: connection
|
|
530
|
-
.rows(`SELECT key, path FROM replica_entries WHERE layer = ${OVERLAY}`)
|
|
531
|
-
.map((row) => ({ key: number(row.key), path: text(row.path) })),
|
|
532
|
-
orphans: connection
|
|
533
|
-
.rows(`SELECT k.key FROM replica_keys k
|
|
534
|
-
WHERE NOT EXISTS (SELECT 1 FROM replica_rooms r WHERE r.key = k.key)
|
|
535
|
-
AND NOT EXISTS (SELECT 1 FROM replica_erasing e WHERE e.key = k.key)`)
|
|
536
|
-
.map((row) => number(row.key)),
|
|
537
|
-
erasing: connection.rows('SELECT key, locator FROM replica_erasing').map((row) => ({
|
|
538
|
-
key: number(row.key),
|
|
539
|
-
locator: text(row.locator),
|
|
540
|
-
})),
|
|
551
|
+
orphans: connection.rows(ORPHANS).map((row) => number(row.key)),
|
|
552
|
+
erasing: connection.rows('SELECT 1 FROM replica_erasing LIMIT 1').length > 0,
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
const ROOM_ROWS = `SELECT h.locator, h.key, h.record, r.documents, k.rederiving IS NULL AS indexed
|
|
556
|
+
FROM (${HELD_RECORDS}) h
|
|
557
|
+
JOIN replica_rooms r ON r.locator = h.locator
|
|
558
|
+
LEFT JOIN replica_keys k ON k.key = h.key`;
|
|
559
|
+
function roomRow(row) {
|
|
560
|
+
return {
|
|
561
|
+
locator: text(row.locator),
|
|
562
|
+
key: number(row.key),
|
|
563
|
+
record: text(row.record),
|
|
564
|
+
indexed: number(row.indexed) === 1,
|
|
565
|
+
documents: number(row.documents),
|
|
541
566
|
};
|
|
542
567
|
}
|
|
568
|
+
export function heldRooms(connection, locators) {
|
|
569
|
+
return (locators === null
|
|
570
|
+
? connection.rows(`${ROOM_ROWS} ORDER BY h.locator`)
|
|
571
|
+
: connection.rows(`${ROOM_ROWS} WHERE h.locator IN (SELECT value FROM json_each(?)) ORDER BY h.locator`, [JSON.stringify(locators)])).map(roomRow);
|
|
572
|
+
}
|
|
573
|
+
export function heldRoom(connection, locator) {
|
|
574
|
+
return heldRooms(connection, [locator])[0] ?? null;
|
|
575
|
+
}
|
|
576
|
+
export function overlaid(connection, key) {
|
|
577
|
+
return connection
|
|
578
|
+
.rows(`SELECT path FROM replica_entries WHERE key = ? AND layer = ${OVERLAY}`, [key])
|
|
579
|
+
.map((row) => text(row.path));
|
|
580
|
+
}
|
|
581
|
+
export function covering(connection) {
|
|
582
|
+
return connection
|
|
583
|
+
.rows(`SELECT r.locator, r.key, r.documents, json_extract(r.record, '$.transfer') AS transfer,
|
|
584
|
+
json_extract(r.record, '$.roomVersion') AS room_version,
|
|
585
|
+
coalesce(json_extract(r.record, '$.inventory.bytes'), 0) AS bytes,
|
|
586
|
+
json_extract(r.record, '$.replica.offline') AS offline,
|
|
587
|
+
k.rederiving IS NULL AS indexed
|
|
588
|
+
FROM replica_rooms r LEFT JOIN replica_keys k ON k.key = r.key ORDER BY r.locator`)
|
|
589
|
+
.map((row) => ({
|
|
590
|
+
locator: text(row.locator),
|
|
591
|
+
key: number(row.key),
|
|
592
|
+
transfer: text(row.transfer),
|
|
593
|
+
roomVersion: text(row.room_version),
|
|
594
|
+
indexed: number(row.indexed) === 1,
|
|
595
|
+
documents: number(row.documents),
|
|
596
|
+
bytes: number(row.bytes),
|
|
597
|
+
offline: text(row.offline),
|
|
598
|
+
}));
|
|
599
|
+
}
|
|
600
|
+
export function offlineMode(connection, locator) {
|
|
601
|
+
const [held] = connection.rows("SELECT json_extract(record, '$.replica.offline') AS offline FROM replica_rooms WHERE locator = ?", [locator]);
|
|
602
|
+
return text(held?.offline);
|
|
603
|
+
}
|
|
604
|
+
export function stagedLocators(connection) {
|
|
605
|
+
return connection.rows(STAGED).map((row) => text(row.locator));
|
|
606
|
+
}
|
|
607
|
+
export function heldLocators(connection) {
|
|
608
|
+
return connection
|
|
609
|
+
.rows(`SELECT locator FROM replica_rooms
|
|
610
|
+
UNION SELECT locator FROM authored_room_drafts
|
|
611
|
+
UNION SELECT locator FROM authored_queues
|
|
612
|
+
UNION ${STAGED}`)
|
|
613
|
+
.map((row) => text(row.locator));
|
|
614
|
+
}
|
|
615
|
+
export function demoted(connection) {
|
|
616
|
+
connection.run(`UPDATE replica_rooms SET record = json_set(record, '$.model.status', 'cached')
|
|
617
|
+
WHERE json_extract(record, '$.model.status') = 'current'`);
|
|
618
|
+
return null;
|
|
619
|
+
}
|
|
620
|
+
export function facts(connection) {
|
|
621
|
+
const held = {};
|
|
622
|
+
for (const row of connection.rows('SELECT name, value FROM replica_facts')) {
|
|
623
|
+
held[text(row.name)] = text(row.value);
|
|
624
|
+
}
|
|
625
|
+
return held;
|
|
626
|
+
}
|
|
627
|
+
export function presentation(connection, app) {
|
|
628
|
+
const [held] = connection.rows('SELECT value FROM replica_presentation WHERE app = ?', [app]);
|
|
629
|
+
return text(held?.value);
|
|
630
|
+
}
|
|
543
631
|
export function ended(connection) {
|
|
544
632
|
for (const statement of REPLICA_TABLES) {
|
|
545
633
|
const table = /^CREATE TABLE (\w+)/u.exec(statement)?.[1];
|