@sixb/pg 0.1.14 → 0.1.16
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.d.ts +8 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +743 -313
- package/dist/index.js.map +15 -15
- 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 +12 -9
- 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 +8 -0
- 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/pg-client.d.ts +2 -0
- package/dist/pg-client.d.ts.map +1 -1
- package/dist/pg-projection-run-storage.d.ts +3 -1
- package/dist/pg-projection-run-storage.d.ts.map +1 -1
- package/dist/storage-errors.d.ts +13 -3
- package/dist/storage-errors.d.ts.map +1 -1
- package/dist/transactions.d.ts +23 -1
- package/dist/transactions.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/index.ts +8 -1
- package/src/latest-run-query.ts +10 -2
- package/src/migrations/051-projection-run-supersession.sql +43 -0
- package/src/migrations/052-compact-source-storage.sql +118 -0
- package/src/migrations.ts +26 -23
- package/src/objects/query-compiler.ts +1 -1
- package/src/ontology-storage/materialization-state.ts +20 -46
- package/src/ontology-storage/shared.ts +18 -12
- package/src/ontology-storage/source-cleanup.ts +66 -22
- package/src/ontology-storage/source-roots.ts +164 -102
- package/src/ontology-storage/sources.ts +150 -120
- package/src/pg-client.ts +132 -2
- package/src/pg-projection-run-storage.ts +56 -2
- package/src/storage-errors.ts +101 -15
- package/src/transactions.ts +113 -20
package/src/migrations.ts
CHANGED
|
@@ -109,7 +109,14 @@ import nativeSessionsSql from "./migrations/049-native-sessions.sql" with { type
|
|
|
109
109
|
import directoryGroupMembershipsSql from "./migrations/050-directory-group-memberships.sql" with {
|
|
110
110
|
type: "text",
|
|
111
111
|
}
|
|
112
|
-
import
|
|
112
|
+
import projectionRunSupersessionSql from "./migrations/051-projection-run-supersession.sql" with {
|
|
113
|
+
type: "text",
|
|
114
|
+
}
|
|
115
|
+
import compactSourceStorageSql from "./migrations/052-compact-source-storage.sql" with {
|
|
116
|
+
type: "text",
|
|
117
|
+
}
|
|
118
|
+
import type { ReservedSQL, SQL, SQLClient } from "./pg-client"
|
|
119
|
+
import { runPgTransactionOn, undoOnFailure, withReservedPgConnection } from "./transactions"
|
|
113
120
|
|
|
114
121
|
export interface PostgresMigrationContext {
|
|
115
122
|
exec(sqlText: string): Promise<void>
|
|
@@ -189,7 +196,7 @@ export function quoteIdent(identifier: string): string {
|
|
|
189
196
|
}
|
|
190
197
|
|
|
191
198
|
function postgresMigrationSession(
|
|
192
|
-
sql:
|
|
199
|
+
sql: ReservedSQL,
|
|
193
200
|
schemaName: string
|
|
194
201
|
): { context: PostgresMigrationContext; state: MigrationHistoryStore } {
|
|
195
202
|
const schema = quoteIdent(schemaName)
|
|
@@ -256,19 +263,15 @@ function postgresMigrationSession(
|
|
|
256
263
|
},
|
|
257
264
|
async transaction(run) {
|
|
258
265
|
// `sql` is the reserved connection holding the migration advisory lock. porsager's
|
|
259
|
-
//
|
|
260
|
-
// route exec()/markStarted()/markApplied() through
|
|
266
|
+
// `.begin` would open the transaction on another pool connection, so drive it on this one
|
|
267
|
+
// and route exec()/markStarted()/markApplied() through it via `active`.
|
|
261
268
|
const previous = active
|
|
262
269
|
active = sql
|
|
263
|
-
await sql.unsafe("BEGIN")
|
|
264
270
|
try {
|
|
265
|
-
await sql
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
} catch (error) {
|
|
270
|
-
await sql.unsafe("ROLLBACK")
|
|
271
|
-
throw error
|
|
271
|
+
return await runPgTransactionOn(sql, async () => {
|
|
272
|
+
await sql.unsafe(`SET LOCAL search_path TO ${schema}`)
|
|
273
|
+
return run()
|
|
274
|
+
})
|
|
272
275
|
} finally {
|
|
273
276
|
active = previous
|
|
274
277
|
}
|
|
@@ -315,23 +318,21 @@ async function withPostgresMigrationLock<T>(
|
|
|
315
318
|
readonly schemaName: string
|
|
316
319
|
readonly migrations: MigrationSet<PostgresMigrationContext>
|
|
317
320
|
},
|
|
318
|
-
run: (sql:
|
|
321
|
+
run: (sql: ReservedSQL) => Promise<T>
|
|
319
322
|
): Promise<T> {
|
|
320
|
-
const sql = await params.sql.reserve()
|
|
321
323
|
const [first, second] = advisoryLockParts(
|
|
322
324
|
`storage:migration:${params.schemaName}:${params.migrations.adapterId}`
|
|
323
325
|
)
|
|
324
326
|
|
|
325
|
-
|
|
327
|
+
// A session-level lock outlives any transaction, so it is released before the connection goes
|
|
328
|
+
// back to the pool — except when the connection was lost, which already released it.
|
|
329
|
+
return withReservedPgConnection(params.sql, async (sql) => {
|
|
330
|
+
const unlock = () => sql`SELECT pg_advisory_unlock(${first}, ${second})`
|
|
326
331
|
await sql`SELECT pg_advisory_lock(${first}, ${second})`
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
}
|
|
332
|
-
} finally {
|
|
333
|
-
sql.release()
|
|
334
|
-
}
|
|
332
|
+
const result = await undoOnFailure(() => run(sql), unlock)
|
|
333
|
+
await unlock()
|
|
334
|
+
return result
|
|
335
|
+
})
|
|
335
336
|
}
|
|
336
337
|
|
|
337
338
|
function advisoryLockParts(key: string): readonly [number, number] {
|
|
@@ -412,6 +413,8 @@ export const postgresStorageMigrations = defineMigrations<PostgresMigrationConte
|
|
|
412
413
|
pgSql("048-file-upload-sessions", fileUploadSessionsSql),
|
|
413
414
|
pgSql("049-native-sessions", nativeSessionsSql),
|
|
414
415
|
pgSql("050-directory-group-memberships", directoryGroupMembershipsSql),
|
|
416
|
+
pgSql("051-projection-run-supersession", projectionRunSupersessionSql),
|
|
417
|
+
pgSql("052-compact-source-storage", compactSourceStorageSql),
|
|
415
418
|
],
|
|
416
419
|
})
|
|
417
420
|
|
|
@@ -110,7 +110,7 @@ export function compilePgObjectQuery(
|
|
|
110
110
|
if (hasVectorProfile(query) && !isVectorProfileQuery(query)) {
|
|
111
111
|
throw new ObjectQueryExecutionError(
|
|
112
112
|
"unsupported_vector_composition",
|
|
113
|
-
"Vector search supports one profile with filters before ranking and limit/project after."
|
|
113
|
+
"Vector search supports one profile with filters, traversals or sets before ranking and limit/project after."
|
|
114
114
|
)
|
|
115
115
|
}
|
|
116
116
|
const source = options.source ?? DEFAULT_OBJECT_QUERY_SOURCE
|
|
@@ -38,15 +38,21 @@ import type {
|
|
|
38
38
|
} from "@sixb/core/storage"
|
|
39
39
|
import type { SQLClient } from "../pg-client"
|
|
40
40
|
import {
|
|
41
|
-
databaseSafeInteger,
|
|
42
41
|
jsonParameter,
|
|
43
42
|
linkRefFromColumns,
|
|
44
43
|
objectRefFromColumns,
|
|
45
44
|
type PgOntologySourceAssertionRow,
|
|
46
45
|
type PgStoredOverrideRow,
|
|
46
|
+
sourceAssertion,
|
|
47
47
|
toIsoString,
|
|
48
48
|
} from "./shared"
|
|
49
|
-
import {
|
|
49
|
+
import {
|
|
50
|
+
activeSourceRows,
|
|
51
|
+
liveSourceRowsJoin,
|
|
52
|
+
replacementAssertionRows,
|
|
53
|
+
replacementSourceRows,
|
|
54
|
+
sourceAssertionColumns,
|
|
55
|
+
} from "./source-roots"
|
|
50
56
|
|
|
51
57
|
export const PG_MATERIALIZATION_WORK_TABLE = "ontology_materialization_work"
|
|
52
58
|
export const PG_REPLACEMENT_WORK_TABLE = "ontology_replacement_work"
|
|
@@ -410,20 +416,14 @@ export class PgMaterializationStateReader {
|
|
|
410
416
|
scope_sort_key TEXT, source_type_id TEXT, source_id TEXT, link_id TEXT
|
|
411
417
|
)
|
|
412
418
|
)
|
|
413
|
-
SELECT
|
|
419
|
+
SELECT ${sourceAssertionColumns(this.sql)}
|
|
414
420
|
FROM ontology_source_rows AS rows
|
|
415
421
|
JOIN requested
|
|
416
422
|
ON requested.source_type_id = rows.source_type_id
|
|
417
423
|
AND requested.source_id = rows.source_primary_id
|
|
418
424
|
AND requested.link_id = rows.link_id
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
AND sources.source_id = rows.source_id
|
|
422
|
-
AND sources.materialization_id = rows.materialization_id
|
|
423
|
-
AND sources.root_sort_key = rows.root_sort_key
|
|
424
|
-
WHERE rows.project_id = ${this.projectId}
|
|
425
|
-
AND rows.entity_kind = 'link'
|
|
426
|
-
AND sources.active
|
|
425
|
+
${liveSourceRowsJoin(this.sql, this.projectId)}
|
|
426
|
+
WHERE rows.entity_kind = 'link'
|
|
427
427
|
`,
|
|
428
428
|
this.sql<LinkSlotOverrideRow[]>`
|
|
429
429
|
WITH requested AS (
|
|
@@ -582,32 +582,20 @@ export class PgMaterializationStateReader {
|
|
|
582
582
|
SELECT rows.source_type_id, rows.source_primary_id AS source_id,
|
|
583
583
|
rows.link_id, rows.target_type_id, rows.target_primary_id AS target_id
|
|
584
584
|
FROM ontology_source_rows AS rows
|
|
585
|
-
|
|
586
|
-
ON sources.project_id = rows.project_id
|
|
587
|
-
AND sources.source_id = rows.source_id
|
|
588
|
-
AND sources.materialization_id = rows.materialization_id
|
|
589
|
-
AND sources.root_sort_key = rows.root_sort_key
|
|
585
|
+
${liveSourceRowsJoin(this.sql, this.projectId)}
|
|
590
586
|
JOIN requested
|
|
591
587
|
ON requested.object_type_id = rows.source_type_id
|
|
592
588
|
AND requested.primary_id = rows.source_primary_id
|
|
593
|
-
WHERE rows.
|
|
594
|
-
AND rows.entity_kind = 'link'
|
|
595
|
-
AND sources.active
|
|
589
|
+
WHERE rows.entity_kind = 'link'
|
|
596
590
|
UNION
|
|
597
591
|
SELECT rows.source_type_id, rows.source_primary_id AS source_id,
|
|
598
592
|
rows.link_id, rows.target_type_id, rows.target_primary_id AS target_id
|
|
599
593
|
FROM ontology_source_rows AS rows
|
|
600
|
-
|
|
601
|
-
ON sources.project_id = rows.project_id
|
|
602
|
-
AND sources.source_id = rows.source_id
|
|
603
|
-
AND sources.materialization_id = rows.materialization_id
|
|
604
|
-
AND sources.root_sort_key = rows.root_sort_key
|
|
594
|
+
${liveSourceRowsJoin(this.sql, this.projectId)}
|
|
605
595
|
JOIN requested
|
|
606
596
|
ON requested.object_type_id = rows.target_type_id
|
|
607
597
|
AND requested.primary_id = rows.target_primary_id
|
|
608
|
-
WHERE rows.
|
|
609
|
-
AND rows.entity_kind = 'link'
|
|
610
|
-
AND sources.active
|
|
598
|
+
WHERE rows.entity_kind = 'link'
|
|
611
599
|
), selected AS (
|
|
612
600
|
SELECT DISTINCT links.*,
|
|
613
601
|
${this.sql.unsafe(linkSortExpression("links"))} AS sort_key
|
|
@@ -912,32 +900,20 @@ export class PgMaterializationStateReader {
|
|
|
912
900
|
SELECT rows.source_type_id, rows.source_primary_id AS source_id,
|
|
913
901
|
rows.link_id, rows.target_type_id, rows.target_primary_id AS target_id
|
|
914
902
|
FROM ontology_source_rows AS rows
|
|
915
|
-
|
|
916
|
-
ON sources.project_id = rows.project_id
|
|
917
|
-
AND sources.source_id = rows.source_id
|
|
918
|
-
AND sources.materialization_id = rows.materialization_id
|
|
919
|
-
AND sources.root_sort_key = rows.root_sort_key
|
|
903
|
+
${liveSourceRowsJoin(this.sql, this.projectId)}
|
|
920
904
|
JOIN incident_objects
|
|
921
905
|
ON incident_objects.object_type_id = rows.source_type_id
|
|
922
906
|
AND incident_objects.primary_id = rows.source_primary_id
|
|
923
|
-
WHERE rows.
|
|
924
|
-
AND rows.entity_kind = 'link'
|
|
925
|
-
AND sources.active
|
|
907
|
+
WHERE rows.entity_kind = 'link'
|
|
926
908
|
UNION
|
|
927
909
|
SELECT rows.source_type_id, rows.source_primary_id AS source_id,
|
|
928
910
|
rows.link_id, rows.target_type_id, rows.target_primary_id AS target_id
|
|
929
911
|
FROM ontology_source_rows AS rows
|
|
930
|
-
|
|
931
|
-
ON sources.project_id = rows.project_id
|
|
932
|
-
AND sources.source_id = rows.source_id
|
|
933
|
-
AND sources.materialization_id = rows.materialization_id
|
|
934
|
-
AND sources.root_sort_key = rows.root_sort_key
|
|
912
|
+
${liveSourceRowsJoin(this.sql, this.projectId)}
|
|
935
913
|
JOIN incident_objects
|
|
936
914
|
ON incident_objects.object_type_id = rows.target_type_id
|
|
937
915
|
AND incident_objects.primary_id = rows.target_primary_id
|
|
938
|
-
WHERE rows.
|
|
939
|
-
AND rows.entity_kind = 'link'
|
|
940
|
-
AND sources.active
|
|
916
|
+
WHERE rows.entity_kind = 'link'
|
|
941
917
|
), diff_links AS (
|
|
942
918
|
SELECT * FROM replacement_links
|
|
943
919
|
UNION SELECT * FROM incident_links
|
|
@@ -1104,9 +1080,7 @@ function storedSource(row: PgOntologySourceAssertionRow): StoredSourceAssertion
|
|
|
1104
1080
|
return {
|
|
1105
1081
|
source: { projectionId: row.source_id },
|
|
1106
1082
|
materializationId: row.materialization_id,
|
|
1107
|
-
|
|
1108
|
-
assertion: structuredClone(row.assertion) as StoredSourceAssertion["assertion"],
|
|
1109
|
-
stagingOrdinal: databaseSafeInteger(row.staging_ordinal, "Source staging ordinal"),
|
|
1083
|
+
...sourceAssertion(row),
|
|
1110
1084
|
} as StoredSourceAssertion
|
|
1111
1085
|
}
|
|
1112
1086
|
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { parseSixbFailure } from "@sixb/core/internal/errors"
|
|
2
|
-
import type { ProjectionEntityRef } from "@sixb/core/internal/materialization"
|
|
3
2
|
import { MaterializationConflictError } from "@sixb/core/internal/materialization"
|
|
3
|
+
import {
|
|
4
|
+
sourceAssertionFromColumns,
|
|
5
|
+
sourceEntityFromKey,
|
|
6
|
+
} from "@sixb/core/internal/ontology-storage-provider"
|
|
4
7
|
import type {
|
|
5
8
|
AssertSourceMaterializationExecutionInput,
|
|
6
9
|
OntologyCommitRecord,
|
|
@@ -50,6 +53,7 @@ export interface PgOntologyCommitRow {
|
|
|
50
53
|
}
|
|
51
54
|
|
|
52
55
|
export interface PgOntologySourceRow {
|
|
56
|
+
readonly version_id: string
|
|
53
57
|
readonly project_id: string
|
|
54
58
|
readonly source_id: string
|
|
55
59
|
readonly materialization_id: string
|
|
@@ -76,19 +80,21 @@ export interface PgOntologySourceRow {
|
|
|
76
80
|
readonly updated_at: Date | string
|
|
77
81
|
}
|
|
78
82
|
|
|
83
|
+
/** An assertion with its root and version, as `sourceAssertionColumns` selects it. */
|
|
79
84
|
export interface PgOntologySourceAssertionRow {
|
|
80
|
-
readonly project_id: string
|
|
81
85
|
readonly source_id: string
|
|
82
86
|
readonly materialization_id: string
|
|
83
|
-
readonly
|
|
84
|
-
readonly entity_key: unknown
|
|
85
|
-
readonly entity_sort_key: string
|
|
86
|
-
readonly root_kind: "object" | "link"
|
|
87
|
-
readonly root_key: unknown
|
|
88
|
-
readonly root_sort_key: string
|
|
87
|
+
readonly root_key: string
|
|
89
88
|
readonly staging_ordinal: number | string
|
|
90
|
-
readonly
|
|
91
|
-
readonly
|
|
89
|
+
readonly entity_kind: "object" | "link"
|
|
90
|
+
readonly object_type_id: string | null
|
|
91
|
+
readonly primary_id: string | null
|
|
92
|
+
readonly source_type_id: string | null
|
|
93
|
+
readonly source_primary_id: string | null
|
|
94
|
+
readonly link_id: string | null
|
|
95
|
+
readonly target_type_id: string | null
|
|
96
|
+
readonly target_primary_id: string | null
|
|
97
|
+
readonly payload: unknown
|
|
92
98
|
}
|
|
93
99
|
|
|
94
100
|
export interface PgStoredOverrideRow {
|
|
@@ -174,8 +180,8 @@ export function sourceRecord(row: PgOntologySourceRow): OntologySourceRecord {
|
|
|
174
180
|
|
|
175
181
|
export function sourceAssertion(row: PgOntologySourceAssertionRow): StageSourceAssertion {
|
|
176
182
|
return {
|
|
177
|
-
root:
|
|
178
|
-
assertion:
|
|
183
|
+
root: sourceEntityFromKey(row.root_key),
|
|
184
|
+
assertion: sourceAssertionFromColumns(row, row.payload),
|
|
179
185
|
stagingOrdinal: databaseSafeInteger(row.staging_ordinal, "Source staging ordinal"),
|
|
180
186
|
}
|
|
181
187
|
}
|
|
@@ -1,24 +1,74 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
CleanupTerminalSourceMaterializationsInput,
|
|
3
3
|
CleanupTerminalSourceMaterializationsResult,
|
|
4
|
+
PurgeAbandonedSourceMaterializationsInput,
|
|
4
5
|
} from "@sixb/core/storage"
|
|
5
6
|
import type { SQLClient } from "../pg-client"
|
|
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 async function purgeAbandonedSourceVersions(
|
|
14
|
+
sql: SQLClient,
|
|
15
|
+
input: PurgeAbandonedSourceMaterializationsInput
|
|
16
|
+
): Promise<CleanupTerminalSourceMaterializationsResult> {
|
|
17
|
+
let remaining = input.limit
|
|
18
|
+
let rowsDeleted = 0
|
|
19
|
+
let materializationsDeleted = 0
|
|
20
|
+
while (remaining > 0) {
|
|
21
|
+
const [candidate] = await sql<{ readonly version_id: string }[]>`
|
|
22
|
+
SELECT version_id FROM ontology_sources
|
|
23
|
+
WHERE project_id = ${input.projectId} AND status = 'abandoned'
|
|
24
|
+
ORDER BY terminal_at, source_id, materialization_id
|
|
25
|
+
LIMIT 1 FOR UPDATE SKIP LOCKED
|
|
26
|
+
`
|
|
27
|
+
if (!candidate) break
|
|
28
|
+
const rows = await sql`
|
|
29
|
+
DELETE FROM ontology_source_rows WHERE ctid IN (
|
|
30
|
+
SELECT rows.ctid FROM ontology_source_roots AS roots
|
|
31
|
+
JOIN ontology_source_rows AS rows ON rows.root_id = roots.id
|
|
32
|
+
WHERE roots.version_id = ${candidate.version_id} LIMIT ${remaining}
|
|
33
|
+
)
|
|
34
|
+
`
|
|
35
|
+
rowsDeleted += rows.count
|
|
36
|
+
remaining -= rows.count
|
|
37
|
+
if (remaining === 0) break
|
|
38
|
+
const roots = await sql`
|
|
39
|
+
DELETE FROM ontology_source_roots WHERE ctid IN (
|
|
40
|
+
SELECT ctid FROM ontology_source_roots
|
|
41
|
+
WHERE version_id = ${candidate.version_id} LIMIT ${remaining}
|
|
42
|
+
)
|
|
43
|
+
`
|
|
44
|
+
rowsDeleted += roots.count
|
|
45
|
+
remaining -= roots.count
|
|
46
|
+
if (remaining === 0) break
|
|
47
|
+
const manifest = await sql`
|
|
48
|
+
DELETE FROM ontology_sources
|
|
49
|
+
WHERE version_id = ${candidate.version_id} AND status = 'abandoned'
|
|
50
|
+
`
|
|
51
|
+
if (manifest.count === 0) break
|
|
52
|
+
materializationsDeleted += manifest.count
|
|
53
|
+
remaining -= manifest.count
|
|
54
|
+
}
|
|
55
|
+
return { rowsDeleted, materializationsDeleted }
|
|
56
|
+
}
|
|
57
|
+
|
|
7
58
|
export async function cleanupSourceVersions(
|
|
8
59
|
sql: SQLClient,
|
|
9
60
|
input: CleanupTerminalSourceMaterializationsInput
|
|
10
61
|
): Promise<CleanupTerminalSourceMaterializationsResult> {
|
|
11
62
|
let remaining = input.limit
|
|
63
|
+
const retired = sql`roots.project_id = ${input.projectId}
|
|
64
|
+
AND roots.retired_at < ${input.terminalBefore} AND versions.status = 'superseded'`
|
|
12
65
|
const removedRows = await sql`
|
|
13
66
|
WITH selected AS (
|
|
14
67
|
SELECT rows.ctid FROM ontology_source_roots AS roots
|
|
15
|
-
JOIN ontology_sources AS
|
|
16
|
-
JOIN ontology_source_rows AS rows
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
WHERE roots.project_id = ${input.projectId} AND NOT roots.active AND roots.retired_at < ${input.terminalBefore}
|
|
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
|
|
68
|
+
JOIN ontology_sources AS versions ON versions.version_id = roots.version_id
|
|
69
|
+
JOIN ontology_source_rows AS rows ON rows.root_id = roots.id
|
|
70
|
+
WHERE ${retired}
|
|
71
|
+
ORDER BY roots.retired_at, roots.id
|
|
22
72
|
LIMIT ${remaining} FOR UPDATE OF rows SKIP LOCKED
|
|
23
73
|
) DELETE FROM ontology_source_rows AS rows USING selected WHERE rows.ctid = selected.ctid RETURNING 1
|
|
24
74
|
`
|
|
@@ -28,13 +78,10 @@ export async function cleanupSourceVersions(
|
|
|
28
78
|
const removed = await sql`
|
|
29
79
|
WITH selected AS (
|
|
30
80
|
SELECT roots.ctid FROM ontology_source_roots AS roots
|
|
31
|
-
JOIN ontology_sources AS
|
|
32
|
-
WHERE
|
|
33
|
-
AND
|
|
34
|
-
|
|
35
|
-
WHERE rows.project_id = roots.project_id AND rows.source_id = roots.source_id
|
|
36
|
-
AND rows.materialization_id = roots.materialization_id AND rows.root_sort_key = roots.root_sort_key)
|
|
37
|
-
ORDER BY roots.retired_at, roots.source_id, roots.materialization_id, roots.root_sort_key
|
|
81
|
+
JOIN ontology_sources AS versions ON versions.version_id = roots.version_id
|
|
82
|
+
WHERE ${retired}
|
|
83
|
+
AND NOT EXISTS (SELECT 1 FROM ontology_source_rows AS rows WHERE rows.root_id = roots.id)
|
|
84
|
+
ORDER BY roots.retired_at, roots.id
|
|
38
85
|
LIMIT ${remaining} FOR UPDATE OF roots SKIP LOCKED
|
|
39
86
|
) DELETE FROM ontology_source_roots AS roots USING selected WHERE roots.ctid = selected.ctid RETURNING 1
|
|
40
87
|
`
|
|
@@ -46,16 +93,13 @@ export async function cleanupSourceVersions(
|
|
|
46
93
|
? []
|
|
47
94
|
: await sql`
|
|
48
95
|
WITH selected AS (
|
|
49
|
-
SELECT
|
|
50
|
-
WHERE project_id = ${input.projectId} AND status
|
|
96
|
+
SELECT versions.ctid FROM ontology_sources AS versions
|
|
97
|
+
WHERE project_id = ${input.projectId} AND status = 'superseded'
|
|
98
|
+
AND terminal_at < ${input.terminalBefore}
|
|
51
99
|
AND NOT EXISTS (SELECT 1 FROM ontology_source_roots AS roots
|
|
52
|
-
WHERE roots.
|
|
53
|
-
AND roots.materialization_id = sources.materialization_id)
|
|
54
|
-
AND NOT EXISTS (SELECT 1 FROM ontology_source_rows AS rows
|
|
55
|
-
WHERE rows.project_id = sources.project_id AND rows.source_id = sources.source_id
|
|
56
|
-
AND rows.materialization_id = sources.materialization_id)
|
|
100
|
+
WHERE roots.version_id = versions.version_id)
|
|
57
101
|
ORDER BY terminal_at, source_id, materialization_id LIMIT ${remaining} FOR UPDATE SKIP LOCKED
|
|
58
|
-
) DELETE FROM ontology_sources AS
|
|
102
|
+
) DELETE FROM ontology_sources AS versions USING selected WHERE versions.ctid = selected.ctid RETURNING 1
|
|
59
103
|
`
|
|
60
104
|
return { rowsDeleted, materializationsDeleted: removedManifests.length }
|
|
61
105
|
}
|