@adrdp/pg-rest 0.1.3 → 0.2.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 +89 -134
- package/dist/adapters/bun.d.ts +1 -1
- package/dist/adapters/node-postgres.d.ts +1 -1
- package/dist/adapters/pglite.d.ts +1 -1
- package/dist/adapters/postgres-js.d.ts +1 -1
- package/dist/index.d.ts +642 -130
- package/dist/index.js +380 -648
- package/dist/schema-BhF_TQdX.js +669 -0
- package/dist/types-DaNxiC7H.d.ts +146 -0
- package/dist/types.d.ts +2 -0
- package/dist/types.js +202 -0
- package/package.json +7 -1
- /package/dist/{adapter-SqPs6SuJ.d.ts → adapter-C2udR5IT.d.ts} +0 -0
package/dist/index.d.ts
CHANGED
|
@@ -1,99 +1,64 @@
|
|
|
1
|
-
import { n as DbSession, r as Row, t as DbAdapter } from "./adapter-
|
|
1
|
+
import { n as DbSession, r as Row, t as DbAdapter } from "./adapter-C2udR5IT.js";
|
|
2
|
+
import { a as ForeignKey, c as SchemaCache, i as Column, o as FunctionDef, s as Relation, t as GenerateTypesOptions } from "./types-DaNxiC7H.js";
|
|
2
3
|
|
|
3
4
|
//#region src/parse/request.d.ts
|
|
4
5
|
type Method = "GET" | "HEAD" | "POST" | "PATCH" | "PUT" | "DELETE" | "OPTIONS";
|
|
5
6
|
//#endregion
|
|
6
|
-
//#region src/
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
readonly
|
|
13
|
-
|
|
14
|
-
readonly
|
|
15
|
-
readonly
|
|
16
|
-
readonly comment: string | null;
|
|
17
|
-
readonly position: number;
|
|
18
|
-
}
|
|
19
|
-
type RelationKind = "table" | "view" | "matview" | "foreign" | "partitioned";
|
|
20
|
-
interface Relation {
|
|
21
|
-
readonly schema: string;
|
|
22
|
-
readonly name: string;
|
|
23
|
-
readonly kind: RelationKind;
|
|
24
|
-
readonly columns: ReadonlyArray<Column>;
|
|
25
|
-
readonly pk: ReadonlyArray<string>;
|
|
26
|
-
readonly uniques: ReadonlyArray<ReadonlyArray<string>>;
|
|
27
|
-
readonly insertable: boolean;
|
|
28
|
-
readonly updatable: boolean;
|
|
29
|
-
readonly deletable: boolean;
|
|
30
|
-
readonly comment: string | null;
|
|
31
|
-
}
|
|
32
|
-
interface ForeignKey {
|
|
33
|
-
readonly name: string;
|
|
34
|
-
readonly schema: string;
|
|
35
|
-
readonly table: string;
|
|
36
|
-
readonly cols: ReadonlyArray<string>;
|
|
37
|
-
readonly fschema: string;
|
|
38
|
-
readonly ftable: string;
|
|
39
|
-
readonly fcols: ReadonlyArray<string>;
|
|
7
|
+
//#region src/errors.d.ts
|
|
8
|
+
/**
|
|
9
|
+
* Error body, in the exact shape PostgREST returns:
|
|
10
|
+
* `{ code, message, details, hint }`.
|
|
11
|
+
*/
|
|
12
|
+
interface ErrorBody {
|
|
13
|
+
readonly code: string;
|
|
14
|
+
readonly message: string;
|
|
15
|
+
readonly details: string | null;
|
|
16
|
+
readonly hint: string | null;
|
|
40
17
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Thrown by the pure parts of the library (parsers, SQL builders). It is
|
|
20
|
+
* converted into an {@link ApiError} at the request boundary.
|
|
21
|
+
*/
|
|
22
|
+
declare class PgRestError extends Error {
|
|
23
|
+
readonly status: number;
|
|
24
|
+
readonly code: string;
|
|
25
|
+
readonly details: string | null;
|
|
26
|
+
readonly hint: string | null;
|
|
27
|
+
readonly headers: Readonly<Record<string, string>>;
|
|
28
|
+
constructor(status: number, code: string, message: string, details?: string | null, hint?: string | null, headers?: Readonly<Record<string, string>>);
|
|
29
|
+
get body(): ErrorBody;
|
|
46
30
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
readonly
|
|
50
|
-
readonly
|
|
51
|
-
readonly
|
|
52
|
-
readonly
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
/** The table when the function's only parameter is a table row (computed relationships). */
|
|
59
|
-
readonly argRelation?: {
|
|
60
|
-
readonly schema: string;
|
|
61
|
-
readonly name: string;
|
|
62
|
-
};
|
|
63
|
-
/** The table whose rows the function returns. */
|
|
64
|
-
readonly returnRelation?: {
|
|
65
|
-
readonly schema: string;
|
|
66
|
-
readonly name: string;
|
|
67
|
-
};
|
|
68
|
-
/** Planner row estimate; 1 on a set-returning function makes a computed relationship to-one. */
|
|
69
|
-
readonly rows: number;
|
|
70
|
-
/** Scalar functions returning a domain named like a media type (`"text/plain"`, …): the raw value is the body. */
|
|
71
|
-
readonly returnMediaType?: {
|
|
72
|
-
readonly name: string;
|
|
73
|
-
readonly bytea: boolean;
|
|
74
|
-
};
|
|
31
|
+
/** An error that has already been mapped to an HTTP response. */
|
|
32
|
+
declare class ApiError extends Error {
|
|
33
|
+
readonly _tag = "ApiError";
|
|
34
|
+
readonly status: number;
|
|
35
|
+
readonly body: ErrorBody;
|
|
36
|
+
readonly headers: Readonly<Record<string, string>>;
|
|
37
|
+
constructor(fields: {
|
|
38
|
+
readonly status: number;
|
|
39
|
+
readonly body: ErrorBody;
|
|
40
|
+
readonly headers: Readonly<Record<string, string>>;
|
|
41
|
+
});
|
|
75
42
|
}
|
|
76
|
-
/**
|
|
77
|
-
interface
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
readonly
|
|
81
|
-
|
|
82
|
-
readonly
|
|
83
|
-
readonly schema: string;
|
|
84
|
-
readonly name: string;
|
|
85
|
-
};
|
|
86
|
-
/** True when the domain wraps `bytea` (the body is binary). */
|
|
87
|
-
readonly bytea: boolean;
|
|
43
|
+
/** Failure talking to the database, carrying Postgres error fields. */
|
|
44
|
+
interface DbErrorInfo {
|
|
45
|
+
/** SQLSTATE, e.g. "23505", or a custom code such as "PT401" / "PGRST". */
|
|
46
|
+
readonly sqlState: string;
|
|
47
|
+
readonly message: string;
|
|
48
|
+
readonly detail?: string | undefined;
|
|
49
|
+
readonly hint?: string | undefined;
|
|
88
50
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
readonly
|
|
92
|
-
readonly
|
|
93
|
-
readonly
|
|
94
|
-
|
|
51
|
+
/** Normalized error thrown by a {@link DbAdapter}. */
|
|
52
|
+
declare class DbQueryError extends Error implements DbErrorInfo {
|
|
53
|
+
readonly sqlState: string;
|
|
54
|
+
readonly detail?: string | undefined;
|
|
55
|
+
readonly hint?: string | undefined;
|
|
56
|
+
constructor(sqlState: string, message: string, detail?: string | undefined, hint?: string | undefined);
|
|
95
57
|
}
|
|
96
58
|
//#endregion
|
|
59
|
+
//#region src/sql/write.d.ts
|
|
60
|
+
type JsonObject = Record<string, unknown>;
|
|
61
|
+
//#endregion
|
|
97
62
|
//#region src/core.d.ts
|
|
98
63
|
/** Who is making the request, as far as the database is concerned. */
|
|
99
64
|
interface RequestContext {
|
|
@@ -113,7 +78,8 @@ interface PreRequestInfo {
|
|
|
113
78
|
readonly claims: Readonly<Record<string, unknown>>;
|
|
114
79
|
readonly method: Method;
|
|
115
80
|
readonly path: string;
|
|
116
|
-
|
|
81
|
+
/** The HTTP request, when the call came through `handle()`. In-process `query()` calls have none. */
|
|
82
|
+
readonly request?: Request | undefined;
|
|
117
83
|
}
|
|
118
84
|
interface CoreConfig {
|
|
119
85
|
readonly schemas: ReadonlyArray<string>;
|
|
@@ -134,56 +100,552 @@ interface CoreConfig {
|
|
|
134
100
|
readonly serverUrl?: string | undefined;
|
|
135
101
|
}
|
|
136
102
|
//#endregion
|
|
137
|
-
//#region src/
|
|
103
|
+
//#region src/query.d.ts
|
|
104
|
+
/** A value a filter compares against. */
|
|
105
|
+
type Scalar = string | number | boolean | null;
|
|
106
|
+
/** The PostgREST filter operators (https://docs.postgrest.org/en/v16/references/api/tables_views.html#operators). */
|
|
107
|
+
type FilterOp = "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "like" | "ilike" | "match" | "imatch" | "in" | "is" | "isdistinct" | "fts" | "plfts" | "phfts" | "wfts" | "cs" | "cd" | "ov" | "sl" | "sr" | "nxl" | "nxr" | "adj";
|
|
108
|
+
/** An operator with its modifiers: `not.`, a quantifier (`eq(any)`) or a text-search config (`fts(english)`). */
|
|
109
|
+
interface FilterSpec {
|
|
110
|
+
readonly op: FilterOp;
|
|
111
|
+
readonly value?: Scalar | ReadonlyArray<Scalar> | undefined;
|
|
112
|
+
/** Invert the operator (`not.eq.1`). */
|
|
113
|
+
readonly not?: boolean | undefined;
|
|
114
|
+
/** Apply the operator to every element of an array column (`eq(any)`). */
|
|
115
|
+
readonly quantifier?: "any" | "all" | undefined;
|
|
116
|
+
/** Text-search configuration: `{ op: "fts", config: "english", value: "cat" }` -> `fts(english).cat`. */
|
|
117
|
+
readonly config?: string | undefined;
|
|
118
|
+
}
|
|
138
119
|
/**
|
|
139
|
-
*
|
|
140
|
-
* `
|
|
120
|
+
* One condition. A plain value means `eq` (and `null` means `is.null`); a tuple is
|
|
121
|
+
* `[operator, value]`; the object form adds the modifiers.
|
|
141
122
|
*/
|
|
142
|
-
|
|
143
|
-
readonly code: string;
|
|
144
|
-
readonly message: string;
|
|
145
|
-
readonly details: string | null;
|
|
146
|
-
readonly hint: string | null;
|
|
147
|
-
}
|
|
123
|
+
type Filter = Scalar | readonly [FilterOp, Scalar | ReadonlyArray<Scalar>] | FilterSpec;
|
|
148
124
|
/**
|
|
149
|
-
*
|
|
150
|
-
*
|
|
125
|
+
* Conditions on columns, ANDed together, plus the reserved keys `and` and `or` which
|
|
126
|
+
* take a list of nested groups. A key may be a dotted path into an embedded resource
|
|
127
|
+
* (`"orders.total"`), exactly like the query string.
|
|
151
128
|
*/
|
|
152
|
-
|
|
129
|
+
interface Where {
|
|
130
|
+
readonly [column: string]: Filter | ReadonlyArray<Where> | undefined;
|
|
131
|
+
}
|
|
132
|
+
/** `"created"`, or the object form for a direction and null placement. */
|
|
133
|
+
type Order = string | {
|
|
134
|
+
readonly column: string;
|
|
135
|
+
readonly desc?: boolean | undefined;
|
|
136
|
+
readonly nulls?: "first" | "last" | undefined;
|
|
137
|
+
};
|
|
138
|
+
/** Columns to return. A string is a column (`"id"`, `"name->>first"`, `"total::text"`, `"label:name"`). */
|
|
139
|
+
type Select = ReadonlyArray<string | {
|
|
140
|
+
readonly [relation: string]: Select | Embed;
|
|
141
|
+
}>;
|
|
142
|
+
/** An embedded resource, with its own columns, filters, order and paging. */
|
|
143
|
+
interface Embed {
|
|
144
|
+
readonly select?: Select | undefined;
|
|
145
|
+
/** Drop parent rows that have no match (`!inner`). */
|
|
146
|
+
readonly inner?: boolean | undefined;
|
|
147
|
+
/** Merge the embedded columns into the parent row (`...rel(*)`). */
|
|
148
|
+
readonly spread?: boolean | undefined;
|
|
149
|
+
/** Disambiguate the relationship: a foreign key name, or the table to join through. */
|
|
150
|
+
readonly hint?: string | undefined;
|
|
151
|
+
/** Rename the resource in the output (`client:clients(*)`). */
|
|
152
|
+
readonly as?: string | undefined;
|
|
153
|
+
readonly where?: Where | undefined;
|
|
154
|
+
readonly order?: ReadonlyArray<Order> | undefined;
|
|
155
|
+
readonly limit?: number | undefined;
|
|
156
|
+
readonly offset?: number | undefined;
|
|
157
|
+
}
|
|
158
|
+
/** What a write returns: the affected rows, or nothing. */
|
|
159
|
+
type QueryReturning = "representation" | "minimal";
|
|
160
|
+
interface Common$1 {
|
|
161
|
+
/** One of the exposed schemas. Defaults to the first one. */
|
|
162
|
+
readonly schema?: string | undefined;
|
|
163
|
+
readonly select?: Select | undefined;
|
|
164
|
+
readonly where?: Where | undefined;
|
|
165
|
+
readonly order?: ReadonlyArray<Order> | undefined;
|
|
166
|
+
readonly limit?: number | undefined;
|
|
167
|
+
readonly offset?: number | undefined;
|
|
168
|
+
/** Return one object instead of an array. 0 or 2+ rows is a 406 `PGRST116`, like `vnd.pgrst.object+json`. */
|
|
169
|
+
readonly single?: boolean | undefined;
|
|
170
|
+
/** Also count the matching rows, ignoring paging (`Prefer: count=`). */
|
|
171
|
+
readonly count?: "exact" | "planned" | "estimated" | undefined;
|
|
172
|
+
/** Leave `null` fields out of the result (`nulls=stripped`). */
|
|
173
|
+
readonly stripNulls?: boolean | undefined;
|
|
174
|
+
/** Refuse the call if it would affect more rows than this (`Prefer: max-affected`). */
|
|
175
|
+
readonly maxAffected?: number | undefined;
|
|
176
|
+
/** Run the statement in this time zone (`Prefer: timezone=`). */
|
|
177
|
+
readonly timezone?: string | undefined;
|
|
178
|
+
}
|
|
179
|
+
/** Read rows from a table or view. */
|
|
180
|
+
interface SelectQuery extends Common$1 {
|
|
181
|
+
readonly table: string;
|
|
182
|
+
readonly action?: "select" | undefined;
|
|
183
|
+
}
|
|
184
|
+
/** Insert rows, or upsert them with `action: "upsert"`. */
|
|
185
|
+
interface InsertQuery extends Common$1 {
|
|
186
|
+
readonly table: string;
|
|
187
|
+
readonly action: "insert" | "upsert";
|
|
188
|
+
readonly rows: JsonObject | ReadonlyArray<JsonObject>;
|
|
189
|
+
/** Columns the conflict is resolved on (`on_conflict`). Defaults to the primary key. */
|
|
190
|
+
readonly onConflict?: ReadonlyArray<string> | undefined;
|
|
191
|
+
/** Only insert these columns, ignoring any other key in `rows`. */
|
|
192
|
+
readonly columns?: ReadonlyArray<string> | undefined;
|
|
193
|
+
/** What to do with columns missing from `rows`: their `DEFAULT` (the default) or `null`. */
|
|
194
|
+
readonly missing?: "default" | "null" | undefined;
|
|
195
|
+
readonly returning?: QueryReturning | undefined;
|
|
196
|
+
}
|
|
197
|
+
/** Update the rows matching `where`. */
|
|
198
|
+
interface UpdateQuery extends Common$1 {
|
|
199
|
+
readonly table: string;
|
|
200
|
+
readonly action: "update";
|
|
201
|
+
readonly set: JsonObject;
|
|
202
|
+
readonly returning?: QueryReturning | undefined;
|
|
203
|
+
}
|
|
204
|
+
/** Delete the rows matching `where`. */
|
|
205
|
+
interface DeleteQuery extends Common$1 {
|
|
206
|
+
readonly table: string;
|
|
207
|
+
readonly action: "delete";
|
|
208
|
+
readonly returning?: QueryReturning | undefined;
|
|
209
|
+
}
|
|
210
|
+
/** Call a function, like `POST /rpc/name`. `select`, `where` and `order` apply to its result. */
|
|
211
|
+
interface RpcQuery extends Common$1 {
|
|
212
|
+
readonly rpc: string;
|
|
213
|
+
readonly args?: Readonly<Record<string, unknown>> | undefined;
|
|
214
|
+
}
|
|
215
|
+
type QueryInput = SelectQuery | InsertQuery | UpdateQuery | DeleteQuery | RpcQuery;
|
|
216
|
+
/** What a query returned. `count` is set only when it was asked for. */
|
|
217
|
+
interface QueryResult<T$1 = unknown> {
|
|
218
|
+
/** The rows, the single object when `single` is set, or `null` when there is no body. */
|
|
219
|
+
readonly data: T$1;
|
|
220
|
+
/** Rows matching the filters, ignoring `limit`/`offset`. */
|
|
221
|
+
readonly count?: number | undefined;
|
|
222
|
+
/** The status the same call would answer with over HTTP (201 after an insert, 204 after a minimal write...). */
|
|
153
223
|
readonly status: number;
|
|
154
|
-
readonly code: string;
|
|
155
|
-
readonly details: string | null;
|
|
156
|
-
readonly hint: string | null;
|
|
157
|
-
readonly headers: Readonly<Record<string, string>>;
|
|
158
|
-
constructor(status: number, code: string, message: string, details?: string | null, hint?: string | null, headers?: Readonly<Record<string, string>>);
|
|
159
|
-
get body(): ErrorBody;
|
|
160
224
|
}
|
|
161
|
-
/**
|
|
162
|
-
|
|
163
|
-
|
|
225
|
+
/**
|
|
226
|
+
* What a query returned, as a value instead of an exception: exactly one of `data` and `error`
|
|
227
|
+
* is set, so narrowing on `error` leaves `data` non-null.
|
|
228
|
+
*/
|
|
229
|
+
type QuerySafeResult<T$1 = unknown> = (QueryResult<T$1> & {
|
|
230
|
+
readonly error: null;
|
|
231
|
+
}) | {
|
|
232
|
+
readonly data: null;
|
|
233
|
+
readonly error: QueryError;
|
|
234
|
+
readonly count?: undefined;
|
|
235
|
+
/** The status the failure would have answered with over HTTP. */
|
|
164
236
|
readonly status: number;
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
readonly
|
|
237
|
+
};
|
|
238
|
+
/** A query that failed, with the PostgREST error body and the input that produced it. */
|
|
239
|
+
declare class QueryError extends ApiError {
|
|
240
|
+
readonly input: QueryInput;
|
|
241
|
+
constructor(input: QueryInput, api: ApiError, options?: {
|
|
242
|
+
readonly cause?: unknown;
|
|
171
243
|
});
|
|
172
244
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
245
|
+
//#endregion
|
|
246
|
+
//#region src/typed.d.ts
|
|
247
|
+
/**
|
|
248
|
+
* The types `generateTypes` emits, as constraints. They describe a database, not a query: see
|
|
249
|
+
* {@link TypedQuery} for what a call may say, and {@link QueryData} for what it returns.
|
|
250
|
+
*/
|
|
251
|
+
interface AnyRelation {
|
|
252
|
+
readonly row: Record<string, unknown>;
|
|
253
|
+
readonly insert: Record<string, unknown>;
|
|
254
|
+
readonly update: Record<string, unknown>;
|
|
255
|
+
readonly pk: ReadonlyArray<string>;
|
|
256
|
+
readonly insertable: boolean;
|
|
257
|
+
readonly updatable: boolean;
|
|
258
|
+
readonly deletable: boolean;
|
|
259
|
+
readonly rel: Record<string, {
|
|
260
|
+
readonly rel: string;
|
|
261
|
+
readonly to: "one" | "many";
|
|
262
|
+
}>;
|
|
180
263
|
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
readonly
|
|
184
|
-
readonly
|
|
185
|
-
|
|
186
|
-
|
|
264
|
+
interface AnySignature {
|
|
265
|
+
readonly args: unknown;
|
|
266
|
+
readonly returns: unknown;
|
|
267
|
+
readonly set: boolean;
|
|
268
|
+
}
|
|
269
|
+
interface AnySchema {
|
|
270
|
+
readonly relations: Record<string, AnyRelation>;
|
|
271
|
+
readonly functions: Record<string, ReadonlyArray<AnySignature>>;
|
|
272
|
+
}
|
|
273
|
+
/** What `createPgRest<Db>` expects: the type `generateTypes` exports. */
|
|
274
|
+
interface AnyDatabase {
|
|
275
|
+
readonly default: string;
|
|
276
|
+
readonly schemas: Record<string, AnySchema>;
|
|
277
|
+
}
|
|
278
|
+
type Schema<Db extends AnyDatabase> = keyof Db["schemas"] & string;
|
|
279
|
+
type Relations<Db extends AnyDatabase, S$1 extends Schema<Db>> = Db["schemas"][S$1]["relations"];
|
|
280
|
+
type Functions<Db extends AnyDatabase, S$1 extends Schema<Db>> = Db["schemas"][S$1]["functions"];
|
|
281
|
+
type Table<Db extends AnyDatabase, S$1 extends Schema<Db>> = keyof Relations<Db, S$1> & string;
|
|
282
|
+
type Row$1<Db extends AnyDatabase, S$1 extends Schema<Db>, T$1 extends Table<Db, S$1>> = Relations<Db, S$1>[T$1]["row"];
|
|
283
|
+
type Column$1<Db extends AnyDatabase, S$1 extends Schema<Db>, T$1 extends Table<Db, S$1>> = keyof Row$1<Db, S$1, T$1> & string;
|
|
284
|
+
type Embeds<Db extends AnyDatabase, S$1 extends Schema<Db>, T$1 extends Table<Db, S$1>> = Relations<Db, S$1>[T$1]["rel"];
|
|
285
|
+
/** The relation an embedded name points at, if it is one of this schema's. */
|
|
286
|
+
type Target<Db extends AnyDatabase, S$1 extends Schema<Db>, E$1> = E$1 extends {
|
|
287
|
+
rel: infer R;
|
|
288
|
+
} ? R extends Table<Db, S$1> ? R : never : never;
|
|
289
|
+
type UnionToIntersection<U$1> = (U$1 extends unknown ? (x: U$1) => void : never) extends ((x: infer I) => void) ? I : never;
|
|
290
|
+
/** Flatten an intersection into one object, so hovers and errors read as a plain row. */
|
|
291
|
+
type Flatten<T$1> = T$1 extends object ? { [K in keyof T$1]: T$1[K] } & {} : T$1;
|
|
292
|
+
/**
|
|
293
|
+
* One item of a `select`. Columns, `alias:column`, `*`, and embedded resources as
|
|
294
|
+
* `{ relation: [...] }` or `{ relation: { select, inner, limit, ... } }`.
|
|
295
|
+
*
|
|
296
|
+
* PostgREST's other string forms -- casts, JSON paths, aggregates -- are not described here: they
|
|
297
|
+
* change the type of the value or invent a column, and parsing them from a string literal would
|
|
298
|
+
* cost more than it gives. Use an untyped instance for those.
|
|
299
|
+
*/
|
|
300
|
+
type SelectItem<Db extends AnyDatabase, S$1 extends Schema<Db>, T$1 extends Table<Db, S$1>> = "*" | Column$1<Db, S$1, T$1> | `${string}:${Column$1<Db, S$1, T$1>}` | { readonly [E in keyof Embeds<Db, S$1, T$1>]?: Embed$1<Db, S$1, Target<Db, S$1, Embeds<Db, S$1, T$1>[E]>> };
|
|
301
|
+
type SelectList<Db extends AnyDatabase, S$1 extends Schema<Db>, T$1 extends Table<Db, S$1>> = ReadonlyArray<SelectItem<Db, S$1, T$1>>;
|
|
302
|
+
/** An embedded resource: its columns, or an object with its own filters and paging. */
|
|
303
|
+
type EmbedOptions<Db extends AnyDatabase, S$1 extends Schema<Db>, T$1 extends Table<Db, S$1>> = {
|
|
304
|
+
/** The columns of the embedded resource, and its own embeds. Defaults to all of them. */
|
|
305
|
+
readonly select?: SelectList<Db, S$1, T$1>;
|
|
306
|
+
/** `!inner`: drop the parent rows that have no match here. A to-one embed stops being nullable. */
|
|
307
|
+
readonly inner?: boolean;
|
|
308
|
+
/** Which relationship to follow, when more than one leads here: a foreign key name, or a table. */
|
|
309
|
+
readonly hint?: string;
|
|
310
|
+
/** Filters on the embedded rows, not on the parent's. */
|
|
311
|
+
readonly where?: Where$1<Db, S$1, T$1>;
|
|
312
|
+
/** How to sort the embedded rows. */
|
|
313
|
+
readonly order?: ReadonlyArray<Order$1<Db, S$1, T$1>>;
|
|
314
|
+
/** At most this many embedded rows per parent row. */
|
|
315
|
+
readonly limit?: number;
|
|
316
|
+
/** Skip this many embedded rows per parent row. */
|
|
317
|
+
readonly offset?: number;
|
|
318
|
+
};
|
|
319
|
+
/**
|
|
320
|
+
* An embedded resource: its columns, or the long form with its own filters and paging.
|
|
321
|
+
*
|
|
322
|
+
* `as` and `spread` are exclusive, because PostgREST's grammar has no way to write both:
|
|
323
|
+
* `...alias:table(*)` does not parse (`PGRST100`), so a type that accepted it would promise
|
|
324
|
+
* something the request cannot express.
|
|
325
|
+
*/
|
|
326
|
+
type Embed$1<Db extends AnyDatabase, S$1 extends Schema<Db>, T$1 extends Table<Db, S$1>> = SelectList<Db, S$1, T$1> | (EmbedOptions<Db, S$1, T$1> & {
|
|
327
|
+
/** Rename the resource in the result. The inferred key follows. */
|
|
328
|
+
readonly as?: string;
|
|
329
|
+
readonly spread?: never;
|
|
330
|
+
}) | (EmbedOptions<Db, S$1, T$1> & {
|
|
331
|
+
/**
|
|
332
|
+
* `...rel(*)`: merge these columns into the parent row instead of nesting them. Spreading a
|
|
333
|
+
* to-many relationship turns each column into an array of its values.
|
|
334
|
+
*/
|
|
335
|
+
readonly spread: true;
|
|
336
|
+
readonly as?: never;
|
|
337
|
+
});
|
|
338
|
+
/** The columns of `Items` picked out of a plain row, `alias:column` renamed, `*` taking them all. */
|
|
339
|
+
type PickedFrom<R$1, Items$1> = Items$1 extends ReadonlyArray<unknown> ? Flatten<UnionToIntersection<{ [I in keyof Items$1]: Items$1[I] extends "*" ? R$1 : Items$1[I] extends keyof R$1 & string ? { [K in Items$1[I]]: R$1[K] } : Items$1[I] extends `${infer A}:${infer C}` ? C extends keyof R$1 & string ? { [K in A]: R$1[C] } : unknown : unknown }[number]>> : R$1;
|
|
340
|
+
/** What a function's result may be asked for: its columns, if it has any. */
|
|
341
|
+
type RowSelect<R$1> = R$1 extends object ? ReadonlyArray<"*" | (keyof R$1 & string) | `${string}:${keyof R$1 & string}`> : never;
|
|
342
|
+
/** The row a `select` produces: the picked columns, the aliases renamed, the embeds nested. */
|
|
343
|
+
type Selected<Db extends AnyDatabase, S$1 extends Schema<Db>, T$1 extends Table<Db, S$1>, Items$1> = Items$1 extends ReadonlyArray<unknown> ? Flatten<UnionToIntersection<{ [I in keyof Items$1]: ItemOf<Db, S$1, T$1, Items$1[I]> }[number]>> : Row$1<Db, S$1, T$1>;
|
|
344
|
+
type ItemOf<Db extends AnyDatabase, S$1 extends Schema<Db>, T$1 extends Table<Db, S$1>, Item> = Item extends "*" ? Row$1<Db, S$1, T$1> : Item extends Column$1<Db, S$1, T$1> ? { [K in Item]: Row$1<Db, S$1, T$1>[K] } : Item extends `${infer A}:${infer C}` ? C extends Column$1<Db, S$1, T$1> ? { [K in A]: Row$1<Db, S$1, T$1>[C] } : unknown : Item extends object ? Embedded<Db, S$1, T$1, Item> : unknown;
|
|
345
|
+
/** Keys of an embed object that are spread into the parent, and the ones that stay nested. */
|
|
346
|
+
type SpreadKeys<Item> = { [E in keyof Item]: Item[E] extends {
|
|
347
|
+
spread: true;
|
|
348
|
+
} ? E : never }[keyof Item];
|
|
349
|
+
type NestedKeys<Item> = { [E in keyof Item]: Item[E] extends {
|
|
350
|
+
spread: true;
|
|
351
|
+
} ? never : E }[keyof Item];
|
|
352
|
+
/** One `{ relation: ... }` item: nested resources under their own key, spread ones merged in. */
|
|
353
|
+
type Embedded<Db extends AnyDatabase, S$1 extends Schema<Db>, T$1 extends Table<Db, S$1>, Item> = NestedPart<Db, S$1, T$1, Item> & SpreadPart<Db, S$1, T$1, Item>;
|
|
354
|
+
/**
|
|
355
|
+
* Each half is skipped when it has no keys: a key-remapped mapped type over an empty key set is not
|
|
356
|
+
* the empty object -- it carries a string index signature, which would spread to the whole row.
|
|
357
|
+
*/
|
|
358
|
+
type NestedPart<Db extends AnyDatabase, S$1 extends Schema<Db>, T$1 extends Table<Db, S$1>, Item> = [NestedKeys<Item>] extends [never] ? unknown : { [E in NestedKeys<Item> & keyof Item & keyof Embeds<Db, S$1, T$1> as Item[E] extends {
|
|
359
|
+
as: infer A extends string;
|
|
360
|
+
} ? A : E]: EmbedOf<Db, S$1, Target<Db, S$1, Embeds<Db, S$1, T$1>[E]>, Embeds<Db, S$1, T$1>[E], Item[E]> };
|
|
361
|
+
type SpreadPart<Db extends AnyDatabase, S$1 extends Schema<Db>, T$1 extends Table<Db, S$1>, Item> = [SpreadKeys<Item>] extends [never] ? unknown : UnionToIntersection<{ [E in SpreadKeys<Item> & keyof Item & keyof Embeds<Db, S$1, T$1>]: SpreadOf<Db, S$1, Target<Db, S$1, Embeds<Db, S$1, T$1>[E]>, Embeds<Db, S$1, T$1>[E], Item[E]> }[SpreadKeys<Item> & keyof Item & keyof Embeds<Db, S$1, T$1>]>;
|
|
362
|
+
/**
|
|
363
|
+
* A spread embed has no key of its own: its columns join the parent row. Spreading a to-many
|
|
364
|
+
* relationship turns each of them into an array of that column's values.
|
|
365
|
+
*/
|
|
366
|
+
type SpreadOf<Db extends AnyDatabase, S$1 extends Schema<Db>, T$1 extends Table<Db, S$1>, Rel, Spec> = Rel extends {
|
|
367
|
+
to: "many";
|
|
368
|
+
} ? Arrayed<SpreadRow<Db, S$1, T$1, Spec>> : SpreadRow<Db, S$1, T$1, Spec>;
|
|
369
|
+
type SpreadRow<Db extends AnyDatabase, S$1 extends Schema<Db>, T$1 extends Table<Db, S$1>, Spec> = Spec extends {
|
|
370
|
+
select: infer Items;
|
|
371
|
+
} ? Selected<Db, S$1, T$1, Items> : Row$1<Db, S$1, T$1>;
|
|
372
|
+
type Arrayed<R$1> = { [K in keyof R$1]: R$1[K][] };
|
|
373
|
+
type EmbedOf<Db extends AnyDatabase, S$1 extends Schema<Db>, T$1 extends Table<Db, S$1>, Rel, Spec> = Spec extends ReadonlyArray<unknown> ? Shaped<Rel, Spec, Selected<Db, S$1, T$1, Spec>> : Spec extends {
|
|
374
|
+
select: infer Items;
|
|
375
|
+
} ? Shaped<Rel, Spec, Selected<Db, S$1, T$1, Items>> : Shaped<Rel, Spec, Row$1<Db, S$1, T$1>>;
|
|
376
|
+
/**
|
|
377
|
+
* A to-many embed is an array. A to-one embed is the row, or null when there is no match -- unless
|
|
378
|
+
* the join is `inner`, which drops the parent rows that have none.
|
|
379
|
+
*/
|
|
380
|
+
type Shaped<Rel, Spec, R$1> = Rel extends {
|
|
381
|
+
to: "many";
|
|
382
|
+
} ? R$1[] : Spec extends {
|
|
383
|
+
inner: true;
|
|
384
|
+
} ? R$1 : R$1 | null;
|
|
385
|
+
/** A condition on a column: the value itself (`eq`), a `[operator, value]` tuple, or the full form. */
|
|
386
|
+
type Filter$1<V> = V | null | readonly [FilterOp, V | ReadonlyArray<V> | null] | {
|
|
387
|
+
readonly op: FilterOp;
|
|
388
|
+
readonly value?: V | ReadonlyArray<V> | null;
|
|
389
|
+
readonly not?: boolean;
|
|
390
|
+
readonly quantifier?: "any" | "all";
|
|
391
|
+
readonly config?: string;
|
|
392
|
+
};
|
|
393
|
+
type WhereOf<R$1, EmbedKeys extends string> = { readonly [K in keyof R$1 & string]?: Filter$1<R$1[K]> } & {
|
|
394
|
+
readonly and?: ReadonlyArray<WhereOf<R$1, EmbedKeys>>;
|
|
395
|
+
readonly or?: ReadonlyArray<WhereOf<R$1, EmbedKeys>>;
|
|
396
|
+
} & {
|
|
397
|
+
/**
|
|
398
|
+
* A filter on an embedded resource, by its dotted path, the way the query string writes it. The
|
|
399
|
+
* column belongs to the other resource, so only the shape of the condition is checked here --
|
|
400
|
+
* prefer the embed's own `where`, which knows its columns.
|
|
401
|
+
*/
|
|
402
|
+
readonly [K in `${EmbedKeys}.${string}`]?: Filter$1<Scalar> };
|
|
403
|
+
type OrderOf<R$1> = (keyof R$1 & string) | `${keyof R$1 & string}.${"asc" | "desc"}` | `${keyof R$1 & string}.${"asc" | "desc"}.${"nullsfirst" | "nullslast"}` | {
|
|
404
|
+
readonly column: keyof R$1 & string;
|
|
405
|
+
readonly desc?: boolean;
|
|
406
|
+
readonly nulls?: "first" | "last";
|
|
407
|
+
};
|
|
408
|
+
type Where$1<Db extends AnyDatabase, S$1 extends Schema<Db>, T$1 extends Table<Db, S$1>> = WhereOf<Row$1<Db, S$1, T$1>, keyof Embeds<Db, S$1, T$1> & string>;
|
|
409
|
+
type Order$1<Db extends AnyDatabase, S$1 extends Schema<Db>, T$1 extends Table<Db, S$1>> = OrderOf<Row$1<Db, S$1, T$1>>;
|
|
410
|
+
interface Common {
|
|
411
|
+
/** At most this many rows. A read that is capped answers `206` with a `Content-Range`. */
|
|
412
|
+
readonly limit?: number;
|
|
413
|
+
/** Skip this many rows. Needs an `order` to mean anything stable. */
|
|
414
|
+
readonly offset?: number;
|
|
415
|
+
/**
|
|
416
|
+
* Return one object instead of an array. Anything other than exactly one row is a `406`
|
|
417
|
+
* (`PGRST116`), so `data` is the row itself, never `undefined`.
|
|
418
|
+
*/
|
|
419
|
+
readonly single?: boolean;
|
|
420
|
+
/**
|
|
421
|
+
* Also count the rows the filters match, ignoring `limit`/`offset`, into `count`:
|
|
422
|
+
* `"exact"` counts them, `"planned"` asks the planner, `"estimated"` takes the planner's
|
|
423
|
+
* number only when it is above `maxRows`.
|
|
424
|
+
*/
|
|
425
|
+
readonly count?: "exact" | "planned" | "estimated";
|
|
426
|
+
/** Leave `null` fields out of the result rather than spelling them out. */
|
|
427
|
+
readonly stripNulls?: boolean;
|
|
428
|
+
/** Refuse the call -- and roll it back -- if it would affect more rows than this (`PGRST124`). */
|
|
429
|
+
readonly maxAffected?: number;
|
|
430
|
+
/** Run the statement in this time zone, which is what `timestamptz` values are rendered in. */
|
|
431
|
+
readonly timezone?: string;
|
|
432
|
+
}
|
|
433
|
+
/** `schema` is optional for the default schema and required for any other. */
|
|
434
|
+
type AtSchema<Db extends AnyDatabase, S$1 extends Schema<Db>> = S$1 extends Db["default"] ? {
|
|
435
|
+
readonly schema?: S$1;
|
|
436
|
+
} : {
|
|
437
|
+
readonly schema: S$1;
|
|
438
|
+
};
|
|
439
|
+
/**
|
|
440
|
+
* Everything a query on one relation may say. Reads and writes share **one** member per table on
|
|
441
|
+
* purpose: when several members of the union carry the same `table` value, TypeScript cannot pick
|
|
442
|
+
* one from the discriminant, and the editor then offers every table's columns inside `select` and
|
|
443
|
+
* `where`. What the separate shapes used to enforce is enforced by {@link WriteRules} instead.
|
|
444
|
+
*/
|
|
445
|
+
type TableQuery<Db extends AnyDatabase, S$1 extends Schema<Db>, T$1 extends Table<Db, S$1>> = Common & AtSchema<Db, S$1> & {
|
|
446
|
+
/**
|
|
447
|
+
* The table or view to read or write. It is what restricts everything below: `select`, `where`
|
|
448
|
+
* and `order` only accept this relation's columns, and `rows`/`set` its writable ones.
|
|
449
|
+
*/
|
|
450
|
+
readonly table: T$1;
|
|
451
|
+
/** Never both: the discriminant has to exist on every member for the editor to pick one. */
|
|
452
|
+
readonly rpc?: never;
|
|
453
|
+
/**
|
|
454
|
+
* What to do. `"select"` (the default) reads; `"insert"` and `"upsert"` take `rows`, `"update"`
|
|
455
|
+
* takes `set`, `"delete"` takes neither. A write returns its rows unless `returning: "minimal"`.
|
|
456
|
+
*/
|
|
457
|
+
readonly action?: "select" | "insert" | "upsert" | "update" | "delete";
|
|
458
|
+
/**
|
|
459
|
+
* The columns to return, and the resources to embed. A string is a column (`"title"`) or a
|
|
460
|
+
* renamed one (`"name:title"`); `"*"` takes them all; `{ tags: ["label"] }` embeds a related
|
|
461
|
+
* resource, and `{ tags: { select, inner, where, order, limit, as, spread } }` is its long form.
|
|
462
|
+
*
|
|
463
|
+
* `data` is inferred from exactly this: pick two columns and the rows have two keys.
|
|
464
|
+
*/
|
|
465
|
+
readonly select?: SelectList<Db, S$1, T$1>;
|
|
466
|
+
/**
|
|
467
|
+
* Which rows, by column. A plain value means `eq` (and `null` means `is.null`),
|
|
468
|
+
* `["gte", 3]` names an operator, and `{ op, value, not, quantifier, config }` is the long form.
|
|
469
|
+
* `and` and `or` take a list of nested groups; a dotted key filters an embedded resource.
|
|
470
|
+
*/
|
|
471
|
+
readonly where?: Where$1<Db, S$1, T$1>;
|
|
472
|
+
/** How to sort: `"created"`, `"created.desc"`, or `{ column, desc, nulls }`. */
|
|
473
|
+
readonly order?: ReadonlyArray<Order$1<Db, S$1, T$1>>;
|
|
474
|
+
/**
|
|
475
|
+
* What to insert: one object or many. Generated and `GENERATED ALWAYS AS IDENTITY` columns are
|
|
476
|
+
* absent, and a column with a default or a nullable one is optional.
|
|
477
|
+
*/
|
|
478
|
+
readonly rows?: Relations<Db, S$1>[T$1]["insert"] | ReadonlyArray<Relations<Db, S$1>[T$1]["insert"]>;
|
|
479
|
+
/** The columns to change, for an `"update"`. The rows are the ones `where` matches. */
|
|
480
|
+
readonly set?: Relations<Db, S$1>[T$1]["update"];
|
|
481
|
+
/** For an `"upsert"`, the columns the conflict is resolved on. Defaults to the primary key. */
|
|
482
|
+
readonly onConflict?: ReadonlyArray<Column$1<Db, S$1, T$1>>;
|
|
483
|
+
/** Insert only these columns, ignoring any other key in `rows` (and so making a bulk insert uniform). */
|
|
484
|
+
readonly columns?: ReadonlyArray<Column$1<Db, S$1, T$1>>;
|
|
485
|
+
/** What a column missing from `rows` gets: its `DEFAULT` (the default here) or `null`. */
|
|
486
|
+
readonly missing?: "default" | "null";
|
|
487
|
+
/** Whether a write answers with the rows it touched (the default here) or with nothing. */
|
|
488
|
+
readonly returning?: "representation" | "minimal";
|
|
489
|
+
};
|
|
490
|
+
/**
|
|
491
|
+
* The payload each action needs, and refuses: `rows` belongs to an insert or an upsert, `set` to an
|
|
492
|
+
* update, and a read has no business with either. Required here rather than in the shape, because
|
|
493
|
+
* an optional property that must sometimes be present cannot be said in one object type.
|
|
494
|
+
*/
|
|
495
|
+
type WriteRules<Db extends AnyDatabase, Q> = (Q extends {
|
|
496
|
+
action: "insert" | "upsert";
|
|
497
|
+
} ? {
|
|
498
|
+
readonly rows: WriteShape<Db, Q, "insert"> | ReadonlyArray<WriteShape<Db, Q, "insert">>;
|
|
499
|
+
} : {
|
|
500
|
+
readonly rows?: never;
|
|
501
|
+
readonly onConflict?: never;
|
|
502
|
+
readonly columns?: never;
|
|
503
|
+
readonly missing?: never;
|
|
504
|
+
}) & (Q extends {
|
|
505
|
+
action: "update";
|
|
506
|
+
} ? {
|
|
507
|
+
readonly set: WriteShape<Db, Q, "update">;
|
|
508
|
+
} : {
|
|
509
|
+
readonly set?: never;
|
|
510
|
+
}) & (Q extends {
|
|
511
|
+
action: "insert" | "upsert" | "update" | "delete";
|
|
512
|
+
} ? unknown : {
|
|
513
|
+
readonly returning?: never;
|
|
514
|
+
});
|
|
515
|
+
type Rpc<Db extends AnyDatabase, S$1 extends Schema<Db>, F$1 extends keyof Functions<Db, S$1> & string> = Common & AtSchema<Db, S$1> & {
|
|
516
|
+
/**
|
|
517
|
+
* The function to call, like `POST /rpc/name`. Its arguments and its result come from the
|
|
518
|
+
* signature the catalog carries, overloads included.
|
|
519
|
+
*/
|
|
520
|
+
readonly rpc: F$1;
|
|
521
|
+
/**
|
|
522
|
+
* `table` is absent from a function call, but it must still be *declared*: a union where some
|
|
523
|
+
* members lack the discriminant altogether is one TypeScript will not narrow, and the editor
|
|
524
|
+
* then offers every table's columns inside `select`.
|
|
525
|
+
*/
|
|
526
|
+
readonly table?: never;
|
|
527
|
+
/** A function call has no action: it is whatever the function does. */
|
|
528
|
+
readonly action?: never;
|
|
529
|
+
/** The arguments, by name. A parameter with a `DEFAULT` is optional. */
|
|
530
|
+
readonly args?: Functions<Db, S$1>[F$1][number]["args"];
|
|
531
|
+
/**
|
|
532
|
+
* A function's result is a row like any other, so it takes the same three. These apply to the
|
|
533
|
+
* rows it returns, not to its arguments -- and a scalar function has no columns to ask for.
|
|
534
|
+
*/
|
|
535
|
+
readonly select?: RowSelect<Functions<Db, S$1>[F$1][number]["returns"]>;
|
|
536
|
+
/** Filters on the rows the function returned, by their column. */
|
|
537
|
+
readonly where?: WhereOf<Functions<Db, S$1>[F$1][number]["returns"], never>;
|
|
538
|
+
/** How to sort the rows the function returned. */
|
|
539
|
+
readonly order?: ReadonlyArray<OrderOf<Functions<Db, S$1>[F$1][number]["returns"]>>;
|
|
540
|
+
};
|
|
541
|
+
/** The keys any member of a union accepts (`keyof` a union keeps only the common ones). */
|
|
542
|
+
type KeysOfUnion<U$1> = U$1 extends unknown ? keyof U$1 : never;
|
|
543
|
+
/**
|
|
544
|
+
* Inference through a type parameter checks assignability, which does not flag excess properties:
|
|
545
|
+
* `{ table: "t", limitt: 10 }` would type-check and the misspelled field would be dropped in
|
|
546
|
+
* silence. Intersecting this makes any unknown key `never`, so it has to be reported.
|
|
547
|
+
*/
|
|
548
|
+
type NoExtraKeys<Q, Allowed> = { readonly [K in Exclude<keyof Q, KeysOfUnion<Allowed>>]: never };
|
|
549
|
+
/** The insert or update shape of the relation a query writes to. */
|
|
550
|
+
type WriteShape<Db extends AnyDatabase, Q, Field extends "insert" | "update"> = Q extends {
|
|
551
|
+
table: infer T;
|
|
552
|
+
} ? T extends Table<Db, SchemaIn<Db, Q>> ? Relations<Db, SchemaIn<Db, Q>>[T][Field] : never : never;
|
|
553
|
+
/**
|
|
554
|
+
* The same guard, for the payload of a write: `rows: { id: 42, ... }` on a generated column, or any
|
|
555
|
+
* other key the relation does not accept, would otherwise reach the database and be refused there.
|
|
556
|
+
*/
|
|
557
|
+
type NoExtraPayload<Db extends AnyDatabase, Q> = (Q extends {
|
|
558
|
+
rows: infer R;
|
|
559
|
+
} ? {
|
|
560
|
+
readonly rows: R extends ReadonlyArray<unknown> ? { readonly [I in keyof R]: R[I] & NoExtraKeys<R[I], WriteShape<Db, Q, "insert">> } : R & NoExtraKeys<R, WriteShape<Db, Q, "insert">>;
|
|
561
|
+
} : unknown) & (Q extends {
|
|
562
|
+
set: infer U;
|
|
563
|
+
} ? {
|
|
564
|
+
readonly set: U & NoExtraKeys<U, WriteShape<Db, Q, "update">>;
|
|
565
|
+
} : unknown);
|
|
566
|
+
/** What a `where` may be keyed by: this relation's columns, a group, or an embedded dotted path. */
|
|
567
|
+
type WhereKeys<Db extends AnyDatabase, S$1 extends Schema<Db>, T$1 extends Table<Db, S$1>> = Column$1<Db, S$1, T$1> | "and" | "or" | `${keyof Embeds<Db, S$1, T$1> & string}.${string}`;
|
|
568
|
+
/**
|
|
569
|
+
* A condition on something that is not a column of this relation. An unknown key inside `where` is
|
|
570
|
+
* not reported by assignability either -- `{ "titel": true }` would reach the database and come
|
|
571
|
+
* back as a `42703`. The columns of the relation the query names, so after its `table`.
|
|
572
|
+
*/
|
|
573
|
+
type NoExtraWhereKeys<Db extends AnyDatabase, Q> = Q extends {
|
|
574
|
+
where: infer W;
|
|
575
|
+
} ? Q extends {
|
|
576
|
+
table: infer T;
|
|
577
|
+
} ? T extends Table<Db, SchemaIn<Db, Q>> ? {
|
|
578
|
+
readonly where: W & { readonly [K in Exclude<keyof W, WhereKeys<Db, SchemaIn<Db, Q>, T>>]: never };
|
|
579
|
+
} : unknown : unknown : unknown;
|
|
580
|
+
/** Every query this database allows, as a union discriminated by `table` or `rpc`. */
|
|
581
|
+
type TypedQuery<Db extends AnyDatabase> = { [S in Schema<Db>]: { [T in Table<Db, S>]: TableQuery<Db, S, T> }[Table<Db, S>] | { [F in keyof Functions<Db, S> & string]: Rpc<Db, S, F> }[keyof Functions<Db, S> & string] }[Schema<Db>];
|
|
582
|
+
type SchemaIn<Db extends AnyDatabase, Q> = Q extends {
|
|
583
|
+
schema: infer S;
|
|
584
|
+
} ? S extends Schema<Db> ? S : never : Db["default"] & Schema<Db>;
|
|
585
|
+
/** The overloads of the function a query calls. */
|
|
586
|
+
type Signatures<Db extends AnyDatabase, Q> = Q extends {
|
|
587
|
+
rpc: infer F;
|
|
588
|
+
} ? F extends keyof Functions<Db, SchemaIn<Db, Q>> & string ? Functions<Db, SchemaIn<Db, Q>>[F][number] : never : never;
|
|
589
|
+
/** One row of the answer, before `single` decides whether it comes alone. */
|
|
590
|
+
type RowOut<Db extends AnyDatabase, Q> = Q extends {
|
|
591
|
+
rpc: string;
|
|
592
|
+
} ? Q extends {
|
|
593
|
+
select: infer Items;
|
|
594
|
+
} ? PickedFrom<Signatures<Db, Q>["returns"], Items> : Signatures<Db, Q>["returns"] : Q extends {
|
|
595
|
+
table: infer T;
|
|
596
|
+
} ? T extends Table<Db, SchemaIn<Db, Q>> ? Q extends {
|
|
597
|
+
select: infer Items;
|
|
598
|
+
} ? Selected<Db, SchemaIn<Db, Q>, T, Items> : Row$1<Db, SchemaIn<Db, Q>, T> : never : never;
|
|
599
|
+
/**
|
|
600
|
+
* What `data` holds: the rows, one object with `single`, and `null` for a write that was asked to
|
|
601
|
+
* return nothing or a function that returns `void`.
|
|
602
|
+
*/
|
|
603
|
+
type QueryData<Db extends AnyDatabase, Q> = Q extends {
|
|
604
|
+
returning: "minimal";
|
|
605
|
+
} ? null : Q extends {
|
|
606
|
+
single: true;
|
|
607
|
+
} ? RowOut<Db, Q> : Q extends {
|
|
608
|
+
rpc: string;
|
|
609
|
+
} ? [Signatures<Db, Q>["set"]] extends [true] ? RowOut<Db, Q>[] : RowOut<Db, Q> : RowOut<Db, Q>[];
|
|
610
|
+
/**
|
|
611
|
+
* A {@link PgRestInstance} whose `query` and `querySafe` are typed by a generated database type:
|
|
612
|
+
* `table` and `rpc` are the ones that exist, `select` and `where` only name real columns and
|
|
613
|
+
* relationships, and `data` is inferred from the `select`.
|
|
614
|
+
*
|
|
615
|
+
* `handle` is unchanged: HTTP requests are strings from outside and cannot be typed.
|
|
616
|
+
*/
|
|
617
|
+
interface TypedPgRestInstance<Db extends AnyDatabase> extends Omit<PgRestInstance, "query" | "querySafe"> {
|
|
618
|
+
/**
|
|
619
|
+
* Run a query, in-process. `table` (or `rpc`) decides what the rest may say: `select`, `where` and
|
|
620
|
+
* `order` take this relation's columns and the resources a foreign key leads to, `rows` and `set`
|
|
621
|
+
* its writable columns. `data` is inferred from the `select`, nesting included.
|
|
622
|
+
*
|
|
623
|
+
* `ctx` is who is asking -- `{ role, claims, settings }` -- applied with `set_config`, so row
|
|
624
|
+
* level security and privileges work as they do over HTTP. They are the database's business: no
|
|
625
|
+
* type here knows what a role may do.
|
|
626
|
+
*
|
|
627
|
+
* Failures **throw** a `QueryError` carrying the PostgREST status and body. Use
|
|
628
|
+
* {@link TypedPgRestInstance.querySafe} to get them as a value instead.
|
|
629
|
+
*
|
|
630
|
+
* @example
|
|
631
|
+
* const { data } = await pgRest.query({
|
|
632
|
+
* table: "todos",
|
|
633
|
+
* select: ["id", "title", { tags: ["label"] }],
|
|
634
|
+
* where: { done: false },
|
|
635
|
+
* limit: 10,
|
|
636
|
+
* });
|
|
637
|
+
* // data: Array<{ id: number; title: string; tags: Array<{ label: string }> }>
|
|
638
|
+
*/
|
|
639
|
+
query<const Q extends TypedQuery<Db>>(input: Q & NoExtraKeys<Q, TypedQuery<Db>> & NoExtraPayload<Db, Q> & NoExtraWhereKeys<Db, Q> & WriteRules<Db, Q>, ctx?: RequestContext): Promise<QueryResult<QueryData<Db, Q>>>;
|
|
640
|
+
/**
|
|
641
|
+
* {@link TypedPgRestInstance.query} with the failure as a value: `{ data, error }`, where exactly
|
|
642
|
+
* one of the two is set, so `if (error)` leaves `data` non-null. It never rejects.
|
|
643
|
+
*
|
|
644
|
+
* @example
|
|
645
|
+
* const { data, error } = await pgRest.querySafe({ table: "todos", select: ["id"] });
|
|
646
|
+
* if (error) return c.json(error.body, error.status);
|
|
647
|
+
*/
|
|
648
|
+
querySafe<const Q extends TypedQuery<Db>>(input: Q & NoExtraKeys<Q, TypedQuery<Db>> & NoExtraPayload<Db, Q> & NoExtraWhereKeys<Db, Q> & WriteRules<Db, Q>, ctx?: RequestContext): Promise<QuerySafeResult<QueryData<Db, Q>>>;
|
|
187
649
|
}
|
|
188
650
|
//#endregion
|
|
189
651
|
//#region src/service.d.ts
|
|
@@ -246,14 +708,64 @@ interface PgRestInstance {
|
|
|
246
708
|
* `resolveContext` is used; otherwise the request runs as the anonymous role.
|
|
247
709
|
*/
|
|
248
710
|
handle(request: Request, ctx?: RequestContext): Promise<Response>;
|
|
711
|
+
/**
|
|
712
|
+
* Run a query described by an object, in-process: no `Request`, no URL, no HTTP status.
|
|
713
|
+
* It goes through the same parser, the same SQL and the same error mapping as
|
|
714
|
+
* {@link PgRestInstance.handle}, so the database sees the same thing either way.
|
|
715
|
+
*
|
|
716
|
+
* Only the HTTP envelope is gone, which is also what it cannot do: content negotiation
|
|
717
|
+
* (CSV, GeoJSON, custom media types), `EXPLAIN` plans and OpenAPI stay on `handle`.
|
|
718
|
+
*
|
|
719
|
+
* Failures throw a {@link QueryError}: an `Error` carrying the PostgREST status, body
|
|
720
|
+
* (`code`, `message`, `details`, `hint`) and the input that produced it.
|
|
721
|
+
*/
|
|
722
|
+
query<T$1 = unknown>(input: QueryInput, ctx?: RequestContext): Promise<QueryResult<T$1>>;
|
|
723
|
+
/**
|
|
724
|
+
* {@link PgRestInstance.query} with the failure as a value instead of an exception:
|
|
725
|
+
* `const { data, error } = await pgRest.querySafe({ table: "todos" })`. Exactly one of the two
|
|
726
|
+
* is set, so `if (error)` leaves `data` non-null. The error is the same {@link QueryError}.
|
|
727
|
+
*
|
|
728
|
+
* It never rejects: an error the library did not foresee comes back as a 500 `error` carrying the
|
|
729
|
+
* original under `cause`, so checking `error` is enough and no `try`/`catch` is needed.
|
|
730
|
+
*/
|
|
731
|
+
querySafe<T$1 = unknown>(input: QueryInput, ctx?: RequestContext): Promise<QuerySafeResult<T$1>>;
|
|
249
732
|
/** Re-read the database catalog (after migrations). */
|
|
250
733
|
reloadSchema(): Promise<void>;
|
|
251
734
|
/** The current introspected schema. */
|
|
252
735
|
schemaCache(): Promise<SchemaCache>;
|
|
736
|
+
/**
|
|
737
|
+
* TypeScript types for this database, as the text of a module. Write it next to your code, keep
|
|
738
|
+
* it in version control, and hand the type it exports to `createPgRest<Database>` so queries
|
|
739
|
+
* check themselves. Run it again after a migration.
|
|
740
|
+
*
|
|
741
|
+
* ```ts
|
|
742
|
+
* writeFileSync("src/db.types.ts", await pgRest.generateTypes({ name: "Database" }));
|
|
743
|
+
* ```
|
|
744
|
+
*
|
|
745
|
+
* The generator is loaded on demand, so a server that never calls this never pays for it. The
|
|
746
|
+
* same function is exported standalone as `@adrdp/pg-rest/types` for when you hold a
|
|
747
|
+
* {@link SchemaCache} rather than an instance.
|
|
748
|
+
*/
|
|
749
|
+
generateTypes(options?: GenerateTypesOptions): Promise<string>;
|
|
253
750
|
/** Stop the handler. The database adapter is left open: close it yourself. */
|
|
254
751
|
close(): Promise<void>;
|
|
255
752
|
}
|
|
256
|
-
|
|
257
|
-
|
|
753
|
+
interface CreatePgRest {
|
|
754
|
+
(options: PgRestOptions): Promise<PgRestInstance>;
|
|
755
|
+
/**
|
|
756
|
+
* With a database type from `generateTypes` (`@adrdp/pg-rest/types`), `query` and `querySafe`
|
|
757
|
+
* are typed by it: `table` and `rpc` are the ones that exist, `select`, `where` and `order` only
|
|
758
|
+
* name real columns and relationships, and `data` is inferred from the `select`.
|
|
759
|
+
*/
|
|
760
|
+
<Db extends AnyDatabase>(options: PgRestOptions): Promise<TypedPgRestInstance<Db>>;
|
|
761
|
+
}
|
|
762
|
+
/**
|
|
763
|
+
* Create a PostgREST-compatible handler over a Postgres database.
|
|
764
|
+
*
|
|
765
|
+
* `createPgRest<Db>(options)` returns the same instance with `query` and `querySafe` typed by a
|
|
766
|
+
* generated database type; the cast is the whole of that difference, since types never reach
|
|
767
|
+
* runtime and the two instances are one object.
|
|
768
|
+
*/
|
|
769
|
+
declare const createPgRest: CreatePgRest;
|
|
258
770
|
//#endregion
|
|
259
|
-
export { ApiError, type Column, type DbAdapter, DbQueryError, type DbSession, type ErrorBody, type ForeignKey, type FunctionDef, PgRestError, PgRestInstance, PgRestOptions, type PreRequestInfo, type Relation, type RequestContext, type Row, type SchemaCache, SchemaLoadError, createPgRest };
|
|
771
|
+
export { type AnyDatabase, type AnyRelation, type AnySchema, type AnySignature, ApiError, type Column, CreatePgRest, type DbAdapter, DbQueryError, type DbSession, type DeleteQuery, type Embed, type ErrorBody, type Filter, type FilterOp, type FilterSpec, type ForeignKey, type FunctionDef, type InsertQuery, type Order, PgRestError, PgRestInstance, PgRestOptions, type PreRequestInfo, type QueryData, QueryError, type QueryInput, type QueryResult, type QueryReturning, type QuerySafeResult, type Relation, type RequestContext, type Row, type RpcQuery, type Scalar, type SchemaCache, SchemaLoadError, type Select, type SelectQuery, type TypedPgRestInstance, type TypedQuery, type UpdateQuery, type Where, createPgRest };
|