palgres 0.0.0-stage → 0.1.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/LICENSE +27 -0
- package/README.md +2 -2
- package/dist/chunks/5DSZT7RI.js +5 -0
- package/dist/chunks/7676QADW.js +2 -0
- package/dist/chunks/W7VRQDZA.js +2 -0
- package/dist/dsl.js +2 -0
- package/dist/index.js +372 -0
- package/dist/testing.js +2 -0
- package/package.json +32 -4
- package/types/internal/src/data.d.ts +15 -0
- package/types/palgres/src/adopt.d.ts +17 -0
- package/types/palgres/src/connect.d.ts +37 -0
- package/types/palgres/src/dsl/columns.d.ts +388 -0
- package/types/palgres/src/dsl/foreign-key.d.ts +33 -0
- package/types/palgres/src/dsl/index.d.ts +11 -0
- package/types/palgres/src/dsl/policy.d.ts +181 -0
- package/types/palgres/src/dsl/raw.d.ts +43 -0
- package/types/palgres/src/dsl/schema.d.ts +288 -0
- package/types/palgres/src/dsl/to-model.d.ts +6 -0
- package/types/palgres/src/forget.d.ts +12 -0
- package/types/palgres/src/index.d.ts +15 -0
- package/types/palgres/src/introspect.d.ts +17 -0
- package/types/palgres/src/migrate.d.ts +189 -0
- package/types/palgres/src/model.d.ts +181 -0
- package/types/palgres/src/plan.d.ts +107 -0
- package/types/palgres/src/pull.d.ts +13 -0
- package/types/palgres/src/query/admission.d.ts +80 -0
- package/types/palgres/src/query/catalog.d.ts +50 -0
- package/types/palgres/src/query/client.d.ts +154 -0
- package/types/palgres/src/query/data-mark.d.ts +7 -0
- package/types/palgres/src/query/diagnostics.d.ts +76 -0
- package/types/palgres/src/query/driver.d.ts +299 -0
- package/types/palgres/src/query/env-gen.d.ts +14 -0
- package/types/palgres/src/query/errors.d.ts +168 -0
- package/types/palgres/src/query/guards.d.ts +62 -0
- package/types/palgres/src/query/index.d.ts +76 -0
- package/types/palgres/src/query/options.d.ts +75 -0
- package/types/palgres/src/query/relations.d.ts +15 -0
- package/types/palgres/src/query/repository.d.ts +42 -0
- package/types/palgres/src/query/request.d.ts +54 -0
- package/types/palgres/src/query/search.d.ts +55 -0
- package/types/palgres/src/query/surface.d.ts +9 -0
- package/types/palgres/src/query/tx-plan.d.ts +229 -0
- package/types/palgres/src/query/typed.d.ts +537 -0
- package/types/palgres/src/query/unique.d.ts +16 -0
- package/types/palgres/src/search-worker.d.ts +36 -0
- package/types/palgres/src/search.d.ts +107 -0
- package/types/palgres/src/testing/fake.d.ts +22 -0
- package/types/palgres/src/testing/index.d.ts +2 -0
- package/types/palgres/src/units.d.ts +24 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { type Schema } from './model.js';
|
|
2
|
+
import { type Adoption, type Plan, type Roles } from './plan.js';
|
|
3
|
+
/** A pool that hands out one connection of its own: Bun's SQL and postgres.js both are. */
|
|
4
|
+
export interface Pool {
|
|
5
|
+
reserve(): Promise<Reserved>;
|
|
6
|
+
}
|
|
7
|
+
export interface Reserved {
|
|
8
|
+
unsafe(sql: string, params?: unknown[]): PromiseLike<unknown>;
|
|
9
|
+
release(): void;
|
|
10
|
+
}
|
|
11
|
+
export interface MigratorOptions {
|
|
12
|
+
/** The database's roles the app connects as (default anon, authenticated, service_role). */
|
|
13
|
+
roles?: Partial<Roles>;
|
|
14
|
+
/**
|
|
15
|
+
* How long a step waits for a table's lock before it gives way, and for all
|
|
16
|
+
* the others it takes while it holds one (default 500 ms; never past half
|
|
17
|
+
* of the server's deadlock_timeout).
|
|
18
|
+
*/
|
|
19
|
+
lockTimeoutMs?: number;
|
|
20
|
+
/** How long a statement step — a CONCURRENTLY build, a VALIDATE: none blocks a writer — waits for the transactions before it (default 10 minutes). */
|
|
21
|
+
statementWaitMs?: number;
|
|
22
|
+
/** How many times a step that gave way is tried (default 10). */
|
|
23
|
+
attempts?: number;
|
|
24
|
+
/** Rows a backfill updates per transaction (default 1000). */
|
|
25
|
+
batchSize?: number;
|
|
26
|
+
/** How long complete and rollback wait for the version going away to disconnect (default 60 s). */
|
|
27
|
+
disconnectTimeoutMs?: number;
|
|
28
|
+
/**
|
|
29
|
+
* A pool on another database of the same server, as this pool's role: what
|
|
30
|
+
* taking over a database Palgres has not migrated makes the declared
|
|
31
|
+
* schema in, to read it as Postgres writes it (adopt.ts). The migrator
|
|
32
|
+
* creates the database and drops it; the role needs CREATEDB.
|
|
33
|
+
*/
|
|
34
|
+
shadow?: (database: string) => Pool & {
|
|
35
|
+
end(): Promise<void>;
|
|
36
|
+
};
|
|
37
|
+
log?: (line: string) => void;
|
|
38
|
+
/**
|
|
39
|
+
* Who opens a migration this migrator starts, kept with it in the ledger
|
|
40
|
+
* while it is open: a release (the default, "deploy") or a developer
|
|
41
|
+
* trying a schema from their own computer ("cli:<who>"). A release that
|
|
42
|
+
* finds a developer's migration open takes its place; a developer who
|
|
43
|
+
* finds another's is told whose it is.
|
|
44
|
+
*/
|
|
45
|
+
openedBy?: string;
|
|
46
|
+
}
|
|
47
|
+
export interface Version {
|
|
48
|
+
n: number;
|
|
49
|
+
digest: string;
|
|
50
|
+
state: 'starting' | 'active' | 'retired' | 'abandoned';
|
|
51
|
+
}
|
|
52
|
+
export interface Status {
|
|
53
|
+
active: Version | null;
|
|
54
|
+
/** The open migration, if one is, and who opened it (null for a ledger older than the record). */
|
|
55
|
+
open: {
|
|
56
|
+
from: number | null;
|
|
57
|
+
to: number;
|
|
58
|
+
phase: string;
|
|
59
|
+
opened_by: string | null;
|
|
60
|
+
} | null;
|
|
61
|
+
}
|
|
62
|
+
export type { Adoption };
|
|
63
|
+
export type StartResult = {
|
|
64
|
+
state: 'in-sync';
|
|
65
|
+
version: number;
|
|
66
|
+
}
|
|
67
|
+
/** A database Palgres had not migrated, holding the schema as declared: taken over as version 1, nothing to migrate. */
|
|
68
|
+
| {
|
|
69
|
+
state: 'adopted';
|
|
70
|
+
version: number;
|
|
71
|
+
adoption: Adoption;
|
|
72
|
+
} | {
|
|
73
|
+
state: 'started' | 'resumed';
|
|
74
|
+
from: number | null;
|
|
75
|
+
to: number;
|
|
76
|
+
changes: string[];
|
|
77
|
+
completed: boolean;
|
|
78
|
+
adoption?: Adoption;
|
|
79
|
+
};
|
|
80
|
+
export declare class MigrationRefused extends Error {
|
|
81
|
+
readonly refusals: string[];
|
|
82
|
+
constructor(refusals: string[]);
|
|
83
|
+
}
|
|
84
|
+
export declare class MigrationOpen extends Error {
|
|
85
|
+
readonly from: number | null;
|
|
86
|
+
readonly to: number;
|
|
87
|
+
/** Who opened it ("deploy", "cli:<who>"); null when the ledger does not say. */
|
|
88
|
+
readonly openedBy: string | null;
|
|
89
|
+
constructor(from: number | null, to: number, openedBy?: string | null);
|
|
90
|
+
}
|
|
91
|
+
/** A step waited for the other version's connections to go, and they have not: nothing is changed, and it goes on when run again. */
|
|
92
|
+
export declare class VersionStillConnected extends Error {
|
|
93
|
+
readonly version: number;
|
|
94
|
+
constructor(version: number, left: number, waitedMs: number);
|
|
95
|
+
}
|
|
96
|
+
/** A backfill's rows stayed held by writers pass after pass: nothing is lost, and it goes on when run again. */
|
|
97
|
+
export declare class RowsHeld extends Error {
|
|
98
|
+
constructor(table: string, passes: number);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Whether a migration's run ended for something that says nothing of the
|
|
102
|
+
* migration itself — the database unreachable or restarting, a lock not had
|
|
103
|
+
* in time, the other version still connected — so that run again it picks up
|
|
104
|
+
* where it stopped. Anything else is the migration's own: it is refused, or
|
|
105
|
+
* what the tables hold does not fit it, and running it again changes nothing.
|
|
106
|
+
*/
|
|
107
|
+
export declare function cutOff(e: unknown): boolean;
|
|
108
|
+
export declare const DEFAULT_ROLES: Roles;
|
|
109
|
+
/** application_name of a connection the app holds for version n — how complete knows the old version is gone. */
|
|
110
|
+
export declare const applicationName: (n: number) => string;
|
|
111
|
+
export declare class Migrator {
|
|
112
|
+
private readonly pool;
|
|
113
|
+
private readonly roles;
|
|
114
|
+
private readonly openedBy;
|
|
115
|
+
private readonly lockTimeoutMs;
|
|
116
|
+
private readonly statementWaitMs;
|
|
117
|
+
private lockTimeoutFor;
|
|
118
|
+
private readonly attempts;
|
|
119
|
+
private readonly batchSize;
|
|
120
|
+
private readonly disconnectTimeoutMs;
|
|
121
|
+
private readonly log;
|
|
122
|
+
private readonly shadow;
|
|
123
|
+
constructor(pool: Pool, options?: MigratorOptions);
|
|
124
|
+
status(): Promise<Status>;
|
|
125
|
+
/**
|
|
126
|
+
* What start would do now, without doing it. A database Palgres has not
|
|
127
|
+
* migrated that holds the schema's tables is taken over first, as start
|
|
128
|
+
* takes it: held as declared, nothing changes; held otherwise, the plan is
|
|
129
|
+
* the difference from what it holds. Taking it over is read in a shadow
|
|
130
|
+
* database (MigratorOptions.shadow), made and dropped; the database itself
|
|
131
|
+
* is not written.
|
|
132
|
+
*/
|
|
133
|
+
plan(schema: Schema): Promise<Plan>;
|
|
134
|
+
/**
|
|
135
|
+
* Starts the migration to `schema`: when it returns, the new version can
|
|
136
|
+
* serve beside the one serving now. The same schema again resumes a start
|
|
137
|
+
* that stopped, or answers that it is in sync.
|
|
138
|
+
*/
|
|
139
|
+
start(schema: Schema): Promise<StartResult>;
|
|
140
|
+
/** Ends the open migration once nothing of the old version is connected: what only it used goes. */
|
|
141
|
+
complete(): Promise<{
|
|
142
|
+
state: 'completed';
|
|
143
|
+
version: number;
|
|
144
|
+
} | {
|
|
145
|
+
state: 'none';
|
|
146
|
+
}>;
|
|
147
|
+
/** Abandons the open migration once nothing of the new version is connected: what start added goes. */
|
|
148
|
+
rollback(): Promise<{
|
|
149
|
+
state: 'rolled-back';
|
|
150
|
+
version: number | null;
|
|
151
|
+
} | {
|
|
152
|
+
state: 'none';
|
|
153
|
+
}>;
|
|
154
|
+
private runStart;
|
|
155
|
+
private runComplete;
|
|
156
|
+
private runSteps;
|
|
157
|
+
private tx;
|
|
158
|
+
private settings;
|
|
159
|
+
private notTakenFirst;
|
|
160
|
+
private statement;
|
|
161
|
+
private backfill;
|
|
162
|
+
private highest;
|
|
163
|
+
private pagesPerBatch;
|
|
164
|
+
private pages;
|
|
165
|
+
private keyedBatch;
|
|
166
|
+
private pageBatch;
|
|
167
|
+
private retrying;
|
|
168
|
+
private waitGone;
|
|
169
|
+
private adopt;
|
|
170
|
+
private made;
|
|
171
|
+
private planFrom;
|
|
172
|
+
private checkedDomain;
|
|
173
|
+
private casts;
|
|
174
|
+
private active;
|
|
175
|
+
private version;
|
|
176
|
+
private open;
|
|
177
|
+
private session;
|
|
178
|
+
private ownAuth;
|
|
179
|
+
private authRefusals;
|
|
180
|
+
private ensure;
|
|
181
|
+
}
|
|
182
|
+
/** The search_path of version n through its views: its views first, then the schema for the types and functions, pg_temp last (connect.ts). */
|
|
183
|
+
export declare function searchPath(n: number, schema?: string): string;
|
|
184
|
+
/**
|
|
185
|
+
* Whether a version's names are the tables' own: no table or column it
|
|
186
|
+
* reads is somewhere else. Then it reads and writes the tables directly; its
|
|
187
|
+
* views are needed only while a migration that renames or retypes is open.
|
|
188
|
+
*/
|
|
189
|
+
export declare function isDirect(layout: Plan['layout']): boolean;
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
export interface Schema {
|
|
2
|
+
tables: Table[];
|
|
3
|
+
enums: Enum[];
|
|
4
|
+
/** CREATE EXTENSION IF NOT EXISTS each; never dropped. */
|
|
5
|
+
extensions: string[];
|
|
6
|
+
/** Named SQL the typed schema cannot say (an expression unique index, a function): applied once by name. */
|
|
7
|
+
raw: Raw[];
|
|
8
|
+
}
|
|
9
|
+
export interface Table {
|
|
10
|
+
/** The Postgres schema; "public" unless given. */
|
|
11
|
+
schema: string;
|
|
12
|
+
name: string;
|
|
13
|
+
/** Its name in the version before this one: renamed, not dropped and created. */
|
|
14
|
+
renamedFrom?: string;
|
|
15
|
+
/** Kept, unseen by this version: the step before removing it, which is when its data may go. */
|
|
16
|
+
ignored?: boolean;
|
|
17
|
+
columns: Column[];
|
|
18
|
+
/** Column names; [] for a table without one. */
|
|
19
|
+
primaryKey: string[];
|
|
20
|
+
uniques: Unique[];
|
|
21
|
+
indexes: Index[];
|
|
22
|
+
checks: Check[];
|
|
23
|
+
foreignKeys: ForeignKey[];
|
|
24
|
+
/** Row-level security on: the app's roles see the rows its policies give them. */
|
|
25
|
+
rls: boolean;
|
|
26
|
+
policies: Policy[];
|
|
27
|
+
/** Semantic search over the table's rows: Palgres embeds `from` and keeps the vectors (search.ts). */
|
|
28
|
+
search?: Search;
|
|
29
|
+
}
|
|
30
|
+
export type SearchMetric = 'cosine' | 'euclidean' | 'inner_product';
|
|
31
|
+
/**
|
|
32
|
+
* A table's rows found by meaning and by word. `from` are the text columns a
|
|
33
|
+
* row is read by, in the order their text is joined; `model` and
|
|
34
|
+
* `dimensions` say how it is embedded. A row whose text changes is embedded
|
|
35
|
+
* again, and until then its old vector is gone (`null`) or still found (`keep`).
|
|
36
|
+
*/
|
|
37
|
+
export interface Search {
|
|
38
|
+
from: string[];
|
|
39
|
+
model: string;
|
|
40
|
+
dimensions: number;
|
|
41
|
+
metric: SearchMetric;
|
|
42
|
+
staleness: 'null' | 'keep';
|
|
43
|
+
}
|
|
44
|
+
export interface Column {
|
|
45
|
+
name: string;
|
|
46
|
+
/** A Postgres type, as canonicalType() writes it ("text", "timestamp with time zone", "numeric(10,2)", "public.mood"). */
|
|
47
|
+
type: string;
|
|
48
|
+
nullable: boolean;
|
|
49
|
+
/** An SQL expression. */
|
|
50
|
+
default?: string;
|
|
51
|
+
renamedFrom?: string;
|
|
52
|
+
ignored?: boolean;
|
|
53
|
+
/**
|
|
54
|
+
* An SQL expression over the row's columns for what is NULL — the rows
|
|
55
|
+
* already there and whatever an older version still writes — when the
|
|
56
|
+
* column becomes NOT NULL.
|
|
57
|
+
*/
|
|
58
|
+
fill?: string;
|
|
59
|
+
identity?: 'always' | 'by default';
|
|
60
|
+
/** GENERATED ALWAYS AS (expr), its value computed when read (virtual) or kept on disk (stored). */
|
|
61
|
+
generated?: {
|
|
62
|
+
expr: string;
|
|
63
|
+
stored: boolean;
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* The column holds a user's id. Users live in the platform, not here: when
|
|
67
|
+
* one is deleted, the app's rows of them go (cascade) or forget them (set
|
|
68
|
+
* null). `owns` marks the one column per table whose user the row belongs to.
|
|
69
|
+
*/
|
|
70
|
+
user?: {
|
|
71
|
+
onDelete: 'cascade' | 'set null';
|
|
72
|
+
owns: boolean;
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
export interface Unique {
|
|
76
|
+
name: string;
|
|
77
|
+
columns: string[];
|
|
78
|
+
}
|
|
79
|
+
export interface Index {
|
|
80
|
+
name: string;
|
|
81
|
+
keys: IndexKey[];
|
|
82
|
+
unique: boolean;
|
|
83
|
+
/** A partial index's predicate, in SQL. */
|
|
84
|
+
where?: string;
|
|
85
|
+
method?: 'btree' | 'hash' | 'gin' | 'gist' | 'brin';
|
|
86
|
+
include?: string[];
|
|
87
|
+
}
|
|
88
|
+
export type IndexKey = {
|
|
89
|
+
column: string;
|
|
90
|
+
desc?: boolean;
|
|
91
|
+
nulls?: 'first' | 'last';
|
|
92
|
+
} | {
|
|
93
|
+
expr: string;
|
|
94
|
+
desc?: boolean;
|
|
95
|
+
nulls?: 'first' | 'last';
|
|
96
|
+
};
|
|
97
|
+
export interface Check {
|
|
98
|
+
name: string;
|
|
99
|
+
expr: string;
|
|
100
|
+
}
|
|
101
|
+
export type FkAction = 'no action' | 'restrict' | 'cascade' | 'set null' | 'set default';
|
|
102
|
+
export interface ForeignKey {
|
|
103
|
+
name: string;
|
|
104
|
+
columns: string[];
|
|
105
|
+
refSchema: string;
|
|
106
|
+
refTable: string;
|
|
107
|
+
refColumns: string[];
|
|
108
|
+
onDelete: FkAction;
|
|
109
|
+
onUpdate: FkAction;
|
|
110
|
+
match?: 'simple' | 'full';
|
|
111
|
+
}
|
|
112
|
+
export interface Policy {
|
|
113
|
+
name: string;
|
|
114
|
+
for: 'all' | 'select' | 'insert' | 'update' | 'delete';
|
|
115
|
+
/** Role names as the schema writes them; the migrator maps them to the database's roles. */
|
|
116
|
+
to: string[];
|
|
117
|
+
using?: string;
|
|
118
|
+
withCheck?: string;
|
|
119
|
+
restrictive?: boolean;
|
|
120
|
+
}
|
|
121
|
+
export interface Enum {
|
|
122
|
+
schema: string;
|
|
123
|
+
name: string;
|
|
124
|
+
values: string[];
|
|
125
|
+
}
|
|
126
|
+
export interface Raw {
|
|
127
|
+
name: string;
|
|
128
|
+
/** The table it belongs to ("schema.table"), when it does. */
|
|
129
|
+
table?: string;
|
|
130
|
+
sql: string;
|
|
131
|
+
/** What takes it back when it leaves the schema (a schema-level unit's). */
|
|
132
|
+
drop?: string;
|
|
133
|
+
/** Made before the schema's tables — a domain, a type, a function a default calls (a schema-level unit's). */
|
|
134
|
+
before?: boolean;
|
|
135
|
+
/** The Postgres schema whose file declares it (a schema-level unit's): made if the schema has no table to make it. */
|
|
136
|
+
schema?: string;
|
|
137
|
+
}
|
|
138
|
+
export declare class SchemaError extends Error {
|
|
139
|
+
readonly problems: string[];
|
|
140
|
+
constructor(problems: string[]);
|
|
141
|
+
}
|
|
142
|
+
export declare const emptySchema: () => Schema;
|
|
143
|
+
export declare const tableKey: (t: {
|
|
144
|
+
schema: string;
|
|
145
|
+
name: string;
|
|
146
|
+
}) => string;
|
|
147
|
+
export declare function canonicalType(type: string): string;
|
|
148
|
+
/** An enum's type, as a column of it says its type: schema.name, a part quoted when its case is its own (Prisma's "Role"). */
|
|
149
|
+
export declare const enumTypeName: (schema: string, name: string) => string;
|
|
150
|
+
/** The extension a table's search keeps its vectors with. */
|
|
151
|
+
export declare const SEARCH_EXTENSION = "vector";
|
|
152
|
+
export declare const SEARCH_METRICS: readonly SearchMetric[];
|
|
153
|
+
/** What a declaration that names no dimensions embeds in. */
|
|
154
|
+
export declare const SEARCH_DEFAULT_DIMENSIONS = 1536;
|
|
155
|
+
/** pgvector indexes a vector of at most 2000 dimensions, and a half-precision one (halfvec) of at most 4000. */
|
|
156
|
+
export declare const SEARCH_VECTOR_DIMENSIONS = 2000;
|
|
157
|
+
export declare const SEARCH_MAX_DIMENSIONS = 4000;
|
|
158
|
+
/**
|
|
159
|
+
* What is wrong with a table's search declaration, each with what to write
|
|
160
|
+
* instead. `what` names the table as its reader knows it: its key in a
|
|
161
|
+
* schema, defineTable("…") where it is declared.
|
|
162
|
+
*/
|
|
163
|
+
export declare function searchProblems(what: string, t: {
|
|
164
|
+
columns: readonly Pick<Column, 'name' | 'type' | 'ignored' | 'generated'>[];
|
|
165
|
+
primaryKey: readonly string[];
|
|
166
|
+
}, s: Search): string[];
|
|
167
|
+
/** Every problem with a schema at once, or none. */
|
|
168
|
+
export declare function validate(schema: Schema): string[];
|
|
169
|
+
/** The schema in one order, every type canonical: what is compared and what the digest is of. */
|
|
170
|
+
export declare function normalize(schema: Schema): Schema;
|
|
171
|
+
/**
|
|
172
|
+
* The schema normalized, its raw units kept in the order they are declared:
|
|
173
|
+
* one may need another made first (a materialized view its view), and what
|
|
174
|
+
* goes, goes last first. What a version records; its digest is of normalize().
|
|
175
|
+
*/
|
|
176
|
+
export declare function normalizeKeepingRawOrder(schema: Schema): Schema;
|
|
177
|
+
/**
|
|
178
|
+
* What identifies a version: two schemas with one digest are one version.
|
|
179
|
+
* Column order is part of it — a version's views list columns as declared.
|
|
180
|
+
*/
|
|
181
|
+
export declare function digest(schema: Schema): string;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { type Raw, type Schema } from './model.js';
|
|
2
|
+
import { type SearchGeneration } from './search.js';
|
|
3
|
+
/** A version's names: each visible table and column of the schema, and where it is in the database. */
|
|
4
|
+
export interface Layout {
|
|
5
|
+
tables: {
|
|
6
|
+
schema: string;
|
|
7
|
+
name: string;
|
|
8
|
+
physical: string;
|
|
9
|
+
columns: {
|
|
10
|
+
name: string;
|
|
11
|
+
physical: string;
|
|
12
|
+
}[];
|
|
13
|
+
}[];
|
|
14
|
+
}
|
|
15
|
+
export type Step =
|
|
16
|
+
/** One transaction, under the migrator's lock timeout; tried again as a whole. */
|
|
17
|
+
{
|
|
18
|
+
kind: 'tx';
|
|
19
|
+
sql: string[];
|
|
20
|
+
why: string;
|
|
21
|
+
}
|
|
22
|
+
/** One statement outside a transaction: CONCURRENTLY, VALIDATE, ALTER TYPE … ADD VALUE. */
|
|
23
|
+
| {
|
|
24
|
+
kind: 'statement';
|
|
25
|
+
sql: string;
|
|
26
|
+
why: string;
|
|
27
|
+
}
|
|
28
|
+
/** UPDATE in batches until no row matches `where`, each its own short transaction. */
|
|
29
|
+
| {
|
|
30
|
+
kind: 'backfill';
|
|
31
|
+
table: string;
|
|
32
|
+
key: string[];
|
|
33
|
+
set: string;
|
|
34
|
+
where: string;
|
|
35
|
+
why: string;
|
|
36
|
+
};
|
|
37
|
+
export interface Plan {
|
|
38
|
+
from: number | null;
|
|
39
|
+
to: number;
|
|
40
|
+
/** What changes, a line each, for people. */
|
|
41
|
+
changes: string[];
|
|
42
|
+
/** What cannot be done this way, and what to do instead; a plan with any is not run. */
|
|
43
|
+
refusals: string[];
|
|
44
|
+
start: Step[];
|
|
45
|
+
complete: Step[];
|
|
46
|
+
rollback: Step[];
|
|
47
|
+
layout: Layout;
|
|
48
|
+
/** A database Palgres had not migrated, taken over first (Migrator.plan): what that changes itself, and what it leaves as it is. */
|
|
49
|
+
adoption?: Adoption;
|
|
50
|
+
}
|
|
51
|
+
/** A database taken over: what adoption changed itself, and what it left as it is. */
|
|
52
|
+
export interface Adoption {
|
|
53
|
+
/** Tables whose row-level security was FORCEd on their owner, as v2 made them: no longer. */
|
|
54
|
+
unforced: string[];
|
|
55
|
+
unmanaged: string[];
|
|
56
|
+
}
|
|
57
|
+
/** The database's roles a policy's names stand for. */
|
|
58
|
+
export interface Roles {
|
|
59
|
+
anon: string;
|
|
60
|
+
authenticated: string;
|
|
61
|
+
service: string;
|
|
62
|
+
}
|
|
63
|
+
export interface PlanInput {
|
|
64
|
+
/** The version serving now, or null for a database Palgres has not migrated yet. */
|
|
65
|
+
from: {
|
|
66
|
+
n: number;
|
|
67
|
+
schema: Schema;
|
|
68
|
+
} | null;
|
|
69
|
+
/** The new version's number: past every version the database has recorded, an abandoned one too. */
|
|
70
|
+
next: number;
|
|
71
|
+
to: Schema;
|
|
72
|
+
/** Tables of `from` that hold at least one row. */
|
|
73
|
+
hasRows: (tableKey: string) => boolean;
|
|
74
|
+
/**
|
|
75
|
+
* Whether Postgres casts a value of one type to the other (the types as the
|
|
76
|
+
* plan writes them in SQL), or undefined where it cannot tell — a type this
|
|
77
|
+
* deploy makes. A column whose type changes is kept in both by casts.
|
|
78
|
+
*/
|
|
79
|
+
castable: (from: string, to: string) => boolean | undefined;
|
|
80
|
+
/**
|
|
81
|
+
* Whether a type is a domain with a CHECK or NOT NULL (the type as the plan
|
|
82
|
+
* writes it), or undefined where it cannot tell: Postgres rewrites a table
|
|
83
|
+
* under a lock to add a column of one.
|
|
84
|
+
*/
|
|
85
|
+
checkedDomain: (type: string) => boolean | undefined;
|
|
86
|
+
roles: Roles;
|
|
87
|
+
/**
|
|
88
|
+
* The generations of search vectors the database holds for a table
|
|
89
|
+
* ("schema.table"), as palgres_search.generations says them; none where
|
|
90
|
+
* not given. A filling one becomes the one that serves only while no
|
|
91
|
+
* migrator runs and no migration is open (search.ts' promote), so what a
|
|
92
|
+
* start reads here is what its steps find.
|
|
93
|
+
*/
|
|
94
|
+
generations?: (tableKey: string) => SearchGeneration[];
|
|
95
|
+
/** The schema pgvector's types are in (default public, where the migration makes the extension). */
|
|
96
|
+
vectorSchema?: string;
|
|
97
|
+
}
|
|
98
|
+
export declare const versionSchema: (n: number, schema: string) => string;
|
|
99
|
+
export declare function plan(input: PlanInput): Plan;
|
|
100
|
+
/**
|
|
101
|
+
* The sequences a default takes its values from — `nextval('public.items_id_seq'::regclass)`,
|
|
102
|
+
* a serial column's. Palgres makes such a sequence before the column and
|
|
103
|
+
* hands it to the column (OWNED BY), as `serial` does.
|
|
104
|
+
*/
|
|
105
|
+
export declare function sequencesOf(expr: string | undefined): string[];
|
|
106
|
+
/** The index a raw unit makes, if its SQL is one CREATE INDEX: adoption compares it by this name. */
|
|
107
|
+
export declare function rawIndexName(r: Raw): string | undefined;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { SchemaUnit } from './units.js';
|
|
2
|
+
import { type Schema } from './model.js';
|
|
3
|
+
export interface Pulled {
|
|
4
|
+
/** File name (db/public.ts) → its source. */
|
|
5
|
+
files: Map<string, string>;
|
|
6
|
+
/** What a person should look at, one line each. */
|
|
7
|
+
notes: string[];
|
|
8
|
+
}
|
|
9
|
+
export declare function pullSchema(schema: Schema, options?: {
|
|
10
|
+
from?: string;
|
|
11
|
+
unmanaged?: readonly string[];
|
|
12
|
+
units?: readonly SchemaUnit[];
|
|
13
|
+
}): Pulled;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
export interface AdmissionLease {
|
|
2
|
+
queueMs: number;
|
|
3
|
+
release(): void;
|
|
4
|
+
}
|
|
5
|
+
/** Deployment settings, never something a query declares. */
|
|
6
|
+
export interface DatabaseAdmissionOptions {
|
|
7
|
+
/** Requests' transactions at once. */
|
|
8
|
+
concurrency: number;
|
|
9
|
+
/**
|
|
10
|
+
* Further transactions of requests already admitted, at once, beside
|
|
11
|
+
* `concurrency` (default: twice as many — a request holds at most two at
|
|
12
|
+
* once, its $asService transaction, open to its end, and an $atomic beside
|
|
13
|
+
* it — so no admitted request waits for this share on another's account).
|
|
14
|
+
* The pool holds concurrency + nestedConcurrency.
|
|
15
|
+
*/
|
|
16
|
+
nestedConcurrency?: number;
|
|
17
|
+
queueLimit?: number;
|
|
18
|
+
queueTimeoutMs?: number;
|
|
19
|
+
/** A signed top-level claim to take turns by instead of `sub`. */
|
|
20
|
+
tenantClaim?: string;
|
|
21
|
+
onReject?: (event: {
|
|
22
|
+
reason: 'full' | 'timeout' | 'cancelled';
|
|
23
|
+
active: number;
|
|
24
|
+
queued: number;
|
|
25
|
+
}) => void;
|
|
26
|
+
}
|
|
27
|
+
export declare class DatabaseAdmission {
|
|
28
|
+
readonly options: DatabaseAdmissionOptions;
|
|
29
|
+
private active;
|
|
30
|
+
private queued;
|
|
31
|
+
private tenants;
|
|
32
|
+
private pending;
|
|
33
|
+
private lastTenant?;
|
|
34
|
+
private accepted;
|
|
35
|
+
private rejected;
|
|
36
|
+
private readonly limit;
|
|
37
|
+
private readonly timeout;
|
|
38
|
+
private readonly nestedLimit;
|
|
39
|
+
private nestedActive;
|
|
40
|
+
private readonly nestedPending;
|
|
41
|
+
constructor(options: DatabaseAdmissionOptions);
|
|
42
|
+
/** How long a wait for a turn lasts before it is a 429: a request's own wait for its further transactions keeps the same deadline. */
|
|
43
|
+
get queueTimeoutMs(): number;
|
|
44
|
+
get snapshot(): {
|
|
45
|
+
active: number;
|
|
46
|
+
queued: number;
|
|
47
|
+
nested: {
|
|
48
|
+
active: number;
|
|
49
|
+
queued: number;
|
|
50
|
+
};
|
|
51
|
+
tenants: number;
|
|
52
|
+
accepted: number;
|
|
53
|
+
rejected: {
|
|
54
|
+
full: number;
|
|
55
|
+
timeout: number;
|
|
56
|
+
cancelled: number;
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
private nestedLease;
|
|
60
|
+
private acquireNested;
|
|
61
|
+
private rejection;
|
|
62
|
+
private take;
|
|
63
|
+
private drain;
|
|
64
|
+
/**
|
|
65
|
+
* A transaction's turn; `nested` for a further transaction of a request
|
|
66
|
+
* already admitted, `returning` for the next one of a request that gave its
|
|
67
|
+
* connection back meanwhile — at the head of its user's line, not refused
|
|
68
|
+
* as full.
|
|
69
|
+
*/
|
|
70
|
+
acquire(claims: Record<string, unknown>, signal?: AbortSignal, options?: {
|
|
71
|
+
nested?: boolean;
|
|
72
|
+
returning?: boolean;
|
|
73
|
+
}): Promise<AdmissionLease>;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* The one queue of a pool. Keyed by the driver object, so every database
|
|
77
|
+
* built on one pool — two versions of an app while a migration is open — waits
|
|
78
|
+
* in the same line; a second set of settings for it is refused.
|
|
79
|
+
*/
|
|
80
|
+
export declare function databaseAdmission(pool: object, options?: DatabaseAdmissionOptions): DatabaseAdmission;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { Binding } from '../connect.js';
|
|
2
|
+
import { type ColumnDef } from '../dsl/columns.js';
|
|
3
|
+
import { type SchemaDef } from '../dsl/schema.js';
|
|
4
|
+
import { type Relation } from './relations.js';
|
|
5
|
+
export interface Transform {
|
|
6
|
+
fromDb?: (v: unknown) => unknown;
|
|
7
|
+
toDb?: (v: unknown) => unknown;
|
|
8
|
+
}
|
|
9
|
+
export interface TableInfo {
|
|
10
|
+
/** Bare in public, "schema.table" otherwise. */
|
|
11
|
+
key: string;
|
|
12
|
+
schema: string;
|
|
13
|
+
name: string;
|
|
14
|
+
/** The relation as the engine's SQL names it. */
|
|
15
|
+
sql: string;
|
|
16
|
+
/** The columns this version sees, in declared order. */
|
|
17
|
+
columns: Map<string, ColumnDef>;
|
|
18
|
+
/** Declared, but not this version's to name. */
|
|
19
|
+
ignored: Set<string>;
|
|
20
|
+
primaryKey: string[];
|
|
21
|
+
/** The primary key when it is one column — what lock ordering and `has`/`with` correlate on. */
|
|
22
|
+
singleKey: string | null;
|
|
23
|
+
uniqueKeys: string[][];
|
|
24
|
+
transforms: Map<string, Transform>;
|
|
25
|
+
/** Columns only the database writes (an ALWAYS identity). */
|
|
26
|
+
databaseOnly: Set<string>;
|
|
27
|
+
relations: Relation[];
|
|
28
|
+
/** Projection lists by alias, made once. */
|
|
29
|
+
projections: Map<string, string>;
|
|
30
|
+
/** The table's search, when it declares one: its key in Palgres' search schema ("schema.table") and the columns its text is read from. */
|
|
31
|
+
search?: {
|
|
32
|
+
key: string;
|
|
33
|
+
from: readonly string[];
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export declare const quoteIdent: (name: string) => string;
|
|
37
|
+
/** A column's type as the engine reads it: the DSL's, an sqlType() as "sql:<type>". */
|
|
38
|
+
export declare function engineType(def: ColumnDef): string;
|
|
39
|
+
export declare class Catalog {
|
|
40
|
+
readonly version: number;
|
|
41
|
+
private readonly tables;
|
|
42
|
+
private readonly ignoredTables;
|
|
43
|
+
constructor(schemas: readonly SchemaDef[], binding: Binding);
|
|
44
|
+
/** A table of this version, or a refusal that names why it is not one. */
|
|
45
|
+
table(key: string, caller: string): TableInfo;
|
|
46
|
+
}
|
|
47
|
+
/** The expression that reads a column as its row type promises, or null when the driver's value already is that. */
|
|
48
|
+
export declare function typedResult(type: string | null, expr: string): string | null;
|
|
49
|
+
/** Whether a JSON-typed column: its value is written as JSON whatever JS value it is. */
|
|
50
|
+
export declare function isJsonType(type: string): boolean;
|