@drej/postgres 0.1.2 → 0.2.0
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/CHANGELOG.md +17 -0
- package/package.json +7 -5
- package/src/adapter.ts +75 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# @drej/postgres
|
|
2
2
|
|
|
3
|
+
## 0.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 2fd33e0: feat: run management API
|
|
8
|
+
|
|
9
|
+
Add `RunStatus` enum, `RunDetails` type, and `ListRunsOptions` for filtering. Replace `listRuns()` with `listRunDetails()`, `listAllRunDetails()`, `getRunDetails()`, and `deleteRun()` on both `IStorageAdapter` and `DrejClient`. Add `WorkflowRun.status` property that tracks execution state as events are consumed.
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- Updated dependencies [22b8a32]
|
|
14
|
+
- Updated dependencies [799b6dd]
|
|
15
|
+
- Updated dependencies [8d9d8bb]
|
|
16
|
+
- Updated dependencies [2fd33e0]
|
|
17
|
+
- Updated dependencies [0d94c2a]
|
|
18
|
+
- @drej/core@0.3.0
|
|
19
|
+
|
|
3
20
|
## 0.1.2
|
|
4
21
|
|
|
5
22
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@drej/postgres",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"publishConfig": {
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"publishConfig": {
|
|
5
|
+
"access": "public"
|
|
6
|
+
},
|
|
5
7
|
"main": "./src/index.ts",
|
|
6
8
|
"dependencies": {
|
|
7
|
-
"postgres": "
|
|
9
|
+
"postgres": "3.4.9",
|
|
8
10
|
"@drej/core": "workspace:*"
|
|
9
11
|
},
|
|
10
12
|
"devDependencies": {
|
|
11
|
-
"bun-types": "
|
|
12
|
-
"typescript": "
|
|
13
|
+
"bun-types": "1.3.14",
|
|
14
|
+
"typescript": "6.0.3"
|
|
13
15
|
}
|
|
14
16
|
}
|
package/src/adapter.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import postgres from "postgres";
|
|
2
|
-
import type { IStorageAdapter, LedgerEntry, LedgerEvent } from "@drej/core";
|
|
2
|
+
import type { IStorageAdapter, LedgerEntry, LedgerEvent, RunDetails, ListRunsOptions } from "@drej/core";
|
|
3
|
+
import { RunStatus } from "@drej/core";
|
|
3
4
|
import { MIGRATION_SQL } from "./migrations";
|
|
4
5
|
|
|
5
6
|
type Row = {
|
|
@@ -13,6 +14,42 @@ type Row = {
|
|
|
13
14
|
ts: string;
|
|
14
15
|
};
|
|
15
16
|
|
|
17
|
+
type AggRow = {
|
|
18
|
+
wf_name: string;
|
|
19
|
+
run_id: string;
|
|
20
|
+
started_at: string | null;
|
|
21
|
+
completed_at: string | null;
|
|
22
|
+
terminal_event: string | null;
|
|
23
|
+
error_msg: string | null;
|
|
24
|
+
step_count: string;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
function terminalToStatus(event: string | null): RunStatus {
|
|
28
|
+
if (event === "workflow_complete") return RunStatus.Completed;
|
|
29
|
+
if (event === "workflow_failed") return RunStatus.Failed;
|
|
30
|
+
return RunStatus.Running;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function aggRowToDetails(row: AggRow): RunDetails {
|
|
34
|
+
return {
|
|
35
|
+
workflowName: row.wf_name,
|
|
36
|
+
runId: row.run_id,
|
|
37
|
+
status: terminalToStatus(row.terminal_event),
|
|
38
|
+
startedAt: Number(row.started_at),
|
|
39
|
+
completedAt: row.completed_at != null ? Number(row.completed_at) : undefined,
|
|
40
|
+
stepCount: Number(row.step_count),
|
|
41
|
+
error: row.error_msg ?? undefined,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function applyOpts(details: RunDetails[], opts?: ListRunsOptions): RunDetails[] {
|
|
46
|
+
let result = details;
|
|
47
|
+
if (opts?.before != null) result = result.filter((d) => d.startedAt < opts.before!);
|
|
48
|
+
if (opts?.status != null) result = result.filter((d) => d.status === opts.status);
|
|
49
|
+
if (opts?.limit != null) result = result.slice(0, opts.limit);
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
|
|
16
53
|
function rowToEntry(row: Row): LedgerEntry {
|
|
17
54
|
return {
|
|
18
55
|
runId: row.run_id,
|
|
@@ -78,10 +115,42 @@ export class PostgresAdapter implements IStorageAdapter {
|
|
|
78
115
|
return rows.length ? rowToEntry(rows[0]) : null;
|
|
79
116
|
}
|
|
80
117
|
|
|
81
|
-
async
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
118
|
+
private async _aggQuery(whereClause: string, params: string[]): Promise<AggRow[]> {
|
|
119
|
+
return this.sql.unsafe<AggRow[]>(
|
|
120
|
+
`WITH agg AS (
|
|
121
|
+
SELECT
|
|
122
|
+
wf_name,
|
|
123
|
+
run_id,
|
|
124
|
+
MIN(CASE WHEN event = 'run_started' THEN ts END) AS started_at,
|
|
125
|
+
MAX(CASE WHEN event IN ('workflow_complete', 'workflow_failed') THEN ts END) AS completed_at,
|
|
126
|
+
MAX(CASE WHEN event IN ('workflow_complete', 'workflow_failed') THEN event END) AS terminal_event,
|
|
127
|
+
MAX(CASE WHEN event = 'workflow_failed' THEN error END) AS error_msg,
|
|
128
|
+
COUNT(CASE WHEN event = 'step_complete' THEN 1 END)::int AS step_count
|
|
129
|
+
FROM drej_events
|
|
130
|
+
${whereClause}
|
|
131
|
+
GROUP BY wf_name, run_id
|
|
132
|
+
)
|
|
133
|
+
SELECT * FROM agg WHERE started_at IS NOT NULL ORDER BY started_at DESC`,
|
|
134
|
+
params,
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async listRunDetails(workflowName: string, opts?: ListRunsOptions): Promise<RunDetails[]> {
|
|
139
|
+
const rows = await this._aggQuery("WHERE wf_name = $1", [workflowName]);
|
|
140
|
+
return applyOpts(rows.map(aggRowToDetails), opts);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async listAllRunDetails(opts?: ListRunsOptions): Promise<RunDetails[]> {
|
|
144
|
+
const rows = await this._aggQuery("", []);
|
|
145
|
+
return applyOpts(rows.map(aggRowToDetails), opts);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async getRunDetails(workflowName: string, runId: string): Promise<RunDetails | null> {
|
|
149
|
+
const rows = await this._aggQuery("WHERE wf_name = $1 AND run_id = $2", [workflowName, runId]);
|
|
150
|
+
return rows.length ? aggRowToDetails(rows[0]) : null;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async deleteRun(workflowName: string, runId: string): Promise<void> {
|
|
154
|
+
await this.sql`DELETE FROM drej_events WHERE wf_name = ${workflowName} AND run_id = ${runId}`;
|
|
86
155
|
}
|
|
87
156
|
}
|