@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.
Files changed (32) hide show
  1. package/README.md +420 -81
  2. package/dist/bin/bunny.js +133 -19
  3. package/dist/src/config/BunnyConfig.d.ts +28 -0
  4. package/dist/src/config/BunnyConfig.js +14 -0
  5. package/dist/src/connection/Connection.d.ts +20 -1
  6. package/dist/src/connection/Connection.js +80 -2
  7. package/dist/src/connection/ConnectionManager.d.ts +40 -0
  8. package/dist/src/connection/ConnectionManager.js +104 -0
  9. package/dist/src/connection/TenantContext.d.ts +15 -0
  10. package/dist/src/connection/TenantContext.js +22 -0
  11. package/dist/src/index.d.ts +7 -0
  12. package/dist/src/index.js +4 -0
  13. package/dist/src/model/BelongsToMany.js +9 -6
  14. package/dist/src/model/Model.d.ts +41 -0
  15. package/dist/src/model/Model.js +217 -18
  16. package/dist/src/model/ModelNotFoundError.d.ts +5 -0
  17. package/dist/src/model/ModelNotFoundError.js +13 -0
  18. package/dist/src/model/MorphRelations.js +10 -10
  19. package/dist/src/query/Builder.d.ts +85 -7
  20. package/dist/src/query/Builder.js +489 -68
  21. package/dist/src/query/grammars/Grammar.d.ts +19 -0
  22. package/dist/src/query/grammars/Grammar.js +47 -0
  23. package/dist/src/query/grammars/MySqlGrammar.d.ts +13 -0
  24. package/dist/src/query/grammars/MySqlGrammar.js +59 -0
  25. package/dist/src/query/grammars/PostgresGrammar.d.ts +13 -0
  26. package/dist/src/query/grammars/PostgresGrammar.js +62 -0
  27. package/dist/src/query/grammars/SQLiteGrammar.d.ts +14 -0
  28. package/dist/src/query/grammars/SQLiteGrammar.js +63 -0
  29. package/dist/src/schema/Schema.js +44 -26
  30. package/dist/src/typegen/TypeGenerator.js +4 -2
  31. package/dist/src/types/index.d.ts +10 -0
  32. 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>;
@@ -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.query();
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.query().select(aggregate);
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.query();
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.query();
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.query().select(aggregate);
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.query();
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.query().select(aggregate);
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.query();
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
- if (!this.connection) {
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 this.connection;
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 builder = new Builder(this.getConnection(), this.getTable());
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
- await new Builder(constructor.getConnection(), constructor.getTable())
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(constructor.getConnection(), constructor.getTable()).insert(this.$attributes);
803
+ await new Builder(connection, connection.qualifyTable(constructor.getTable())).insert(this.$attributes);
662
804
  }
663
805
  else {
664
- const result = await new Builder(constructor.getConnection(), constructor.getTable()).insertGetId(this.$attributes);
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
- await new Builder(constructor.getConnection(), constructor.getTable())
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
- await new Builder(constructor.getConnection(), constructor.getTable())
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
- await new Builder(constructor.getConnection(), constructor.getTable())
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
- await new Builder(constructor.getConnection(), constructor.getTable())
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,5 @@
1
+ export declare class ModelNotFoundError extends Error {
2
+ modelName: string;
3
+ identifiers?: any;
4
+ constructor(modelName: string, identifiers?: any);
5
+ }
@@ -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.query();
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.query();
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.query().select(aggregate);
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.query();
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.query();
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.query().select(aggregate);
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.query();
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.query();
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.query().select(aggregate);
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);