@agentshouse/mdruntime 0.1.0-ce41fec66d91b → 0.1.0-ce5b3c1e6ea87
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 +2 -2
- 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 +251 -0
- package/dist/adapter.d.ts +44 -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 +20 -4
- 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 +6 -6
- package/dist/compile.d.ts.map +1 -1
- package/dist/compile.js +231 -300
- package/dist/connection.d.ts +5 -141
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +101 -5058
- 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 +136 -0
- package/dist/conversation-live.d.ts.map +1 -0
- package/dist/conversation-live.js +248 -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 +34 -38
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +856 -850
- 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 -7
- 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 +4 -5
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +23 -22
- 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 +23 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- 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 +268 -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 +5 -1
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +47 -8
- package/dist/messages.d.ts +27 -3
- package/dist/messages.d.ts.map +1 -1
- package/dist/messages.js +97 -19
- 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 +57 -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 -208
- 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/reach.d.ts +14 -12
- package/dist/reach.d.ts.map +1 -1
- package/dist/reach.js +167 -114
- package/dist/react.d.ts +10 -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/readiness.d.ts +0 -2
- package/dist/readiness.d.ts.map +1 -1
- package/dist/reads.d.ts +37 -0
- package/dist/reads.d.ts.map +1 -0
- package/dist/reads.js +171 -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 +7 -0
- 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 +52 -16
- package/dist/room-draft.d.ts +4 -3
- package/dist/room-draft.d.ts.map +1 -1
- package/dist/room-draft.js +65 -52
- package/dist/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 -21
- package/dist/rows.d.ts.map +1 -1
- package/dist/rows.js +48 -184
- package/dist/runtime.d.ts +43 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +1 -0
- package/dist/save.d.ts +3 -1
- package/dist/save.d.ts.map +1 -1
- package/dist/save.js +16 -11
- package/dist/saves.d.ts +70 -0
- package/dist/saves.d.ts.map +1 -0
- package/dist/saves.js +1006 -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 -0
- package/dist/shared.d.ts +1 -1
- package/dist/shared.d.ts.map +1 -1
- package/dist/shared.js +9 -5
- package/dist/shown.d.ts +31 -0
- package/dist/shown.d.ts.map +1 -0
- package/dist/shown.js +295 -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 -145
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +143 -366
- package/dist/stored.d.ts +58 -32
- package/dist/stored.d.ts.map +1 -1
- package/dist/stored.js +264 -187
- 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 +20 -0
- package/dist/sync.d.ts.map +1 -0
- package/dist/sync.js +532 -0
- package/dist/tables.d.ts +117 -27
- package/dist/tables.d.ts.map +1 -1
- package/dist/tables.js +211 -49
- 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 +17 -1
- package/dist/wire.d.ts.map +1 -1
- package/dist/wire.js +7 -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/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,19 +1,20 @@
|
|
|
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
|
-
'CREATE TABLE
|
|
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 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)",
|
|
8
9
|
'CREATE UNIQUE INDEX replica_entries_path ON replica_entries (key, layer, path)',
|
|
9
10
|
'CREATE INDEX replica_entries_visible ON replica_entries (key, visible, present, path, binary)',
|
|
10
11
|
'CREATE INDEX replica_entries_folder ON replica_entries (key, folder, path)',
|
|
11
12
|
'CREATE INDEX replica_entries_type ON replica_entries (key, type, visible, present, queried, folder)',
|
|
12
13
|
'CREATE INDEX replica_entries_key ON replica_entries (key)',
|
|
13
|
-
|
|
14
|
+
sql.VALUE_TABLE,
|
|
14
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',
|
|
15
16
|
'CREATE INDEX replica_links_target ON replica_links (key, target, kind, keys)',
|
|
16
|
-
'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',
|
|
17
18
|
'CREATE TABLE replica_erasing (key INTEGER PRIMARY KEY, locator TEXT NOT NULL)',
|
|
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',
|
|
@@ -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(?)', [
|
|
@@ -75,27 +69,15 @@ function entryId(connection, key, layer, path) {
|
|
|
75
69
|
const [row] = connection.rows('SELECT id FROM replica_entries WHERE key = ? AND layer = ? AND path = ?', [key, layer, path]);
|
|
76
70
|
return row === undefined ? null : number(row.id);
|
|
77
71
|
}
|
|
78
|
-
function
|
|
79
|
-
return { dropped: [], made: [] };
|
|
80
|
-
}
|
|
81
|
-
function wordsWritten(connection, owed) {
|
|
82
|
-
unindexDocuments(connection, owed.dropped);
|
|
83
|
-
for (const { id, path, content } of owed.made)
|
|
84
|
-
indexDocument(connection, id, path, content);
|
|
85
|
-
}
|
|
86
|
-
function removeEntry(connection, key, layer, path, owed) {
|
|
72
|
+
function removeEntry(connection, key, layer, path) {
|
|
87
73
|
const id = entryId(connection, key, layer, path);
|
|
88
74
|
if (id === null)
|
|
89
75
|
return;
|
|
90
76
|
dropDerived(connection, id);
|
|
91
|
-
owed.dropped.push(id);
|
|
92
77
|
connection.run('DELETE FROM replica_entries WHERE id = ?', [id]);
|
|
93
78
|
}
|
|
94
|
-
function
|
|
95
|
-
|
|
96
|
-
}
|
|
97
|
-
function insertEntry(connection, key, layer, entry, present, made) {
|
|
98
|
-
connection.run('INSERT INTO replica_entries (key, layer, path, visible, present, queried, content, binary, revision, file_id, change, written, type, declared, folder, fields) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', [
|
|
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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', [
|
|
99
81
|
key,
|
|
100
82
|
layer,
|
|
101
83
|
entry.path,
|
|
@@ -106,32 +88,34 @@ function insertEntry(connection, key, layer, entry, present, made) {
|
|
|
106
88
|
entry.binary === null ? null : JSON.stringify(entry.binary),
|
|
107
89
|
entry.revision,
|
|
108
90
|
entry.fileId,
|
|
91
|
+
entry.created,
|
|
92
|
+
instantKey(entry.created),
|
|
109
93
|
entry.change === null ? null : JSON.stringify(entry.change),
|
|
94
|
+
instantKey(entry.change?.time),
|
|
110
95
|
entry.written,
|
|
111
96
|
made.type,
|
|
112
97
|
made.declared,
|
|
113
98
|
made.folder,
|
|
114
99
|
made.fields,
|
|
100
|
+
made.links,
|
|
101
|
+
part,
|
|
115
102
|
]);
|
|
116
103
|
}
|
|
117
104
|
function textOf(entry) {
|
|
118
105
|
return entry.binary === null ? entry.content : null;
|
|
119
106
|
}
|
|
120
|
-
function putEntry(connection, key, layer, entry, present, composition
|
|
121
|
-
removeEntry(connection, key, layer, entry.path
|
|
107
|
+
function putEntry(connection, key, layer, entry, present, composition) {
|
|
108
|
+
removeEntry(connection, key, layer, entry.path);
|
|
122
109
|
const content = textOf(entry);
|
|
123
|
-
|
|
124
|
-
insertEntry(connection, key, layer, entry, present, made);
|
|
110
|
+
insertEntry(connection, key, layer, entry, present, present ? described(entry.path, content, entry.facts) : ABSENT);
|
|
125
111
|
if (!present)
|
|
126
112
|
return;
|
|
127
113
|
const id = entryId(connection, key, layer, entry.path);
|
|
128
|
-
writeDerived(connection, id, key,
|
|
129
|
-
if (searched && content !== null && made.queried)
|
|
130
|
-
owed.made.push({ id, path: entry.path, content });
|
|
114
|
+
writeDerived(connection, id, key, entry.path, heldOf(entry.path, content, entry.facts), composition);
|
|
131
115
|
}
|
|
132
|
-
function placeEntry(connection, key, entry,
|
|
133
|
-
removeEntry(connection, key, CONFIRMED, entry.path
|
|
134
|
-
insertEntry(connection, key, CONFIRMED, entry, true, described(entry.path, textOf(entry)));
|
|
116
|
+
function placeEntry(connection, key, entry, part) {
|
|
117
|
+
removeEntry(connection, key, CONFIRMED, entry.path);
|
|
118
|
+
insertEntry(connection, key, CONFIRMED, entry, true, described(entry.path, textOf(entry), entry.facts), part);
|
|
135
119
|
}
|
|
136
120
|
function revealed(connection, key, touched) {
|
|
137
121
|
if (touched.length === 0)
|
|
@@ -140,7 +124,7 @@ function revealed(connection, key, touched) {
|
|
|
140
124
|
}
|
|
141
125
|
function newKey(connection, locator, transfer, fingerprint, built) {
|
|
142
126
|
const owed = built ? null : 0;
|
|
143
|
-
connection.run('INSERT INTO replica_keys (locator, transfer, fingerprint, rederiving
|
|
127
|
+
connection.run('INSERT INTO replica_keys (locator, transfer, fingerprint, rederiving) VALUES (?, ?, ?, ?)', [locator, transfer, fingerprint, owed]);
|
|
144
128
|
const [row] = connection.rows('SELECT last_insert_rowid() AS key');
|
|
145
129
|
return number(row.key);
|
|
146
130
|
}
|
|
@@ -153,36 +137,96 @@ function recomposed(connection, key, fingerprint) {
|
|
|
153
137
|
}
|
|
154
138
|
export function entered(connection, locator, composition, rows) {
|
|
155
139
|
const key = newKey(connection, locator, '', composedOf(composition).fingerprint, true);
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
putEntry(connection, key, CONFIRMED, entry, true, composition, owed, false);
|
|
159
|
-
}
|
|
160
|
-
wordsWritten(connection, owed);
|
|
140
|
+
for (const entry of rows)
|
|
141
|
+
putEntry(connection, key, CONFIRMED, entry, true, composition);
|
|
161
142
|
return key;
|
|
162
143
|
}
|
|
163
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
|
+
}
|
|
164
150
|
const key = request.key ??
|
|
165
151
|
newKey(connection, request.locator, request.transfer, request.fingerprint, false);
|
|
166
152
|
recomposed(connection, key, request.fingerprint);
|
|
167
|
-
connection
|
|
168
|
-
const owed = words();
|
|
153
|
+
owing(connection, key);
|
|
169
154
|
for (const entry of request.entries)
|
|
170
|
-
placeEntry(connection, key, entry,
|
|
155
|
+
placeEntry(connection, key, entry, request.part);
|
|
171
156
|
for (const path of request.folders) {
|
|
172
|
-
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]);
|
|
173
158
|
}
|
|
174
|
-
wordsWritten(connection, owed);
|
|
175
159
|
return key;
|
|
176
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
|
+
}
|
|
177
222
|
export function refreshing(connection, request) {
|
|
178
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]);
|
|
179
224
|
if (held.length === 0)
|
|
180
225
|
return null;
|
|
181
226
|
recomposed(connection, request.key, request.composed.fingerprint);
|
|
182
227
|
const composition = request.composed.composition;
|
|
183
|
-
const owed = words();
|
|
184
228
|
for (const entry of request.entries) {
|
|
185
|
-
putEntry(connection, request.key, REFRESHED, entry, true, composition
|
|
229
|
+
putEntry(connection, request.key, REFRESHED, entry, true, composition);
|
|
186
230
|
}
|
|
187
231
|
for (const path of request.removals) {
|
|
188
232
|
putEntry(connection, request.key, REFRESHED, {
|
|
@@ -191,9 +235,11 @@ export function refreshing(connection, request) {
|
|
|
191
235
|
binary: null,
|
|
192
236
|
revision: null,
|
|
193
237
|
fileId: null,
|
|
238
|
+
created: null,
|
|
194
239
|
change: null,
|
|
195
240
|
written: null,
|
|
196
|
-
|
|
241
|
+
facts: null,
|
|
242
|
+
}, false, composition);
|
|
197
243
|
}
|
|
198
244
|
for (const [list, present] of [
|
|
199
245
|
[request.folders, 1],
|
|
@@ -203,11 +249,9 @@ export function refreshing(connection, request) {
|
|
|
203
249
|
connection.run('INSERT OR REPLACE INTO replica_folders (key, layer, path, present) VALUES (?, ?, ?, ?)', [request.key, REFRESHED, path, present]);
|
|
204
250
|
}
|
|
205
251
|
}
|
|
206
|
-
wordsWritten(connection, owed);
|
|
207
252
|
return null;
|
|
208
253
|
}
|
|
209
254
|
function dropLayer(connection, key, layer) {
|
|
210
|
-
unindexDocuments(connection, heldIds(connection, 'SELECT id FROM replica_entries WHERE key = ? AND layer = ?', [key, layer]));
|
|
211
255
|
for (const table of ['replica_values', 'replica_links']) {
|
|
212
256
|
connection.run(`DELETE FROM ${table} WHERE doc IN (SELECT id FROM replica_entries WHERE key = ? AND layer = ?)`, [key, layer]);
|
|
213
257
|
}
|
|
@@ -226,7 +270,6 @@ function refreshedPaths(connection, key) {
|
|
|
226
270
|
function applyRefresh(connection, key) {
|
|
227
271
|
const touched = refreshedPaths(connection, key);
|
|
228
272
|
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}`;
|
|
229
|
-
unindexDocuments(connection, heldIds(connection, replaced, [key]));
|
|
230
273
|
for (const table of ['replica_values', 'replica_links']) {
|
|
231
274
|
connection.run(`DELETE FROM ${table} WHERE doc IN (${replaced})`, [key]);
|
|
232
275
|
}
|
|
@@ -252,15 +295,18 @@ function counted(connection, key, roots) {
|
|
|
252
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)]);
|
|
253
296
|
return number(row.held);
|
|
254
297
|
}
|
|
255
|
-
export function counts(connection, rooms) {
|
|
256
|
-
return rooms.map(({ key, roots }) => counted(connection, key, roots));
|
|
257
|
-
}
|
|
258
298
|
function erasing(connection, key, locator) {
|
|
259
299
|
connection.run('INSERT OR REPLACE INTO replica_erasing (key, locator) VALUES (?, ?)', [
|
|
260
300
|
key,
|
|
261
301
|
locator,
|
|
262
302
|
]);
|
|
263
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
|
+
}
|
|
264
310
|
function commitRoom(connection, room) {
|
|
265
311
|
const touched = new Set();
|
|
266
312
|
recomposed(connection, room.key, room.composed.fingerprint);
|
|
@@ -274,51 +320,64 @@ function commitRoom(connection, room) {
|
|
|
274
320
|
for (const path of applyRefresh(connection, room.key))
|
|
275
321
|
touched.add(path);
|
|
276
322
|
}
|
|
277
|
-
const owed = words();
|
|
278
323
|
for (const entry of room.confirmed?.set ?? []) {
|
|
279
|
-
putEntry(connection, room.key, CONFIRMED, entry, true, composition
|
|
324
|
+
putEntry(connection, room.key, CONFIRMED, entry, true, composition);
|
|
280
325
|
touched.add(entry.path);
|
|
281
326
|
}
|
|
282
327
|
for (const path of room.confirmed?.removed ?? []) {
|
|
283
|
-
removeEntry(connection, room.key, CONFIRMED, path
|
|
328
|
+
removeEntry(connection, room.key, CONFIRMED, path);
|
|
284
329
|
touched.add(path);
|
|
285
330
|
}
|
|
331
|
+
const savedAt = new Date().toISOString();
|
|
286
332
|
for (const entry of room.overlay?.set ?? []) {
|
|
287
|
-
putEntry(connection, room.key, OVERLAY, entry, entry.present, composition
|
|
333
|
+
putEntry(connection, room.key, OVERLAY, saved(connection, room.key, entry, savedAt), entry.present, composition);
|
|
288
334
|
touched.add(entry.path);
|
|
289
335
|
}
|
|
290
336
|
for (const path of room.overlay?.cleared ?? []) {
|
|
291
|
-
removeEntry(connection, room.key, OVERLAY, path
|
|
337
|
+
removeEntry(connection, room.key, OVERLAY, path);
|
|
292
338
|
touched.add(path);
|
|
293
339
|
}
|
|
294
340
|
const changed = [...touched];
|
|
295
341
|
revealed(connection, room.key, changed);
|
|
296
342
|
if (room.record !== undefined) {
|
|
297
|
-
connection.run(
|
|
298
|
-
|
|
299
|
-
room.key,
|
|
300
|
-
room.record,
|
|
301
|
-
]);
|
|
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]);
|
|
302
345
|
}
|
|
303
|
-
wordsWritten(connection, owed);
|
|
304
346
|
return room.published === undefined ? changed : null;
|
|
305
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')`;
|
|
306
365
|
export function commit(connection, rooms) {
|
|
307
|
-
const counted = {};
|
|
308
366
|
const changed = {};
|
|
309
367
|
const indexed = {};
|
|
310
368
|
for (const room of rooms) {
|
|
311
369
|
changed[room.locator] = commitRoom(connection, room);
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
const [held] = connection.rows('SELECT rederiving, searching FROM replica_keys WHERE key = ?', [
|
|
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,
|
|
316
373
|
room.key,
|
|
317
374
|
]);
|
|
318
|
-
|
|
319
|
-
|
|
375
|
+
const [held] = connection.rows('SELECT rederiving FROM replica_keys WHERE key = ?', [room.key]);
|
|
376
|
+
indexed[room.locator] = held !== undefined && held.rederiving === null;
|
|
320
377
|
}
|
|
321
|
-
|
|
378
|
+
if (rooms.some((room) => room.record !== undefined))
|
|
379
|
+
connection.run(UNHELD_MODELS);
|
|
380
|
+
return { changed, indexed };
|
|
322
381
|
}
|
|
323
382
|
function rootsOf(connection, locator) {
|
|
324
383
|
const [row] = connection.rows('SELECT record FROM replica_rooms WHERE locator = ?', [locator]);
|
|
@@ -332,6 +391,7 @@ export function fenceRooms(connection, locators) {
|
|
|
332
391
|
}
|
|
333
392
|
connection.run('DELETE FROM replica_rooms WHERE locator = ?', [locator]);
|
|
334
393
|
}
|
|
394
|
+
connection.run(UNHELD_MODELS);
|
|
335
395
|
return null;
|
|
336
396
|
}
|
|
337
397
|
export function abandon(connection, locator) {
|
|
@@ -355,7 +415,6 @@ export function erase(connection, locator, limit) {
|
|
|
355
415
|
return { remaining: false };
|
|
356
416
|
const key = number(held.key);
|
|
357
417
|
const batch = 'SELECT id FROM replica_entries WHERE key = ? ORDER BY id LIMIT ?';
|
|
358
|
-
unindexDocuments(connection, heldIds(connection, batch, [key, limit]));
|
|
359
418
|
for (const table of ['replica_values', 'replica_links']) {
|
|
360
419
|
connection.run(`DELETE FROM ${table} WHERE doc IN (${batch})`, [key, limit]);
|
|
361
420
|
}
|
|
@@ -375,40 +434,31 @@ function cursor(value) {
|
|
|
375
434
|
export function rederive(connection, key, composed, bytes, ms, floor) {
|
|
376
435
|
const started = performance.now();
|
|
377
436
|
recomposed(connection, key, composed.fingerprint);
|
|
378
|
-
const [held] = connection.rows('SELECT rederiving
|
|
379
|
-
key,
|
|
380
|
-
]);
|
|
437
|
+
const [held] = connection.rows('SELECT rederiving FROM replica_keys WHERE key = ?', [key]);
|
|
381
438
|
const deriving = cursor(held?.rederiving);
|
|
382
|
-
|
|
383
|
-
if (deriving === null && searching === null)
|
|
439
|
+
if (deriving === null)
|
|
384
440
|
return { done: true, text: 0 };
|
|
385
441
|
const composition = composed.composition;
|
|
386
|
-
let last =
|
|
442
|
+
let last = deriving;
|
|
387
443
|
let spent = 0;
|
|
388
444
|
let built = 0;
|
|
389
445
|
let read = false;
|
|
390
|
-
const late = () => spent >= floor && performance.now() - started >= ms;
|
|
391
|
-
const owed = [];
|
|
392
446
|
reading: for (;;) {
|
|
393
|
-
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]);
|
|
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]);
|
|
394
448
|
for (const row of rows) {
|
|
395
449
|
const id = number(row.id);
|
|
396
450
|
const path = text(row.path);
|
|
397
|
-
const
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
if (owedWords && described(path, content).queried)
|
|
406
|
-
owed.push({ id, path, content });
|
|
407
|
-
else if (owedRows)
|
|
408
|
-
built += content?.length ?? 0;
|
|
451
|
+
const size = row.size === null ? 0 : number(row.size);
|
|
452
|
+
dropDerived(connection, id);
|
|
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;
|
|
409
459
|
last = id;
|
|
410
|
-
spent += ENTRY_WEIGHT +
|
|
411
|
-
if (spent >= bytes ||
|
|
460
|
+
spent += ENTRY_WEIGHT + size;
|
|
461
|
+
if (spent >= bytes || (spent >= floor && performance.now() - started >= ms))
|
|
412
462
|
break reading;
|
|
413
463
|
}
|
|
414
464
|
if (rows.length < DERIVED_ROWS) {
|
|
@@ -416,23 +466,8 @@ export function rederive(connection, key, composed, bytes, ms, floor) {
|
|
|
416
466
|
break;
|
|
417
467
|
}
|
|
418
468
|
}
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
indexDocument(connection, id, path, content);
|
|
422
|
-
built += content.length;
|
|
423
|
-
const next = owed[at + 1];
|
|
424
|
-
if (next !== undefined && late()) {
|
|
425
|
-
searched = next.id - 1;
|
|
426
|
-
break;
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
const done = read && searched === last;
|
|
430
|
-
connection.run('UPDATE replica_keys SET rederiving = ?, searching = ? WHERE key = ?', [
|
|
431
|
-
deriving === null || read ? null : Math.max(deriving, last),
|
|
432
|
-
searching === null || done ? null : Math.max(searching, searched),
|
|
433
|
-
key,
|
|
434
|
-
]);
|
|
435
|
-
return { done, text: built };
|
|
469
|
+
connection.run('UPDATE replica_keys SET rederiving = ? WHERE key = ?', [read ? null : last, key]);
|
|
470
|
+
return { done: read, text: built };
|
|
436
471
|
}
|
|
437
472
|
function heldEntry(row) {
|
|
438
473
|
return {
|
|
@@ -441,12 +476,24 @@ function heldEntry(row) {
|
|
|
441
476
|
binary: json(row.binary),
|
|
442
477
|
revision: text(row.revision),
|
|
443
478
|
fileId: text(row.file_id),
|
|
479
|
+
created: text(row.created),
|
|
444
480
|
change: json(row.change),
|
|
445
481
|
written: text(row.written),
|
|
446
482
|
type: text(row.type),
|
|
483
|
+
facts: factsHeld(row),
|
|
484
|
+
};
|
|
485
|
+
}
|
|
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) ?? [],
|
|
447
494
|
};
|
|
448
495
|
}
|
|
449
|
-
const ENTRY_COLUMNS = 'e.path, e.content, e.binary, e.revision, e.file_id, e.change, e.written, e.type';
|
|
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';
|
|
450
497
|
function unrefreshed(alias) {
|
|
451
498
|
return `NOT EXISTS (SELECT 1 FROM replica_entries r WHERE r.key = ${alias}.key AND r.layer = ${REFRESHED} AND r.path = ${alias}.path)`;
|
|
452
499
|
}
|
|
@@ -457,22 +504,6 @@ function viewed(view, alias) {
|
|
|
457
504
|
return `${alias}.layer = ${CONFIRMED}`;
|
|
458
505
|
return `${alias}.present = 1 AND (${alias}.layer = ${REFRESHED} OR (${alias}.layer = ${CONFIRMED} AND ${unrefreshed(alias)}))`;
|
|
459
506
|
}
|
|
460
|
-
function layers(view) {
|
|
461
|
-
if (view !== 'refreshed')
|
|
462
|
-
return [viewed(view, 'e')];
|
|
463
|
-
return [
|
|
464
|
-
`e.layer = ${REFRESHED} AND e.present = 1`,
|
|
465
|
-
`e.layer = ${CONFIRMED} AND e.present = 1 AND ${unrefreshed('e')}`,
|
|
466
|
-
];
|
|
467
|
-
}
|
|
468
|
-
function pathOrdered(connection, columns, key, view, condition, after, limit) {
|
|
469
|
-
const beyond = after === null ? '' : ' AND e.path > ?';
|
|
470
|
-
const parts = layers(view).map((layer) => `SELECT ${columns} FROM replica_entries e WHERE e.key = ? AND ${layer}${condition}${beyond}`);
|
|
471
|
-
return connection.rows(`${parts.join(' UNION ALL ')} ORDER BY path LIMIT ?`, [
|
|
472
|
-
...parts.flatMap(() => (after === null ? [key] : [key, after])),
|
|
473
|
-
limit,
|
|
474
|
-
]);
|
|
475
|
-
}
|
|
476
507
|
export function entries(connection, key, view, list) {
|
|
477
508
|
if (list.length === 0)
|
|
478
509
|
return [];
|
|
@@ -491,19 +522,12 @@ export function typed(connection, key, view, list) {
|
|
|
491
522
|
binary: number(row.binary) === 1,
|
|
492
523
|
}));
|
|
493
524
|
}
|
|
494
|
-
export function referrers(connection, key, view, targets
|
|
525
|
+
export function referrers(connection, key, view, targets) {
|
|
495
526
|
if (targets.length === 0)
|
|
496
527
|
return [];
|
|
497
528
|
return connection
|
|
498
|
-
.rows(`SELECT DISTINCT e.path, l.target
|
|
499
|
-
.map((row) => ({
|
|
500
|
-
path: text(row.path),
|
|
501
|
-
target: text(row.target),
|
|
502
|
-
kind: text(row.kind),
|
|
503
|
-
}));
|
|
504
|
-
}
|
|
505
|
-
export function files(connection, key, view, after, limit) {
|
|
506
|
-
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) }));
|
|
507
531
|
}
|
|
508
532
|
export function folders(connection, key, view, list) {
|
|
509
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);
|
|
@@ -511,50 +535,103 @@ export function folders(connection, key, view, list) {
|
|
|
511
535
|
export function typedWithin(connection, key, view, roots, within) {
|
|
512
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);
|
|
513
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})`;
|
|
514
549
|
export function opened(connection) {
|
|
515
|
-
const facts = {};
|
|
516
|
-
for (const row of connection.rows('SELECT name, value FROM replica_facts')) {
|
|
517
|
-
facts[text(row.name)] = text(row.value);
|
|
518
|
-
}
|
|
519
550
|
return {
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
presentation: connection.rows('SELECT app, value FROM replica_presentation').map((row) => ({
|
|
536
|
-
app: text(row.app),
|
|
537
|
-
value: text(row.value),
|
|
538
|
-
})),
|
|
539
|
-
overlaid: connection
|
|
540
|
-
.rows(`SELECT key, path FROM replica_entries WHERE layer = ${OVERLAY}`)
|
|
541
|
-
.map((row) => ({ key: number(row.key), path: text(row.path) })),
|
|
542
|
-
orphans: connection
|
|
543
|
-
.rows(`SELECT k.key FROM replica_keys k
|
|
544
|
-
WHERE NOT EXISTS (SELECT 1 FROM replica_rooms r WHERE r.key = k.key)
|
|
545
|
-
AND NOT EXISTS (SELECT 1 FROM replica_erasing e WHERE e.key = k.key)`)
|
|
546
|
-
.map((row) => number(row.key)),
|
|
547
|
-
erasing: connection.rows('SELECT key, locator FROM replica_erasing').map((row) => ({
|
|
548
|
-
key: number(row.key),
|
|
549
|
-
locator: text(row.locator),
|
|
550
|
-
})),
|
|
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),
|
|
551
566
|
};
|
|
552
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
|
+
}
|
|
553
631
|
export function ended(connection) {
|
|
554
632
|
for (const statement of REPLICA_TABLES) {
|
|
555
633
|
const table = /^CREATE TABLE (\w+)/u.exec(statement)?.[1];
|
|
556
634
|
if (table !== undefined)
|
|
557
635
|
connection.run(`DELETE FROM ${table}`);
|
|
558
636
|
}
|
|
559
|
-
unindexAll(connection);
|
|
560
637
|
}
|