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,154 @@
|
|
|
1
|
+
import type { DatabaseDiagnostics } from './diagnostics.js';
|
|
2
|
+
import type { AtomicOptions, InsertManyOptions, Page, RawPageOptions } from './options.js';
|
|
3
|
+
import type { TxPlanBody, TxPlanResponse } from './tx-plan.js';
|
|
4
|
+
export interface FindManyOptions {
|
|
5
|
+
/** One ordering or an ordered list. `nulls` pins where NULLs go — Postgres' default changes with the direction. */
|
|
6
|
+
orderBy?: {
|
|
7
|
+
column: string;
|
|
8
|
+
direction?: 'asc' | 'desc';
|
|
9
|
+
nulls?: 'first' | 'last';
|
|
10
|
+
} | {
|
|
11
|
+
column: string;
|
|
12
|
+
direction?: 'asc' | 'desc';
|
|
13
|
+
nulls?: 'first' | 'last';
|
|
14
|
+
}[];
|
|
15
|
+
/** Only these columns; an unknown name is refused before SQL. */
|
|
16
|
+
select?: string[];
|
|
17
|
+
/** Related rows too, in the same statement (LATERAL): `has` filters through a relation, `with` fetches it. */
|
|
18
|
+
with?: Record<string, unknown>;
|
|
19
|
+
limit?: number;
|
|
20
|
+
/** Only with `limit`: an offset into an unbounded result is not a page. */
|
|
21
|
+
offset?: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* A row lock, held until the transaction ends: `update` FOR UPDATE (the row
|
|
25
|
+
* is about to change or go), `noKeyUpdate` FOR NO KEY UPDATE (it changes,
|
|
26
|
+
* its key stays — what updateMany takes), `share` FOR SHARE (it must not
|
|
27
|
+
* change while this transaction reads on). Postgres applies the table's
|
|
28
|
+
* UPDATE policies to a locking read, so a row the caller may read but not
|
|
29
|
+
* update is not returned locked.
|
|
30
|
+
*/
|
|
31
|
+
export type RowLock = 'update' | 'share' | 'noKeyUpdate';
|
|
32
|
+
/** How a table's rows are searched. */
|
|
33
|
+
export interface SearchOptions {
|
|
34
|
+
/** How many rows at most (default 20; 1 to 100). */
|
|
35
|
+
limit?: number;
|
|
36
|
+
/** Only rows this filter matches — findMany's filter. */
|
|
37
|
+
where?: Record<string, unknown>;
|
|
38
|
+
/** "hybrid" (default): by meaning and by word, fused; "text": by word alone; "vector": by meaning alone. */
|
|
39
|
+
mode?: 'hybrid' | 'text' | 'vector';
|
|
40
|
+
/** Only rows whose _score is at least this. */
|
|
41
|
+
minScore?: number;
|
|
42
|
+
}
|
|
43
|
+
/** The operations a request's transaction, a savepoint and an $atomic scope all have. */
|
|
44
|
+
export interface DBOps {
|
|
45
|
+
/** Null unless the request asked for diagnostics or a budget. Parameter values are never in it. */
|
|
46
|
+
diagnostics(): DatabaseDiagnostics | null;
|
|
47
|
+
/** One row by exactly one declared unique key; null never stands for a unique value. With `lock`, the row is locked in the same statement, until the transaction ends. */
|
|
48
|
+
findUnique(table: string, where: Record<string, unknown>, opts?: {
|
|
49
|
+
select?: readonly string[];
|
|
50
|
+
with?: Record<string, unknown>;
|
|
51
|
+
lock?: RowLock;
|
|
52
|
+
}): Promise<Record<string, unknown> | null>;
|
|
53
|
+
/** Keyset pagination: opaque cursors sealed to the query and the caller, a unique ordering. */
|
|
54
|
+
page(table: string, query?: Record<string, unknown>, opts?: RawPageOptions): Promise<Page<Record<string, unknown>>>;
|
|
55
|
+
/**
|
|
56
|
+
* Raw SQL on this transaction — the request's own, a savepoint's or an
|
|
57
|
+
* $atomic scope's. Not read-only: a write here commits with it, and what
|
|
58
|
+
* stands between it and the data is RLS and the role. Parameters are $1…$n;
|
|
59
|
+
* an array of scalars is a Postgres array (`= ANY($1::uuid[])`), an object
|
|
60
|
+
* is JSON, JSON text for a jsonb parameter is that JSON. Rows are plain
|
|
61
|
+
* objects; bigint and numeric are strings, a timestamp an ISO string.
|
|
62
|
+
* Without a type argument the rows are `unknown`: only the author knows
|
|
63
|
+
* what raw SQL returns.
|
|
64
|
+
*/
|
|
65
|
+
query<T = unknown>(sql: string, params?: unknown[]): Promise<T[]>;
|
|
66
|
+
insert(table: string, data: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
67
|
+
/**
|
|
68
|
+
* sum/avg (always text: exact), min/max, count, optionally grouped. `count`
|
|
69
|
+
* is `true` for the rows, or named filters — `{ open: { done: false } }` —
|
|
70
|
+
* each counted in the same statement (count(*) FILTER (WHERE …)).
|
|
71
|
+
*/
|
|
72
|
+
aggregate(table: string, q: {
|
|
73
|
+
where?: Record<string, unknown>;
|
|
74
|
+
sum?: readonly string[];
|
|
75
|
+
avg?: readonly string[];
|
|
76
|
+
min?: readonly string[];
|
|
77
|
+
max?: readonly string[];
|
|
78
|
+
count?: boolean | Readonly<Record<string, Record<string, unknown>>>;
|
|
79
|
+
groupBy?: readonly string[];
|
|
80
|
+
}): Promise<Record<string, unknown> | Record<string, unknown>[]>;
|
|
81
|
+
/** Many rows, ONE statement; every row has the same keys — the column list is shared. `action: "ignore"` alone skips a row that collides with any unique key. */
|
|
82
|
+
insertMany(table: string, rows: readonly Record<string, unknown>[], opts: InsertManyOptions & {
|
|
83
|
+
returning: false;
|
|
84
|
+
}): Promise<number>;
|
|
85
|
+
insertMany(table: string, rows: readonly Record<string, unknown>[], opts?: InsertManyOptions & {
|
|
86
|
+
returning?: true;
|
|
87
|
+
}): Promise<Record<string, unknown>[]>;
|
|
88
|
+
insertMany(table: string, rows: readonly Record<string, unknown>[], opts?: InsertManyOptions): Promise<Record<string, unknown>[] | number>;
|
|
89
|
+
/** Insert, or update on a collision of `onConflict` — one statement, so two racing callers cannot both lose. */
|
|
90
|
+
put(table: string, data: Record<string, unknown>, opts: {
|
|
91
|
+
onConflict: readonly string[];
|
|
92
|
+
}): Promise<Record<string, unknown>>;
|
|
93
|
+
/** The row with this id updated, or null when none matched (absent, or hidden by RLS). */
|
|
94
|
+
update(table: string, id: string, data: Record<string, unknown>): Promise<Record<string, unknown> | null>;
|
|
95
|
+
delete(table: string, id: string): Promise<void>;
|
|
96
|
+
findById(table: string, id: string): Promise<Record<string, unknown> | null>;
|
|
97
|
+
/**
|
|
98
|
+
* Every row the filter matches, updated in one statement; an empty filter is
|
|
99
|
+
* refused. Zero rows is neither an error nor a success: with the condition
|
|
100
|
+
* in `where` (`{ id, balance: { gte: amount } }`), the returned array is the
|
|
101
|
+
* only thing that says whether it applied.
|
|
102
|
+
*/
|
|
103
|
+
updateMany(table: string, where: Record<string, unknown>, set: Record<string, unknown>, opts?: {
|
|
104
|
+
returning?: boolean;
|
|
105
|
+
}): Promise<Record<string, unknown>[] | number>;
|
|
106
|
+
/**
|
|
107
|
+
* Claims an idempotency key: `{ inserted: true }` this call wrote the row,
|
|
108
|
+
* `{ inserted: false, row }` someone did first and `row` is theirs — both
|
|
109
|
+
* successes. `unique` finds the row, `extra` is only written.
|
|
110
|
+
*/
|
|
111
|
+
claim(table: string, unique: Record<string, unknown>, extra?: Record<string, unknown>): Promise<{
|
|
112
|
+
inserted: boolean;
|
|
113
|
+
row: Record<string, unknown>;
|
|
114
|
+
}>;
|
|
115
|
+
/** Locks these rows in an order the engine sets (by primary key), not the caller's: two callers cannot take them in opposite orders. */
|
|
116
|
+
lockRows(table: string, ids: readonly string[]): Promise<void>;
|
|
117
|
+
/** Locks the rows a filter matches, selected and locked in one statement, ordered by primary key. An empty filter is refused. */
|
|
118
|
+
lockRowsWhere(table: string, where: Record<string, unknown>, opts?: {
|
|
119
|
+
mode?: RowLock;
|
|
120
|
+
}): Promise<void>;
|
|
121
|
+
/** Locks a NAME, not a row, until this transaction ends — "one invoice run at a time". Never session-scoped: that would outlive the request. */
|
|
122
|
+
advisoryXactLock(key: string): Promise<void>;
|
|
123
|
+
/** Deletes every row the filter matches; how many. An empty filter is refused. */
|
|
124
|
+
deleteMany(table: string, where: Record<string, unknown>): Promise<number>;
|
|
125
|
+
/** How many rows match; an empty filter counts the table. */
|
|
126
|
+
count(table: string, where?: Record<string, unknown>): Promise<number>;
|
|
127
|
+
findMany(table: string, query?: Record<string, unknown>, opts?: FindManyOptions): Promise<Record<string, unknown>[]>;
|
|
128
|
+
/**
|
|
129
|
+
* The rows of a table that declares search nearest to `query` — by meaning
|
|
130
|
+
* (its embedding against the rows') and by word (full text), fused — each
|
|
131
|
+
* with its `_score`, best first. It runs as the caller: a row their
|
|
132
|
+
* policies hide is never found. A row not embedded yet is found by its
|
|
133
|
+
* words; when the query cannot be embedded, so is every row ("hybrid").
|
|
134
|
+
*/
|
|
135
|
+
search(table: string, query: string, opts?: SearchOptions): Promise<(Record<string, unknown> & {
|
|
136
|
+
_score: number;
|
|
137
|
+
})[]>;
|
|
138
|
+
}
|
|
139
|
+
export interface DBClient extends DBOps {
|
|
140
|
+
/** An independent transaction: resolves after its COMMIT, retries the whole callback on a fresh one. One identity throughout. */
|
|
141
|
+
atomic<T>(fn: (tx: AtomicClient) => Promise<T>, options?: AtomicOptions): Promise<T>;
|
|
142
|
+
/** A plan (`$transaction`) run on this transaction inside one savepoint. */
|
|
143
|
+
txPlan(plan: TxPlanBody): Promise<TxPlanResponse>;
|
|
144
|
+
/**
|
|
145
|
+
* `fn` in a SAVEPOINT of this transaction: a failure in it rolls back only
|
|
146
|
+
* what its handle wrote. The handle is a parameter, not an ambient swap — a
|
|
147
|
+
* concurrent Promise.all branch's writes must stay outside the boundary.
|
|
148
|
+
*/
|
|
149
|
+
attempt<T>(fn: (tx: DBOps) => Promise<T>): Promise<T>;
|
|
150
|
+
/** The same operations as service_role, which passes row-level security — its own transaction on its own connection. No asService of its own. */
|
|
151
|
+
asService(): Omit<DBClient, 'asService'>;
|
|
152
|
+
}
|
|
153
|
+
/** A root transaction cannot change identity or open another root. */
|
|
154
|
+
export type AtomicClient = Omit<DBClient, 'asService' | 'atomic'>;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { carryMark, isData, isValue, markData, markRows } from '../../../internal/src/data.js';
|
|
2
|
+
/**
|
|
3
|
+
* The 400 for data where structure goes. `field` is where in the call it
|
|
4
|
+
* stood (`where.token`, `orderBy`); the words reach the caller, so they name
|
|
5
|
+
* the field, never the table.
|
|
6
|
+
*/
|
|
7
|
+
export declare function refuseDataAsStructure(v: unknown, field: string, what: string): void;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
export interface DatabaseBudget {
|
|
2
|
+
/** Statements, failed ones and retries included. */
|
|
3
|
+
maxQueries?: number;
|
|
4
|
+
/** Rows returned; nested relation rows count in bytes. */
|
|
5
|
+
maxRows?: number;
|
|
6
|
+
/** Estimated JSON bytes of the results — not protocol traffic. */
|
|
7
|
+
maxBytes?: number;
|
|
8
|
+
}
|
|
9
|
+
export interface DatabaseQueryEvent {
|
|
10
|
+
ordinal: number;
|
|
11
|
+
fingerprint: string;
|
|
12
|
+
name?: string;
|
|
13
|
+
sql?: string;
|
|
14
|
+
source?: string;
|
|
15
|
+
durationMs: number;
|
|
16
|
+
rows: number;
|
|
17
|
+
bytes: number;
|
|
18
|
+
errorCode?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface DatabaseDiagnostics {
|
|
21
|
+
endpoint?: string;
|
|
22
|
+
requestId?: string;
|
|
23
|
+
outcome: 'active' | 'committed' | 'failed';
|
|
24
|
+
elapsedMs: number;
|
|
25
|
+
queries: number;
|
|
26
|
+
rows: number;
|
|
27
|
+
bytes: number;
|
|
28
|
+
queueMs: number;
|
|
29
|
+
/** Until the driver's transaction callback starts; includes BEGIN. */
|
|
30
|
+
poolMs: number;
|
|
31
|
+
/** From the transaction callback through the acknowledged COMMIT/ROLLBACK. */
|
|
32
|
+
connectionMs?: number;
|
|
33
|
+
setupMs: number;
|
|
34
|
+
/** Waiting on the driver: Postgres' execution, locks, the network. */
|
|
35
|
+
sqlMs: number;
|
|
36
|
+
commitMs: number;
|
|
37
|
+
rollbackMs: number;
|
|
38
|
+
commits: number;
|
|
39
|
+
commitFailures: number;
|
|
40
|
+
rollbackRequests: number;
|
|
41
|
+
retries: number;
|
|
42
|
+
/** The first 200 statements; the totals count every one. */
|
|
43
|
+
statements: readonly DatabaseQueryEvent[];
|
|
44
|
+
}
|
|
45
|
+
export interface DatabaseDiagnosticsOptions extends DatabaseBudget {
|
|
46
|
+
endpoint?: string;
|
|
47
|
+
requestId?: string;
|
|
48
|
+
/** A stack capture costs work on every statement, so it is asked for. */
|
|
49
|
+
captureSource?: boolean;
|
|
50
|
+
/** Parameters are never recorded; raw SQL text can carry inline literals. */
|
|
51
|
+
includeSql?: boolean;
|
|
52
|
+
onQuery?: (event: DatabaseQueryEvent) => void | Promise<void>;
|
|
53
|
+
onComplete?: (diagnostics: DatabaseDiagnostics) => void | Promise<void>;
|
|
54
|
+
}
|
|
55
|
+
type Timing = 'queueMs' | 'poolMs' | 'setupMs' | 'sqlMs' | 'commitMs' | 'rollbackMs' | 'connectionMs';
|
|
56
|
+
export declare class DatabaseTrace {
|
|
57
|
+
private readonly start;
|
|
58
|
+
private readonly options;
|
|
59
|
+
private ended?;
|
|
60
|
+
private failure?;
|
|
61
|
+
private readonly state;
|
|
62
|
+
constructor(options: DatabaseDiagnosticsOptions);
|
|
63
|
+
check(): void;
|
|
64
|
+
time(key: Timing, started: number): void;
|
|
65
|
+
retry(): void;
|
|
66
|
+
committed(): void;
|
|
67
|
+
commitFailed(): void;
|
|
68
|
+
failed(): void;
|
|
69
|
+
rolledBack(): void;
|
|
70
|
+
private refuse;
|
|
71
|
+
private emit;
|
|
72
|
+
query(sql: string, run: () => PromiseLike<unknown>): Promise<unknown>;
|
|
73
|
+
get snapshot(): DatabaseDiagnostics;
|
|
74
|
+
complete(outcome: 'committed' | 'failed'): void;
|
|
75
|
+
}
|
|
76
|
+
export {};
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
/** A statement in flight. */
|
|
2
|
+
export type Statement = PromiseLike<unknown>;
|
|
3
|
+
/** What the engine says of a statement it wrote itself. */
|
|
4
|
+
export interface StatementHint {
|
|
5
|
+
/**
|
|
6
|
+
* Every $n in the text is the engine's own placeholder, and no part of the
|
|
7
|
+
* text came from outside the engine: the statement may travel in the round
|
|
8
|
+
* trip that opens its transaction, its values as literals (inlineParams).
|
|
9
|
+
*/
|
|
10
|
+
inline?: boolean;
|
|
11
|
+
/**
|
|
12
|
+
* A plain read — a SELECT without a locking clause, no function the
|
|
13
|
+
* engine calls writes. A transaction of nothing else has nothing to commit.
|
|
14
|
+
*/
|
|
15
|
+
read?: boolean;
|
|
16
|
+
}
|
|
17
|
+
export interface SqlTx {
|
|
18
|
+
unsafe(sql: string, params?: unknown[], hint?: StatementHint): Statement;
|
|
19
|
+
savepoint<T>(fn: (sp: SqlTx) => Promise<T>): Promise<T>;
|
|
20
|
+
/**
|
|
21
|
+
* Gives the transaction's connection up: closed now, whatever is in flight
|
|
22
|
+
* on it — the server rolls back what it held — and never lent again; the
|
|
23
|
+
* transaction ends without a word more on it. For a connection that stopped
|
|
24
|
+
* answering (control.ts' CANCEL_GRACE_MS). A driver that cannot close one
|
|
25
|
+
* connection of its pool has none.
|
|
26
|
+
*/
|
|
27
|
+
abandon?(): void;
|
|
28
|
+
}
|
|
29
|
+
/** How a transaction starts. */
|
|
30
|
+
export interface Opening {
|
|
31
|
+
/** Statements separated by ";", without parameters: what the transaction runs first. */
|
|
32
|
+
sql: string;
|
|
33
|
+
/** Gets the rows of the opening's last statement, before any statement after it is answered. */
|
|
34
|
+
opened?(rows: Record<string, unknown>[]): void;
|
|
35
|
+
/**
|
|
36
|
+
* A name of its own for the round trip that carries the opening, said in
|
|
37
|
+
* it as a comment: cancelOpening(tag) stops that round trip while it runs,
|
|
38
|
+
* before its backend is known by anything else.
|
|
39
|
+
*/
|
|
40
|
+
tag?: string;
|
|
41
|
+
}
|
|
42
|
+
export interface SqlDriver {
|
|
43
|
+
/**
|
|
44
|
+
* A statement on its own. It goes on a connection that has just answered,
|
|
45
|
+
* and once: a connection the server closed while it sat idle in the pool —
|
|
46
|
+
* a database that slept, restarted or moved (a switchover terminates every
|
|
47
|
+
* backend, 57P01) — is dropped before the statement is sent, and another
|
|
48
|
+
* taken; a connection lost after it was sent is the statement's failure,
|
|
49
|
+
* never a second run.
|
|
50
|
+
*/
|
|
51
|
+
unsafe(sql: string, params?: unknown[]): Statement;
|
|
52
|
+
/**
|
|
53
|
+
* A transaction: commits when `fn` resolves, rolls back when it rejects.
|
|
54
|
+
* It runs `opening` first, in as few round trips as the driver can: Bun's
|
|
55
|
+
* sends it with the BEGIN, and with the transaction's first statement when
|
|
56
|
+
* the engine wrote that one (StatementHint) — one round trip for all three.
|
|
57
|
+
*/
|
|
58
|
+
begin<T>(fn: (tx: SqlTx) => Promise<T>, opening?: Opening): Promise<T>;
|
|
59
|
+
/**
|
|
60
|
+
* Cancels one backend's statement through a connection of its own. The
|
|
61
|
+
* ticket names the backend (pid, backend_start) and its transaction
|
|
62
|
+
* (xact_start): a pooler hands the same server connection to the next
|
|
63
|
+
* client, and a late cancel must never reach that client's query.
|
|
64
|
+
*/
|
|
65
|
+
cancelBackend?(pid: number, startedAt: string, xactStartedAt: string): Promise<void>;
|
|
66
|
+
/** Cancels the round trip that opens a transaction, by its tag, while it runs: true when it found it running. */
|
|
67
|
+
cancelOpening?(tag: string): Promise<boolean>;
|
|
68
|
+
}
|
|
69
|
+
/** A parameter as the text Postgres reads, or null. */
|
|
70
|
+
export declare function encodeParam(value: unknown): string | null;
|
|
71
|
+
/** A JS array as a Postgres array literal. Unquoted NULL is the null element; "NULL" would be the four-letter string. */
|
|
72
|
+
export declare function encodePgArray(value: readonly unknown[]): string;
|
|
73
|
+
/**
|
|
74
|
+
* postgres.js' `types` option for a pool the engine uses: postgres.js
|
|
75
|
+
* serializes a parameter by the type the server describes, and its json,
|
|
76
|
+
* boolean, date and bytea serializers would re-encode the text the engine
|
|
77
|
+
* already wrote. Parsing (results) is postgres.js' own.
|
|
78
|
+
*/
|
|
79
|
+
export declare const POSTGRES_JS_TYPES: {
|
|
80
|
+
json: {
|
|
81
|
+
to: number;
|
|
82
|
+
from: number[];
|
|
83
|
+
serialize: (x: unknown) => unknown;
|
|
84
|
+
parse: (x: string) => unknown;
|
|
85
|
+
};
|
|
86
|
+
boolean: {
|
|
87
|
+
to: number;
|
|
88
|
+
from: number[];
|
|
89
|
+
serialize: (x: unknown) => unknown;
|
|
90
|
+
parse: (x: string) => x is "t";
|
|
91
|
+
};
|
|
92
|
+
date: {
|
|
93
|
+
to: number;
|
|
94
|
+
from: number[];
|
|
95
|
+
serialize: (x: unknown) => unknown;
|
|
96
|
+
parse: (x: string) => Date;
|
|
97
|
+
};
|
|
98
|
+
bytea: {
|
|
99
|
+
to: number;
|
|
100
|
+
from: number[];
|
|
101
|
+
serialize: (x: unknown) => unknown;
|
|
102
|
+
parse: (x: string) => Buffer<ArrayBuffer>;
|
|
103
|
+
};
|
|
104
|
+
};
|
|
105
|
+
/** Bun's SQL as the engine sees it (structural: this package does not depend on Bun's types). */
|
|
106
|
+
export interface BunPool {
|
|
107
|
+
unsafe(sql: string, params?: unknown[]): Statement;
|
|
108
|
+
reserve(): Promise<BunReserved>;
|
|
109
|
+
/**
|
|
110
|
+
* A connection it lent has none under it (bunSlotWithoutConnection), and
|
|
111
|
+
* nothing was sent on it. Told so, a pool that can (renewingBunPool) takes
|
|
112
|
+
* it back and opens itself anew. One that cannot — Bun's own — is not given
|
|
113
|
+
* it back: it would lend it again.
|
|
114
|
+
*/
|
|
115
|
+
discard?(reserved: BunReserved): void;
|
|
116
|
+
}
|
|
117
|
+
/** One of the pool's connections, held. */
|
|
118
|
+
export interface BunReserved {
|
|
119
|
+
unsafe(sql: string, params?: unknown[]): Statement & {
|
|
120
|
+
simple(): PromiseLike<unknown>;
|
|
121
|
+
};
|
|
122
|
+
/** Back to the pool, as it is. */
|
|
123
|
+
release(): void;
|
|
124
|
+
/** Closed: the pool opens another in its place. It waits for what is in flight on it unless told `timeout: 0`. */
|
|
125
|
+
close(options?: {
|
|
126
|
+
timeout?: number;
|
|
127
|
+
}): PromiseLike<unknown> | void;
|
|
128
|
+
}
|
|
129
|
+
/** The rows of a simple query's last statement: Bun answers several statements with one array per statement. */
|
|
130
|
+
export declare function lastRows(result: unknown): Record<string, unknown>[];
|
|
131
|
+
/**
|
|
132
|
+
* `text` with each $n as its value's literal: what lets a statement travel in
|
|
133
|
+
* a round trip that takes no parameters. Only for a statement the engine
|
|
134
|
+
* wrote (StatementHint.inline): its quotes are the engine's own — "…"
|
|
135
|
+
* identifiers, '…' and E'…' literals, every quote in them doubled — and its
|
|
136
|
+
* only $ are its placeholders, each bound once. Whatever else is in it — a
|
|
137
|
+
* comment, a second statement, a backslash, a $ that is no placeholder, a
|
|
138
|
+
* placeholder without a value or a value without one — answers undefined,
|
|
139
|
+
* and the statement goes on its own with its parameters. A value is an
|
|
140
|
+
* untyped literal, which Postgres reads as it reads an untyped parameter: by
|
|
141
|
+
* its context.
|
|
142
|
+
*/
|
|
143
|
+
export declare function inlineParams(text: string, params: readonly unknown[]): string | undefined;
|
|
144
|
+
/**
|
|
145
|
+
* Tries to open a transaction — or send a statement on its own — on a live
|
|
146
|
+
* connection. A server that closed the pool's connections leaves as many dead
|
|
147
|
+
* ones as the pool held, each failing at once: the next one is tried, up to
|
|
148
|
+
* this many — and so is a connection lent with none under it, each such
|
|
149
|
+
* counted among them. A connection that does not open says the database is
|
|
150
|
+
* not reachable: one more try, then the failure.
|
|
151
|
+
*/
|
|
152
|
+
export declare const OPEN_ATTEMPTS = 10;
|
|
153
|
+
export declare const OPEN_ATTEMPTS_UNREACHABLE = 2;
|
|
154
|
+
/**
|
|
155
|
+
* A Bun SQL pool as a driver. A transaction is a connection held for it
|
|
156
|
+
* (reserve), not Bun's begin(): Bun sends statements without prepared
|
|
157
|
+
* statements one round trip at a time, so the BEGIN, the transaction's
|
|
158
|
+
* opening and — when the engine wrote it — its first statement go as ONE
|
|
159
|
+
* simple query: a request of one statement is two round trips (that one and
|
|
160
|
+
* its COMMIT) where begin() takes four.
|
|
161
|
+
*
|
|
162
|
+
* Nothing is sent until the transaction's first statement. A connection the
|
|
163
|
+
* server had closed fails in that first round trip, and it is sent again on
|
|
164
|
+
* another: no COMMIT was in it, so whatever of it ran on a connection that
|
|
165
|
+
* was then lost is rolled back by the server.
|
|
166
|
+
*
|
|
167
|
+
* A statement on its own (unsafe) is a transaction of one, its BEGIN sent
|
|
168
|
+
* alone first. Bun's pool learns that the server closed an idle connection
|
|
169
|
+
* only when it reads the server's FATAL, and a statement given it before
|
|
170
|
+
* then fails with that FATAL (57P01) — the error a statement the server
|
|
171
|
+
* terminated while it ran gets too, so nothing in it says the statement did
|
|
172
|
+
* not run. The BEGIN is what meets the dead connection: it fails, the
|
|
173
|
+
* connection is dropped, and the statement goes on another. What fails after
|
|
174
|
+
* the statement went is its failure, never sent again — on its own it would
|
|
175
|
+
* have committed as it ended, and a nextval() is never rolled back. Two
|
|
176
|
+
* round trips more than the pool's own unsafe (the BEGIN, the COMMIT): it is
|
|
177
|
+
* the engine's checks and its cancels, never a request's statements.
|
|
178
|
+
*
|
|
179
|
+
* A connection Bun lent with no connection under it — the server ended it in
|
|
180
|
+
* the read that opened it (bunSlotWithoutConnection) — refuses the first
|
|
181
|
+
* round trip before anything is written. The round trip goes on another, and
|
|
182
|
+
* the pool is told (BunPool.discard): renewingBunPool opens itself anew, so
|
|
183
|
+
* that it lends its full count again. Bun's own pool cannot be told: the
|
|
184
|
+
* connection is kept, never given back — it would be lent again — and that
|
|
185
|
+
* pool lends one fewer from then on.
|
|
186
|
+
*
|
|
187
|
+
* The connection goes back to the pool only with its transaction ended: one
|
|
188
|
+
* released inside a transaction hands it to the next borrower (measured, Bun
|
|
189
|
+
* 1.4.2). One whose end did not answer is closed instead. `control`, a second
|
|
190
|
+
* small pool, carries cancellation: a cancel sent on the application pool
|
|
191
|
+
* would wait behind the statement it is meant to stop.
|
|
192
|
+
*/
|
|
193
|
+
export declare function bunDriver(pool: BunPool, control?: BunPool): SqlDriver;
|
|
194
|
+
/**
|
|
195
|
+
* How long a Bun pool's close() may take past its own timeout. Past its
|
|
196
|
+
* timeout it has closed every connection it holds, each telling the pool at
|
|
197
|
+
* once; what it may still wait for is a connection lent with none under it
|
|
198
|
+
* (bunSlotWithoutConnection), whose close never comes — there is no socket
|
|
199
|
+
* left to close.
|
|
200
|
+
*/
|
|
201
|
+
export declare const BUN_CLOSE_GRACE_MS = 1000;
|
|
202
|
+
/**
|
|
203
|
+
* Closes a Bun pool: its work given `timeout` seconds to end, then every
|
|
204
|
+
* connection closed — and settled by then, BUN_CLOSE_GRACE_MS later at the
|
|
205
|
+
* latest: Bun 1.4.2's close() never settles once it has lent a connection
|
|
206
|
+
* with none under it (oven-sh/bun#42804).
|
|
207
|
+
*/
|
|
208
|
+
export declare function closeBunPool(pool: {
|
|
209
|
+
close(options?: {
|
|
210
|
+
timeout?: number;
|
|
211
|
+
}): PromiseLike<unknown>;
|
|
212
|
+
}, timeout: number): Promise<void>;
|
|
213
|
+
/** Bun's SQL client as renewingBunPool opens it. */
|
|
214
|
+
export interface BunSqlPool extends BunPool {
|
|
215
|
+
close(options?: {
|
|
216
|
+
timeout?: number;
|
|
217
|
+
}): PromiseLike<unknown>;
|
|
218
|
+
}
|
|
219
|
+
/** A Bun pool that opens itself anew when it lent a connection with none under it. */
|
|
220
|
+
export interface RenewingBunPool<P extends BunSqlPool = BunSqlPool> extends BunPool {
|
|
221
|
+
/** The pool it lends from now. */
|
|
222
|
+
readonly current: P;
|
|
223
|
+
/** How many times it opened itself anew. */
|
|
224
|
+
readonly renewals: number;
|
|
225
|
+
discard(reserved: BunReserved): void;
|
|
226
|
+
/** Closes the pool it lends from and the ones it left, settled by `timeout` and BUN_CLOSE_GRACE_MS at the latest (closeBunPool). */
|
|
227
|
+
close(options?: {
|
|
228
|
+
timeout?: number;
|
|
229
|
+
}): Promise<void>;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* A Bun pool that stays whole when Bun's is not (Bun 1.4.2): told that a
|
|
233
|
+
* connection it lent has none under it (bunSlotWithoutConnection), it lends
|
|
234
|
+
* from then on from a pool it opens anew — `open()`, as many connections —
|
|
235
|
+
* and leaves the old one: that one lends nothing more, its connections lent
|
|
236
|
+
* go on to their end, and once they have it closes them all. The connection
|
|
237
|
+
* with none under it goes back to it, which is what it waits for. The pool
|
|
238
|
+
* Bun cannot mend is replaced, never shrunk: however many times it happens,
|
|
239
|
+
* the app has its full count of connections again, and no more than that
|
|
240
|
+
* beside the ones still at work in the pools it left.
|
|
241
|
+
*/
|
|
242
|
+
export declare function renewingBunPool<P extends BunSqlPool>(open: () => P): RenewingBunPool<P>;
|
|
243
|
+
/**
|
|
244
|
+
* cancelOpening through a pool of its own: the backend whose statement in
|
|
245
|
+
* flight starts with the tag's comment — this login's, in this database. A
|
|
246
|
+
* tag names one round trip, so a cancel that arrives late finds nothing: the
|
|
247
|
+
* backend is idle, or runs a statement that does not start with it.
|
|
248
|
+
*/
|
|
249
|
+
export declare function cancelOpeningThrough(control: {
|
|
250
|
+
unsafe(sql: string, params?: unknown[]): PromiseLike<unknown>;
|
|
251
|
+
}): NonNullable<SqlDriver['cancelOpening']>;
|
|
252
|
+
/**
|
|
253
|
+
* cancelBackend through a pool of its own (logged in as the app): it matches
|
|
254
|
+
* pid, backend_start AND xact_start, this login and this database — a ticket
|
|
255
|
+
* of a transaction that has ended cancels nothing.
|
|
256
|
+
*/
|
|
257
|
+
export declare function cancelBackendThrough(control: {
|
|
258
|
+
unsafe(sql: string, params?: unknown[]): PromiseLike<unknown>;
|
|
259
|
+
}): NonNullable<SqlDriver['cancelBackend']>;
|
|
260
|
+
export declare class DriverRefused extends Error {
|
|
261
|
+
constructor(what: string);
|
|
262
|
+
}
|
|
263
|
+
/** Asks Postgres what it received for each kind of text the engine sends, and refuses a driver that changed it. */
|
|
264
|
+
export declare function verifyDriver(sql: SqlDriver): Promise<void>;
|
|
265
|
+
/** What postgresJsDriver needs of postgres.js: its pool, as `postgres(url, { types: POSTGRES_JS_TYPES })` makes it. */
|
|
266
|
+
export interface PostgresJs {
|
|
267
|
+
unsafe(text: string, params?: unknown[]): PromiseLike<unknown> & {
|
|
268
|
+
simple(): PromiseLike<unknown>;
|
|
269
|
+
};
|
|
270
|
+
begin<T>(fn: (tx: PostgresJsTx) => Promise<T>): Promise<T>;
|
|
271
|
+
}
|
|
272
|
+
interface PostgresJsTx {
|
|
273
|
+
unsafe(text: string, params?: unknown[]): PromiseLike<unknown> & {
|
|
274
|
+
simple(): PromiseLike<unknown>;
|
|
275
|
+
};
|
|
276
|
+
savepoint<T>(fn: (tx: PostgresJsTx) => Promise<T>): Promise<T>;
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* postgres.js as the engine's driver: its transaction runs the opening after
|
|
280
|
+
* its own BEGIN, before the work — a round trip more than Bun's, the same
|
|
281
|
+
* transaction. `control`, a pool of one, is what a cancel goes through.
|
|
282
|
+
*
|
|
283
|
+
* postgres.js sends a statement on a connection whose close it has not read
|
|
284
|
+
* yet, and fails it then (CONNECTION_CLOSED). A transaction whose BEGIN or
|
|
285
|
+
* opening failed so — before the work was handed the transaction — goes on
|
|
286
|
+
* another connection; a statement on its own is a transaction of one, so
|
|
287
|
+
* the same holds for it. Nothing that reached the work is sent again.
|
|
288
|
+
*
|
|
289
|
+
* Once postgres.js has seen a transaction's connection close, nothing more
|
|
290
|
+
* is given to it. postgres.js 3.4.9 writes what it is given next — the
|
|
291
|
+
* ROLLBACK of the transaction the failure ended, its COMMIT, a statement —
|
|
292
|
+
* to the closed socket, and throws where no caller can catch it
|
|
293
|
+
* (porsager/postgres#1133): a Node app would stop on every transaction a
|
|
294
|
+
* database that moved cut. So a statement after the close is refused with
|
|
295
|
+
* it, and the transaction's end — or a savepoint's — is never asked for:
|
|
296
|
+
* postgres.js has already rejected the transaction's begin() with the close.
|
|
297
|
+
*/
|
|
298
|
+
export declare function postgresJsDriver(pool: PostgresJs, control: PostgresJs): SqlDriver;
|
|
299
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type SchemaDef } from '../dsl/schema.js';
|
|
2
|
+
/** The lines that wrap the generated block, so a tool can replace it in a file that holds more. */
|
|
3
|
+
export declare const ENV_BLOCK_START = "// palbase:env:begin";
|
|
4
|
+
export declare const ENV_BLOCK_END = "// palbase:env:end";
|
|
5
|
+
/**
|
|
6
|
+
* The palbase-env.d.ts text for a project's schemas (db/public.ts,
|
|
7
|
+
* db/billing.ts, …), augmenting `module`'s `Tables` and `Schemas`. It ends in
|
|
8
|
+
* `export {};`: without it the file is a global script and `declare module`
|
|
9
|
+
* there would DECLARE a module that shadows the real one instead of
|
|
10
|
+
* augmenting it.
|
|
11
|
+
*/
|
|
12
|
+
export declare function makeEnvDts(schemas: readonly SchemaDef[], options?: {
|
|
13
|
+
module?: string;
|
|
14
|
+
}): string;
|