@rebasepro/types 0.17.3 → 0.18.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/dist/call_context.d.ts +20 -0
- package/dist/controllers/client.d.ts +36 -4
- package/dist/controllers/data.d.ts +120 -10
- package/dist/errors.d.ts +83 -4
- package/dist/index.es.js +522 -160
- package/dist/index.es.js.map +1 -1
- package/dist/types/admin_block.d.ts +2 -2
- package/dist/types/auth_adapter.d.ts +41 -6
- package/dist/types/backend.d.ts +48 -0
- package/dist/types/collections.d.ts +25 -1
- package/dist/types/cron.d.ts +34 -0
- package/dist/types/database_adapter.d.ts +39 -0
- package/dist/types/entity_callbacks.d.ts +14 -1
- package/dist/types/filter-operators.d.ts +24 -1
- package/dist/types/policy.d.ts +29 -1
- package/dist/types/properties.d.ts +216 -3
- package/dist/types/relations.d.ts +65 -7
- package/dist/types/resource_kinds.d.ts +173 -17
- package/dist/types/resources.d.ts +108 -7
- package/dist/types/rls-functions.d.ts +11 -0
- package/dist/types/storage_source.d.ts +12 -23
- package/package.json +24 -23
- package/src/call_context.ts +0 -120
- package/src/controllers/auth_state.ts +0 -24
- package/src/controllers/client.ts +0 -494
- package/src/controllers/collection_registry.ts +0 -62
- package/src/controllers/data.ts +0 -1012
- package/src/controllers/data_driver.ts +0 -576
- package/src/controllers/effective_role.ts +0 -4
- package/src/controllers/email.ts +0 -91
- package/src/controllers/index.ts +0 -11
- package/src/controllers/storage.ts +0 -252
- package/src/errors.ts +0 -119
- package/src/index.ts +0 -5
- package/src/types/admin_block.ts +0 -209
- package/src/types/api_keys.ts +0 -108
- package/src/types/auth_adapter.ts +0 -580
- package/src/types/backend.ts +0 -987
- package/src/types/backup.ts +0 -26
- package/src/types/channel_bus.ts +0 -202
- package/src/types/chips.ts +0 -34
- package/src/types/collection_contract.ts +0 -278
- package/src/types/collections.ts +0 -763
- package/src/types/component_ref.ts +0 -92
- package/src/types/cron.ts +0 -213
- package/src/types/data_source.ts +0 -357
- package/src/types/database_adapter.ts +0 -267
- package/src/types/entities.ts +0 -226
- package/src/types/entity_callbacks.ts +0 -229
- package/src/types/filter-operators.ts +0 -444
- package/src/types/history.ts +0 -66
- package/src/types/index.ts +0 -36
- package/src/types/indexes.ts +0 -180
- package/src/types/policy.ts +0 -328
- package/src/types/postgres_introspection.ts +0 -101
- package/src/types/project_manifest.ts +0 -598
- package/src/types/properties.ts +0 -1368
- package/src/types/relations.ts +0 -417
- package/src/types/resource_kinds.ts +0 -390
- package/src/types/resources.ts +0 -368
- package/src/types/rls-functions.ts +0 -98
- package/src/types/schema_editing.ts +0 -157
- package/src/types/schema_version.ts +0 -112
- package/src/types/search.ts +0 -247
- package/src/types/security_rules.ts +0 -344
- package/src/types/storage_authorize.ts +0 -77
- package/src/types/storage_source.ts +0 -248
- package/src/types/websockets.ts +0 -117
- package/src/users/index.ts +0 -2
- package/src/users/user.ts +0 -69
package/src/types/relations.ts
DELETED
|
@@ -1,417 +0,0 @@
|
|
|
1
|
-
import type { AnyCollectionConfig } from "./collections";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @group Models
|
|
5
|
-
*/
|
|
6
|
-
export type OnAction = "cascade" | "restrict" | "no action" | "set null" | "set default";
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* What kind of link a relation is.
|
|
10
|
-
*
|
|
11
|
-
* The discriminant. Every other field a relation carries belongs to exactly one
|
|
12
|
-
* of these, which is the point: a relation used to be a single open interface
|
|
13
|
-
* where `cardinality`, `direction`, `localKey`, `foreignKeyOnTarget`, `through`
|
|
14
|
-
* and `joinPath` were all optional and any combination typechecked. Which link
|
|
15
|
-
* you meant then had to be *inferred* from which fields you happened to set,
|
|
16
|
-
* and the inference was ~200 lines that guessed, fell back on naming
|
|
17
|
-
* conventions, and swallowed its own failures.
|
|
18
|
-
*
|
|
19
|
-
* Most of that guessing produced bugs rather than convenience. A `many`
|
|
20
|
-
* relation carrying a `localKey` — a combination the old type permitted — made
|
|
21
|
-
* the write path stamp the parent's own foreign key onto the child row. Under
|
|
22
|
-
* these kinds that state cannot be written down.
|
|
23
|
-
*
|
|
24
|
-
* @group Models
|
|
25
|
-
*/
|
|
26
|
-
export type RelationKind = "belongsTo" | "hasOne" | "hasMany" | "manyToMany" | "via";
|
|
27
|
-
|
|
28
|
-
/** Fields every relation carries, whatever its kind. @group Models */
|
|
29
|
-
export interface RelationBase {
|
|
30
|
-
/**
|
|
31
|
-
* The name this link is addressed by: the key in `include`, the tab in the
|
|
32
|
-
* admin panel, and the path segment of a nested URL.
|
|
33
|
-
*
|
|
34
|
-
* Defaults to the declaring property's key, or to the target's slug for an
|
|
35
|
-
* entry in `relations`.
|
|
36
|
-
*/
|
|
37
|
-
relationName?: string;
|
|
38
|
-
|
|
39
|
-
/** The collection on the other end. */
|
|
40
|
-
target: () => AnyCollectionConfig;
|
|
41
|
-
|
|
42
|
-
onUpdate?: OnAction;
|
|
43
|
-
onDelete?: OnAction;
|
|
44
|
-
|
|
45
|
-
/** Presentation overrides applied when this relation is rendered as a tab. */
|
|
46
|
-
overrides?: Partial<AnyCollectionConfig>;
|
|
47
|
-
|
|
48
|
-
validation?: {
|
|
49
|
-
required?: boolean;
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* This collection holds the foreign key. One target row per source row.
|
|
55
|
-
*
|
|
56
|
-
* ```ts
|
|
57
|
-
* author: { kind: "belongsTo", target: () => authors, localKey: "author_id" }
|
|
58
|
-
* ```
|
|
59
|
-
* @group Models
|
|
60
|
-
*/
|
|
61
|
-
export interface BelongsToRelation extends RelationBase {
|
|
62
|
-
kind: "belongsTo";
|
|
63
|
-
/**
|
|
64
|
-
* Column on **this** collection's table holding the target's key.
|
|
65
|
-
* Defaults to `<relationName>_id`.
|
|
66
|
-
*/
|
|
67
|
-
localKey?: string;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* The target holds the foreign key, and at most one target row points back.
|
|
72
|
-
*
|
|
73
|
-
* ```ts
|
|
74
|
-
* profile: { kind: "hasOne", target: () => profiles, foreignKeyOnTarget: "user_id" }
|
|
75
|
-
* ```
|
|
76
|
-
* @group Models
|
|
77
|
-
*/
|
|
78
|
-
export interface HasOneRelation extends RelationBase {
|
|
79
|
-
kind: "hasOne";
|
|
80
|
-
/**
|
|
81
|
-
* Column on the **target's** table holding this collection's key.
|
|
82
|
-
* Defaults to `<thisCollection>_id`.
|
|
83
|
-
*/
|
|
84
|
-
foreignKeyOnTarget?: string;
|
|
85
|
-
/**
|
|
86
|
-
* Column on **this** collection's table whose value `foreignKeyOnTarget`
|
|
87
|
-
* holds. Defaults to this collection's primary key.
|
|
88
|
-
*
|
|
89
|
-
* Set it when the two sides are joined on a natural key rather than on the
|
|
90
|
-
* row id — an external identity id, a SKU, a tenant slug. See
|
|
91
|
-
* {@link HasManyRelation.sourceKey}, which this mirrors.
|
|
92
|
-
*/
|
|
93
|
-
sourceKey?: string;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* The target holds the foreign key, and many target rows point back. The
|
|
98
|
-
* children belong to this parent alone — deleting one deletes a row.
|
|
99
|
-
*
|
|
100
|
-
* ```ts
|
|
101
|
-
* posts: { kind: "hasMany", target: () => posts, foreignKeyOnTarget: "author_id" }
|
|
102
|
-
* ```
|
|
103
|
-
* @group Models
|
|
104
|
-
*/
|
|
105
|
-
export interface HasManyRelation extends RelationBase {
|
|
106
|
-
kind: "hasMany";
|
|
107
|
-
/**
|
|
108
|
-
* Column on the **target's** table holding this collection's key.
|
|
109
|
-
* Defaults to `<thisCollection>_id`.
|
|
110
|
-
*/
|
|
111
|
-
foreignKeyOnTarget?: string;
|
|
112
|
-
/**
|
|
113
|
-
* Column on **this** collection's table whose value `foreignKeyOnTarget`
|
|
114
|
-
* holds. Defaults to this collection's primary key.
|
|
115
|
-
*
|
|
116
|
-
* The mirror of `localKey` on {@link BelongsToRelation}: that one names the
|
|
117
|
-
* column this side reads from, this one names the column the other side
|
|
118
|
-
* points at. Without it the pair can only be joined on the row id, which
|
|
119
|
-
* makes a natural-key link — `auth_user_id ↔ auth_user_id`, a SKU, a tenant
|
|
120
|
-
* slug — inexpressible as `hasMany`, and it has to drop to the read-only
|
|
121
|
-
* `via`.
|
|
122
|
-
*
|
|
123
|
-
* The column must be unique: the link addresses one source row per value,
|
|
124
|
-
* and Postgres will not accept a foreign key against a non-unique column.
|
|
125
|
-
*
|
|
126
|
-
* ```ts
|
|
127
|
-
* applications: {
|
|
128
|
-
* kind: "hasMany",
|
|
129
|
-
* target: () => talentApplications,
|
|
130
|
-
* sourceKey: "auth_user_id",
|
|
131
|
-
* foreignKeyOnTarget: "auth_user_id"
|
|
132
|
-
* }
|
|
133
|
-
* ```
|
|
134
|
-
*/
|
|
135
|
-
sourceKey?: string;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Both sides hold many, through a junction table. The target rows are shared,
|
|
140
|
-
* so this collection owns the *link* and not the row: removing one removes a
|
|
141
|
-
* junction row and leaves the target alone.
|
|
142
|
-
*
|
|
143
|
-
* Declared the same way from either side — there is no owning and inverse
|
|
144
|
-
* version. Swap `sourceColumn` and `targetColumn` to describe the other
|
|
145
|
-
* direction.
|
|
146
|
-
*
|
|
147
|
-
* ```ts
|
|
148
|
-
* tags: { kind: "manyToMany", target: () => tags }
|
|
149
|
-
* ```
|
|
150
|
-
* @group Models
|
|
151
|
-
*/
|
|
152
|
-
export interface ManyToManyRelation extends RelationBase {
|
|
153
|
-
kind: "manyToMany";
|
|
154
|
-
/**
|
|
155
|
-
* The junction table and its two key columns. Every part defaults: the
|
|
156
|
-
* table to both table names sorted and joined, the columns to
|
|
157
|
-
* `<collection>_id` and `<relationName>_id`.
|
|
158
|
-
*/
|
|
159
|
-
through?: {
|
|
160
|
-
table?: string;
|
|
161
|
-
/** Junction column holding **this** collection's key. */
|
|
162
|
-
sourceColumn?: string;
|
|
163
|
-
/** Junction column holding the **target's** key. */
|
|
164
|
-
targetColumn?: string;
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* An explicit chain of joins, for links the four shapes above cannot express:
|
|
170
|
-
* multi-hop paths, composite keys, or a join whose condition is not a plain
|
|
171
|
-
* foreign key.
|
|
172
|
-
*
|
|
173
|
-
* Read-only. Rebase will not infer how to write through an arbitrary join
|
|
174
|
-
* chain, and guessing is what this type exists to stop.
|
|
175
|
-
*
|
|
176
|
-
* ```ts
|
|
177
|
-
* permissions: {
|
|
178
|
-
* kind: "via",
|
|
179
|
-
* target: () => permissions,
|
|
180
|
-
* cardinality: "many",
|
|
181
|
-
* joinPath: [
|
|
182
|
-
* { table: "user_roles", on: { from: "id", to: "user_id" } },
|
|
183
|
-
* { table: "role_permissions", on: { from: "role_id", to: "role_id" } },
|
|
184
|
-
* { table: "permissions", on: { from: "permission_id", to: "id" } }
|
|
185
|
-
* ]
|
|
186
|
-
* }
|
|
187
|
-
* ```
|
|
188
|
-
* @group Models
|
|
189
|
-
*/
|
|
190
|
-
export interface ViaRelation extends RelationBase {
|
|
191
|
-
kind: "via";
|
|
192
|
-
/** Whether the chain yields one row or many. Cannot be derived from a join chain. */
|
|
193
|
-
cardinality: "one" | "many";
|
|
194
|
-
joinPath: JoinStep[];
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* A link from one collection to another, as authored.
|
|
199
|
-
*
|
|
200
|
-
* A closed union: pick the kind that describes the link and the type offers
|
|
201
|
-
* exactly the fields that kind needs. See {@link ResolvedRelation} for the form
|
|
202
|
-
* the runtime works with, which has every default filled in.
|
|
203
|
-
*
|
|
204
|
-
* @group Models
|
|
205
|
-
*/
|
|
206
|
-
export type Relation =
|
|
207
|
-
| BelongsToRelation
|
|
208
|
-
| HasOneRelation
|
|
209
|
-
| HasManyRelation
|
|
210
|
-
| ManyToManyRelation
|
|
211
|
-
| ViaRelation;
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* A relation with every default filled in — the form the runtime works with.
|
|
215
|
-
*
|
|
216
|
-
* The authored {@link Relation} and this are deliberately different types.
|
|
217
|
-
* They used to be one, which meant no reader could tell which fields had been
|
|
218
|
-
* supplied and which had been guessed, and so every consumer re-derived what it
|
|
219
|
-
* needed with its own chain of `if (through) … else if (localKey) …` fallbacks.
|
|
220
|
-
* Those chains disagreed with each other; that disagreement is what produced
|
|
221
|
-
* silently wrong reads and corrupt writes.
|
|
222
|
-
*
|
|
223
|
-
* Here each variant carries exactly its own fields, all required. A consumer
|
|
224
|
-
* switches on `kind` and gets what it needs without a fallback, and the cases
|
|
225
|
-
* it forgot are a compile error rather than a wrong answer at runtime.
|
|
226
|
-
*
|
|
227
|
-
* @group Models
|
|
228
|
-
*/
|
|
229
|
-
export type ResolvedRelation =
|
|
230
|
-
| ResolvedBelongsTo
|
|
231
|
-
| ResolvedHasOne
|
|
232
|
-
| ResolvedHasMany
|
|
233
|
-
| ResolvedManyToMany
|
|
234
|
-
| ResolvedVia;
|
|
235
|
-
|
|
236
|
-
/** Fields present on every resolved relation. @group Models */
|
|
237
|
-
export interface ResolvedRelationBase {
|
|
238
|
-
/** Always set: defaulted during resolution if the author omitted it. */
|
|
239
|
-
relationName: string;
|
|
240
|
-
target: () => AnyCollectionConfig;
|
|
241
|
-
/** The target's slug, resolved once so consumers need not call `target()`. */
|
|
242
|
-
targetSlug: string;
|
|
243
|
-
onUpdate?: OnAction;
|
|
244
|
-
onDelete?: OnAction;
|
|
245
|
-
overrides?: Partial<AnyCollectionConfig>;
|
|
246
|
-
validation?: { required?: boolean };
|
|
247
|
-
/**
|
|
248
|
-
* Whether one row or many come back. Derived from `kind` — kept because it
|
|
249
|
-
* is what most consumers actually branch on, and because `via` is the one
|
|
250
|
-
* kind where it is authored rather than implied.
|
|
251
|
-
*/
|
|
252
|
-
cardinality: "one" | "many";
|
|
253
|
-
/**
|
|
254
|
-
* Whether Rebase knows how to write through this link. False only for
|
|
255
|
-
* {@link ResolvedVia}, whose join chain it will not invent a write for.
|
|
256
|
-
*/
|
|
257
|
-
writable: boolean;
|
|
258
|
-
/**
|
|
259
|
-
* Whether the target rows are shared with other parents. True for
|
|
260
|
-
* many-to-many and for multi-hop `via`: what the parent owns is the link,
|
|
261
|
-
* so removing one must not delete the row.
|
|
262
|
-
*/
|
|
263
|
-
shared: boolean;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
/** @group Models */
|
|
267
|
-
export interface ResolvedBelongsTo extends ResolvedRelationBase {
|
|
268
|
-
kind: "belongsTo";
|
|
269
|
-
cardinality: "one";
|
|
270
|
-
writable: true;
|
|
271
|
-
shared: false;
|
|
272
|
-
/** Column on this collection's table. */
|
|
273
|
-
localKey: string;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
/** @group Models */
|
|
277
|
-
export interface ResolvedHasOne extends ResolvedRelationBase {
|
|
278
|
-
kind: "hasOne";
|
|
279
|
-
cardinality: "one";
|
|
280
|
-
writable: true;
|
|
281
|
-
shared: false;
|
|
282
|
-
/** Column on the target's table. */
|
|
283
|
-
foreignKeyOnTarget: string;
|
|
284
|
-
/** @see ResolvedHasMany.sourceKey */
|
|
285
|
-
sourceKey?: string;
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
/** @group Models */
|
|
289
|
-
export interface ResolvedHasMany extends ResolvedRelationBase {
|
|
290
|
-
kind: "hasMany";
|
|
291
|
-
cardinality: "many";
|
|
292
|
-
writable: true;
|
|
293
|
-
shared: false;
|
|
294
|
-
/** Column on the target's table. */
|
|
295
|
-
foreignKeyOnTarget: string;
|
|
296
|
-
/**
|
|
297
|
-
* Column on the source's table that `foreignKeyOnTarget` points at, or
|
|
298
|
-
* `undefined` for the source's primary key.
|
|
299
|
-
*
|
|
300
|
-
* The one optional field on a resolved relation, and deliberately so. Every
|
|
301
|
-
* other default is filled in here because it can be: a table name and a
|
|
302
|
-
* column name are derivable from the relation and its two endpoints alone.
|
|
303
|
-
* The primary key is not — this driver resolves it from `isId`, then the
|
|
304
|
-
* Drizzle schema, then a column named `id`, and the middle tier does not
|
|
305
|
-
* exist at resolution time.
|
|
306
|
-
*
|
|
307
|
-
* So `undefined` is a sentinel with exactly one meaning, not a field a
|
|
308
|
-
* consumer is invited to guess at. Read it through `sourceKeyField()`,
|
|
309
|
-
* which is the only place that turns it into a column name.
|
|
310
|
-
*/
|
|
311
|
-
sourceKey?: string;
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
/** @group Models */
|
|
315
|
-
export interface ResolvedManyToMany extends ResolvedRelationBase {
|
|
316
|
-
kind: "manyToMany";
|
|
317
|
-
cardinality: "many";
|
|
318
|
-
writable: true;
|
|
319
|
-
shared: true;
|
|
320
|
-
through: {
|
|
321
|
-
table: string;
|
|
322
|
-
sourceColumn: string;
|
|
323
|
-
targetColumn: string;
|
|
324
|
-
};
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
/** @group Models */
|
|
328
|
-
export interface ResolvedVia extends ResolvedRelationBase {
|
|
329
|
-
kind: "via";
|
|
330
|
-
writable: false;
|
|
331
|
-
joinPath: JoinStep[];
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
// ── Narrowing helpers ────────────────────────────────────────────────
|
|
335
|
-
//
|
|
336
|
-
// Consumers that only care about one axis — "does this list many rows",
|
|
337
|
-
// "is there a column on the target" — should ask that question rather
|
|
338
|
-
// than enumerate kinds, so adding a kind later does not silently skip them.
|
|
339
|
-
|
|
340
|
-
/** Relations whose target row carries this collection's key. @group Models */
|
|
341
|
-
export type ResolvedForeignKeyOnTarget = ResolvedHasOne | ResolvedHasMany;
|
|
342
|
-
|
|
343
|
-
/** @group Models */
|
|
344
|
-
export function hasForeignKeyOnTarget(relation: ResolvedRelation): relation is ResolvedForeignKeyOnTarget {
|
|
345
|
-
return relation.kind === "hasOne" || relation.kind === "hasMany";
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
/** @group Models */
|
|
349
|
-
export function isManyToMany(relation: ResolvedRelation): relation is ResolvedManyToMany {
|
|
350
|
-
return relation.kind === "manyToMany";
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
/** @group Models */
|
|
354
|
-
export function isToMany(relation: ResolvedRelation): boolean {
|
|
355
|
-
return relation.cardinality === "many";
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
/**
|
|
359
|
-
* Defines a single, explicit step in a multi-join path.
|
|
360
|
-
*
|
|
361
|
-
* Each step represents one JOIN operation in the sequence. The `from` columns
|
|
362
|
-
* refer to the previous table in the chain (or the source table for the first step),
|
|
363
|
-
* and the `to` columns refer to the current table being joined.
|
|
364
|
-
*
|
|
365
|
-
* @example Single column join:
|
|
366
|
-
* ```typescript
|
|
367
|
-
* {
|
|
368
|
-
* table: "authors",
|
|
369
|
-
* on: {
|
|
370
|
-
* from: "author_id", // Column from previous table (e.g., posts.author_id)
|
|
371
|
-
* to: "id" // Column from current table (authors.id)
|
|
372
|
-
* }
|
|
373
|
-
* }
|
|
374
|
-
* ```
|
|
375
|
-
*
|
|
376
|
-
* @example Multi-column composite key join:
|
|
377
|
-
* ```typescript
|
|
378
|
-
* {
|
|
379
|
-
* table: "order_items",
|
|
380
|
-
* on: {
|
|
381
|
-
* from: ["order_id", "store_id"], // Multiple columns from previous table
|
|
382
|
-
* to: ["order_id", "store_id"] // Corresponding columns in current table
|
|
383
|
-
* }
|
|
384
|
-
* }
|
|
385
|
-
* ```
|
|
386
|
-
*/
|
|
387
|
-
export interface JoinStep {
|
|
388
|
-
/**
|
|
389
|
-
* The database table name to join TO in this step.
|
|
390
|
-
* This is the table you're joining into, not the table you're joining from.
|
|
391
|
-
*
|
|
392
|
-
* @example "authors", "user_roles", "product_categories"
|
|
393
|
-
*/
|
|
394
|
-
table: string;
|
|
395
|
-
|
|
396
|
-
/**
|
|
397
|
-
* The join condition for this step. Defines how the previous table
|
|
398
|
-
* connects to the current table.
|
|
399
|
-
*
|
|
400
|
-
* - `from`: Column name(s) on the PREVIOUS table in the join chain
|
|
401
|
-
* - `to`: Column name(s) on the CURRENT table (specified in `table`)
|
|
402
|
-
*
|
|
403
|
-
* For the first step, `from` refers to the source collection's table.
|
|
404
|
-
* For subsequent steps, `from` refers to the table from the previous step.
|
|
405
|
-
*
|
|
406
|
-
* Both `from` and `to` support:
|
|
407
|
-
* - Single column: `"user_id"`
|
|
408
|
-
* - Multiple columns: `["company_id", "region_id"]` for composite keys
|
|
409
|
-
*
|
|
410
|
-
* When using arrays, both `from` and `to` must have the same length,
|
|
411
|
-
* and columns are matched by position (index 0 with index 0, etc.).
|
|
412
|
-
*/
|
|
413
|
-
on: {
|
|
414
|
-
from: string | string[];
|
|
415
|
-
to: string | string[];
|
|
416
|
-
};
|
|
417
|
-
}
|