@bunnykit/orm 0.1.4 → 0.1.6
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 +420 -81
- package/dist/bin/bunny.js +133 -19
- package/dist/src/config/BunnyConfig.d.ts +28 -0
- package/dist/src/config/BunnyConfig.js +14 -0
- package/dist/src/connection/Connection.d.ts +20 -1
- package/dist/src/connection/Connection.js +80 -2
- package/dist/src/connection/ConnectionManager.d.ts +40 -0
- package/dist/src/connection/ConnectionManager.js +104 -0
- package/dist/src/connection/TenantContext.d.ts +15 -0
- package/dist/src/connection/TenantContext.js +22 -0
- package/dist/src/index.d.ts +7 -0
- package/dist/src/index.js +4 -0
- package/dist/src/model/BelongsToMany.js +9 -6
- package/dist/src/model/Model.d.ts +41 -0
- package/dist/src/model/Model.js +217 -18
- package/dist/src/model/ModelNotFoundError.d.ts +5 -0
- package/dist/src/model/ModelNotFoundError.js +13 -0
- package/dist/src/model/MorphRelations.js +10 -10
- package/dist/src/query/Builder.d.ts +85 -7
- package/dist/src/query/Builder.js +489 -68
- package/dist/src/query/grammars/Grammar.d.ts +19 -0
- package/dist/src/query/grammars/Grammar.js +47 -0
- package/dist/src/query/grammars/MySqlGrammar.d.ts +13 -0
- package/dist/src/query/grammars/MySqlGrammar.js +59 -0
- package/dist/src/query/grammars/PostgresGrammar.d.ts +13 -0
- package/dist/src/query/grammars/PostgresGrammar.js +62 -0
- package/dist/src/query/grammars/SQLiteGrammar.d.ts +14 -0
- package/dist/src/query/grammars/SQLiteGrammar.js +63 -0
- package/dist/src/schema/Schema.js +44 -26
- package/dist/src/typegen/TypeGenerator.js +4 -2
- package/dist/src/types/index.d.ts +10 -0
- package/package.json +1 -1
|
@@ -97,10 +97,13 @@ export declare class Model<T extends Record<string, any> = Record<string, any>>
|
|
|
97
97
|
$exists: boolean;
|
|
98
98
|
$relations: Record<string, any>;
|
|
99
99
|
$casts: Record<string, CastDefinition>;
|
|
100
|
+
$connection?: Connection;
|
|
100
101
|
constructor(attributes?: Partial<T>);
|
|
101
102
|
static getTable(): string;
|
|
102
103
|
static getConnection(): Connection;
|
|
103
104
|
static setConnection(connection: Connection): void;
|
|
105
|
+
static on<M extends typeof Model>(this: M, connection: string | Connection): Builder<InstanceType<M>>;
|
|
106
|
+
static forTenant<M extends typeof Model>(this: M, tenantId: string): Builder<InstanceType<M>>;
|
|
104
107
|
static query<M extends typeof Model>(this: M): Builder<InstanceType<M>>;
|
|
105
108
|
static addGlobalScope(name: string, scope: GlobalScope): void;
|
|
106
109
|
static removeGlobalScope(name: string): void;
|
|
@@ -109,12 +112,39 @@ export declare class Model<T extends Record<string, any> = Record<string, any>>
|
|
|
109
112
|
static shouldAutoGeneratePrimaryKey(): Promise<boolean>;
|
|
110
113
|
static create<M extends typeof Model>(this: M, attributes: Partial<InstanceType<M> extends Model<infer U> ? U : Record<string, any>>): Promise<InstanceType<M>>;
|
|
111
114
|
static find<M extends typeof Model>(this: M, id: any): Promise<InstanceType<M> | null>;
|
|
115
|
+
static findOrFail<M extends typeof Model>(this: M, id: any): Promise<InstanceType<M>>;
|
|
112
116
|
static first<M extends typeof Model>(this: M): Promise<InstanceType<M> | null>;
|
|
117
|
+
static firstOrFail<M extends typeof Model>(this: M): Promise<InstanceType<M>>;
|
|
118
|
+
static firstOrCreate<M extends typeof Model>(this: M, attributes?: Record<string, any>, values?: Record<string, any>): Promise<InstanceType<M>>;
|
|
119
|
+
static updateOrCreate<M extends typeof Model>(this: M, attributes: Record<string, any>, values?: Record<string, any>): Promise<InstanceType<M>>;
|
|
113
120
|
static where<M extends typeof Model>(this: M, column: string | Record<string, any>, operator?: string | any, value?: any): Builder<InstanceType<M>>;
|
|
121
|
+
static orderBy<M extends typeof Model>(this: M, column: string, direction?: "asc" | "desc"): Builder<InstanceType<M>>;
|
|
114
122
|
static whereIn<M extends typeof Model>(this: M, column: string, values: any[]): Builder<InstanceType<M>>;
|
|
115
123
|
static whereNull<M extends typeof Model>(this: M, column: string): Builder<InstanceType<M>>;
|
|
116
124
|
static whereNotNull<M extends typeof Model>(this: M, column: string): Builder<InstanceType<M>>;
|
|
117
125
|
static orWhere<M extends typeof Model>(this: M, column: string | Record<string, any>, operator?: string | any, value?: any): Builder<InstanceType<M>>;
|
|
126
|
+
static whereNot<M extends typeof Model>(this: M, column: string | Record<string, any>, value?: any): Builder<InstanceType<M>>;
|
|
127
|
+
static orWhereNot<M extends typeof Model>(this: M, column: string | Record<string, any>, value?: any): Builder<InstanceType<M>>;
|
|
128
|
+
static whereDate<M extends typeof Model>(this: M, column: string, operator?: string | any, value?: any): Builder<InstanceType<M>>;
|
|
129
|
+
static orWhereDate<M extends typeof Model>(this: M, column: string, operator?: string | any, value?: any): Builder<InstanceType<M>>;
|
|
130
|
+
static whereDay<M extends typeof Model>(this: M, column: string, operator?: string | any, value?: any): Builder<InstanceType<M>>;
|
|
131
|
+
static orWhereDay<M extends typeof Model>(this: M, column: string, operator?: string | any, value?: any): Builder<InstanceType<M>>;
|
|
132
|
+
static whereMonth<M extends typeof Model>(this: M, column: string, operator?: string | any, value?: any): Builder<InstanceType<M>>;
|
|
133
|
+
static orWhereMonth<M extends typeof Model>(this: M, column: string, operator?: string | any, value?: any): Builder<InstanceType<M>>;
|
|
134
|
+
static whereYear<M extends typeof Model>(this: M, column: string, operator?: string | any, value?: any): Builder<InstanceType<M>>;
|
|
135
|
+
static orWhereYear<M extends typeof Model>(this: M, column: string, operator?: string | any, value?: any): Builder<InstanceType<M>>;
|
|
136
|
+
static whereTime<M extends typeof Model>(this: M, column: string, operator?: string | any, value?: any): Builder<InstanceType<M>>;
|
|
137
|
+
static orWhereTime<M extends typeof Model>(this: M, column: string, operator?: string | any, value?: any): Builder<InstanceType<M>>;
|
|
138
|
+
static latest<M extends typeof Model>(this: M, column?: string): Builder<InstanceType<M>>;
|
|
139
|
+
static oldest<M extends typeof Model>(this: M, column?: string): Builder<InstanceType<M>>;
|
|
140
|
+
static when<M extends typeof Model>(this: M, condition: any, callback: (query: Builder<any>) => void | Builder<any>, defaultCallback?: (query: Builder<any>) => void | Builder<any>): Builder<InstanceType<M>>;
|
|
141
|
+
static unless<M extends typeof Model>(this: M, condition: any, callback: (query: Builder<any>) => void | Builder<any>, defaultCallback?: (query: Builder<any>) => void | Builder<any>): Builder<InstanceType<M>>;
|
|
142
|
+
static tap<M extends typeof Model>(this: M, callback: (query: Builder<any>) => void | Builder<any>): Builder<InstanceType<M>>;
|
|
143
|
+
static take<M extends typeof Model>(this: M, count: number): Builder<InstanceType<M>>;
|
|
144
|
+
static skip<M extends typeof Model>(this: M, count: number): Builder<InstanceType<M>>;
|
|
145
|
+
static inRandomOrder<M extends typeof Model>(this: M): Builder<InstanceType<M>>;
|
|
146
|
+
static lockForUpdate<M extends typeof Model>(this: M): Builder<InstanceType<M>>;
|
|
147
|
+
static sharedLock<M extends typeof Model>(this: M): Builder<InstanceType<M>>;
|
|
118
148
|
static with<M extends typeof Model>(this: M, ...relations: string[]): Builder<InstanceType<M>>;
|
|
119
149
|
static withTrashed<M extends typeof Model>(this: M): Builder<InstanceType<M>>;
|
|
120
150
|
static onlyTrashed<M extends typeof Model>(this: M): Builder<InstanceType<M>>;
|
|
@@ -131,9 +161,15 @@ export declare class Model<T extends Record<string, any> = Record<string, any>>
|
|
|
131
161
|
static withMax<M extends typeof Model>(this: M, relationName: string, column: string, alias?: string): Builder<InstanceType<M>>;
|
|
132
162
|
static all<M extends typeof Model>(this: M): Promise<InstanceType<M>[]>;
|
|
133
163
|
static paginate<M extends typeof Model>(this: M, perPage?: number, page?: number): Promise<import("../query/Builder.js").Paginator<InstanceType<M>>>;
|
|
164
|
+
static chunk<M extends typeof Model>(this: M, count: number, callback: (items: InstanceType<M>[]) => void | Promise<void>): Promise<void>;
|
|
165
|
+
static each<M extends typeof Model>(this: M, count: number, callback: (item: InstanceType<M>) => void | Promise<void>): Promise<void>;
|
|
166
|
+
static cursor<M extends typeof Model>(this: M): AsyncGenerator<InstanceType<M>>;
|
|
167
|
+
static lazy<M extends typeof Model>(this: M, count?: number): AsyncGenerator<InstanceType<M>>;
|
|
134
168
|
static eagerLoadRelations(models: Model[], relations: string[]): Promise<void>;
|
|
135
169
|
static eagerLoadRelation(models: Model[], relationName: string): Promise<void>;
|
|
136
170
|
fill(attributes: Partial<T>): this;
|
|
171
|
+
setConnection(connection: Connection): this;
|
|
172
|
+
getConnection(): Connection;
|
|
137
173
|
isFillable(key: string): boolean;
|
|
138
174
|
getAttribute<K extends keyof T>(key: K): T[K];
|
|
139
175
|
getAttribute(key: string): any;
|
|
@@ -147,6 +183,11 @@ export declare class Model<T extends Record<string, any> = Record<string, any>>
|
|
|
147
183
|
getDirty(): Partial<T>;
|
|
148
184
|
isDirty(): boolean;
|
|
149
185
|
save(): Promise<this>;
|
|
186
|
+
updateTimestamps(): void;
|
|
187
|
+
touch(): Promise<boolean>;
|
|
188
|
+
increment(column: string, amount?: number, extra?: Record<string, any>): Promise<this>;
|
|
189
|
+
decrement(column: string, amount?: number, extra?: Record<string, any>): Promise<this>;
|
|
190
|
+
load(...relations: string[]): Promise<this>;
|
|
150
191
|
delete(): Promise<boolean>;
|
|
151
192
|
restore(): Promise<boolean>;
|
|
152
193
|
forceDelete(): Promise<boolean>;
|
package/dist/src/model/Model.js
CHANGED
|
@@ -4,6 +4,9 @@ import { ObserverRegistry } from "./Observer.js";
|
|
|
4
4
|
import { MorphTo, MorphOne, MorphMany, MorphToMany } from "./MorphRelations.js";
|
|
5
5
|
import { BelongsToMany } from "./BelongsToMany.js";
|
|
6
6
|
import { Schema } from "../schema/Schema.js";
|
|
7
|
+
import { ModelNotFoundError } from "./ModelNotFoundError.js";
|
|
8
|
+
import { ConnectionManager } from "../connection/ConnectionManager.js";
|
|
9
|
+
import { TenantContext } from "../connection/TenantContext.js";
|
|
7
10
|
const globalScopes = new WeakMap();
|
|
8
11
|
function getGlobalScopes(model) {
|
|
9
12
|
const scopes = new Map();
|
|
@@ -31,7 +34,7 @@ export class Relation {
|
|
|
31
34
|
constructor(parent, related, foreignKey, localKey) {
|
|
32
35
|
this.parent = parent;
|
|
33
36
|
this.related = related;
|
|
34
|
-
this.builder = related.
|
|
37
|
+
this.builder = related.on(parent.getConnection());
|
|
35
38
|
this.foreignKey = foreignKey || this.defaultForeignKey();
|
|
36
39
|
this.localKey = localKey || related.primaryKey;
|
|
37
40
|
}
|
|
@@ -45,7 +48,7 @@ export class Relation {
|
|
|
45
48
|
return column.includes(".") ? column : `${this.related.getTable()}.${column}`;
|
|
46
49
|
}
|
|
47
50
|
newExistenceQuery(parentQuery, aggregate, callback) {
|
|
48
|
-
const query = this.related.
|
|
51
|
+
const query = this.related.on(parentQuery.connection).select(aggregate);
|
|
49
52
|
query.whereColumn(`${this.related.getTable()}.${this.foreignKey}`, "=", `${parentQuery.tableName}.${this.localKey}`);
|
|
50
53
|
if (callback)
|
|
51
54
|
callback(query);
|
|
@@ -73,7 +76,7 @@ export class HasMany extends Relation {
|
|
|
73
76
|
this.builder.where(this.foreignKey, parentValue);
|
|
74
77
|
}
|
|
75
78
|
addEagerConstraints(models) {
|
|
76
|
-
this.builder = this.related.
|
|
79
|
+
this.builder = this.related.on(this.parent.getConnection());
|
|
77
80
|
const keys = models.map((m) => m.getAttribute(this.localKey));
|
|
78
81
|
this.builder.whereIn(this.foreignKey, keys);
|
|
79
82
|
}
|
|
@@ -120,7 +123,7 @@ export class BelongsTo extends Relation {
|
|
|
120
123
|
this.builder.where(this.localKey, childValue);
|
|
121
124
|
}
|
|
122
125
|
addEagerConstraints(models) {
|
|
123
|
-
this.builder = this.related.
|
|
126
|
+
this.builder = this.related.on(this.parent.getConnection());
|
|
124
127
|
const keys = models.map((m) => m.getAttribute(this.foreignKey));
|
|
125
128
|
this.builder.whereIn(this.localKey, keys);
|
|
126
129
|
}
|
|
@@ -151,7 +154,7 @@ export class BelongsTo extends Relation {
|
|
|
151
154
|
return this.parent;
|
|
152
155
|
}
|
|
153
156
|
newExistenceQuery(parentQuery, aggregate, callback) {
|
|
154
|
-
const query = this.related.
|
|
157
|
+
const query = this.related.on(parentQuery.connection).select(aggregate);
|
|
155
158
|
query.whereColumn(`${this.related.getTable()}.${this.localKey}`, "=", `${parentQuery.tableName}.${this.foreignKey}`);
|
|
156
159
|
if (callback)
|
|
157
160
|
callback(query);
|
|
@@ -183,7 +186,7 @@ export class HasManyThrough extends Relation {
|
|
|
183
186
|
const throughTable = this.through.getTable();
|
|
184
187
|
const relatedTable = this.related.getTable();
|
|
185
188
|
const keys = models.map((m) => m.getAttribute(this.localKey));
|
|
186
|
-
this.builder = this.related.
|
|
189
|
+
this.builder = this.related.on(this.parent.getConnection());
|
|
187
190
|
this.builder.select(`${relatedTable}.*`, `${throughTable}.${this.firstKey}`);
|
|
188
191
|
this.builder.join(throughTable, `${throughTable}.${this.secondLocalKey}`, "=", `${relatedTable}.${this.secondKey}`);
|
|
189
192
|
this.builder.whereIn(`${throughTable}.${this.firstKey}`, keys);
|
|
@@ -211,7 +214,7 @@ export class HasManyThrough extends Relation {
|
|
|
211
214
|
newExistenceQuery(parentQuery, aggregate, callback) {
|
|
212
215
|
const throughTable = this.through.getTable();
|
|
213
216
|
const relatedTable = this.related.getTable();
|
|
214
|
-
const query = this.related.
|
|
217
|
+
const query = this.related.on(parentQuery.connection).select(aggregate);
|
|
215
218
|
query.join(throughTable, `${throughTable}.${this.secondLocalKey}`, "=", `${relatedTable}.${this.secondKey}`);
|
|
216
219
|
query.whereColumn(`${throughTable}.${this.firstKey}`, "=", `${parentQuery.tableName}.${this.localKey}`);
|
|
217
220
|
if (callback)
|
|
@@ -249,7 +252,7 @@ export class HasOne extends Relation {
|
|
|
249
252
|
this.builder.where(this.foreignKey, parentValue);
|
|
250
253
|
}
|
|
251
254
|
addEagerConstraints(models) {
|
|
252
|
-
this.builder = this.related.
|
|
255
|
+
this.builder = this.related.on(this.parent.getConnection());
|
|
253
256
|
const keys = models.map((m) => m.getAttribute(this.localKey));
|
|
254
257
|
this.builder.whereIn(this.foreignKey, keys);
|
|
255
258
|
}
|
|
@@ -292,6 +295,7 @@ export class Model {
|
|
|
292
295
|
$exists = false;
|
|
293
296
|
$relations = {};
|
|
294
297
|
$casts = {};
|
|
298
|
+
$connection;
|
|
295
299
|
constructor(attributes) {
|
|
296
300
|
const defaults = this.constructor.attributes;
|
|
297
301
|
if (Object.keys(defaults).length > 0) {
|
|
@@ -337,16 +341,35 @@ export class Model {
|
|
|
337
341
|
return this.table || snakeCase(this.name) + "s";
|
|
338
342
|
}
|
|
339
343
|
static getConnection() {
|
|
340
|
-
|
|
344
|
+
const tenantConnection = TenantContext.current()?.connection;
|
|
345
|
+
const ownConnection = Object.prototype.hasOwnProperty.call(this, "connection") ? this.connection : undefined;
|
|
346
|
+
const connection = ownConnection || tenantConnection || this.connection || ConnectionManager.getDefault();
|
|
347
|
+
if (!connection) {
|
|
341
348
|
throw new Error(`No connection set on model ${this.name}`);
|
|
342
349
|
}
|
|
343
|
-
return
|
|
350
|
+
return connection;
|
|
344
351
|
}
|
|
345
352
|
static setConnection(connection) {
|
|
346
353
|
this.connection = connection;
|
|
354
|
+
ConnectionManager.setDefault(connection);
|
|
355
|
+
}
|
|
356
|
+
static on(connection) {
|
|
357
|
+
const resolved = typeof connection === "string" ? ConnectionManager.require(connection) : connection;
|
|
358
|
+
const builder = new Builder(resolved, resolved.qualifyTable(this.getTable()));
|
|
359
|
+
builder.setModel(this);
|
|
360
|
+
this.applyGlobalScopes(builder);
|
|
361
|
+
return builder;
|
|
362
|
+
}
|
|
363
|
+
static forTenant(tenantId) {
|
|
364
|
+
const context = ConnectionManager.getResolvedTenant(tenantId);
|
|
365
|
+
if (!context) {
|
|
366
|
+
throw new Error(`Tenant "${tenantId}" has not been resolved. Use TenantContext.run() or await ConnectionManager.resolveTenant() first.`);
|
|
367
|
+
}
|
|
368
|
+
return this.on(context.connection);
|
|
347
369
|
}
|
|
348
370
|
static query() {
|
|
349
|
-
const
|
|
371
|
+
const connection = this.getConnection();
|
|
372
|
+
const builder = new Builder(connection, connection.qualifyTable(this.getTable()));
|
|
350
373
|
builder.setModel(this);
|
|
351
374
|
this.applyGlobalScopes(builder);
|
|
352
375
|
return builder;
|
|
@@ -397,12 +420,44 @@ export class Model {
|
|
|
397
420
|
static async find(id) {
|
|
398
421
|
return this.query().find(id, this.primaryKey);
|
|
399
422
|
}
|
|
423
|
+
static async findOrFail(id) {
|
|
424
|
+
const result = await this.find(id);
|
|
425
|
+
if (!result) {
|
|
426
|
+
throw new ModelNotFoundError(this.name, id);
|
|
427
|
+
}
|
|
428
|
+
return result;
|
|
429
|
+
}
|
|
400
430
|
static async first() {
|
|
401
431
|
return this.query().first();
|
|
402
432
|
}
|
|
433
|
+
static async firstOrFail() {
|
|
434
|
+
const result = await this.first();
|
|
435
|
+
if (!result) {
|
|
436
|
+
throw new ModelNotFoundError(this.name);
|
|
437
|
+
}
|
|
438
|
+
return result;
|
|
439
|
+
}
|
|
440
|
+
static async firstOrCreate(attributes = {}, values = {}) {
|
|
441
|
+
const found = await this.where(attributes).first();
|
|
442
|
+
if (found)
|
|
443
|
+
return found;
|
|
444
|
+
return this.create({ ...attributes, ...values });
|
|
445
|
+
}
|
|
446
|
+
static async updateOrCreate(attributes, values = {}) {
|
|
447
|
+
const found = await this.where(attributes).first();
|
|
448
|
+
if (found) {
|
|
449
|
+
found.fill(values);
|
|
450
|
+
await found.save();
|
|
451
|
+
return found;
|
|
452
|
+
}
|
|
453
|
+
return this.create({ ...attributes, ...values });
|
|
454
|
+
}
|
|
403
455
|
static where(column, operator, value) {
|
|
404
456
|
return this.query().where(column, operator, value);
|
|
405
457
|
}
|
|
458
|
+
static orderBy(column, direction) {
|
|
459
|
+
return this.query().orderBy(column, direction);
|
|
460
|
+
}
|
|
406
461
|
static whereIn(column, values) {
|
|
407
462
|
return this.query().whereIn(column, values);
|
|
408
463
|
}
|
|
@@ -415,6 +470,72 @@ export class Model {
|
|
|
415
470
|
static orWhere(column, operator, value) {
|
|
416
471
|
return this.query().orWhere(column, operator, value);
|
|
417
472
|
}
|
|
473
|
+
static whereNot(column, value) {
|
|
474
|
+
return this.query().whereNot(column, value);
|
|
475
|
+
}
|
|
476
|
+
static orWhereNot(column, value) {
|
|
477
|
+
return this.query().orWhereNot(column, value);
|
|
478
|
+
}
|
|
479
|
+
static whereDate(column, operator, value) {
|
|
480
|
+
return this.query().whereDate(column, operator, value);
|
|
481
|
+
}
|
|
482
|
+
static orWhereDate(column, operator, value) {
|
|
483
|
+
return this.query().orWhereDate(column, operator, value);
|
|
484
|
+
}
|
|
485
|
+
static whereDay(column, operator, value) {
|
|
486
|
+
return this.query().whereDay(column, operator, value);
|
|
487
|
+
}
|
|
488
|
+
static orWhereDay(column, operator, value) {
|
|
489
|
+
return this.query().orWhereDay(column, operator, value);
|
|
490
|
+
}
|
|
491
|
+
static whereMonth(column, operator, value) {
|
|
492
|
+
return this.query().whereMonth(column, operator, value);
|
|
493
|
+
}
|
|
494
|
+
static orWhereMonth(column, operator, value) {
|
|
495
|
+
return this.query().orWhereMonth(column, operator, value);
|
|
496
|
+
}
|
|
497
|
+
static whereYear(column, operator, value) {
|
|
498
|
+
return this.query().whereYear(column, operator, value);
|
|
499
|
+
}
|
|
500
|
+
static orWhereYear(column, operator, value) {
|
|
501
|
+
return this.query().orWhereYear(column, operator, value);
|
|
502
|
+
}
|
|
503
|
+
static whereTime(column, operator, value) {
|
|
504
|
+
return this.query().whereTime(column, operator, value);
|
|
505
|
+
}
|
|
506
|
+
static orWhereTime(column, operator, value) {
|
|
507
|
+
return this.query().orWhereTime(column, operator, value);
|
|
508
|
+
}
|
|
509
|
+
static latest(column) {
|
|
510
|
+
return this.query().latest(column);
|
|
511
|
+
}
|
|
512
|
+
static oldest(column) {
|
|
513
|
+
return this.query().oldest(column);
|
|
514
|
+
}
|
|
515
|
+
static when(condition, callback, defaultCallback) {
|
|
516
|
+
return this.query().when(condition, callback, defaultCallback);
|
|
517
|
+
}
|
|
518
|
+
static unless(condition, callback, defaultCallback) {
|
|
519
|
+
return this.query().unless(condition, callback, defaultCallback);
|
|
520
|
+
}
|
|
521
|
+
static tap(callback) {
|
|
522
|
+
return this.query().tap(callback);
|
|
523
|
+
}
|
|
524
|
+
static take(count) {
|
|
525
|
+
return this.query().take(count);
|
|
526
|
+
}
|
|
527
|
+
static skip(count) {
|
|
528
|
+
return this.query().skip(count);
|
|
529
|
+
}
|
|
530
|
+
static inRandomOrder() {
|
|
531
|
+
return this.query().inRandomOrder();
|
|
532
|
+
}
|
|
533
|
+
static lockForUpdate() {
|
|
534
|
+
return this.query().lockForUpdate();
|
|
535
|
+
}
|
|
536
|
+
static sharedLock() {
|
|
537
|
+
return this.query().sharedLock();
|
|
538
|
+
}
|
|
418
539
|
static with(...relations) {
|
|
419
540
|
return this.query().with(...relations);
|
|
420
541
|
}
|
|
@@ -463,6 +584,18 @@ export class Model {
|
|
|
463
584
|
static async paginate(perPage, page) {
|
|
464
585
|
return this.query().paginate(perPage, page);
|
|
465
586
|
}
|
|
587
|
+
static async chunk(count, callback) {
|
|
588
|
+
return this.query().chunk(count, callback);
|
|
589
|
+
}
|
|
590
|
+
static async each(count, callback) {
|
|
591
|
+
return this.query().each(count, callback);
|
|
592
|
+
}
|
|
593
|
+
static cursor() {
|
|
594
|
+
return this.query().cursor();
|
|
595
|
+
}
|
|
596
|
+
static lazy(count) {
|
|
597
|
+
return this.query().lazy(count);
|
|
598
|
+
}
|
|
466
599
|
static async eagerLoadRelations(models, relations) {
|
|
467
600
|
for (const relationName of relations) {
|
|
468
601
|
if (relationName.includes(".")) {
|
|
@@ -502,6 +635,13 @@ export class Model {
|
|
|
502
635
|
}
|
|
503
636
|
return this;
|
|
504
637
|
}
|
|
638
|
+
setConnection(connection) {
|
|
639
|
+
this.$connection = connection;
|
|
640
|
+
return this;
|
|
641
|
+
}
|
|
642
|
+
getConnection() {
|
|
643
|
+
return this.$connection || this.constructor.getConnection();
|
|
644
|
+
}
|
|
505
645
|
isFillable(key) {
|
|
506
646
|
const constructor = this.constructor;
|
|
507
647
|
if (constructor.fillable.length > 0) {
|
|
@@ -634,7 +774,8 @@ export class Model {
|
|
|
634
774
|
const dirty = this.getDirty();
|
|
635
775
|
if (Object.keys(dirty).length > 0) {
|
|
636
776
|
const pk = this.getAttribute(constructor.primaryKey);
|
|
637
|
-
|
|
777
|
+
const connection = this.getConnection();
|
|
778
|
+
await new Builder(connection, connection.qualifyTable(constructor.getTable()))
|
|
638
779
|
.where(constructor.primaryKey, pk)
|
|
639
780
|
.update(dirty);
|
|
640
781
|
}
|
|
@@ -657,11 +798,12 @@ export class Model {
|
|
|
657
798
|
const generated = crypto.randomUUID();
|
|
658
799
|
this.$attributes[primaryKey] = generated;
|
|
659
800
|
}
|
|
801
|
+
const connection = this.getConnection();
|
|
660
802
|
if (shouldGeneratePrimaryKey || primaryKeyValue !== null && primaryKeyValue !== undefined && primaryKeyValue !== "") {
|
|
661
|
-
await new Builder(
|
|
803
|
+
await new Builder(connection, connection.qualifyTable(constructor.getTable())).insert(this.$attributes);
|
|
662
804
|
}
|
|
663
805
|
else {
|
|
664
|
-
const result = await new Builder(
|
|
806
|
+
const result = await new Builder(connection, connection.qualifyTable(constructor.getTable())).insertGetId(this.$attributes);
|
|
665
807
|
if (result) {
|
|
666
808
|
this.$attributes[constructor.primaryKey] = result;
|
|
667
809
|
}
|
|
@@ -673,6 +815,59 @@ export class Model {
|
|
|
673
815
|
}
|
|
674
816
|
return this;
|
|
675
817
|
}
|
|
818
|
+
updateTimestamps() {
|
|
819
|
+
const constructor = this.constructor;
|
|
820
|
+
if (!constructor.timestamps)
|
|
821
|
+
return;
|
|
822
|
+
const now = this.freshTimestamp();
|
|
823
|
+
this.$attributes["updated_at"] = now;
|
|
824
|
+
if (!this.$exists) {
|
|
825
|
+
this.$attributes["created_at"] = now;
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
async touch() {
|
|
829
|
+
if (!this.$exists)
|
|
830
|
+
return false;
|
|
831
|
+
const constructor = this.constructor;
|
|
832
|
+
if (!constructor.timestamps)
|
|
833
|
+
return false;
|
|
834
|
+
const now = this.freshTimestamp();
|
|
835
|
+
const pk = this.getAttribute(constructor.primaryKey);
|
|
836
|
+
const connection = this.getConnection();
|
|
837
|
+
await new Builder(connection, connection.qualifyTable(constructor.getTable()))
|
|
838
|
+
.where(constructor.primaryKey, pk)
|
|
839
|
+
.update({ updated_at: now });
|
|
840
|
+
this.$attributes["updated_at"] = now;
|
|
841
|
+
this.$original = { ...this.$attributes };
|
|
842
|
+
return true;
|
|
843
|
+
}
|
|
844
|
+
async increment(column, amount = 1, extra = {}) {
|
|
845
|
+
const constructor = this.constructor;
|
|
846
|
+
const pk = this.getAttribute(constructor.primaryKey);
|
|
847
|
+
if (!pk)
|
|
848
|
+
return this;
|
|
849
|
+
const connection = this.getConnection();
|
|
850
|
+
const builder = new Builder(connection, connection.qualifyTable(constructor.getTable()))
|
|
851
|
+
.where(constructor.primaryKey, pk);
|
|
852
|
+
if (constructor.timestamps) {
|
|
853
|
+
extra = { ...extra, updated_at: this.freshTimestamp() };
|
|
854
|
+
}
|
|
855
|
+
await builder.increment(column, amount, extra);
|
|
856
|
+
this.$attributes[column] = (this.$attributes[column] || 0) + amount;
|
|
857
|
+
for (const [key, value] of Object.entries(extra)) {
|
|
858
|
+
this.$attributes[key] = value;
|
|
859
|
+
}
|
|
860
|
+
this.$original = { ...this.$attributes };
|
|
861
|
+
return this;
|
|
862
|
+
}
|
|
863
|
+
async decrement(column, amount = 1, extra = {}) {
|
|
864
|
+
return this.increment(column, -amount, extra);
|
|
865
|
+
}
|
|
866
|
+
async load(...relations) {
|
|
867
|
+
const constructor = this.constructor;
|
|
868
|
+
await constructor.eagerLoadRelations([this], relations);
|
|
869
|
+
return this;
|
|
870
|
+
}
|
|
676
871
|
async delete() {
|
|
677
872
|
const constructor = this.constructor;
|
|
678
873
|
await ObserverRegistry.dispatch("deleting", this);
|
|
@@ -681,14 +876,16 @@ export class Model {
|
|
|
681
876
|
return false;
|
|
682
877
|
if (constructor.softDeletes) {
|
|
683
878
|
const deletedAt = this.freshTimestamp();
|
|
684
|
-
|
|
879
|
+
const connection = this.getConnection();
|
|
880
|
+
await new Builder(connection, connection.qualifyTable(constructor.getTable()))
|
|
685
881
|
.where(constructor.primaryKey, pk)
|
|
686
882
|
.update({ [constructor.deletedAtColumn]: deletedAt });
|
|
687
883
|
this.$attributes[constructor.deletedAtColumn] = deletedAt;
|
|
688
884
|
this.$original = { ...this.$attributes };
|
|
689
885
|
}
|
|
690
886
|
else {
|
|
691
|
-
|
|
887
|
+
const connection = this.getConnection();
|
|
888
|
+
await new Builder(connection, connection.qualifyTable(constructor.getTable()))
|
|
692
889
|
.where(constructor.primaryKey, pk)
|
|
693
890
|
.delete();
|
|
694
891
|
this.$exists = false;
|
|
@@ -703,7 +900,8 @@ export class Model {
|
|
|
703
900
|
const pk = this.getAttribute(constructor.primaryKey);
|
|
704
901
|
if (!pk)
|
|
705
902
|
return false;
|
|
706
|
-
|
|
903
|
+
const connection = this.getConnection();
|
|
904
|
+
await new Builder(connection, connection.qualifyTable(constructor.getTable()))
|
|
707
905
|
.where(constructor.primaryKey, pk)
|
|
708
906
|
.update({ [constructor.deletedAtColumn]: null });
|
|
709
907
|
this.$attributes[constructor.deletedAtColumn] = null;
|
|
@@ -716,7 +914,8 @@ export class Model {
|
|
|
716
914
|
const pk = this.getAttribute(constructor.primaryKey);
|
|
717
915
|
if (!pk)
|
|
718
916
|
return false;
|
|
719
|
-
|
|
917
|
+
const connection = this.getConnection();
|
|
918
|
+
await new Builder(connection, connection.qualifyTable(constructor.getTable()))
|
|
720
919
|
.where(constructor.primaryKey, pk)
|
|
721
920
|
.delete();
|
|
722
921
|
this.$exists = false;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export class ModelNotFoundError extends Error {
|
|
2
|
+
modelName;
|
|
3
|
+
identifiers;
|
|
4
|
+
constructor(modelName, identifiers) {
|
|
5
|
+
const msg = identifiers !== undefined
|
|
6
|
+
? `No query results for model [${modelName}] ${JSON.stringify(identifiers)}`
|
|
7
|
+
: `No query results for model [${modelName}]`;
|
|
8
|
+
super(msg);
|
|
9
|
+
this.name = "ModelNotFoundError";
|
|
10
|
+
this.modelName = modelName;
|
|
11
|
+
this.identifiers = identifiers;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -31,7 +31,7 @@ export class MorphTo {
|
|
|
31
31
|
if (!Related) {
|
|
32
32
|
throw new Error(`No morph mapping found for type: ${type}. Register it with MorphMap.register() or pass a typeMap.`);
|
|
33
33
|
}
|
|
34
|
-
return Related.find(id);
|
|
34
|
+
return Related.on(this.parent.getConnection()).find(id);
|
|
35
35
|
}
|
|
36
36
|
addEagerConstraints(models) {
|
|
37
37
|
// MorphTo eager loading is handled separately in getEager
|
|
@@ -83,7 +83,7 @@ export class MorphOne {
|
|
|
83
83
|
this.typeColumn = typeColumn || `${name}_type`;
|
|
84
84
|
this.idColumn = idColumn || `${name}_id`;
|
|
85
85
|
this.localKey = localKey || parent.constructor.primaryKey;
|
|
86
|
-
this.builder = related.
|
|
86
|
+
this.builder = related.on(parent.getConnection());
|
|
87
87
|
this.builder.where(this.typeColumn, this.getMorphType());
|
|
88
88
|
this.builder.where(this.idColumn, this.parent.getAttribute(this.localKey));
|
|
89
89
|
}
|
|
@@ -94,7 +94,7 @@ export class MorphOne {
|
|
|
94
94
|
return this.builder;
|
|
95
95
|
}
|
|
96
96
|
addEagerConstraints(models) {
|
|
97
|
-
this.builder = this.related.
|
|
97
|
+
this.builder = this.related.on(this.parent.getConnection());
|
|
98
98
|
const keys = models.map((m) => m.getAttribute(this.localKey));
|
|
99
99
|
this.builder.whereIn(this.idColumn, keys);
|
|
100
100
|
this.builder.where(this.typeColumn, this.getMorphType());
|
|
@@ -120,7 +120,7 @@ export class MorphOne {
|
|
|
120
120
|
return column.includes(".") ? column : `${this.related.getTable()}.${column}`;
|
|
121
121
|
}
|
|
122
122
|
newExistenceQuery(parentTable, aggregate, callback) {
|
|
123
|
-
const query = this.related.
|
|
123
|
+
const query = this.related.on(this.parent.getConnection()).select(aggregate);
|
|
124
124
|
query.whereColumn(`${this.related.getTable()}.${this.idColumn}`, "=", `${parentTable}.${this.localKey}`);
|
|
125
125
|
query.where(`${this.related.getTable()}.${this.typeColumn}`, this.getMorphType());
|
|
126
126
|
if (callback)
|
|
@@ -152,7 +152,7 @@ export class MorphMany {
|
|
|
152
152
|
this.typeColumn = typeColumn || `${name}_type`;
|
|
153
153
|
this.idColumn = idColumn || `${name}_id`;
|
|
154
154
|
this.localKey = localKey || parent.constructor.primaryKey;
|
|
155
|
-
this.builder = related.
|
|
155
|
+
this.builder = related.on(parent.getConnection());
|
|
156
156
|
this.builder.where(this.typeColumn, this.getMorphType());
|
|
157
157
|
this.builder.where(this.idColumn, this.parent.getAttribute(this.localKey));
|
|
158
158
|
}
|
|
@@ -163,7 +163,7 @@ export class MorphMany {
|
|
|
163
163
|
return this.builder;
|
|
164
164
|
}
|
|
165
165
|
addEagerConstraints(models) {
|
|
166
|
-
this.builder = this.related.
|
|
166
|
+
this.builder = this.related.on(this.parent.getConnection());
|
|
167
167
|
const keys = models.map((m) => m.getAttribute(this.localKey));
|
|
168
168
|
this.builder.whereIn(this.idColumn, keys);
|
|
169
169
|
this.builder.where(this.typeColumn, this.getMorphType());
|
|
@@ -191,7 +191,7 @@ export class MorphMany {
|
|
|
191
191
|
return column.includes(".") ? column : `${this.related.getTable()}.${column}`;
|
|
192
192
|
}
|
|
193
193
|
newExistenceQuery(parentTable, aggregate, callback) {
|
|
194
|
-
const query = this.related.
|
|
194
|
+
const query = this.related.on(this.parent.getConnection()).select(aggregate);
|
|
195
195
|
query.whereColumn(`${this.related.getTable()}.${this.idColumn}`, "=", `${parentTable}.${this.localKey}`);
|
|
196
196
|
query.where(`${this.related.getTable()}.${this.typeColumn}`, this.getMorphType());
|
|
197
197
|
if (callback)
|
|
@@ -229,7 +229,7 @@ export class MorphToMany {
|
|
|
229
229
|
this.morphType = morphType || parent.constructor.morphName || parent.constructor.name;
|
|
230
230
|
this.foreignPivotKey = foreignPivotKey || `${snakeCase(name)}_id`;
|
|
231
231
|
this.relatedPivotKey = relatedPivotKey || `${snakeCase(related.name)}_id`;
|
|
232
|
-
this.builder = related.
|
|
232
|
+
this.builder = related.on(parent.getConnection());
|
|
233
233
|
this.addConstraints();
|
|
234
234
|
}
|
|
235
235
|
addConstraints() {
|
|
@@ -245,7 +245,7 @@ export class MorphToMany {
|
|
|
245
245
|
addEagerConstraints(models) {
|
|
246
246
|
const keys = models.map((m) => m.getAttribute(this.parentKey));
|
|
247
247
|
const relatedTable = this.related.getTable();
|
|
248
|
-
this.builder = this.related.
|
|
248
|
+
this.builder = this.related.on(this.parent.getConnection());
|
|
249
249
|
this.builder.select(`${relatedTable}.*`, `${this.table}.${this.foreignPivotKey}`);
|
|
250
250
|
this.builder.join(this.table, `${this.table}.${this.relatedPivotKey}`, "=", `${relatedTable}.${this.relatedKey}`);
|
|
251
251
|
this.builder.whereIn(`${this.table}.${this.foreignPivotKey}`, keys);
|
|
@@ -276,7 +276,7 @@ export class MorphToMany {
|
|
|
276
276
|
}
|
|
277
277
|
newExistenceQuery(parentTable, aggregate, callback) {
|
|
278
278
|
const relatedTable = this.related.getTable();
|
|
279
|
-
const query = this.related.
|
|
279
|
+
const query = this.related.on(this.parent.getConnection()).select(aggregate);
|
|
280
280
|
query.join(this.table, `${this.table}.${this.relatedPivotKey}`, "=", `${relatedTable}.${this.relatedKey}`);
|
|
281
281
|
query.whereColumn(`${this.table}.${this.foreignPivotKey}`, "=", `${parentTable}.${this.parentKey}`);
|
|
282
282
|
query.where(`${this.table}.${this.name}_type`, this.morphType);
|