@bunyad/orm 0.1.0-alpha.0 → 0.2.0-beta.0
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 +3 -3
- package/dist/concerns.d.ts +2 -2
- package/dist/factory.d.ts +3 -3
- package/dist/model-events.d.ts +2 -2
- package/dist/model-events.js +1 -1
- package/dist/model-query.d.ts +55 -55
- package/dist/model-query.js +51 -51
- package/dist/model-strictness.d.ts +2 -3
- package/dist/model-strictness.js +2 -3
- package/dist/model.d.ts +106 -106
- package/dist/model.js +103 -103
- package/dist/orm-collection.d.ts +1 -1
- package/dist/orm-collection.js +1 -1
- package/dist/relations.d.ts +4 -4
- package/dist/relations.js +3 -3
- package/dist/scopes.d.ts +1 -2
- package/dist/scopes.js +1 -2
- package/package.json +3 -3
package/dist/model.js
CHANGED
|
@@ -355,7 +355,7 @@ export class Model {
|
|
|
355
355
|
/** When false, `save()` skips `created_at` / `updated_at`. */
|
|
356
356
|
static timestamps = true;
|
|
357
357
|
/**
|
|
358
|
-
*
|
|
358
|
+
* `$casts` property — prefer `static casts()` when adding enums / Attribute.
|
|
359
359
|
* May be a plain object or a method returning the map.
|
|
360
360
|
*/
|
|
361
361
|
static casts = {};
|
|
@@ -366,19 +366,19 @@ export class Model {
|
|
|
366
366
|
*/
|
|
367
367
|
static relations = {};
|
|
368
368
|
/**
|
|
369
|
-
*
|
|
369
|
+
* `$touches` — relation names whose related models get `touch()` after
|
|
370
370
|
* this model is saved (or soft-deleted). Honor `withoutTouching`.
|
|
371
371
|
*/
|
|
372
372
|
static touches = [];
|
|
373
|
-
/**
|
|
373
|
+
/** `$hidden`. */
|
|
374
374
|
static hidden = [];
|
|
375
|
-
/**
|
|
375
|
+
/** `$visible` allow-list (empty = all non-hidden). */
|
|
376
376
|
static visible = [];
|
|
377
|
-
/**
|
|
377
|
+
/** `$appends` — accessors included in `toArray()`. */
|
|
378
378
|
static appends = [];
|
|
379
|
-
/**
|
|
379
|
+
/** `$fillable`. */
|
|
380
380
|
static fillable = [];
|
|
381
|
-
/**
|
|
381
|
+
/** `$guarded` — default guard all until fillable is set. */
|
|
382
382
|
static guarded = ["*"];
|
|
383
383
|
/** Set in constructor / hydrate — avoid empty `{}` alloc before assign. */
|
|
384
384
|
#original;
|
|
@@ -395,7 +395,7 @@ export class Model {
|
|
|
395
395
|
#visible = null;
|
|
396
396
|
/** Per-instance connection override (`$model->setConnection()`). */
|
|
397
397
|
#connection;
|
|
398
|
-
/**
|
|
398
|
+
/** `$exists` — true after retrieve / successful insert. */
|
|
399
399
|
get exists() {
|
|
400
400
|
return this.#exists;
|
|
401
401
|
}
|
|
@@ -444,7 +444,7 @@ export class Model {
|
|
|
444
444
|
return out;
|
|
445
445
|
}
|
|
446
446
|
/**
|
|
447
|
-
*
|
|
447
|
+
* `getAttribute` — throws when `preventAccessingMissingAttributes` is on
|
|
448
448
|
* and the key was not retrieved / does not exist (relations exempt).
|
|
449
449
|
*/
|
|
450
450
|
getAttribute(key) {
|
|
@@ -478,18 +478,18 @@ export class Model {
|
|
|
478
478
|
}
|
|
479
479
|
return undefined;
|
|
480
480
|
}
|
|
481
|
-
/**
|
|
481
|
+
/** `isDirty`. */
|
|
482
482
|
isDirty(...attributes) {
|
|
483
483
|
const dirty = this.getDirty();
|
|
484
484
|
if (attributes.length === 0)
|
|
485
485
|
return Object.keys(dirty).length > 0;
|
|
486
486
|
return attributes.some((key) => Object.prototype.hasOwnProperty.call(dirty, key));
|
|
487
487
|
}
|
|
488
|
-
/**
|
|
488
|
+
/** `isClean`. */
|
|
489
489
|
isClean(...attributes) {
|
|
490
490
|
return !this.isDirty(...attributes);
|
|
491
491
|
}
|
|
492
|
-
/**
|
|
492
|
+
/** `getDirty`. */
|
|
493
493
|
getDirty() {
|
|
494
494
|
const dirty = {};
|
|
495
495
|
const original = this.#original ?? {};
|
|
@@ -505,11 +505,11 @@ export class Model {
|
|
|
505
505
|
return { ...original };
|
|
506
506
|
return original[key];
|
|
507
507
|
}
|
|
508
|
-
/**
|
|
508
|
+
/** `getChanges` — attributes changed by the last save. */
|
|
509
509
|
getChanges() {
|
|
510
510
|
return this.#changes ? { ...this.#changes } : {};
|
|
511
511
|
}
|
|
512
|
-
/**
|
|
512
|
+
/** `wasChanged`. */
|
|
513
513
|
wasChanged(...attributes) {
|
|
514
514
|
const changes = this.#changes;
|
|
515
515
|
if (!changes)
|
|
@@ -518,50 +518,50 @@ export class Model {
|
|
|
518
518
|
return Object.keys(changes).length > 0;
|
|
519
519
|
return attributes.some((key) => Object.prototype.hasOwnProperty.call(changes, key));
|
|
520
520
|
}
|
|
521
|
-
/**
|
|
521
|
+
/** `wasRecentlyCreated`. */
|
|
522
522
|
wasRecentlyCreated() {
|
|
523
523
|
return this.#wasRecentlyCreated;
|
|
524
524
|
}
|
|
525
|
-
/**
|
|
525
|
+
/** `append`. */
|
|
526
526
|
append(...attributes) {
|
|
527
527
|
const current = this.getAppends();
|
|
528
528
|
this.#appends = [...new Set([...current, ...attributes.flat()])];
|
|
529
529
|
return this;
|
|
530
530
|
}
|
|
531
|
-
/**
|
|
531
|
+
/** `setAppends`. */
|
|
532
532
|
setAppends(attributes) {
|
|
533
533
|
this.#appends = [...attributes];
|
|
534
534
|
return this;
|
|
535
535
|
}
|
|
536
|
-
/**
|
|
536
|
+
/** `getAppends`. */
|
|
537
537
|
getAppends() {
|
|
538
538
|
if (this.#appends)
|
|
539
539
|
return [...this.#appends];
|
|
540
540
|
return [...(this.constructor.appends ?? [])];
|
|
541
541
|
}
|
|
542
|
-
/**
|
|
542
|
+
/** `getHidden`. */
|
|
543
543
|
getHidden() {
|
|
544
544
|
if (this.#hidden)
|
|
545
545
|
return [...this.#hidden];
|
|
546
546
|
return [...(this.constructor.hidden ?? [])];
|
|
547
547
|
}
|
|
548
|
-
/**
|
|
548
|
+
/** `getVisible`. */
|
|
549
549
|
getVisible() {
|
|
550
550
|
if (this.#visible)
|
|
551
551
|
return [...this.#visible];
|
|
552
552
|
return [...(this.constructor.visible ?? [])];
|
|
553
553
|
}
|
|
554
|
-
/**
|
|
554
|
+
/** `setHidden`. */
|
|
555
555
|
setHidden(attributes) {
|
|
556
556
|
this.#hidden = [...attributes];
|
|
557
557
|
return this;
|
|
558
558
|
}
|
|
559
|
-
/**
|
|
559
|
+
/** `setVisible`. */
|
|
560
560
|
setVisible(attributes) {
|
|
561
561
|
this.#visible = [...attributes];
|
|
562
562
|
return this;
|
|
563
563
|
}
|
|
564
|
-
/**
|
|
564
|
+
/** `makeVisible` — show attributes for this instance. */
|
|
565
565
|
makeVisible(...attributes) {
|
|
566
566
|
const attrs = attributes.flat();
|
|
567
567
|
const hidden = new Set(this.getHidden());
|
|
@@ -574,7 +574,7 @@ export class Model {
|
|
|
574
574
|
}
|
|
575
575
|
return this;
|
|
576
576
|
}
|
|
577
|
-
/**
|
|
577
|
+
/** `makeHidden` — hide attributes for this instance. */
|
|
578
578
|
makeHidden(...attributes) {
|
|
579
579
|
const attrs = attributes.flat();
|
|
580
580
|
this.#hidden = [...new Set([...this.getHidden(), ...attrs])];
|
|
@@ -586,7 +586,7 @@ export class Model {
|
|
|
586
586
|
return this;
|
|
587
587
|
}
|
|
588
588
|
/**
|
|
589
|
-
* Run a callback without touching timestamps (
|
|
589
|
+
* Run a callback without touching timestamps (`Model::withoutTimestamps`).
|
|
590
590
|
*/
|
|
591
591
|
static async withoutTimestamps(callback) {
|
|
592
592
|
const previous = this.timestamps;
|
|
@@ -605,23 +605,23 @@ export class Model {
|
|
|
605
605
|
static isIgnoringTouch() {
|
|
606
606
|
return isIgnoringTouch(this);
|
|
607
607
|
}
|
|
608
|
-
/**
|
|
608
|
+
/** `Model::preventLazyLoading`. */
|
|
609
609
|
static preventLazyLoading(prevent = true) {
|
|
610
610
|
setPreventLazyLoading(prevent);
|
|
611
611
|
}
|
|
612
|
-
/**
|
|
612
|
+
/** `Model::preventSilentlyDiscardingAttributes`. */
|
|
613
613
|
static preventSilentlyDiscardingAttributes(prevent = true) {
|
|
614
614
|
setPreventSilentlyDiscardingAttributes(prevent);
|
|
615
615
|
}
|
|
616
|
-
/**
|
|
616
|
+
/** `Model::preventAccessingMissingAttributes`. */
|
|
617
617
|
static preventAccessingMissingAttributes(prevent = true) {
|
|
618
618
|
setPreventAccessingMissingAttributes(prevent);
|
|
619
619
|
}
|
|
620
|
-
/**
|
|
620
|
+
/** `Model::shouldBeStrict` — enable/disable the strictness trio. */
|
|
621
621
|
static shouldBeStrict(should = true) {
|
|
622
622
|
setShouldBeStrict(should);
|
|
623
623
|
}
|
|
624
|
-
/**
|
|
624
|
+
/** `Model::addGlobalScope`. */
|
|
625
625
|
static addGlobalScope(nameOrScope, scope) {
|
|
626
626
|
if (typeof nameOrScope === "function") {
|
|
627
627
|
registerGlobalScope(this, nameOrScope.name || `scope_${Date.now()}`, nameOrScope);
|
|
@@ -631,28 +631,28 @@ export class Model {
|
|
|
631
631
|
throw new Error("addGlobalScope requires a callback.");
|
|
632
632
|
registerGlobalScope(this, nameOrScope, scope);
|
|
633
633
|
}
|
|
634
|
-
/**
|
|
634
|
+
/** `Model::addGlobalScope` removal helper. */
|
|
635
635
|
static removeGlobalScope(name) {
|
|
636
636
|
unregisterGlobalScope(this, name);
|
|
637
637
|
}
|
|
638
638
|
/**
|
|
639
|
-
*
|
|
639
|
+
* `boot` — runs once per model class before first use.
|
|
640
640
|
* Prefer registering listeners in `booted()`.
|
|
641
641
|
*/
|
|
642
642
|
static boot() { }
|
|
643
643
|
/**
|
|
644
|
-
*
|
|
644
|
+
* `booted` — runs once after `boot`. Typical place for `static::created(...)`.
|
|
645
645
|
*/
|
|
646
646
|
static booted() { }
|
|
647
647
|
/** Ensure this model class has been booted. */
|
|
648
648
|
static bootIfNotBooted() {
|
|
649
649
|
bootIfNotBooted(this);
|
|
650
650
|
}
|
|
651
|
-
/**
|
|
651
|
+
/** `Model::observe`. */
|
|
652
652
|
static observe(observer) {
|
|
653
653
|
observeModel(this, observer);
|
|
654
654
|
}
|
|
655
|
-
/**
|
|
655
|
+
/** `Model::withoutEvents`. */
|
|
656
656
|
static withoutEvents(callback) {
|
|
657
657
|
return withoutModelEvents(this, callback);
|
|
658
658
|
}
|
|
@@ -779,7 +779,7 @@ export class Model {
|
|
|
779
779
|
static getConnection() {
|
|
780
780
|
return resolveConnection(this.connection);
|
|
781
781
|
}
|
|
782
|
-
/**
|
|
782
|
+
/** `$model->setConnection($name)`. */
|
|
783
783
|
setConnection(connection) {
|
|
784
784
|
this.#connection = connection;
|
|
785
785
|
return this;
|
|
@@ -799,7 +799,7 @@ export class Model {
|
|
|
799
799
|
return manager;
|
|
800
800
|
}
|
|
801
801
|
/**
|
|
802
|
-
*
|
|
802
|
+
* `Model::on($connection)` — same model, different named connection.
|
|
803
803
|
*/
|
|
804
804
|
static on(connection) {
|
|
805
805
|
return this.newQuery({ connection });
|
|
@@ -814,21 +814,21 @@ export class Model {
|
|
|
814
814
|
const query = new Ctor(this, options);
|
|
815
815
|
return withLocalScopeProxy(query);
|
|
816
816
|
}
|
|
817
|
-
/**
|
|
817
|
+
/** `withoutGlobalScopes()`. */
|
|
818
818
|
static withoutGlobalScopes(names) {
|
|
819
819
|
return this.newQuery({
|
|
820
820
|
withoutGlobalScopes: names ?? true,
|
|
821
821
|
});
|
|
822
822
|
}
|
|
823
|
-
/**
|
|
823
|
+
/** `withoutGlobalScope($name)`. */
|
|
824
824
|
static withoutGlobalScope(name) {
|
|
825
825
|
return this.newQuery({ withoutGlobalScopes: [name] });
|
|
826
826
|
}
|
|
827
|
-
/**
|
|
827
|
+
/** `Model::query()` — scoped `ModelQuery` (not a raw table builder). */
|
|
828
828
|
static query(options) {
|
|
829
829
|
return this.newQuery(options);
|
|
830
830
|
}
|
|
831
|
-
/**
|
|
831
|
+
/** `Model::find`. */
|
|
832
832
|
static find(id) {
|
|
833
833
|
this.bootIfNotBooted();
|
|
834
834
|
if (canFastFind(this)) {
|
|
@@ -839,12 +839,12 @@ export class Model {
|
|
|
839
839
|
.where(this.primaryKey, id)
|
|
840
840
|
.first();
|
|
841
841
|
}
|
|
842
|
-
/**
|
|
842
|
+
/** `getRouteKeyName()` — column used for implicit route binding. */
|
|
843
843
|
static getRouteKeyName() {
|
|
844
844
|
return this.primaryKey;
|
|
845
845
|
}
|
|
846
846
|
/**
|
|
847
|
-
*
|
|
847
|
+
* `resolveRouteBinding` — find by PK or custom `{param:column}` field.
|
|
848
848
|
*/
|
|
849
849
|
static resolveRouteBinding(value, field) {
|
|
850
850
|
const column = field ?? this.getRouteKeyName();
|
|
@@ -855,7 +855,7 @@ export class Model {
|
|
|
855
855
|
return this.newQuery().where(column, value).first();
|
|
856
856
|
}
|
|
857
857
|
/**
|
|
858
|
-
*
|
|
858
|
+
* `resolveSoftDeletableRouteBinding` — same as
|
|
859
859
|
* `resolveRouteBinding` but includes soft-deleted rows (`withTrashed()`).
|
|
860
860
|
* Used by the router when the route opts in via `withTrashed()`.
|
|
861
861
|
*/
|
|
@@ -885,20 +885,20 @@ export class Model {
|
|
|
885
885
|
model.#exists = true;
|
|
886
886
|
return model;
|
|
887
887
|
}
|
|
888
|
-
/**
|
|
888
|
+
/** `Model::findOrFail`. */
|
|
889
889
|
static async findOrFail(id) {
|
|
890
890
|
const model = await this.find(id);
|
|
891
891
|
if (!model)
|
|
892
892
|
throw new ModelNotFoundException();
|
|
893
893
|
return model;
|
|
894
894
|
}
|
|
895
|
-
/**
|
|
895
|
+
/** `Model::all`. */
|
|
896
896
|
static async all() {
|
|
897
897
|
this.bootIfNotBooted();
|
|
898
898
|
return this.newQuery().get();
|
|
899
899
|
}
|
|
900
900
|
/**
|
|
901
|
-
*
|
|
901
|
+
* `Model::get` — same as `query().get()` / `all()`.
|
|
902
902
|
* Typed helper for autocomplete; Proxy also forwards other terminals.
|
|
903
903
|
*/
|
|
904
904
|
static get() {
|
|
@@ -995,30 +995,30 @@ export class Model {
|
|
|
995
995
|
return q.whereDate(column, opOrValue);
|
|
996
996
|
return q.whereDate(column, String(opOrValue), value);
|
|
997
997
|
}
|
|
998
|
-
/**
|
|
998
|
+
/** `Model::whereNot(closure)`. */
|
|
999
999
|
static whereNot(callback) {
|
|
1000
1000
|
this.bootIfNotBooted();
|
|
1001
1001
|
return this.newQuery().whereNot(callback);
|
|
1002
1002
|
}
|
|
1003
|
-
/**
|
|
1003
|
+
/** `Model::orWhereNot(closure)`. */
|
|
1004
1004
|
static orWhereNot(callback) {
|
|
1005
1005
|
this.bootIfNotBooted();
|
|
1006
1006
|
return this.newQuery().orWhereNot(callback);
|
|
1007
1007
|
}
|
|
1008
|
-
/**
|
|
1008
|
+
/** `withTrashed()`. */
|
|
1009
1009
|
static withTrashed() {
|
|
1010
1010
|
this.bootIfNotBooted();
|
|
1011
1011
|
return this.newQuery({
|
|
1012
1012
|
withTrashed: true,
|
|
1013
1013
|
});
|
|
1014
1014
|
}
|
|
1015
|
-
/**
|
|
1015
|
+
/** `onlyTrashed()`. */
|
|
1016
1016
|
static onlyTrashed() {
|
|
1017
1017
|
return this.newQuery({
|
|
1018
1018
|
onlyTrashed: true,
|
|
1019
1019
|
});
|
|
1020
1020
|
}
|
|
1021
|
-
/**
|
|
1021
|
+
/** `withoutTrashed()`. */
|
|
1022
1022
|
static withoutTrashed() {
|
|
1023
1023
|
return this.newQuery({
|
|
1024
1024
|
withTrashed: false,
|
|
@@ -1035,27 +1035,27 @@ export class Model {
|
|
|
1035
1035
|
eagerLoad: normalizeWithRelations(relations),
|
|
1036
1036
|
});
|
|
1037
1037
|
}
|
|
1038
|
-
/**
|
|
1038
|
+
/** `Model::whereHas`. */
|
|
1039
1039
|
static whereHas(relation, callback) {
|
|
1040
1040
|
this.bootIfNotBooted();
|
|
1041
1041
|
return this.newQuery().whereHas(relation, callback);
|
|
1042
1042
|
}
|
|
1043
|
-
/**
|
|
1043
|
+
/** `Model::whereDoesntHave`. */
|
|
1044
1044
|
static whereDoesntHave(relation, callback) {
|
|
1045
1045
|
this.bootIfNotBooted();
|
|
1046
1046
|
return this.newQuery().whereDoesntHave(relation, callback);
|
|
1047
1047
|
}
|
|
1048
|
-
/**
|
|
1048
|
+
/** `Model::orWhereHas`. */
|
|
1049
1049
|
static orWhereHas(relation, callback) {
|
|
1050
1050
|
this.bootIfNotBooted();
|
|
1051
1051
|
return this.newQuery().orWhereHas(relation, callback);
|
|
1052
1052
|
}
|
|
1053
|
-
/**
|
|
1053
|
+
/** `Model::whereRelation`. */
|
|
1054
1054
|
static whereRelation(relation, column, opOrValue, value) {
|
|
1055
1055
|
this.bootIfNotBooted();
|
|
1056
1056
|
return this.newQuery().whereRelation(relation, column, opOrValue, value);
|
|
1057
1057
|
}
|
|
1058
|
-
/**
|
|
1058
|
+
/** `Model::orWhereRelation`. */
|
|
1059
1059
|
static orWhereRelation(relation, column, opOrValue, value) {
|
|
1060
1060
|
this.bootIfNotBooted();
|
|
1061
1061
|
return this.newQuery().orWhereRelation(relation, column, opOrValue, value);
|
|
@@ -1065,7 +1065,7 @@ export class Model {
|
|
|
1065
1065
|
this.bootIfNotBooted();
|
|
1066
1066
|
return this.newQuery().withCount(...relations);
|
|
1067
1067
|
}
|
|
1068
|
-
/**
|
|
1068
|
+
/** `Model::withSum`. */
|
|
1069
1069
|
static withSum(relation, column) {
|
|
1070
1070
|
this.bootIfNotBooted();
|
|
1071
1071
|
return this.newQuery().withSum(relation, column);
|
|
@@ -1110,40 +1110,40 @@ export class Model {
|
|
|
1110
1110
|
this.bootIfNotBooted();
|
|
1111
1111
|
return this.newQuery().whereKey(id);
|
|
1112
1112
|
}
|
|
1113
|
-
/**
|
|
1113
|
+
/** `Model::whereUuid`. */
|
|
1114
1114
|
static whereUuid(column, value) {
|
|
1115
1115
|
this.bootIfNotBooted();
|
|
1116
1116
|
return this.newQuery().whereUuid(column, value);
|
|
1117
1117
|
}
|
|
1118
|
-
/**
|
|
1118
|
+
/** `Model::whereUlid`. */
|
|
1119
1119
|
static whereUlid(column, value) {
|
|
1120
1120
|
this.bootIfNotBooted();
|
|
1121
1121
|
return this.newQuery().whereUlid(column, value);
|
|
1122
1122
|
}
|
|
1123
|
-
/**
|
|
1123
|
+
/** `Model::join`. */
|
|
1124
1124
|
static join(table, first, op, second) {
|
|
1125
1125
|
this.bootIfNotBooted();
|
|
1126
1126
|
return this.newQuery().join(table, first, op, second);
|
|
1127
1127
|
}
|
|
1128
|
-
/**
|
|
1128
|
+
/** `Model::leftJoin`. */
|
|
1129
1129
|
static leftJoin(table, first, op, second) {
|
|
1130
1130
|
this.bootIfNotBooted();
|
|
1131
1131
|
return this.newQuery().leftJoin(table, first, op, second);
|
|
1132
1132
|
}
|
|
1133
|
-
/**
|
|
1133
|
+
/** `Model::paginate`. */
|
|
1134
1134
|
static async paginate(perPage = 15, page, options = {}) {
|
|
1135
1135
|
return this.newQuery().paginate(perPage, page, options);
|
|
1136
1136
|
}
|
|
1137
|
-
/**
|
|
1137
|
+
/** `Model::cursorPaginate`. */
|
|
1138
1138
|
static async cursorPaginate(perPage = 15, cursor = null, options = {}) {
|
|
1139
1139
|
return this.newQuery().cursorPaginate(perPage, cursor, options);
|
|
1140
1140
|
}
|
|
1141
|
-
/**
|
|
1141
|
+
/** `Model::create` (respects `$fillable` / `$guarded`). */
|
|
1142
1142
|
static create(attributes) {
|
|
1143
1143
|
this.bootIfNotBooted();
|
|
1144
1144
|
return this.forceCreate(filterFillable(this, attributes));
|
|
1145
1145
|
}
|
|
1146
|
-
/**
|
|
1146
|
+
/** `Model::forceCreate` — insert every given attribute, ignoring `$fillable`. */
|
|
1147
1147
|
static forceCreate(useAttrs) {
|
|
1148
1148
|
this.bootIfNotBooted();
|
|
1149
1149
|
// Assign raw attributes (skip get-casts) so mutators like Attribute.set can run on save.
|
|
@@ -1176,7 +1176,7 @@ export class Model {
|
|
|
1176
1176
|
}
|
|
1177
1177
|
return after(saved);
|
|
1178
1178
|
}
|
|
1179
|
-
/**
|
|
1179
|
+
/** `firstOrNew`. */
|
|
1180
1180
|
static async firstOrNew(attributes, values = {}) {
|
|
1181
1181
|
let q = this.newQuery();
|
|
1182
1182
|
for (const [column, value] of Object.entries(attributes)) {
|
|
@@ -1187,7 +1187,7 @@ export class Model {
|
|
|
1187
1187
|
return existing;
|
|
1188
1188
|
return new this({ ...attributes, ...values });
|
|
1189
1189
|
}
|
|
1190
|
-
/**
|
|
1190
|
+
/** `firstOrCreate`. */
|
|
1191
1191
|
static async firstOrCreate(attributes, values = {}) {
|
|
1192
1192
|
let q = this.newQuery();
|
|
1193
1193
|
for (const [column, value] of Object.entries(attributes)) {
|
|
@@ -1198,7 +1198,7 @@ export class Model {
|
|
|
1198
1198
|
return existing;
|
|
1199
1199
|
return this.create({ ...attributes, ...values });
|
|
1200
1200
|
}
|
|
1201
|
-
/**
|
|
1201
|
+
/** `updateOrCreate`. */
|
|
1202
1202
|
static async updateOrCreate(attributes, values = {}) {
|
|
1203
1203
|
let q = this.newQuery();
|
|
1204
1204
|
for (const [column, value] of Object.entries(attributes)) {
|
|
@@ -1220,21 +1220,21 @@ export class Model {
|
|
|
1220
1220
|
return this.newQuery().insert(values);
|
|
1221
1221
|
}
|
|
1222
1222
|
/**
|
|
1223
|
-
*
|
|
1223
|
+
* `Model::upsert` — bulk insert-or-update on unique conflict.
|
|
1224
1224
|
* Delegates to `ModelQuery.upsert` (timestamps stamped when enabled).
|
|
1225
1225
|
*/
|
|
1226
1226
|
static async upsert(values, uniqueBy, update = null) {
|
|
1227
1227
|
this.bootIfNotBooted();
|
|
1228
1228
|
return this.newQuery().upsert(values, uniqueBy, update);
|
|
1229
1229
|
}
|
|
1230
|
-
/**
|
|
1230
|
+
/** `$model->fill($attributes)`. */
|
|
1231
1231
|
fill(attributes) {
|
|
1232
1232
|
const ctor = this.constructor;
|
|
1233
1233
|
const finalAttrs = filterFillable(ctor, attributes);
|
|
1234
1234
|
assignOwn(this, ctor.castAttributes(finalAttrs, "get"));
|
|
1235
1235
|
return this;
|
|
1236
1236
|
}
|
|
1237
|
-
/**
|
|
1237
|
+
/** `$model->update($attributes)`. */
|
|
1238
1238
|
async update(attributes) {
|
|
1239
1239
|
this.fill(attributes);
|
|
1240
1240
|
await this.save();
|
|
@@ -1441,16 +1441,16 @@ export class Model {
|
|
|
1441
1441
|
}
|
|
1442
1442
|
this.syncOriginal();
|
|
1443
1443
|
await fireModelEvent(this, "saved");
|
|
1444
|
-
//
|
|
1444
|
+
// finishSave → touchOwners (Relation.touch honors withoutTouching on related).
|
|
1445
1445
|
await this.touchOwners();
|
|
1446
1446
|
return this;
|
|
1447
1447
|
}
|
|
1448
|
-
/**
|
|
1448
|
+
/** `$model->saveQuietly()`. */
|
|
1449
1449
|
async saveQuietly() {
|
|
1450
1450
|
const ctor = this.constructor;
|
|
1451
1451
|
return ctor.withoutEvents(() => this.save());
|
|
1452
1452
|
}
|
|
1453
|
-
/**
|
|
1453
|
+
/** `$model->refresh()`. */
|
|
1454
1454
|
async refresh() {
|
|
1455
1455
|
const ctor = this.constructor;
|
|
1456
1456
|
const key = ctor.primaryKey;
|
|
@@ -1464,7 +1464,7 @@ export class Model {
|
|
|
1464
1464
|
return this;
|
|
1465
1465
|
}
|
|
1466
1466
|
/**
|
|
1467
|
-
*
|
|
1467
|
+
* Refresh under row lock (`lockForUpdate`).
|
|
1468
1468
|
* Reloads this instance from a locked select of the same primary key.
|
|
1469
1469
|
*/
|
|
1470
1470
|
async refreshForUpdate() {
|
|
@@ -1482,7 +1482,7 @@ export class Model {
|
|
|
1482
1482
|
}
|
|
1483
1483
|
return this;
|
|
1484
1484
|
}
|
|
1485
|
-
/**
|
|
1485
|
+
/** `$model->fresh()`. */
|
|
1486
1486
|
async fresh() {
|
|
1487
1487
|
const ctor = this.constructor;
|
|
1488
1488
|
const key = ctor.primaryKey;
|
|
@@ -1502,7 +1502,7 @@ export class Model {
|
|
|
1502
1502
|
await eagerLoadModels([this], missing);
|
|
1503
1503
|
return this;
|
|
1504
1504
|
}
|
|
1505
|
-
/**
|
|
1505
|
+
/** `$model->relationLoaded($key)`. */
|
|
1506
1506
|
relationLoaded(key) {
|
|
1507
1507
|
return Object.prototype.hasOwnProperty.call(this, key);
|
|
1508
1508
|
}
|
|
@@ -1526,14 +1526,14 @@ export class Model {
|
|
|
1526
1526
|
}
|
|
1527
1527
|
}
|
|
1528
1528
|
/**
|
|
1529
|
-
*
|
|
1529
|
+
* `$model->touches($relation)` — whether `$touches` lists this relation.
|
|
1530
1530
|
*/
|
|
1531
1531
|
touches(relation) {
|
|
1532
1532
|
const ctor = this.constructor;
|
|
1533
1533
|
return (ctor.touches ?? []).includes(relation);
|
|
1534
1534
|
}
|
|
1535
1535
|
/**
|
|
1536
|
-
*
|
|
1536
|
+
* `$model->touchOwners()` — touch each relation in `$touches`.
|
|
1537
1537
|
* Uses `relation.touch()` when available (BelongsTo / HasOne / HasMany);
|
|
1538
1538
|
* otherwise loads the related model and calls `touch()` on it.
|
|
1539
1539
|
*/
|
|
@@ -1556,7 +1556,7 @@ export class Model {
|
|
|
1556
1556
|
}
|
|
1557
1557
|
}
|
|
1558
1558
|
/**
|
|
1559
|
-
*
|
|
1559
|
+
* `$model->touch()` — bump `updated_at` (no-op while `withoutTouching`).
|
|
1560
1560
|
* Saving also runs `$touches` / `touchOwners()` for listed relations.
|
|
1561
1561
|
*/
|
|
1562
1562
|
async touch() {
|
|
@@ -1574,7 +1574,7 @@ export class Model {
|
|
|
1574
1574
|
return true;
|
|
1575
1575
|
}
|
|
1576
1576
|
/**
|
|
1577
|
-
* Relation query builder (`$model->product()`
|
|
1577
|
+
* Relation query builder (`$model->product()`).
|
|
1578
1578
|
*
|
|
1579
1579
|
* Define relations on `static relations` and declare the loaded property:
|
|
1580
1580
|
* `declare product: Product | null` — then use `model.product` after `with('product')`,
|
|
@@ -1605,7 +1605,7 @@ export class Model {
|
|
|
1605
1605
|
}
|
|
1606
1606
|
throw new Error(`Call to undefined relationship [${name}] on model [${ctor.name ?? "Model"}].`);
|
|
1607
1607
|
}
|
|
1608
|
-
/**
|
|
1608
|
+
/** `$model->replicate()`. */
|
|
1609
1609
|
replicate(except = []) {
|
|
1610
1610
|
const ctor = this.constructor;
|
|
1611
1611
|
ctor.bootIfNotBooted();
|
|
@@ -1618,7 +1618,7 @@ export class Model {
|
|
|
1618
1618
|
attrs[k] = v;
|
|
1619
1619
|
}
|
|
1620
1620
|
const copy = new ctor(attrs);
|
|
1621
|
-
// Fire sync-style; listeners may be async but replicate is sync
|
|
1621
|
+
// Fire sync-style; listeners may be async but replicate is sync.
|
|
1622
1622
|
void fireModelEvent(copy, "replicating");
|
|
1623
1623
|
return copy;
|
|
1624
1624
|
}
|
|
@@ -1633,7 +1633,7 @@ export class Model {
|
|
|
1633
1633
|
await fireModelEvent(this, "trashed");
|
|
1634
1634
|
return;
|
|
1635
1635
|
}
|
|
1636
|
-
//
|
|
1636
|
+
// delete(): touchOwners before performDeleteOnModel.
|
|
1637
1637
|
await this.touchOwners();
|
|
1638
1638
|
await this.#performForceDelete();
|
|
1639
1639
|
await fireModelEvent(this, "deleted");
|
|
@@ -1664,7 +1664,7 @@ export class Model {
|
|
|
1664
1664
|
await fireModelEvent(this, "forceDeleted");
|
|
1665
1665
|
await fireModelEvent(this, "deleted");
|
|
1666
1666
|
}
|
|
1667
|
-
/**
|
|
1667
|
+
/** `$model->deleteQuietly()`. */
|
|
1668
1668
|
async deleteQuietly() {
|
|
1669
1669
|
const ctor = this.constructor;
|
|
1670
1670
|
await ctor.withoutEvents(() => this.delete());
|
|
@@ -1705,7 +1705,7 @@ export class Model {
|
|
|
1705
1705
|
const value = this[col];
|
|
1706
1706
|
return value != null && value !== "";
|
|
1707
1707
|
}
|
|
1708
|
-
/**
|
|
1708
|
+
/** `$model->toArray()`. */
|
|
1709
1709
|
toArray() {
|
|
1710
1710
|
const ctor = this.constructor;
|
|
1711
1711
|
const hiddenList = this.getHidden();
|
|
@@ -1746,7 +1746,7 @@ export class Model {
|
|
|
1746
1746
|
}
|
|
1747
1747
|
return this[key];
|
|
1748
1748
|
}
|
|
1749
|
-
/**
|
|
1749
|
+
/** `$model->loadCount(...$relations)`. */
|
|
1750
1750
|
async loadCount(...relations) {
|
|
1751
1751
|
const names = relations.flat();
|
|
1752
1752
|
if (names.length === 0)
|
|
@@ -1758,7 +1758,7 @@ export class Model {
|
|
|
1758
1758
|
}
|
|
1759
1759
|
return this;
|
|
1760
1760
|
}
|
|
1761
|
-
/**
|
|
1761
|
+
/** `$model->loadSum($relation, $column)`. */
|
|
1762
1762
|
async loadSum(relation, column) {
|
|
1763
1763
|
const parsed = parseRelationAlias(relation);
|
|
1764
1764
|
const value = await aggregateRelation(this, parsed.relation, "sum", column);
|
|
@@ -1783,7 +1783,7 @@ export class Model {
|
|
|
1783
1783
|
this[parsed.alias ?? `${parsed.relation}_max_${column}`] = value;
|
|
1784
1784
|
return this;
|
|
1785
1785
|
}
|
|
1786
|
-
/**
|
|
1786
|
+
/** `$model->loadExists(...$relations)`. */
|
|
1787
1787
|
async loadExists(...relations) {
|
|
1788
1788
|
for (const relation of relations.flat()) {
|
|
1789
1789
|
const parsed = parseRelationAlias(relation);
|
|
@@ -1799,7 +1799,7 @@ export class Model {
|
|
|
1799
1799
|
toJson() {
|
|
1800
1800
|
return this.toJSON();
|
|
1801
1801
|
}
|
|
1802
|
-
/**
|
|
1802
|
+
/** `$model->increment($column, $amount)`. */
|
|
1803
1803
|
async increment(column, amount = 1) {
|
|
1804
1804
|
const row = this;
|
|
1805
1805
|
const current = Number(row[column] ?? 0);
|
|
@@ -1807,11 +1807,11 @@ export class Model {
|
|
|
1807
1807
|
await this.save();
|
|
1808
1808
|
return this;
|
|
1809
1809
|
}
|
|
1810
|
-
/**
|
|
1810
|
+
/** `$model->decrement($column, $amount)`. */
|
|
1811
1811
|
async decrement(column, amount = 1) {
|
|
1812
1812
|
return this.increment(column, -amount);
|
|
1813
1813
|
}
|
|
1814
|
-
/**
|
|
1814
|
+
/** `Model::destroy($ids)`. */
|
|
1815
1815
|
static async destroy(ids) {
|
|
1816
1816
|
const list = Array.isArray(ids) ? ids : [ids];
|
|
1817
1817
|
let n = 0;
|
|
@@ -1825,7 +1825,7 @@ export class Model {
|
|
|
1825
1825
|
return n;
|
|
1826
1826
|
}
|
|
1827
1827
|
/**
|
|
1828
|
-
*
|
|
1828
|
+
* `Model::forceDestroy($ids)` — permanent delete by key(s).
|
|
1829
1829
|
* Soft-delete models are found via `withTrashed()` so trashed rows are included.
|
|
1830
1830
|
*/
|
|
1831
1831
|
static async forceDestroy(ids) {
|
|
@@ -1842,18 +1842,18 @@ export class Model {
|
|
|
1842
1842
|
}
|
|
1843
1843
|
return n;
|
|
1844
1844
|
}
|
|
1845
|
-
/**
|
|
1845
|
+
/** `$this->hasMany(Related::class)`. */
|
|
1846
1846
|
hasMany(related, foreignKey, localKey) {
|
|
1847
1847
|
const key = foreignKey ?? `${singular(this.constructor.table)}_id`;
|
|
1848
1848
|
return new HasMany(this, related, key, localKey);
|
|
1849
1849
|
}
|
|
1850
|
-
/**
|
|
1850
|
+
/** `$this->hasOne(Related::class)`. */
|
|
1851
1851
|
hasOne(related, foreignKey, localKey) {
|
|
1852
1852
|
const key = foreignKey ?? `${singular(this.constructor.table)}_id`;
|
|
1853
1853
|
return new HasOne(this, related, key, localKey);
|
|
1854
1854
|
}
|
|
1855
1855
|
/**
|
|
1856
|
-
*
|
|
1856
|
+
* `$this->hasManyThrough(Related::class, Through::class)`.
|
|
1857
1857
|
* Parent → Through (firstKey) → Related (secondKey).
|
|
1858
1858
|
*/
|
|
1859
1859
|
hasManyThrough(related, through, firstKey, secondKey, localKey, secondLocalKey) {
|
|
@@ -1861,18 +1861,18 @@ export class Model {
|
|
|
1861
1861
|
return new HasManyThrough(this, related, through, firstKey ?? `${singular(parentCtor.table)}_id`, secondKey ?? `${singular(through.table)}_id`, localKey ?? parentCtor.primaryKey, secondLocalKey ?? through.primaryKey);
|
|
1862
1862
|
}
|
|
1863
1863
|
/**
|
|
1864
|
-
*
|
|
1864
|
+
* `$this->hasOneThrough(Related::class, Through::class)`.
|
|
1865
1865
|
*/
|
|
1866
1866
|
hasOneThrough(related, through, firstKey, secondKey, localKey, secondLocalKey) {
|
|
1867
1867
|
const parentCtor = this.constructor;
|
|
1868
1868
|
return new HasOneThrough(this, related, through, firstKey ?? `${singular(parentCtor.table)}_id`, secondKey ?? `${singular(through.table)}_id`, localKey ?? parentCtor.primaryKey, secondLocalKey ?? through.primaryKey);
|
|
1869
1869
|
}
|
|
1870
|
-
/**
|
|
1870
|
+
/** `$this->belongsTo(Related::class)`. */
|
|
1871
1871
|
belongsTo(related, foreignKey, ownerKey) {
|
|
1872
1872
|
const key = foreignKey ?? `${singular(related.table)}_id`;
|
|
1873
1873
|
return new BelongsTo(this, related, key, ownerKey);
|
|
1874
1874
|
}
|
|
1875
|
-
/**
|
|
1875
|
+
/** `$this->belongsToMany(Related::class, pivot)`. */
|
|
1876
1876
|
belongsToMany(related, table, foreignPivotKey, relatedPivotKey) {
|
|
1877
1877
|
const parent = this.constructor;
|
|
1878
1878
|
const pivot = table ??
|
|
@@ -1903,15 +1903,15 @@ export class Model {
|
|
|
1903
1903
|
: [name, primaryMorph].filter((value, index, all) => all.indexOf(value) === index);
|
|
1904
1904
|
return new MorphToMany(this, related, table, foreign, relatedKey, morphTypeColumn, morphTypes, options.pivotTenantKey, options.parentTenantKey ?? options.pivotTenantKey);
|
|
1905
1905
|
}
|
|
1906
|
-
/**
|
|
1906
|
+
/** `$this->morphMany(Related::class, name)`. */
|
|
1907
1907
|
morphMany(related, name, type, id, localKey) {
|
|
1908
1908
|
return new MorphMany(this, related, type ?? `${name}_type`, id ?? `${name}_id`, morphTypeFor(this.constructor), localKey);
|
|
1909
1909
|
}
|
|
1910
|
-
/**
|
|
1910
|
+
/** `$this->morphOne(Related::class, name)`. */
|
|
1911
1911
|
morphOne(related, name, type, id, localKey) {
|
|
1912
1912
|
return new MorphOne(this, related, type ?? `${name}_type`, id ?? `${name}_id`, morphTypeFor(this.constructor), localKey);
|
|
1913
1913
|
}
|
|
1914
|
-
/**
|
|
1914
|
+
/** `$this->morphTo($name)`. */
|
|
1915
1915
|
morphTo(name, type, id, ownerKey) {
|
|
1916
1916
|
return new MorphTo(this, type ?? `${name}_type`, id ?? `${name}_id`, ownerKey);
|
|
1917
1917
|
}
|