@rebasepro/types 0.24.0 → 0.24.1-canary.gcb918fc
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 +68 -10
- package/dist/controllers/data.d.ts +412 -76
- 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 +20 -79
- package/dist/index.es.js +140 -12
- package/dist/index.es.js.map +1 -1
- package/dist/types/auth_adapter.d.ts +32 -1
- package/dist/types/backend.d.ts +168 -4
- package/dist/types/backup.d.ts +19 -0
- package/dist/types/cron.d.ts +22 -7
- package/dist/types/database_adapter.d.ts +32 -6
- package/dist/types/entities.d.ts +11 -0
- package/dist/types/history.d.ts +15 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/project_manifest.d.ts +8 -0
- package/dist/types/properties.d.ts +28 -2
- package/dist/types/register.d.ts +43 -0
- package/dist/types/relations.d.ts +37 -1
- package/dist/types/resource_kinds.d.ts +7 -1
- package/dist/types/storage_authorize.d.ts +5 -0
- package/dist/types/websockets.d.ts +32 -1
- 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,20 @@ 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
|
+
}
|
|
146
253
|
/**
|
|
147
254
|
* An include checked against one generated collection's relations: `R` is its
|
|
148
255
|
* `Relations` map (relation name → the accessor it reaches) and `DB` the
|
|
@@ -212,10 +319,12 @@ export declare const MAX_INCLUDE_DEPTH = 3;
|
|
|
212
319
|
*
|
|
213
320
|
* ## Pagination precedence
|
|
214
321
|
*
|
|
215
|
-
* `limit`/`offset` and `page` describe the same window two ways
|
|
216
|
-
* `
|
|
217
|
-
*
|
|
218
|
-
*
|
|
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`).
|
|
219
328
|
*
|
|
220
329
|
* @group Data
|
|
221
330
|
*/
|
|
@@ -234,13 +343,14 @@ export interface FindParams<M extends Record<string, unknown> = Record<string, u
|
|
|
234
343
|
*/
|
|
235
344
|
limit?: number;
|
|
236
345
|
/**
|
|
237
|
-
* Number of items to skip.
|
|
238
|
-
*
|
|
346
|
+
* Number of items to skip. Not with {@link FindParams.page}: the pair is
|
|
347
|
+
* refused with `PAGE_WITH_OFFSET`.
|
|
239
348
|
*/
|
|
240
349
|
offset?: number;
|
|
241
350
|
/**
|
|
242
|
-
* Page number (1-indexed), alternative to {@link FindParams.offset}
|
|
243
|
-
*
|
|
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`.
|
|
244
354
|
*/
|
|
245
355
|
page?: number;
|
|
246
356
|
/**
|
|
@@ -256,13 +366,13 @@ export interface FindParams<M extends Record<string, unknown> = Record<string, u
|
|
|
256
366
|
* { role: ["in", ["admin", "editor"]] }
|
|
257
367
|
* { age: [[">=", 18], ["<", 65]] }
|
|
258
368
|
*/
|
|
259
|
-
where?:
|
|
369
|
+
where?: WhereFor<M>;
|
|
260
370
|
/**
|
|
261
371
|
* Logical grouping conditions (AND/OR). Use this for anything `where`
|
|
262
372
|
* can't express — notably OR-ing conditions. AND-ed with `where` and
|
|
263
373
|
* `searchString` when present (see the interface docs).
|
|
264
374
|
*/
|
|
265
|
-
logical?:
|
|
375
|
+
logical?: LogicalConditionFor<M>;
|
|
266
376
|
/**
|
|
267
377
|
* Sort order as a `[field, direction]` tuple, or a list of them applied in
|
|
268
378
|
* order of significance — the second key breaks ties on the first, and so on.
|
|
@@ -307,8 +417,10 @@ export interface FindParams<M extends Record<string, unknown> = Record<string, u
|
|
|
307
417
|
* projection (which it always is) every row is already distinct. Pair it
|
|
308
418
|
* with `fields` naming the columns you actually want the distinct values of.
|
|
309
419
|
*
|
|
310
|
-
*
|
|
311
|
-
*
|
|
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.
|
|
312
424
|
*/
|
|
313
425
|
distinct?: boolean;
|
|
314
426
|
/**
|
|
@@ -368,6 +480,23 @@ export interface FindParams<M extends Record<string, unknown> = Record<string, u
|
|
|
368
480
|
* carries a `searchString`; there is nothing to explain otherwise.
|
|
369
481
|
*/
|
|
370
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";
|
|
371
500
|
}
|
|
372
501
|
/**
|
|
373
502
|
* Paginated response from a collection query.
|
|
@@ -396,7 +525,7 @@ export interface FindResponse<M extends Record<string, unknown> = Record<string,
|
|
|
396
525
|
*/
|
|
397
526
|
export interface QueryBuilderInterface<M extends Record<string, unknown> = Record<string, unknown>> {
|
|
398
527
|
where<K extends keyof M & string, Op extends WhereFilterOp>(column: K, operator: Op, value: WhereValueFor<Op, M[K]>): this;
|
|
399
|
-
where(logicalCondition:
|
|
528
|
+
where(logicalCondition: LogicalConditionFor<M>): this;
|
|
400
529
|
orderBy(column: (keyof M & string) | ComputedSortField, direction?: "asc" | "desc"): this;
|
|
401
530
|
limit(count: number): this;
|
|
402
531
|
offset(count: number): this;
|
|
@@ -439,7 +568,7 @@ export interface CollectionAccessor<M extends Record<string, unknown> = Record<s
|
|
|
439
568
|
/**
|
|
440
569
|
* Find a single record by its ID.
|
|
441
570
|
*/
|
|
442
|
-
findById(id: string | number): Promise<Entity<M> | undefined>;
|
|
571
|
+
findById(id: string | number, options?: ByIdReadOptions): Promise<Entity<M> | undefined>;
|
|
443
572
|
/**
|
|
444
573
|
* Create a new record.
|
|
445
574
|
* @param data The entity data to create.
|
|
@@ -459,9 +588,16 @@ export interface CollectionAccessor<M extends Record<string, unknown> = Record<s
|
|
|
459
588
|
}): Promise<Entity<M>[]>;
|
|
460
589
|
/**
|
|
461
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.
|
|
462
596
|
* @returns The updated entity
|
|
463
597
|
*/
|
|
464
|
-
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>>;
|
|
465
601
|
/**
|
|
466
602
|
* Update many records in a single transaction.
|
|
467
603
|
*
|
|
@@ -487,10 +623,23 @@ export interface CollectionAccessor<M extends Record<string, unknown> = Record<s
|
|
|
487
623
|
*/
|
|
488
624
|
listen?(params: FindParams<M> | undefined, onUpdate: (response: FindResponse<M>) => void, onError?: (error: Error) => void): () => void;
|
|
489
625
|
/**
|
|
490
|
-
* 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.
|
|
491
628
|
* Optional method.
|
|
492
629
|
*/
|
|
493
|
-
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>;
|
|
494
643
|
/**
|
|
495
644
|
* Count the number of records matching the given filter.
|
|
496
645
|
*
|
|
@@ -509,7 +658,7 @@ export interface CollectionAccessor<M extends Record<string, unknown> = Record<s
|
|
|
509
658
|
*/
|
|
510
659
|
aggregate?(params: AggregateParams<M>): Promise<AggregateResult>;
|
|
511
660
|
where<K extends keyof M & string, Op extends WhereFilterOp>(column: K, operator: Op, value: WhereValueFor<Op, M[K]>): QueryBuilderInterface<M>;
|
|
512
|
-
where(logicalCondition:
|
|
661
|
+
where(logicalCondition: LogicalConditionFor<M>): QueryBuilderInterface<M>;
|
|
513
662
|
orderBy(column: (keyof M & string) | ComputedSortField, direction?: "asc" | "desc"): QueryBuilderInterface<M>;
|
|
514
663
|
limit(count: number): QueryBuilderInterface<M>;
|
|
515
664
|
offset(count: number): QueryBuilderInterface<M>;
|
|
@@ -536,6 +685,11 @@ export interface CollectionAccessor<M extends Record<string, unknown> = Record<s
|
|
|
536
685
|
* @group Data
|
|
537
686
|
*/
|
|
538
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
|
+
*/
|
|
539
693
|
total: number;
|
|
540
694
|
limit: number;
|
|
541
695
|
offset: number;
|
|
@@ -631,9 +785,26 @@ export type AggregateSelect<M extends Record<string, unknown> = Record<string, u
|
|
|
631
785
|
fn: "count";
|
|
632
786
|
field?: Extract<keyof M, string>;
|
|
633
787
|
} | {
|
|
634
|
-
fn: "sum" | "avg"
|
|
788
|
+
fn: "sum" | "avg";
|
|
789
|
+
field: NumericKeyOf<M>;
|
|
790
|
+
} | {
|
|
791
|
+
fn: "min" | "max";
|
|
635
792
|
field: Extract<keyof M, string>;
|
|
636
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>;
|
|
637
808
|
/**
|
|
638
809
|
* One row of an aggregate result: the `groupBy` columns, plus one key per
|
|
639
810
|
* {@link AggregateSelect} under its derived alias.
|
|
@@ -667,16 +838,48 @@ export interface AggregateParams<M extends Record<string, unknown> = Record<stri
|
|
|
667
838
|
/** Columns to group by. Omit for a single row over everything that matches. */
|
|
668
839
|
groupBy?: Extract<keyof M, string>[];
|
|
669
840
|
/** Filter conditions, as {@link FindParams.where}. */
|
|
670
|
-
where?:
|
|
841
|
+
where?: WhereFor<M>;
|
|
671
842
|
/** An `and`/`or`/`not` group, AND-ed with `where`. */
|
|
672
|
-
logical?:
|
|
843
|
+
logical?: LogicalConditionFor<M>;
|
|
673
844
|
/** Text search, AND-ed with the filters. */
|
|
674
845
|
searchString?: string;
|
|
675
846
|
/** Most groups to return. Grouped aggregates only. */
|
|
676
847
|
limit?: number;
|
|
677
848
|
/** Groups to skip, to page past `limit`. Grouped aggregates only. */
|
|
678
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>>[];
|
|
679
868
|
}
|
|
869
|
+
/**
|
|
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>;
|
|
680
883
|
/**
|
|
681
884
|
* Where a grouped aggregate's page of groups sits: the `limit` it was cut at,
|
|
682
885
|
* the `offset` it started from, and whether more groups follow.
|
|
@@ -704,11 +907,12 @@ export interface AggregateResult extends Array<AggregateRow> {
|
|
|
704
907
|
readonly meta?: AggregateMeta;
|
|
705
908
|
}
|
|
706
909
|
/**
|
|
707
|
-
* Which column an iteration
|
|
910
|
+
* Which column an iteration sorts by when it is asked to seek, for keyset
|
|
911
|
+
* ("seek") pagination.
|
|
708
912
|
*
|
|
709
913
|
* Either the column name on its own — sorted ascending — or the column plus an
|
|
710
|
-
* explicit direction.
|
|
711
|
-
*
|
|
914
|
+
* explicit direction. It is used only when the query names no `orderBy`; see
|
|
915
|
+
* {@link PageWalkOptions.cursor}.
|
|
712
916
|
*
|
|
713
917
|
* @group Data
|
|
714
918
|
*/
|
|
@@ -730,23 +934,23 @@ export interface PageWalkOptions<M extends Record<string, unknown> = Record<stri
|
|
|
730
934
|
*/
|
|
731
935
|
pageSize?: number;
|
|
732
936
|
/**
|
|
733
|
-
*
|
|
937
|
+
* **Require** seeking: fail rather than fall back to offset paging.
|
|
734
938
|
*
|
|
735
|
-
*
|
|
736
|
-
*
|
|
737
|
-
*
|
|
738
|
-
*
|
|
739
|
-
*
|
|
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.
|
|
740
947
|
*
|
|
741
|
-
*
|
|
742
|
-
*
|
|
743
|
-
*
|
|
744
|
-
*
|
|
745
|
-
*
|
|
746
|
-
*
|
|
747
|
-
* Implemented with the parameters `find()` already takes (an `orderBy` plus
|
|
748
|
-
* a `>` / `<` filter on the cursor column), so it works on every transport
|
|
749
|
-
* 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.
|
|
750
954
|
*
|
|
751
955
|
* @example
|
|
752
956
|
* for await (const job of client.data.jobs.iterate({ cursor: "id" })) { … }
|
|
@@ -764,6 +968,9 @@ export interface PageWalkOptions<M extends Record<string, unknown> = Record<stri
|
|
|
764
968
|
* `find()` takes except the window itself (`limit`, `offset`, `page`), which
|
|
765
969
|
* the iterator owns, plus the walk options.
|
|
766
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
|
+
*
|
|
767
974
|
* @group Data
|
|
768
975
|
*/
|
|
769
976
|
export type IterateParams<M extends Record<string, unknown> = Record<string, unknown>, Inc = IncludeSpec> = Omit<FindParams<M, Inc>, "limit" | "offset" | "page"> & PageWalkOptions<M>;
|
|
@@ -806,7 +1013,7 @@ export interface SDKQueryBuilderInterface<M extends Record<string, unknown> = Re
|
|
|
806
1013
|
* errors on a typed client.
|
|
807
1014
|
*/
|
|
808
1015
|
where(column: NonColumnFieldPath, operator: WhereFilterOp, value: unknown): this;
|
|
809
|
-
where(logicalCondition:
|
|
1016
|
+
where(logicalCondition: LogicalConditionFor<M>): this;
|
|
810
1017
|
/**
|
|
811
1018
|
* Sort by a column, a relation or JSON path, `_score`, or an aggregate over
|
|
812
1019
|
* a to-many relation — the same key set {@link FindParams.orderBy} takes.
|
|
@@ -826,7 +1033,7 @@ export interface SDKQueryBuilderInterface<M extends Record<string, unknown> = Re
|
|
|
826
1033
|
*
|
|
827
1034
|
* The query embedding is the caller's to produce.
|
|
828
1035
|
*/
|
|
829
|
-
vectorSearch(property:
|
|
1036
|
+
vectorSearch(property: Extract<keyof M, string>, vector: number[], options?: {
|
|
830
1037
|
distance?: "cosine" | "l2" | "inner_product";
|
|
831
1038
|
threshold?: number;
|
|
832
1039
|
}): this;
|
|
@@ -839,7 +1046,7 @@ export interface SDKQueryBuilderInterface<M extends Record<string, unknown> = Re
|
|
|
839
1046
|
* Return only these columns. A real projection: the columns are what is
|
|
840
1047
|
* read from the database, not what survives a trim of the response.
|
|
841
1048
|
*/
|
|
842
|
-
fields(...columns:
|
|
1049
|
+
fields(...columns: Extract<keyof M, string>[]): this;
|
|
843
1050
|
/** `SELECT DISTINCT` over the projection — see {@link FindParams.distinct}. */
|
|
844
1051
|
distinct(enabled?: boolean): this;
|
|
845
1052
|
/** Continue after a previous page's `meta.nextCursor`. */
|
|
@@ -941,10 +1148,13 @@ export declare const BATCH_REF_KEY = "$ref";
|
|
|
941
1148
|
* one, which is the case worth catching.
|
|
942
1149
|
*
|
|
943
1150
|
* Any `$`-prefixed key counts, because `{ $increment: 1 }` written to a number
|
|
944
|
-
* column as a JSON document is the failure this exists to prevent.
|
|
945
|
-
*
|
|
946
|
-
* `map`
|
|
947
|
-
*
|
|
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.
|
|
948
1158
|
*
|
|
949
1159
|
* The one exception is `{ $ref: … }`, the batch's backward reference. It stands
|
|
950
1160
|
* where a *value* goes and is resolved to one before the row is written, so it
|
|
@@ -953,7 +1163,7 @@ export declare const BATCH_REF_KEY = "$ref";
|
|
|
953
1163
|
*
|
|
954
1164
|
* @group Data
|
|
955
1165
|
*/
|
|
956
|
-
export declare function isFieldOperation(value: unknown): boolean;
|
|
1166
|
+
export declare function isFieldOperation(value: unknown, propertyType?: string): boolean;
|
|
957
1167
|
/** True when any value in a write payload is (or is attempting to be) one. @group Data */
|
|
958
1168
|
export declare function hasFieldOperation(values: Record<string, unknown> | undefined): boolean;
|
|
959
1169
|
export type FieldOperation =
|
|
@@ -980,8 +1190,23 @@ export type FieldOperation =
|
|
|
980
1190
|
* @group Data
|
|
981
1191
|
*/
|
|
982
1192
|
export type UpdateValues<U> = {
|
|
983
|
-
[K in keyof U]?: U[K] |
|
|
1193
|
+
[K in keyof U]?: U[K] | FieldOperationFor<U[K]>;
|
|
984
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);
|
|
985
1210
|
/**
|
|
986
1211
|
* Where an upsert looks for the row it might be replacing.
|
|
987
1212
|
*
|
|
@@ -1060,7 +1285,7 @@ export type BatchOperation<DB = Record<string, unknown>> = {
|
|
|
1060
1285
|
collection: K;
|
|
1061
1286
|
id: string | number | BatchRef;
|
|
1062
1287
|
values: {
|
|
1063
|
-
[F in keyof UpdateOf<DB[K]>]?: UpdateOf<DB[K]>[F] |
|
|
1288
|
+
[F in keyof UpdateOf<DB[K]>]?: UpdateOf<DB[K]>[F] | FieldOperationFor<UpdateOf<DB[K]>[F]> | BatchRef;
|
|
1064
1289
|
};
|
|
1065
1290
|
ref?: string;
|
|
1066
1291
|
} | {
|
|
@@ -1155,6 +1380,66 @@ export interface WriteOptions {
|
|
|
1155
1380
|
*/
|
|
1156
1381
|
ifMatch?: string;
|
|
1157
1382
|
}
|
|
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
|
+
}
|
|
1158
1443
|
export interface SDKCollectionClient<M extends Record<string, unknown> = Record<string, unknown>, I = Partial<M>, U = Partial<M>,
|
|
1159
1444
|
/** The include this collection takes; {@link IncludeOf} for a generated `Database`. */
|
|
1160
1445
|
Inc = IncludeSpec> {
|
|
@@ -1201,14 +1486,15 @@ Inc = IncludeSpec> {
|
|
|
1201
1486
|
*
|
|
1202
1487
|
* ## Consistency
|
|
1203
1488
|
*
|
|
1204
|
-
*
|
|
1205
|
-
*
|
|
1206
|
-
*
|
|
1207
|
-
*
|
|
1208
|
-
*
|
|
1209
|
-
*
|
|
1210
|
-
*
|
|
1211
|
-
*
|
|
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.
|
|
1212
1498
|
*
|
|
1213
1499
|
* @example
|
|
1214
1500
|
* for await (const job of client.data.jobs.iterate({
|
|
@@ -1230,7 +1516,7 @@ Inc = IncludeSpec> {
|
|
|
1230
1516
|
* {@link FindAllParams.maxRows} when the data really is bigger, or switch to
|
|
1231
1517
|
* `iterate()` and stream it.
|
|
1232
1518
|
*
|
|
1233
|
-
* The
|
|
1519
|
+
* The consistency notes on {@link iterate} apply here too.
|
|
1234
1520
|
*
|
|
1235
1521
|
* @throws When more rows match than `maxRows` allows.
|
|
1236
1522
|
*
|
|
@@ -1242,9 +1528,10 @@ Inc = IncludeSpec> {
|
|
|
1242
1528
|
*/
|
|
1243
1529
|
findAll(params?: FindAllParams<M, Inc>): Promise<M[]>;
|
|
1244
1530
|
/**
|
|
1245
|
-
* 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.
|
|
1246
1533
|
*/
|
|
1247
|
-
findById(id: string | number): Promise<M | undefined>;
|
|
1534
|
+
findById(id: string | number, options?: ByIdReadOptions<Inc>): Promise<M | undefined>;
|
|
1248
1535
|
/**
|
|
1249
1536
|
* Read one record by its ID, or throw if it is not there.
|
|
1250
1537
|
*
|
|
@@ -1361,6 +1648,10 @@ Inc = IncludeSpec> {
|
|
|
1361
1648
|
* `unique` index. Anything else is a 400 rather than a Postgres error
|
|
1362
1649
|
* raised half-way through a transaction.
|
|
1363
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
|
+
*
|
|
1364
1655
|
* The `on_create` timestamp of a row that already existed is left alone: a
|
|
1365
1656
|
* conflict means the row's creation is a fact about the past, and a nightly
|
|
1366
1657
|
* re-import that reset `createdAt` on everything it touched would take
|
|
@@ -1368,9 +1659,9 @@ Inc = IncludeSpec> {
|
|
|
1368
1659
|
*
|
|
1369
1660
|
* @example
|
|
1370
1661
|
* ```ts
|
|
1371
|
-
* await client.data.
|
|
1372
|
-
* {
|
|
1373
|
-
* { onConflict: ["
|
|
1662
|
+
* await client.data.products.upsert(
|
|
1663
|
+
* { sku: "LAMP-01", name: "Desk lamp" },
|
|
1664
|
+
* { onConflict: ["sku"] }
|
|
1374
1665
|
* );
|
|
1375
1666
|
* ```
|
|
1376
1667
|
*/
|
|
@@ -1479,8 +1770,28 @@ Inc = IncludeSpec> {
|
|
|
1479
1770
|
* other reason to reach for it instead.
|
|
1480
1771
|
*/
|
|
1481
1772
|
listen(params: FindParams<M, Inc> | undefined, onUpdate: (response: FindResult<M>) => void, onError?: (error: Error) => void): () => void;
|
|
1482
|
-
/**
|
|
1483
|
-
|
|
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>;
|
|
1484
1795
|
/**
|
|
1485
1796
|
* Count the number of records matching the given filter.
|
|
1486
1797
|
*
|
|
@@ -1516,7 +1827,7 @@ Inc = IncludeSpec> {
|
|
|
1516
1827
|
where<K extends keyof M & string, Op extends WhereFilterOp>(column: K, operator: Op, value: WhereValueFor<Op, M[K]>): SDKQueryBuilderInterface<M, Inc>;
|
|
1517
1828
|
/** A relation path (`author.name`) or a JSON path (`metadata->>tier`). */
|
|
1518
1829
|
where(column: NonColumnFieldPath, operator: WhereFilterOp, value: unknown): SDKQueryBuilderInterface<M, Inc>;
|
|
1519
|
-
where(logicalCondition:
|
|
1830
|
+
where(logicalCondition: LogicalConditionFor<M>): SDKQueryBuilderInterface<M, Inc>;
|
|
1520
1831
|
orderBy(column: FieldPath<M> | ComputedSortField | RelationAggregateSort, direction?: "asc" | "desc", nulls?: NullsPlacement): SDKQueryBuilderInterface<M, Inc>;
|
|
1521
1832
|
limit(count: number): SDKQueryBuilderInterface<M, Inc>;
|
|
1522
1833
|
offset(count: number): SDKQueryBuilderInterface<M, Inc>;
|
|
@@ -1528,13 +1839,13 @@ Inc = IncludeSpec> {
|
|
|
1528
1839
|
* Postgres only, over a `type: "vector"` property. See
|
|
1529
1840
|
* {@link SDKQueryBuilderInterface.vectorSearch}.
|
|
1530
1841
|
*/
|
|
1531
|
-
vectorSearch(property:
|
|
1842
|
+
vectorSearch(property: Extract<keyof M, string>, vector: number[], options?: {
|
|
1532
1843
|
distance?: "cosine" | "l2" | "inner_product";
|
|
1533
1844
|
threshold?: number;
|
|
1534
1845
|
}): SDKQueryBuilderInterface<M, Inc>;
|
|
1535
1846
|
include(...relations: IncludeArgOf<Inc>[]): SDKQueryBuilderInterface<M, Inc>;
|
|
1536
1847
|
/** {@link SDKQueryBuilderInterface.fields} */
|
|
1537
|
-
fields(...columns:
|
|
1848
|
+
fields(...columns: Extract<keyof M, string>[]): SDKQueryBuilderInterface<M, Inc>;
|
|
1538
1849
|
/** {@link SDKQueryBuilderInterface.distinct} */
|
|
1539
1850
|
distinct(enabled?: boolean): SDKQueryBuilderInterface<M, Inc>;
|
|
1540
1851
|
/** {@link SDKQueryBuilderInterface.after} */
|
|
@@ -1635,6 +1946,31 @@ export type InsertOf<T> = T extends {
|
|
|
1635
1946
|
export type UpdateOf<T> = T extends {
|
|
1636
1947
|
Update: infer U extends Record<string, unknown>;
|
|
1637
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
|
+
};
|
|
1638
1974
|
/**
|
|
1639
1975
|
* Note on the untyped branch below: its index signature is
|
|
1640
1976
|
* `SDKCollectionClient`, NOT `SDKCollectionClient | ((slug: string) => …)`.
|
|
@@ -1655,7 +1991,7 @@ export type UpdateOf<T> = T extends {
|
|
|
1655
1991
|
* compile for any of them. Do not restore the arm; use `collection(slug)` if a
|
|
1656
1992
|
* caller genuinely needs the by-slug function.
|
|
1657
1993
|
*/
|
|
1658
|
-
export type RebaseSdkData<DB = unknown> = {
|
|
1994
|
+
export type RebaseSdkData<DB = unknown> = (unknown extends DB ? unknown : TypedSlugCollection<DB>) & {
|
|
1659
1995
|
/**
|
|
1660
1996
|
* Get a flat collection accessor by slug.
|
|
1661
1997
|
*
|
|
@@ -1664,9 +2000,7 @@ export type RebaseSdkData<DB = unknown> = {
|
|
|
1664
2000
|
* await accessor.find({ limit: 10 });
|
|
1665
2001
|
*/
|
|
1666
2002
|
collection<M extends Record<string, unknown> = Record<string, unknown>>(slug: string): SDKCollectionClient<M>;
|
|
1667
|
-
} & (
|
|
1668
|
-
[K in keyof DB]: SDKCollectionClient<RowOf<DB[K]>, InsertOf<DB[K]>, UpdateOf<DB[K]>, IncludeOf<DB[K], DB>>;
|
|
1669
|
-
} : {
|
|
2003
|
+
} & (unknown extends DB ? {
|
|
1670
2004
|
/**
|
|
1671
2005
|
* Dynamic flat collection accessor.
|
|
1672
2006
|
* Access any collection by its slug as a property.
|
|
@@ -1675,5 +2009,7 @@ export type RebaseSdkData<DB = unknown> = {
|
|
|
1675
2009
|
* data.products.find({ where: { status: ["==", "published"] } })
|
|
1676
2010
|
*/
|
|
1677
2011
|
[collectionSlug: string]: SDKCollectionClient;
|
|
2012
|
+
} : {
|
|
2013
|
+
[K in keyof DB]: SDKCollectionClient<RowOf<DB[K]>, InsertOf<DB[K]>, UpdateOf<DB[K]>, IncludeOf<DB[K], DB>>;
|
|
1678
2014
|
});
|
|
1679
2015
|
export {};
|