@rebasepro/types 0.14.0 → 0.14.1-canary.g932d14c
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/controllers/data.d.ts +6 -3
- package/dist/controllers/data_driver.d.ts +44 -2
- package/dist/index.es.js.map +1 -1
- package/dist/types/backend.d.ts +32 -5
- package/dist/types/database_adapter.d.ts +31 -2
- package/dist/types/filter-operators.d.ts +21 -4
- package/package.json +1 -1
- package/src/controllers/data.ts +6 -3
- package/src/controllers/data_driver.ts +44 -2
- package/src/types/backend.ts +32 -5
- package/src/types/database_adapter.ts +31 -2
- package/src/types/filter-operators.ts +22 -4
package/dist/types/backend.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CollectionConfig, FilterValues, WhereFilterOp } from "./collections";
|
|
2
|
+
import type { OrderByTuple } from "./filter-operators";
|
|
2
3
|
import type { LogicalCondition } from "../controllers/data";
|
|
3
4
|
import type { AuthAdapter } from "./auth_adapter";
|
|
4
5
|
import type { HistoryConfig } from "../controllers/client";
|
|
@@ -34,7 +35,8 @@ export interface QueryFilter {
|
|
|
34
35
|
*/
|
|
35
36
|
export interface FetchCollectionOptions<M extends Record<string, unknown> = Record<string, unknown>> {
|
|
36
37
|
filter?: FilterValues<Extract<keyof M, string>>;
|
|
37
|
-
orderBy
|
|
38
|
+
/** See `FetchCollectionProps.orderBy`: a field name plus `order`, or a list of tuples. */
|
|
39
|
+
orderBy?: string | OrderByTuple[];
|
|
38
40
|
order?: "desc" | "asc";
|
|
39
41
|
limit?: number;
|
|
40
42
|
offset?: number;
|
|
@@ -48,7 +50,8 @@ export interface FetchCollectionOptions<M extends Record<string, unknown> = Reco
|
|
|
48
50
|
*/
|
|
49
51
|
export interface SearchOptions<M extends Record<string, unknown> = Record<string, unknown>> {
|
|
50
52
|
filter?: FilterValues<Extract<keyof M, string>>;
|
|
51
|
-
orderBy
|
|
53
|
+
/** See `FetchCollectionProps.orderBy`: a field name plus `order`, or a list of tuples. */
|
|
54
|
+
orderBy?: string | OrderByTuple[];
|
|
52
55
|
order?: "desc" | "asc";
|
|
53
56
|
limit?: number;
|
|
54
57
|
databaseId?: string;
|
|
@@ -156,7 +159,25 @@ export interface CollectionSubscriptionConfig {
|
|
|
156
159
|
clientId: string;
|
|
157
160
|
path: string;
|
|
158
161
|
filter?: unknown;
|
|
159
|
-
|
|
162
|
+
/**
|
|
163
|
+
* An `or(...)`/`and(...)` group, applied alongside `filter`.
|
|
164
|
+
*
|
|
165
|
+
* Declared here because a subscription is a query, and every field a query
|
|
166
|
+
* has this one needs too. It was missing, so the type-checked boundary
|
|
167
|
+
* dropped it: the client sent the group, nothing rejected it, and the
|
|
168
|
+
* subscription re-fetched with the group gone — pushing every row the
|
|
169
|
+
* caller's policies allowed rather than the ones they asked for. The same
|
|
170
|
+
* defect `FetchCollectionProps.logical` documents, one layer up.
|
|
171
|
+
*/
|
|
172
|
+
logical?: LogicalCondition;
|
|
173
|
+
/**
|
|
174
|
+
* Where the subscription's page starts. Missing for the same reason, with
|
|
175
|
+
* a quieter symptom: a subscriber watching page two was pushed page one,
|
|
176
|
+
* and a `collection_update` frame carries no window for it to notice with.
|
|
177
|
+
*/
|
|
178
|
+
offset?: number;
|
|
179
|
+
/** See `FetchCollectionProps.orderBy`: a field name plus `order`, or a list of tuples. */
|
|
180
|
+
orderBy?: string | OrderByTuple[];
|
|
160
181
|
order?: "desc" | "asc";
|
|
161
182
|
limit?: number;
|
|
162
183
|
startAfter?: unknown;
|
|
@@ -617,8 +638,14 @@ export interface BackendBootstrapper {
|
|
|
617
638
|
* enum types, and never drop, narrow or rewrite anything. This runs
|
|
618
639
|
* unattended against live customer data with nobody reading a diff, so the
|
|
619
640
|
* destructive half stays a deliberate migration.
|
|
641
|
+
*
|
|
642
|
+
* `driverResult` is optional: this runs before `initializeDriver`, and only
|
|
643
|
+
* the bundle path has a pre-init stand-in to pass. An adapter built by an
|
|
644
|
+
* application already holds its own connection and MUST use it when this is
|
|
645
|
+
* `undefined` — dereferencing it unconditionally works for managed tenants
|
|
646
|
+
* and breaks every app that builds its own adapter.
|
|
620
647
|
*/
|
|
621
|
-
ensureCollectionSchema?(collections: unknown[], driverResult
|
|
648
|
+
ensureCollectionSchema?(collections: unknown[], driverResult?: InitializedDriver, log?: (message: string) => void): Promise<{
|
|
622
649
|
applied: number;
|
|
623
650
|
}>;
|
|
624
651
|
/**
|
|
@@ -637,7 +664,7 @@ export interface BackendBootstrapper {
|
|
|
637
664
|
* Runs after auth initialization, because the generated policies call the
|
|
638
665
|
* `auth.*` helper functions and `CREATE POLICY` validates they exist.
|
|
639
666
|
*/
|
|
640
|
-
ensureCollectionPolicies?(collections: unknown[], driverResult
|
|
667
|
+
ensureCollectionPolicies?(collections: unknown[], driverResult?: InitializedDriver, log?: (message: string) => void): Promise<{
|
|
641
668
|
applied: number;
|
|
642
669
|
}>;
|
|
643
670
|
/**
|
|
@@ -84,8 +84,16 @@ export interface DatabaseAdapter {
|
|
|
84
84
|
* into a `BackendBootstrapper`: the runtime calls it through the bootstrapper
|
|
85
85
|
* at boot, and a wrapper that silently omits it leaves a managed tenant
|
|
86
86
|
* 500ing every data route with no create step ever having run.
|
|
87
|
+
*
|
|
88
|
+
* `driverResult` is optional because this runs BEFORE `initializeDriver`, so
|
|
89
|
+
* there may be no result to pass. The bundle path can supply a pre-init
|
|
90
|
+
* stand-in because the coordinator opened the connection itself; an app that
|
|
91
|
+
* constructed this adapter never handed the framework a connection handle,
|
|
92
|
+
* so it passes `undefined` and the adapter MUST fall back to the connection
|
|
93
|
+
* it was constructed with. An adapter that dereferences `driverResult`
|
|
94
|
+
* unconditionally works for managed tenants and breaks every self-built one.
|
|
87
95
|
*/
|
|
88
|
-
ensureCollectionSchema?(collections: unknown[], driverResult
|
|
96
|
+
ensureCollectionSchema?(collections: unknown[], driverResult?: InitializedDriver, log?: (message: string) => void): Promise<{
|
|
89
97
|
applied: number;
|
|
90
98
|
}>;
|
|
91
99
|
/**
|
|
@@ -98,7 +106,7 @@ export interface DatabaseAdapter {
|
|
|
98
106
|
* policies, tables exist but every user-context read is denied (a public
|
|
99
107
|
* collection answers 401).
|
|
100
108
|
*/
|
|
101
|
-
ensureCollectionPolicies?(collections: unknown[], driverResult
|
|
109
|
+
ensureCollectionPolicies?(collections: unknown[], driverResult?: InitializedDriver, log?: (message: string) => void): Promise<{
|
|
102
110
|
applied: number;
|
|
103
111
|
}>;
|
|
104
112
|
/**
|
|
@@ -147,4 +155,25 @@ export interface DatabaseAdapterInitConfig {
|
|
|
147
155
|
baas?: {
|
|
148
156
|
unprotectedTables?: "exclude" | "serve";
|
|
149
157
|
};
|
|
158
|
+
/**
|
|
159
|
+
* What the runtime's boot-time table provisioning did, in this process,
|
|
160
|
+
* before this driver was initialized.
|
|
161
|
+
*
|
|
162
|
+
* A driver that checks for missing tables cannot otherwise tell "the create
|
|
163
|
+
* step ran and this table still is not here" from "no create step ran at
|
|
164
|
+
* all" — and those need opposite advice. The Postgres driver's drift warning
|
|
165
|
+
* assumed the first, told operators to redeploy with REBASE_MIGRATE_ON_BOOT
|
|
166
|
+
* unset, and pointed at driver version skew; for an app whose boot path had
|
|
167
|
+
* no provisioning step, all of that was unactionable and one investigation
|
|
168
|
+
* chased a driver that was perfectly current.
|
|
169
|
+
*
|
|
170
|
+
* Absent when the caller predates this field: treat that as "unknown" and
|
|
171
|
+
* fall back to generic guidance rather than asserting either case.
|
|
172
|
+
*/
|
|
173
|
+
schemaProvisioning?: {
|
|
174
|
+
/** Whether the table-creation hook actually ran this boot. */
|
|
175
|
+
attempted: boolean;
|
|
176
|
+
/** Why it did not, when it did not — safe to print verbatim. */
|
|
177
|
+
reason?: string;
|
|
178
|
+
};
|
|
150
179
|
}
|
|
@@ -44,12 +44,28 @@
|
|
|
44
44
|
* boundary, handled by `serializeOrderBy` / `deserializeOrderBy` in
|
|
45
45
|
* `@rebasepro/common`.
|
|
46
46
|
*
|
|
47
|
-
* Design note: the natural extension for multi-column sort is
|
|
48
|
-
* `OrderByTuple[]` — not implemented yet (server consumes only the first).
|
|
49
|
-
*
|
|
50
47
|
* @group Models
|
|
51
48
|
*/
|
|
52
49
|
export type OrderByTuple<Key extends string = string> = [Key, "asc" | "desc"];
|
|
50
|
+
/**
|
|
51
|
+
* One sort key, or several applied in order of significance.
|
|
52
|
+
*
|
|
53
|
+
* ```ts
|
|
54
|
+
* orderBy: ["created_at", "desc"] // one key
|
|
55
|
+
* orderBy: [["roles", "asc"], ["created_at", "desc"]] // roles, then newest first
|
|
56
|
+
* ```
|
|
57
|
+
*
|
|
58
|
+
* The two forms are told apart by whether the first element is itself an
|
|
59
|
+
* array, so a single tuple never needs wrapping and every existing caller
|
|
60
|
+
* keeps working unchanged. `normalizeOrderBy` in `@rebasepro/common` collapses
|
|
61
|
+
* both to the list form, which is what every layer below the call site speaks.
|
|
62
|
+
*
|
|
63
|
+
* Ties on the last key are broken by the row id, so a multi-key sort is a
|
|
64
|
+
* total order and pages over it neither repeat nor skip rows.
|
|
65
|
+
*
|
|
66
|
+
* @group Models
|
|
67
|
+
*/
|
|
68
|
+
export type OrderBySpec<Key extends string = string> = OrderByTuple<Key> | OrderByTuple<Key>[];
|
|
53
69
|
/**
|
|
54
70
|
* Canonical filter operators supported across all database backends.
|
|
55
71
|
* Each DB driver translates these to its native query format.
|
|
@@ -133,8 +149,9 @@ export interface FilterPreset<Key extends string = string> {
|
|
|
133
149
|
filterValues: FilterValues<Key>;
|
|
134
150
|
/**
|
|
135
151
|
* Optional sort override to apply alongside the filter values.
|
|
152
|
+
* One key, or several in order of significance.
|
|
136
153
|
*/
|
|
137
|
-
sort?:
|
|
154
|
+
sort?: OrderBySpec<Key>;
|
|
138
155
|
}
|
|
139
156
|
/**
|
|
140
157
|
* PostgREST short-code operators. Wire format only — these never appear
|
package/package.json
CHANGED
package/src/controllers/data.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { VectorSearchParams } from "./data_driver";
|
|
2
2
|
import type { ComputedSortField, SearchMatch } from "../types/search";
|
|
3
3
|
import { Entity, EntityValues } from "../types/entities";
|
|
4
|
-
import { WhereFilterOp, FieldPath, FilterValues,
|
|
4
|
+
import { WhereFilterOp, FieldPath, FilterValues, OrderBySpec } from "../types/filter-operators";
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Operator-blind filter value: whatever the column holds, a list of it, or null.
|
|
@@ -160,10 +160,13 @@ export interface FindParams<M extends Record<string, unknown> = Record<string, u
|
|
|
160
160
|
*/
|
|
161
161
|
logical?: LogicalCondition;
|
|
162
162
|
/**
|
|
163
|
-
* Sort order as a `[field, direction]` tuple
|
|
163
|
+
* Sort order as a `[field, direction]` tuple, or a list of them applied in
|
|
164
|
+
* order of significance — the second key breaks ties on the first, and so on.
|
|
165
|
+
*
|
|
164
166
|
* @example orderBy: ["created_at", "desc"]
|
|
167
|
+
* @example orderBy: [["roles", "asc"], ["created_at", "desc"]]
|
|
165
168
|
*/
|
|
166
|
-
orderBy?:
|
|
169
|
+
orderBy?: OrderBySpec<FieldPath<M> | ComputedSortField>;
|
|
167
170
|
/**
|
|
168
171
|
* Relations to include in the response.
|
|
169
172
|
*
|
|
@@ -2,6 +2,7 @@ import { RebaseApiError } from "../errors";
|
|
|
2
2
|
import type { CollectionRegistryController } from "./collection_registry";
|
|
3
3
|
import type { EntityStatus, EntityValues } from "../types/entities";
|
|
4
4
|
import type { CollectionConfig, FilterValues } from "../types/collections";
|
|
5
|
+
import type { OrderByTuple } from "../types/filter-operators";
|
|
5
6
|
import type { RebaseCallContext } from "../call_context";
|
|
6
7
|
import type { LogicalCondition } from "./data";
|
|
7
8
|
|
|
@@ -167,10 +168,25 @@ export interface FetchCollectionProps<M extends Record<string, unknown> = Record
|
|
|
167
168
|
limit?: number;
|
|
168
169
|
offset?: number;
|
|
169
170
|
startAfter?: unknown;
|
|
170
|
-
|
|
171
|
+
/**
|
|
172
|
+
* The sort, in either of two spellings:
|
|
173
|
+
*
|
|
174
|
+
* - a field name, whose direction is the separate `order` below — the
|
|
175
|
+
* original single-column contract, which every existing driver reads;
|
|
176
|
+
* - a list of `[field, direction]` tuples applied in order of significance,
|
|
177
|
+
* which carries a multi-column sort and ignores `order` entirely.
|
|
178
|
+
*
|
|
179
|
+
* `normalizeDriverOrderBy` in `@rebasepro/common` collapses the pair to the
|
|
180
|
+
* list form. A driver that has not been taught the list form should read it
|
|
181
|
+
* through that helper rather than assume a string: handed an array, `String()`
|
|
182
|
+
* would produce a field name like `roles,asc` and the sort would 400 (or,
|
|
183
|
+
* with unknown-field warnings on, silently vanish).
|
|
184
|
+
*/
|
|
185
|
+
orderBy?: string | OrderByTuple[];
|
|
171
186
|
searchString?: string;
|
|
172
187
|
/** Ask each row which declared search field matched — populates `_matches`. */
|
|
173
188
|
searchExplain?: boolean;
|
|
189
|
+
/** Direction for the string form of `orderBy`. Ignored when `orderBy` is a list. */
|
|
174
190
|
order?: "desc" | "asc";
|
|
175
191
|
/** Vector similarity search configuration */
|
|
176
192
|
vectorSearch?: VectorSearchParams;
|
|
@@ -508,7 +524,8 @@ export interface RestFetchService {
|
|
|
508
524
|
filter?: FilterValues<string>;
|
|
509
525
|
/** An `or(...)`/`and(...)` group, applied alongside `filter`. */
|
|
510
526
|
logical?: LogicalCondition;
|
|
511
|
-
orderBy
|
|
527
|
+
/** See `FetchCollectionProps.orderBy`: a field name plus `order`, or a list of tuples. */
|
|
528
|
+
orderBy?: string | OrderByTuple[];
|
|
512
529
|
order?: "desc" | "asc";
|
|
513
530
|
limit?: number;
|
|
514
531
|
offset?: number;
|
|
@@ -522,6 +539,31 @@ export interface RestFetchService {
|
|
|
522
539
|
include?: string[]
|
|
523
540
|
): Promise<Record<string, unknown>[]>;
|
|
524
541
|
|
|
542
|
+
/**
|
|
543
|
+
* `count`/`sum`/`avg`/`min`/`max` over the rows a filter selects,
|
|
544
|
+
* optionally grouped.
|
|
545
|
+
*
|
|
546
|
+
* Optional, and the REST route answers 501 where a driver does not
|
|
547
|
+
* implement it — an aggregate is not a thing to approximate, and an empty
|
|
548
|
+
* result set would read as "nothing matched".
|
|
549
|
+
*
|
|
550
|
+
* Any implementation **must apply the same row-level authorization as a
|
|
551
|
+
* read**. An aggregate is an efficient way to learn about rows you cannot
|
|
552
|
+
* select, and `count(*)` over a table whose policies would return nothing
|
|
553
|
+
* has to be zero.
|
|
554
|
+
*/
|
|
555
|
+
aggregate?(
|
|
556
|
+
collectionPath: string,
|
|
557
|
+
options: {
|
|
558
|
+
aggregates: { fn: "count" | "sum" | "avg" | "min" | "max"; field?: string; alias: string }[];
|
|
559
|
+
groupBy?: string[];
|
|
560
|
+
filter?: FilterValues<string>;
|
|
561
|
+
logical?: LogicalCondition;
|
|
562
|
+
searchString?: string;
|
|
563
|
+
limit?: number;
|
|
564
|
+
}
|
|
565
|
+
): Promise<Record<string, unknown>[]>;
|
|
566
|
+
|
|
525
567
|
/**
|
|
526
568
|
* Fetch a single flattened entity with optional relation includes.
|
|
527
569
|
*/
|
package/src/types/backend.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CollectionConfig, FilterValues, WhereFilterOp } from "./collections";
|
|
2
|
+
import type { OrderByTuple } from "./filter-operators";
|
|
2
3
|
import type { LogicalCondition } from "../controllers/data";
|
|
3
4
|
import type { AuthAdapter } from "./auth_adapter";
|
|
4
5
|
import type { HistoryConfig } from "../controllers/client";
|
|
@@ -47,7 +48,8 @@ export interface QueryFilter {
|
|
|
47
48
|
*/
|
|
48
49
|
export interface FetchCollectionOptions<M extends Record<string, unknown> = Record<string, unknown>> {
|
|
49
50
|
filter?: FilterValues<Extract<keyof M, string>>;
|
|
50
|
-
orderBy
|
|
51
|
+
/** See `FetchCollectionProps.orderBy`: a field name plus `order`, or a list of tuples. */
|
|
52
|
+
orderBy?: string | OrderByTuple[];
|
|
51
53
|
order?: "desc" | "asc";
|
|
52
54
|
limit?: number;
|
|
53
55
|
offset?: number;
|
|
@@ -62,7 +64,8 @@ export interface FetchCollectionOptions<M extends Record<string, unknown> = Reco
|
|
|
62
64
|
*/
|
|
63
65
|
export interface SearchOptions<M extends Record<string, unknown> = Record<string, unknown>> {
|
|
64
66
|
filter?: FilterValues<Extract<keyof M, string>>;
|
|
65
|
-
orderBy
|
|
67
|
+
/** See `FetchCollectionProps.orderBy`: a field name plus `order`, or a list of tuples. */
|
|
68
|
+
orderBy?: string | OrderByTuple[];
|
|
66
69
|
order?: "desc" | "asc";
|
|
67
70
|
limit?: number;
|
|
68
71
|
databaseId?: string;
|
|
@@ -237,7 +240,25 @@ export interface CollectionSubscriptionConfig {
|
|
|
237
240
|
clientId: string;
|
|
238
241
|
path: string;
|
|
239
242
|
filter?: unknown;
|
|
240
|
-
|
|
243
|
+
/**
|
|
244
|
+
* An `or(...)`/`and(...)` group, applied alongside `filter`.
|
|
245
|
+
*
|
|
246
|
+
* Declared here because a subscription is a query, and every field a query
|
|
247
|
+
* has this one needs too. It was missing, so the type-checked boundary
|
|
248
|
+
* dropped it: the client sent the group, nothing rejected it, and the
|
|
249
|
+
* subscription re-fetched with the group gone — pushing every row the
|
|
250
|
+
* caller's policies allowed rather than the ones they asked for. The same
|
|
251
|
+
* defect `FetchCollectionProps.logical` documents, one layer up.
|
|
252
|
+
*/
|
|
253
|
+
logical?: LogicalCondition;
|
|
254
|
+
/**
|
|
255
|
+
* Where the subscription's page starts. Missing for the same reason, with
|
|
256
|
+
* a quieter symptom: a subscriber watching page two was pushed page one,
|
|
257
|
+
* and a `collection_update` frame carries no window for it to notice with.
|
|
258
|
+
*/
|
|
259
|
+
offset?: number;
|
|
260
|
+
/** See `FetchCollectionProps.orderBy`: a field name plus `order`, or a list of tuples. */
|
|
261
|
+
orderBy?: string | OrderByTuple[];
|
|
241
262
|
order?: "desc" | "asc";
|
|
242
263
|
limit?: number;
|
|
243
264
|
startAfter?: unknown;
|
|
@@ -801,10 +822,16 @@ export interface BackendBootstrapper {
|
|
|
801
822
|
* enum types, and never drop, narrow or rewrite anything. This runs
|
|
802
823
|
* unattended against live customer data with nobody reading a diff, so the
|
|
803
824
|
* destructive half stays a deliberate migration.
|
|
825
|
+
*
|
|
826
|
+
* `driverResult` is optional: this runs before `initializeDriver`, and only
|
|
827
|
+
* the bundle path has a pre-init stand-in to pass. An adapter built by an
|
|
828
|
+
* application already holds its own connection and MUST use it when this is
|
|
829
|
+
* `undefined` — dereferencing it unconditionally works for managed tenants
|
|
830
|
+
* and breaks every app that builds its own adapter.
|
|
804
831
|
*/
|
|
805
832
|
ensureCollectionSchema?(
|
|
806
833
|
collections: unknown[],
|
|
807
|
-
driverResult
|
|
834
|
+
driverResult?: InitializedDriver,
|
|
808
835
|
log?: (message: string) => void
|
|
809
836
|
): Promise<{ applied: number }>;
|
|
810
837
|
|
|
@@ -826,7 +853,7 @@ export interface BackendBootstrapper {
|
|
|
826
853
|
*/
|
|
827
854
|
ensureCollectionPolicies?(
|
|
828
855
|
collections: unknown[],
|
|
829
|
-
driverResult
|
|
856
|
+
driverResult?: InitializedDriver,
|
|
830
857
|
log?: (message: string) => void
|
|
831
858
|
): Promise<{ applied: number }>;
|
|
832
859
|
|
|
@@ -108,10 +108,18 @@ export interface DatabaseAdapter {
|
|
|
108
108
|
* into a `BackendBootstrapper`: the runtime calls it through the bootstrapper
|
|
109
109
|
* at boot, and a wrapper that silently omits it leaves a managed tenant
|
|
110
110
|
* 500ing every data route with no create step ever having run.
|
|
111
|
+
*
|
|
112
|
+
* `driverResult` is optional because this runs BEFORE `initializeDriver`, so
|
|
113
|
+
* there may be no result to pass. The bundle path can supply a pre-init
|
|
114
|
+
* stand-in because the coordinator opened the connection itself; an app that
|
|
115
|
+
* constructed this adapter never handed the framework a connection handle,
|
|
116
|
+
* so it passes `undefined` and the adapter MUST fall back to the connection
|
|
117
|
+
* it was constructed with. An adapter that dereferences `driverResult`
|
|
118
|
+
* unconditionally works for managed tenants and breaks every self-built one.
|
|
111
119
|
*/
|
|
112
120
|
ensureCollectionSchema?(
|
|
113
121
|
collections: unknown[],
|
|
114
|
-
driverResult
|
|
122
|
+
driverResult?: InitializedDriver,
|
|
115
123
|
log?: (message: string) => void,
|
|
116
124
|
): Promise<{ applied: number }>;
|
|
117
125
|
|
|
@@ -127,7 +135,7 @@ export interface DatabaseAdapter {
|
|
|
127
135
|
*/
|
|
128
136
|
ensureCollectionPolicies?(
|
|
129
137
|
collections: unknown[],
|
|
130
|
-
driverResult
|
|
138
|
+
driverResult?: InitializedDriver,
|
|
131
139
|
log?: (message: string) => void,
|
|
132
140
|
): Promise<{ applied: number }>;
|
|
133
141
|
|
|
@@ -178,4 +186,25 @@ export interface DatabaseAdapterInitConfig {
|
|
|
178
186
|
* Drivers that introspect should honour `unprotectedTables`.
|
|
179
187
|
*/
|
|
180
188
|
baas?: { unprotectedTables?: "exclude" | "serve" };
|
|
189
|
+
/**
|
|
190
|
+
* What the runtime's boot-time table provisioning did, in this process,
|
|
191
|
+
* before this driver was initialized.
|
|
192
|
+
*
|
|
193
|
+
* A driver that checks for missing tables cannot otherwise tell "the create
|
|
194
|
+
* step ran and this table still is not here" from "no create step ran at
|
|
195
|
+
* all" — and those need opposite advice. The Postgres driver's drift warning
|
|
196
|
+
* assumed the first, told operators to redeploy with REBASE_MIGRATE_ON_BOOT
|
|
197
|
+
* unset, and pointed at driver version skew; for an app whose boot path had
|
|
198
|
+
* no provisioning step, all of that was unactionable and one investigation
|
|
199
|
+
* chased a driver that was perfectly current.
|
|
200
|
+
*
|
|
201
|
+
* Absent when the caller predates this field: treat that as "unknown" and
|
|
202
|
+
* fall back to generic guidance rather than asserting either case.
|
|
203
|
+
*/
|
|
204
|
+
schemaProvisioning?: {
|
|
205
|
+
/** Whether the table-creation hook actually ran this boot. */
|
|
206
|
+
attempted: boolean;
|
|
207
|
+
/** Why it did not, when it did not — safe to print verbatim. */
|
|
208
|
+
reason?: string;
|
|
209
|
+
};
|
|
181
210
|
}
|
|
@@ -45,13 +45,30 @@
|
|
|
45
45
|
* boundary, handled by `serializeOrderBy` / `deserializeOrderBy` in
|
|
46
46
|
* `@rebasepro/common`.
|
|
47
47
|
*
|
|
48
|
-
* Design note: the natural extension for multi-column sort is
|
|
49
|
-
* `OrderByTuple[]` — not implemented yet (server consumes only the first).
|
|
50
|
-
*
|
|
51
48
|
* @group Models
|
|
52
49
|
*/
|
|
53
50
|
export type OrderByTuple<Key extends string = string> = [Key, "asc" | "desc"];
|
|
54
51
|
|
|
52
|
+
/**
|
|
53
|
+
* One sort key, or several applied in order of significance.
|
|
54
|
+
*
|
|
55
|
+
* ```ts
|
|
56
|
+
* orderBy: ["created_at", "desc"] // one key
|
|
57
|
+
* orderBy: [["roles", "asc"], ["created_at", "desc"]] // roles, then newest first
|
|
58
|
+
* ```
|
|
59
|
+
*
|
|
60
|
+
* The two forms are told apart by whether the first element is itself an
|
|
61
|
+
* array, so a single tuple never needs wrapping and every existing caller
|
|
62
|
+
* keeps working unchanged. `normalizeOrderBy` in `@rebasepro/common` collapses
|
|
63
|
+
* both to the list form, which is what every layer below the call site speaks.
|
|
64
|
+
*
|
|
65
|
+
* Ties on the last key are broken by the row id, so a multi-key sort is a
|
|
66
|
+
* total order and pages over it neither repeat nor skip rows.
|
|
67
|
+
*
|
|
68
|
+
* @group Models
|
|
69
|
+
*/
|
|
70
|
+
export type OrderBySpec<Key extends string = string> = OrderByTuple<Key> | OrderByTuple<Key>[];
|
|
71
|
+
|
|
55
72
|
/**
|
|
56
73
|
* Canonical filter operators supported across all database backends.
|
|
57
74
|
* Each DB driver translates these to its native query format.
|
|
@@ -161,8 +178,9 @@ export interface FilterPreset<Key extends string = string> {
|
|
|
161
178
|
|
|
162
179
|
/**
|
|
163
180
|
* Optional sort override to apply alongside the filter values.
|
|
181
|
+
* One key, or several in order of significance.
|
|
164
182
|
*/
|
|
165
|
-
sort?:
|
|
183
|
+
sort?: OrderBySpec<Key>;
|
|
166
184
|
}
|
|
167
185
|
|
|
168
186
|
/**
|