bun-query-builder 0.1.58 → 0.1.59
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/bin/cli.js +86 -33
- package/dist/orm.d.ts +67 -8
- package/dist/src/index.js +85 -32
- package/dist/type-inference.d.ts +112 -25
- package/package.json +1 -1
package/dist/bin/cli.js
CHANGED
|
@@ -20018,6 +20018,23 @@ var init_actions = __esm(() => {
|
|
|
20018
20018
|
init_wait_ready();
|
|
20019
20019
|
});
|
|
20020
20020
|
|
|
20021
|
+
// src/relation-utils.ts
|
|
20022
|
+
function normalizeRelationEntry(entry) {
|
|
20023
|
+
if (typeof entry === "string")
|
|
20024
|
+
return { model: entry };
|
|
20025
|
+
if (entry && typeof entry === "object" && typeof entry.model === "string") {
|
|
20026
|
+
const e = entry;
|
|
20027
|
+
return { model: e.model, foreignKey: e.foreignKey, onDelete: e.onDelete };
|
|
20028
|
+
}
|
|
20029
|
+
return null;
|
|
20030
|
+
}
|
|
20031
|
+
function normalizeRelationList(rel) {
|
|
20032
|
+
if (!rel)
|
|
20033
|
+
return [];
|
|
20034
|
+
const entries = Array.isArray(rel) ? rel : typeof rel === "object" ? Object.values(rel) : [];
|
|
20035
|
+
return entries.map(normalizeRelationEntry).filter((x) => x !== null);
|
|
20036
|
+
}
|
|
20037
|
+
|
|
20021
20038
|
// ../../node_modules/@stacksjs/ts-faker/dist/chunk-aggdkeg4.js
|
|
20022
20039
|
import { existsSync as zS } from "fs";
|
|
20023
20040
|
import { join as YS } from "path";
|
|
@@ -24753,12 +24770,12 @@ class ModelInstance {
|
|
|
24753
24770
|
only(keys) {
|
|
24754
24771
|
const out = {};
|
|
24755
24772
|
for (const k2 of keys) {
|
|
24756
|
-
out[k2] = this._attributes[k2];
|
|
24773
|
+
out[k2] = this._attributes[toSnakeCase(k2)];
|
|
24757
24774
|
}
|
|
24758
24775
|
return out;
|
|
24759
24776
|
}
|
|
24760
24777
|
except(keys) {
|
|
24761
|
-
const drop = new Set(keys.map((k2) => k2));
|
|
24778
|
+
const drop = new Set(keys.map((k2) => toSnakeCase(k2)));
|
|
24762
24779
|
const out = {};
|
|
24763
24780
|
for (const k2 of Object.keys(this._attributes)) {
|
|
24764
24781
|
if (!drop.has(k2))
|
|
@@ -24786,7 +24803,8 @@ class ModelInstance {
|
|
|
24786
24803
|
if (this._original === null)
|
|
24787
24804
|
return false;
|
|
24788
24805
|
if (column) {
|
|
24789
|
-
|
|
24806
|
+
const key = toSnakeCase(column);
|
|
24807
|
+
return this._attributes[key] !== this._original[key];
|
|
24790
24808
|
}
|
|
24791
24809
|
return Object.keys(this._attributes).some((k2) => this._attributes[k2] !== this._original[k2]);
|
|
24792
24810
|
}
|
|
@@ -24795,7 +24813,7 @@ class ModelInstance {
|
|
|
24795
24813
|
}
|
|
24796
24814
|
getOriginal(column) {
|
|
24797
24815
|
const orig = this.getOriginalAttributes();
|
|
24798
|
-
return orig[column];
|
|
24816
|
+
return orig[toSnakeCase(column)];
|
|
24799
24817
|
}
|
|
24800
24818
|
getChanges() {
|
|
24801
24819
|
if (this._original === null)
|
|
@@ -24834,7 +24852,7 @@ class ModelInstance {
|
|
|
24834
24852
|
const setters = this._definition.set || {};
|
|
24835
24853
|
for (const [key, setter] of Object.entries(setters)) {
|
|
24836
24854
|
if (this.isDirty(key)) {
|
|
24837
|
-
this._attributes[key] = setter(this._attributes);
|
|
24855
|
+
this._attributes[toSnakeCase(key)] = setter(this._attributes);
|
|
24838
24856
|
}
|
|
24839
24857
|
}
|
|
24840
24858
|
if (this._attributes[pk]) {
|
|
@@ -25045,6 +25063,34 @@ function resolveRelation(definition, relationName) {
|
|
|
25045
25063
|
}
|
|
25046
25064
|
return null;
|
|
25047
25065
|
}
|
|
25066
|
+
function findBelongsToEntry() {
|
|
25067
|
+
const rel = definition.belongsTo;
|
|
25068
|
+
if (!rel)
|
|
25069
|
+
return null;
|
|
25070
|
+
const lower = relationName.toLowerCase();
|
|
25071
|
+
const unwrap = (entry) => {
|
|
25072
|
+
if (typeof entry === "string")
|
|
25073
|
+
return { model: entry };
|
|
25074
|
+
if (entry && typeof entry === "object" && typeof entry.model === "string")
|
|
25075
|
+
return { model: entry.model, foreignKey: entry.foreignKey };
|
|
25076
|
+
return null;
|
|
25077
|
+
};
|
|
25078
|
+
if (Array.isArray(rel)) {
|
|
25079
|
+
for (const item of rel) {
|
|
25080
|
+
const e2 = unwrap(item);
|
|
25081
|
+
if (e2 && e2.model.toLowerCase() === lower)
|
|
25082
|
+
return e2;
|
|
25083
|
+
}
|
|
25084
|
+
return null;
|
|
25085
|
+
}
|
|
25086
|
+
if (typeof rel === "object") {
|
|
25087
|
+
for (const [key, value] of Object.entries(rel)) {
|
|
25088
|
+
if (key === relationName || key.toLowerCase() === lower)
|
|
25089
|
+
return unwrap(value);
|
|
25090
|
+
}
|
|
25091
|
+
}
|
|
25092
|
+
return null;
|
|
25093
|
+
}
|
|
25048
25094
|
function findBelongsToManyEntry() {
|
|
25049
25095
|
const rel = definition.belongsToMany;
|
|
25050
25096
|
if (!rel)
|
|
@@ -25084,12 +25130,13 @@ function resolveRelation(definition, relationName) {
|
|
|
25084
25130
|
const foreignKey = toSnakeCase(parentName) + "_id";
|
|
25085
25131
|
return { type: "hasOne", relatedModelName: hasOneModel, relatedTable, foreignKey, localKey: parentPk };
|
|
25086
25132
|
}
|
|
25087
|
-
const
|
|
25088
|
-
if (
|
|
25133
|
+
const belongsToEntry = findBelongsToEntry();
|
|
25134
|
+
if (belongsToEntry) {
|
|
25135
|
+
const belongsToModel = belongsToEntry.model;
|
|
25089
25136
|
const relatedModel = getModelFromRegistry(belongsToModel);
|
|
25090
25137
|
const relatedTable = relatedModel?.getTable?.() || toTableName(belongsToModel);
|
|
25091
25138
|
const relatedPk = relatedModel?.getDefinition?.()?.primaryKey || "id";
|
|
25092
|
-
const foreignKey = toSnakeCase(belongsToModel)
|
|
25139
|
+
const foreignKey = belongsToEntry.foreignKey || `${toSnakeCase(belongsToModel)}_id`;
|
|
25093
25140
|
return { type: "belongsTo", relatedModelName: belongsToModel, relatedTable, foreignKey, localKey: relatedPk };
|
|
25094
25141
|
}
|
|
25095
25142
|
const found = findBelongsToManyEntry();
|
|
@@ -25634,7 +25681,10 @@ class ModelQueryBuilder {
|
|
|
25634
25681
|
return this;
|
|
25635
25682
|
}
|
|
25636
25683
|
with(...relations) {
|
|
25637
|
-
|
|
25684
|
+
for (const r2 of relations) {
|
|
25685
|
+
if (!this._withRelations.includes(r2))
|
|
25686
|
+
this._withRelations.push(r2);
|
|
25687
|
+
}
|
|
25638
25688
|
return this;
|
|
25639
25689
|
}
|
|
25640
25690
|
getWithRelations() {
|
|
@@ -26193,12 +26243,19 @@ function createModel(definition) {
|
|
|
26193
26243
|
}
|
|
26194
26244
|
async function createTableFromModel(definition) {
|
|
26195
26245
|
const exec = getExecutor();
|
|
26196
|
-
const pk = definition.primaryKey || "id";
|
|
26246
|
+
const pk = toSnakeCase(definition.primaryKey || "id");
|
|
26197
26247
|
const columns = [];
|
|
26248
|
+
const emitted = new Set([pk]);
|
|
26198
26249
|
columns.push(definition.autoIncrement !== false ? `${pk} INTEGER PRIMARY KEY AUTOINCREMENT` : `${pk} INTEGER PRIMARY KEY`);
|
|
26199
|
-
if (definition.traits?.useUuid)
|
|
26250
|
+
if (definition.traits?.useUuid) {
|
|
26200
26251
|
columns.push("uuid TEXT UNIQUE");
|
|
26201
|
-
|
|
26252
|
+
emitted.add("uuid");
|
|
26253
|
+
}
|
|
26254
|
+
for (const [attrName, attr] of Object.entries(definition.attributes)) {
|
|
26255
|
+
const name = toSnakeCase(attrName);
|
|
26256
|
+
if (emitted.has(name))
|
|
26257
|
+
continue;
|
|
26258
|
+
emitted.add(name);
|
|
26202
26259
|
let colType = "TEXT";
|
|
26203
26260
|
if (attr.type === "number")
|
|
26204
26261
|
colType = "INTEGER";
|
|
@@ -26219,10 +26276,23 @@ async function createTableFromModel(definition) {
|
|
|
26219
26276
|
}
|
|
26220
26277
|
columns.push(colDef);
|
|
26221
26278
|
}
|
|
26279
|
+
for (const rel of normalizeRelationList(definition.belongsTo)) {
|
|
26280
|
+
const name = rel.foreignKey ?? `${toSnakeCase(rel.model)}_id`;
|
|
26281
|
+
if (emitted.has(name))
|
|
26282
|
+
continue;
|
|
26283
|
+
emitted.add(name);
|
|
26284
|
+
columns.push(`${name} INTEGER`);
|
|
26285
|
+
}
|
|
26222
26286
|
if (timestampsEnabled(definition)) {
|
|
26223
|
-
|
|
26287
|
+
for (const c2 of ["created_at", "updated_at"]) {
|
|
26288
|
+
if (emitted.has(c2))
|
|
26289
|
+
continue;
|
|
26290
|
+
emitted.add(c2);
|
|
26291
|
+
columns.push(`${c2} TEXT`);
|
|
26292
|
+
}
|
|
26224
26293
|
}
|
|
26225
|
-
if (softDeletesEnabled(definition)) {
|
|
26294
|
+
if (softDeletesEnabled(definition) && !emitted.has("deleted_at")) {
|
|
26295
|
+
emitted.add("deleted_at");
|
|
26226
26296
|
columns.push("deleted_at TEXT");
|
|
26227
26297
|
}
|
|
26228
26298
|
await exec.run(`CREATE TABLE IF NOT EXISTS ${definition.table} (${columns.join(", ")})`, []);
|
|
@@ -26265,7 +26335,7 @@ async function seedModel(definition, count, faker) {
|
|
|
26265
26335
|
const data = {};
|
|
26266
26336
|
for (const [name, attr] of Object.entries(definition.attributes)) {
|
|
26267
26337
|
if (attr.factory)
|
|
26268
|
-
data[name] = attr.factory(faker);
|
|
26338
|
+
data[toSnakeCase(name)] = attr.factory(faker);
|
|
26269
26339
|
}
|
|
26270
26340
|
if (timestampsEnabled(definition)) {
|
|
26271
26341
|
const now = formatNow();
|
|
@@ -27766,23 +27836,6 @@ async function loadModels(options) {
|
|
|
27766
27836
|
}
|
|
27767
27837
|
var init_loader = () => {};
|
|
27768
27838
|
|
|
27769
|
-
// src/relation-utils.ts
|
|
27770
|
-
function normalizeRelationEntry(entry) {
|
|
27771
|
-
if (typeof entry === "string")
|
|
27772
|
-
return { model: entry };
|
|
27773
|
-
if (entry && typeof entry === "object" && typeof entry.model === "string") {
|
|
27774
|
-
const e2 = entry;
|
|
27775
|
-
return { model: e2.model, foreignKey: e2.foreignKey, onDelete: e2.onDelete };
|
|
27776
|
-
}
|
|
27777
|
-
return null;
|
|
27778
|
-
}
|
|
27779
|
-
function normalizeRelationList(rel) {
|
|
27780
|
-
if (!rel)
|
|
27781
|
-
return [];
|
|
27782
|
-
const entries = Array.isArray(rel) ? rel : typeof rel === "object" ? Object.values(rel) : [];
|
|
27783
|
-
return entries.map(normalizeRelationEntry).filter((x2) => x2 !== null);
|
|
27784
|
-
}
|
|
27785
|
-
|
|
27786
27839
|
// src/meta.ts
|
|
27787
27840
|
function buildSchemaMeta(models) {
|
|
27788
27841
|
const modelToTable = {};
|
|
@@ -31022,7 +31075,7 @@ function getPrefix() {
|
|
|
31022
31075
|
}
|
|
31023
31076
|
var prefix = getPrefix();
|
|
31024
31077
|
// package.json
|
|
31025
|
-
var version2 = "0.1.
|
|
31078
|
+
var version2 = "0.1.59";
|
|
31026
31079
|
|
|
31027
31080
|
// bin/cli.ts
|
|
31028
31081
|
init_actions();
|
package/dist/orm.d.ts
CHANGED
|
@@ -68,6 +68,17 @@ export declare interface ModelHookInstance extends Record<string, unknown> {
|
|
|
68
68
|
except?(keys: ReadonlyArray<string>): Record<string, unknown>
|
|
69
69
|
toArray?(): Record<string, unknown>
|
|
70
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* Object form of a `belongsTo` entry. The migration generator has always
|
|
73
|
+
* honored `foreignKey`/`onDelete` here (see `normalizeRelationEntry`), but the
|
|
74
|
+
* declaration type only admitted plain model-name strings — so the supported
|
|
75
|
+
* form was a type error at the call site.
|
|
76
|
+
*/
|
|
77
|
+
export declare interface BelongsToEntry {
|
|
78
|
+
readonly model: string
|
|
79
|
+
readonly foreignKey?: string
|
|
80
|
+
readonly onDelete?: import('./schema').OnForeignKeyAction
|
|
81
|
+
}
|
|
71
82
|
// Base model definition
|
|
72
83
|
export declare interface ModelDefinition {
|
|
73
84
|
readonly name: string
|
|
@@ -113,7 +124,7 @@ export declare interface ModelDefinition {
|
|
|
113
124
|
readonly useActivityLog?: boolean | object
|
|
114
125
|
readonly useSocials?: readonly string[]
|
|
115
126
|
}
|
|
116
|
-
readonly belongsTo?: readonly string[] | Readonly<Record<string, string>>
|
|
127
|
+
readonly belongsTo?: readonly (string | BelongsToEntry)[] | Readonly<Record<string, string | BelongsToEntry>>
|
|
117
128
|
readonly hasMany?: readonly string[] | Readonly<Record<string, string>>
|
|
118
129
|
readonly hasOne?: readonly string[] | Readonly<Record<string, string>>
|
|
119
130
|
readonly belongsToMany?: readonly (string | object)[] | Readonly<Record<string, string | object>>
|
|
@@ -247,7 +258,7 @@ declare type SnakeCaseAttributes<TDef extends ModelDefinition> = {
|
|
|
247
258
|
// System fields added by traits. The primary-key column honors the model's
|
|
248
259
|
// declared `primaryKey` (default 'id') — a custom-pk model exposes THAT
|
|
249
260
|
// column, not a phantom 'id'. Mirrors InferAttributes in type-inference.ts.
|
|
250
|
-
declare type
|
|
261
|
+
declare type TraitSystemFields<TDef extends ModelDefinition> = { [K in TDef extends { primaryKey: infer PK extends string } ? PK : 'id']: number } &
|
|
251
262
|
(TDef['traits'] extends { useUuid: true } ? { uuid: string } : {}) &
|
|
252
263
|
(TDef['traits'] extends { useTimestamps: true } ? { created_at: string; updated_at: string | null } : {}) &
|
|
253
264
|
(TDef['traits'] extends { timestampable: true | object } ? { created_at: string; updated_at: string | null } : {}) &
|
|
@@ -255,6 +266,34 @@ declare type SystemFields<TDef extends ModelDefinition> = { [K in TDef extends {
|
|
|
255
266
|
(TDef['traits'] extends { softDeletable: true | object } ? { deleted_at: string | null } : {}) &
|
|
256
267
|
(TDef['traits'] extends { useAuth: true | object } ? { two_factor_secret: string | null; public_key: string | null } : {}) &
|
|
257
268
|
(TDef['traits'] extends { billable: true | object } ? { stripe_id: string | null } : {});
|
|
269
|
+
/**
|
|
270
|
+
* Every column name the model declares itself, in both the casing it was
|
|
271
|
+
* written in and its snake_case column form.
|
|
272
|
+
*/
|
|
273
|
+
declare type DeclaredColumns<TDef extends ModelDefinition> = AttributeKeys<TDef> | SnakeCase<AttributeKeys<TDef>>;
|
|
274
|
+
/**
|
|
275
|
+
* Trait-added system fields, minus anything the model declares explicitly.
|
|
276
|
+
*
|
|
277
|
+
* Without the `Omit`, a model that declares a column a trait also contributes
|
|
278
|
+
* (`created_at: { type: 'date' }` alongside `useTimestamps`, or a `user_id`
|
|
279
|
+
* string alongside `belongsTo: ['User']`) intersected the two shapes into
|
|
280
|
+
* `Date & string` — or outright `never`. Every read of that column then had an
|
|
281
|
+
* uninhabited type and every write was rejected. A column the model spells out
|
|
282
|
+
* is the authority on its own type; the trait default only fills the gap.
|
|
283
|
+
*/
|
|
284
|
+
declare type SystemFields<TDef extends ModelDefinition> = Omit<TraitSystemFields<TDef>, DeclaredColumns<TDef>>;
|
|
285
|
+
/**
|
|
286
|
+
* A single `belongsTo` entry reduced to the FK column it puts on this table.
|
|
287
|
+
* Mirrors `normalizeRelationEntry` in relation-utils.ts: an explicit
|
|
288
|
+
* `foreignKey` wins, otherwise the name is derived from the model name.
|
|
289
|
+
*/
|
|
290
|
+
declare type BelongsToFkOf<E> = E extends string
|
|
291
|
+
? `${SnakeCase<Uncapitalize<E>>}_id`
|
|
292
|
+
: E extends { foreignKey: infer F extends string }
|
|
293
|
+
? F
|
|
294
|
+
: E extends { model: infer M extends string }
|
|
295
|
+
? `${SnakeCase<Uncapitalize<M>>}_id`
|
|
296
|
+
: never;
|
|
258
297
|
/**
|
|
259
298
|
* The foreign-key columns a `belongsTo` puts on THIS model's table.
|
|
260
299
|
*
|
|
@@ -264,14 +303,25 @@ declare type SystemFields<TDef extends ModelDefinition> = { [K in TDef extends {
|
|
|
264
303
|
* from both `ModelAttributes` and `ColumnName`, which made every such query a
|
|
265
304
|
* type error against a column that demonstrably exists.
|
|
266
305
|
*
|
|
267
|
-
*
|
|
268
|
-
*
|
|
306
|
+
* All four declaration shapes the migration generator accepts are covered:
|
|
307
|
+
* `['Farm']`, `[{ model: 'Farm', foreignKey: 'owner_id' }]`, `{ farm: 'Farm' }`
|
|
308
|
+
* and `{ owner: { model: 'User', foreignKey: 'owner_id' } }`. The array case
|
|
309
|
+
* MUST be checked first — a tuple also structurally matches `Record`, and the
|
|
310
|
+
* record branch would otherwise read its numeric indices as entries.
|
|
311
|
+
*
|
|
312
|
+
* The default name follows the same snake_case convention the relation resolver
|
|
313
|
+
* uses at runtime: `Farm` -> `farm_id`, `TreatmentMap` -> `treatment_map_id`.
|
|
269
314
|
*/
|
|
270
|
-
declare type BelongsToKeys<TDef extends ModelDefinition> = TDef extends { belongsTo: infer R
|
|
271
|
-
?
|
|
315
|
+
declare type BelongsToKeys<TDef extends ModelDefinition> = TDef extends { belongsTo: infer R }
|
|
316
|
+
? R extends readonly (infer E)[]
|
|
317
|
+
? BelongsToFkOf<E>
|
|
318
|
+
: R extends Readonly<Record<string, infer W>>
|
|
319
|
+
? BelongsToFkOf<W>
|
|
320
|
+
: never
|
|
272
321
|
: never;
|
|
322
|
+
// A declared attribute of the same name wins — see SystemFields above.
|
|
273
323
|
declare type BelongsToColumns<TDef extends ModelDefinition> = {
|
|
274
|
-
[K in BelongsToKeys<TDef
|
|
324
|
+
[K in Exclude<BelongsToKeys<TDef>, DeclaredColumns<TDef>>]: number
|
|
275
325
|
}
|
|
276
326
|
// Complete model type
|
|
277
327
|
declare type ModelAttributes<TDef extends ModelDefinition> = InferModelAttributes<TDef> & SnakeCaseAttributes<TDef> & SystemFields<TDef> & BelongsToColumns<TDef>;
|
|
@@ -295,9 +345,18 @@ declare type HiddenKeys<TDef extends ModelDefinition> = {
|
|
|
295
345
|
declare type FillableKeys<TDef extends ModelDefinition> = {
|
|
296
346
|
[K in AttributeKeys<TDef>]: TDef['attributes'][K] extends { fillable: true } ? K : never
|
|
297
347
|
}[AttributeKeys<TDef>];
|
|
348
|
+
/**
|
|
349
|
+
* `belongsTo` foreign keys are always writable.
|
|
350
|
+
*
|
|
351
|
+
* Attaching a record to its parent IS the create: `Mission.create({ …,
|
|
352
|
+
* field_id: field.id })`. There is no attribute declaration to put
|
|
353
|
+
* `fillable: true` on, because the column comes from the relation rather than
|
|
354
|
+
* from `attributes`, so without this every such create was a type error
|
|
355
|
+
* against the one column the relation exists to set.
|
|
356
|
+
*/
|
|
298
357
|
declare type FillableAttributes<TDef extends ModelDefinition> = Partial<Pick<
|
|
299
358
|
ModelAttributes<TDef>,
|
|
300
|
-
FillableKeys<TDef> | SnakeCase<FillableKeys<TDef>>
|
|
359
|
+
FillableKeys<TDef> | SnakeCase<FillableKeys<TDef>> | BelongsToKeys<TDef>
|
|
301
360
|
>>;
|
|
302
361
|
// Numeric attribute columns — constrains aggregate methods (sum, avg, etc.)
|
|
303
362
|
declare type NumericColumns<TDef extends ModelDefinition> = {
|
package/dist/src/index.js
CHANGED
|
@@ -20017,6 +20017,23 @@ var init_actions = __esm(() => {
|
|
|
20017
20017
|
init_wait_ready();
|
|
20018
20018
|
});
|
|
20019
20019
|
|
|
20020
|
+
// src/relation-utils.ts
|
|
20021
|
+
function normalizeRelationEntry(entry) {
|
|
20022
|
+
if (typeof entry === "string")
|
|
20023
|
+
return { model: entry };
|
|
20024
|
+
if (entry && typeof entry === "object" && typeof entry.model === "string") {
|
|
20025
|
+
const e = entry;
|
|
20026
|
+
return { model: e.model, foreignKey: e.foreignKey, onDelete: e.onDelete };
|
|
20027
|
+
}
|
|
20028
|
+
return null;
|
|
20029
|
+
}
|
|
20030
|
+
function normalizeRelationList(rel) {
|
|
20031
|
+
if (!rel)
|
|
20032
|
+
return [];
|
|
20033
|
+
const entries = Array.isArray(rel) ? rel : typeof rel === "object" ? Object.values(rel) : [];
|
|
20034
|
+
return entries.map(normalizeRelationEntry).filter((x) => x !== null);
|
|
20035
|
+
}
|
|
20036
|
+
|
|
20020
20037
|
// ../../node_modules/@stacksjs/ts-faker/dist/chunk-aggdkeg4.js
|
|
20021
20038
|
import { existsSync as zS } from "fs";
|
|
20022
20039
|
import { join as YS } from "path";
|
|
@@ -24752,12 +24769,12 @@ class ModelInstance {
|
|
|
24752
24769
|
only(keys) {
|
|
24753
24770
|
const out = {};
|
|
24754
24771
|
for (const k2 of keys) {
|
|
24755
|
-
out[k2] = this._attributes[k2];
|
|
24772
|
+
out[k2] = this._attributes[toSnakeCase(k2)];
|
|
24756
24773
|
}
|
|
24757
24774
|
return out;
|
|
24758
24775
|
}
|
|
24759
24776
|
except(keys) {
|
|
24760
|
-
const drop = new Set(keys.map((k2) => k2));
|
|
24777
|
+
const drop = new Set(keys.map((k2) => toSnakeCase(k2)));
|
|
24761
24778
|
const out = {};
|
|
24762
24779
|
for (const k2 of Object.keys(this._attributes)) {
|
|
24763
24780
|
if (!drop.has(k2))
|
|
@@ -24785,7 +24802,8 @@ class ModelInstance {
|
|
|
24785
24802
|
if (this._original === null)
|
|
24786
24803
|
return false;
|
|
24787
24804
|
if (column) {
|
|
24788
|
-
|
|
24805
|
+
const key = toSnakeCase(column);
|
|
24806
|
+
return this._attributes[key] !== this._original[key];
|
|
24789
24807
|
}
|
|
24790
24808
|
return Object.keys(this._attributes).some((k2) => this._attributes[k2] !== this._original[k2]);
|
|
24791
24809
|
}
|
|
@@ -24794,7 +24812,7 @@ class ModelInstance {
|
|
|
24794
24812
|
}
|
|
24795
24813
|
getOriginal(column) {
|
|
24796
24814
|
const orig = this.getOriginalAttributes();
|
|
24797
|
-
return orig[column];
|
|
24815
|
+
return orig[toSnakeCase(column)];
|
|
24798
24816
|
}
|
|
24799
24817
|
getChanges() {
|
|
24800
24818
|
if (this._original === null)
|
|
@@ -24833,7 +24851,7 @@ class ModelInstance {
|
|
|
24833
24851
|
const setters = this._definition.set || {};
|
|
24834
24852
|
for (const [key, setter] of Object.entries(setters)) {
|
|
24835
24853
|
if (this.isDirty(key)) {
|
|
24836
|
-
this._attributes[key] = setter(this._attributes);
|
|
24854
|
+
this._attributes[toSnakeCase(key)] = setter(this._attributes);
|
|
24837
24855
|
}
|
|
24838
24856
|
}
|
|
24839
24857
|
if (this._attributes[pk]) {
|
|
@@ -25044,6 +25062,34 @@ function resolveRelation(definition, relationName) {
|
|
|
25044
25062
|
}
|
|
25045
25063
|
return null;
|
|
25046
25064
|
}
|
|
25065
|
+
function findBelongsToEntry() {
|
|
25066
|
+
const rel = definition.belongsTo;
|
|
25067
|
+
if (!rel)
|
|
25068
|
+
return null;
|
|
25069
|
+
const lower = relationName.toLowerCase();
|
|
25070
|
+
const unwrap = (entry) => {
|
|
25071
|
+
if (typeof entry === "string")
|
|
25072
|
+
return { model: entry };
|
|
25073
|
+
if (entry && typeof entry === "object" && typeof entry.model === "string")
|
|
25074
|
+
return { model: entry.model, foreignKey: entry.foreignKey };
|
|
25075
|
+
return null;
|
|
25076
|
+
};
|
|
25077
|
+
if (Array.isArray(rel)) {
|
|
25078
|
+
for (const item of rel) {
|
|
25079
|
+
const e2 = unwrap(item);
|
|
25080
|
+
if (e2 && e2.model.toLowerCase() === lower)
|
|
25081
|
+
return e2;
|
|
25082
|
+
}
|
|
25083
|
+
return null;
|
|
25084
|
+
}
|
|
25085
|
+
if (typeof rel === "object") {
|
|
25086
|
+
for (const [key, value] of Object.entries(rel)) {
|
|
25087
|
+
if (key === relationName || key.toLowerCase() === lower)
|
|
25088
|
+
return unwrap(value);
|
|
25089
|
+
}
|
|
25090
|
+
}
|
|
25091
|
+
return null;
|
|
25092
|
+
}
|
|
25047
25093
|
function findBelongsToManyEntry() {
|
|
25048
25094
|
const rel = definition.belongsToMany;
|
|
25049
25095
|
if (!rel)
|
|
@@ -25083,12 +25129,13 @@ function resolveRelation(definition, relationName) {
|
|
|
25083
25129
|
const foreignKey = toSnakeCase(parentName) + "_id";
|
|
25084
25130
|
return { type: "hasOne", relatedModelName: hasOneModel, relatedTable, foreignKey, localKey: parentPk };
|
|
25085
25131
|
}
|
|
25086
|
-
const
|
|
25087
|
-
if (
|
|
25132
|
+
const belongsToEntry = findBelongsToEntry();
|
|
25133
|
+
if (belongsToEntry) {
|
|
25134
|
+
const belongsToModel = belongsToEntry.model;
|
|
25088
25135
|
const relatedModel = getModelFromRegistry(belongsToModel);
|
|
25089
25136
|
const relatedTable = relatedModel?.getTable?.() || toTableName(belongsToModel);
|
|
25090
25137
|
const relatedPk = relatedModel?.getDefinition?.()?.primaryKey || "id";
|
|
25091
|
-
const foreignKey = toSnakeCase(belongsToModel)
|
|
25138
|
+
const foreignKey = belongsToEntry.foreignKey || `${toSnakeCase(belongsToModel)}_id`;
|
|
25092
25139
|
return { type: "belongsTo", relatedModelName: belongsToModel, relatedTable, foreignKey, localKey: relatedPk };
|
|
25093
25140
|
}
|
|
25094
25141
|
const found = findBelongsToManyEntry();
|
|
@@ -25633,7 +25680,10 @@ class ModelQueryBuilder {
|
|
|
25633
25680
|
return this;
|
|
25634
25681
|
}
|
|
25635
25682
|
with(...relations) {
|
|
25636
|
-
|
|
25683
|
+
for (const r2 of relations) {
|
|
25684
|
+
if (!this._withRelations.includes(r2))
|
|
25685
|
+
this._withRelations.push(r2);
|
|
25686
|
+
}
|
|
25637
25687
|
return this;
|
|
25638
25688
|
}
|
|
25639
25689
|
getWithRelations() {
|
|
@@ -26192,12 +26242,19 @@ function createModel(definition) {
|
|
|
26192
26242
|
}
|
|
26193
26243
|
async function createTableFromModel(definition) {
|
|
26194
26244
|
const exec = getExecutor();
|
|
26195
|
-
const pk = definition.primaryKey || "id";
|
|
26245
|
+
const pk = toSnakeCase(definition.primaryKey || "id");
|
|
26196
26246
|
const columns = [];
|
|
26247
|
+
const emitted = new Set([pk]);
|
|
26197
26248
|
columns.push(definition.autoIncrement !== false ? `${pk} INTEGER PRIMARY KEY AUTOINCREMENT` : `${pk} INTEGER PRIMARY KEY`);
|
|
26198
|
-
if (definition.traits?.useUuid)
|
|
26249
|
+
if (definition.traits?.useUuid) {
|
|
26199
26250
|
columns.push("uuid TEXT UNIQUE");
|
|
26200
|
-
|
|
26251
|
+
emitted.add("uuid");
|
|
26252
|
+
}
|
|
26253
|
+
for (const [attrName, attr] of Object.entries(definition.attributes)) {
|
|
26254
|
+
const name = toSnakeCase(attrName);
|
|
26255
|
+
if (emitted.has(name))
|
|
26256
|
+
continue;
|
|
26257
|
+
emitted.add(name);
|
|
26201
26258
|
let colType = "TEXT";
|
|
26202
26259
|
if (attr.type === "number")
|
|
26203
26260
|
colType = "INTEGER";
|
|
@@ -26218,10 +26275,23 @@ async function createTableFromModel(definition) {
|
|
|
26218
26275
|
}
|
|
26219
26276
|
columns.push(colDef);
|
|
26220
26277
|
}
|
|
26278
|
+
for (const rel of normalizeRelationList(definition.belongsTo)) {
|
|
26279
|
+
const name = rel.foreignKey ?? `${toSnakeCase(rel.model)}_id`;
|
|
26280
|
+
if (emitted.has(name))
|
|
26281
|
+
continue;
|
|
26282
|
+
emitted.add(name);
|
|
26283
|
+
columns.push(`${name} INTEGER`);
|
|
26284
|
+
}
|
|
26221
26285
|
if (timestampsEnabled(definition)) {
|
|
26222
|
-
|
|
26286
|
+
for (const c2 of ["created_at", "updated_at"]) {
|
|
26287
|
+
if (emitted.has(c2))
|
|
26288
|
+
continue;
|
|
26289
|
+
emitted.add(c2);
|
|
26290
|
+
columns.push(`${c2} TEXT`);
|
|
26291
|
+
}
|
|
26223
26292
|
}
|
|
26224
|
-
if (softDeletesEnabled(definition)) {
|
|
26293
|
+
if (softDeletesEnabled(definition) && !emitted.has("deleted_at")) {
|
|
26294
|
+
emitted.add("deleted_at");
|
|
26225
26295
|
columns.push("deleted_at TEXT");
|
|
26226
26296
|
}
|
|
26227
26297
|
await exec.run(`CREATE TABLE IF NOT EXISTS ${definition.table} (${columns.join(", ")})`, []);
|
|
@@ -26264,7 +26334,7 @@ async function seedModel(definition, count, faker) {
|
|
|
26264
26334
|
const data = {};
|
|
26265
26335
|
for (const [name, attr] of Object.entries(definition.attributes)) {
|
|
26266
26336
|
if (attr.factory)
|
|
26267
|
-
data[name] = attr.factory(faker);
|
|
26337
|
+
data[toSnakeCase(name)] = attr.factory(faker);
|
|
26268
26338
|
}
|
|
26269
26339
|
if (timestampsEnabled(definition)) {
|
|
26270
26340
|
const now = formatNow();
|
|
@@ -27765,23 +27835,6 @@ async function loadModels(options) {
|
|
|
27765
27835
|
}
|
|
27766
27836
|
var init_loader = () => {};
|
|
27767
27837
|
|
|
27768
|
-
// src/relation-utils.ts
|
|
27769
|
-
function normalizeRelationEntry(entry) {
|
|
27770
|
-
if (typeof entry === "string")
|
|
27771
|
-
return { model: entry };
|
|
27772
|
-
if (entry && typeof entry === "object" && typeof entry.model === "string") {
|
|
27773
|
-
const e2 = entry;
|
|
27774
|
-
return { model: e2.model, foreignKey: e2.foreignKey, onDelete: e2.onDelete };
|
|
27775
|
-
}
|
|
27776
|
-
return null;
|
|
27777
|
-
}
|
|
27778
|
-
function normalizeRelationList(rel) {
|
|
27779
|
-
if (!rel)
|
|
27780
|
-
return [];
|
|
27781
|
-
const entries = Array.isArray(rel) ? rel : typeof rel === "object" ? Object.values(rel) : [];
|
|
27782
|
-
return entries.map(normalizeRelationEntry).filter((x2) => x2 !== null);
|
|
27783
|
-
}
|
|
27784
|
-
|
|
27785
27838
|
// src/meta.ts
|
|
27786
27839
|
function buildSchemaMeta(models) {
|
|
27787
27840
|
const modelToTable = {};
|
package/dist/type-inference.d.ts
CHANGED
|
@@ -32,7 +32,7 @@ declare interface InferableModelDefinition {
|
|
|
32
32
|
readonly useAuth?: boolean | object
|
|
33
33
|
readonly billable?: boolean | object
|
|
34
34
|
}
|
|
35
|
-
readonly belongsTo?: readonly string[] | Readonly<Record<string, string>>
|
|
35
|
+
readonly belongsTo?: readonly (string | object)[] | Readonly<Record<string, string | object>>
|
|
36
36
|
readonly hasMany?: readonly string[] | Readonly<Record<string, string>>
|
|
37
37
|
readonly hasOne?: readonly string[] | Readonly<Record<string, string>>
|
|
38
38
|
readonly belongsToMany?: readonly (string | object)[] | Readonly<Record<string, string | object>>
|
|
@@ -72,6 +72,41 @@ declare type ResolveDefinition<TModel> = TModel extends { getDefinition: () => i
|
|
|
72
72
|
never;
|
|
73
73
|
/** Extract user-defined attribute keys from a model definition */
|
|
74
74
|
declare type DefinitionAttributeKeys<TDef extends InferableModelDefinition> = keyof TDef['attributes'] & string;
|
|
75
|
+
/** The model's primary-key column name, defaulting to `id`. */
|
|
76
|
+
declare type PrimaryKeyOf<TDef> = TDef extends { primaryKey: infer PK extends string } ? PK : 'id';
|
|
77
|
+
/**
|
|
78
|
+
* A single `belongsTo` entry reduced to the FK column it puts on this table.
|
|
79
|
+
* Mirrors `normalizeRelationEntry` in relation-utils.ts and `BelongsToFkOf` in
|
|
80
|
+
* orm.ts: an explicit `foreignKey` wins, otherwise the name is derived from
|
|
81
|
+
* the model name.
|
|
82
|
+
*/
|
|
83
|
+
declare type BelongsToFkOf<E> = E extends string
|
|
84
|
+
? `${SnakeCase<Uncapitalize<E>>}_id`
|
|
85
|
+
: E extends { foreignKey: infer F extends string }
|
|
86
|
+
? F
|
|
87
|
+
: E extends { model: infer M extends string }
|
|
88
|
+
? `${SnakeCase<Uncapitalize<M>>}_id`
|
|
89
|
+
: never;
|
|
90
|
+
/**
|
|
91
|
+
* The foreign-key columns a `belongsTo` puts on THIS model's table — they are
|
|
92
|
+
* emitted by the migration generator, so they are as real as any declared
|
|
93
|
+
* attribute. The array case MUST be checked first: a tuple also structurally
|
|
94
|
+
* matches `Record`, and the record branch would otherwise read its numeric
|
|
95
|
+
* indices as entries.
|
|
96
|
+
*/
|
|
97
|
+
declare type BelongsToKeys<TDef> = TDef extends { belongsTo: infer R }
|
|
98
|
+
? R extends readonly (infer E)[]
|
|
99
|
+
? BelongsToFkOf<E>
|
|
100
|
+
: R extends Readonly<Record<string, infer W>>
|
|
101
|
+
? BelongsToFkOf<W>
|
|
102
|
+
: never
|
|
103
|
+
: never;
|
|
104
|
+
/** camelCase -> snake_case, matching the column names migrations emit. */
|
|
105
|
+
declare type SnakeCase<S extends string> = S extends `${infer C}${infer Rest}`
|
|
106
|
+
? C extends Lowercase<C>
|
|
107
|
+
? `${C}${SnakeCase<Rest>}`
|
|
108
|
+
: `_${Lowercase<C>}${SnakeCase<Rest>}`
|
|
109
|
+
: S;
|
|
75
110
|
// ============================================================================
|
|
76
111
|
// Single attribute type inference
|
|
77
112
|
// ============================================================================
|
|
@@ -93,14 +128,23 @@ export type InferAttributes<TModel> = ResolveDefinition<TModel> extends infer TD
|
|
|
93
128
|
[K in DefinitionAttributeKeys<TDef>]: TDef['attributes'][K] extends { nullable: true }
|
|
94
129
|
? InferSingleAttributeType<TDef['attributes'][K]> | null
|
|
95
130
|
: InferSingleAttributeType<TDef['attributes'][K]>
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
&
|
|
102
|
-
|
|
103
|
-
|
|
131
|
+
}
|
|
132
|
+
// A column the model spells out is the authority on its own type; the
|
|
133
|
+
// trait / FK default only fills the gap. Without the Omit, a model that
|
|
134
|
+
// declares `created_at: { type: 'date' }` alongside `useTimestamps`
|
|
135
|
+
// intersected the two into `Date & string` — an uninhabited type.
|
|
136
|
+
& Omit<
|
|
137
|
+
{ [K in PrimaryKeyOf<TDef>]: number }
|
|
138
|
+
& (TDef['traits'] extends { useUuid: true } ? { uuid: string } : {})
|
|
139
|
+
& (TDef['traits'] extends { useTimestamps: true } ? { created_at: string; updated_at: string | null } : {})
|
|
140
|
+
& (TDef['traits'] extends { timestampable: true | object } ? { created_at: string; updated_at: string | null } : {})
|
|
141
|
+
& (TDef['traits'] extends { useSoftDeletes: true } ? { deleted_at: string | null } : {})
|
|
142
|
+
& (TDef['traits'] extends { softDeletable: true | object } ? { deleted_at: string | null } : {})
|
|
143
|
+
& (TDef['traits'] extends { useAuth: true | object } ? { two_factor_secret: string | null; public_key: string | null } : {})
|
|
144
|
+
& (TDef['traits'] extends { billable: true | object } ? { stripe_id: string | null } : {})
|
|
145
|
+
& { [K in BelongsToKeys<TDef>]: number },
|
|
146
|
+
DefinitionAttributeKeys<TDef>
|
|
147
|
+
>
|
|
104
148
|
: never;
|
|
105
149
|
/**
|
|
106
150
|
* The full row type for a model, including an index signature for trait-added
|
|
@@ -144,6 +188,11 @@ export type ModelCreateDataLoose<TModel> = InferFillableAttributes<TModel> & { [
|
|
|
144
188
|
* Infer only the fillable fields from a model definition or wrapped model.
|
|
145
189
|
* This is the type accepted by `create()`, `update()`, and `fill()`.
|
|
146
190
|
*
|
|
191
|
+
* Mirrors `InferAttributes`: a column declared `nullable: true` admits `null`.
|
|
192
|
+
* Columns that are `nullable` or carry a `default` are also OPTIONAL — the
|
|
193
|
+
* database supplies a value when the caller omits one, so requiring them at
|
|
194
|
+
* the call site rejected perfectly valid inserts.
|
|
195
|
+
*
|
|
147
196
|
* @example
|
|
148
197
|
* ```ts
|
|
149
198
|
* type UserFillable = InferFillableAttributes<typeof UserModel>
|
|
@@ -151,11 +200,25 @@ export type ModelCreateDataLoose<TModel> = InferFillableAttributes<TModel> & { [
|
|
|
151
200
|
* ```
|
|
152
201
|
*/
|
|
153
202
|
export type InferFillableAttributes<TModel> = ResolveDefinition<TModel> extends infer TDef extends InferableModelDefinition
|
|
154
|
-
?
|
|
155
|
-
[K in DefinitionAttributeKeys<TDef> as TDef['attributes'][K] extends { fillable: true } ? K : never]:
|
|
156
|
-
InferSingleAttributeType<TDef['attributes'][K]>
|
|
157
|
-
}
|
|
203
|
+
? FillableRequired<TDef> & FillableOptional<TDef>
|
|
158
204
|
: never;
|
|
205
|
+
/** Fillable keys the caller MUST supply — no `nullable`, no `default`. */
|
|
206
|
+
declare type FillableRequired<TDef extends InferableModelDefinition> = {
|
|
207
|
+
[K in DefinitionAttributeKeys<TDef> as TDef['attributes'][K] extends { fillable: true }
|
|
208
|
+
? TDef['attributes'][K] extends { nullable: true } | { default: unknown } ? never : K
|
|
209
|
+
: never]:
|
|
210
|
+
InferFillableType<TDef['attributes'][K]>
|
|
211
|
+
}
|
|
212
|
+
/** Fillable keys the database can fill in — `nullable` or `default`. */
|
|
213
|
+
declare type FillableOptional<TDef extends InferableModelDefinition> = {
|
|
214
|
+
[K in DefinitionAttributeKeys<TDef> as TDef['attributes'][K] extends { fillable: true }
|
|
215
|
+
? TDef['attributes'][K] extends { nullable: true } | { default: unknown } ? K : never
|
|
216
|
+
: never]?:
|
|
217
|
+
InferFillableType<TDef['attributes'][K]>
|
|
218
|
+
}
|
|
219
|
+
declare type InferFillableType<TAttr> = TAttr extends { nullable: true }
|
|
220
|
+
? InferSingleAttributeType<TAttr> | null
|
|
221
|
+
: InferSingleAttributeType<TAttr>;
|
|
159
222
|
/**
|
|
160
223
|
* Infer the primary key type from a model definition or wrapped model.
|
|
161
224
|
* Returns the literal string type of the primary key column name.
|
|
@@ -183,7 +246,9 @@ export type InferTableName<TModel> = ResolveDefinition<TModel> extends infer TDe
|
|
|
183
246
|
: never;
|
|
184
247
|
/**
|
|
185
248
|
* Infer all valid relation names from a model definition or wrapped model.
|
|
186
|
-
*
|
|
249
|
+
* Covers every relation kind `RelationCardinality` knows about: belongsTo,
|
|
250
|
+
* hasMany, hasOne, belongsToMany, hasOneThrough, hasManyThrough, and the
|
|
251
|
+
* polymorphic morphOne / morphMany / morphToMany / morphedByMany.
|
|
187
252
|
*
|
|
188
253
|
* @example
|
|
189
254
|
* ```ts
|
|
@@ -198,6 +263,10 @@ export type InferRelationNames<TModel> = ResolveDefinition<TModel> extends infer
|
|
|
198
263
|
| InferBelongsToManyNames<TDef>
|
|
199
264
|
| InferHasOneThroughNames<TDef>
|
|
200
265
|
| InferHasManyThroughNames<TDef>
|
|
266
|
+
| InferMorphOneNames<TDef>
|
|
267
|
+
| InferMorphManyNames<TDef>
|
|
268
|
+
| InferMorphToManyNames<TDef>
|
|
269
|
+
| InferMorphedByManyNames<TDef>
|
|
201
270
|
: never;
|
|
202
271
|
/**
|
|
203
272
|
* Infer column names that have numeric types from a model definition or wrapped model.
|
|
@@ -223,10 +292,18 @@ export type InferNumericColumns<TModel> = ResolveDefinition<TModel> extends infe
|
|
|
223
292
|
* type UserCols = InferColumnNames<typeof UserModel>
|
|
224
293
|
* // 'name' | 'email' | 'age' | 'role' | 'id' | 'uuid' | 'created_at' | 'updated_at'
|
|
225
294
|
* ```
|
|
295
|
+
*
|
|
296
|
+
* Kept in parity with the ORM layer's `ColumnName`: the primary key honors a
|
|
297
|
+
* custom `primaryKey` (a custom-pk model exposes THAT column, not a phantom
|
|
298
|
+
* `id`), belongsTo-implied foreign keys are included because the migration
|
|
299
|
+
* generator emits them, and every declared attribute is also valid in its
|
|
300
|
+
* snake_case column form.
|
|
226
301
|
*/
|
|
227
302
|
export type InferColumnNames<TModel> = ResolveDefinition<TModel> extends infer TDef extends InferableModelDefinition
|
|
228
303
|
? DefinitionAttributeKeys<TDef>
|
|
229
|
-
|
|
|
304
|
+
| SnakeCase<DefinitionAttributeKeys<TDef>>
|
|
305
|
+
| PrimaryKeyOf<TDef>
|
|
306
|
+
| BelongsToKeys<TDef>
|
|
230
307
|
| (TDef['traits'] extends { useUuid: true } ? 'uuid' : never)
|
|
231
308
|
| (TDef['traits'] extends { useTimestamps: true } ? 'created_at' | 'updated_at' : never)
|
|
232
309
|
| (TDef['traits'] extends { timestampable: true | object } ? 'created_at' | 'updated_at' : never)
|
|
@@ -303,25 +380,35 @@ export type InferPivotColumns<TModel, R extends string> = ResolveDefinition<TMod
|
|
|
303
380
|
: Record<string, unknown>
|
|
304
381
|
: Record<string, unknown>;
|
|
305
382
|
/**
|
|
306
|
-
* Relation names of one relation declaration.
|
|
307
|
-
*
|
|
308
|
-
*
|
|
383
|
+
* Relation names of one relation declaration. A bare string (`morphOne:
|
|
384
|
+
* 'Image'`) lowercases the model name; array form lowercases the (unwrapped)
|
|
385
|
+
* model name; record form uses the keys.
|
|
386
|
+
*
|
|
387
|
+
* Order matters. The bare-string case must precede the record case (a string
|
|
388
|
+
* would otherwise fall through to `never`), and the array case MUST precede
|
|
389
|
+
* the record case: a tuple also structurally matches `Readonly<Record<...>>`
|
|
309
390
|
* and would otherwise leak its own keys ('length', indices, ...) into the
|
|
310
391
|
* relation-name union.
|
|
311
392
|
*/
|
|
312
|
-
declare type RelationKeyOf<V> = V extends
|
|
313
|
-
?
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
:
|
|
393
|
+
declare type RelationKeyOf<V> = V extends string
|
|
394
|
+
? Lowercase<V>
|
|
395
|
+
: V extends readonly (infer E)[]
|
|
396
|
+
? E extends string ? Lowercase<E>
|
|
397
|
+
: E extends { model: infer M extends string } ? Lowercase<M>
|
|
398
|
+
: never
|
|
399
|
+
: V extends Readonly<Record<infer K, unknown>>
|
|
400
|
+
? K & string
|
|
401
|
+
: never;
|
|
319
402
|
declare type InferBelongsToNames<TDef> = TDef extends { belongsTo: infer V } ? RelationKeyOf<V> : never;
|
|
320
403
|
declare type InferHasManyNames<TDef> = TDef extends { hasMany: infer V } ? RelationKeyOf<V> : never;
|
|
321
404
|
declare type InferHasOneNames<TDef> = TDef extends { hasOne: infer V } ? RelationKeyOf<V> : never;
|
|
322
405
|
declare type InferBelongsToManyNames<TDef> = TDef extends { belongsToMany: infer V } ? RelationKeyOf<V> : never;
|
|
323
406
|
declare type InferHasOneThroughNames<TDef> = TDef extends { hasOneThrough: infer V } ? RelationKeyOf<V> : never;
|
|
324
407
|
declare type InferHasManyThroughNames<TDef> = TDef extends { hasManyThrough: infer V } ? RelationKeyOf<V> : never;
|
|
408
|
+
declare type InferMorphOneNames<TDef> = TDef extends { morphOne: infer V } ? RelationKeyOf<V> : never;
|
|
409
|
+
declare type InferMorphManyNames<TDef> = TDef extends { morphMany: infer V } ? RelationKeyOf<V> : never;
|
|
410
|
+
declare type InferMorphToManyNames<TDef> = TDef extends { morphToMany: infer V } ? RelationKeyOf<V> : never;
|
|
411
|
+
declare type InferMorphedByManyNames<TDef> = TDef extends { morphedByMany: infer V } ? RelationKeyOf<V> : never;
|
|
325
412
|
/**
|
|
326
413
|
* Determine the cardinality of a relation on a model.
|
|
327
414
|
* hasMany / belongsToMany / hasManyThrough / morphMany / morphToMany /
|
package/package.json
CHANGED