@lenne.tech/nest-server 11.23.1 → 11.24.1
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/CLAUDE.md +67 -13
- package/FRAMEWORK-API.md +3 -1
- package/dist/core/common/decorators/restricted.decorator.d.ts +1 -1
- package/dist/core/common/decorators/restricted.decorator.js +45 -4
- package/dist/core/common/decorators/restricted.decorator.js.map +1 -1
- package/dist/core/common/helpers/service.helper.js +28 -28
- package/dist/core/common/helpers/service.helper.js.map +1 -1
- package/dist/core/common/plugins/mongoose-role-guard.plugin.js +9 -2
- package/dist/core/common/plugins/mongoose-role-guard.plugin.js.map +1 -1
- package/dist/core/common/services/crud.service.d.ts +13 -1
- package/dist/core/common/services/crud.service.js +34 -0
- package/dist/core/common/services/crud.service.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/migration-guides/11.23.x-to-11.24.0.md +272 -0
- package/migration-guides/11.24.0-to-11.24.1.md +67 -0
- package/package.json +1 -1
- package/src/core/common/decorators/restricted.decorator.ts +72 -6
- package/src/core/common/helpers/service.helper.ts +42 -36
- package/src/core/common/interfaces/prepare-input-options.interface.ts +1 -0
- package/src/core/common/interfaces/prepare-output-options.interface.ts +1 -0
- package/src/core/common/plugins/mongoose-role-guard.plugin.ts +12 -2
- package/src/core/common/services/crud.service.ts +86 -0
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
Query,
|
|
10
10
|
QueryFilter,
|
|
11
11
|
QueryOptions,
|
|
12
|
+
Types,
|
|
12
13
|
} from 'mongoose';
|
|
13
14
|
|
|
14
15
|
import { FilterArgs } from '../args/filter.args';
|
|
@@ -692,6 +693,91 @@ export abstract class CrudService<
|
|
|
692
693
|
return this.deleteForce(id, serviceOptions);
|
|
693
694
|
}
|
|
694
695
|
|
|
696
|
+
/**
|
|
697
|
+
* Append items to an array field without loading the full array.
|
|
698
|
+
* Uses MongoDB $push — bypasses the process() pipeline entirely.
|
|
699
|
+
* Mongoose plugins (Tenant, Audit, RoleGuard) fire via pre('findOneAndUpdate').
|
|
700
|
+
*
|
|
701
|
+
* Use this instead of loading the full array and passing it through update():
|
|
702
|
+
* @example
|
|
703
|
+
* // WRONG — OOM risk on large arrays:
|
|
704
|
+
* // entity.logs.push(newLog);
|
|
705
|
+
* // await this.update(id, { logs: entity.logs });
|
|
706
|
+
*
|
|
707
|
+
* // CORRECT — atomic append:
|
|
708
|
+
* await this.pushToArray(id, 'logs', newLog);
|
|
709
|
+
* await this.pushToArray(id, 'logs', newLog, { $slice: -500 }); // Keep last 500
|
|
710
|
+
*
|
|
711
|
+
* @param id - Document ID (string, ObjectId, or object with id/_id property)
|
|
712
|
+
* @param field - Array field name. MUST be a compile-time constant — never pass user-controlled input.
|
|
713
|
+
* @param items - Item(s) to append
|
|
714
|
+
* @param options - MongoDB $push modifiers ($slice, $position, $sort)
|
|
715
|
+
*/
|
|
716
|
+
async pushToArray(
|
|
717
|
+
id: string | Types.ObjectId | { id?: any; _id?: any },
|
|
718
|
+
field: string,
|
|
719
|
+
items: any | any[],
|
|
720
|
+
options?: { $slice?: number; $position?: number; $sort?: Record<string, 1 | -1> },
|
|
721
|
+
): Promise<void> {
|
|
722
|
+
if (typeof field !== 'string' || field.startsWith('$') || field.includes('\0')) {
|
|
723
|
+
throw new Error(`pushToArray: invalid field name "${field}"`);
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
const itemsArray = Array.isArray(items) ? items : [items];
|
|
727
|
+
if (itemsArray.length === 0) {
|
|
728
|
+
return;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
const stringId = getStringIds(id);
|
|
732
|
+
const pushOp: any = { $each: itemsArray };
|
|
733
|
+
if (options?.$slice !== undefined) {
|
|
734
|
+
pushOp.$slice = options.$slice;
|
|
735
|
+
}
|
|
736
|
+
if (options?.$position !== undefined) {
|
|
737
|
+
pushOp.$position = options.$position;
|
|
738
|
+
}
|
|
739
|
+
if (options?.$sort) {
|
|
740
|
+
pushOp.$sort = options.$sort;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
await this.mainDbModel
|
|
744
|
+
.findByIdAndUpdate(stringId, { $push: { [field]: pushOp } } as any)
|
|
745
|
+
.lean()
|
|
746
|
+
.exec();
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
/**
|
|
750
|
+
* Remove items from an array field.
|
|
751
|
+
* Uses MongoDB $pull — bypasses the process() pipeline entirely.
|
|
752
|
+
* Mongoose plugins (Tenant, Audit, RoleGuard) fire via pre('findOneAndUpdate').
|
|
753
|
+
*
|
|
754
|
+
* @example
|
|
755
|
+
* // Remove by exact match
|
|
756
|
+
* await this.pullFromArray(id, 'tags', 'obsolete');
|
|
757
|
+
*
|
|
758
|
+
* // Remove by condition
|
|
759
|
+
* await this.pullFromArray(id, 'logs', { level: 'DEBUG' });
|
|
760
|
+
*
|
|
761
|
+
* @param id - Document ID (string, ObjectId, or object with id/_id property)
|
|
762
|
+
* @param field - Array field name. MUST be a compile-time constant — never pass user-controlled input.
|
|
763
|
+
* @param condition - Match condition for removal. MUST be application-controlled.
|
|
764
|
+
*/
|
|
765
|
+
async pullFromArray(
|
|
766
|
+
id: string | Types.ObjectId | { id?: any; _id?: any },
|
|
767
|
+
field: string,
|
|
768
|
+
condition: any,
|
|
769
|
+
): Promise<void> {
|
|
770
|
+
if (typeof field !== 'string' || field.startsWith('$') || field.includes('\0')) {
|
|
771
|
+
throw new Error(`pullFromArray: invalid field name "${field}"`);
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
const stringId = getStringIds(id);
|
|
775
|
+
await this.mainDbModel
|
|
776
|
+
.findByIdAndUpdate(stringId, { $pull: { [field]: condition } } as any)
|
|
777
|
+
.lean()
|
|
778
|
+
.exec();
|
|
779
|
+
}
|
|
780
|
+
|
|
695
781
|
/**
|
|
696
782
|
* Execute, populate and map Mongoose query or document(s) with serviceOptions
|
|
697
783
|
* Generic T is the type of the returned object(s)
|