@rebasepro/types 0.23.0 → 0.24.1-canary.g19596ef
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/dist/call_context.d.ts +8 -4
- package/dist/controllers/client.d.ts +113 -24
- package/dist/controllers/collection_registry.d.ts +17 -0
- package/dist/controllers/data.d.ts +570 -122
- package/dist/controllers/data_driver.d.ts +85 -1
- package/dist/controllers/index.d.ts +1 -0
- package/dist/controllers/storage-references.d.ts +114 -0
- package/dist/controllers/storage.d.ts +73 -13
- package/dist/errors.d.ts +15 -1
- package/dist/index.es.js +1228 -43
- package/dist/index.es.js.map +1 -1
- package/dist/types/admin_block.d.ts +1 -1
- package/dist/types/api_keys.d.ts +68 -36
- package/dist/types/auth_adapter.d.ts +97 -2
- package/dist/types/backend.d.ts +356 -9
- package/dist/types/backup.d.ts +102 -0
- package/dist/types/collection_patch.d.ts +74 -0
- package/dist/types/collections.d.ts +23 -0
- package/dist/types/cron.d.ts +58 -7
- package/dist/types/database_adapter.d.ts +34 -8
- package/dist/types/entities.d.ts +11 -0
- package/dist/types/history.d.ts +15 -1
- package/dist/types/index.d.ts +3 -0
- package/dist/types/project_manifest.d.ts +73 -1
- package/dist/types/properties.d.ts +39 -2
- package/dist/types/register.d.ts +43 -0
- package/dist/types/relations.d.ts +37 -1
- package/dist/types/resource_kinds.d.ts +20 -10
- package/dist/types/schema_editing.d.ts +39 -13
- package/dist/types/scopes.d.ts +272 -0
- package/dist/types/storage_authorize.d.ts +10 -1
- package/dist/types/storage_source.d.ts +2 -6
- package/dist/types/websockets.d.ts +32 -1
- package/dist/users/user.d.ts +7 -0
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { VectorSearchParams } from "./data_driver.js";
|
|
2
2
|
import type { ComputedSortField, SearchMatch } from "../types/search.js";
|
|
3
3
|
import { Entity, EntityValues } from "../types/entities.js";
|
|
4
|
-
import { WhereFilterOp, FieldPath, NonColumnFieldPath, FilterValues, NullsPlacement, OrderBySpec, RelationAggregateSort } from "../types/filter-operators.js";
|
|
4
|
+
import { WhereFilterOp, FieldPath, NonColumnFieldPath, FilterValues, NullsPlacement, OrderBySpec, OrderByTuple, RelationAggregateSort } from "../types/filter-operators.js";
|
|
5
5
|
/**
|
|
6
6
|
* The element type of an array column, and the column's own type otherwise.
|
|
7
7
|
*
|
|
@@ -44,8 +44,10 @@ export type WhereElementOf<T> = ElementOf<T> | IdOf<ElementOf<T>>;
|
|
|
44
44
|
* - `array-contains` → one element of the column (or a related row's id).
|
|
45
45
|
* - `in` / `not-in` / `array-contains-any` → a list of elements; a bare element
|
|
46
46
|
* is read as the one-element list, and `null` is a null check.
|
|
47
|
-
* - `like` / `ilike` / `not-like` / `not-ilike` → a SQL pattern
|
|
48
|
-
* string,
|
|
47
|
+
* - `like` / `ilike` / `not-like` / `not-ilike` → a SQL pattern, always a
|
|
48
|
+
* string. It matches a text column, or an enum by its label; on a number,
|
|
49
|
+
* a date or any other column the Postgres driver refuses it with a 400
|
|
50
|
+
* (`INVALID_FILTER_OPERATOR`).
|
|
49
51
|
* - `is-null` / `is-not-null` → nothing; the value is ignored everywhere.
|
|
50
52
|
* - everything else → the column's own type, or `null` for a null comparison.
|
|
51
53
|
*
|
|
@@ -54,6 +56,33 @@ export type WhereElementOf<T> = ElementOf<T> | IdOf<ElementOf<T>>;
|
|
|
54
56
|
* permissive as it was.
|
|
55
57
|
*/
|
|
56
58
|
export type WhereValueFor<Op extends WhereFilterOp, T> = Op extends "array-contains" ? WhereElementOf<T> : Op extends "in" | "not-in" | "array-contains-any" ? readonly WhereElementOf<T>[] | WhereElementOf<T> | null : Op extends "like" | "ilike" | "not-like" | "not-ilike" ? string : Op extends "is-null" | "is-not-null" ? null | undefined : T | null;
|
|
59
|
+
/**
|
|
60
|
+
* One `[operator, value]` condition on a column of type `T`, with the value
|
|
61
|
+
* typed for the operator exactly as the fluent `where(column, op, value)` types
|
|
62
|
+
* it — a union with one tuple per operator, so `["array-contains", "featured"]`
|
|
63
|
+
* on a `string[]` column compiles and `["array-contains", ["featured"]]` (which
|
|
64
|
+
* builds `@> ARRAY[$1]` and matches nothing) does not.
|
|
65
|
+
*/
|
|
66
|
+
export type WhereConditionFor<T> = {
|
|
67
|
+
[Op in WhereFilterOp]: [Op, WhereValueFor<Op, T>];
|
|
68
|
+
}[WhereFilterOp];
|
|
69
|
+
/**
|
|
70
|
+
* The object-form `where` for row type `M`: each column takes conditions typed
|
|
71
|
+
* against that column, as the fluent form does.
|
|
72
|
+
*
|
|
73
|
+
* `FilterValues` typed the key and left the value `unknown`, so the very
|
|
74
|
+
* shapes the fluent form was fixed to refuse — a wrong value type, an array
|
|
75
|
+
* where `array-contains` wants one element — compiled in `find({ where })`,
|
|
76
|
+
* the form `listen`, `observe`, `count` and `iterate` all take.
|
|
77
|
+
*
|
|
78
|
+
* A path that is not a column (`author.name`, `metadata->>tier`) has no type to
|
|
79
|
+
* check against and stays `unknown`, as in {@link FieldPath}. An untyped `M`
|
|
80
|
+
* (`Record<string, unknown>`, every key) collapses to plain `FilterValues`, so
|
|
81
|
+
* an untyped client is exactly as permissive as before.
|
|
82
|
+
*/
|
|
83
|
+
export type WhereFor<M extends Record<string, unknown>> = string extends keyof M ? FilterValues<FieldPath<M>> : {
|
|
84
|
+
[K in Extract<keyof M, string>]?: WhereConditionFor<M[K]> | WhereConditionFor<M[K]>[];
|
|
85
|
+
} & FilterValues<NonColumnFieldPath>;
|
|
57
86
|
/**
|
|
58
87
|
* A group of conditions combined with `and`, `or`, or negated with `not`.
|
|
59
88
|
*
|
|
@@ -79,6 +108,53 @@ export interface FilterCondition {
|
|
|
79
108
|
operator: WhereFilterOp;
|
|
80
109
|
value: unknown;
|
|
81
110
|
}
|
|
111
|
+
/**
|
|
112
|
+
* One {@link FilterCondition} on row type `M`: the column is one of `M`'s and
|
|
113
|
+
* the value is typed for the operator against that column, exactly as the
|
|
114
|
+
* fluent `where(column, op, value)` types it. A path that is not a column
|
|
115
|
+
* (`author.name`, `metadata->>tier`) has nothing to check against and stays
|
|
116
|
+
* `unknown`, as in {@link WhereFor}.
|
|
117
|
+
*
|
|
118
|
+
* An untyped `M` (`Record<string, unknown>`) collapses to plain
|
|
119
|
+
* `FilterCondition`, so an untyped client is exactly as permissive as before.
|
|
120
|
+
*/
|
|
121
|
+
export type FilterConditionFor<M extends Record<string, unknown>> = ColumnConditions<M>[keyof ColumnConditions<M>] | {
|
|
122
|
+
column: NonColumnFieldPath;
|
|
123
|
+
operator: WhereFilterOp;
|
|
124
|
+
value: unknown;
|
|
125
|
+
};
|
|
126
|
+
/**
|
|
127
|
+
* Per column, the union of its typed conditions; an index-signature key (an
|
|
128
|
+
* untyped row) maps to plain {@link FilterCondition}.
|
|
129
|
+
*
|
|
130
|
+
* A key-remapped mapped type rather than a conditional over `keyof M`, for the
|
|
131
|
+
* reason {@link NumericKeyOf} gives: tsc measures the conditional form as
|
|
132
|
+
* invariant in `M`, and a typed `SDKCollectionClient<Post>` stopped widening to
|
|
133
|
+
* the wide `SDKCollectionClient`.
|
|
134
|
+
*/
|
|
135
|
+
type ColumnConditions<M extends Record<string, unknown>> = {
|
|
136
|
+
[K in keyof M as K extends string ? K : never]: string extends K ? FilterCondition : {
|
|
137
|
+
[Op in WhereFilterOp]: {
|
|
138
|
+
column: K;
|
|
139
|
+
operator: Op;
|
|
140
|
+
value: WhereValueFor<Op, M[K]>;
|
|
141
|
+
};
|
|
142
|
+
}[WhereFilterOp];
|
|
143
|
+
};
|
|
144
|
+
/**
|
|
145
|
+
* A {@link LogicalCondition} whose every condition, at any depth, is a
|
|
146
|
+
* {@link FilterConditionFor} row type `M`.
|
|
147
|
+
*
|
|
148
|
+
* `cond()` cannot know the row it will be used on, so it returns its column,
|
|
149
|
+
* operator and value exactly as written; this is where they are checked.
|
|
150
|
+
* `FindParams.logical` and the builders' `.where(group)` take it, so
|
|
151
|
+
* `posts.where(or(cond("titel", "==", 1)))` is a compile error on a typed
|
|
152
|
+
* client rather than the server's 400.
|
|
153
|
+
*/
|
|
154
|
+
export interface LogicalConditionFor<M extends Record<string, unknown>> {
|
|
155
|
+
type: "and" | "or" | "not";
|
|
156
|
+
conditions: (FilterConditionFor<M> | LogicalConditionFor<M>)[];
|
|
157
|
+
}
|
|
82
158
|
/**
|
|
83
159
|
* How one relation is loaded by {@link FindParams.include}.
|
|
84
160
|
*
|
|
@@ -123,6 +199,19 @@ export interface IncludeOptions {
|
|
|
123
199
|
fields?: string[];
|
|
124
200
|
/** Relations of the related row to load in turn. */
|
|
125
201
|
include?: IncludeSpec;
|
|
202
|
+
/**
|
|
203
|
+
* Also serve how many related rows there are in all, per parent, under
|
|
204
|
+
* the row's `_count` ({@link INCLUDE_COUNT_KEY}) — `{ tags: [...], _count:
|
|
205
|
+
* { tags: 37 } }`. Counted by the same query that reads the rows, over the
|
|
206
|
+
* same rows a read without `limit` would return (the include's `where`,
|
|
207
|
+
* soft delete, row-level security), so `limit` caps what is sent and the
|
|
208
|
+
* count says what was left out.
|
|
209
|
+
*
|
|
210
|
+
* To-many relations only: a to-one relation is a 400.
|
|
211
|
+
*
|
|
212
|
+
* @since 0.24
|
|
213
|
+
*/
|
|
214
|
+
count?: boolean;
|
|
126
215
|
}
|
|
127
216
|
/**
|
|
128
217
|
* The relations a read loads, as a list of (possibly dotted) names or as a
|
|
@@ -131,7 +220,11 @@ export interface IncludeOptions {
|
|
|
131
220
|
* - `["author", "comments.author"]` — a dotted path is the same thing as the
|
|
132
221
|
* nested object form, spelled flat. It is what the REST `?include=` parameter
|
|
133
222
|
* carries, and the two forms compile to the same request.
|
|
134
|
-
* - `["*"]` — every relation, one hop deep
|
|
223
|
+
* - `["*"]` — every relation the collection declares, one hop deep, those
|
|
224
|
+
* declared only for a record's tabs included — so on a list it can embed
|
|
225
|
+
* every row of a to-many relation no column shows. Name the relations the
|
|
226
|
+
* view renders instead; the admin panel does, and sends `*` only when it
|
|
227
|
+
* cannot resolve a collection's relations in the browser.
|
|
135
228
|
* - `{ comments: { limit: 5, include: { author: true } } }` — the parametrised
|
|
136
229
|
* form.
|
|
137
230
|
*
|
|
@@ -143,6 +236,61 @@ export interface IncludeOptions {
|
|
|
143
236
|
* @group Data
|
|
144
237
|
*/
|
|
145
238
|
export type IncludeSpec = string[] | Record<string, true | IncludeOptions>;
|
|
239
|
+
/**
|
|
240
|
+
* What a read of one record by id takes besides the id — `findById` and
|
|
241
|
+
* `listenById`.
|
|
242
|
+
*
|
|
243
|
+
* @group Data
|
|
244
|
+
*/
|
|
245
|
+
export interface ByIdReadOptions<Inc = IncludeSpec> {
|
|
246
|
+
/**
|
|
247
|
+
* Relations to load into the row, as {@link FindParams.include} loads them
|
|
248
|
+
* into each row of a list. A to-many relation not named here is absent
|
|
249
|
+
* from the row — not empty.
|
|
250
|
+
*/
|
|
251
|
+
include?: Inc;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* An include checked against one generated collection's relations: `R` is its
|
|
255
|
+
* `Relations` map (relation name → the accessor it reaches) and `DB` the
|
|
256
|
+
* generated `Database`, so a nested `include` is checked against the *target's*
|
|
257
|
+
* relations in turn.
|
|
258
|
+
*
|
|
259
|
+
* A name, a dotted path starting with one, or `"*"`; or the tree, keyed by
|
|
260
|
+
* relation name. A name that is not a relation is a 400 `UNKNOWN_RELATION`
|
|
261
|
+
* from the server, and a compile error here.
|
|
262
|
+
*
|
|
263
|
+
* @group Data
|
|
264
|
+
*/
|
|
265
|
+
export type IncludeSpecFor<DB, R> = readonly (Extract<keyof R, string> | "*" | `${Extract<keyof R, string>}.${string}`)[] | {
|
|
266
|
+
[K in Extract<keyof R, string>]?: true | IncludeOptionsFor<DB, R[K]>;
|
|
267
|
+
};
|
|
268
|
+
/**
|
|
269
|
+
* {@link IncludeOptions} for a relation that reaches the generated collection
|
|
270
|
+
* `T`: its nested `include` is checked against `T`'s relations.
|
|
271
|
+
*
|
|
272
|
+
* @group Data
|
|
273
|
+
*/
|
|
274
|
+
export interface IncludeOptionsFor<DB, T> extends Omit<IncludeOptions, "include"> {
|
|
275
|
+
include?: T extends keyof DB ? IncludeOf<DB[T], DB> : IncludeSpec;
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* The include a generated `Database` entry takes — {@link IncludeSpecFor} over
|
|
279
|
+
* its `Relations` — or the unchecked {@link IncludeSpec} for anything that does
|
|
280
|
+
* not declare its relations (a hand-written row type, an older generated file).
|
|
281
|
+
*
|
|
282
|
+
* @group Data
|
|
283
|
+
*/
|
|
284
|
+
export type IncludeOf<Entry, DB> = Entry extends {
|
|
285
|
+
Relations: infer R;
|
|
286
|
+
} ? IncludeSpecFor<DB, R> : IncludeSpec;
|
|
287
|
+
/**
|
|
288
|
+
* One argument of the fluent `.include(...)`: an element of the include list, a
|
|
289
|
+
* whole list, or the tree.
|
|
290
|
+
*
|
|
291
|
+
* @group Data
|
|
292
|
+
*/
|
|
293
|
+
export type IncludeArgOf<Inc> = Inc extends readonly (infer E)[] ? E | Inc : Inc;
|
|
146
294
|
/**
|
|
147
295
|
* Hops an {@link IncludeSpec} may nest. `comments.author` is two.
|
|
148
296
|
*
|
|
@@ -171,14 +319,16 @@ export declare const MAX_INCLUDE_DEPTH = 3;
|
|
|
171
319
|
*
|
|
172
320
|
* ## Pagination precedence
|
|
173
321
|
*
|
|
174
|
-
* `limit`/`offset` and `page` describe the same window two ways
|
|
175
|
-
* `
|
|
176
|
-
*
|
|
177
|
-
*
|
|
322
|
+
* `limit`/`offset` and `page` describe the same window two ways, so send one.
|
|
323
|
+
* `page` is `offset = (page - 1) * (limit ?? DEFAULT_LIST_LIMIT)`. A read with
|
|
324
|
+
* **both** is refused with `PAGE_WITH_OFFSET` — a 400 from the server, and a
|
|
325
|
+
* `RebaseClientError` with that code from a client before any request — rather
|
|
326
|
+
* than quietly applying one of them. `after` is refused beside either
|
|
327
|
+
* (`CURSOR_WITH_OFFSET`).
|
|
178
328
|
*
|
|
179
329
|
* @group Data
|
|
180
330
|
*/
|
|
181
|
-
export interface FindParams<M extends Record<string, unknown> = Record<string, unknown
|
|
331
|
+
export interface FindParams<M extends Record<string, unknown> = Record<string, unknown>, Inc = IncludeSpec> {
|
|
182
332
|
/**
|
|
183
333
|
* Maximum number of items to return.
|
|
184
334
|
*
|
|
@@ -193,13 +343,14 @@ export interface FindParams<M extends Record<string, unknown> = Record<string, u
|
|
|
193
343
|
*/
|
|
194
344
|
limit?: number;
|
|
195
345
|
/**
|
|
196
|
-
* Number of items to skip.
|
|
197
|
-
*
|
|
346
|
+
* Number of items to skip. Not with {@link FindParams.page}: the pair is
|
|
347
|
+
* refused with `PAGE_WITH_OFFSET`.
|
|
198
348
|
*/
|
|
199
349
|
offset?: number;
|
|
200
350
|
/**
|
|
201
|
-
* Page number (1-indexed), alternative to {@link FindParams.offset}
|
|
202
|
-
*
|
|
351
|
+
* Page number (1-indexed), alternative to {@link FindParams.offset}: it
|
|
352
|
+
* skips `(page - 1) * (limit ?? DEFAULT_LIST_LIMIT)` rows. Sent with
|
|
353
|
+
* `offset`, the read is refused with `PAGE_WITH_OFFSET`.
|
|
203
354
|
*/
|
|
204
355
|
page?: number;
|
|
205
356
|
/**
|
|
@@ -215,13 +366,13 @@ export interface FindParams<M extends Record<string, unknown> = Record<string, u
|
|
|
215
366
|
* { role: ["in", ["admin", "editor"]] }
|
|
216
367
|
* { age: [[">=", 18], ["<", 65]] }
|
|
217
368
|
*/
|
|
218
|
-
where?:
|
|
369
|
+
where?: WhereFor<M>;
|
|
219
370
|
/**
|
|
220
371
|
* Logical grouping conditions (AND/OR). Use this for anything `where`
|
|
221
372
|
* can't express — notably OR-ing conditions. AND-ed with `where` and
|
|
222
373
|
* `searchString` when present (see the interface docs).
|
|
223
374
|
*/
|
|
224
|
-
logical?:
|
|
375
|
+
logical?: LogicalConditionFor<M>;
|
|
225
376
|
/**
|
|
226
377
|
* Sort order as a `[field, direction]` tuple, or a list of them applied in
|
|
227
378
|
* order of significance — the second key breaks ties on the first, and so on.
|
|
@@ -236,11 +387,14 @@ export interface FindParams<M extends Record<string, unknown> = Record<string, u
|
|
|
236
387
|
* Not checked against `M` here: a relation name comes from the collection's
|
|
237
388
|
* `relations`, not from its columns, so nothing in a *hand-written* row type
|
|
238
389
|
* can validate one. A **generated** `Database` narrows this to the
|
|
239
|
-
* collection's actual relation keys, recursively — see
|
|
390
|
+
* collection's actual relation keys, recursively — see
|
|
391
|
+
* {@link IncludeSpecFor}. The row a read returns still types each relation
|
|
392
|
+
* as optional; the generated `RowWith<A, I>` names the row with the
|
|
393
|
+
* included ones required.
|
|
240
394
|
*
|
|
241
395
|
* An unknown name is a 400 `UNKNOWN_RELATION`. It used to be ignored.
|
|
242
396
|
*/
|
|
243
|
-
include?:
|
|
397
|
+
include?: Inc;
|
|
244
398
|
/**
|
|
245
399
|
* Columns to return, instead of all of them.
|
|
246
400
|
*
|
|
@@ -263,8 +417,10 @@ export interface FindParams<M extends Record<string, unknown> = Record<string, u
|
|
|
263
417
|
* projection (which it always is) every row is already distinct. Pair it
|
|
264
418
|
* with `fields` naming the columns you actually want the distinct values of.
|
|
265
419
|
*
|
|
266
|
-
*
|
|
267
|
-
*
|
|
420
|
+
* A distinct read is not counted, whichever door it goes through: over
|
|
421
|
+
* HTTP its `meta.total` is absent, and in-process it is the rows up to the
|
|
422
|
+
* end of the page — as for {@link FindParams.count} `"none"`. `hasMore`
|
|
423
|
+
* is exact either way.
|
|
268
424
|
*/
|
|
269
425
|
distinct?: boolean;
|
|
270
426
|
/**
|
|
@@ -324,6 +480,23 @@ export interface FindParams<M extends Record<string, unknown> = Record<string, u
|
|
|
324
480
|
* carries a `searchString`; there is nothing to explain otherwise.
|
|
325
481
|
*/
|
|
326
482
|
searchExplain?: boolean;
|
|
483
|
+
/**
|
|
484
|
+
* Whether to count the whole matching set for `meta.total`.
|
|
485
|
+
*
|
|
486
|
+
* `"exact"`, the default, runs a `COUNT(*)` over every row the query
|
|
487
|
+
* matches beside the page — and on a large table that count, not the page,
|
|
488
|
+
* is most of what a list read costs: it reads every matching row to report
|
|
489
|
+
* one number. `"none"` skips it. `meta.hasMore` is still exact (the read
|
|
490
|
+
* asks for one row past the page and reports whether it came back), so
|
|
491
|
+
* nothing that pages — `iterate()`, `findAll()`, a "load more" button —
|
|
492
|
+
* needs the count.
|
|
493
|
+
*
|
|
494
|
+
* Without the count there is no `total` to report: over HTTP `meta.total`
|
|
495
|
+
* is absent, and in-process it is the rows up to the end of this page
|
|
496
|
+
* (`offset` + the page), the figure a driver that cannot count reports.
|
|
497
|
+
* Sent as `?count=none`.
|
|
498
|
+
*/
|
|
499
|
+
count?: "exact" | "none";
|
|
327
500
|
}
|
|
328
501
|
/**
|
|
329
502
|
* Paginated response from a collection query.
|
|
@@ -352,7 +525,7 @@ export interface FindResponse<M extends Record<string, unknown> = Record<string,
|
|
|
352
525
|
*/
|
|
353
526
|
export interface QueryBuilderInterface<M extends Record<string, unknown> = Record<string, unknown>> {
|
|
354
527
|
where<K extends keyof M & string, Op extends WhereFilterOp>(column: K, operator: Op, value: WhereValueFor<Op, M[K]>): this;
|
|
355
|
-
where(logicalCondition:
|
|
528
|
+
where(logicalCondition: LogicalConditionFor<M>): this;
|
|
356
529
|
orderBy(column: (keyof M & string) | ComputedSortField, direction?: "asc" | "desc"): this;
|
|
357
530
|
limit(count: number): this;
|
|
358
531
|
offset(count: number): this;
|
|
@@ -395,7 +568,7 @@ export interface CollectionAccessor<M extends Record<string, unknown> = Record<s
|
|
|
395
568
|
/**
|
|
396
569
|
* Find a single record by its ID.
|
|
397
570
|
*/
|
|
398
|
-
findById(id: string | number): Promise<Entity<M> | undefined>;
|
|
571
|
+
findById(id: string | number, options?: ByIdReadOptions): Promise<Entity<M> | undefined>;
|
|
399
572
|
/**
|
|
400
573
|
* Create a new record.
|
|
401
574
|
* @param data The entity data to create.
|
|
@@ -415,9 +588,16 @@ export interface CollectionAccessor<M extends Record<string, unknown> = Record<s
|
|
|
415
588
|
}): Promise<Entity<M>[]>;
|
|
416
589
|
/**
|
|
417
590
|
* Update an existing record by ID.
|
|
591
|
+
*
|
|
592
|
+
* `options.ifMatch` is the version the edit was made against
|
|
593
|
+
* ({@link Entity.etag}): the write is refused with `412
|
|
594
|
+
* PRECONDITION_FAILED` when the row has changed since. A data source that
|
|
595
|
+
* cannot check one ignores it, and the write is unconditional.
|
|
418
596
|
* @returns The updated entity
|
|
419
597
|
*/
|
|
420
|
-
update(id: string | number, data: Partial<EntityValues<M
|
|
598
|
+
update(id: string | number, data: Partial<EntityValues<M>>, options?: {
|
|
599
|
+
ifMatch?: string;
|
|
600
|
+
}): Promise<Entity<M>>;
|
|
421
601
|
/**
|
|
422
602
|
* Update many records in a single transaction.
|
|
423
603
|
*
|
|
@@ -443,10 +623,23 @@ export interface CollectionAccessor<M extends Record<string, unknown> = Record<s
|
|
|
443
623
|
*/
|
|
444
624
|
listen?(params: FindParams<M> | undefined, onUpdate: (response: FindResponse<M>) => void, onError?: (error: Error) => void): () => void;
|
|
445
625
|
/**
|
|
446
|
-
* Subscribe to a single record for real-time updates
|
|
626
|
+
* Subscribe to a single record for real-time updates: every frame is the
|
|
627
|
+
* record as `findById(id, options)` reads it.
|
|
447
628
|
* Optional method.
|
|
448
629
|
*/
|
|
449
|
-
listenById?(id: string | number, onUpdate: (entity: Entity<M> | undefined) => void, onError?: (error: Error) => void): () => void;
|
|
630
|
+
listenById?(id: string | number, onUpdate: (entity: Entity<M> | undefined) => void, onError?: (error: Error) => void, options?: ByIdReadOptions): () => void;
|
|
631
|
+
/**
|
|
632
|
+
* {@link SDKCollectionClient.listenCount}: the matching rows' count, live.
|
|
633
|
+
* Optional method; absent where the data source cannot subscribe.
|
|
634
|
+
*/
|
|
635
|
+
listenCount?(params: FindParams<M> | undefined, onCount: (total: number) => void, onError?: (error: Error) => void): () => void;
|
|
636
|
+
/**
|
|
637
|
+
* The rows a soft delete stamped, and the delete that removes a row for
|
|
638
|
+
* good: what {@link SDKCollectionClient.trash} is built from. A restore is
|
|
639
|
+
* an ordinary {@link update}. Optional; absent where the data source
|
|
640
|
+
* cannot read a collection's trash.
|
|
641
|
+
*/
|
|
642
|
+
trash?: CollectionTrashAccessor<M>;
|
|
450
643
|
/**
|
|
451
644
|
* Count the number of records matching the given filter.
|
|
452
645
|
*
|
|
@@ -463,9 +656,9 @@ export interface CollectionAccessor<M extends Record<string, unknown> = Record<s
|
|
|
463
656
|
* absent implementation in a stub that says so rather than returning a
|
|
464
657
|
* number nothing counted.
|
|
465
658
|
*/
|
|
466
|
-
aggregate?(params: AggregateParams<M>): Promise<
|
|
659
|
+
aggregate?(params: AggregateParams<M>): Promise<AggregateResult>;
|
|
467
660
|
where<K extends keyof M & string, Op extends WhereFilterOp>(column: K, operator: Op, value: WhereValueFor<Op, M[K]>): QueryBuilderInterface<M>;
|
|
468
|
-
where(logicalCondition:
|
|
661
|
+
where(logicalCondition: LogicalConditionFor<M>): QueryBuilderInterface<M>;
|
|
469
662
|
orderBy(column: (keyof M & string) | ComputedSortField, direction?: "asc" | "desc"): QueryBuilderInterface<M>;
|
|
470
663
|
limit(count: number): QueryBuilderInterface<M>;
|
|
471
664
|
offset(count: number): QueryBuilderInterface<M>;
|
|
@@ -492,6 +685,11 @@ export interface CollectionAccessor<M extends Record<string, unknown> = Record<s
|
|
|
492
685
|
* @group Data
|
|
493
686
|
*/
|
|
494
687
|
export interface PaginationMeta {
|
|
688
|
+
/**
|
|
689
|
+
* Every row the query matches, counted. Not counted — and absent from an
|
|
690
|
+
* HTTP response — when the query asked for {@link FindParams.count}
|
|
691
|
+
* `"none"`, and on a `distinct` read over HTTP.
|
|
692
|
+
*/
|
|
495
693
|
total: number;
|
|
496
694
|
limit: number;
|
|
497
695
|
offset: number;
|
|
@@ -587,9 +785,26 @@ export type AggregateSelect<M extends Record<string, unknown> = Record<string, u
|
|
|
587
785
|
fn: "count";
|
|
588
786
|
field?: Extract<keyof M, string>;
|
|
589
787
|
} | {
|
|
590
|
-
fn: "sum" | "avg"
|
|
788
|
+
fn: "sum" | "avg";
|
|
789
|
+
field: NumericKeyOf<M>;
|
|
790
|
+
} | {
|
|
791
|
+
fn: "min" | "max";
|
|
591
792
|
field: Extract<keyof M, string>;
|
|
592
793
|
};
|
|
794
|
+
/**
|
|
795
|
+
* The columns of `M` that hold numbers — what `sum` and `avg` can add up. Any
|
|
796
|
+
* column used to be accepted, and `sum` of a text column was a 400. An untyped
|
|
797
|
+
* row (every key `string`) keeps every name.
|
|
798
|
+
*
|
|
799
|
+
* Written as the keys of a key-remapped mapped type, not as a conditional over
|
|
800
|
+
* `keyof M`: tsc measures the conditional form as invariant in `M`, which made
|
|
801
|
+
* a typed `SDKCollectionClient<Post>` unassignable to the wide
|
|
802
|
+
* `SDKCollectionClient` that helpers taking any collection accept. A mapped
|
|
803
|
+
* type is related structurally, so a typed client still widens.
|
|
804
|
+
*/
|
|
805
|
+
export type NumericKeyOf<M extends Record<string, unknown>> = Extract<keyof {
|
|
806
|
+
[K in keyof M as string extends K ? K : NonNullable<M[K]> extends number ? K : never]: M[K];
|
|
807
|
+
}, string>;
|
|
593
808
|
/**
|
|
594
809
|
* One row of an aggregate result: the `groupBy` columns, plus one key per
|
|
595
810
|
* {@link AggregateSelect} under its derived alias.
|
|
@@ -605,14 +820,15 @@ export type AggregateRow = Record<string, unknown>;
|
|
|
605
820
|
* What {@link SDKCollectionClient.aggregate} takes: the same narrowing a
|
|
606
821
|
* `find()` takes, minus the parts of it that describe a *page* of rows.
|
|
607
822
|
*
|
|
608
|
-
* `limit`
|
|
609
|
-
*
|
|
610
|
-
*
|
|
611
|
-
*
|
|
823
|
+
* `limit` and `offset` page through the **groups**, as they page a listing's
|
|
824
|
+
* rows, because grouping by a high-cardinality column is a whole table's worth
|
|
825
|
+
* of rows in one response. Over HTTP a grouped aggregate with no `limit` gets
|
|
826
|
+
* the listing default (50 groups) — read {@link AggregateResult.meta} to know
|
|
827
|
+
* when there were more. Without `groupBy` there is one row: `limit` does nothing
|
|
828
|
+
* there and `offset` is refused.
|
|
612
829
|
*
|
|
613
|
-
* `
|
|
614
|
-
*
|
|
615
|
-
* They were silently ignored on the REST route; here they do not typecheck.
|
|
830
|
+
* `include`, `after` and the rest are absent on purpose: an aggregate has no
|
|
831
|
+
* relations to load and no row to continue after.
|
|
616
832
|
*
|
|
617
833
|
* @group Data
|
|
618
834
|
*/
|
|
@@ -622,20 +838,81 @@ export interface AggregateParams<M extends Record<string, unknown> = Record<stri
|
|
|
622
838
|
/** Columns to group by. Omit for a single row over everything that matches. */
|
|
623
839
|
groupBy?: Extract<keyof M, string>[];
|
|
624
840
|
/** Filter conditions, as {@link FindParams.where}. */
|
|
625
|
-
where?:
|
|
841
|
+
where?: WhereFor<M>;
|
|
626
842
|
/** An `and`/`or`/`not` group, AND-ed with `where`. */
|
|
627
|
-
logical?:
|
|
843
|
+
logical?: LogicalConditionFor<M>;
|
|
628
844
|
/** Text search, AND-ed with the filters. */
|
|
629
845
|
searchString?: string;
|
|
630
|
-
/** Most groups to return.
|
|
846
|
+
/** Most groups to return. Grouped aggregates only. */
|
|
631
847
|
limit?: number;
|
|
848
|
+
/** Groups to skip, to page past `limit`. Grouped aggregates only. */
|
|
849
|
+
offset?: number;
|
|
850
|
+
/**
|
|
851
|
+
* Sort the groups — by a `groupBy` column or by an aggregate's alias
|
|
852
|
+
* (`"count"`, `"sum_total"`, see {@link AggregateAlias}). One
|
|
853
|
+
* `[key, "asc" | "desc"]` tuple, or several applied in order. Groups the
|
|
854
|
+
* sort leaves tied keep their `groupBy` order. Grouped aggregates only:
|
|
855
|
+
* without `groupBy` there is one row, and over HTTP an `orderBy` beside it is
|
|
856
|
+
* refused with `INVALID_AGGREGATE_WINDOW`. A key that is neither a group
|
|
857
|
+
* column nor a selected aggregate is refused with `INVALID_ORDER_BY`.
|
|
858
|
+
*
|
|
859
|
+
* ```ts
|
|
860
|
+
* await client.data.orders.aggregate({
|
|
861
|
+
* select: [{ fn: "sum", field: "total" }],
|
|
862
|
+
* groupBy: ["status"],
|
|
863
|
+
* orderBy: ["sum_total", "desc"]
|
|
864
|
+
* });
|
|
865
|
+
* ```
|
|
866
|
+
*/
|
|
867
|
+
orderBy?: OrderByTuple<AggregateOrderKey<M>> | OrderByTuple<AggregateOrderKey<M>>[];
|
|
632
868
|
}
|
|
633
869
|
/**
|
|
634
|
-
*
|
|
870
|
+
* The key an {@link AggregateSelect} comes back under: `count` for `count()`,
|
|
871
|
+
* `<fn>_<field>` otherwise (`sum_total`, `max_created_at`).
|
|
872
|
+
*
|
|
873
|
+
* @group Data
|
|
874
|
+
*/
|
|
875
|
+
export type AggregateAlias<M extends Record<string, unknown> = Record<string, unknown>> = "count" | `${"count" | "min" | "max"}_${Extract<keyof M, string>}` | `${"sum" | "avg"}_${NumericKeyOf<M>}`;
|
|
876
|
+
/**
|
|
877
|
+
* What {@link AggregateParams.orderBy} can sort the groups by: a column (to
|
|
878
|
+
* group by) or an aggregate's alias.
|
|
879
|
+
*
|
|
880
|
+
* @group Data
|
|
881
|
+
*/
|
|
882
|
+
export type AggregateOrderKey<M extends Record<string, unknown> = Record<string, unknown>> = Extract<keyof M, string> | AggregateAlias<M>;
|
|
883
|
+
/**
|
|
884
|
+
* Where a grouped aggregate's page of groups sits: the `limit` it was cut at,
|
|
885
|
+
* the `offset` it started from, and whether more groups follow.
|
|
886
|
+
*
|
|
887
|
+
* @group Data
|
|
888
|
+
*/
|
|
889
|
+
export interface AggregateMeta {
|
|
890
|
+
limit: number;
|
|
891
|
+
offset: number;
|
|
892
|
+
hasMore: boolean;
|
|
893
|
+
}
|
|
894
|
+
/**
|
|
895
|
+
* What {@link SDKCollectionClient.aggregate} resolves to: the rows, as an
|
|
896
|
+
* array, carrying the page they are as `meta`.
|
|
897
|
+
*
|
|
898
|
+
* `meta` is present on a grouped aggregate that was cut at a `limit` — which,
|
|
899
|
+
* over HTTP, is every grouped one, since the route applies the listing default
|
|
900
|
+
* when none is given. `hasMore: true` means the groups did not all fit: page on
|
|
901
|
+
* with `offset`, or raise `limit`. It is a non-enumerable property, so a spread,
|
|
902
|
+
* `JSON.stringify` or `Object.keys` of the result sees only the rows.
|
|
903
|
+
*
|
|
904
|
+
* @group Data
|
|
905
|
+
*/
|
|
906
|
+
export interface AggregateResult extends Array<AggregateRow> {
|
|
907
|
+
readonly meta?: AggregateMeta;
|
|
908
|
+
}
|
|
909
|
+
/**
|
|
910
|
+
* Which column an iteration sorts by when it is asked to seek, for keyset
|
|
911
|
+
* ("seek") pagination.
|
|
635
912
|
*
|
|
636
913
|
* Either the column name on its own — sorted ascending — or the column plus an
|
|
637
|
-
* explicit direction.
|
|
638
|
-
*
|
|
914
|
+
* explicit direction. It is used only when the query names no `orderBy`; see
|
|
915
|
+
* {@link PageWalkOptions.cursor}.
|
|
639
916
|
*
|
|
640
917
|
* @group Data
|
|
641
918
|
*/
|
|
@@ -657,23 +934,23 @@ export interface PageWalkOptions<M extends Record<string, unknown> = Record<stri
|
|
|
657
934
|
*/
|
|
658
935
|
pageSize?: number;
|
|
659
936
|
/**
|
|
660
|
-
*
|
|
937
|
+
* **Require** seeking: fail rather than fall back to offset paging.
|
|
661
938
|
*
|
|
662
|
-
*
|
|
663
|
-
*
|
|
664
|
-
*
|
|
665
|
-
*
|
|
666
|
-
*
|
|
939
|
+
* Every walk already seeks when it can. After the first page it hands the
|
|
940
|
+
* server's `meta.nextCursor` back as `after`, so each page asks for rows
|
|
941
|
+
* strictly after the last one seen — concurrent writes before that row
|
|
942
|
+
* cannot shift the window, and the database never skips rows by count.
|
|
943
|
+
* Where the server issues no cursor (a relevance-ordered search, a vector
|
|
944
|
+
* search, a `distinct` read, a server that predates cursors), the default
|
|
945
|
+
* walk pages by offset instead, which a concurrent insert or delete can
|
|
946
|
+
* make skip or repeat a row.
|
|
667
947
|
*
|
|
668
|
-
*
|
|
669
|
-
*
|
|
670
|
-
*
|
|
671
|
-
*
|
|
672
|
-
*
|
|
673
|
-
*
|
|
674
|
-
* Implemented with the parameters `find()` already takes (an `orderBy` plus
|
|
675
|
-
* a `>` / `<` filter on the cursor column), so it works on every transport
|
|
676
|
-
* and needs nothing new from the server.
|
|
948
|
+
* Passing `cursor` turns that fallback into an error: a listing with no
|
|
949
|
+
* cursor throws `cursor-missing`, and a cursor that stops advancing throws
|
|
950
|
+
* `cursor-stalled`. It also names the column to sort by when the query has
|
|
951
|
+
* no `orderBy`; an explicit `orderBy` wins, and the cursor follows whatever
|
|
952
|
+
* the query is sorted by, multi-key sorts and nullable keys included. The
|
|
953
|
+
* row id breaks the final tie, so the order is always total.
|
|
677
954
|
*
|
|
678
955
|
* @example
|
|
679
956
|
* for await (const job of client.data.jobs.iterate({ cursor: "id" })) { … }
|
|
@@ -691,9 +968,12 @@ export interface PageWalkOptions<M extends Record<string, unknown> = Record<stri
|
|
|
691
968
|
* `find()` takes except the window itself (`limit`, `offset`, `page`), which
|
|
692
969
|
* the iterator owns, plus the walk options.
|
|
693
970
|
*
|
|
971
|
+
* `count` is accepted and ignored: no page of a walk is counted, since nothing
|
|
972
|
+
* a walk returns carries a total (see {@link FindParams.count}).
|
|
973
|
+
*
|
|
694
974
|
* @group Data
|
|
695
975
|
*/
|
|
696
|
-
export type IterateParams<M extends Record<string, unknown> = Record<string, unknown
|
|
976
|
+
export type IterateParams<M extends Record<string, unknown> = Record<string, unknown>, Inc = IncludeSpec> = Omit<FindParams<M, Inc>, "limit" | "offset" | "page"> & PageWalkOptions<M>;
|
|
697
977
|
/**
|
|
698
978
|
* Parameters accepted by {@link SDKCollectionClient.findAll}: the iteration
|
|
699
979
|
* parameters plus the ceiling that keeps a whole collection from being pulled
|
|
@@ -701,7 +981,7 @@ export type IterateParams<M extends Record<string, unknown> = Record<string, unk
|
|
|
701
981
|
*
|
|
702
982
|
* @group Data
|
|
703
983
|
*/
|
|
704
|
-
export type FindAllParams<M extends Record<string, unknown> = Record<string, unknown
|
|
984
|
+
export type FindAllParams<M extends Record<string, unknown> = Record<string, unknown>, Inc = IncludeSpec> = IterateParams<M, Inc> & {
|
|
705
985
|
/**
|
|
706
986
|
* Most rows to materialise. Defaults to 10 000. Exceeding it **throws**
|
|
707
987
|
* — a truncated array returned as if it were the whole answer is the
|
|
@@ -716,7 +996,7 @@ export type FindAllParams<M extends Record<string, unknown> = Record<string, unk
|
|
|
716
996
|
*
|
|
717
997
|
* @group Data
|
|
718
998
|
*/
|
|
719
|
-
export interface SDKQueryBuilderInterface<M extends Record<string, unknown> = Record<string, unknown
|
|
999
|
+
export interface SDKQueryBuilderInterface<M extends Record<string, unknown> = Record<string, unknown>, Inc = IncludeSpec> {
|
|
720
1000
|
where<K extends keyof M & string, Op extends WhereFilterOp>(column: K, operator: Op, value: WhereValueFor<Op, M[K]>): this;
|
|
721
1001
|
/**
|
|
722
1002
|
* Filter on a relation path (`author.name`) or a JSON path
|
|
@@ -733,7 +1013,7 @@ export interface SDKQueryBuilderInterface<M extends Record<string, unknown> = Re
|
|
|
733
1013
|
* errors on a typed client.
|
|
734
1014
|
*/
|
|
735
1015
|
where(column: NonColumnFieldPath, operator: WhereFilterOp, value: unknown): this;
|
|
736
|
-
where(logicalCondition:
|
|
1016
|
+
where(logicalCondition: LogicalConditionFor<M>): this;
|
|
737
1017
|
/**
|
|
738
1018
|
* Sort by a column, a relation or JSON path, `_score`, or an aggregate over
|
|
739
1019
|
* a to-many relation — the same key set {@link FindParams.orderBy} takes.
|
|
@@ -753,7 +1033,7 @@ export interface SDKQueryBuilderInterface<M extends Record<string, unknown> = Re
|
|
|
753
1033
|
*
|
|
754
1034
|
* The query embedding is the caller's to produce.
|
|
755
1035
|
*/
|
|
756
|
-
vectorSearch(property:
|
|
1036
|
+
vectorSearch(property: Extract<keyof M, string>, vector: number[], options?: {
|
|
757
1037
|
distance?: "cosine" | "l2" | "inner_product";
|
|
758
1038
|
threshold?: number;
|
|
759
1039
|
}): this;
|
|
@@ -761,12 +1041,12 @@ export interface SDKQueryBuilderInterface<M extends Record<string, unknown> = Re
|
|
|
761
1041
|
* Load relations — names, dotted paths (`"comments.author"`), or the
|
|
762
1042
|
* parametrised tree. Repeated calls merge rather than replace.
|
|
763
1043
|
*/
|
|
764
|
-
include(...relations:
|
|
1044
|
+
include(...relations: IncludeArgOf<Inc>[]): this;
|
|
765
1045
|
/**
|
|
766
1046
|
* Return only these columns. A real projection: the columns are what is
|
|
767
1047
|
* read from the database, not what survives a trim of the response.
|
|
768
1048
|
*/
|
|
769
|
-
fields(...columns:
|
|
1049
|
+
fields(...columns: Extract<keyof M, string>[]): this;
|
|
770
1050
|
/** `SELECT DISTINCT` over the projection — see {@link FindParams.distinct}. */
|
|
771
1051
|
distinct(enabled?: boolean): this;
|
|
772
1052
|
/** Continue after a previous page's `meta.nextCursor`. */
|
|
@@ -777,9 +1057,10 @@ export interface SDKQueryBuilderInterface<M extends Record<string, unknown> = Re
|
|
|
777
1057
|
*
|
|
778
1058
|
* The builder's `where`/`logical`/`search` narrow which rows are
|
|
779
1059
|
* aggregated; its `orderBy`, `include` and window do not apply and are
|
|
780
|
-
* ignored, exactly as they are on the REST route.
|
|
1060
|
+
* ignored, exactly as they are on the REST route. Page the groups with the
|
|
1061
|
+
* `limit`/`offset` passed here.
|
|
781
1062
|
*/
|
|
782
|
-
aggregate(params: Omit<AggregateParams<M>, "where" | "logical" | "searchString">): Promise<
|
|
1063
|
+
aggregate(params: Omit<AggregateParams<M>, "where" | "logical" | "searchString">): Promise<AggregateResult>;
|
|
783
1064
|
/**
|
|
784
1065
|
* Page through everything this query matches, one row at a time.
|
|
785
1066
|
*
|
|
@@ -867,10 +1148,13 @@ export declare const BATCH_REF_KEY = "$ref";
|
|
|
867
1148
|
* one, which is the case worth catching.
|
|
868
1149
|
*
|
|
869
1150
|
* Any `$`-prefixed key counts, because `{ $increment: 1 }` written to a number
|
|
870
|
-
* column as a JSON document is the failure this exists to prevent.
|
|
871
|
-
*
|
|
872
|
-
* `map`
|
|
873
|
-
*
|
|
1151
|
+
* column as a JSON document is the failure this exists to prevent.
|
|
1152
|
+
*
|
|
1153
|
+
* Except on a `map` (pass `propertyType`): a map's value is a JSON document,
|
|
1154
|
+
* and one may legitimately carry `$` keys — a JSON Schema's `$schema`, a
|
|
1155
|
+
* MongoDB-style export. There, only a single-key object whose key is one of
|
|
1156
|
+
* {@link FIELD_OPERATORS} is an operation, and anything else is data. A caller
|
|
1157
|
+
* that does not know the property type gets the strict reading.
|
|
874
1158
|
*
|
|
875
1159
|
* The one exception is `{ $ref: … }`, the batch's backward reference. It stands
|
|
876
1160
|
* where a *value* goes and is resolved to one before the row is written, so it
|
|
@@ -879,7 +1163,7 @@ export declare const BATCH_REF_KEY = "$ref";
|
|
|
879
1163
|
*
|
|
880
1164
|
* @group Data
|
|
881
1165
|
*/
|
|
882
|
-
export declare function isFieldOperation(value: unknown): boolean;
|
|
1166
|
+
export declare function isFieldOperation(value: unknown, propertyType?: string): boolean;
|
|
883
1167
|
/** True when any value in a write payload is (or is attempting to be) one. @group Data */
|
|
884
1168
|
export declare function hasFieldOperation(values: Record<string, unknown> | undefined): boolean;
|
|
885
1169
|
export type FieldOperation =
|
|
@@ -906,8 +1190,23 @@ export type FieldOperation =
|
|
|
906
1190
|
* @group Data
|
|
907
1191
|
*/
|
|
908
1192
|
export type UpdateValues<U> = {
|
|
909
|
-
[K in keyof U]?: U[K] |
|
|
1193
|
+
[K in keyof U]?: U[K] | FieldOperationFor<U[K]>;
|
|
910
1194
|
};
|
|
1195
|
+
/**
|
|
1196
|
+
* The field operations a column of type `T` takes: `$inc` on a number, `$push`
|
|
1197
|
+
* / `$pull` on an array, `$merge` on a map. Any operation on any column used to
|
|
1198
|
+
* compile — `update(id, { title: { $inc: 1 } })` — and the server answered 400.
|
|
1199
|
+
* A column whose type says nothing (`unknown`, an untyped client) takes them all.
|
|
1200
|
+
*/
|
|
1201
|
+
export type FieldOperationFor<T> = unknown extends T ? FieldOperation : (NonNullable<T> extends number ? {
|
|
1202
|
+
$inc: number;
|
|
1203
|
+
} : never) | (NonNullable<T> extends readonly unknown[] ? {
|
|
1204
|
+
$push: unknown;
|
|
1205
|
+
} | {
|
|
1206
|
+
$pull: unknown;
|
|
1207
|
+
} : never) | (NonNullable<T> extends readonly unknown[] ? never : NonNullable<T> extends Record<string, unknown> ? {
|
|
1208
|
+
$merge: Record<string, unknown>;
|
|
1209
|
+
} : never);
|
|
911
1210
|
/**
|
|
912
1211
|
* Where an upsert looks for the row it might be replacing.
|
|
913
1212
|
*
|
|
@@ -944,22 +1243,40 @@ export interface BatchRef {
|
|
|
944
1243
|
/** `<ref name>.<field>`, e.g. `order.id`. */
|
|
945
1244
|
$ref: string;
|
|
946
1245
|
}
|
|
947
|
-
/**
|
|
1246
|
+
/**
|
|
1247
|
+
* A row's values in a batch: the collection's own columns, each of which may
|
|
1248
|
+
* instead be a {@link BatchRef} to a value an earlier operation produces.
|
|
1249
|
+
*
|
|
1250
|
+
* Homomorphic over the row type, so a column the row type requires is required
|
|
1251
|
+
* here too — a create in a batch is the same insert `create()` is. There used
|
|
1252
|
+
* to be an `& Record<string, unknown>` on the end, which let a misspelt column
|
|
1253
|
+
* compile and come back as a 400 `VALIDATION_UNKNOWN_FIELDS`.
|
|
1254
|
+
*/
|
|
1255
|
+
type BatchValues<T> = {
|
|
1256
|
+
[F in keyof T]: T[F] | BatchRef;
|
|
1257
|
+
};
|
|
1258
|
+
/**
|
|
1259
|
+
* One entry of a batch request.
|
|
1260
|
+
*
|
|
1261
|
+
* `collection` is the collection's **accessor** on a typed client — the name
|
|
1262
|
+
* `client.data.<accessor>` takes, and the key of the generated `Database`
|
|
1263
|
+
* (`orderItems`). The client resolves it to the slug the route knows
|
|
1264
|
+
* (`order_items`) through its `collections` dictionary; a slug that is not an
|
|
1265
|
+
* accessor is sent as written.
|
|
1266
|
+
*
|
|
1267
|
+
* @group Data
|
|
1268
|
+
*/
|
|
948
1269
|
export type BatchOperation<DB = Record<string, unknown>> = {
|
|
949
1270
|
[K in Extract<keyof DB, string>]: {
|
|
950
1271
|
op: "create";
|
|
951
1272
|
collection: K;
|
|
952
|
-
values:
|
|
953
|
-
[F in keyof InsertOf<DB[K]>]?: InsertOf<DB[K]>[F] | BatchRef;
|
|
954
|
-
} & Record<string, unknown>;
|
|
1273
|
+
values: BatchValues<InsertOf<DB[K]>>;
|
|
955
1274
|
/** Name this row so a later operation can reference its columns. */
|
|
956
1275
|
ref?: string;
|
|
957
1276
|
} | {
|
|
958
1277
|
op: "upsert";
|
|
959
1278
|
collection: K;
|
|
960
|
-
values:
|
|
961
|
-
[F in keyof InsertOf<DB[K]>]?: InsertOf<DB[K]>[F] | BatchRef;
|
|
962
|
-
} & Record<string, unknown>;
|
|
1279
|
+
values: BatchValues<InsertOf<DB[K]>>;
|
|
963
1280
|
/** See {@link UpsertOptions.onConflict}. Defaults to the primary key. */
|
|
964
1281
|
onConflict?: readonly string[];
|
|
965
1282
|
ref?: string;
|
|
@@ -968,8 +1285,8 @@ export type BatchOperation<DB = Record<string, unknown>> = {
|
|
|
968
1285
|
collection: K;
|
|
969
1286
|
id: string | number | BatchRef;
|
|
970
1287
|
values: {
|
|
971
|
-
[F in keyof UpdateOf<DB[K]>]?: UpdateOf<DB[K]>[F] |
|
|
972
|
-
}
|
|
1288
|
+
[F in keyof UpdateOf<DB[K]>]?: UpdateOf<DB[K]>[F] | FieldOperationFor<UpdateOf<DB[K]>[F]> | BatchRef;
|
|
1289
|
+
};
|
|
973
1290
|
ref?: string;
|
|
974
1291
|
} | {
|
|
975
1292
|
op: "delete";
|
|
@@ -1021,6 +1338,10 @@ export interface WriteOptions {
|
|
|
1021
1338
|
* attempt is still being answered gets `IDEMPOTENCY_KEY_IN_PROGRESS` (409)
|
|
1022
1339
|
* and should be sent again. A server that cannot store keys ignores the
|
|
1023
1340
|
* header rather than refusing the write.
|
|
1341
|
+
*
|
|
1342
|
+
* The in-process accessor (`context.data`, `rebase.data`) has no store to
|
|
1343
|
+
* keep keys in, and refuses one with `UNSUPPORTED_OPTION` rather than
|
|
1344
|
+
* writing as though it had been checked.
|
|
1024
1345
|
*/
|
|
1025
1346
|
idempotencyKey?: string;
|
|
1026
1347
|
/**
|
|
@@ -1035,7 +1356,9 @@ export interface WriteOptions {
|
|
|
1035
1356
|
*
|
|
1036
1357
|
* Reach for it on imports and fire-and-forget writes. The method resolves
|
|
1037
1358
|
* to `undefined` (or `[]`) when it is set, so a caller cannot accidentally
|
|
1038
|
-
* use a row the server never sent
|
|
1359
|
+
* use a row the server never sent — and `create`, `update` and `upsert`
|
|
1360
|
+
* are typed `M | undefined` for a literal `returning: false`, so reading a
|
|
1361
|
+
* field off the result is a compile error rather than a `TypeError`.
|
|
1039
1362
|
*/
|
|
1040
1363
|
returning?: boolean;
|
|
1041
1364
|
/**
|
|
@@ -1051,11 +1374,75 @@ export interface WriteOptions {
|
|
|
1051
1374
|
*
|
|
1052
1375
|
* `"*"` asserts only that the row exists.
|
|
1053
1376
|
*
|
|
1054
|
-
* Honoured on `update` and `delete
|
|
1377
|
+
* Honoured on `update` and `delete` over HTTP. The in-process accessor
|
|
1378
|
+
* (`context.data`, `rebase.data`) cannot check a precondition yet, and
|
|
1379
|
+
* refuses one with `UNSUPPORTED_OPTION` rather than writing unconditionally.
|
|
1055
1380
|
*/
|
|
1056
1381
|
ifMatch?: string;
|
|
1057
1382
|
}
|
|
1058
|
-
|
|
1383
|
+
/**
|
|
1384
|
+
* The entity-shaped half of {@link TrashClient}, on a {@link CollectionAccessor}.
|
|
1385
|
+
*/
|
|
1386
|
+
export interface CollectionTrashAccessor<M extends Record<string, unknown> = Record<string, unknown>> {
|
|
1387
|
+
/** The trashed rows matching `params`. */
|
|
1388
|
+
find(params?: FindParams<M>): Promise<FindResponse<M>>;
|
|
1389
|
+
/** How many trashed rows match `params`. */
|
|
1390
|
+
count(params?: FindParams<M>): Promise<number>;
|
|
1391
|
+
/** Delete a row for good, trashed or live. */
|
|
1392
|
+
purge(id: string | number): Promise<void>;
|
|
1393
|
+
/** {@link purge} for several rows, as one transaction, where the data source can. */
|
|
1394
|
+
purgeMany?(ids: (string | number)[]): Promise<void>;
|
|
1395
|
+
}
|
|
1396
|
+
/**
|
|
1397
|
+
* Options for {@link TrashClient.restore} and {@link TrashClient.restoreMany}.
|
|
1398
|
+
*/
|
|
1399
|
+
export interface RestoreOptions<M extends Record<string, unknown> = Record<string, unknown>> extends WriteOptions {
|
|
1400
|
+
/**
|
|
1401
|
+
* The collection's soft-delete field, as declared in `softDelete`.
|
|
1402
|
+
* Defaults to `deletedAt`, the field `softDelete: true` uses; pass the
|
|
1403
|
+
* name a `softDelete: { field: "archivedAt" }` collection declares.
|
|
1404
|
+
*
|
|
1405
|
+
* A restore is an ordinary update setting this field to `null`, which is
|
|
1406
|
+
* the one update the server lets reach a trashed row.
|
|
1407
|
+
*/
|
|
1408
|
+
field?: keyof M & string;
|
|
1409
|
+
}
|
|
1410
|
+
/**
|
|
1411
|
+
* The trash of a collection that declares `softDelete`: the rows a delete
|
|
1412
|
+
* stamped rather than removed. `client.data.<slug>.trash` in the browser,
|
|
1413
|
+
* `context.data.<slug>.trash` and `rebase.data.<slug>.trash` on the server.
|
|
1414
|
+
*
|
|
1415
|
+
* For a collection that declares `softDelete`. On one that does not, `find`
|
|
1416
|
+
* and `count` answer for the live rows, `restore` is refused for a field the
|
|
1417
|
+
* collection does not have, and `purge` is an ordinary delete.
|
|
1418
|
+
*
|
|
1419
|
+
* Where the data source cannot read a trash, every method is a stub that
|
|
1420
|
+
* throws when called.
|
|
1421
|
+
*/
|
|
1422
|
+
export interface TrashClient<M extends Record<string, unknown> = Record<string, unknown>, Inc = IncludeSpec> {
|
|
1423
|
+
/** The trashed rows matching `params` — `GET /data/<slug>?deleted=only`. */
|
|
1424
|
+
find(params?: FindParams<M, Inc>): Promise<FindResult<M>>;
|
|
1425
|
+
/** How many trashed rows match `params` — `GET /data/<slug>/count?deleted=only`. */
|
|
1426
|
+
count(params?: FindParams<M, Inc>): Promise<number>;
|
|
1427
|
+
/**
|
|
1428
|
+
* Bring a trashed row back: the update setting the soft-delete field to
|
|
1429
|
+
* `null` (`PATCH /data/<slug>/<id>`). Resolves with the restored row.
|
|
1430
|
+
*/
|
|
1431
|
+
restore(id: string | number, options?: RestoreOptions<M>): Promise<M>;
|
|
1432
|
+
/** {@link TrashClient.restore} for several rows, as one transaction (`PATCH /data/<slug>/bulk`). */
|
|
1433
|
+
restoreMany(ids: (string | number)[], options?: RestoreOptions<M>): Promise<M[]>;
|
|
1434
|
+
/**
|
|
1435
|
+
* Delete a row for good — `DELETE /data/<slug>/<id>?hard=true`. It cannot
|
|
1436
|
+
* be restored afterwards. Needs the same permission an ordinary delete
|
|
1437
|
+
* does, and works on a live row as well as a trashed one.
|
|
1438
|
+
*/
|
|
1439
|
+
purge(id: string | number, options?: WriteOptions): Promise<void>;
|
|
1440
|
+
/** {@link TrashClient.purge} for several rows, as one transaction (`POST /data/<slug>/bulk/delete?hard=true`). */
|
|
1441
|
+
purgeMany(ids: (string | number)[], options?: WriteOptions): Promise<void>;
|
|
1442
|
+
}
|
|
1443
|
+
export interface SDKCollectionClient<M extends Record<string, unknown> = Record<string, unknown>, I = Partial<M>, U = Partial<M>,
|
|
1444
|
+
/** The include this collection takes; {@link IncludeOf} for a generated `Database`. */
|
|
1445
|
+
Inc = IncludeSpec> {
|
|
1059
1446
|
/**
|
|
1060
1447
|
* Find multiple records with optional filtering, pagination, and sorting.
|
|
1061
1448
|
*
|
|
@@ -1079,7 +1466,7 @@ export interface SDKCollectionClient<M extends Record<string, unknown> = Record<
|
|
|
1079
1466
|
* it is where the pagination metadata lives, and it is present exactly when
|
|
1080
1467
|
* there is some.
|
|
1081
1468
|
*/
|
|
1082
|
-
find(params?: FindParams<M>): Promise<FindResult<M>>;
|
|
1469
|
+
find(params?: FindParams<M, Inc>): Promise<FindResult<M>>;
|
|
1083
1470
|
/**
|
|
1084
1471
|
* Walk every record matching a query, one row at a time, fetching pages as
|
|
1085
1472
|
* the consumer consumes them.
|
|
@@ -1099,14 +1486,15 @@ export interface SDKCollectionClient<M extends Record<string, unknown> = Record<
|
|
|
1099
1486
|
*
|
|
1100
1487
|
* ## Consistency
|
|
1101
1488
|
*
|
|
1102
|
-
*
|
|
1103
|
-
*
|
|
1104
|
-
*
|
|
1105
|
-
*
|
|
1106
|
-
*
|
|
1107
|
-
*
|
|
1108
|
-
*
|
|
1109
|
-
*
|
|
1489
|
+
* After the first page the walk **seeks**: it hands the server's
|
|
1490
|
+
* `meta.nextCursor` back as `after`, so each page asks for rows strictly
|
|
1491
|
+
* after the last one it saw, which concurrent writes cannot perturb. A
|
|
1492
|
+
* listing the server issues no cursor for — relevance, a vector search, a
|
|
1493
|
+
* `distinct` read — is paged by **offset** instead, which is only as stable
|
|
1494
|
+
* as the table is still: a row inserted or deleted ahead of the window
|
|
1495
|
+
* between two requests shifts every later one, so the walk can skip a row
|
|
1496
|
+
* or hand back the same one twice. Pass {@link PageWalkOptions.cursor} to
|
|
1497
|
+
* make seeking a requirement rather than a preference.
|
|
1110
1498
|
*
|
|
1111
1499
|
* @example
|
|
1112
1500
|
* for await (const job of client.data.jobs.iterate({
|
|
@@ -1117,7 +1505,7 @@ export interface SDKCollectionClient<M extends Record<string, unknown> = Record<
|
|
|
1117
1505
|
* await handle(job);
|
|
1118
1506
|
* }
|
|
1119
1507
|
*/
|
|
1120
|
-
iterate(params?: IterateParams<M>): AsyncIterableIterator<M>;
|
|
1508
|
+
iterate(params?: IterateParams<M, Inc>): AsyncIterableIterator<M>;
|
|
1121
1509
|
/**
|
|
1122
1510
|
* {@link iterate}, collected into an array.
|
|
1123
1511
|
*
|
|
@@ -1128,7 +1516,7 @@ export interface SDKCollectionClient<M extends Record<string, unknown> = Record<
|
|
|
1128
1516
|
* {@link FindAllParams.maxRows} when the data really is bigger, or switch to
|
|
1129
1517
|
* `iterate()` and stream it.
|
|
1130
1518
|
*
|
|
1131
|
-
* The
|
|
1519
|
+
* The consistency notes on {@link iterate} apply here too.
|
|
1132
1520
|
*
|
|
1133
1521
|
* @throws When more rows match than `maxRows` allows.
|
|
1134
1522
|
*
|
|
@@ -1138,11 +1526,12 @@ export interface SDKCollectionClient<M extends Record<string, unknown> = Record<
|
|
|
1138
1526
|
* cursor: "id"
|
|
1139
1527
|
* });
|
|
1140
1528
|
*/
|
|
1141
|
-
findAll(params?: FindAllParams<M>): Promise<M[]>;
|
|
1529
|
+
findAll(params?: FindAllParams<M, Inc>): Promise<M[]>;
|
|
1142
1530
|
/**
|
|
1143
|
-
* Find a single record by its ID.
|
|
1531
|
+
* Find a single record by its ID. `options.include` loads its relations,
|
|
1532
|
+
* as `find({ include })` does for each row of a list.
|
|
1144
1533
|
*/
|
|
1145
|
-
findById(id: string | number): Promise<M | undefined>;
|
|
1534
|
+
findById(id: string | number, options?: ByIdReadOptions<Inc>): Promise<M | undefined>;
|
|
1146
1535
|
/**
|
|
1147
1536
|
* Read one record by its ID, or throw if it is not there.
|
|
1148
1537
|
*
|
|
@@ -1183,8 +1572,11 @@ export interface SDKCollectionClient<M extends Record<string, unknown> = Record<
|
|
|
1183
1572
|
* on anything else (a `sku`, a composite key), there is no `id` column to
|
|
1184
1573
|
* receive it — put the key in `data` instead, where it belongs among the
|
|
1185
1574
|
* columns.
|
|
1186
|
-
* @returns The created row
|
|
1575
|
+
* @returns The created row — or nothing, with `returning: false`.
|
|
1187
1576
|
*/
|
|
1577
|
+
create(data: I, id: string | number | undefined, options: WriteOptions & {
|
|
1578
|
+
returning: false;
|
|
1579
|
+
}): Promise<M | undefined>;
|
|
1188
1580
|
create(data: I, id?: string | number, options?: WriteOptions): Promise<M>;
|
|
1189
1581
|
/**
|
|
1190
1582
|
* Write many records in a single request and a single transaction.
|
|
@@ -1236,6 +1628,9 @@ export interface SDKCollectionClient<M extends Record<string, unknown> = Record<
|
|
|
1236
1628
|
* that retry from a second deliberate edit — which on a `PATCH` that
|
|
1237
1629
|
* increments or appends is a second edit applied.
|
|
1238
1630
|
*/
|
|
1631
|
+
update(id: string | number, data: U | UpdateValues<U>, options: WriteOptions & {
|
|
1632
|
+
returning: false;
|
|
1633
|
+
}): Promise<M | undefined>;
|
|
1239
1634
|
update(id: string | number, data: U | UpdateValues<U>, options?: WriteOptions): Promise<M>;
|
|
1240
1635
|
/**
|
|
1241
1636
|
* Insert the row, or replace the one already occupying its key.
|
|
@@ -1253,6 +1648,10 @@ export interface SDKCollectionClient<M extends Record<string, unknown> = Record<
|
|
|
1253
1648
|
* `unique` index. Anything else is a 400 rather than a Postgres error
|
|
1254
1649
|
* raised half-way through a transaction.
|
|
1255
1650
|
*
|
|
1651
|
+
* Refused (400 `INVALID_CONFLICT_TARGET`) on the auth collection, whose
|
|
1652
|
+
* rows are the users: a create and an update of a user follow different
|
|
1653
|
+
* rules, and an upsert only learns which it is inside the write.
|
|
1654
|
+
*
|
|
1256
1655
|
* The `on_create` timestamp of a row that already existed is left alone: a
|
|
1257
1656
|
* conflict means the row's creation is a fact about the past, and a nightly
|
|
1258
1657
|
* re-import that reset `createdAt` on everything it touched would take
|
|
@@ -1260,12 +1659,15 @@ export interface SDKCollectionClient<M extends Record<string, unknown> = Record<
|
|
|
1260
1659
|
*
|
|
1261
1660
|
* @example
|
|
1262
1661
|
* ```ts
|
|
1263
|
-
* await client.data.
|
|
1264
|
-
* {
|
|
1265
|
-
* { onConflict: ["
|
|
1662
|
+
* await client.data.products.upsert(
|
|
1663
|
+
* { sku: "LAMP-01", name: "Desk lamp" },
|
|
1664
|
+
* { onConflict: ["sku"] }
|
|
1266
1665
|
* );
|
|
1267
1666
|
* ```
|
|
1268
1667
|
*/
|
|
1668
|
+
upsert(data: I, options: UpsertOptions & {
|
|
1669
|
+
returning: false;
|
|
1670
|
+
}): Promise<M | undefined>;
|
|
1269
1671
|
upsert(data: I, options?: UpsertOptions): Promise<M>;
|
|
1270
1672
|
/**
|
|
1271
1673
|
* Update many records in a single request and a single transaction.
|
|
@@ -1367,16 +1769,36 @@ export interface SDKCollectionClient<M extends Record<string, unknown> = Record<
|
|
|
1367
1769
|
* `observe()` degrades to a single fetch instead of throwing, which is the
|
|
1368
1770
|
* other reason to reach for it instead.
|
|
1369
1771
|
*/
|
|
1370
|
-
listen(params: FindParams<M> | undefined, onUpdate: (response: FindResult<M>) => void, onError?: (error: Error) => void): () => void;
|
|
1371
|
-
/**
|
|
1372
|
-
|
|
1772
|
+
listen(params: FindParams<M, Inc> | undefined, onUpdate: (response: FindResult<M>) => void, onError?: (error: Error) => void): () => void;
|
|
1773
|
+
/**
|
|
1774
|
+
* {@link listen} for a single row. Prefer `observeById()`. Every frame is
|
|
1775
|
+
* the row as `findById(id, options)` reads it, relations included.
|
|
1776
|
+
*/
|
|
1777
|
+
listenById(id: string | number, onUpdate: (row: M | undefined) => void, onError?: (error: Error) => void, options?: ByIdReadOptions<Inc>): () => void;
|
|
1778
|
+
/**
|
|
1779
|
+
* The number of rows matching `params`, kept current: `onCount` is called
|
|
1780
|
+
* with the total once it is known, and again whenever a write changes it.
|
|
1781
|
+
* The live counterpart of {@link count} — a list's total, or a "select all
|
|
1782
|
+
* N" offer, that does not go stale while other people add and remove rows.
|
|
1783
|
+
* Only the filter (`where`, `logical`, `searchString`) counts; the window
|
|
1784
|
+
* and sort are ignored.
|
|
1785
|
+
*
|
|
1786
|
+
* Always present; on a client that cannot subscribe it is a stub that
|
|
1787
|
+
* throws, as {@link listen} is.
|
|
1788
|
+
*/
|
|
1789
|
+
listenCount(params: FindParams<M, Inc> | undefined, onCount: (total: number) => void, onError?: (error: Error) => void): () => void;
|
|
1790
|
+
/**
|
|
1791
|
+
* The collection's trash: list, count, restore and purge the rows a soft
|
|
1792
|
+
* delete stamped. See {@link TrashClient}.
|
|
1793
|
+
*/
|
|
1794
|
+
trash: TrashClient<M, Inc>;
|
|
1373
1795
|
/**
|
|
1374
1796
|
* Count the number of records matching the given filter.
|
|
1375
1797
|
*
|
|
1376
1798
|
* Always present; see {@link listen} for what a transport that cannot serve
|
|
1377
1799
|
* it does instead.
|
|
1378
1800
|
*/
|
|
1379
|
-
count(params?: FindParams<M>): Promise<number>;
|
|
1801
|
+
count(params?: FindParams<M, Inc>): Promise<number>;
|
|
1380
1802
|
/**
|
|
1381
1803
|
* `count`/`sum`/`avg`/`min`/`max` over the matching rows, optionally
|
|
1382
1804
|
* grouped — the SDK half of `GET /<collection>/aggregate`.
|
|
@@ -1401,33 +1823,33 @@ export interface SDKCollectionClient<M extends Record<string, unknown> = Record<
|
|
|
1401
1823
|
* naming the capability rather than an empty result set, which would read
|
|
1402
1824
|
* as "nothing matched".
|
|
1403
1825
|
*/
|
|
1404
|
-
aggregate(params: AggregateParams<M>): Promise<
|
|
1405
|
-
where<K extends keyof M & string, Op extends WhereFilterOp>(column: K, operator: Op, value: WhereValueFor<Op, M[K]>): SDKQueryBuilderInterface<M>;
|
|
1826
|
+
aggregate(params: AggregateParams<M>): Promise<AggregateResult>;
|
|
1827
|
+
where<K extends keyof M & string, Op extends WhereFilterOp>(column: K, operator: Op, value: WhereValueFor<Op, M[K]>): SDKQueryBuilderInterface<M, Inc>;
|
|
1406
1828
|
/** A relation path (`author.name`) or a JSON path (`metadata->>tier`). */
|
|
1407
|
-
where(column: NonColumnFieldPath, operator: WhereFilterOp, value: unknown): SDKQueryBuilderInterface<M>;
|
|
1408
|
-
where(logicalCondition:
|
|
1409
|
-
orderBy(column: FieldPath<M> | ComputedSortField | RelationAggregateSort, direction?: "asc" | "desc", nulls?: NullsPlacement): SDKQueryBuilderInterface<M>;
|
|
1410
|
-
limit(count: number): SDKQueryBuilderInterface<M>;
|
|
1411
|
-
offset(count: number): SDKQueryBuilderInterface<M>;
|
|
1829
|
+
where(column: NonColumnFieldPath, operator: WhereFilterOp, value: unknown): SDKQueryBuilderInterface<M, Inc>;
|
|
1830
|
+
where(logicalCondition: LogicalConditionFor<M>): SDKQueryBuilderInterface<M, Inc>;
|
|
1831
|
+
orderBy(column: FieldPath<M> | ComputedSortField | RelationAggregateSort, direction?: "asc" | "desc", nulls?: NullsPlacement): SDKQueryBuilderInterface<M, Inc>;
|
|
1832
|
+
limit(count: number): SDKQueryBuilderInterface<M, Inc>;
|
|
1833
|
+
offset(count: number): SDKQueryBuilderInterface<M, Inc>;
|
|
1412
1834
|
search(searchString: string, options?: {
|
|
1413
1835
|
explain?: boolean;
|
|
1414
|
-
}): SDKQueryBuilderInterface<M>;
|
|
1836
|
+
}): SDKQueryBuilderInterface<M, Inc>;
|
|
1415
1837
|
/**
|
|
1416
1838
|
* Order rows by nearest-neighbour distance to `vector`, closest first.
|
|
1417
1839
|
* Postgres only, over a `type: "vector"` property. See
|
|
1418
1840
|
* {@link SDKQueryBuilderInterface.vectorSearch}.
|
|
1419
1841
|
*/
|
|
1420
|
-
vectorSearch(property:
|
|
1842
|
+
vectorSearch(property: Extract<keyof M, string>, vector: number[], options?: {
|
|
1421
1843
|
distance?: "cosine" | "l2" | "inner_product";
|
|
1422
1844
|
threshold?: number;
|
|
1423
|
-
}): SDKQueryBuilderInterface<M>;
|
|
1424
|
-
include(...relations:
|
|
1845
|
+
}): SDKQueryBuilderInterface<M, Inc>;
|
|
1846
|
+
include(...relations: IncludeArgOf<Inc>[]): SDKQueryBuilderInterface<M, Inc>;
|
|
1425
1847
|
/** {@link SDKQueryBuilderInterface.fields} */
|
|
1426
|
-
fields(...columns:
|
|
1848
|
+
fields(...columns: Extract<keyof M, string>[]): SDKQueryBuilderInterface<M, Inc>;
|
|
1427
1849
|
/** {@link SDKQueryBuilderInterface.distinct} */
|
|
1428
|
-
distinct(enabled?: boolean): SDKQueryBuilderInterface<M>;
|
|
1850
|
+
distinct(enabled?: boolean): SDKQueryBuilderInterface<M, Inc>;
|
|
1429
1851
|
/** {@link SDKQueryBuilderInterface.after} */
|
|
1430
|
-
after(cursor: string): SDKQueryBuilderInterface<M>;
|
|
1852
|
+
after(cursor: string): SDKQueryBuilderInterface<M, Inc>;
|
|
1431
1853
|
}
|
|
1432
1854
|
/**
|
|
1433
1855
|
* The unified data access object for the **admin panel** (Entity-shaped).
|
|
@@ -1524,6 +1946,31 @@ export type InsertOf<T> = T extends {
|
|
|
1524
1946
|
export type UpdateOf<T> = T extends {
|
|
1525
1947
|
Update: infer U extends Record<string, unknown>;
|
|
1526
1948
|
} ? U : Partial<RowOf<T>>;
|
|
1949
|
+
/**
|
|
1950
|
+
* The slugs a generated `Database` declares, from the `Slug` each entry
|
|
1951
|
+
* carries beside the accessor codegen chose for it.
|
|
1952
|
+
* @group Data
|
|
1953
|
+
*/
|
|
1954
|
+
export type SlugOf<DB> = {
|
|
1955
|
+
[K in keyof DB]: DB[K] extends {
|
|
1956
|
+
Slug: infer S extends string;
|
|
1957
|
+
} ? S : never;
|
|
1958
|
+
}[keyof DB];
|
|
1959
|
+
/** The generated `Database` entry whose `Slug` is `S`. */
|
|
1960
|
+
type EntryOfSlug<DB, S extends string> = DB[{
|
|
1961
|
+
[K in keyof DB]: DB[K] extends {
|
|
1962
|
+
Slug: S;
|
|
1963
|
+
} ? K : never;
|
|
1964
|
+
}[keyof DB]];
|
|
1965
|
+
/**
|
|
1966
|
+
* `collection(slug)` for a slug the registered `Database` declares: the same
|
|
1967
|
+
* typed client as the slug's accessor (`collection("my-notes")` is
|
|
1968
|
+
* `myNotes`). A slug it does not declare, or one computed at runtime, is
|
|
1969
|
+
* served by the untyped overload.
|
|
1970
|
+
*/
|
|
1971
|
+
type TypedSlugCollection<DB> = {
|
|
1972
|
+
collection<S extends SlugOf<DB>>(slug: S): SDKCollectionClient<RowOf<EntryOfSlug<DB, S>>, InsertOf<EntryOfSlug<DB, S>>, UpdateOf<EntryOfSlug<DB, S>>, IncludeOf<EntryOfSlug<DB, S>, DB>>;
|
|
1973
|
+
};
|
|
1527
1974
|
/**
|
|
1528
1975
|
* Note on the untyped branch below: its index signature is
|
|
1529
1976
|
* `SDKCollectionClient`, NOT `SDKCollectionClient | ((slug: string) => …)`.
|
|
@@ -1544,7 +1991,7 @@ export type UpdateOf<T> = T extends {
|
|
|
1544
1991
|
* compile for any of them. Do not restore the arm; use `collection(slug)` if a
|
|
1545
1992
|
* caller genuinely needs the by-slug function.
|
|
1546
1993
|
*/
|
|
1547
|
-
export type RebaseSdkData<DB = unknown> = {
|
|
1994
|
+
export type RebaseSdkData<DB = unknown> = (unknown extends DB ? unknown : TypedSlugCollection<DB>) & {
|
|
1548
1995
|
/**
|
|
1549
1996
|
* Get a flat collection accessor by slug.
|
|
1550
1997
|
*
|
|
@@ -1553,9 +2000,7 @@ export type RebaseSdkData<DB = unknown> = {
|
|
|
1553
2000
|
* await accessor.find({ limit: 10 });
|
|
1554
2001
|
*/
|
|
1555
2002
|
collection<M extends Record<string, unknown> = Record<string, unknown>>(slug: string): SDKCollectionClient<M>;
|
|
1556
|
-
} & (
|
|
1557
|
-
[K in keyof DB]: SDKCollectionClient<RowOf<DB[K]>, InsertOf<DB[K]>, UpdateOf<DB[K]>>;
|
|
1558
|
-
} : {
|
|
2003
|
+
} & (unknown extends DB ? {
|
|
1559
2004
|
/**
|
|
1560
2005
|
* Dynamic flat collection accessor.
|
|
1561
2006
|
* Access any collection by its slug as a property.
|
|
@@ -1564,4 +2009,7 @@ export type RebaseSdkData<DB = unknown> = {
|
|
|
1564
2009
|
* data.products.find({ where: { status: ["==", "published"] } })
|
|
1565
2010
|
*/
|
|
1566
2011
|
[collectionSlug: string]: SDKCollectionClient;
|
|
2012
|
+
} : {
|
|
2013
|
+
[K in keyof DB]: SDKCollectionClient<RowOf<DB[K]>, InsertOf<DB[K]>, UpdateOf<DB[K]>, IncludeOf<DB[K], DB>>;
|
|
1567
2014
|
});
|
|
2015
|
+
export {};
|