@sixb/sqlite 0.1.14 → 0.1.15
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/dist/index.js +673 -241
- package/dist/index.js.map +10 -10
- package/dist/latest-run-query.d.ts +2 -0
- package/dist/latest-run-query.d.ts.map +1 -1
- package/dist/migrations.d.ts.map +1 -1
- package/dist/ontology-storage/materialization-state.d.ts.map +1 -1
- package/dist/ontology-storage/shared.d.ts +11 -8
- package/dist/ontology-storage/shared.d.ts.map +1 -1
- package/dist/ontology-storage/source-cleanup.d.ts +7 -1
- package/dist/ontology-storage/source-cleanup.d.ts.map +1 -1
- package/dist/ontology-storage/source-roots.d.ts +14 -2
- package/dist/ontology-storage/source-roots.d.ts.map +1 -1
- package/dist/ontology-storage/sources.d.ts +8 -3
- package/dist/ontology-storage/sources.d.ts.map +1 -1
- package/dist/projection-run-storage.d.ts +3 -1
- package/dist/projection-run-storage.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/latest-run-query.ts +8 -2
- package/src/migrations/051-projection-run-supersession.sql +126 -0
- package/src/migrations/052-compact-source-storage.sql +181 -0
- package/src/migrations.ts +38 -0
- package/src/ontology-storage/materialization-state.ts +34 -44
- package/src/ontology-storage/shared.ts +20 -11
- package/src/ontology-storage/source-cleanup.ts +61 -24
- package/src/ontology-storage/source-roots.ts +166 -110
- package/src/ontology-storage/sources.ts +169 -118
- package/src/projection-run-storage.ts +59 -1
package/src/migrations.ts
CHANGED
|
@@ -115,6 +115,12 @@ import nativeSessionsSql from "./migrations/049-native-sessions.sql" with { type
|
|
|
115
115
|
import directoryGroupMembershipsSql from "./migrations/050-directory-group-memberships.sql" with {
|
|
116
116
|
type: "text",
|
|
117
117
|
}
|
|
118
|
+
import projectionRunSupersessionSql from "./migrations/051-projection-run-supersession.sql" with {
|
|
119
|
+
type: "text",
|
|
120
|
+
}
|
|
121
|
+
import compactSourceStorageSql from "./migrations/052-compact-source-storage.sql" with {
|
|
122
|
+
type: "text",
|
|
123
|
+
}
|
|
118
124
|
|
|
119
125
|
const MIGRATIONS_TABLE_SQL = `
|
|
120
126
|
CREATE TABLE IF NOT EXISTS sixb_migrations (
|
|
@@ -220,6 +226,26 @@ export const sqliteStorageMigrations = defineMigrations({
|
|
|
220
226
|
sqliteSql("048-file-upload-sessions", fileUploadSessionsSql),
|
|
221
227
|
sqliteSql("049-native-sessions", nativeSessionsSql),
|
|
222
228
|
sqliteSql("050-directory-group-memberships", directoryGroupMembershipsSql),
|
|
229
|
+
sqliteSql("051-projection-run-supersession", projectionRunSupersessionSql),
|
|
230
|
+
sqliteStep(
|
|
231
|
+
"052-compact-source-storage",
|
|
232
|
+
(db) => {
|
|
233
|
+
// SQLite has no procedural block to check the copy in SQL: count around it instead.
|
|
234
|
+
const before = sourceStorageCounts(db)
|
|
235
|
+
db.run(compactSourceStorageSql)
|
|
236
|
+
const after = sourceStorageCounts(db)
|
|
237
|
+
if (
|
|
238
|
+
after.versions !== before.versions ||
|
|
239
|
+
after.roots !== before.roots ||
|
|
240
|
+
after.rows !== before.rows
|
|
241
|
+
) {
|
|
242
|
+
throw new Error(
|
|
243
|
+
"[SixbSqliteStorage] Source versions, roots or rows were lost while compacting source storage."
|
|
244
|
+
)
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
{ checksum: checksum(compactSourceStorageSql) }
|
|
248
|
+
),
|
|
223
249
|
],
|
|
224
250
|
})
|
|
225
251
|
|
|
@@ -378,6 +404,18 @@ function rowToMigrationRecord(row: unknown): MigrationRecord {
|
|
|
378
404
|
}
|
|
379
405
|
}
|
|
380
406
|
|
|
407
|
+
function sourceStorageCounts(db: Database): {
|
|
408
|
+
readonly versions: number
|
|
409
|
+
readonly roots: number
|
|
410
|
+
readonly rows: number
|
|
411
|
+
} {
|
|
412
|
+
return db
|
|
413
|
+
.query(`SELECT (SELECT count(*) FROM ontology_sources) AS versions,
|
|
414
|
+
(SELECT count(*) FROM ontology_source_roots) AS roots,
|
|
415
|
+
(SELECT count(*) FROM ontology_source_rows) AS rows`)
|
|
416
|
+
.get() as { readonly versions: number; readonly roots: number; readonly rows: number }
|
|
417
|
+
}
|
|
418
|
+
|
|
381
419
|
function checksum(value: string): string {
|
|
382
420
|
return createHash("sha256").update(value).digest("hex")
|
|
383
421
|
}
|
|
@@ -43,8 +43,15 @@ import {
|
|
|
43
43
|
parseJson,
|
|
44
44
|
type SqliteOntologySourceAssertionRow,
|
|
45
45
|
type SqliteStoredOverrideRow,
|
|
46
|
+
sourceAssertion,
|
|
46
47
|
} from "./shared"
|
|
47
|
-
import {
|
|
48
|
+
import {
|
|
49
|
+
activeSourceRows,
|
|
50
|
+
LIVE_SOURCE_ROWS_JOIN,
|
|
51
|
+
replacementAssertionRows,
|
|
52
|
+
replacementSourceRows,
|
|
53
|
+
SOURCE_ASSERTION_COLUMNS,
|
|
54
|
+
} from "./source-roots"
|
|
48
55
|
|
|
49
56
|
export const SQLITE_MATERIALIZATION_WORK_TABLE = "ontology_materialization_work"
|
|
50
57
|
export const SQLITE_REPLACEMENT_WORK_TABLE = "ontology_replacement_work"
|
|
@@ -438,19 +445,13 @@ export class SqliteMaterializationStateReader {
|
|
|
438
445
|
json_extract(value, '$.linkId') AS link_id
|
|
439
446
|
FROM json_each(?)
|
|
440
447
|
)
|
|
441
|
-
SELECT
|
|
448
|
+
SELECT ${SOURCE_ASSERTION_COLUMNS} FROM requested
|
|
442
449
|
CROSS JOIN ontology_source_rows AS rows
|
|
443
|
-
ON rows.
|
|
444
|
-
AND rows.entity_kind = 'link'
|
|
450
|
+
ON rows.entity_kind = 'link'
|
|
445
451
|
AND rows.source_type_id = requested.source_type_id
|
|
446
452
|
AND rows.source_primary_id = requested.source_primary_id
|
|
447
453
|
AND rows.link_id = requested.link_id
|
|
448
|
-
|
|
449
|
-
ON sources.project_id = rows.project_id
|
|
450
|
-
AND sources.source_id = rows.source_id
|
|
451
|
-
AND sources.materialization_id = rows.materialization_id
|
|
452
|
-
AND sources.root_sort_key = rows.root_sort_key
|
|
453
|
-
WHERE sources.active = 1`
|
|
454
|
+
${LIVE_SOURCE_ROWS_JOIN}`
|
|
454
455
|
)
|
|
455
456
|
.all(requestedJson, this.projectId) as SqliteOntologySourceAssertionRow[]
|
|
456
457
|
const slotOverrideRows = this.db
|
|
@@ -570,12 +571,8 @@ export class SqliteMaterializationStateReader {
|
|
|
570
571
|
SELECT rows.source_type_id, rows.source_primary_id, rows.link_id,
|
|
571
572
|
rows.target_type_id, rows.target_primary_id
|
|
572
573
|
FROM ontology_source_rows AS rows
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
AND sources.source_id = rows.source_id
|
|
576
|
-
AND sources.materialization_id = rows.materialization_id
|
|
577
|
-
AND sources.root_sort_key = rows.root_sort_key
|
|
578
|
-
WHERE rows.project_id = ? AND rows.entity_kind = 'link' AND sources.active = 1
|
|
574
|
+
${LIVE_SOURCE_ROWS_JOIN}
|
|
575
|
+
WHERE rows.entity_kind = 'link'
|
|
579
576
|
), selected AS (
|
|
580
577
|
SELECT DISTINCT links.*,
|
|
581
578
|
${linkSortExpression("links")} AS sort_key
|
|
@@ -752,7 +749,7 @@ export class SqliteMaterializationStateReader {
|
|
|
752
749
|
}
|
|
753
750
|
|
|
754
751
|
private prepareReplacementObjects(input: ReplacementIdentityInput): void {
|
|
755
|
-
const rows = replacementSourceRows({
|
|
752
|
+
const rows = replacementSourceRows(this.db, {
|
|
756
753
|
projectId: this.projectId,
|
|
757
754
|
sourceId: input.sourceId,
|
|
758
755
|
materializationId: input.candidateMaterializationId,
|
|
@@ -765,7 +762,7 @@ export class SqliteMaterializationStateReader {
|
|
|
765
762
|
session_id, entity_kind, identity_key, sort_key, diff_required
|
|
766
763
|
)
|
|
767
764
|
SELECT ?, 'object', json_array(object_type_id, primary_id),
|
|
768
|
-
|
|
765
|
+
${objectSortExpression()}, 1
|
|
769
766
|
FROM (${rows.sql}) AS rows
|
|
770
767
|
WHERE entity_kind = 'object'
|
|
771
768
|
GROUP BY object_type_id, primary_id
|
|
@@ -775,7 +772,7 @@ export class SqliteMaterializationStateReader {
|
|
|
775
772
|
}
|
|
776
773
|
|
|
777
774
|
private prepareReplacementLinks(input: ReplacementIdentityInput): void {
|
|
778
|
-
const rows = replacementSourceRows({
|
|
775
|
+
const rows = replacementSourceRows(this.db, {
|
|
779
776
|
projectId: this.projectId,
|
|
780
777
|
sourceId: input.sourceId,
|
|
781
778
|
materializationId: input.candidateMaterializationId,
|
|
@@ -834,31 +831,21 @@ export class SqliteMaterializationStateReader {
|
|
|
834
831
|
UNION
|
|
835
832
|
SELECT rows.source_type_id, rows.source_primary_id AS source_id,
|
|
836
833
|
rows.link_id, rows.target_type_id, rows.target_primary_id AS target_id
|
|
837
|
-
FROM
|
|
838
|
-
JOIN
|
|
839
|
-
ON
|
|
840
|
-
AND
|
|
841
|
-
AND
|
|
842
|
-
|
|
843
|
-
JOIN incident_objects
|
|
844
|
-
ON incident_objects.object_type_id = rows.source_type_id
|
|
845
|
-
AND incident_objects.primary_id = rows.source_primary_id
|
|
846
|
-
WHERE rows.project_id = ? AND rows.entity_kind = 'link'
|
|
847
|
-
AND sources.active = 1
|
|
834
|
+
FROM incident_objects
|
|
835
|
+
CROSS JOIN ontology_source_rows AS rows
|
|
836
|
+
ON rows.entity_kind = 'link'
|
|
837
|
+
AND rows.source_type_id = incident_objects.object_type_id
|
|
838
|
+
AND rows.source_primary_id = incident_objects.primary_id
|
|
839
|
+
${LIVE_SOURCE_ROWS_JOIN}
|
|
848
840
|
UNION
|
|
849
841
|
SELECT rows.source_type_id, rows.source_primary_id AS source_id,
|
|
850
842
|
rows.link_id, rows.target_type_id, rows.target_primary_id AS target_id
|
|
851
|
-
FROM
|
|
852
|
-
JOIN
|
|
853
|
-
ON
|
|
854
|
-
AND
|
|
855
|
-
AND
|
|
856
|
-
|
|
857
|
-
JOIN incident_objects
|
|
858
|
-
ON incident_objects.object_type_id = rows.target_type_id
|
|
859
|
-
AND incident_objects.primary_id = rows.target_primary_id
|
|
860
|
-
WHERE rows.project_id = ? AND rows.entity_kind = 'link'
|
|
861
|
-
AND sources.active = 1
|
|
843
|
+
FROM incident_objects
|
|
844
|
+
CROSS JOIN ontology_source_rows AS rows
|
|
845
|
+
ON rows.entity_kind = 'link'
|
|
846
|
+
AND rows.target_type_id = incident_objects.object_type_id
|
|
847
|
+
AND rows.target_primary_id = incident_objects.primary_id
|
|
848
|
+
${LIVE_SOURCE_ROWS_JOIN}
|
|
862
849
|
), diff_links AS (
|
|
863
850
|
SELECT * FROM replacement_links
|
|
864
851
|
UNION SELECT * FROM incident_links
|
|
@@ -1062,9 +1049,7 @@ function storedSource(row: SqliteOntologySourceAssertionRow): StoredSourceAssert
|
|
|
1062
1049
|
return {
|
|
1063
1050
|
source: { projectionId: row.source_id },
|
|
1064
1051
|
materializationId: row.materialization_id,
|
|
1065
|
-
|
|
1066
|
-
assertion: parseJson<StoredSourceAssertion["assertion"]>(row.assertion),
|
|
1067
|
-
stagingOrdinal: row.staging_ordinal,
|
|
1052
|
+
...sourceAssertion(row),
|
|
1068
1053
|
} as StoredSourceAssertion
|
|
1069
1054
|
}
|
|
1070
1055
|
|
|
@@ -1130,6 +1115,11 @@ function storedPoint(row: TelemetryRow): StoredTelemetryPoint {
|
|
|
1130
1115
|
}
|
|
1131
1116
|
}
|
|
1132
1117
|
|
|
1118
|
+
function objectSortExpression(alias?: string): string {
|
|
1119
|
+
const prefix = alias ? `${alias}.` : ""
|
|
1120
|
+
return `LOWER(HEX(CAST(json_array(${prefix}object_type_id, ${prefix}primary_id) AS BLOB)))`
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1133
1123
|
export function linkSortExpression(alias?: string): string {
|
|
1134
1124
|
const prefix = alias ? `${alias}.` : ""
|
|
1135
1125
|
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)))`
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import type { Database } from "bun:sqlite"
|
|
2
2
|
import { parseSixbFailure } from "@sixb/core/internal/errors"
|
|
3
|
-
import type { ProjectionEntityRef } from "@sixb/core/internal/materialization"
|
|
4
3
|
import { MaterializationConflictError } from "@sixb/core/internal/materialization"
|
|
4
|
+
import {
|
|
5
|
+
sourceAssertionFromColumns,
|
|
6
|
+
sourceEntityFromKey,
|
|
7
|
+
} from "@sixb/core/internal/ontology-storage-provider"
|
|
5
8
|
import type {
|
|
6
9
|
AssertSourceMaterializationExecutionInput,
|
|
7
10
|
OntologyCommitRecord,
|
|
@@ -48,6 +51,7 @@ export interface SqliteOntologyCommitRow {
|
|
|
48
51
|
}
|
|
49
52
|
|
|
50
53
|
export interface SqliteOntologySourceRow {
|
|
54
|
+
readonly version_id: number
|
|
51
55
|
readonly project_id: string
|
|
52
56
|
readonly source_id: string
|
|
53
57
|
readonly materialization_id: string
|
|
@@ -74,19 +78,21 @@ export interface SqliteOntologySourceRow {
|
|
|
74
78
|
readonly updated_at: string
|
|
75
79
|
}
|
|
76
80
|
|
|
81
|
+
/** An assertion with its root and version, as `SOURCE_ASSERTION_COLUMNS` selects it. */
|
|
77
82
|
export interface SqliteOntologySourceAssertionRow {
|
|
78
|
-
readonly project_id: string
|
|
79
83
|
readonly source_id: string
|
|
80
84
|
readonly materialization_id: string
|
|
81
|
-
readonly entity_kind: "object" | "link"
|
|
82
|
-
readonly entity_key: string
|
|
83
|
-
readonly entity_sort_key: string
|
|
84
|
-
readonly root_kind: "object" | "link"
|
|
85
85
|
readonly root_key: string
|
|
86
|
-
readonly root_sort_key: string
|
|
87
86
|
readonly staging_ordinal: number
|
|
88
|
-
readonly
|
|
89
|
-
readonly
|
|
87
|
+
readonly entity_kind: "object" | "link"
|
|
88
|
+
readonly object_type_id: string | null
|
|
89
|
+
readonly primary_id: string | null
|
|
90
|
+
readonly source_type_id: string | null
|
|
91
|
+
readonly source_primary_id: string | null
|
|
92
|
+
readonly link_id: string | null
|
|
93
|
+
readonly target_type_id: string | null
|
|
94
|
+
readonly target_primary_id: string | null
|
|
95
|
+
readonly payload: string | null
|
|
90
96
|
}
|
|
91
97
|
|
|
92
98
|
export interface SqliteStoredOverrideRow {
|
|
@@ -149,8 +155,11 @@ export function sourceRecord(row: SqliteOntologySourceRow): OntologySourceRecord
|
|
|
149
155
|
|
|
150
156
|
export function sourceAssertion(row: SqliteOntologySourceAssertionRow): StageSourceAssertion {
|
|
151
157
|
return {
|
|
152
|
-
root:
|
|
153
|
-
assertion:
|
|
158
|
+
root: sourceEntityFromKey(row.root_key),
|
|
159
|
+
assertion: sourceAssertionFromColumns(
|
|
160
|
+
row,
|
|
161
|
+
row.payload === null ? null : parseJson<unknown>(row.payload)
|
|
162
|
+
),
|
|
154
163
|
stagingOrdinal: row.staging_ordinal,
|
|
155
164
|
}
|
|
156
165
|
}
|
|
@@ -2,38 +2,79 @@ import type { Database } from "bun:sqlite"
|
|
|
2
2
|
import type {
|
|
3
3
|
CleanupTerminalSourceMaterializationsInput,
|
|
4
4
|
CleanupTerminalSourceMaterializationsResult,
|
|
5
|
+
PurgeAbandonedSourceMaterializationsInput,
|
|
5
6
|
} from "@sixb/core/storage"
|
|
6
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Superseded versions can still hold live roots (a delta keeps unchanged roots where they were),
|
|
10
|
+
* so they are cleaned root by root once retired. An abandoned candidate was never published:
|
|
11
|
+
* everything it holds goes, one whole version at a time, each delete on its own version prefix.
|
|
12
|
+
*/
|
|
13
|
+
export function purgeAbandonedSourceVersions(
|
|
14
|
+
db: Database,
|
|
15
|
+
input: PurgeAbandonedSourceMaterializationsInput
|
|
16
|
+
): CleanupTerminalSourceMaterializationsResult {
|
|
17
|
+
let remaining = input.limit
|
|
18
|
+
let rowsDeleted = 0
|
|
19
|
+
let materializationsDeleted = 0
|
|
20
|
+
const nextCandidate = db.query(`
|
|
21
|
+
SELECT version_id FROM ontology_sources
|
|
22
|
+
WHERE project_id = ? AND status = 'abandoned'
|
|
23
|
+
ORDER BY terminal_at, source_id, materialization_id LIMIT 1
|
|
24
|
+
`)
|
|
25
|
+
const deleteRows = db.query(`DELETE FROM ontology_source_rows WHERE rowid IN (
|
|
26
|
+
SELECT rows.rowid FROM ontology_source_roots AS roots
|
|
27
|
+
CROSS JOIN ontology_source_rows AS rows ON rows.root_id = roots.id
|
|
28
|
+
WHERE roots.version_id = ? LIMIT ?)`)
|
|
29
|
+
const deleteRoots = db.query(`DELETE FROM ontology_source_roots WHERE id IN (
|
|
30
|
+
SELECT id FROM ontology_source_roots WHERE version_id = ? LIMIT ?)`)
|
|
31
|
+
const deleteManifest = db.query(
|
|
32
|
+
"DELETE FROM ontology_sources WHERE version_id = ? AND status = 'abandoned'"
|
|
33
|
+
)
|
|
34
|
+
while (remaining > 0) {
|
|
35
|
+
const candidate = nextCandidate.get(input.projectId) as { readonly version_id: number } | null
|
|
36
|
+
if (!candidate) break
|
|
37
|
+
const rows = deleteRows.run(candidate.version_id, remaining).changes
|
|
38
|
+
rowsDeleted += rows
|
|
39
|
+
remaining -= rows
|
|
40
|
+
if (remaining === 0) break
|
|
41
|
+
const roots = deleteRoots.run(candidate.version_id, remaining).changes
|
|
42
|
+
rowsDeleted += roots
|
|
43
|
+
remaining -= roots
|
|
44
|
+
if (remaining === 0) break
|
|
45
|
+
const manifest = deleteManifest.run(candidate.version_id).changes
|
|
46
|
+
if (manifest === 0) break
|
|
47
|
+
materializationsDeleted += manifest
|
|
48
|
+
remaining -= manifest
|
|
49
|
+
}
|
|
50
|
+
return { rowsDeleted, materializationsDeleted }
|
|
51
|
+
}
|
|
52
|
+
|
|
7
53
|
export function cleanupSourceVersions(
|
|
8
54
|
db: Database,
|
|
9
55
|
input: CleanupTerminalSourceMaterializationsInput
|
|
10
56
|
): CleanupTerminalSourceMaterializationsResult {
|
|
11
57
|
let remaining = input.limit
|
|
58
|
+
const retired = `roots.project_id = ? AND roots.retired_at < ? AND versions.status = 'superseded'`
|
|
12
59
|
let rowsDeleted = db
|
|
13
60
|
.query(`DELETE FROM ontology_source_rows WHERE rowid IN (
|
|
14
61
|
SELECT rows.rowid FROM ontology_source_roots AS roots
|
|
15
|
-
JOIN ontology_sources AS
|
|
16
|
-
CROSS JOIN ontology_source_rows AS rows
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
WHERE roots.project_id = ? AND roots.active = 0 AND roots.retired_at < ?
|
|
20
|
-
AND sources.status IN ('superseded', 'abandoned')
|
|
21
|
-
ORDER BY roots.retired_at, roots.source_id, roots.materialization_id, roots.root_sort_key, rows.entity_sort_key
|
|
62
|
+
JOIN ontology_sources AS versions ON versions.version_id = roots.version_id
|
|
63
|
+
CROSS JOIN ontology_source_rows AS rows ON rows.root_id = roots.id
|
|
64
|
+
WHERE ${retired}
|
|
65
|
+
ORDER BY roots.retired_at, roots.id
|
|
22
66
|
LIMIT ?
|
|
23
67
|
)`)
|
|
24
68
|
.run(input.projectId, input.terminalBefore, remaining).changes
|
|
25
69
|
remaining -= rowsDeleted
|
|
26
70
|
if (remaining > 0) {
|
|
27
71
|
const removed = db
|
|
28
|
-
.query(`DELETE FROM ontology_source_roots WHERE
|
|
29
|
-
SELECT roots.
|
|
30
|
-
JOIN ontology_sources AS
|
|
31
|
-
WHERE
|
|
32
|
-
AND
|
|
33
|
-
|
|
34
|
-
WHERE rows.project_id = roots.project_id AND rows.source_id = roots.source_id
|
|
35
|
-
AND rows.materialization_id = roots.materialization_id AND rows.root_sort_key = roots.root_sort_key)
|
|
36
|
-
ORDER BY roots.retired_at, roots.source_id, roots.materialization_id, roots.root_sort_key LIMIT ?
|
|
72
|
+
.query(`DELETE FROM ontology_source_roots WHERE id IN (
|
|
73
|
+
SELECT roots.id FROM ontology_source_roots AS roots
|
|
74
|
+
JOIN ontology_sources AS versions ON versions.version_id = roots.version_id
|
|
75
|
+
WHERE ${retired}
|
|
76
|
+
AND NOT EXISTS (SELECT 1 FROM ontology_source_rows AS rows WHERE rows.root_id = roots.id)
|
|
77
|
+
ORDER BY roots.retired_at, roots.id LIMIT ?
|
|
37
78
|
)`)
|
|
38
79
|
.run(input.projectId, input.terminalBefore, remaining).changes
|
|
39
80
|
rowsDeleted += removed
|
|
@@ -43,15 +84,11 @@ export function cleanupSourceVersions(
|
|
|
43
84
|
remaining === 0
|
|
44
85
|
? 0
|
|
45
86
|
: db
|
|
46
|
-
.query(`DELETE FROM ontology_sources WHERE
|
|
47
|
-
SELECT
|
|
48
|
-
WHERE project_id = ? AND status
|
|
87
|
+
.query(`DELETE FROM ontology_sources WHERE version_id IN (
|
|
88
|
+
SELECT versions.version_id FROM ontology_sources AS versions
|
|
89
|
+
WHERE project_id = ? AND status = 'superseded' AND terminal_at < ?
|
|
49
90
|
AND NOT EXISTS (SELECT 1 FROM ontology_source_roots AS roots
|
|
50
|
-
WHERE roots.
|
|
51
|
-
AND roots.materialization_id = sources.materialization_id)
|
|
52
|
-
AND NOT EXISTS (SELECT 1 FROM ontology_source_rows AS rows
|
|
53
|
-
WHERE rows.project_id = sources.project_id AND rows.source_id = sources.source_id
|
|
54
|
-
AND rows.materialization_id = sources.materialization_id)
|
|
91
|
+
WHERE roots.version_id = versions.version_id)
|
|
55
92
|
ORDER BY terminal_at, source_id, materialization_id LIMIT ?
|
|
56
93
|
)`)
|
|
57
94
|
.run(input.projectId, input.terminalBefore, remaining).changes
|