@sixb/sqlite 0.1.0 → 0.1.2
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 +18 -13
- package/dist/action-run-storage.d.ts +5 -2
- package/dist/action-run-storage.d.ts.map +1 -1
- package/dist/agents/agent-storage.d.ts +4 -2
- package/dist/agents/agent-storage.d.ts.map +1 -1
- package/dist/agents/rows.d.ts +3 -10
- package/dist/agents/rows.d.ts.map +1 -1
- package/dist/agents/runs.d.ts +3 -2
- package/dist/agents/runs.d.ts.map +1 -1
- package/dist/ai-usage-storage.d.ts +22 -0
- package/dist/ai-usage-storage.d.ts.map +1 -0
- package/dist/auth-storage/service-accounts.d.ts.map +1 -1
- package/dist/auth-storage/shared.d.ts +1 -10
- package/dist/auth-storage/shared.d.ts.map +1 -1
- package/dist/connector-connection-storage.d.ts +9 -0
- package/dist/connector-connection-storage.d.ts.map +1 -0
- package/dist/execution-storage.d.ts +14 -0
- package/dist/execution-storage.d.ts.map +1 -0
- package/dist/index.d.ts +13 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4114 -1149
- package/dist/index.js.map +30 -27
- package/dist/latest-run-query.d.ts.map +1 -1
- package/dist/migrations.d.ts +0 -1
- package/dist/migrations.d.ts.map +1 -1
- package/dist/ontology-storage/materialization-session.d.ts +50 -8
- package/dist/ontology-storage/materialization-session.d.ts.map +1 -1
- package/dist/ontology-storage/materialization-state.d.ts +4 -5
- package/dist/ontology-storage/materialization-state.d.ts.map +1 -1
- package/dist/ontology-storage/materialization-writer.d.ts.map +1 -1
- package/dist/ontology-storage/materializations.d.ts +0 -2
- package/dist/ontology-storage/materializations.d.ts.map +1 -1
- package/dist/ontology-storage/outbox.d.ts.map +1 -1
- package/dist/ontology-storage/shared.d.ts +3 -3
- package/dist/ontology-storage/shared.d.ts.map +1 -1
- package/dist/ontology-storage/sources.d.ts.map +1 -1
- package/dist/pipeline-run-storage.d.ts +7 -2
- package/dist/pipeline-run-storage.d.ts.map +1 -1
- package/dist/projection-run-storage.d.ts +9 -2
- package/dist/projection-run-storage.d.ts.map +1 -1
- package/dist/run-list-query.d.ts +1 -1
- package/dist/run-list-query.d.ts.map +1 -1
- package/dist/sync-run-storage.d.ts +7 -2
- package/dist/sync-run-storage.d.ts.map +1 -1
- package/dist/testing.d.ts +6 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/transactions.d.ts +3 -0
- package/dist/transactions.d.ts.map +1 -1
- package/dist/webhook-run-storage.d.ts +9 -2
- package/dist/webhook-run-storage.d.ts.map +1 -1
- package/dist/workflow-run-storage.d.ts +7 -3
- package/dist/workflow-run-storage.d.ts.map +1 -1
- package/package.json +4 -3
- package/src/action-run-storage.ts +51 -74
- package/src/agents/agent-storage.ts +5 -3
- package/src/agents/rows.ts +8 -40
- package/src/agents/runs.ts +27 -21
- package/src/ai-usage-storage.ts +324 -0
- package/src/auth-storage/service-accounts.ts +14 -21
- package/src/auth-storage/shared.ts +0 -22
- package/src/connector-connection-storage.ts +784 -0
- package/src/execution-storage.ts +158 -0
- package/src/index.ts +63 -22
- package/src/latest-run-query.ts +7 -1
- package/src/migrations/002-workflow-run-output.sql +27 -0
- package/src/migrations/003-merge-sync-runs.sql +71 -0
- package/src/migrations/004-executions.sql +142 -0
- package/src/migrations/005-workflow-executions.sql +7 -0
- package/src/migrations/006-narrow-ontology-source-root-index.sql +4 -0
- package/src/migrations/007-split-overrides.sql +154 -0
- package/src/migrations/008-action-executions.sql +4 -0
- package/src/migrations/009-agent-executions.sql +115 -0
- package/src/migrations/010-ai-usage-accounting-foundation.sql +74 -0
- package/src/migrations/011-sync-failure-record.sql +22 -0
- package/src/migrations/012-pipeline-failure-record.sql +45 -0
- package/src/migrations/013-workflow-failure-record.sql +45 -0
- package/src/migrations/014-agent-failure-record.sql +59 -0
- package/src/migrations/015-projection-failure-record.sql +20 -0
- package/src/migrations/016-webhook-run-failure-record.sql +19 -0
- package/src/migrations/017-action-failure-record.sql +65 -0
- package/src/migrations/018-ontology-outbox-failure-record.sql +80 -0
- package/src/migrations/019-webhook-delivery-failure-record.sql +62 -0
- package/src/migrations/020-drop-run-usage-projections.sql +7 -0
- package/src/migrations/021-sync-pipeline-executions.sql +101 -0
- package/src/migrations/022-projection-executions.sql +244 -0
- package/src/migrations/023-webhook-executions.sql +51 -0
- package/src/migrations/024-ontology-commit-executions.sql +58 -0
- package/src/migrations/025-connector-connections.sql +257 -0
- package/src/migrations.ts +126 -5
- package/src/ontology-storage/materialization-session.ts +317 -143
- package/src/ontology-storage/materialization-state.ts +398 -150
- package/src/ontology-storage/materialization-writer.ts +142 -67
- package/src/ontology-storage/materializations.ts +67 -141
- package/src/ontology-storage/outbox.ts +10 -3
- package/src/ontology-storage/shared.ts +10 -4
- package/src/ontology-storage/sources.ts +4 -1
- package/src/pipeline-run-storage.ts +128 -43
- package/src/projection-run-storage.ts +209 -97
- package/src/run-list-query.ts +9 -4
- package/src/sync-run-storage.ts +120 -34
- package/src/testing.ts +20 -0
- package/src/transactions.ts +10 -3
- package/src/webhook-run-storage.ts +118 -74
- package/src/workflow-run-storage.ts +124 -133
- package/dist/validation.d.ts +0 -5
- package/dist/validation.d.ts.map +0 -1
- package/dist/webhook-delivery-storage.d.ts +0 -27
- package/dist/webhook-delivery-storage.d.ts.map +0 -1
- package/src/validation.ts +0 -30
- package/src/webhook-delivery-storage.ts +0 -272
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
import {
|
|
19
19
|
appendScopeSnapshot,
|
|
20
20
|
finishScopeAccumulator,
|
|
21
|
+
linkSlotOverrideValue,
|
|
21
22
|
startScopeAccumulator,
|
|
22
23
|
} from "@sixb/core/internal/ontology-storage-provider"
|
|
23
24
|
import type {
|
|
@@ -27,6 +28,7 @@ import type {
|
|
|
27
28
|
SourceReplacementLinkState,
|
|
28
29
|
SourceReplacementObjectState,
|
|
29
30
|
StoredLinkOverride,
|
|
31
|
+
StoredLinkSlotOverride,
|
|
30
32
|
StoredObjectOverride,
|
|
31
33
|
StoredSourceAssertion,
|
|
32
34
|
StoredSourceLinkAssertion,
|
|
@@ -38,8 +40,8 @@ import {
|
|
|
38
40
|
linkRefFromColumns,
|
|
39
41
|
objectRefFromColumns,
|
|
40
42
|
parseJson,
|
|
41
|
-
type SqliteOntologyOverrideRow,
|
|
42
43
|
type SqliteOntologySourceAssertionRow,
|
|
44
|
+
type SqliteStoredOverrideRow,
|
|
43
45
|
} from "./shared"
|
|
44
46
|
|
|
45
47
|
export const SQLITE_MATERIALIZATION_WORK_TABLE = "ontology_materialization_work"
|
|
@@ -81,12 +83,12 @@ interface LinkScopeRow extends EffectiveLinkRow {
|
|
|
81
83
|
readonly scope_sort_key: string
|
|
82
84
|
}
|
|
83
85
|
|
|
84
|
-
interface ObjectOverrideRow extends
|
|
86
|
+
interface ObjectOverrideRow extends SqliteStoredOverrideRow {
|
|
85
87
|
readonly object_type_id: string
|
|
86
88
|
readonly primary_id: string
|
|
87
89
|
}
|
|
88
90
|
|
|
89
|
-
interface LinkOverrideRow extends
|
|
91
|
+
interface LinkOverrideRow extends SqliteStoredOverrideRow {
|
|
90
92
|
readonly source_type_id: string
|
|
91
93
|
readonly source_primary_id: string
|
|
92
94
|
readonly link_id: string
|
|
@@ -94,6 +96,17 @@ interface LinkOverrideRow extends SqliteOntologyOverrideRow {
|
|
|
94
96
|
readonly target_primary_id: string
|
|
95
97
|
}
|
|
96
98
|
|
|
99
|
+
interface LinkSlotOverrideRow {
|
|
100
|
+
readonly source_type_id: string
|
|
101
|
+
readonly source_primary_id: string
|
|
102
|
+
readonly link_id: string
|
|
103
|
+
readonly target_type_id: string
|
|
104
|
+
readonly target_primary_id: string
|
|
105
|
+
readonly value: string
|
|
106
|
+
readonly last_commit_id: string
|
|
107
|
+
readonly updated_at: string
|
|
108
|
+
}
|
|
109
|
+
|
|
97
110
|
interface ReplacementSources {
|
|
98
111
|
readonly owned: ReadonlySet<string>
|
|
99
112
|
readonly byMaterialization: ReadonlyMap<string, ReadonlyMap<string, StoredSourceAssertion>>
|
|
@@ -122,6 +135,18 @@ interface ReplacementIdentityInput {
|
|
|
122
135
|
readonly pageRows: number
|
|
123
136
|
}
|
|
124
137
|
|
|
138
|
+
interface ReplacementWorkRow {
|
|
139
|
+
readonly entity_kind: "object" | "link"
|
|
140
|
+
readonly identity_key: string
|
|
141
|
+
readonly sort_key: string
|
|
142
|
+
readonly diff_required: number
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
interface ReplacementCursor {
|
|
146
|
+
readonly sortKey: string
|
|
147
|
+
readonly identityKey: string
|
|
148
|
+
}
|
|
149
|
+
|
|
125
150
|
export class SqliteMaterializationStateReader {
|
|
126
151
|
constructor(
|
|
127
152
|
private readonly db: Database,
|
|
@@ -142,33 +167,43 @@ export class SqliteMaterializationStateReader {
|
|
|
142
167
|
json_extract(value, '$.primaryId') AS primary_id
|
|
143
168
|
FROM json_each(?)
|
|
144
169
|
`
|
|
170
|
+
// Keep the JSON request set on the outer side of each lookup. SQLite cannot estimate the
|
|
171
|
+
// cardinality of json_each() and otherwise scans every project row once per requested key.
|
|
172
|
+
// CROSS JOIN deliberately fixes the loop order so the existing composite indexes are used.
|
|
145
173
|
const effectiveRows = this.db
|
|
146
174
|
.query(
|
|
147
175
|
`WITH requested AS (${requestedObjects})
|
|
148
|
-
SELECT objects.* FROM
|
|
149
|
-
JOIN
|
|
150
|
-
|
|
176
|
+
SELECT objects.* FROM requested
|
|
177
|
+
CROSS JOIN objects
|
|
178
|
+
ON objects.project_id = ?
|
|
179
|
+
AND objects.object_type_id = requested.object_type_id
|
|
180
|
+
AND objects.primary_id = requested.primary_id`
|
|
151
181
|
)
|
|
152
182
|
.all(requested, this.projectId) as EffectiveObjectRow[]
|
|
153
183
|
const sourceRows = this.db
|
|
154
184
|
.query(
|
|
155
185
|
`WITH requested AS (${requestedObjects})
|
|
156
|
-
SELECT rows.* FROM
|
|
157
|
-
JOIN
|
|
186
|
+
SELECT rows.* FROM requested
|
|
187
|
+
CROSS JOIN ontology_source_rows AS rows
|
|
188
|
+
ON rows.project_id = ?
|
|
189
|
+
AND rows.entity_kind = 'object'
|
|
190
|
+
AND rows.object_type_id = requested.object_type_id
|
|
191
|
+
AND rows.primary_id = requested.primary_id
|
|
158
192
|
JOIN ontology_sources AS sources
|
|
159
193
|
ON sources.project_id = rows.project_id
|
|
160
194
|
AND sources.source_id = rows.source_id
|
|
161
195
|
AND sources.materialization_id = rows.materialization_id
|
|
162
|
-
WHERE
|
|
163
|
-
AND sources.status = 'active'`
|
|
196
|
+
WHERE sources.status = 'active'`
|
|
164
197
|
)
|
|
165
198
|
.all(requested, this.projectId) as SqliteOntologySourceAssertionRow[]
|
|
166
199
|
const overrideRows = this.db
|
|
167
200
|
.query(
|
|
168
201
|
`WITH requested AS (${requestedObjects})
|
|
169
|
-
SELECT overrides.* FROM
|
|
170
|
-
JOIN
|
|
171
|
-
|
|
202
|
+
SELECT overrides.* FROM requested
|
|
203
|
+
CROSS JOIN ontology_object_overrides AS overrides
|
|
204
|
+
ON overrides.project_id = ?
|
|
205
|
+
AND overrides.object_type_id = requested.object_type_id
|
|
206
|
+
AND overrides.primary_id = requested.primary_id`
|
|
172
207
|
)
|
|
173
208
|
.all(requested, this.projectId) as ObjectOverrideRow[]
|
|
174
209
|
const telemetryRows = this.db
|
|
@@ -180,11 +215,11 @@ export class SqliteMaterializationStateReader {
|
|
|
180
215
|
timeseries.property_id
|
|
181
216
|
ORDER BY timeseries.at DESC
|
|
182
217
|
) AS rank
|
|
183
|
-
FROM
|
|
184
|
-
JOIN
|
|
185
|
-
ON
|
|
186
|
-
AND
|
|
187
|
-
|
|
218
|
+
FROM requested
|
|
219
|
+
CROSS JOIN timeseries
|
|
220
|
+
ON timeseries.project_id = ?
|
|
221
|
+
AND timeseries.object_type_id = requested.object_type_id
|
|
222
|
+
AND timeseries.object_id = requested.primary_id
|
|
188
223
|
)
|
|
189
224
|
SELECT * FROM ranked WHERE rank = 1`
|
|
190
225
|
)
|
|
@@ -261,36 +296,61 @@ export class SqliteMaterializationStateReader {
|
|
|
261
296
|
const effectiveRows = this.db
|
|
262
297
|
.query(
|
|
263
298
|
`WITH requested AS (${effectiveRequest})
|
|
264
|
-
SELECT links.* FROM
|
|
265
|
-
JOIN
|
|
266
|
-
|
|
299
|
+
SELECT links.* FROM requested
|
|
300
|
+
CROSS JOIN links
|
|
301
|
+
ON links.project_id = ?
|
|
302
|
+
AND links.source_type_id = requested.source_type_id
|
|
303
|
+
AND links.source_id = requested.source_id
|
|
304
|
+
AND links.link_id = requested.link_id
|
|
305
|
+
AND links.target_type_id = requested.target_type_id
|
|
306
|
+
AND links.target_id = requested.target_id`
|
|
267
307
|
)
|
|
268
308
|
.all(requested, this.projectId) as EffectiveLinkRow[]
|
|
269
309
|
const sourceRows = this.db
|
|
270
310
|
.query(
|
|
271
311
|
`WITH requested AS (${sourceRequest})
|
|
272
|
-
SELECT rows.* FROM
|
|
273
|
-
JOIN
|
|
274
|
-
|
|
275
|
-
|
|
312
|
+
SELECT rows.* FROM requested
|
|
313
|
+
CROSS JOIN ontology_source_rows AS rows
|
|
314
|
+
ON rows.project_id = ?
|
|
315
|
+
AND rows.entity_kind = 'link'
|
|
316
|
+
AND rows.source_type_id = requested.source_type_id
|
|
317
|
+
AND rows.source_primary_id = requested.source_primary_id
|
|
318
|
+
AND rows.link_id = requested.link_id
|
|
319
|
+
AND rows.target_type_id = requested.target_type_id
|
|
320
|
+
AND rows.target_primary_id = requested.target_primary_id
|
|
276
321
|
JOIN ontology_sources AS sources
|
|
277
322
|
ON sources.project_id = rows.project_id
|
|
278
323
|
AND sources.source_id = rows.source_id
|
|
279
324
|
AND sources.materialization_id = rows.materialization_id
|
|
280
|
-
WHERE
|
|
281
|
-
AND sources.status = 'active'`
|
|
325
|
+
WHERE sources.status = 'active'`
|
|
282
326
|
)
|
|
283
327
|
.all(requested, this.projectId) as SqliteOntologySourceAssertionRow[]
|
|
284
328
|
const overrideRows = this.db
|
|
285
329
|
.query(
|
|
286
330
|
`WITH requested AS (${sourceRequest})
|
|
287
|
-
SELECT overrides.* FROM
|
|
288
|
-
JOIN
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
331
|
+
SELECT overrides.* FROM requested
|
|
332
|
+
CROSS JOIN ontology_link_overrides AS overrides
|
|
333
|
+
ON overrides.project_id = ?
|
|
334
|
+
AND overrides.identity_kind = 'edge'
|
|
335
|
+
AND overrides.source_type_id = requested.source_type_id
|
|
336
|
+
AND overrides.source_primary_id = requested.source_primary_id
|
|
337
|
+
AND overrides.link_id = requested.link_id
|
|
338
|
+
AND overrides.target_type_id = requested.target_type_id
|
|
339
|
+
AND overrides.target_primary_id = requested.target_primary_id`
|
|
292
340
|
)
|
|
293
341
|
.all(requested, this.projectId) as LinkOverrideRow[]
|
|
342
|
+
const slotOverrideRows = this.db
|
|
343
|
+
.query(
|
|
344
|
+
`WITH requested AS (${sourceRequest})
|
|
345
|
+
SELECT overrides.* FROM requested
|
|
346
|
+
CROSS JOIN ontology_link_overrides AS overrides
|
|
347
|
+
ON overrides.project_id = ?
|
|
348
|
+
AND overrides.identity_kind = 'slot'
|
|
349
|
+
AND overrides.source_type_id = requested.source_type_id
|
|
350
|
+
AND overrides.source_primary_id = requested.source_primary_id
|
|
351
|
+
AND overrides.link_id = requested.link_id`
|
|
352
|
+
)
|
|
353
|
+
.all(requested, this.projectId) as LinkSlotOverrideRow[]
|
|
294
354
|
const effective = new Map(
|
|
295
355
|
effectiveRows.map((row) => [linkRefKey(linkRefFromColumns(row)), row] as const)
|
|
296
356
|
)
|
|
@@ -300,6 +360,12 @@ export class SqliteMaterializationStateReader {
|
|
|
300
360
|
(row) => [linkRefKey(linkRefFromOverrideColumns(row)), storedLinkOverride(row)] as const
|
|
301
361
|
)
|
|
302
362
|
)
|
|
363
|
+
const slotOverrides = new Map(
|
|
364
|
+
slotOverrideRows.map((row) => {
|
|
365
|
+
const stored = storedLinkSlotOverride(row)
|
|
366
|
+
return [linkScopeSortKey(stored.ref.source, stored.ref.linkId), stored] as const
|
|
367
|
+
})
|
|
368
|
+
)
|
|
303
369
|
return refs.map((ref) => {
|
|
304
370
|
const key = linkRefKey(ref)
|
|
305
371
|
const effectiveRow = effective.get(key)
|
|
@@ -307,6 +373,7 @@ export class SqliteMaterializationStateReader {
|
|
|
307
373
|
ref: structuredClone(ref),
|
|
308
374
|
source: sourceLink(sources.get(projectionEntityKey({ kind: "link", ref }))),
|
|
309
375
|
override: overrides.get(key) ?? null,
|
|
376
|
+
slotOverride: slotOverrides.get(linkScopeSortKey(ref.source, ref.linkId)) ?? null,
|
|
310
377
|
effective: effectiveRow ? effectiveLinkSnapshot(effectiveRow) : null,
|
|
311
378
|
}
|
|
312
379
|
})
|
|
@@ -337,9 +404,13 @@ export class SqliteMaterializationStateReader {
|
|
|
337
404
|
json_extract(value, '$.at') AS at
|
|
338
405
|
FROM json_each(?)
|
|
339
406
|
)
|
|
340
|
-
SELECT timeseries.* FROM
|
|
341
|
-
JOIN
|
|
342
|
-
|
|
407
|
+
SELECT timeseries.* FROM requested
|
|
408
|
+
CROSS JOIN timeseries
|
|
409
|
+
ON timeseries.project_id = ?
|
|
410
|
+
AND timeseries.object_type_id = requested.object_type_id
|
|
411
|
+
AND timeseries.object_id = requested.object_id
|
|
412
|
+
AND timeseries.property_id = requested.property_id
|
|
413
|
+
AND timeseries.at = requested.at`
|
|
343
414
|
)
|
|
344
415
|
.all(requested, this.projectId) as TelemetryRow[]
|
|
345
416
|
const found = new Map(
|
|
@@ -367,9 +438,59 @@ export class SqliteMaterializationStateReader {
|
|
|
367
438
|
const accumulators = new Map(
|
|
368
439
|
scopes.map(({ source, linkId }) => {
|
|
369
440
|
const key = linkScopeSortKey(source, linkId)
|
|
370
|
-
return [key, startScopeAccumulator(source, linkId
|
|
441
|
+
return [key, startScopeAccumulator(source, linkId)] as const
|
|
371
442
|
})
|
|
372
443
|
)
|
|
444
|
+
const requestedJson = canonicalJson(requested)
|
|
445
|
+
const sourceRows = this.db
|
|
446
|
+
.query(
|
|
447
|
+
`WITH requested AS (
|
|
448
|
+
SELECT DISTINCT
|
|
449
|
+
json_extract(value, '$.sourceTypeId') AS source_type_id,
|
|
450
|
+
json_extract(value, '$.sourceId') AS source_primary_id,
|
|
451
|
+
json_extract(value, '$.linkId') AS link_id
|
|
452
|
+
FROM json_each(?)
|
|
453
|
+
)
|
|
454
|
+
SELECT rows.* FROM requested
|
|
455
|
+
CROSS JOIN ontology_source_rows AS rows
|
|
456
|
+
ON rows.project_id = ?
|
|
457
|
+
AND rows.entity_kind = 'link'
|
|
458
|
+
AND rows.source_type_id = requested.source_type_id
|
|
459
|
+
AND rows.source_primary_id = requested.source_primary_id
|
|
460
|
+
AND rows.link_id = requested.link_id
|
|
461
|
+
JOIN ontology_sources AS sources
|
|
462
|
+
ON sources.project_id = rows.project_id
|
|
463
|
+
AND sources.source_id = rows.source_id
|
|
464
|
+
AND sources.materialization_id = rows.materialization_id
|
|
465
|
+
WHERE sources.status = 'active'`
|
|
466
|
+
)
|
|
467
|
+
.all(requestedJson, this.projectId) as SqliteOntologySourceAssertionRow[]
|
|
468
|
+
const slotOverrideRows = this.db
|
|
469
|
+
.query(
|
|
470
|
+
`WITH requested AS (
|
|
471
|
+
SELECT DISTINCT
|
|
472
|
+
json_extract(value, '$.sourceTypeId') AS source_type_id,
|
|
473
|
+
json_extract(value, '$.sourceId') AS source_primary_id,
|
|
474
|
+
json_extract(value, '$.linkId') AS link_id
|
|
475
|
+
FROM json_each(?)
|
|
476
|
+
)
|
|
477
|
+
SELECT overrides.* FROM requested
|
|
478
|
+
CROSS JOIN ontology_link_overrides AS overrides
|
|
479
|
+
ON overrides.project_id = ?
|
|
480
|
+
AND overrides.identity_kind = 'slot'
|
|
481
|
+
AND overrides.source_type_id = requested.source_type_id
|
|
482
|
+
AND overrides.source_primary_id = requested.source_primary_id
|
|
483
|
+
AND overrides.link_id = requested.link_id`
|
|
484
|
+
)
|
|
485
|
+
.all(requestedJson, this.projectId) as LinkSlotOverrideRow[]
|
|
486
|
+
const sources = activeScopeSourceMap(sourceRows)
|
|
487
|
+
const overrides = new Map(
|
|
488
|
+
slotOverrideRows.map((row) => {
|
|
489
|
+
const stored = storedLinkSlotOverride(row)
|
|
490
|
+
return [linkScopeSortKey(stored.ref.source, stored.ref.linkId), stored] as const
|
|
491
|
+
})
|
|
492
|
+
)
|
|
493
|
+
const effective = new Map<string, EffectiveLinkSnapshot | null>()
|
|
373
494
|
const rows = this.db
|
|
374
495
|
.query(
|
|
375
496
|
`
|
|
@@ -382,13 +503,16 @@ export class SqliteMaterializationStateReader {
|
|
|
382
503
|
FROM json_each(?)
|
|
383
504
|
)
|
|
384
505
|
SELECT requested.scope_sort_key, links.*
|
|
385
|
-
FROM
|
|
386
|
-
JOIN
|
|
387
|
-
|
|
506
|
+
FROM requested
|
|
507
|
+
CROSS JOIN links
|
|
508
|
+
ON links.project_id = ?
|
|
509
|
+
AND links.source_type_id = requested.source_type_id
|
|
510
|
+
AND links.source_id = requested.source_id
|
|
511
|
+
AND links.link_id = requested.link_id
|
|
388
512
|
ORDER BY requested.scope_sort_key, ${linkSortExpression("links")}
|
|
389
513
|
`
|
|
390
514
|
)
|
|
391
|
-
.iterate(
|
|
515
|
+
.iterate(requestedJson, this.projectId) as Iterable<LinkScopeRow>
|
|
392
516
|
for (const row of rows) {
|
|
393
517
|
const accumulator = accumulators.get(row.scope_sort_key)
|
|
394
518
|
if (!accumulator) {
|
|
@@ -397,11 +521,19 @@ export class SqliteMaterializationStateReader {
|
|
|
397
521
|
`Unexpected link scope '${row.scope_sort_key}' returned by storage.`
|
|
398
522
|
)
|
|
399
523
|
}
|
|
400
|
-
|
|
524
|
+
const snapshot = effectiveLinkSnapshot(row)
|
|
525
|
+
appendScopeSnapshot(accumulator, snapshot)
|
|
526
|
+
effective.set(row.scope_sort_key, accumulator.effectiveCount === 1 ? snapshot : null)
|
|
401
527
|
}
|
|
402
|
-
return scopes.map(({ source, linkId }) =>
|
|
403
|
-
|
|
404
|
-
|
|
528
|
+
return scopes.map(({ source, linkId }) => {
|
|
529
|
+
const key = linkScopeSortKey(source, linkId)
|
|
530
|
+
return {
|
|
531
|
+
...finishScopeAccumulator(accumulators.get(key)!),
|
|
532
|
+
sourceAssertion: sources.get(key) ?? null,
|
|
533
|
+
override: overrides.get(key) ?? null,
|
|
534
|
+
effective: effective.get(key) ?? null,
|
|
535
|
+
}
|
|
536
|
+
})
|
|
405
537
|
}
|
|
406
538
|
|
|
407
539
|
linkScope(source: OntologyObjectRef, linkId: string): MaterializationLinkScopeState {
|
|
@@ -433,8 +565,8 @@ export class SqliteMaterializationStateReader {
|
|
|
433
565
|
FROM links WHERE project_id = ?
|
|
434
566
|
UNION
|
|
435
567
|
SELECT source_type_id, source_primary_id, link_id, target_type_id, target_primary_id
|
|
436
|
-
FROM
|
|
437
|
-
WHERE project_id = ?
|
|
568
|
+
FROM ontology_link_overrides
|
|
569
|
+
WHERE project_id = ?
|
|
438
570
|
UNION
|
|
439
571
|
SELECT rows.source_type_id, rows.source_primary_id, rows.link_id,
|
|
440
572
|
rows.target_type_id, rows.target_primary_id
|
|
@@ -478,29 +610,15 @@ export class SqliteMaterializationStateReader {
|
|
|
478
610
|
}
|
|
479
611
|
|
|
480
612
|
*replacementIdentities(input: ReplacementIdentityInput): Iterable<ReplacementIdentity[]> {
|
|
481
|
-
|
|
613
|
+
this.prepareReplacementIdentities(input)
|
|
614
|
+
let cursor: ReplacementCursor | null = null
|
|
482
615
|
while (true) {
|
|
483
|
-
|
|
484
|
-
const rows = this.replacementObjectRows(input, cursor)
|
|
485
|
-
if (rows.length === 0) break
|
|
486
|
-
yield rows.map((row) => ({
|
|
487
|
-
kind: "object",
|
|
488
|
-
ref: { objectTypeId: row.object_type_id, primaryId: row.primary_id },
|
|
489
|
-
sortKey: row.sort_key,
|
|
490
|
-
diffRequired: true,
|
|
491
|
-
}))
|
|
492
|
-
cursor = rows[rows.length - 1]?.sort_key ?? null
|
|
493
|
-
continue
|
|
494
|
-
}
|
|
495
|
-
const rows = this.replacementLinkRows(input, cursor)
|
|
616
|
+
const rows = this.replacementRows(input, cursor)
|
|
496
617
|
if (rows.length === 0) break
|
|
497
|
-
yield rows.map(
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
diffRequired: row.diff_required === 1,
|
|
502
|
-
}))
|
|
503
|
-
cursor = rows[rows.length - 1]?.sort_key ?? null
|
|
618
|
+
yield rows.map(replacementIdentity)
|
|
619
|
+
if (rows.length < input.pageRows) break
|
|
620
|
+
const last = rows[rows.length - 1]!
|
|
621
|
+
cursor = { sortKey: last.sort_key, identityKey: last.identity_key }
|
|
504
622
|
}
|
|
505
623
|
}
|
|
506
624
|
|
|
@@ -550,6 +668,7 @@ export class SqliteMaterializationStateReader {
|
|
|
550
668
|
? sourceLink(candidate?.get(key))
|
|
551
669
|
: state.source,
|
|
552
670
|
override: state.override,
|
|
671
|
+
slotOverride: state.slotOverride,
|
|
553
672
|
effective: state.effective,
|
|
554
673
|
diffRequired: identities[index]!.diffRequired,
|
|
555
674
|
}
|
|
@@ -592,16 +711,6 @@ export class SqliteMaterializationStateReader {
|
|
|
592
711
|
return row ? row.last_commit_id : undefined
|
|
593
712
|
}
|
|
594
713
|
|
|
595
|
-
overrideLastCommit(kind: "object" | "link", entityKey: string): string | null {
|
|
596
|
-
const row = this.db
|
|
597
|
-
.query(
|
|
598
|
-
`SELECT last_commit_id FROM ontology_overrides
|
|
599
|
-
WHERE project_id = ? AND entity_kind = ? AND entity_key = ?`
|
|
600
|
-
)
|
|
601
|
-
.get(this.projectId, kind, entityKey) as { readonly last_commit_id: string } | null
|
|
602
|
-
return row?.last_commit_id ?? null
|
|
603
|
-
}
|
|
604
|
-
|
|
605
714
|
private replacementSources(
|
|
606
715
|
sourceId: string,
|
|
607
716
|
materializationIds: readonly string[],
|
|
@@ -610,22 +719,30 @@ export class SqliteMaterializationStateReader {
|
|
|
610
719
|
if (materializationIds.length === 0 || refs.length === 0) {
|
|
611
720
|
return { owned: new Set(), byMaterialization: new Map() }
|
|
612
721
|
}
|
|
613
|
-
const
|
|
722
|
+
const requestedEntities = canonicalJson(
|
|
723
|
+
refs.map((ref) => ({ entityKind: ref.kind, entityKey: projectionEntityKey(ref) }))
|
|
724
|
+
)
|
|
614
725
|
const requestedMaterializations = canonicalJson([...new Set(materializationIds)])
|
|
615
726
|
const rows = this.db
|
|
616
727
|
.query(
|
|
617
728
|
`WITH requested_entities AS (
|
|
618
|
-
SELECT value AS
|
|
729
|
+
SELECT DISTINCT json_extract(value, '$.entityKind') AS entity_kind,
|
|
730
|
+
json_extract(value, '$.entityKey') AS entity_key
|
|
731
|
+
FROM json_each(?)
|
|
619
732
|
), requested_materializations AS (
|
|
620
733
|
SELECT value AS materialization_id FROM json_each(?)
|
|
621
734
|
)
|
|
622
|
-
SELECT rows.* FROM
|
|
623
|
-
JOIN requested_entities
|
|
624
|
-
JOIN
|
|
625
|
-
|
|
735
|
+
SELECT rows.* FROM requested_materializations
|
|
736
|
+
CROSS JOIN requested_entities
|
|
737
|
+
CROSS JOIN ontology_source_rows AS rows
|
|
738
|
+
ON rows.project_id = ?
|
|
739
|
+
AND rows.source_id = ?
|
|
740
|
+
AND rows.materialization_id = requested_materializations.materialization_id
|
|
741
|
+
AND rows.entity_kind = requested_entities.entity_kind
|
|
742
|
+
AND rows.entity_key = requested_entities.entity_key`
|
|
626
743
|
)
|
|
627
744
|
.all(
|
|
628
|
-
|
|
745
|
+
requestedEntities,
|
|
629
746
|
requestedMaterializations,
|
|
630
747
|
this.projectId,
|
|
631
748
|
sourceId
|
|
@@ -643,62 +760,48 @@ export class SqliteMaterializationStateReader {
|
|
|
643
760
|
return { owned, byMaterialization }
|
|
644
761
|
}
|
|
645
762
|
|
|
646
|
-
private
|
|
647
|
-
input
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
763
|
+
private prepareReplacementIdentities(input: ReplacementIdentityInput): void {
|
|
764
|
+
if (input.kind === "object") {
|
|
765
|
+
this.prepareReplacementObjects(input)
|
|
766
|
+
return
|
|
767
|
+
}
|
|
768
|
+
this.prepareReplacementLinks(input)
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
private prepareReplacementObjects(input: ReplacementIdentityInput): void {
|
|
772
|
+
this.db
|
|
651
773
|
.query(
|
|
652
774
|
`
|
|
653
|
-
|
|
775
|
+
INSERT INTO ${SQLITE_REPLACEMENT_WORK_TABLE} (
|
|
776
|
+
session_id, entity_kind, identity_key, sort_key, diff_required
|
|
777
|
+
)
|
|
778
|
+
SELECT ?, 'object', json_array(object_type_id, primary_id),
|
|
779
|
+
MIN(entity_sort_key), 1
|
|
654
780
|
FROM ontology_source_rows
|
|
655
781
|
WHERE project_id = ? AND source_id = ? AND entity_kind = 'object'
|
|
656
782
|
AND materialization_id IN (?, COALESCE(?, ''))
|
|
657
|
-
|
|
658
|
-
ORDER BY sort_key
|
|
659
|
-
LIMIT ?
|
|
783
|
+
GROUP BY object_type_id, primary_id
|
|
660
784
|
`
|
|
661
785
|
)
|
|
662
|
-
.
|
|
786
|
+
.run(
|
|
787
|
+
input.sessionId,
|
|
663
788
|
this.projectId,
|
|
664
789
|
input.sourceId,
|
|
665
790
|
input.candidateMaterializationId,
|
|
666
|
-
input.previousMaterializationId
|
|
667
|
-
|
|
668
|
-
cursor,
|
|
669
|
-
input.pageRows
|
|
670
|
-
) as (EffectiveObjectRow & { readonly sort_key: string })[]
|
|
791
|
+
input.previousMaterializationId
|
|
792
|
+
)
|
|
671
793
|
}
|
|
672
794
|
|
|
673
|
-
private
|
|
674
|
-
|
|
675
|
-
cursor: string | null
|
|
676
|
-
): (EffectiveLinkRow & { readonly sort_key: string; readonly diff_required: number })[] {
|
|
677
|
-
return this.db
|
|
795
|
+
private prepareReplacementLinks(input: ReplacementIdentityInput): void {
|
|
796
|
+
this.db
|
|
678
797
|
.query(
|
|
679
798
|
`
|
|
680
799
|
WITH incident_objects AS (
|
|
681
|
-
SELECT
|
|
800
|
+
SELECT DISTINCT
|
|
682
801
|
json_extract(payload, '$.ref.objectTypeId') AS object_type_id,
|
|
683
802
|
json_extract(payload, '$.ref.primaryId') AS primary_id
|
|
684
803
|
FROM ${SQLITE_MATERIALIZATION_WORK_TABLE}
|
|
685
804
|
WHERE session_id = ? AND kind = 'incident-object'
|
|
686
|
-
), authority_links AS (
|
|
687
|
-
SELECT source_type_id, source_id, link_id, target_type_id, target_id
|
|
688
|
-
FROM links WHERE project_id = ?
|
|
689
|
-
UNION
|
|
690
|
-
SELECT source_type_id, source_primary_id, link_id, target_type_id, target_primary_id
|
|
691
|
-
FROM ontology_overrides
|
|
692
|
-
WHERE project_id = ? AND entity_kind = 'link'
|
|
693
|
-
UNION
|
|
694
|
-
SELECT rows.source_type_id, rows.source_primary_id, rows.link_id,
|
|
695
|
-
rows.target_type_id, rows.target_primary_id
|
|
696
|
-
FROM ontology_source_rows AS rows
|
|
697
|
-
JOIN ontology_sources AS sources
|
|
698
|
-
ON sources.project_id = rows.project_id
|
|
699
|
-
AND sources.source_id = rows.source_id
|
|
700
|
-
AND sources.materialization_id = rows.materialization_id
|
|
701
|
-
WHERE rows.project_id = ? AND rows.entity_kind = 'link' AND sources.status = 'active'
|
|
702
805
|
), replacement_links AS (
|
|
703
806
|
SELECT source_type_id, source_primary_id AS source_id, link_id,
|
|
704
807
|
target_type_id, target_primary_id AS target_id
|
|
@@ -706,14 +809,67 @@ export class SqliteMaterializationStateReader {
|
|
|
706
809
|
WHERE project_id = ? AND source_id = ? AND entity_kind = 'link'
|
|
707
810
|
AND materialization_id IN (?, COALESCE(?, ''))
|
|
708
811
|
), incident_links AS (
|
|
709
|
-
SELECT links
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
812
|
+
SELECT links.source_type_id, links.source_id, links.link_id,
|
|
813
|
+
links.target_type_id, links.target_id
|
|
814
|
+
FROM links
|
|
815
|
+
JOIN incident_objects
|
|
816
|
+
ON incident_objects.object_type_id = links.source_type_id
|
|
817
|
+
AND incident_objects.primary_id = links.source_id
|
|
818
|
+
WHERE links.project_id = ?
|
|
819
|
+
UNION
|
|
820
|
+
SELECT links.source_type_id, links.source_id, links.link_id,
|
|
821
|
+
links.target_type_id, links.target_id
|
|
822
|
+
FROM links
|
|
823
|
+
JOIN incident_objects
|
|
824
|
+
ON incident_objects.object_type_id = links.target_type_id
|
|
825
|
+
AND incident_objects.primary_id = links.target_id
|
|
826
|
+
WHERE links.project_id = ?
|
|
827
|
+
UNION
|
|
828
|
+
SELECT overrides.source_type_id,
|
|
829
|
+
overrides.source_primary_id AS source_id,
|
|
830
|
+
overrides.link_id, overrides.target_type_id,
|
|
831
|
+
overrides.target_primary_id AS target_id
|
|
832
|
+
FROM ontology_link_overrides AS overrides
|
|
833
|
+
JOIN incident_objects
|
|
834
|
+
ON incident_objects.object_type_id = overrides.source_type_id
|
|
835
|
+
AND incident_objects.primary_id = overrides.source_primary_id
|
|
836
|
+
WHERE overrides.project_id = ?
|
|
837
|
+
UNION
|
|
838
|
+
SELECT overrides.source_type_id,
|
|
839
|
+
overrides.source_primary_id AS source_id,
|
|
840
|
+
overrides.link_id, overrides.target_type_id,
|
|
841
|
+
overrides.target_primary_id AS target_id
|
|
842
|
+
FROM ontology_link_overrides AS overrides
|
|
843
|
+
JOIN incident_objects
|
|
844
|
+
ON incident_objects.object_type_id = overrides.target_type_id
|
|
845
|
+
AND incident_objects.primary_id = overrides.target_primary_id
|
|
846
|
+
WHERE overrides.project_id = ?
|
|
847
|
+
UNION
|
|
848
|
+
SELECT rows.source_type_id, rows.source_primary_id AS source_id,
|
|
849
|
+
rows.link_id, rows.target_type_id, rows.target_primary_id AS target_id
|
|
850
|
+
FROM ontology_source_rows AS rows
|
|
851
|
+
JOIN ontology_sources AS sources
|
|
852
|
+
ON sources.project_id = rows.project_id
|
|
853
|
+
AND sources.source_id = rows.source_id
|
|
854
|
+
AND sources.materialization_id = rows.materialization_id
|
|
855
|
+
JOIN incident_objects
|
|
856
|
+
ON incident_objects.object_type_id = rows.source_type_id
|
|
857
|
+
AND incident_objects.primary_id = rows.source_primary_id
|
|
858
|
+
WHERE rows.project_id = ? AND rows.entity_kind = 'link'
|
|
859
|
+
AND sources.status = 'active'
|
|
860
|
+
UNION
|
|
861
|
+
SELECT rows.source_type_id, rows.source_primary_id AS source_id,
|
|
862
|
+
rows.link_id, rows.target_type_id, rows.target_primary_id AS target_id
|
|
863
|
+
FROM ontology_source_rows AS rows
|
|
864
|
+
JOIN ontology_sources AS sources
|
|
865
|
+
ON sources.project_id = rows.project_id
|
|
866
|
+
AND sources.source_id = rows.source_id
|
|
867
|
+
AND sources.materialization_id = rows.materialization_id
|
|
868
|
+
JOIN incident_objects
|
|
869
|
+
ON incident_objects.object_type_id = rows.target_type_id
|
|
870
|
+
AND incident_objects.primary_id = rows.target_primary_id
|
|
871
|
+
WHERE rows.project_id = ? AND rows.entity_kind = 'link'
|
|
872
|
+
AND sources.status = 'active'
|
|
717
873
|
), diff_links AS (
|
|
718
874
|
SELECT * FROM replacement_links
|
|
719
875
|
UNION SELECT * FROM incident_links
|
|
@@ -727,6 +883,16 @@ export class SqliteMaterializationStateReader {
|
|
|
727
883
|
FROM links
|
|
728
884
|
JOIN affected_scopes USING (source_type_id, source_id, link_id)
|
|
729
885
|
WHERE links.project_id = ?
|
|
886
|
+
UNION ALL
|
|
887
|
+
SELECT overrides.source_type_id, overrides.source_primary_id AS source_id,
|
|
888
|
+
overrides.link_id, overrides.target_type_id,
|
|
889
|
+
overrides.target_primary_id AS target_id, 0 AS diff_required
|
|
890
|
+
FROM ontology_link_overrides AS overrides
|
|
891
|
+
JOIN affected_scopes
|
|
892
|
+
ON affected_scopes.source_type_id = overrides.source_type_id
|
|
893
|
+
AND affected_scopes.source_id = overrides.source_primary_id
|
|
894
|
+
AND affected_scopes.link_id = overrides.link_id
|
|
895
|
+
WHERE overrides.project_id = ? AND overrides.identity_kind = 'slot'
|
|
730
896
|
), selected AS (
|
|
731
897
|
SELECT source_type_id, source_id, link_id, target_type_id, target_id,
|
|
732
898
|
${linkSortExpression("all_links")} AS sort_key,
|
|
@@ -734,26 +900,78 @@ export class SqliteMaterializationStateReader {
|
|
|
734
900
|
FROM all_links
|
|
735
901
|
GROUP BY source_type_id, source_id, link_id, target_type_id, target_id
|
|
736
902
|
)
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
903
|
+
INSERT INTO ${SQLITE_REPLACEMENT_WORK_TABLE} (
|
|
904
|
+
session_id, entity_kind, identity_key, sort_key, diff_required
|
|
905
|
+
)
|
|
906
|
+
SELECT ?, 'link',
|
|
907
|
+
json_array(source_type_id, source_id, link_id, target_type_id, target_id),
|
|
908
|
+
sort_key, diff_required
|
|
909
|
+
FROM selected
|
|
741
910
|
`
|
|
742
911
|
)
|
|
743
|
-
.
|
|
912
|
+
.run(
|
|
744
913
|
input.sessionId,
|
|
745
914
|
this.projectId,
|
|
746
|
-
this.projectId,
|
|
747
|
-
this.projectId,
|
|
748
|
-
this.projectId,
|
|
749
915
|
input.sourceId,
|
|
750
916
|
input.candidateMaterializationId,
|
|
751
917
|
input.previousMaterializationId,
|
|
752
918
|
this.projectId,
|
|
753
|
-
|
|
754
|
-
|
|
919
|
+
this.projectId,
|
|
920
|
+
this.projectId,
|
|
921
|
+
this.projectId,
|
|
922
|
+
this.projectId,
|
|
923
|
+
this.projectId,
|
|
924
|
+
this.projectId,
|
|
925
|
+
this.projectId,
|
|
926
|
+
input.sessionId
|
|
927
|
+
)
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
private replacementRows(
|
|
931
|
+
input: ReplacementIdentityInput,
|
|
932
|
+
cursor: ReplacementCursor | null
|
|
933
|
+
): ReplacementWorkRow[] {
|
|
934
|
+
return this.db
|
|
935
|
+
.query(
|
|
936
|
+
`
|
|
937
|
+
SELECT entity_kind, identity_key, sort_key, diff_required
|
|
938
|
+
FROM ${SQLITE_REPLACEMENT_WORK_TABLE}
|
|
939
|
+
WHERE session_id = ? AND entity_kind = ?
|
|
940
|
+
AND (? IS NULL OR (sort_key, identity_key) > (?, ?))
|
|
941
|
+
ORDER BY sort_key, identity_key
|
|
942
|
+
LIMIT ?
|
|
943
|
+
`
|
|
944
|
+
)
|
|
945
|
+
.all(
|
|
946
|
+
input.sessionId,
|
|
947
|
+
input.kind,
|
|
948
|
+
cursor?.sortKey ?? null,
|
|
949
|
+
cursor?.sortKey ?? null,
|
|
950
|
+
cursor?.identityKey ?? null,
|
|
755
951
|
input.pageRows
|
|
756
|
-
) as
|
|
952
|
+
) as ReplacementWorkRow[]
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
function replacementIdentity(row: ReplacementWorkRow): ReplacementIdentity {
|
|
957
|
+
const parts = parseJson<string[]>(row.identity_key)
|
|
958
|
+
if (row.entity_kind === "object") {
|
|
959
|
+
return {
|
|
960
|
+
kind: "object",
|
|
961
|
+
ref: { objectTypeId: parts[0]!, primaryId: parts[1]! },
|
|
962
|
+
sortKey: row.sort_key,
|
|
963
|
+
diffRequired: true,
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
return {
|
|
967
|
+
kind: "link",
|
|
968
|
+
ref: {
|
|
969
|
+
source: { objectTypeId: parts[0]!, primaryId: parts[1]! },
|
|
970
|
+
linkId: parts[2]!,
|
|
971
|
+
target: { objectTypeId: parts[3]!, primaryId: parts[4]! },
|
|
972
|
+
},
|
|
973
|
+
sortKey: row.sort_key,
|
|
974
|
+
diffRequired: row.diff_required === 1,
|
|
757
975
|
}
|
|
758
976
|
}
|
|
759
977
|
|
|
@@ -775,6 +993,26 @@ function activeSourceMap(
|
|
|
775
993
|
return result
|
|
776
994
|
}
|
|
777
995
|
|
|
996
|
+
function activeScopeSourceMap(
|
|
997
|
+
rows: readonly SqliteOntologySourceAssertionRow[]
|
|
998
|
+
): ReadonlyMap<string, StoredSourceLinkAssertion> {
|
|
999
|
+
const result = new Map<string, StoredSourceLinkAssertion>()
|
|
1000
|
+
for (const row of rows) {
|
|
1001
|
+
const source = sourceLink(storedSource(row))
|
|
1002
|
+
if (!source) continue
|
|
1003
|
+
const ref = source.assertion.ref
|
|
1004
|
+
const key = linkScopeSortKey(ref.source, ref.linkId)
|
|
1005
|
+
if (result.has(key)) {
|
|
1006
|
+
throw new MaterializationConflictError(
|
|
1007
|
+
"source-materialization",
|
|
1008
|
+
`Multiple active sources assert cardinality-one link slot ${key}.`
|
|
1009
|
+
)
|
|
1010
|
+
}
|
|
1011
|
+
result.set(key, source)
|
|
1012
|
+
}
|
|
1013
|
+
return result
|
|
1014
|
+
}
|
|
1015
|
+
|
|
778
1016
|
function sourceObject(
|
|
779
1017
|
source: StoredSourceAssertion | undefined
|
|
780
1018
|
): StoredSourceObjectAssertion | null {
|
|
@@ -805,6 +1043,19 @@ function storedLinkOverride(row: LinkOverrideRow): StoredLinkOverride {
|
|
|
805
1043
|
}
|
|
806
1044
|
}
|
|
807
1045
|
|
|
1046
|
+
function storedLinkSlotOverride(row: LinkSlotOverrideRow): StoredLinkSlotOverride {
|
|
1047
|
+
const ref = {
|
|
1048
|
+
source: { objectTypeId: row.source_type_id, primaryId: row.source_primary_id },
|
|
1049
|
+
linkId: row.link_id,
|
|
1050
|
+
}
|
|
1051
|
+
return {
|
|
1052
|
+
ref,
|
|
1053
|
+
value: linkSlotOverrideValue(parseJson<unknown>(row.value), linkScopeLabel(ref)),
|
|
1054
|
+
lastCommitId: row.last_commit_id,
|
|
1055
|
+
updatedAt: row.updated_at,
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
|
|
808
1059
|
function linkRefFromOverrideColumns(row: LinkOverrideRow): OntologyLinkRef {
|
|
809
1060
|
return {
|
|
810
1061
|
source: { objectTypeId: row.source_type_id, primaryId: row.source_primary_id },
|
|
@@ -813,6 +1064,13 @@ function linkRefFromOverrideColumns(row: LinkOverrideRow): OntologyLinkRef {
|
|
|
813
1064
|
}
|
|
814
1065
|
}
|
|
815
1066
|
|
|
1067
|
+
function linkScopeLabel(scope: {
|
|
1068
|
+
readonly source: OntologyObjectRef
|
|
1069
|
+
readonly linkId: string
|
|
1070
|
+
}): string {
|
|
1071
|
+
return JSON.stringify([scope.source.objectTypeId, scope.source.primaryId, scope.linkId])
|
|
1072
|
+
}
|
|
1073
|
+
|
|
816
1074
|
function storedSource(row: SqliteOntologySourceAssertionRow): StoredSourceAssertion {
|
|
817
1075
|
return {
|
|
818
1076
|
source: { projectionId: row.source_id },
|
|
@@ -885,17 +1143,7 @@ function storedPoint(row: TelemetryRow): StoredTelemetryPoint {
|
|
|
885
1143
|
}
|
|
886
1144
|
}
|
|
887
1145
|
|
|
888
|
-
export function objectSortExpression(alias?: string): string {
|
|
889
|
-
const prefix = alias ? `${alias}.` : ""
|
|
890
|
-
return `LOWER(HEX(CAST(json_array(${prefix}object_type_id, ${prefix}primary_id) AS BLOB)))`
|
|
891
|
-
}
|
|
892
|
-
|
|
893
1146
|
export function linkSortExpression(alias?: string): string {
|
|
894
1147
|
const prefix = alias ? `${alias}.` : ""
|
|
895
1148
|
return `LOWER(HEX(CAST(json_array(${prefix}source_type_id, ${prefix}source_id, ${prefix}link_id, ${prefix}target_type_id, ${prefix}target_id) AS BLOB)))`
|
|
896
1149
|
}
|
|
897
|
-
|
|
898
|
-
export function pointSortExpression(alias?: string): string {
|
|
899
|
-
const prefix = alias ? `${alias}.` : ""
|
|
900
|
-
return `LOWER(HEX(CAST(json_array(${prefix}object_type_id, ${prefix}object_id, ${prefix}property_id, ${prefix}at) AS BLOB)))`
|
|
901
|
-
}
|