@evalstudio/postgres 0.4.0 → 0.5.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/README.md +33 -11
- package/dist/index.d.ts +11 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -1
- package/dist/index.js.map +1 -1
- package/dist/migrations.d.ts +17 -0
- package/dist/migrations.d.ts.map +1 -0
- package/dist/migrations.js +88 -0
- package/dist/migrations.js.map +1 -0
- package/dist/migrator.d.ts +23 -0
- package/dist/migrator.d.ts.map +1 -0
- package/dist/migrator.js +75 -0
- package/dist/migrator.js.map +1 -0
- package/dist/schema.d.ts +4 -3
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +11 -81
- package/dist/schema.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@ npm init -y
|
|
|
17
17
|
### 2. Install dependencies
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
npm install @evalstudio/cli @evalstudio/postgres
|
|
20
|
+
npm install @evalstudio/cli @evalstudio/postgres dotenv-cli
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
### 3. Initialize the project
|
|
@@ -28,7 +28,13 @@ npx evalstudio init
|
|
|
28
28
|
|
|
29
29
|
This creates an `evalstudio.config.json` in the current directory.
|
|
30
30
|
|
|
31
|
-
### 4.
|
|
31
|
+
### 4. Create a `.env` file
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
EVALSTUDIO_DATABASE_URL=postgresql://user:pass@localhost:5432/evalstudio
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### 5. Configure PostgreSQL storage
|
|
32
38
|
|
|
33
39
|
Edit `evalstudio.config.json` to use Postgres:
|
|
34
40
|
|
|
@@ -52,31 +58,33 @@ Edit `evalstudio.config.json` to use Postgres:
|
|
|
52
58
|
|
|
53
59
|
The `connectionString` supports `${VAR}` placeholders that resolve from environment variables at runtime. If `connectionString` is omitted entirely, it falls back to the `EVALSTUDIO_DATABASE_URL` environment variable.
|
|
54
60
|
|
|
55
|
-
###
|
|
61
|
+
### 6. Add scripts
|
|
56
62
|
|
|
57
63
|
Update your `package.json`:
|
|
58
64
|
|
|
59
65
|
```json
|
|
60
66
|
{
|
|
61
67
|
"scripts": {
|
|
62
|
-
"start": "evalstudio serve",
|
|
63
|
-
"db:init": "evalstudio db init"
|
|
68
|
+
"start": "dotenv -- evalstudio serve",
|
|
69
|
+
"db:init": "dotenv -- evalstudio db init"
|
|
64
70
|
},
|
|
65
71
|
"dependencies": {
|
|
66
72
|
"@evalstudio/cli": "latest",
|
|
67
|
-
"@evalstudio/postgres": "latest"
|
|
73
|
+
"@evalstudio/postgres": "latest",
|
|
74
|
+
"dotenv-cli": "latest"
|
|
68
75
|
}
|
|
69
76
|
}
|
|
70
77
|
```
|
|
71
78
|
|
|
72
|
-
|
|
79
|
+
The `dotenv --` prefix loads variables from `.env` before running the command, so the `${EVALSTUDIO_DATABASE_URL}` placeholder in the config resolves correctly.
|
|
80
|
+
|
|
81
|
+
### 7. Initialize the database
|
|
73
82
|
|
|
74
83
|
```bash
|
|
75
|
-
export EVALSTUDIO_DATABASE_URL="postgresql://user:pass@localhost:5432/evalstudio"
|
|
76
84
|
npm run db:init
|
|
77
85
|
```
|
|
78
86
|
|
|
79
|
-
###
|
|
87
|
+
### 8. Start the server
|
|
80
88
|
|
|
81
89
|
```bash
|
|
82
90
|
npm start
|
|
@@ -111,7 +119,7 @@ docker run -p 3000:3000 \
|
|
|
111
119
|
evalstudio-server
|
|
112
120
|
```
|
|
113
121
|
|
|
114
|
-
`db:init` is idempotent — it's safe to run on every container start.
|
|
122
|
+
`db:init` is idempotent — it's safe to run on every container start. Only pending migrations are applied; already-applied ones are skipped.
|
|
115
123
|
|
|
116
124
|
## How It Works
|
|
117
125
|
|
|
@@ -119,6 +127,16 @@ When `storage.type` is set to `"postgres"` in your config, `@evalstudio/core` dy
|
|
|
119
127
|
|
|
120
128
|
If the package is not installed, you'll get a clear error message telling you to add it.
|
|
121
129
|
|
|
130
|
+
### Migrations
|
|
131
|
+
|
|
132
|
+
Schema changes are managed via version-stamped SQL migrations. A `schema_migrations` table tracks which migrations have been applied. Each migration runs in its own transaction — if one fails, previously applied migrations remain committed.
|
|
133
|
+
|
|
134
|
+
To check migration status:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
evalstudio db status
|
|
138
|
+
```
|
|
139
|
+
|
|
122
140
|
## API
|
|
123
141
|
|
|
124
142
|
### `createPostgresStorage(connectionString: string): Promise<StorageProvider>`
|
|
@@ -127,7 +145,11 @@ Creates a PostgreSQL-backed storage provider. The database schema must already e
|
|
|
127
145
|
|
|
128
146
|
### `initSchema(connectionString: string): Promise<void>`
|
|
129
147
|
|
|
130
|
-
|
|
148
|
+
Runs all pending database migrations. Used internally by the `evalstudio db init` CLI command.
|
|
149
|
+
|
|
150
|
+
### `getMigrationStatus(connectionString: string): Promise<MigrationStatus>`
|
|
151
|
+
|
|
152
|
+
Returns applied and pending migrations. Used internally by `evalstudio db status`.
|
|
131
153
|
|
|
132
154
|
## License
|
|
133
155
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { StorageProvider } from "@evalstudio/core";
|
|
2
|
+
import { type MigrationStatus } from "./migrator.js";
|
|
2
3
|
/**
|
|
3
4
|
* Creates a PostgreSQL-backed StorageProvider.
|
|
4
5
|
*
|
|
@@ -10,10 +11,19 @@ import type { StorageProvider } from "@evalstudio/core";
|
|
|
10
11
|
*/
|
|
11
12
|
export declare function createPostgresStorage(connectionString: string): Promise<StorageProvider>;
|
|
12
13
|
/**
|
|
13
|
-
*
|
|
14
|
+
* Runs all pending database migrations.
|
|
14
15
|
* Used by the `evalstudio db init` CLI command.
|
|
16
|
+
* Safe to call on every startup — already-applied migrations are skipped.
|
|
15
17
|
*
|
|
16
18
|
* @param connectionString - PostgreSQL connection string
|
|
17
19
|
*/
|
|
18
20
|
export declare function initSchema(connectionString: string): Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* Returns applied and pending migration status.
|
|
23
|
+
* Used by the `evalstudio db status` CLI command.
|
|
24
|
+
*
|
|
25
|
+
* @param connectionString - PostgreSQL connection string
|
|
26
|
+
*/
|
|
27
|
+
export declare function getMigrationStatus(connectionString: string): Promise<MigrationStatus>;
|
|
28
|
+
export type { MigrationStatus };
|
|
19
29
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAIxD,OAAO,EAAgD,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AAEnG;;;;;;;;GAQG;AACH,wBAAsB,qBAAqB,CAAC,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAQ9F;AAED;;;;;;GAMG;AACH,wBAAsB,UAAU,CAAC,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAOxE;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CAAC,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAO3F;AAED,YAAY,EAAE,eAAe,EAAE,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createPool } from "./pool.js";
|
|
2
2
|
import { createPostgresStorageProvider } from "./postgres-storage.js";
|
|
3
3
|
import { initSchema as initSchemaImpl } from "./schema.js";
|
|
4
|
+
import { getMigrationStatus as getMigrationStatusImpl } from "./migrator.js";
|
|
4
5
|
/**
|
|
5
6
|
* Creates a PostgreSQL-backed StorageProvider.
|
|
6
7
|
*
|
|
@@ -18,8 +19,9 @@ export async function createPostgresStorage(connectionString) {
|
|
|
18
19
|
return createPostgresStorageProvider(pool);
|
|
19
20
|
}
|
|
20
21
|
/**
|
|
21
|
-
*
|
|
22
|
+
* Runs all pending database migrations.
|
|
22
23
|
* Used by the `evalstudio db init` CLI command.
|
|
24
|
+
* Safe to call on every startup — already-applied migrations are skipped.
|
|
23
25
|
*
|
|
24
26
|
* @param connectionString - PostgreSQL connection string
|
|
25
27
|
*/
|
|
@@ -32,4 +34,19 @@ export async function initSchema(connectionString) {
|
|
|
32
34
|
await pool.end();
|
|
33
35
|
}
|
|
34
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* Returns applied and pending migration status.
|
|
39
|
+
* Used by the `evalstudio db status` CLI command.
|
|
40
|
+
*
|
|
41
|
+
* @param connectionString - PostgreSQL connection string
|
|
42
|
+
*/
|
|
43
|
+
export async function getMigrationStatus(connectionString) {
|
|
44
|
+
const pool = createPool(connectionString);
|
|
45
|
+
try {
|
|
46
|
+
return await getMigrationStatusImpl(pool);
|
|
47
|
+
}
|
|
48
|
+
finally {
|
|
49
|
+
await pool.end();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
35
52
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,6BAA6B,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,EAAE,UAAU,IAAI,cAAc,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,6BAA6B,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,EAAE,UAAU,IAAI,cAAc,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,EAAE,kBAAkB,IAAI,sBAAsB,EAAwB,MAAM,eAAe,CAAC;AAEnG;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,gBAAwB;IAClE,MAAM,IAAI,GAAG,UAAU,CAAC,gBAAgB,CAAC,CAAC;IAE1C,mEAAmE;IACnE,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;IACpC,MAAM,CAAC,OAAO,EAAE,CAAC;IAEjB,OAAO,6BAA6B,CAAC,IAAI,CAAC,CAAC;AAC7C,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,gBAAwB;IACvD,MAAM,IAAI,GAAG,UAAU,CAAC,gBAAgB,CAAC,CAAC;IAC1C,IAAI,CAAC;QACH,MAAM,cAAc,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;YAAS,CAAC;QACT,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC;IACnB,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,gBAAwB;IAC/D,MAAM,IAAI,GAAG,UAAU,CAAC,gBAAgB,CAAC,CAAC;IAC1C,IAAI,CAAC;QACH,OAAO,MAAM,sBAAsB,CAAC,IAAI,CAAC,CAAC;IAC5C,CAAC;YAAS,CAAC;QACT,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC;IACnB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Migration registry for EvalStudio PostgreSQL storage.
|
|
3
|
+
*
|
|
4
|
+
* Each migration is a versioned SQL string that runs in a transaction.
|
|
5
|
+
* Migrations are forward-only and immutable once shipped — never edit
|
|
6
|
+
* an existing migration. To make changes, add a new one.
|
|
7
|
+
*
|
|
8
|
+
* Naming convention: NNN_descriptive_name (e.g., 001_initial)
|
|
9
|
+
* The `version` integer is what the system uses; the `name` is for humans.
|
|
10
|
+
*/
|
|
11
|
+
export interface Migration {
|
|
12
|
+
version: number;
|
|
13
|
+
name: string;
|
|
14
|
+
sql: string;
|
|
15
|
+
}
|
|
16
|
+
export declare const ALL_MIGRATIONS: Migration[];
|
|
17
|
+
//# sourceMappingURL=migrations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrations.d.ts","sourceRoot":"","sources":["../src/migrations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAED,eAAO,MAAM,cAAc,EAAE,SAAS,EA4ErC,CAAC"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Migration registry for EvalStudio PostgreSQL storage.
|
|
3
|
+
*
|
|
4
|
+
* Each migration is a versioned SQL string that runs in a transaction.
|
|
5
|
+
* Migrations are forward-only and immutable once shipped — never edit
|
|
6
|
+
* an existing migration. To make changes, add a new one.
|
|
7
|
+
*
|
|
8
|
+
* Naming convention: NNN_descriptive_name (e.g., 001_initial)
|
|
9
|
+
* The `version` integer is what the system uses; the `name` is for humans.
|
|
10
|
+
*/
|
|
11
|
+
export const ALL_MIGRATIONS = [
|
|
12
|
+
{
|
|
13
|
+
version: 1,
|
|
14
|
+
name: "001_initial",
|
|
15
|
+
sql: `
|
|
16
|
+
-- FK strategy:
|
|
17
|
+
-- project_id → ON DELETE CASCADE (deleting a project removes all its data)
|
|
18
|
+
-- all other FKs → ON DELETE SET NULL (referenced entities can always be deleted)
|
|
19
|
+
|
|
20
|
+
CREATE TABLE IF NOT EXISTS projects (
|
|
21
|
+
id UUID PRIMARY KEY,
|
|
22
|
+
name TEXT NOT NULL,
|
|
23
|
+
llm_settings JSONB,
|
|
24
|
+
max_concurrency INTEGER,
|
|
25
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
26
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
CREATE TABLE IF NOT EXISTS personas (
|
|
30
|
+
id UUID PRIMARY KEY,
|
|
31
|
+
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
|
32
|
+
data JSONB NOT NULL
|
|
33
|
+
);
|
|
34
|
+
CREATE INDEX IF NOT EXISTS idx_personas_project ON personas(project_id);
|
|
35
|
+
|
|
36
|
+
CREATE TABLE IF NOT EXISTS scenarios (
|
|
37
|
+
id UUID PRIMARY KEY,
|
|
38
|
+
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
|
39
|
+
data JSONB NOT NULL
|
|
40
|
+
);
|
|
41
|
+
CREATE INDEX IF NOT EXISTS idx_scenarios_project ON scenarios(project_id);
|
|
42
|
+
|
|
43
|
+
CREATE TABLE IF NOT EXISTS connectors (
|
|
44
|
+
id UUID PRIMARY KEY,
|
|
45
|
+
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
|
46
|
+
data JSONB NOT NULL
|
|
47
|
+
);
|
|
48
|
+
CREATE INDEX IF NOT EXISTS idx_connectors_project ON connectors(project_id);
|
|
49
|
+
|
|
50
|
+
CREATE TABLE IF NOT EXISTS evals (
|
|
51
|
+
id UUID PRIMARY KEY,
|
|
52
|
+
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
|
53
|
+
connector_id UUID REFERENCES connectors(id) ON DELETE SET NULL,
|
|
54
|
+
data JSONB NOT NULL
|
|
55
|
+
);
|
|
56
|
+
CREATE INDEX IF NOT EXISTS idx_evals_project ON evals(project_id);
|
|
57
|
+
CREATE INDEX IF NOT EXISTS idx_evals_connector ON evals(connector_id);
|
|
58
|
+
|
|
59
|
+
CREATE TABLE IF NOT EXISTS executions (
|
|
60
|
+
id INTEGER NOT NULL,
|
|
61
|
+
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
|
62
|
+
eval_id UUID REFERENCES evals(id) ON DELETE SET NULL,
|
|
63
|
+
data JSONB NOT NULL,
|
|
64
|
+
PRIMARY KEY (project_id, id)
|
|
65
|
+
);
|
|
66
|
+
CREATE INDEX IF NOT EXISTS idx_executions_project ON executions(project_id);
|
|
67
|
+
CREATE INDEX IF NOT EXISTS idx_executions_eval ON executions(eval_id);
|
|
68
|
+
|
|
69
|
+
CREATE TABLE IF NOT EXISTS runs (
|
|
70
|
+
id UUID PRIMARY KEY,
|
|
71
|
+
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
|
72
|
+
eval_id UUID REFERENCES evals(id) ON DELETE SET NULL,
|
|
73
|
+
scenario_id UUID REFERENCES scenarios(id) ON DELETE SET NULL,
|
|
74
|
+
persona_id UUID REFERENCES personas(id) ON DELETE SET NULL,
|
|
75
|
+
connector_id UUID REFERENCES connectors(id) ON DELETE SET NULL,
|
|
76
|
+
execution_id INTEGER,
|
|
77
|
+
status TEXT NOT NULL,
|
|
78
|
+
data JSONB NOT NULL
|
|
79
|
+
);
|
|
80
|
+
CREATE INDEX IF NOT EXISTS idx_runs_project ON runs(project_id);
|
|
81
|
+
CREATE INDEX IF NOT EXISTS idx_runs_status ON runs(project_id, status);
|
|
82
|
+
CREATE INDEX IF NOT EXISTS idx_runs_eval ON runs(project_id, eval_id);
|
|
83
|
+
CREATE INDEX IF NOT EXISTS idx_runs_scenario ON runs(project_id, scenario_id);
|
|
84
|
+
CREATE INDEX IF NOT EXISTS idx_runs_execution ON runs(project_id, execution_id);
|
|
85
|
+
`,
|
|
86
|
+
},
|
|
87
|
+
];
|
|
88
|
+
//# sourceMappingURL=migrations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrations.js","sourceRoot":"","sources":["../src/migrations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAQH,MAAM,CAAC,MAAM,cAAc,GAAgB;IACzC;QACE,OAAO,EAAE,CAAC;QACV,IAAI,EAAE,aAAa;QACnB,GAAG,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAsEJ;KACF;CACF,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Pool } from "pg";
|
|
2
|
+
export interface MigrationStatus {
|
|
3
|
+
applied: Array<{
|
|
4
|
+
version: number;
|
|
5
|
+
name: string;
|
|
6
|
+
appliedAt: Date;
|
|
7
|
+
}>;
|
|
8
|
+
pending: Array<{
|
|
9
|
+
version: number;
|
|
10
|
+
name: string;
|
|
11
|
+
}>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Runs all pending migrations in order.
|
|
15
|
+
* Each migration executes in its own transaction.
|
|
16
|
+
* Safe to call on every startup — already-applied migrations are skipped.
|
|
17
|
+
*/
|
|
18
|
+
export declare function runMigrations(pool: Pool): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* Returns the current migration status: which are applied and which are pending.
|
|
21
|
+
*/
|
|
22
|
+
export declare function getMigrationStatus(pool: Pool): Promise<MigrationStatus>;
|
|
23
|
+
//# sourceMappingURL=migrator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrator.d.ts","sourceRoot":"","sources":["../src/migrator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;AAU/B,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,IAAI,CAAA;KAAE,CAAC,CAAC;IACnE,OAAO,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACnD;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAY7D;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,eAAe,CAAC,CA4B7E"}
|
package/dist/migrator.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { ALL_MIGRATIONS } from "./migrations.js";
|
|
2
|
+
const SCHEMA_MIGRATIONS_DDL = `
|
|
3
|
+
CREATE TABLE IF NOT EXISTS schema_migrations (
|
|
4
|
+
version INTEGER PRIMARY KEY,
|
|
5
|
+
name TEXT NOT NULL,
|
|
6
|
+
applied_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
7
|
+
)`;
|
|
8
|
+
/**
|
|
9
|
+
* Runs all pending migrations in order.
|
|
10
|
+
* Each migration executes in its own transaction.
|
|
11
|
+
* Safe to call on every startup — already-applied migrations are skipped.
|
|
12
|
+
*/
|
|
13
|
+
export async function runMigrations(pool) {
|
|
14
|
+
await pool.query(SCHEMA_MIGRATIONS_DDL);
|
|
15
|
+
const applied = await getAppliedVersions(pool);
|
|
16
|
+
validateMigrationOrder();
|
|
17
|
+
const pending = ALL_MIGRATIONS.filter((m) => !applied.has(m.version));
|
|
18
|
+
for (const migration of pending) {
|
|
19
|
+
await applyMigration(pool, migration);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Returns the current migration status: which are applied and which are pending.
|
|
24
|
+
*/
|
|
25
|
+
export async function getMigrationStatus(pool) {
|
|
26
|
+
// Check if schema_migrations table exists
|
|
27
|
+
const tableExists = await pool.query(`SELECT EXISTS (
|
|
28
|
+
SELECT FROM information_schema.tables
|
|
29
|
+
WHERE table_name = 'schema_migrations'
|
|
30
|
+
) AS exists`);
|
|
31
|
+
if (!tableExists.rows[0].exists) {
|
|
32
|
+
return {
|
|
33
|
+
applied: [],
|
|
34
|
+
pending: ALL_MIGRATIONS.map((m) => ({ version: m.version, name: m.name })),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const { rows } = await pool.query("SELECT version, name, applied_at FROM schema_migrations ORDER BY version");
|
|
38
|
+
const appliedVersions = new Set(rows.map((r) => r.version));
|
|
39
|
+
return {
|
|
40
|
+
applied: rows.map((r) => ({ version: r.version, name: r.name, appliedAt: r.applied_at })),
|
|
41
|
+
pending: ALL_MIGRATIONS
|
|
42
|
+
.filter((m) => !appliedVersions.has(m.version))
|
|
43
|
+
.map((m) => ({ version: m.version, name: m.name })),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
async function getAppliedVersions(pool) {
|
|
47
|
+
const { rows } = await pool.query("SELECT version FROM schema_migrations ORDER BY version");
|
|
48
|
+
return new Set(rows.map((r) => r.version));
|
|
49
|
+
}
|
|
50
|
+
function validateMigrationOrder() {
|
|
51
|
+
for (let i = 1; i < ALL_MIGRATIONS.length; i++) {
|
|
52
|
+
if (ALL_MIGRATIONS[i].version <= ALL_MIGRATIONS[i - 1].version) {
|
|
53
|
+
throw new Error(`Migration ordering error: ${ALL_MIGRATIONS[i].name} ` +
|
|
54
|
+
`(version ${ALL_MIGRATIONS[i].version}) must be greater than ` +
|
|
55
|
+
`${ALL_MIGRATIONS[i - 1].name} (version ${ALL_MIGRATIONS[i - 1].version})`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
async function applyMigration(pool, migration) {
|
|
60
|
+
const client = await pool.connect();
|
|
61
|
+
try {
|
|
62
|
+
await client.query("BEGIN");
|
|
63
|
+
await client.query(migration.sql);
|
|
64
|
+
await client.query("INSERT INTO schema_migrations (version, name) VALUES ($1, $2)", [migration.version, migration.name]);
|
|
65
|
+
await client.query("COMMIT");
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
await client.query("ROLLBACK");
|
|
69
|
+
throw new Error(`Migration ${migration.name} failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
70
|
+
}
|
|
71
|
+
finally {
|
|
72
|
+
client.release();
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=migrator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrator.js","sourceRoot":"","sources":["../src/migrator.ts"],"names":[],"mappings":"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"}
|
package/dist/schema.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { Pool } from "pg";
|
|
2
2
|
/**
|
|
3
|
-
* Initializes the database schema.
|
|
4
|
-
*
|
|
3
|
+
* Initializes the database schema by running all pending migrations.
|
|
4
|
+
* Safe to call on every startup — already-applied migrations are skipped.
|
|
5
5
|
*/
|
|
6
6
|
export declare function initSchema(pool: Pool): Promise<void>;
|
|
7
7
|
/**
|
|
8
|
-
* Checks if the schema has been initialized (
|
|
8
|
+
* Checks if the schema has been initialized (schema_migrations table exists
|
|
9
|
+
* and has at least one applied migration).
|
|
9
10
|
*/
|
|
10
11
|
export declare function schemaExists(pool: Pool): Promise<boolean>;
|
|
11
12
|
//# sourceMappingURL=schema.d.ts.map
|
package/dist/schema.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;AAG/B;;;GAGG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAE1D;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAa/D"}
|
package/dist/schema.js
CHANGED
|
@@ -1,93 +1,23 @@
|
|
|
1
|
+
import { runMigrations } from "./migrator.js";
|
|
1
2
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* Design: reference columns (project_id, eval_id, etc.) are real columns
|
|
5
|
-
* with REFERENCES constraints for relational integrity. The rest of the
|
|
6
|
-
* entity payload lives in a JSONB `data` column to avoid mapping every
|
|
7
|
-
* field upfront.
|
|
8
|
-
*/
|
|
9
|
-
const SCHEMA_SQL = `
|
|
10
|
-
CREATE TABLE IF NOT EXISTS projects (
|
|
11
|
-
id UUID PRIMARY KEY,
|
|
12
|
-
name TEXT NOT NULL,
|
|
13
|
-
llm_settings JSONB,
|
|
14
|
-
max_concurrency INTEGER,
|
|
15
|
-
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
16
|
-
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
17
|
-
);
|
|
18
|
-
|
|
19
|
-
CREATE TABLE IF NOT EXISTS personas (
|
|
20
|
-
id UUID PRIMARY KEY,
|
|
21
|
-
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
|
22
|
-
data JSONB NOT NULL
|
|
23
|
-
);
|
|
24
|
-
CREATE INDEX IF NOT EXISTS idx_personas_project ON personas(project_id);
|
|
25
|
-
|
|
26
|
-
CREATE TABLE IF NOT EXISTS scenarios (
|
|
27
|
-
id UUID PRIMARY KEY,
|
|
28
|
-
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
|
29
|
-
data JSONB NOT NULL
|
|
30
|
-
);
|
|
31
|
-
CREATE INDEX IF NOT EXISTS idx_scenarios_project ON scenarios(project_id);
|
|
32
|
-
|
|
33
|
-
CREATE TABLE IF NOT EXISTS connectors (
|
|
34
|
-
id UUID PRIMARY KEY,
|
|
35
|
-
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
|
36
|
-
data JSONB NOT NULL
|
|
37
|
-
);
|
|
38
|
-
CREATE INDEX IF NOT EXISTS idx_connectors_project ON connectors(project_id);
|
|
39
|
-
|
|
40
|
-
CREATE TABLE IF NOT EXISTS evals (
|
|
41
|
-
id UUID PRIMARY KEY,
|
|
42
|
-
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
|
43
|
-
connector_id UUID NOT NULL REFERENCES connectors(id),
|
|
44
|
-
data JSONB NOT NULL
|
|
45
|
-
);
|
|
46
|
-
CREATE INDEX IF NOT EXISTS idx_evals_project ON evals(project_id);
|
|
47
|
-
CREATE INDEX IF NOT EXISTS idx_evals_connector ON evals(connector_id);
|
|
48
|
-
|
|
49
|
-
CREATE TABLE IF NOT EXISTS executions (
|
|
50
|
-
id INTEGER NOT NULL,
|
|
51
|
-
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
|
52
|
-
eval_id UUID NOT NULL REFERENCES evals(id),
|
|
53
|
-
data JSONB NOT NULL,
|
|
54
|
-
PRIMARY KEY (project_id, id)
|
|
55
|
-
);
|
|
56
|
-
CREATE INDEX IF NOT EXISTS idx_executions_project ON executions(project_id);
|
|
57
|
-
CREATE INDEX IF NOT EXISTS idx_executions_eval ON executions(eval_id);
|
|
58
|
-
|
|
59
|
-
CREATE TABLE IF NOT EXISTS runs (
|
|
60
|
-
id UUID PRIMARY KEY,
|
|
61
|
-
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
|
62
|
-
eval_id UUID REFERENCES evals(id),
|
|
63
|
-
scenario_id UUID NOT NULL REFERENCES scenarios(id),
|
|
64
|
-
persona_id UUID REFERENCES personas(id),
|
|
65
|
-
connector_id UUID REFERENCES connectors(id),
|
|
66
|
-
execution_id INTEGER,
|
|
67
|
-
status TEXT NOT NULL,
|
|
68
|
-
data JSONB NOT NULL
|
|
69
|
-
);
|
|
70
|
-
CREATE INDEX IF NOT EXISTS idx_runs_project ON runs(project_id);
|
|
71
|
-
CREATE INDEX IF NOT EXISTS idx_runs_status ON runs(project_id, status);
|
|
72
|
-
CREATE INDEX IF NOT EXISTS idx_runs_eval ON runs(project_id, eval_id);
|
|
73
|
-
CREATE INDEX IF NOT EXISTS idx_runs_scenario ON runs(project_id, scenario_id);
|
|
74
|
-
CREATE INDEX IF NOT EXISTS idx_runs_execution ON runs(project_id, execution_id);
|
|
75
|
-
`;
|
|
76
|
-
/**
|
|
77
|
-
* Initializes the database schema.
|
|
78
|
-
* Uses IF NOT EXISTS so it's safe to call on every startup.
|
|
3
|
+
* Initializes the database schema by running all pending migrations.
|
|
4
|
+
* Safe to call on every startup — already-applied migrations are skipped.
|
|
79
5
|
*/
|
|
80
6
|
export async function initSchema(pool) {
|
|
81
|
-
await pool
|
|
7
|
+
await runMigrations(pool);
|
|
82
8
|
}
|
|
83
9
|
/**
|
|
84
|
-
* Checks if the schema has been initialized (
|
|
10
|
+
* Checks if the schema has been initialized (schema_migrations table exists
|
|
11
|
+
* and has at least one applied migration).
|
|
85
12
|
*/
|
|
86
13
|
export async function schemaExists(pool) {
|
|
87
14
|
const result = await pool.query(`SELECT EXISTS (
|
|
88
15
|
SELECT FROM information_schema.tables
|
|
89
|
-
WHERE table_name = '
|
|
16
|
+
WHERE table_name = 'schema_migrations'
|
|
90
17
|
) AS exists`);
|
|
91
|
-
|
|
18
|
+
if (!result.rows[0].exists)
|
|
19
|
+
return false;
|
|
20
|
+
const count = await pool.query("SELECT COUNT(*) AS count FROM schema_migrations");
|
|
21
|
+
return parseInt(count.rows[0].count, 10) > 0;
|
|
92
22
|
}
|
|
93
23
|
//# sourceMappingURL=schema.js.map
|
package/dist/schema.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,IAAU;IACzC,MAAM,aAAa,CAAC,IAAI,CAAC,CAAC;AAC5B,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAU;IAC3C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,CAC7B;;;gBAGY,CACb,CAAC;IACF,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAEzC,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,KAAK,CAC5B,iDAAiD,CAClD,CAAC;IACF,OAAO,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;AAC/C,CAAC"}
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.
|
|
6
|
+
"version": "0.5.0",
|
|
7
7
|
"description": "PostgreSQL storage backend for EvalStudio",
|
|
8
8
|
"type": "module",
|
|
9
9
|
"main": "./dist/index.js",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
],
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"pg": "^8.13.1",
|
|
32
|
-
"@evalstudio/core": "0.
|
|
32
|
+
"@evalstudio/core": "0.5.0"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@types/pg": "^8.11.11",
|