vasuzex 2.3.6 → 2.3.8
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.
|
@@ -34,7 +34,10 @@ export class Model extends GuruORMModel {
|
|
|
34
34
|
|
|
35
35
|
// Boot tracking
|
|
36
36
|
static booted = false;
|
|
37
|
-
|
|
37
|
+
// NOTE: Do NOT re-declare globalScopes here.
|
|
38
|
+
// GuruORM already initialises it as `new Map()` on the base Model class.
|
|
39
|
+
// Overriding with `{}` would break applyScopes() → getGlobalScopes() which
|
|
40
|
+
// calls map.get() — crashing any model that registers a global scope.
|
|
38
41
|
|
|
39
42
|
// Event dispatcher
|
|
40
43
|
static dispatcher = null;
|
|
@@ -140,15 +143,15 @@ export class Model extends GuruORMModel {
|
|
|
140
143
|
}
|
|
141
144
|
|
|
142
145
|
/**
|
|
143
|
-
* Set attribute with mutator support
|
|
146
|
+
* Set attribute with mutator support.
|
|
147
|
+
* Delegates accessor lookup to GuruORM's cached getMutator().
|
|
144
148
|
*/
|
|
145
149
|
setAttribute(key, value) {
|
|
146
150
|
// Skip mutators when hydrating from database
|
|
147
151
|
if (!this.isHydrating) {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
const result = this[mutator](value);
|
|
152
|
+
const mutator = this.getMutator(key); // cached in GuruORM core
|
|
153
|
+
if (mutator !== null) {
|
|
154
|
+
const result = mutator.call(this, value);
|
|
152
155
|
// If mutator returns a promise, store it for later resolution
|
|
153
156
|
if (result instanceof Promise) {
|
|
154
157
|
this.pendingMutators.push(result);
|
|
@@ -169,25 +172,21 @@ export class Model extends GuruORMModel {
|
|
|
169
172
|
}
|
|
170
173
|
|
|
171
174
|
/**
|
|
172
|
-
* Get attribute with accessor support and lazy loading
|
|
173
|
-
*
|
|
175
|
+
* Get attribute with accessor support and lazy loading.
|
|
176
|
+
* Delegates accessor lookup to GuruORM's cached getAccessor().
|
|
174
177
|
*/
|
|
175
178
|
getAttribute(key) {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
return this[accessor](this.attributes[key]);
|
|
179
|
+
const accessor = this.getAccessor(key); // cached in GuruORM core
|
|
180
|
+
if (accessor !== null) {
|
|
181
|
+
return accessor.call(this, this.attributes[key]);
|
|
180
182
|
}
|
|
181
183
|
|
|
182
|
-
//
|
|
184
|
+
// Safety: appended (computed) attributes without an accessor return null
|
|
183
185
|
if (this.constructor.appends.includes(key)) {
|
|
184
|
-
return
|
|
186
|
+
return null;
|
|
185
187
|
}
|
|
186
188
|
|
|
187
|
-
// Delegate to GuruORM's getAttribute for
|
|
188
|
-
// - Lazy loading of relationships
|
|
189
|
-
// - Loaded relations
|
|
190
|
-
// - Attributes with casting
|
|
189
|
+
// Delegate to GuruORM's getAttribute for lazy loading, relations, and casts
|
|
191
190
|
return super.getAttribute(key);
|
|
192
191
|
}
|
|
193
192
|
|
|
@@ -755,20 +754,10 @@ export class Model extends GuruORMModel {
|
|
|
755
754
|
static async find(id) {
|
|
756
755
|
try {
|
|
757
756
|
const pk = this.primaryKey || 'id';
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
//
|
|
761
|
-
|
|
762
|
-
query = query.whereNull(this.deletedAt);
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
const result = await query.first();
|
|
766
|
-
|
|
767
|
-
if (!result) {
|
|
768
|
-
return null;
|
|
769
|
-
}
|
|
770
|
-
|
|
771
|
-
return this.newFromBuilder(result);
|
|
757
|
+
// Note: this.where() calls this.query() which already applies the soft-delete
|
|
758
|
+
// scope via whereNull(qualifiedColumn). Do NOT add whereNull again here.
|
|
759
|
+
// GuruORM Builder.first() returns a hydrated model instance (or null) directly.
|
|
760
|
+
return await this.where(pk, id).first();
|
|
772
761
|
} catch (error) {
|
|
773
762
|
// Log database error if logger is available
|
|
774
763
|
if (this.logger) {
|
|
@@ -797,35 +786,19 @@ export class Model extends GuruORMModel {
|
|
|
797
786
|
* Get all records (override GuruORM's all)
|
|
798
787
|
*/
|
|
799
788
|
static async all() {
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
//
|
|
803
|
-
|
|
804
|
-
query = query.whereNull(this.deletedAt);
|
|
805
|
-
}
|
|
806
|
-
|
|
807
|
-
const results = await query.get();
|
|
808
|
-
return results.map(result => this.newFromBuilder(result));
|
|
789
|
+
// query() already applies the soft-delete scope - no duplicate whereNull needed.
|
|
790
|
+
// GuruORM Builder.get() returns a Collection of hydrated model instances.
|
|
791
|
+
// Spread into a plain Array to maintain the same return type as before.
|
|
792
|
+
return [...await this.query().get()];
|
|
809
793
|
}
|
|
810
794
|
|
|
811
795
|
/**
|
|
812
796
|
* Get first record
|
|
813
797
|
*/
|
|
814
798
|
static async first() {
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
if (this.softDeletes) {
|
|
819
|
-
query = query.whereNull(this.deletedAt);
|
|
820
|
-
}
|
|
821
|
-
|
|
822
|
-
const result = await query.first();
|
|
823
|
-
|
|
824
|
-
if (!result) {
|
|
825
|
-
return null;
|
|
826
|
-
}
|
|
827
|
-
|
|
828
|
-
return this.newFromBuilder(result);
|
|
799
|
+
// query() already applies the soft-delete scope.
|
|
800
|
+
// GuruORM Builder.first() returns a hydrated model instance or null directly.
|
|
801
|
+
return await this.query().first();
|
|
829
802
|
}
|
|
830
803
|
|
|
831
804
|
/**
|
|
@@ -833,31 +806,24 @@ export class Model extends GuruORMModel {
|
|
|
833
806
|
*/
|
|
834
807
|
static async paginate(perPage = null, page = 1) {
|
|
835
808
|
perPage = perPage || this.perPage;
|
|
836
|
-
|
|
837
809
|
const offset = (page - 1) * perPage;
|
|
838
|
-
|
|
839
|
-
let query = this.query();
|
|
840
|
-
|
|
841
|
-
// Apply soft deletes
|
|
842
|
-
if (this.softDeletes) {
|
|
843
|
-
query = query.whereNull(this.deletedAt);
|
|
844
|
-
}
|
|
845
|
-
|
|
846
|
-
const countResult = await query.count('* as count');
|
|
847
|
-
const totalCount = countResult[0]?.count || 0;
|
|
848
|
-
|
|
849
|
-
const results = await query.limit(perPage).offset(offset).get();
|
|
850
810
|
|
|
851
|
-
|
|
811
|
+
// Use two separate queries:
|
|
812
|
+
// 1. count query — GuruORM's count() returns a plain number, not an array.
|
|
813
|
+
// 2. data query — limit/offset applied on its own fresh builder.
|
|
814
|
+
// Both go through this.query() which already applies the soft-delete scope.
|
|
815
|
+
// Do NOT add whereNull again here — that would produce a duplicate SQL condition.
|
|
816
|
+
const totalCount = await this.query().count();
|
|
817
|
+
const items = [...await this.query().limit(perPage).offset(offset).get()];
|
|
852
818
|
|
|
853
819
|
return {
|
|
854
820
|
data: items,
|
|
855
821
|
total: totalCount,
|
|
856
822
|
perPage,
|
|
857
823
|
currentPage: page,
|
|
858
|
-
lastPage: Math.ceil(totalCount / perPage),
|
|
824
|
+
lastPage: Math.ceil(totalCount / perPage) || 1,
|
|
859
825
|
from: offset + 1,
|
|
860
|
-
to: offset + items.length
|
|
826
|
+
to: offset + items.length,
|
|
861
827
|
};
|
|
862
828
|
}
|
|
863
829
|
|
|
@@ -887,17 +853,24 @@ export class Model extends GuruORMModel {
|
|
|
887
853
|
query = query.whereNull(qualifiedColumn);
|
|
888
854
|
}
|
|
889
855
|
|
|
890
|
-
//
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
856
|
+
// Inject updated_at on bulk Builder-level updates (e.g. User.where(...).update({}))
|
|
857
|
+
// Cache the wrapper closure per model class so it is created only ONCE, not on
|
|
858
|
+
// every query() call (which would allocate a new closure per DB operation).
|
|
859
|
+
if (this.timestamps && this.updatedAt) {
|
|
860
|
+
if (!Object.prototype.hasOwnProperty.call(this, '_cachedUpdateFn')) {
|
|
861
|
+
const modelClass = this;
|
|
862
|
+
// query.update is EloquentBuilder.prototype.update — a stable reference
|
|
863
|
+
// captured once and reused for the lifetime of this model class.
|
|
864
|
+
const protoUpdate = query.update;
|
|
865
|
+
this._cachedUpdateFn = async function timestampedUpdate(data) {
|
|
866
|
+
if (data[modelClass.updatedAt] === undefined) {
|
|
867
|
+
data[modelClass.updatedAt] = new Date();
|
|
868
|
+
}
|
|
869
|
+
return protoUpdate.call(this, data);
|
|
870
|
+
};
|
|
898
871
|
}
|
|
899
|
-
|
|
900
|
-
}
|
|
872
|
+
query.update = this._cachedUpdateFn;
|
|
873
|
+
}
|
|
901
874
|
|
|
902
875
|
return query;
|
|
903
876
|
}
|
|
@@ -77,6 +77,7 @@ export function EnhancedPhotoManager({
|
|
|
77
77
|
deletePhoto,
|
|
78
78
|
deleteMultiplePhotos,
|
|
79
79
|
reorderPhotos,
|
|
80
|
+
setPrimaryPhoto,
|
|
80
81
|
} = photosHook;
|
|
81
82
|
|
|
82
83
|
const [selectedPhotos, setSelectedPhotos] = useState([]);
|
|
@@ -255,6 +256,7 @@ export function EnhancedPhotoManager({
|
|
|
255
256
|
isSelected={selectedPhotos.includes(photo.id)}
|
|
256
257
|
onSelect={handlePhotoSelect}
|
|
257
258
|
onDelete={handlePhotoDelete}
|
|
259
|
+
onSetPrimary={setPrimaryPhoto || undefined}
|
|
258
260
|
disabled={loading}
|
|
259
261
|
/>
|
|
260
262
|
))}
|
|
@@ -294,6 +296,7 @@ EnhancedPhotoManager.propTypes = {
|
|
|
294
296
|
deletePhoto: PropTypes.func,
|
|
295
297
|
deleteMultiplePhotos: PropTypes.func,
|
|
296
298
|
reorderPhotos: PropTypes.func,
|
|
299
|
+
setPrimaryPhoto: PropTypes.func,
|
|
297
300
|
}).isRequired,
|
|
298
301
|
/** Section title */
|
|
299
302
|
title: PropTypes.string,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vasuzex",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.8",
|
|
4
4
|
"description": "Laravel-inspired framework for Node.js monorepos - V2 with optimized dependencies",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./framework/index.js",
|
|
@@ -108,7 +108,7 @@
|
|
|
108
108
|
"express-rate-limit": "^8.2.1",
|
|
109
109
|
"firebase-admin": "^13.6.0",
|
|
110
110
|
"fs-extra": "^11.3.2",
|
|
111
|
-
"guruorm": "^2.
|
|
111
|
+
"guruorm": "^2.1.20",
|
|
112
112
|
"helmet": "^8.1.0",
|
|
113
113
|
"inquirer": "^9.3.8",
|
|
114
114
|
"ip2location-nodejs": "^9.7.0",
|