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