@cnstra/persist-postgres 0.3.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 +60 -20
- package/dist/chunk-BPKIKGKB.mjs +310 -0
- package/dist/chunk-BPKIKGKB.mjs.map +1 -0
- package/dist/cli.js +277 -57
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +6 -7
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +54 -51
- package/dist/index.d.ts +54 -51
- package/dist/index.js +656 -264
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +388 -213
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -3
- package/dist/chunk-5FLIKV6I.mjs +0 -94
- package/dist/chunk-5FLIKV6I.mjs.map +0 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,80 +1,66 @@
|
|
|
1
|
-
import { Pool } from 'pg';
|
|
2
1
|
import { ICNSStimulationRepository, ICNSStimulationRosterQuery } from '@cnstra/persist';
|
|
3
2
|
import { TCNSStimulationState, TCNSStimulationAttempt, TCNSStimulationTask, TCNSStimulationRosterFilter, TCNSStimulationRosterPage, TCNSStimulationRosterFacets } from '@cnstra/persist-dto';
|
|
3
|
+
import { Pool } from 'pg';
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
* Schema / migrations for the CNStra stimulation/attempt/task relational store.
|
|
7
|
-
*
|
|
8
|
-
* The package OWNS this schema — run it explicitly via `cnstra-persist-postgres migrate`
|
|
9
|
-
* or `ensureSchema(db)`, or let the repository auto-create it on first use. Tables
|
|
10
|
-
* under a configurable prefix (default `cns_`); the stimulation's `progress` is
|
|
11
|
-
* NORMALISED into `stimulation_frontier` (one row per outstanding task).
|
|
12
|
-
*/
|
|
13
|
-
/** Minimal pg client surface (a `pg` Pool or Client satisfies it). */
|
|
14
|
-
interface IPgQueryable {
|
|
5
|
+
interface ICNSPgQueryable {
|
|
15
6
|
query(text: string, params?: unknown[]): Promise<{
|
|
16
7
|
rows: unknown[];
|
|
17
8
|
}>;
|
|
18
9
|
}
|
|
19
|
-
declare const DEFAULT_PREFIX = "cns_";
|
|
20
|
-
/** Guard the table prefix (it is interpolated into DDL/DML, not parameterised). */
|
|
21
|
-
declare function assertSafePrefix(prefix: string): string;
|
|
22
|
-
/** The full CREATE TABLE + CREATE INDEX DDL (idempotent). */
|
|
23
|
-
declare function persistPostgresSchemaSql(prefix?: string): string;
|
|
24
|
-
/** Idempotently create all tables + indexes. Safe to run repeatedly. */
|
|
25
|
-
declare function ensureSchema(db: IPgQueryable, prefix?: string): Promise<void>;
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Postgres relational store for the CNStra stimulation/attempt/task resumable model
|
|
29
|
-
* (`ICNSStimulationRepository`). The stimulation's `progress` is NORMALISED: the
|
|
30
|
-
* outstanding frontier into `<prefix>stimulation_frontier` (one row per task) —
|
|
31
|
-
* rebuilt into `TCNSProgress` on read.
|
|
32
|
-
*
|
|
33
|
-
* Reuses the `IPgQueryable` seam so `pg` is an optional peer: inject any pg
|
|
34
|
-
* client/pool, or pass a `connectionString` for the repo to own a Pool. Behaviourally
|
|
35
|
-
* matches `CNSInMemoryStimulationRepository` (listStimulations newest-first, getAttempts
|
|
36
|
-
* by attemptNumber, getTasks by index, delete cascades).
|
|
37
|
-
*/
|
|
38
10
|
|
|
39
|
-
|
|
11
|
+
type TCNSPostgresStimulationRepositoryOptions = {
|
|
40
12
|
connectionString?: string;
|
|
41
|
-
/** Inject an existing pg Pool (transactions supported; not closed by `close()`). */
|
|
42
13
|
pool?: Pool;
|
|
43
|
-
|
|
44
|
-
queryable?: IPgQueryable;
|
|
45
|
-
/** Table prefix (default `cns_`). */
|
|
14
|
+
queryable?: ICNSPgQueryable;
|
|
46
15
|
tablePrefix?: string;
|
|
47
|
-
/** Lazily ensure the schema on first use (default true). */
|
|
48
16
|
autoMigrate?: boolean;
|
|
49
|
-
|
|
17
|
+
now?: () => number;
|
|
18
|
+
};
|
|
19
|
+
|
|
50
20
|
declare class CNSPostgresStimulationRepository implements ICNSStimulationRepository, ICNSStimulationRosterQuery {
|
|
21
|
+
private static readonly LOCK_STIMULATION;
|
|
22
|
+
private static readonly RETENTION_BATCH;
|
|
51
23
|
private readonly db;
|
|
52
24
|
private readonly pool?;
|
|
53
25
|
private readonly ownsPool;
|
|
54
26
|
private readonly p;
|
|
55
27
|
private readonly autoMigrate;
|
|
28
|
+
private readonly now;
|
|
29
|
+
private readonly taskPartitions;
|
|
56
30
|
private ready;
|
|
57
31
|
constructor(opts: TCNSPostgresStimulationRepositoryOptions);
|
|
58
|
-
private
|
|
32
|
+
private schemaReady;
|
|
59
33
|
/** Run `fn` in a transaction when a Pool is available; else best-effort inline. */
|
|
60
34
|
private tx;
|
|
61
35
|
saveStimulation(s: TCNSStimulationState): Promise<void>;
|
|
62
36
|
saveAttempt(a: TCNSStimulationAttempt): Promise<void>;
|
|
37
|
+
private lockStimulation;
|
|
38
|
+
private rollUpAttempts;
|
|
63
39
|
appendTask(t: TCNSStimulationTask): Promise<void>;
|
|
64
40
|
getStimulation(stimulationId: string): Promise<TCNSStimulationState | undefined>;
|
|
65
41
|
listStimulations(filter?: {
|
|
66
42
|
scopeName?: string;
|
|
43
|
+
since?: number;
|
|
67
44
|
}): Promise<TCNSStimulationState[]>;
|
|
68
45
|
getAttempts(stimulationId: string): Promise<TCNSStimulationAttempt[]>;
|
|
69
46
|
getTasks(stimulationAttemptId: string): Promise<TCNSStimulationTask[]>;
|
|
70
47
|
/**
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
* status, and the DISTINCT activated neuron names (for the neurons lens +
|
|
74
|
-
* filter). Newest-first (`startedAt DESC, stimulationId DESC`) so the keyset
|
|
75
|
-
* cursor is stable. `limit` is applied only when paginating (roster); facets
|
|
76
|
-
* pull the whole filtered set.
|
|
48
|
+
* Attempts of many stimulations in ONE query, so a page of runs costs one
|
|
49
|
+
* round trip rather than one per run.
|
|
77
50
|
*/
|
|
51
|
+
getAttemptsFor(stimulationIds: readonly string[]): Promise<TCNSStimulationAttempt[]>;
|
|
52
|
+
/** Tasks of many attempts in ONE query — see {@link getAttemptsFor}. */
|
|
53
|
+
getTasksFor(stimulationAttemptIds: readonly string[]): Promise<TCNSStimulationTask[]>;
|
|
54
|
+
/**
|
|
55
|
+
* The CTE every roster read stands on. The roster fields are kept on the
|
|
56
|
+
* stimulation row by `saveAttempt` / `saveStimulation`, so the window and the
|
|
57
|
+
* order come from `stimulation(started_at DESC, stimulation_id)`; the total
|
|
58
|
+
* still counts the whole filtered set. Shared so the facet tallies are counted
|
|
59
|
+
* over exactly the set the roster pages through.
|
|
60
|
+
* The task table is read only when `withNeurons` asks for the neuron names.
|
|
61
|
+
* It binds `$1..$7` (the filter); the keyset cursor belongs to the roster's tail.
|
|
62
|
+
*/
|
|
63
|
+
private rosterCte;
|
|
78
64
|
private selectRoster;
|
|
79
65
|
queryRoster(filter: TCNSStimulationRosterFilter, opts: {
|
|
80
66
|
cursor?: string;
|
|
@@ -85,15 +71,32 @@ declare class CNSPostgresStimulationRepository implements ICNSStimulationReposit
|
|
|
85
71
|
}): Promise<TCNSStimulationRosterFacets>;
|
|
86
72
|
delete(stimulationId: string): Promise<void>;
|
|
87
73
|
/**
|
|
88
|
-
* Retention: prune stimulations not updated for `olderThanMs
|
|
89
|
-
* attempts
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
74
|
+
* Retention: prune stimulations not updated for `olderThanMs`, with their
|
|
75
|
+
* attempts and tasks, in batches of one transaction each, then the attempts and
|
|
76
|
+
* tasks older than that whose parent row never arrived or is already gone; last,
|
|
77
|
+
* with a pool, drop the daily task partitions that ended before the window and
|
|
78
|
+
* create the next seven.
|
|
79
|
+
* Returns the number of stimulations removed.
|
|
93
80
|
*/
|
|
94
81
|
deleteStale(olderThanMs: number): Promise<number>;
|
|
95
82
|
close(): Promise<void>;
|
|
96
|
-
private buildProgress;
|
|
97
83
|
}
|
|
98
84
|
|
|
99
|
-
|
|
85
|
+
type TCNSPostgresStimulationMigrateOptions = {
|
|
86
|
+
readonly contract?: boolean;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
declare class CNSPostgresStimulationSchema {
|
|
90
|
+
static readonly DEFAULT_TABLE_PREFIX = "cns_";
|
|
91
|
+
private static readonly LONGEST_SUFFIX;
|
|
92
|
+
private static readonly migrator;
|
|
93
|
+
static assertTablePrefix(tablePrefix: string): string;
|
|
94
|
+
static tables(tablePrefix?: string): string[];
|
|
95
|
+
static migrationTable(tablePrefix?: string): string;
|
|
96
|
+
static migrationSql(tablePrefix?: string, appliedSteps?: readonly number[], options?: TCNSPostgresStimulationMigrateOptions): string;
|
|
97
|
+
static migrate(pool: Pool, tablePrefix?: string, options?: TCNSPostgresStimulationMigrateOptions): Promise<void>;
|
|
98
|
+
static verify(database: ICNSPgQueryable, tablePrefix?: string): Promise<void>;
|
|
99
|
+
private static initialSql;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export { CNSPostgresStimulationRepository, CNSPostgresStimulationSchema, type ICNSPgQueryable, type TCNSPostgresStimulationMigrateOptions, type TCNSPostgresStimulationRepositoryOptions };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,80 +1,66 @@
|
|
|
1
|
-
import { Pool } from 'pg';
|
|
2
1
|
import { ICNSStimulationRepository, ICNSStimulationRosterQuery } from '@cnstra/persist';
|
|
3
2
|
import { TCNSStimulationState, TCNSStimulationAttempt, TCNSStimulationTask, TCNSStimulationRosterFilter, TCNSStimulationRosterPage, TCNSStimulationRosterFacets } from '@cnstra/persist-dto';
|
|
3
|
+
import { Pool } from 'pg';
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
* Schema / migrations for the CNStra stimulation/attempt/task relational store.
|
|
7
|
-
*
|
|
8
|
-
* The package OWNS this schema — run it explicitly via `cnstra-persist-postgres migrate`
|
|
9
|
-
* or `ensureSchema(db)`, or let the repository auto-create it on first use. Tables
|
|
10
|
-
* under a configurable prefix (default `cns_`); the stimulation's `progress` is
|
|
11
|
-
* NORMALISED into `stimulation_frontier` (one row per outstanding task).
|
|
12
|
-
*/
|
|
13
|
-
/** Minimal pg client surface (a `pg` Pool or Client satisfies it). */
|
|
14
|
-
interface IPgQueryable {
|
|
5
|
+
interface ICNSPgQueryable {
|
|
15
6
|
query(text: string, params?: unknown[]): Promise<{
|
|
16
7
|
rows: unknown[];
|
|
17
8
|
}>;
|
|
18
9
|
}
|
|
19
|
-
declare const DEFAULT_PREFIX = "cns_";
|
|
20
|
-
/** Guard the table prefix (it is interpolated into DDL/DML, not parameterised). */
|
|
21
|
-
declare function assertSafePrefix(prefix: string): string;
|
|
22
|
-
/** The full CREATE TABLE + CREATE INDEX DDL (idempotent). */
|
|
23
|
-
declare function persistPostgresSchemaSql(prefix?: string): string;
|
|
24
|
-
/** Idempotently create all tables + indexes. Safe to run repeatedly. */
|
|
25
|
-
declare function ensureSchema(db: IPgQueryable, prefix?: string): Promise<void>;
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Postgres relational store for the CNStra stimulation/attempt/task resumable model
|
|
29
|
-
* (`ICNSStimulationRepository`). The stimulation's `progress` is NORMALISED: the
|
|
30
|
-
* outstanding frontier into `<prefix>stimulation_frontier` (one row per task) —
|
|
31
|
-
* rebuilt into `TCNSProgress` on read.
|
|
32
|
-
*
|
|
33
|
-
* Reuses the `IPgQueryable` seam so `pg` is an optional peer: inject any pg
|
|
34
|
-
* client/pool, or pass a `connectionString` for the repo to own a Pool. Behaviourally
|
|
35
|
-
* matches `CNSInMemoryStimulationRepository` (listStimulations newest-first, getAttempts
|
|
36
|
-
* by attemptNumber, getTasks by index, delete cascades).
|
|
37
|
-
*/
|
|
38
10
|
|
|
39
|
-
|
|
11
|
+
type TCNSPostgresStimulationRepositoryOptions = {
|
|
40
12
|
connectionString?: string;
|
|
41
|
-
/** Inject an existing pg Pool (transactions supported; not closed by `close()`). */
|
|
42
13
|
pool?: Pool;
|
|
43
|
-
|
|
44
|
-
queryable?: IPgQueryable;
|
|
45
|
-
/** Table prefix (default `cns_`). */
|
|
14
|
+
queryable?: ICNSPgQueryable;
|
|
46
15
|
tablePrefix?: string;
|
|
47
|
-
/** Lazily ensure the schema on first use (default true). */
|
|
48
16
|
autoMigrate?: boolean;
|
|
49
|
-
|
|
17
|
+
now?: () => number;
|
|
18
|
+
};
|
|
19
|
+
|
|
50
20
|
declare class CNSPostgresStimulationRepository implements ICNSStimulationRepository, ICNSStimulationRosterQuery {
|
|
21
|
+
private static readonly LOCK_STIMULATION;
|
|
22
|
+
private static readonly RETENTION_BATCH;
|
|
51
23
|
private readonly db;
|
|
52
24
|
private readonly pool?;
|
|
53
25
|
private readonly ownsPool;
|
|
54
26
|
private readonly p;
|
|
55
27
|
private readonly autoMigrate;
|
|
28
|
+
private readonly now;
|
|
29
|
+
private readonly taskPartitions;
|
|
56
30
|
private ready;
|
|
57
31
|
constructor(opts: TCNSPostgresStimulationRepositoryOptions);
|
|
58
|
-
private
|
|
32
|
+
private schemaReady;
|
|
59
33
|
/** Run `fn` in a transaction when a Pool is available; else best-effort inline. */
|
|
60
34
|
private tx;
|
|
61
35
|
saveStimulation(s: TCNSStimulationState): Promise<void>;
|
|
62
36
|
saveAttempt(a: TCNSStimulationAttempt): Promise<void>;
|
|
37
|
+
private lockStimulation;
|
|
38
|
+
private rollUpAttempts;
|
|
63
39
|
appendTask(t: TCNSStimulationTask): Promise<void>;
|
|
64
40
|
getStimulation(stimulationId: string): Promise<TCNSStimulationState | undefined>;
|
|
65
41
|
listStimulations(filter?: {
|
|
66
42
|
scopeName?: string;
|
|
43
|
+
since?: number;
|
|
67
44
|
}): Promise<TCNSStimulationState[]>;
|
|
68
45
|
getAttempts(stimulationId: string): Promise<TCNSStimulationAttempt[]>;
|
|
69
46
|
getTasks(stimulationAttemptId: string): Promise<TCNSStimulationTask[]>;
|
|
70
47
|
/**
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
* status, and the DISTINCT activated neuron names (for the neurons lens +
|
|
74
|
-
* filter). Newest-first (`startedAt DESC, stimulationId DESC`) so the keyset
|
|
75
|
-
* cursor is stable. `limit` is applied only when paginating (roster); facets
|
|
76
|
-
* pull the whole filtered set.
|
|
48
|
+
* Attempts of many stimulations in ONE query, so a page of runs costs one
|
|
49
|
+
* round trip rather than one per run.
|
|
77
50
|
*/
|
|
51
|
+
getAttemptsFor(stimulationIds: readonly string[]): Promise<TCNSStimulationAttempt[]>;
|
|
52
|
+
/** Tasks of many attempts in ONE query — see {@link getAttemptsFor}. */
|
|
53
|
+
getTasksFor(stimulationAttemptIds: readonly string[]): Promise<TCNSStimulationTask[]>;
|
|
54
|
+
/**
|
|
55
|
+
* The CTE every roster read stands on. The roster fields are kept on the
|
|
56
|
+
* stimulation row by `saveAttempt` / `saveStimulation`, so the window and the
|
|
57
|
+
* order come from `stimulation(started_at DESC, stimulation_id)`; the total
|
|
58
|
+
* still counts the whole filtered set. Shared so the facet tallies are counted
|
|
59
|
+
* over exactly the set the roster pages through.
|
|
60
|
+
* The task table is read only when `withNeurons` asks for the neuron names.
|
|
61
|
+
* It binds `$1..$7` (the filter); the keyset cursor belongs to the roster's tail.
|
|
62
|
+
*/
|
|
63
|
+
private rosterCte;
|
|
78
64
|
private selectRoster;
|
|
79
65
|
queryRoster(filter: TCNSStimulationRosterFilter, opts: {
|
|
80
66
|
cursor?: string;
|
|
@@ -85,15 +71,32 @@ declare class CNSPostgresStimulationRepository implements ICNSStimulationReposit
|
|
|
85
71
|
}): Promise<TCNSStimulationRosterFacets>;
|
|
86
72
|
delete(stimulationId: string): Promise<void>;
|
|
87
73
|
/**
|
|
88
|
-
* Retention: prune stimulations not updated for `olderThanMs
|
|
89
|
-
* attempts
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
74
|
+
* Retention: prune stimulations not updated for `olderThanMs`, with their
|
|
75
|
+
* attempts and tasks, in batches of one transaction each, then the attempts and
|
|
76
|
+
* tasks older than that whose parent row never arrived or is already gone; last,
|
|
77
|
+
* with a pool, drop the daily task partitions that ended before the window and
|
|
78
|
+
* create the next seven.
|
|
79
|
+
* Returns the number of stimulations removed.
|
|
93
80
|
*/
|
|
94
81
|
deleteStale(olderThanMs: number): Promise<number>;
|
|
95
82
|
close(): Promise<void>;
|
|
96
|
-
private buildProgress;
|
|
97
83
|
}
|
|
98
84
|
|
|
99
|
-
|
|
85
|
+
type TCNSPostgresStimulationMigrateOptions = {
|
|
86
|
+
readonly contract?: boolean;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
declare class CNSPostgresStimulationSchema {
|
|
90
|
+
static readonly DEFAULT_TABLE_PREFIX = "cns_";
|
|
91
|
+
private static readonly LONGEST_SUFFIX;
|
|
92
|
+
private static readonly migrator;
|
|
93
|
+
static assertTablePrefix(tablePrefix: string): string;
|
|
94
|
+
static tables(tablePrefix?: string): string[];
|
|
95
|
+
static migrationTable(tablePrefix?: string): string;
|
|
96
|
+
static migrationSql(tablePrefix?: string, appliedSteps?: readonly number[], options?: TCNSPostgresStimulationMigrateOptions): string;
|
|
97
|
+
static migrate(pool: Pool, tablePrefix?: string, options?: TCNSPostgresStimulationMigrateOptions): Promise<void>;
|
|
98
|
+
static verify(database: ICNSPgQueryable, tablePrefix?: string): Promise<void>;
|
|
99
|
+
private static initialSql;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export { CNSPostgresStimulationRepository, CNSPostgresStimulationSchema, type ICNSPgQueryable, type TCNSPostgresStimulationMigrateOptions, type TCNSPostgresStimulationRepositoryOptions };
|