@sixb/pg 0.0.1
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/LICENSE +21 -0
- package/README.md +73 -0
- package/dist/agents/agent-storage.d.ts +20 -0
- package/dist/agents/agent-storage.d.ts.map +1 -0
- package/dist/agents/index.d.ts +6 -0
- package/dist/agents/index.d.ts.map +1 -0
- package/dist/agents/messages.d.ts +13 -0
- package/dist/agents/messages.d.ts.map +1 -0
- package/dist/agents/rows.d.ts +77 -0
- package/dist/agents/rows.d.ts.map +1 -0
- package/dist/agents/runs.d.ts +25 -0
- package/dist/agents/runs.d.ts.map +1 -0
- package/dist/agents/threads.d.ts +13 -0
- package/dist/agents/threads.d.ts.map +1 -0
- package/dist/auth-storage/access-tokens.d.ts +33 -0
- package/dist/auth-storage/access-tokens.d.ts.map +1 -0
- package/dist/auth-storage/auth-storage.d.ts +41 -0
- package/dist/auth-storage/auth-storage.d.ts.map +1 -0
- package/dist/auth-storage/group-memberships.d.ts +21 -0
- package/dist/auth-storage/group-memberships.d.ts.map +1 -0
- package/dist/auth-storage/identities.d.ts +17 -0
- package/dist/auth-storage/identities.d.ts.map +1 -0
- package/dist/auth-storage/index.d.ts +3 -0
- package/dist/auth-storage/index.d.ts.map +1 -0
- package/dist/auth-storage/invitations.d.ts +29 -0
- package/dist/auth-storage/invitations.d.ts.map +1 -0
- package/dist/auth-storage/magic-links.d.ts +28 -0
- package/dist/auth-storage/magic-links.d.ts.map +1 -0
- package/dist/auth-storage/oidc-attempts.d.ts +18 -0
- package/dist/auth-storage/oidc-attempts.d.ts.map +1 -0
- package/dist/auth-storage/rows.d.ts +138 -0
- package/dist/auth-storage/rows.d.ts.map +1 -0
- package/dist/auth-storage/service-account-group-memberships.d.ts +17 -0
- package/dist/auth-storage/service-account-group-memberships.d.ts.map +1 -0
- package/dist/auth-storage/service-accounts.d.ts +14 -0
- package/dist/auth-storage/service-accounts.d.ts.map +1 -0
- package/dist/auth-storage/sessions.d.ts +55 -0
- package/dist/auth-storage/sessions.d.ts.map +1 -0
- package/dist/auth-storage/shared.d.ts +159 -0
- package/dist/auth-storage/shared.d.ts.map +1 -0
- package/dist/auth-storage/users.d.ts +19 -0
- package/dist/auth-storage/users.d.ts.map +1 -0
- package/dist/index.d.ts +127 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11957 -0
- package/dist/index.js.map +55 -0
- package/dist/latest-run-query.d.ts +24 -0
- package/dist/latest-run-query.d.ts.map +1 -0
- package/dist/migrations.d.ts +20 -0
- package/dist/migrations.d.ts.map +1 -0
- package/dist/ontology-storage/commits.d.ts +11 -0
- package/dist/ontology-storage/commits.d.ts.map +1 -0
- package/dist/ontology-storage/index.d.ts +22 -0
- package/dist/ontology-storage/index.d.ts.map +1 -0
- package/dist/ontology-storage/materialization-session.d.ts +63 -0
- package/dist/ontology-storage/materialization-session.d.ts.map +1 -0
- package/dist/ontology-storage/materialization-state.d.ts +69 -0
- package/dist/ontology-storage/materialization-state.d.ts.map +1 -0
- package/dist/ontology-storage/materialization-writer.d.ts +15 -0
- package/dist/ontology-storage/materialization-writer.d.ts.map +1 -0
- package/dist/ontology-storage/materializations.d.ts +33 -0
- package/dist/ontology-storage/materializations.d.ts.map +1 -0
- package/dist/ontology-storage/outbox.d.ts +12 -0
- package/dist/ontology-storage/outbox.d.ts.map +1 -0
- package/dist/ontology-storage/shared.d.ts +95 -0
- package/dist/ontology-storage/shared.d.ts.map +1 -0
- package/dist/ontology-storage/sources.d.ts +25 -0
- package/dist/ontology-storage/sources.d.ts.map +1 -0
- package/dist/pg-action-run-storage.d.ts +21 -0
- package/dist/pg-action-run-storage.d.ts.map +1 -0
- package/dist/pg-client.d.ts +58 -0
- package/dist/pg-client.d.ts.map +1 -0
- package/dist/pg-object-query-compiler.d.ts +55 -0
- package/dist/pg-object-query-compiler.d.ts.map +1 -0
- package/dist/pg-object-storage.d.ts +90 -0
- package/dist/pg-object-storage.d.ts.map +1 -0
- package/dist/pg-pipeline-run-storage.d.ts +18 -0
- package/dist/pg-pipeline-run-storage.d.ts.map +1 -0
- package/dist/pg-projection-run-storage.d.ts +19 -0
- package/dist/pg-projection-run-storage.d.ts.map +1 -0
- package/dist/pg-rules-storage.d.ts +25 -0
- package/dist/pg-rules-storage.d.ts.map +1 -0
- package/dist/pg-sync-run-storage.d.ts +15 -0
- package/dist/pg-sync-run-storage.d.ts.map +1 -0
- package/dist/pg-timeseries-storage.d.ts +32 -0
- package/dist/pg-timeseries-storage.d.ts.map +1 -0
- package/dist/pg-webhook-delivery-storage.d.ts +17 -0
- package/dist/pg-webhook-delivery-storage.d.ts.map +1 -0
- package/dist/pg-webhook-run-storage.d.ts +14 -0
- package/dist/pg-webhook-run-storage.d.ts.map +1 -0
- package/dist/pg-workflow-intervention-storage.d.ts +16 -0
- package/dist/pg-workflow-intervention-storage.d.ts.map +1 -0
- package/dist/pg-workflow-run-storage.d.ts +49 -0
- package/dist/pg-workflow-run-storage.d.ts.map +1 -0
- package/dist/run-list-query.d.ts +30 -0
- package/dist/run-list-query.d.ts.map +1 -0
- package/dist/storage-errors.d.ts +16 -0
- package/dist/storage-errors.d.ts.map +1 -0
- package/dist/transactions.d.ts +10 -0
- package/dist/transactions.d.ts.map +1 -0
- package/dist/tsconfig.json +5 -0
- package/package.json +60 -0
- package/src/agents/agent-storage.ts +26 -0
- package/src/agents/index.ts +5 -0
- package/src/agents/messages.ts +144 -0
- package/src/agents/rows.ts +227 -0
- package/src/agents/runs.ts +330 -0
- package/src/agents/threads.ts +116 -0
- package/src/auth-storage/access-tokens.ts +254 -0
- package/src/auth-storage/auth-storage.ts +798 -0
- package/src/auth-storage/group-memberships.ts +47 -0
- package/src/auth-storage/identities.ts +85 -0
- package/src/auth-storage/index.ts +2 -0
- package/src/auth-storage/invitations.ts +280 -0
- package/src/auth-storage/magic-links.ts +140 -0
- package/src/auth-storage/oidc-attempts.ts +93 -0
- package/src/auth-storage/rows.ts +352 -0
- package/src/auth-storage/service-account-group-memberships.ts +150 -0
- package/src/auth-storage/service-accounts.ts +154 -0
- package/src/auth-storage/sessions.ts +193 -0
- package/src/auth-storage/shared.ts +799 -0
- package/src/auth-storage/users.ts +196 -0
- package/src/index.ts +367 -0
- package/src/latest-run-query.ts +42 -0
- package/src/migrations/001-initial-schema.sql +1195 -0
- package/src/migrations.ts +280 -0
- package/src/ontology-storage/commits.ts +115 -0
- package/src/ontology-storage/index.ts +35 -0
- package/src/ontology-storage/materialization-session.ts +426 -0
- package/src/ontology-storage/materialization-state.ts +1109 -0
- package/src/ontology-storage/materialization-writer.ts +509 -0
- package/src/ontology-storage/materializations.ts +939 -0
- package/src/ontology-storage/outbox.ts +216 -0
- package/src/ontology-storage/shared.ts +293 -0
- package/src/ontology-storage/sources.ts +658 -0
- package/src/pg-action-run-storage.ts +657 -0
- package/src/pg-client.ts +124 -0
- package/src/pg-object-query-compiler.ts +1545 -0
- package/src/pg-object-storage.ts +638 -0
- package/src/pg-pipeline-run-storage.ts +457 -0
- package/src/pg-projection-run-storage.ts +526 -0
- package/src/pg-rules-storage.ts +308 -0
- package/src/pg-sync-run-storage.ts +263 -0
- package/src/pg-timeseries-storage.ts +180 -0
- package/src/pg-webhook-delivery-storage.ts +180 -0
- package/src/pg-webhook-run-storage.ts +185 -0
- package/src/pg-workflow-intervention-storage.ts +339 -0
- package/src/pg-workflow-run-storage.ts +1065 -0
- package/src/run-list-query.ts +108 -0
- package/src/sql.d.ts +4 -0
- package/src/storage-errors.ts +72 -0
- package/src/transactions.ts +58 -0
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
import type { DatasetVersionRef } from "@sixb/core/lake-storage"
|
|
2
|
+
import type {
|
|
3
|
+
FinishPipelineRunInput,
|
|
4
|
+
FinishPipelineStepRunInput,
|
|
5
|
+
ListLatestPipelineRunsInput,
|
|
6
|
+
ListLatestPipelineRunsResult,
|
|
7
|
+
ListPipelineRunsInput,
|
|
8
|
+
ListPipelineRunsResult,
|
|
9
|
+
ListPipelineStepRunsInput,
|
|
10
|
+
ListPipelineStepRunsResult,
|
|
11
|
+
PipelineRunFailure,
|
|
12
|
+
PipelineRunRecord,
|
|
13
|
+
PipelineRunStorage,
|
|
14
|
+
PipelineStepRunRecord,
|
|
15
|
+
StartPipelineRunInput,
|
|
16
|
+
StartPipelineStepRunInput,
|
|
17
|
+
} from "@sixb/core/storage"
|
|
18
|
+
import { PipelineRunError } from "@sixb/core/storage"
|
|
19
|
+
import { queryLatestRunsByOwnerId } from "./latest-run-query"
|
|
20
|
+
import type { SqlParameter } from "./pg-client"
|
|
21
|
+
import { appendRunListFilters, hasEmptyStatuses, queryRunList } from "./run-list-query"
|
|
22
|
+
import { isUniqueViolation } from "./storage-errors"
|
|
23
|
+
import { type PgStoreClient, runPgTransaction } from "./transactions"
|
|
24
|
+
|
|
25
|
+
export class PgPipelineRunStorage implements PipelineRunStorage {
|
|
26
|
+
constructor(private readonly sql: PgStoreClient) {}
|
|
27
|
+
|
|
28
|
+
async start(input: StartPipelineRunInput): Promise<PipelineRunRecord> {
|
|
29
|
+
try {
|
|
30
|
+
const [row] = await this.sql<PipelineRunDatabaseRow[]>`
|
|
31
|
+
INSERT INTO pipeline_runs (
|
|
32
|
+
project_id,
|
|
33
|
+
id,
|
|
34
|
+
pipeline_id,
|
|
35
|
+
status,
|
|
36
|
+
started_at
|
|
37
|
+
) VALUES (
|
|
38
|
+
${input.projectId},
|
|
39
|
+
${input.id},
|
|
40
|
+
${input.pipelineId},
|
|
41
|
+
${"running"},
|
|
42
|
+
${input.startedAt ?? new Date()}
|
|
43
|
+
)
|
|
44
|
+
RETURNING *
|
|
45
|
+
`
|
|
46
|
+
|
|
47
|
+
return rowToPipelineRunRecord(row)
|
|
48
|
+
} catch (error) {
|
|
49
|
+
if (isUniqueViolation(error)) {
|
|
50
|
+
throw new PipelineRunError(
|
|
51
|
+
`[SixbPg] Pipeline run '${input.id}' already exists for project '${input.projectId}'.`
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
throw error
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async finish(input: FinishPipelineRunInput): Promise<PipelineRunRecord> {
|
|
60
|
+
return runPgTransaction(this.sql, async (tx) => {
|
|
61
|
+
const [existing] = await tx<PipelineRunDatabaseRow[]>`
|
|
62
|
+
SELECT * FROM pipeline_runs
|
|
63
|
+
WHERE project_id = ${input.projectId} AND id = ${input.id}
|
|
64
|
+
`
|
|
65
|
+
|
|
66
|
+
if (!existing) {
|
|
67
|
+
throw new PipelineRunError(
|
|
68
|
+
`[SixbPg] Pipeline run '${input.id}' not found for project '${input.projectId}'.`
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (existing.status !== "running") {
|
|
73
|
+
throw new PipelineRunError(
|
|
74
|
+
`[SixbPg] Pipeline run '${input.id}' for project '${input.projectId}' is already terminal.`
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const [updated] =
|
|
79
|
+
input.status === "succeeded"
|
|
80
|
+
? await tx<PipelineRunDatabaseRow[]>`
|
|
81
|
+
UPDATE pipeline_runs
|
|
82
|
+
SET
|
|
83
|
+
status = ${input.status},
|
|
84
|
+
finished_at = ${input.finishedAt ?? new Date()},
|
|
85
|
+
output_dataset_id = ${input.output?.datasetId ?? null},
|
|
86
|
+
output_version_id = ${input.output?.versionId ?? null},
|
|
87
|
+
error_name = ${null},
|
|
88
|
+
error_message = ${null}
|
|
89
|
+
WHERE project_id = ${input.projectId} AND id = ${input.id}
|
|
90
|
+
RETURNING *
|
|
91
|
+
`
|
|
92
|
+
: await tx<PipelineRunDatabaseRow[]>`
|
|
93
|
+
UPDATE pipeline_runs
|
|
94
|
+
SET
|
|
95
|
+
status = ${input.status},
|
|
96
|
+
finished_at = ${input.finishedAt ?? new Date()},
|
|
97
|
+
output_dataset_id = ${null},
|
|
98
|
+
output_version_id = ${null},
|
|
99
|
+
error_name = ${input.error?.name ?? null},
|
|
100
|
+
error_message = ${input.error?.message ?? null}
|
|
101
|
+
WHERE project_id = ${input.projectId} AND id = ${input.id}
|
|
102
|
+
RETURNING *
|
|
103
|
+
`
|
|
104
|
+
|
|
105
|
+
return rowToPipelineRunRecord(updated)
|
|
106
|
+
})
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async startStep(input: StartPipelineStepRunInput): Promise<PipelineStepRunRecord> {
|
|
110
|
+
return runPgTransaction(this.sql, async (tx) => {
|
|
111
|
+
const [pipelineRun] = await tx<PipelineRunDatabaseRow[]>`
|
|
112
|
+
SELECT * FROM pipeline_runs
|
|
113
|
+
WHERE project_id = ${input.projectId} AND id = ${input.pipelineRunId}
|
|
114
|
+
`
|
|
115
|
+
|
|
116
|
+
if (!pipelineRun) {
|
|
117
|
+
throw new PipelineRunError(
|
|
118
|
+
`[SixbPg] Pipeline run '${input.pipelineRunId}' not found for project '${input.projectId}'.`
|
|
119
|
+
)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (pipelineRun.status !== "running") {
|
|
123
|
+
throw new PipelineRunError(
|
|
124
|
+
`[SixbPg] Pipeline run '${input.pipelineRunId}' for project '${input.projectId}' is already terminal.`
|
|
125
|
+
)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (pipelineRun.pipeline_id !== input.pipelineId) {
|
|
129
|
+
throw new PipelineRunError(
|
|
130
|
+
`[SixbPg] Pipeline step run '${input.id}' pipeline '${input.pipelineId}' does not match pipeline run '${input.pipelineRunId}' pipeline '${pipelineRun.pipeline_id}'.`
|
|
131
|
+
)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
try {
|
|
135
|
+
const [row] = await tx<PipelineStepRunDatabaseRow[]>`
|
|
136
|
+
INSERT INTO pipeline_step_runs (
|
|
137
|
+
project_id,
|
|
138
|
+
id,
|
|
139
|
+
pipeline_run_id,
|
|
140
|
+
pipeline_id,
|
|
141
|
+
step_id,
|
|
142
|
+
dataset_id,
|
|
143
|
+
mode,
|
|
144
|
+
status,
|
|
145
|
+
started_at,
|
|
146
|
+
inputs
|
|
147
|
+
) VALUES (
|
|
148
|
+
${input.projectId},
|
|
149
|
+
${input.id},
|
|
150
|
+
${input.pipelineRunId},
|
|
151
|
+
${input.pipelineId},
|
|
152
|
+
${input.stepId},
|
|
153
|
+
${input.datasetId},
|
|
154
|
+
${input.mode},
|
|
155
|
+
${"running"},
|
|
156
|
+
${input.startedAt ?? new Date()},
|
|
157
|
+
${JSON.stringify(input.inputs)}::text::jsonb
|
|
158
|
+
)
|
|
159
|
+
RETURNING *
|
|
160
|
+
`
|
|
161
|
+
|
|
162
|
+
return rowToPipelineStepRunRecord(row)
|
|
163
|
+
} catch (error) {
|
|
164
|
+
if (isUniqueViolation(error)) {
|
|
165
|
+
throw new PipelineRunError(
|
|
166
|
+
`[SixbPg] Pipeline step run '${input.id}' already exists for project '${input.projectId}'.`
|
|
167
|
+
)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
throw error
|
|
171
|
+
}
|
|
172
|
+
})
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async finishStep(input: FinishPipelineStepRunInput): Promise<PipelineStepRunRecord> {
|
|
176
|
+
assertOptionalNonNegativeInteger(input.rowsWritten, "rowsWritten")
|
|
177
|
+
|
|
178
|
+
return runPgTransaction(this.sql, async (tx) => {
|
|
179
|
+
const [existing] = await tx<PipelineStepRunDatabaseRow[]>`
|
|
180
|
+
SELECT * FROM pipeline_step_runs
|
|
181
|
+
WHERE project_id = ${input.projectId} AND id = ${input.id}
|
|
182
|
+
`
|
|
183
|
+
|
|
184
|
+
if (!existing) {
|
|
185
|
+
throw new PipelineRunError(
|
|
186
|
+
`[SixbPg] Pipeline step run '${input.id}' not found for project '${input.projectId}'.`
|
|
187
|
+
)
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (existing.status !== "running") {
|
|
191
|
+
throw new PipelineRunError(
|
|
192
|
+
`[SixbPg] Pipeline step run '${input.id}' for project '${input.projectId}' is already terminal.`
|
|
193
|
+
)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (input.status === "succeeded" && input.output.datasetId !== existing.dataset_id) {
|
|
197
|
+
throw new PipelineRunError(
|
|
198
|
+
`[SixbPg] Pipeline step run '${input.id}' output dataset '${input.output.datasetId}' does not match '${existing.dataset_id}'.`
|
|
199
|
+
)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const [updated] =
|
|
203
|
+
input.status === "succeeded"
|
|
204
|
+
? await tx<PipelineStepRunDatabaseRow[]>`
|
|
205
|
+
UPDATE pipeline_step_runs
|
|
206
|
+
SET
|
|
207
|
+
status = ${input.status},
|
|
208
|
+
finished_at = ${input.finishedAt ?? new Date()},
|
|
209
|
+
output_version_id = ${input.output.versionId},
|
|
210
|
+
rows_written = ${input.rowsWritten ?? existing.rows_written ?? null},
|
|
211
|
+
error_name = ${null},
|
|
212
|
+
error_message = ${null}
|
|
213
|
+
WHERE project_id = ${input.projectId} AND id = ${input.id}
|
|
214
|
+
RETURNING *
|
|
215
|
+
`
|
|
216
|
+
: await tx<PipelineStepRunDatabaseRow[]>`
|
|
217
|
+
UPDATE pipeline_step_runs
|
|
218
|
+
SET
|
|
219
|
+
status = ${input.status},
|
|
220
|
+
finished_at = ${input.finishedAt ?? new Date()},
|
|
221
|
+
output_version_id = ${null},
|
|
222
|
+
rows_written = ${input.rowsWritten ?? existing.rows_written ?? null},
|
|
223
|
+
error_name = ${input.error?.name ?? null},
|
|
224
|
+
error_message = ${input.error?.message ?? null}
|
|
225
|
+
WHERE project_id = ${input.projectId} AND id = ${input.id}
|
|
226
|
+
RETURNING *
|
|
227
|
+
`
|
|
228
|
+
|
|
229
|
+
return rowToPipelineStepRunRecord(updated)
|
|
230
|
+
})
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
async getById(params: { projectId: string; id: string }): Promise<PipelineRunRecord | null> {
|
|
234
|
+
const [row] = await this.sql<PipelineRunDatabaseRow[]>`
|
|
235
|
+
SELECT * FROM pipeline_runs
|
|
236
|
+
WHERE project_id = ${params.projectId} AND id = ${params.id}
|
|
237
|
+
`
|
|
238
|
+
|
|
239
|
+
return row ? rowToPipelineRunRecord(row) : null
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
async list(input: ListPipelineRunsInput): Promise<ListPipelineRunsResult> {
|
|
243
|
+
if (hasEmptyStatuses(input) || input.pipelineIds?.length === 0) {
|
|
244
|
+
return {
|
|
245
|
+
runs: [],
|
|
246
|
+
hasMore: false,
|
|
247
|
+
total: 0,
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const whereClauses = ["project_id = $1"]
|
|
252
|
+
const params: SqlParameter[] = [input.projectId]
|
|
253
|
+
let index = 2
|
|
254
|
+
|
|
255
|
+
if (input.pipelineId) {
|
|
256
|
+
whereClauses.push(`pipeline_id = $${index++}`)
|
|
257
|
+
params.push(input.pipelineId)
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (input.pipelineIds) {
|
|
261
|
+
const placeholders = input.pipelineIds.map(() => `$${index++}`).join(", ")
|
|
262
|
+
whereClauses.push(`pipeline_id IN (${placeholders})`)
|
|
263
|
+
params.push(...input.pipelineIds)
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
index = appendRunListFilters(whereClauses, params, index, input)
|
|
267
|
+
|
|
268
|
+
const { rows, total, hasMore } = await queryRunList<PipelineRunDatabaseRow>({
|
|
269
|
+
sql: this.sql,
|
|
270
|
+
tableName: "pipeline_runs",
|
|
271
|
+
whereClauses,
|
|
272
|
+
params,
|
|
273
|
+
nextIndex: index,
|
|
274
|
+
order: input.order,
|
|
275
|
+
limit: input.limit,
|
|
276
|
+
offset: input.offset,
|
|
277
|
+
})
|
|
278
|
+
const runs = rows.map(rowToPipelineRunRecord)
|
|
279
|
+
|
|
280
|
+
return {
|
|
281
|
+
runs,
|
|
282
|
+
hasMore,
|
|
283
|
+
total,
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
async listLatestByPipelineIds(
|
|
288
|
+
input: ListLatestPipelineRunsInput
|
|
289
|
+
): Promise<ListLatestPipelineRunsResult> {
|
|
290
|
+
const rows = await queryLatestRunsByOwnerId<PipelineRunDatabaseRow>({
|
|
291
|
+
sql: this.sql,
|
|
292
|
+
tableName: "pipeline_runs",
|
|
293
|
+
ownerColumn: "pipeline_id",
|
|
294
|
+
ownerIds: input.pipelineIds,
|
|
295
|
+
projectId: input.projectId,
|
|
296
|
+
ownerIdFor: (row) => row.pipeline_id,
|
|
297
|
+
})
|
|
298
|
+
|
|
299
|
+
return {
|
|
300
|
+
runs: rows.map(rowToPipelineRunRecord),
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
async listSteps(input: ListPipelineStepRunsInput): Promise<ListPipelineStepRunsResult> {
|
|
305
|
+
if (hasEmptyStatuses(input)) {
|
|
306
|
+
return {
|
|
307
|
+
steps: [],
|
|
308
|
+
hasMore: false,
|
|
309
|
+
total: 0,
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const whereClauses = ["project_id = $1"]
|
|
314
|
+
const params: SqlParameter[] = [input.projectId]
|
|
315
|
+
let index = 2
|
|
316
|
+
|
|
317
|
+
if (input.pipelineRunId) {
|
|
318
|
+
whereClauses.push(`pipeline_run_id = $${index++}`)
|
|
319
|
+
params.push(input.pipelineRunId)
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
if (input.pipelineId) {
|
|
323
|
+
whereClauses.push(`pipeline_id = $${index++}`)
|
|
324
|
+
params.push(input.pipelineId)
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
if (input.stepId) {
|
|
328
|
+
whereClauses.push(`step_id = $${index++}`)
|
|
329
|
+
params.push(input.stepId)
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
if (input.datasetId) {
|
|
333
|
+
whereClauses.push(`dataset_id = $${index++}`)
|
|
334
|
+
params.push(input.datasetId)
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
index = appendRunListFilters(whereClauses, params, index, input)
|
|
338
|
+
|
|
339
|
+
const { rows, total, hasMore } = await queryRunList<PipelineStepRunDatabaseRow>({
|
|
340
|
+
sql: this.sql,
|
|
341
|
+
tableName: "pipeline_step_runs",
|
|
342
|
+
whereClauses,
|
|
343
|
+
params,
|
|
344
|
+
nextIndex: index,
|
|
345
|
+
order: input.order,
|
|
346
|
+
limit: input.limit,
|
|
347
|
+
offset: input.offset,
|
|
348
|
+
})
|
|
349
|
+
const steps = rows.map(rowToPipelineStepRunRecord)
|
|
350
|
+
|
|
351
|
+
return {
|
|
352
|
+
steps,
|
|
353
|
+
hasMore,
|
|
354
|
+
total,
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
function toFailure(row: {
|
|
360
|
+
readonly error_name: string | null
|
|
361
|
+
readonly error_message: string | null
|
|
362
|
+
}): PipelineRunFailure | undefined {
|
|
363
|
+
if (!row.error_message) {
|
|
364
|
+
return undefined
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
return {
|
|
368
|
+
name: row.error_name ?? undefined,
|
|
369
|
+
message: row.error_message,
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
function rowToPipelineRunRecord(row: PipelineRunDatabaseRow): PipelineRunRecord {
|
|
374
|
+
return {
|
|
375
|
+
id: row.id,
|
|
376
|
+
projectId: row.project_id,
|
|
377
|
+
pipelineId: row.pipeline_id,
|
|
378
|
+
status: row.status,
|
|
379
|
+
startedAt: new Date(row.started_at),
|
|
380
|
+
finishedAt: row.finished_at ? new Date(row.finished_at) : undefined,
|
|
381
|
+
output:
|
|
382
|
+
row.output_dataset_id && row.output_version_id
|
|
383
|
+
? {
|
|
384
|
+
datasetId: row.output_dataset_id,
|
|
385
|
+
versionId: row.output_version_id,
|
|
386
|
+
}
|
|
387
|
+
: undefined,
|
|
388
|
+
error: toFailure(row),
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
function rowToPipelineStepRunRecord(row: PipelineStepRunDatabaseRow): PipelineStepRunRecord {
|
|
393
|
+
return {
|
|
394
|
+
id: row.id,
|
|
395
|
+
projectId: row.project_id,
|
|
396
|
+
pipelineRunId: row.pipeline_run_id,
|
|
397
|
+
pipelineId: row.pipeline_id,
|
|
398
|
+
stepId: row.step_id,
|
|
399
|
+
datasetId: row.dataset_id,
|
|
400
|
+
mode: row.mode,
|
|
401
|
+
status: row.status,
|
|
402
|
+
startedAt: new Date(row.started_at),
|
|
403
|
+
finishedAt: row.finished_at ? new Date(row.finished_at) : undefined,
|
|
404
|
+
inputs: parseDatasetVersionRefs(row.inputs),
|
|
405
|
+
output: row.output_version_id
|
|
406
|
+
? {
|
|
407
|
+
datasetId: row.dataset_id,
|
|
408
|
+
versionId: row.output_version_id,
|
|
409
|
+
}
|
|
410
|
+
: undefined,
|
|
411
|
+
rowsWritten: row.rows_written != null ? Number(row.rows_written) : undefined,
|
|
412
|
+
error: toFailure(row),
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
function parseDatasetVersionRefs(
|
|
417
|
+
value: readonly DatasetVersionRef[] | string
|
|
418
|
+
): readonly DatasetVersionRef[] {
|
|
419
|
+
return typeof value === "string" ? (JSON.parse(value) as readonly DatasetVersionRef[]) : value
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
function assertOptionalNonNegativeInteger(value: number | undefined, fieldName: string): void {
|
|
423
|
+
if (value !== undefined && (!Number.isInteger(value) || value < 0)) {
|
|
424
|
+
throw new PipelineRunError(`[SixbPg] Pipeline run ${fieldName} must be a non-negative integer.`)
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
interface PipelineRunDatabaseRow {
|
|
429
|
+
project_id: string
|
|
430
|
+
id: string
|
|
431
|
+
pipeline_id: string
|
|
432
|
+
status: PipelineRunRecord["status"]
|
|
433
|
+
started_at: Date | string
|
|
434
|
+
finished_at: Date | string | null
|
|
435
|
+
output_dataset_id: string | null
|
|
436
|
+
output_version_id: string | null
|
|
437
|
+
error_name: string | null
|
|
438
|
+
error_message: string | null
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
interface PipelineStepRunDatabaseRow {
|
|
442
|
+
project_id: string
|
|
443
|
+
id: string
|
|
444
|
+
pipeline_run_id: string
|
|
445
|
+
pipeline_id: string
|
|
446
|
+
step_id: string
|
|
447
|
+
dataset_id: string
|
|
448
|
+
mode: PipelineStepRunRecord["mode"]
|
|
449
|
+
status: PipelineStepRunRecord["status"]
|
|
450
|
+
started_at: Date | string
|
|
451
|
+
finished_at: Date | string | null
|
|
452
|
+
inputs: readonly DatasetVersionRef[] | string
|
|
453
|
+
output_version_id: string | null
|
|
454
|
+
rows_written: number | string | null
|
|
455
|
+
error_name: string | null
|
|
456
|
+
error_message: string | null
|
|
457
|
+
}
|