@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.
@@ -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)