@drej/postgres 0.2.0 → 0.3.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/dist/index.d.mts +24 -0
- package/dist/index.mjs +183 -0
- package/package.json +19 -4
- package/CHANGELOG.md +0 -58
- package/src/adapter.ts +0 -156
- package/src/index.ts +0 -1
- package/src/migrations.ts +0 -16
- package/tsconfig.json +0 -13
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { CheckpointInfo, EnvironmentRecord, IStorageAdapter, LedgerEntry, ListSandboxOptions, SandboxDetails } from "@drej/core";
|
|
2
|
+
|
|
3
|
+
//#region src/adapter.d.ts
|
|
4
|
+
declare class PostgresAdapter implements IStorageAdapter {
|
|
5
|
+
private readonly sql;
|
|
6
|
+
constructor(connectionString: string);
|
|
7
|
+
connect(): Promise<void>;
|
|
8
|
+
close(): Promise<void>;
|
|
9
|
+
append(entry: LedgerEntry): Promise<void>;
|
|
10
|
+
readAll(name: string, sandboxId: string): Promise<LedgerEntry[]>;
|
|
11
|
+
lastCheckpoint(name: string, sandboxId: string): Promise<LedgerEntry | null>;
|
|
12
|
+
private _aggQuery;
|
|
13
|
+
listSandboxDetails(name: string, opts?: ListSandboxOptions): Promise<SandboxDetails[]>;
|
|
14
|
+
listAllSandboxDetails(opts?: ListSandboxOptions): Promise<SandboxDetails[]>;
|
|
15
|
+
getSandboxDetails(name: string, sandboxId: string): Promise<SandboxDetails | null>;
|
|
16
|
+
deleteSandbox(name: string, sandboxId: string): Promise<void>;
|
|
17
|
+
listCheckpoints(name: string, sandboxId: string): Promise<CheckpointInfo[]>;
|
|
18
|
+
getEnvironment(name: string): Promise<EnvironmentRecord | null>;
|
|
19
|
+
saveEnvironment(record: EnvironmentRecord): Promise<void>;
|
|
20
|
+
deleteEnvironment(name: string): Promise<void>;
|
|
21
|
+
listEnvironments(): Promise<EnvironmentRecord[]>;
|
|
22
|
+
}
|
|
23
|
+
//#endregion
|
|
24
|
+
export { PostgresAdapter };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import postgres from "postgres";
|
|
2
|
+
import { SandboxStatus } from "@drej/core";
|
|
3
|
+
//#region src/migrations.ts
|
|
4
|
+
const MIGRATION_SQL = `
|
|
5
|
+
CREATE TABLE IF NOT EXISTS drej_events (
|
|
6
|
+
id BIGSERIAL PRIMARY KEY,
|
|
7
|
+
sandbox_id TEXT NOT NULL,
|
|
8
|
+
name TEXT NOT NULL,
|
|
9
|
+
step_idx INTEGER NOT NULL,
|
|
10
|
+
branch INTEGER,
|
|
11
|
+
event TEXT NOT NULL,
|
|
12
|
+
payload JSONB,
|
|
13
|
+
error TEXT,
|
|
14
|
+
ts BIGINT NOT NULL
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
CREATE INDEX IF NOT EXISTS drej_events_sandbox_id ON drej_events(sandbox_id);
|
|
18
|
+
CREATE INDEX IF NOT EXISTS drej_events_name ON drej_events(name);
|
|
19
|
+
|
|
20
|
+
CREATE TABLE IF NOT EXISTS drej_environments (
|
|
21
|
+
name TEXT PRIMARY KEY,
|
|
22
|
+
snapshot_id TEXT NOT NULL,
|
|
23
|
+
image TEXT NOT NULL,
|
|
24
|
+
built_at BIGINT NOT NULL
|
|
25
|
+
);
|
|
26
|
+
`;
|
|
27
|
+
//#endregion
|
|
28
|
+
//#region src/adapter.ts
|
|
29
|
+
function aggRowToDetails(row) {
|
|
30
|
+
return {
|
|
31
|
+
name: row.name,
|
|
32
|
+
sandboxId: row.sandbox_id,
|
|
33
|
+
status: Number(row.is_closed) ? SandboxStatus.Completed : SandboxStatus.Running,
|
|
34
|
+
startedAt: Number(row.started_at),
|
|
35
|
+
completedAt: row.completed_at != null ? Number(row.completed_at) : void 0,
|
|
36
|
+
execCount: Number(row.exec_count)
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function applyOpts(details, opts) {
|
|
40
|
+
let result = details;
|
|
41
|
+
if (opts?.before != null) result = result.filter((d) => d.startedAt < opts.before);
|
|
42
|
+
if (opts?.status != null) result = result.filter((d) => d.status === opts.status);
|
|
43
|
+
if (opts?.limit != null) result = result.slice(0, opts.limit);
|
|
44
|
+
return result;
|
|
45
|
+
}
|
|
46
|
+
function rowToEntry(row) {
|
|
47
|
+
return {
|
|
48
|
+
sandboxId: row.sandbox_id,
|
|
49
|
+
name: row.name,
|
|
50
|
+
stepIndex: row.step_idx,
|
|
51
|
+
branch: row.branch ?? void 0,
|
|
52
|
+
event: row.event,
|
|
53
|
+
payload: row.payload ?? void 0,
|
|
54
|
+
error: row.error ?? void 0,
|
|
55
|
+
ts: Number(row.ts)
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
var PostgresAdapter = class {
|
|
59
|
+
sql;
|
|
60
|
+
constructor(connectionString) {
|
|
61
|
+
this.sql = postgres(connectionString);
|
|
62
|
+
}
|
|
63
|
+
async connect() {
|
|
64
|
+
await this.sql.unsafe(MIGRATION_SQL);
|
|
65
|
+
}
|
|
66
|
+
async close() {
|
|
67
|
+
await this.sql.end();
|
|
68
|
+
}
|
|
69
|
+
async append(entry) {
|
|
70
|
+
await this.sql`
|
|
71
|
+
INSERT INTO drej_events (sandbox_id, name, step_idx, branch, event, payload, error, ts)
|
|
72
|
+
VALUES (
|
|
73
|
+
${entry.sandboxId},
|
|
74
|
+
${entry.name},
|
|
75
|
+
${entry.stepIndex},
|
|
76
|
+
${entry.branch ?? null},
|
|
77
|
+
${entry.event},
|
|
78
|
+
${entry.payload !== void 0 ? JSON.stringify(entry.payload) : null},
|
|
79
|
+
${entry.error ?? null},
|
|
80
|
+
${entry.ts}
|
|
81
|
+
)
|
|
82
|
+
`;
|
|
83
|
+
}
|
|
84
|
+
async readAll(name, sandboxId) {
|
|
85
|
+
return (await this.sql`
|
|
86
|
+
SELECT sandbox_id, name, step_idx, branch, event, payload, error, ts
|
|
87
|
+
FROM drej_events
|
|
88
|
+
WHERE name = ${name} AND sandbox_id = ${sandboxId}
|
|
89
|
+
ORDER BY ts ASC
|
|
90
|
+
`).map(rowToEntry);
|
|
91
|
+
}
|
|
92
|
+
async lastCheckpoint(name, sandboxId) {
|
|
93
|
+
const rows = await this.sql`
|
|
94
|
+
SELECT sandbox_id, name, step_idx, branch, event, payload, error, ts
|
|
95
|
+
FROM drej_events
|
|
96
|
+
WHERE name = ${name} AND sandbox_id = ${sandboxId} AND event = 'checkpoint_created'
|
|
97
|
+
ORDER BY ts DESC
|
|
98
|
+
LIMIT 1
|
|
99
|
+
`;
|
|
100
|
+
return rows.length ? rowToEntry(rows[0]) : null;
|
|
101
|
+
}
|
|
102
|
+
async _aggQuery(whereClause, params) {
|
|
103
|
+
return this.sql.unsafe(`WITH agg AS (
|
|
104
|
+
SELECT
|
|
105
|
+
name,
|
|
106
|
+
sandbox_id,
|
|
107
|
+
MIN(CASE WHEN event = 'sandbox_created' THEN ts END) AS started_at,
|
|
108
|
+
MAX(CASE WHEN event = 'sandbox_closed' THEN ts END) AS completed_at,
|
|
109
|
+
MAX(CASE WHEN event = 'sandbox_closed' THEN 1 ELSE 0 END)::int AS is_closed,
|
|
110
|
+
COUNT(CASE WHEN event = 'exec_complete' THEN 1 END)::int AS exec_count
|
|
111
|
+
FROM drej_events
|
|
112
|
+
${whereClause}
|
|
113
|
+
GROUP BY name, sandbox_id
|
|
114
|
+
)
|
|
115
|
+
SELECT * FROM agg WHERE started_at IS NOT NULL ORDER BY started_at DESC`, params);
|
|
116
|
+
}
|
|
117
|
+
async listSandboxDetails(name, opts) {
|
|
118
|
+
return applyOpts((await this._aggQuery("WHERE name = $1", [name])).map(aggRowToDetails), opts);
|
|
119
|
+
}
|
|
120
|
+
async listAllSandboxDetails(opts) {
|
|
121
|
+
return applyOpts((await this._aggQuery("", [])).map(aggRowToDetails), opts);
|
|
122
|
+
}
|
|
123
|
+
async getSandboxDetails(name, sandboxId) {
|
|
124
|
+
const rows = await this._aggQuery("WHERE name = $1 AND sandbox_id = $2", [name, sandboxId]);
|
|
125
|
+
return rows.length ? aggRowToDetails(rows[0]) : null;
|
|
126
|
+
}
|
|
127
|
+
async deleteSandbox(name, sandboxId) {
|
|
128
|
+
await this.sql`DELETE FROM drej_events WHERE name = ${name} AND sandbox_id = ${sandboxId}`;
|
|
129
|
+
}
|
|
130
|
+
async listCheckpoints(name, sandboxId) {
|
|
131
|
+
return (await this.sql`
|
|
132
|
+
SELECT sandbox_id, name, step_idx, branch, event, payload, error, ts
|
|
133
|
+
FROM drej_events
|
|
134
|
+
WHERE name = ${name} AND sandbox_id = ${sandboxId} AND event = 'checkpoint_created'
|
|
135
|
+
ORDER BY ts ASC
|
|
136
|
+
`).map((r) => {
|
|
137
|
+
const p = r.payload ?? {};
|
|
138
|
+
return {
|
|
139
|
+
snapshotId: p.snapshotId,
|
|
140
|
+
tag: p.name,
|
|
141
|
+
createdAt: Number(r.ts)
|
|
142
|
+
};
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
async getEnvironment(name) {
|
|
146
|
+
const rows = await this.sql`
|
|
147
|
+
SELECT name, snapshot_id, image, built_at FROM drej_environments WHERE name = ${name}
|
|
148
|
+
`;
|
|
149
|
+
if (!rows.length) return null;
|
|
150
|
+
const r = rows[0];
|
|
151
|
+
return {
|
|
152
|
+
name: r.name,
|
|
153
|
+
snapshotId: r.snapshot_id,
|
|
154
|
+
image: r.image,
|
|
155
|
+
builtAt: Number(r.built_at)
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
async saveEnvironment(record) {
|
|
159
|
+
await this.sql`
|
|
160
|
+
INSERT INTO drej_environments (name, snapshot_id, image, built_at)
|
|
161
|
+
VALUES (${record.name}, ${record.snapshotId}, ${record.image}, ${record.builtAt})
|
|
162
|
+
ON CONFLICT (name) DO UPDATE
|
|
163
|
+
SET snapshot_id = excluded.snapshot_id,
|
|
164
|
+
image = excluded.image,
|
|
165
|
+
built_at = excluded.built_at
|
|
166
|
+
`;
|
|
167
|
+
}
|
|
168
|
+
async deleteEnvironment(name) {
|
|
169
|
+
await this.sql`DELETE FROM drej_environments WHERE name = ${name}`;
|
|
170
|
+
}
|
|
171
|
+
async listEnvironments() {
|
|
172
|
+
return (await this.sql`
|
|
173
|
+
SELECT name, snapshot_id, image, built_at FROM drej_environments ORDER BY built_at DESC
|
|
174
|
+
`).map((r) => ({
|
|
175
|
+
name: r.name,
|
|
176
|
+
snapshotId: r.snapshot_id,
|
|
177
|
+
image: r.image,
|
|
178
|
+
builtAt: Number(r.built_at)
|
|
179
|
+
}));
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
//#endregion
|
|
183
|
+
export { PostgresAdapter };
|
package/package.json
CHANGED
|
@@ -1,16 +1,31 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@drej/postgres",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"files": [
|
|
5
|
+
"dist"
|
|
6
|
+
],
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "./dist/index.mjs",
|
|
9
|
+
"types": "./dist/index.d.mts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"import": "./dist/index.mjs",
|
|
13
|
+
"types": "./dist/index.d.mts"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
4
16
|
"publishConfig": {
|
|
5
17
|
"access": "public"
|
|
6
18
|
},
|
|
7
|
-
"
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsdown"
|
|
21
|
+
},
|
|
8
22
|
"dependencies": {
|
|
9
|
-
"
|
|
10
|
-
"
|
|
23
|
+
"@drej/core": "workspace:*",
|
|
24
|
+
"postgres": "3.4.9"
|
|
11
25
|
},
|
|
12
26
|
"devDependencies": {
|
|
13
27
|
"bun-types": "1.3.14",
|
|
28
|
+
"tsdown": "0.22.3",
|
|
14
29
|
"typescript": "6.0.3"
|
|
15
30
|
}
|
|
16
31
|
}
|
package/CHANGELOG.md
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
# @drej/postgres
|
|
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
|
-
|
|
20
|
-
## 0.1.2
|
|
21
|
-
|
|
22
|
-
### Patch Changes
|
|
23
|
-
|
|
24
|
-
- Updated dependencies [4c0ad93]
|
|
25
|
-
- Updated dependencies [b04f8eb]
|
|
26
|
-
- Updated dependencies [a971b7b]
|
|
27
|
-
- Updated dependencies [ce173be]
|
|
28
|
-
- Updated dependencies [86c2dde]
|
|
29
|
-
- Updated dependencies [82094ae]
|
|
30
|
-
- @drej/core@0.2.0
|
|
31
|
-
|
|
32
|
-
## 0.1.1
|
|
33
|
-
|
|
34
|
-
### Patch Changes
|
|
35
|
-
|
|
36
|
-
- 0ea4c33: Rename npm scope from `@drej/*` to `@drej/*` and add TSDoc to all public API surfaces.
|
|
37
|
-
|
|
38
|
-
- All workspace packages now published under `@drej/*` (e.g. `@drej/sqlite`, `@drej/postgres`)
|
|
39
|
-
- `DrejClient`, `WorkflowBuilder`, `SandboxStepBuilder`, `IStorageAdapter`, `LedgerEvent`, `SandboxOpts` and all their members now have hover documentation visible in VS Code
|
|
40
|
-
|
|
41
|
-
- Updated dependencies [0ea4c33]
|
|
42
|
-
- @drej/core@0.1.1
|
|
43
|
-
|
|
44
|
-
## 0.1.0
|
|
45
|
-
|
|
46
|
-
### Minor Changes
|
|
47
|
-
|
|
48
|
-
- 82e77fd: Introduce pluggable storage adapter system.
|
|
49
|
-
|
|
50
|
-
- `ILedger` renamed to `IStorageAdapter` with optional `connect()` and `close()` lifecycle methods
|
|
51
|
-
- `DrejClientOptions.adapter` accepts any `IStorageAdapter` implementation; `DrejClient` exposes matching `connect()` and `close()` methods
|
|
52
|
-
- New `@drej/postgres` package: `PostgresAdapter` backed by a user-supplied Postgres connection string; owns its schema and runs migrations on `connect()`
|
|
53
|
-
|
|
54
|
-
### Patch Changes
|
|
55
|
-
|
|
56
|
-
- Updated dependencies [82e77fd]
|
|
57
|
-
- Updated dependencies [5d77498]
|
|
58
|
-
- @drej/core@0.1.0
|
package/src/adapter.ts
DELETED
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
import postgres from "postgres";
|
|
2
|
-
import type { IStorageAdapter, LedgerEntry, LedgerEvent, RunDetails, ListRunsOptions } from "@drej/core";
|
|
3
|
-
import { RunStatus } from "@drej/core";
|
|
4
|
-
import { MIGRATION_SQL } from "./migrations";
|
|
5
|
-
|
|
6
|
-
type Row = {
|
|
7
|
-
run_id: string;
|
|
8
|
-
wf_name: string;
|
|
9
|
-
step_idx: number;
|
|
10
|
-
branch: number | null;
|
|
11
|
-
event: string;
|
|
12
|
-
payload: unknown;
|
|
13
|
-
error: string | null;
|
|
14
|
-
ts: string;
|
|
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
|
-
|
|
53
|
-
function rowToEntry(row: Row): LedgerEntry {
|
|
54
|
-
return {
|
|
55
|
-
runId: row.run_id,
|
|
56
|
-
workflowName: row.wf_name,
|
|
57
|
-
stepIndex: row.step_idx,
|
|
58
|
-
branch: row.branch ?? undefined,
|
|
59
|
-
event: row.event as LedgerEvent,
|
|
60
|
-
payload: row.payload ?? undefined,
|
|
61
|
-
error: row.error ?? undefined,
|
|
62
|
-
ts: Number(row.ts),
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export class PostgresAdapter implements IStorageAdapter {
|
|
67
|
-
private readonly sql: ReturnType<typeof postgres>;
|
|
68
|
-
|
|
69
|
-
constructor(connectionString: string) {
|
|
70
|
-
this.sql = postgres(connectionString);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
async connect(): Promise<void> {
|
|
74
|
-
await this.sql.unsafe(MIGRATION_SQL);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
async close(): Promise<void> {
|
|
78
|
-
await this.sql.end();
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
async append(entry: LedgerEntry): Promise<void> {
|
|
82
|
-
await this.sql`
|
|
83
|
-
INSERT INTO drej_events (run_id, wf_name, step_idx, branch, event, payload, error, ts)
|
|
84
|
-
VALUES (
|
|
85
|
-
${entry.runId},
|
|
86
|
-
${entry.workflowName},
|
|
87
|
-
${entry.stepIndex},
|
|
88
|
-
${entry.branch ?? null},
|
|
89
|
-
${entry.event},
|
|
90
|
-
${entry.payload !== undefined ? JSON.stringify(entry.payload) : null},
|
|
91
|
-
${entry.error ?? null},
|
|
92
|
-
${entry.ts}
|
|
93
|
-
)
|
|
94
|
-
`;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
async readAll(workflowName: string, runId: string): Promise<LedgerEntry[]> {
|
|
98
|
-
const rows = await this.sql<Row[]>`
|
|
99
|
-
SELECT run_id, wf_name, step_idx, branch, event, payload, error, ts
|
|
100
|
-
FROM drej_events
|
|
101
|
-
WHERE wf_name = ${workflowName} AND run_id = ${runId}
|
|
102
|
-
ORDER BY ts ASC
|
|
103
|
-
`;
|
|
104
|
-
return rows.map(rowToEntry);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
async lastCheckpoint(workflowName: string, runId: string): Promise<LedgerEntry | null> {
|
|
108
|
-
const rows = await this.sql<Row[]>`
|
|
109
|
-
SELECT run_id, wf_name, step_idx, branch, event, payload, error, ts
|
|
110
|
-
FROM drej_events
|
|
111
|
-
WHERE wf_name = ${workflowName} AND run_id = ${runId} AND event = 'checkpoint'
|
|
112
|
-
ORDER BY ts DESC
|
|
113
|
-
LIMIT 1
|
|
114
|
-
`;
|
|
115
|
-
return rows.length ? rowToEntry(rows[0]) : null;
|
|
116
|
-
}
|
|
117
|
-
|
|
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}`;
|
|
155
|
-
}
|
|
156
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { PostgresAdapter } from "./adapter";
|
package/src/migrations.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
export const MIGRATION_SQL = `
|
|
2
|
-
CREATE TABLE IF NOT EXISTS drej_events (
|
|
3
|
-
id BIGSERIAL PRIMARY KEY,
|
|
4
|
-
run_id TEXT NOT NULL,
|
|
5
|
-
wf_name TEXT NOT NULL,
|
|
6
|
-
step_idx INTEGER NOT NULL,
|
|
7
|
-
branch INTEGER,
|
|
8
|
-
event TEXT NOT NULL,
|
|
9
|
-
payload JSONB,
|
|
10
|
-
error TEXT,
|
|
11
|
-
ts BIGINT NOT NULL
|
|
12
|
-
);
|
|
13
|
-
|
|
14
|
-
CREATE INDEX IF NOT EXISTS drej_events_run_id ON drej_events(run_id);
|
|
15
|
-
CREATE INDEX IF NOT EXISTS drej_events_wf_name ON drej_events(wf_name);
|
|
16
|
-
`;
|
package/tsconfig.json
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ESNext",
|
|
4
|
-
"module": "ESNext",
|
|
5
|
-
"moduleResolution": "bundler",
|
|
6
|
-
"strict": true,
|
|
7
|
-
"noEmit": true,
|
|
8
|
-
"skipLibCheck": true,
|
|
9
|
-
"allowImportingTsExtensions": true,
|
|
10
|
-
"types": ["bun-types"]
|
|
11
|
-
},
|
|
12
|
-
"include": ["src"]
|
|
13
|
-
}
|