c2-mongoose 2.1.214 → 2.1.216

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.
@@ -0,0 +1,27 @@
1
+ import mongoose from "mongoose";
2
+ import { SearchOptions, SearchResponse } from "../types/SearchResponse";
3
+ import SearchFlow from "./SearchFlow";
4
+ export interface IPopulate {
5
+ [key: string]: any;
6
+ path: string;
7
+ select: string;
8
+ populate: IPopulate;
9
+ }
10
+ declare class SearcherFlow<D> {
11
+ private model;
12
+ [key: string]: any;
13
+ private searchText;
14
+ private orderSense;
15
+ private orderBy;
16
+ private page;
17
+ private limit;
18
+ private pageable;
19
+ private selection;
20
+ private populate;
21
+ constructor(repository: mongoose.Model<any>, search?: SearchFlow);
22
+ prepareSearch(search: any): void;
23
+ search(model: mongoose.Model<any>, options: SearchOptions): Promise<SearchResponse<D>>;
24
+ transformObject(originalObject: any): any;
25
+ buildDefaultFilters(objectSearch: any): any;
26
+ }
27
+ export default SearcherFlow;
@@ -0,0 +1,278 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
14
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
15
+ return new (P || (P = Promise))(function (resolve, reject) {
16
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
17
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
18
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
19
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
20
+ });
21
+ };
22
+ var __generator = (this && this.__generator) || function (thisArg, body) {
23
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
24
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
25
+ function verb(n) { return function (v) { return step([n, v]); }; }
26
+ function step(op) {
27
+ if (f) throw new TypeError("Generator is already executing.");
28
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
29
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
30
+ if (y = 0, t) op = [op[0] & 2, t.value];
31
+ switch (op[0]) {
32
+ case 0: case 1: t = op; break;
33
+ case 4: _.label++; return { value: op[1], done: false };
34
+ case 5: _.label++; y = op[1]; op = [0]; continue;
35
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
36
+ default:
37
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
38
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
39
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
40
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
41
+ if (t[2]) _.ops.pop();
42
+ _.trys.pop(); continue;
43
+ }
44
+ op = body.call(thisArg, _);
45
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
46
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
47
+ }
48
+ };
49
+ var __importDefault = (this && this.__importDefault) || function (mod) {
50
+ return (mod && mod.__esModule) ? mod : { "default": mod };
51
+ };
52
+ Object.defineProperty(exports, "__esModule", { value: true });
53
+ var mongoose_1 = require("mongoose");
54
+ var Utils_1 = require("../utils/Utils");
55
+ var BuildSelectSingleFlowItem_1 = __importDefault(require("./item/BuildSelectSingleFlowItem"));
56
+ var BuildPopulateSingleFlowItem_1 = __importDefault(require("./item/BuildPopulateSingleFlowItem"));
57
+ var moment_1 = __importDefault(require("moment"));
58
+ var SearcherFlow = /** @class */ (function () {
59
+ function SearcherFlow(repository, search) {
60
+ this.searchText = "";
61
+ this.orderSense = "desc";
62
+ this.orderBy = "_id";
63
+ this.page = 1;
64
+ this.limit = 50;
65
+ this.pageable = true;
66
+ this.selection = [""];
67
+ this.populate = [""];
68
+ this.model = repository;
69
+ for (var key in search) {
70
+ this[key] = search[key];
71
+ }
72
+ }
73
+ SearcherFlow.prototype.prepareSearch = function (search) {
74
+ for (var key in search) {
75
+ this[key] = search[key];
76
+ }
77
+ // this.projection = this.buildProjections()
78
+ // this.populate = this.buildPopulate()
79
+ // this.buildOrdenation()
80
+ };
81
+ SearcherFlow.prototype.search = function (model, options) {
82
+ return __awaiter(this, void 0, void 0, function () {
83
+ var stagesItems, stagesPaging, stagesMetadata, facet, _i, stagesMetadata_1, metadata, result, _a, resultAux;
84
+ return __generator(this, function (_b) {
85
+ switch (_b.label) {
86
+ case 0:
87
+ stagesItems = [];
88
+ if ((0, Utils_1.isNotEmpty)(options.pipelines)) {
89
+ stagesItems.push.apply(stagesItems, options.pipelines);
90
+ }
91
+ if ((0, Utils_1.isNotEmpty)(options.unions)) {
92
+ stagesItems.push.apply(stagesItems, options.unions);
93
+ }
94
+ stagesItems.push({ $match: this.filters });
95
+ if ((0, Utils_1.isNotEmpty)(this.projection)) {
96
+ stagesItems.push({ $project: BuildSelectSingleFlowItem_1.default.build(model, this.select) });
97
+ }
98
+ // stagesItems.push({ $sort: this.sort })
99
+ if (this.pageable === true) {
100
+ stagesItems.push({ $skip: ((this.page - 1) * this.limit) || 0 });
101
+ stagesItems.push({ $limit: this.limit });
102
+ }
103
+ stagesPaging = [];
104
+ if ((0, Utils_1.isNotEmpty)(options.pipelines)) {
105
+ stagesPaging.push.apply(stagesPaging, options.pipelines);
106
+ }
107
+ if ((0, Utils_1.isNotEmpty)(options.unions)) {
108
+ stagesPaging.push.apply(stagesPaging, options.unions);
109
+ }
110
+ stagesPaging.push({ $match: this.filters });
111
+ stagesPaging.push({ $count: "total" });
112
+ stagesPaging.push({
113
+ $addFields: {
114
+ page: this.pageable === true ? this.page : 1,
115
+ limit: this.pageable === true ? this.limit : '$total',
116
+ totalPages: this.pageable === true ? {
117
+ $cond: {
118
+ if: { $eq: ['$total', 0] },
119
+ then: 0,
120
+ else: { $ceil: { $divide: ['$total', this.limit] } }
121
+ }
122
+ } : 1,
123
+ startIndex: this.pageable === true ? { $subtract: [{ $multiply: [this.page, this.limit] }, this.limit - 1] } : 1,
124
+ endIndex: this.pageable === true ? { $multiply: [this.page, this.limit] } : '$total'
125
+ }
126
+ });
127
+ stagesMetadata = [];
128
+ if ((0, Utils_1.isNotEmpty)(options.metadata)) {
129
+ stagesMetadata.push.apply(stagesMetadata, options.metadata);
130
+ }
131
+ facet = {};
132
+ if (this.onlyMetadata === false || this.onlyMetadata === undefined) {
133
+ facet.items = stagesItems;
134
+ facet.paging = stagesPaging;
135
+ }
136
+ for (_i = 0, stagesMetadata_1 = stagesMetadata; _i < stagesMetadata_1.length; _i++) {
137
+ metadata = stagesMetadata_1[_i];
138
+ facet[metadata.id] = metadata.conditions;
139
+ }
140
+ return [4 /*yield*/, model.aggregate([
141
+ {
142
+ $facet: facet
143
+ },
144
+ ], {
145
+ collation: {
146
+ locale: "pt",
147
+ numericOrdering: true
148
+ }
149
+ }).session(options === null || options === void 0 ? void 0 : options.session)];
150
+ case 1:
151
+ result = _b.sent();
152
+ if (!(0, Utils_1.isNotEmpty)(this.populate)) return [3 /*break*/, 3];
153
+ _a = result[0];
154
+ return [4 /*yield*/, model.populate(result[0].items, BuildPopulateSingleFlowItem_1.default.buildPopulate(model, this.populate, this.selection))];
155
+ case 2:
156
+ _a.items = _b.sent();
157
+ _b.label = 3;
158
+ case 3:
159
+ resultAux = this.transformObject(result[0]);
160
+ return [2 /*return*/, resultAux];
161
+ }
162
+ });
163
+ });
164
+ };
165
+ SearcherFlow.prototype.transformObject = function (originalObject) {
166
+ var metadata = {};
167
+ var transformedObject = {};
168
+ for (var key in originalObject) {
169
+ if (key.startsWith('metadata-')) {
170
+ if (originalObject[key].length === 1) {
171
+ metadata[key.replace("metadata-", "")] = originalObject[key][0];
172
+ continue;
173
+ }
174
+ metadata[key.replace("metadata-", "")] = originalObject[key];
175
+ }
176
+ else {
177
+ transformedObject[key] = originalObject[key];
178
+ }
179
+ }
180
+ var hasPagination = (originalObject === null || originalObject === void 0 ? void 0 : originalObject.paging) ? true : false;
181
+ return __assign(__assign({}, transformedObject), { metadata: metadata, paging: hasPagination ? (originalObject === null || originalObject === void 0 ? void 0 : originalObject.paging[0]) || { total: 0, page: 1, limit: this.limit } : undefined });
182
+ };
183
+ SearcherFlow.prototype.buildDefaultFilters = function (objectSearch) {
184
+ var _this = this;
185
+ var filters = { $and: [] };
186
+ Object.entries(objectSearch).forEach(function (_a) {
187
+ var key = _a[0], value = _a[1];
188
+ if ((0, Utils_1.isNotEmpty)(value)) {
189
+ var condition = {};
190
+ if ([
191
+ 'onlyMetadata',
192
+ 'projection',
193
+ 'pageable',
194
+ 'orderSense',
195
+ 'orderBy',
196
+ 'properties',
197
+ 'populate',
198
+ 'page',
199
+ 'limit',
200
+ 'model',
201
+ 'select',
202
+ 'searchText',
203
+ 'sort',
204
+ 'isPageable',
205
+ 'searchPageable'
206
+ ].includes(key)) {
207
+ return;
208
+ }
209
+ if (typeof value === 'string' && _this.isValidObjectId(value)) {
210
+ value = new mongoose_1.Types.ObjectId(value);
211
+ }
212
+ if (value === 'true') {
213
+ value = true;
214
+ }
215
+ if (value === 'false') {
216
+ value = false;
217
+ }
218
+ if (key.endsWith('DateRange') || key.endsWith('DateTimeRange')) {
219
+ var fieldName = key.replace('Range', '');
220
+ var values = value;
221
+ if ((0, Utils_1.isNotEmpty)(values[0])) {
222
+ var momentValue = (0, moment_1.default)(values[0]);
223
+ momentValue.hour(0);
224
+ momentValue.minute(0);
225
+ momentValue.second(0);
226
+ condition[fieldName] = __assign(__assign({}, condition[fieldName]), { $gte: momentValue.tz('America/Sao_Paulo', true).toDate() });
227
+ }
228
+ if ((0, Utils_1.isNotEmpty)(values[1])) {
229
+ var momentValue = (0, moment_1.default)(values[1]);
230
+ momentValue.hour(23);
231
+ momentValue.minute(59);
232
+ momentValue.second(59);
233
+ condition[fieldName] = __assign(__assign({}, condition[fieldName]), { $lte: momentValue.tz('America/Sao_Paulo', true).toDate() });
234
+ }
235
+ filters.$and.push(condition);
236
+ }
237
+ else if (key.endsWith('Like')) {
238
+ var fieldName = key.replace('Like', '');
239
+ condition[fieldName] = _this.buildRegex(value); //{ $regex: value as any, $options: 'i' }
240
+ filters.$and.push(condition);
241
+ }
242
+ else if (key.endsWith('Exists')) {
243
+ var fieldName = key.replace('Exists', '');
244
+ condition[fieldName] = { $exists: value };
245
+ filters.$and.push(condition);
246
+ }
247
+ else {
248
+ if (!Array.isArray(value)) {
249
+ condition[key] = value;
250
+ }
251
+ else {
252
+ var arr = [];
253
+ for (var _i = 0, value_1 = value; _i < value_1.length; _i++) {
254
+ var val = value_1[_i];
255
+ if (typeof val === 'string' && _this.isValidObjectId(val)) {
256
+ val = new mongoose_1.Types.ObjectId(val);
257
+ }
258
+ arr.push(val);
259
+ }
260
+ if (key.startsWith("notIn")) {
261
+ key = key.replace("notIn", "");
262
+ condition[key] = { $nin: arr };
263
+ }
264
+ else {
265
+ condition[key] = { $in: arr };
266
+ }
267
+ }
268
+ filters.$and.push(condition);
269
+ }
270
+ }
271
+ });
272
+ if (filters.$and.length === 0)
273
+ delete filters['$and'];
274
+ return filters;
275
+ };
276
+ return SearcherFlow;
277
+ }());
278
+ exports.default = SearcherFlow;
@@ -0,0 +1,8 @@
1
+ import mongoose from "mongoose";
2
+ import { IPopulate } from "../SearcherFlow";
3
+ declare class BuildPopulateSingleFlowItem {
4
+ buildPopulate(model: mongoose.Model<any>, populatesStr: string[], selectsStr: string[]): IPopulate[];
5
+ buildPath(target: string, nested?: string): IPopulate;
6
+ }
7
+ declare const _default: BuildPopulateSingleFlowItem;
8
+ export default _default;
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ var Utils_1 = require("../../utils/Utils");
15
+ var BuildPopulateSingleFlowItem = /** @class */ (function () {
16
+ function BuildPopulateSingleFlowItem() {
17
+ }
18
+ BuildPopulateSingleFlowItem.prototype.buildPopulate = function (model, populatesStr, selectsStr) {
19
+ var _a, _b, _c, _d;
20
+ var populate = [];
21
+ if ((0, Utils_1.isEmpty)(populatesStr)) {
22
+ return [];
23
+ }
24
+ var _loop_1 = function () {
25
+ var _e = property.split('.'), first = _e[0], rest = _e.slice(1);
26
+ var nested = rest.join('.');
27
+ var populateLocal = this_1.buildPath(first, nested);
28
+ if (Array.isArray(selectsStr)) {
29
+ var selects = selectsStr.filter(function (sel) { return sel.startsWith("".concat(first, ".")); });
30
+ var select = selects.map(function (sel) { return sel.split(".")[1]; }).join(" ");
31
+ if ((0, Utils_1.isNotEmpty)(select)) {
32
+ populateLocal.select = select;
33
+ }
34
+ }
35
+ var existing = populate.find(function (populateAux) { return populateAux.path === populateLocal.path; });
36
+ if (existing) {
37
+ var populateAux = __assign(__assign({}, existing === null || existing === void 0 ? void 0 : existing.populate), { path: "".concat((_b = (_a = existing.populate) === null || _a === void 0 ? void 0 : _a.path) !== null && _b !== void 0 ? _b : "", " ").concat((_d = (_c = populateLocal.populate) === null || _c === void 0 ? void 0 : _c.path) !== null && _d !== void 0 ? _d : "").trim() });
38
+ existing.populate = populateAux;
39
+ return "continue";
40
+ }
41
+ populate.push(populateLocal);
42
+ };
43
+ var this_1 = this;
44
+ for (var _i = 0, populatesStr_1 = populatesStr; _i < populatesStr_1.length; _i++) {
45
+ var property = populatesStr_1[_i];
46
+ _loop_1();
47
+ }
48
+ return populate;
49
+ };
50
+ BuildPopulateSingleFlowItem.prototype.buildPath = function (target, nested) {
51
+ if (nested === void 0) { nested = ""; }
52
+ var populate = {};
53
+ populate.path = target;
54
+ if ((0, Utils_1.isNotEmpty)(nested)) {
55
+ var _a = nested.split('.'), first = _a[0], rest = _a.slice(1);
56
+ var nested2 = rest.join('.');
57
+ populate.populate = this.buildPath(first, nested2);
58
+ }
59
+ return populate;
60
+ };
61
+ return BuildPopulateSingleFlowItem;
62
+ }());
63
+ exports.default = new BuildPopulateSingleFlowItem;
@@ -10,7 +10,7 @@ var BuildSelectPopulateFlowItem = /** @class */ (function () {
10
10
  if (campoInfo.instance === "ObjectID") {
11
11
  return undefined;
12
12
  }
13
- if ((0, Utils_1.isEmpty)(projection[path]) || isNaN(projection[path]) === false) {
13
+ if ((0, Utils_1.isEmpty)(projection) || (0, Utils_1.isEmpty)(projection[path]) || isNaN(projection[path]) === false) {
14
14
  return undefined;
15
15
  }
16
16
  return projection[path];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "c2-mongoose",
3
- "version": "2.1.214",
3
+ "version": "2.1.216",
4
4
  "description": "Lib to make any search in database mongoose and use as basic crud",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -520,25 +520,6 @@ abstract class SearchFlow {
520
520
 
521
521
  return filters
522
522
  }
523
-
524
- // public addFilterModel(model: any, filters: any) {
525
- // Object.entries(model).forEach(([key, value]) => {
526
- // if (key.endsWith('DateRange')) {
527
- // return
528
- // }
529
- // if (key.endsWith('Like')) {
530
- // return
531
- // }
532
- // if (['onlyMetadata', 'projection', 'pageable', 'orderSense', 'orderBy', 'properties', 'populate', 'page', 'limit', 'model', 'select', 'searchText', 'isPageable', 'searchPageable'].includes(key)) {
533
- // return
534
- // }
535
- // if (isNotEmpty(value)) {
536
- // let condition = {} as any
537
- // condition[key] = value
538
- // filters.$and.push(condition)
539
- // }
540
- // })
541
- // }
542
523
  }
543
524
 
544
525
  export default SearchFlow
@@ -0,0 +1,261 @@
1
+ import mongoose, { ClientSession, Types } from "mongoose"
2
+ import { SearchOptions, SearchResponse } from "../types/SearchResponse"
3
+ import { isEmpty, isNotEmpty } from "../utils/Utils"
4
+ import SearchFlow from "./SearchFlow"
5
+ import BuildSelectSingleFlowItem from "./item/BuildSelectSingleFlowItem"
6
+ import BuildPopulateSingleFlowItem from "./item/BuildPopulateSingleFlowItem"
7
+ import moment from "moment"
8
+ export interface IPopulate {
9
+ [key: string]: any
10
+ path: string
11
+ select: string
12
+ populate: IPopulate
13
+ }
14
+
15
+ class SearcherFlow<D> {
16
+
17
+ private model: mongoose.Model<any>
18
+
19
+ [key: string]: any
20
+ private searchText: string = ""
21
+ private orderSense: string = "desc"
22
+ private orderBy: string = "_id"
23
+ private page: number = 1
24
+ private limit: number = 50
25
+ private pageable: boolean = true
26
+
27
+ private selection: string[] = [""]
28
+ private populate: string[] = [""]
29
+
30
+ constructor(repository: mongoose.Model<any>, search?: SearchFlow) {
31
+ this.model = repository
32
+ for (const key in search) {
33
+ this[key] = search[key];
34
+ }
35
+ }
36
+
37
+ public prepareSearch(search: any) {
38
+ for (const key in search) {
39
+ this[key] = search[key];
40
+ }
41
+
42
+ // this.projection = this.buildProjections()
43
+ // this.populate = this.buildPopulate()
44
+ // this.buildOrdenation()
45
+ }
46
+
47
+ async search(model: mongoose.Model<any>, options: SearchOptions): Promise<SearchResponse<D>> {
48
+
49
+ let stagesItems: any[] = []
50
+
51
+ if (isNotEmpty(options.pipelines)) {
52
+ stagesItems.push(...options.pipelines)
53
+ }
54
+ if (isNotEmpty(options.unions)) {
55
+ stagesItems.push(...options.unions)
56
+ }
57
+
58
+ stagesItems.push({ $match: this.filters })
59
+
60
+ if (isNotEmpty(this.projection)) {
61
+ stagesItems.push({ $project: BuildSelectSingleFlowItem.build(model, this.select) })
62
+ }
63
+
64
+ // stagesItems.push({ $sort: this.sort })
65
+ if (this.pageable === true) {
66
+ stagesItems.push({ $skip: ((this.page - 1) * this.limit) || 0 })
67
+ stagesItems.push({ $limit: this.limit })
68
+ }
69
+
70
+
71
+ let stagesPaging: any[] = []
72
+ if (isNotEmpty(options.pipelines)) {
73
+ stagesPaging.push(...options.pipelines)
74
+ }
75
+ if (isNotEmpty(options.unions)) {
76
+ stagesPaging.push(...options.unions)
77
+ }
78
+
79
+ stagesPaging.push({ $match: this.filters })
80
+ stagesPaging.push({ $count: "total" })
81
+ stagesPaging.push({
82
+ $addFields: {
83
+ page: this.pageable === true ? this.page : 1,
84
+ limit: this.pageable === true ? this.limit : '$total',
85
+ totalPages: this.pageable === true ? {
86
+ $cond: {
87
+ if: { $eq: ['$total', 0] },
88
+ then: 0,
89
+ else: { $ceil: { $divide: ['$total', this.limit] } }
90
+ }
91
+ } : 1,
92
+ startIndex: this.pageable === true ? { $subtract: [{ $multiply: [this.page, this.limit] }, this.limit - 1] } : 1,
93
+ endIndex: this.pageable === true ? { $multiply: [this.page, this.limit] } : '$total'
94
+ }
95
+ })
96
+
97
+ let stagesMetadata: any[] = []
98
+ if (isNotEmpty(options.metadata)) {
99
+ stagesMetadata.push(...options.metadata)
100
+ }
101
+
102
+ const facet: { [key: string]: any } = {}
103
+ if (this.onlyMetadata === false || this.onlyMetadata === undefined) {
104
+ facet.items = stagesItems
105
+ facet.paging = stagesPaging
106
+ }
107
+
108
+ for (let metadata of stagesMetadata) {
109
+ facet[metadata.id] = metadata.conditions
110
+ }
111
+
112
+ const result = await model.aggregate(
113
+ [
114
+ {
115
+ $facet: facet
116
+ },
117
+ ], {
118
+ collation: {
119
+ locale: "pt",
120
+ numericOrdering: true
121
+ }
122
+ }).session(options?.session as ClientSession)
123
+
124
+
125
+ if (isNotEmpty(this.populate)) {
126
+ result[0].items = await model.populate(result[0].items, BuildPopulateSingleFlowItem.buildPopulate(model, this.populate, this.selection))
127
+ }
128
+
129
+ let resultAux = this.transformObject(result[0])
130
+ return resultAux
131
+ }
132
+
133
+ transformObject(originalObject: any): any {
134
+ const metadata: any = {};
135
+ const transformedObject: any = {};
136
+
137
+ for (const key in originalObject) {
138
+ if (key.startsWith('metadata-')) {
139
+ if (originalObject[key].length === 1) {
140
+ metadata[key.replace("metadata-", "")] = originalObject[key][0]
141
+ continue
142
+ }
143
+ metadata[key.replace("metadata-", "")] = originalObject[key]
144
+ } else {
145
+ transformedObject[key] = originalObject[key];
146
+ }
147
+ }
148
+
149
+ let hasPagination = originalObject?.paging ? true : false
150
+
151
+ return {
152
+ ...transformedObject,
153
+ metadata,
154
+ paging: hasPagination ? originalObject?.paging[0] || { total: 0, page: 1, limit: this.limit } : undefined,
155
+ };
156
+ }
157
+
158
+ public buildDefaultFilters(objectSearch: any) {
159
+ let filters = { $and: [] } as any
160
+ Object.entries(objectSearch).forEach(([key, value]) => {
161
+ if (isNotEmpty(value)) {
162
+ let condition = {} as any
163
+ if ([
164
+ 'onlyMetadata',
165
+ 'projection',
166
+ 'pageable',
167
+ 'orderSense',
168
+ 'orderBy',
169
+ 'properties',
170
+ 'populate',
171
+ 'page',
172
+ 'limit',
173
+ 'model',
174
+ 'select',
175
+ 'searchText',
176
+ 'sort',
177
+ 'isPageable',
178
+ 'searchPageable'].includes(key)) {
179
+ return
180
+ }
181
+
182
+ if (typeof value === 'string' && this.isValidObjectId(value as string)) {
183
+ value = new Types.ObjectId(value as string)
184
+ }
185
+
186
+ if (value === 'true') {
187
+ value = true
188
+ }
189
+
190
+ if (value === 'false') {
191
+ value = false
192
+ }
193
+
194
+ if (key.endsWith('DateRange') || key.endsWith('DateTimeRange')) {
195
+ var fieldName = key.replace('Range', '')
196
+ var values = value as any
197
+ if (isNotEmpty(values[0])) {
198
+ var momentValue = moment(values[0])
199
+ momentValue.hour(0)
200
+ momentValue.minute(0)
201
+ momentValue.second(0)
202
+ condition[fieldName] = {
203
+ ...condition[fieldName],
204
+ $gte: momentValue.tz('America/Sao_Paulo', true).toDate()
205
+ }
206
+ }
207
+
208
+ if (isNotEmpty(values[1])) {
209
+ var momentValue = moment(values[1])
210
+ momentValue.hour(23)
211
+ momentValue.minute(59)
212
+ momentValue.second(59)
213
+ condition[fieldName] = {
214
+ ...condition[fieldName],
215
+ $lte: momentValue.tz('America/Sao_Paulo', true).toDate()
216
+ }
217
+ }
218
+ filters.$and.push(condition)
219
+ } else if (key.endsWith('Like')) {
220
+ var fieldName = key.replace('Like', '')
221
+ condition[fieldName] = this.buildRegex(value as string) //{ $regex: value as any, $options: 'i' }
222
+ filters.$and.push(condition)
223
+ } else if (key.endsWith('Exists')) {
224
+ var fieldName = key.replace('Exists', '')
225
+ condition[fieldName] = { $exists: value as boolean }
226
+ filters.$and.push(condition)
227
+ }
228
+
229
+ else {
230
+ if (!Array.isArray(value)) {
231
+ condition[key] = value
232
+ } else {
233
+ let arr = []
234
+ for (let val of value) {
235
+ if (typeof val === 'string' && this.isValidObjectId(val as string)) {
236
+ val = new Types.ObjectId(val as string)
237
+ }
238
+ arr.push(val)
239
+ }
240
+
241
+ if (key.startsWith("notIn")) {
242
+ key = key.replace("notIn", "")
243
+ condition[key] = { $nin: arr }
244
+ } else {
245
+ condition[key] = { $in: arr }
246
+ }
247
+
248
+ }
249
+ filters.$and.push(condition)
250
+ }
251
+ }
252
+ })
253
+
254
+ if (filters.$and.length === 0)
255
+ delete filters['$and']
256
+
257
+ return filters
258
+ }
259
+ }
260
+
261
+ export default SearcherFlow
@@ -0,0 +1,55 @@
1
+ import mongoose from "mongoose";
2
+ import { isEmpty, isNotEmpty } from "../../utils/Utils";
3
+ import { IPopulate } from "../SearcherFlow";
4
+
5
+ class BuildPopulateSingleFlowItem {
6
+
7
+ public buildPopulate(model: mongoose.Model<any>, populatesStr: string[], selectsStr: string[]): IPopulate[] {
8
+ var populate = [] as IPopulate[]
9
+ if (isEmpty(populatesStr)) {
10
+ return []
11
+ }
12
+
13
+ for (var property of populatesStr) {
14
+ let [first, ...rest] = property.split('.')
15
+ let nested = rest.join('.')
16
+
17
+ let populateLocal = this.buildPath(first, nested)
18
+
19
+ if (Array.isArray(selectsStr)) {
20
+ let selects = (selectsStr as []).filter((sel: string) => sel.startsWith(`${first}.`))
21
+ let select = selects.map((sel: string) => sel.split(".")[1]).join(" ")
22
+ if (isNotEmpty(select)) {
23
+ populateLocal.select = select
24
+ }
25
+ }
26
+
27
+ const existing = populate.find((populateAux: IPopulate) => populateAux.path === populateLocal.path)
28
+ if (existing) {
29
+ const populateAux = {
30
+ ...existing?.populate,
31
+ path: `${existing.populate?.path ?? ``} ${populateLocal.populate?.path ?? ``}`.trim()
32
+ }
33
+ existing.populate = populateAux
34
+ continue
35
+ }
36
+
37
+ populate.push(populateLocal)
38
+ }
39
+
40
+ return populate
41
+ }
42
+
43
+ public buildPath(target: string, nested: string = ""): IPopulate {
44
+ var populate = {} as IPopulate
45
+ populate.path = target
46
+ if (isNotEmpty(nested)) {
47
+ let [first, ...rest] = nested.split('.')
48
+ let nested2 = rest.join('.')
49
+ populate.populate = this.buildPath(first, nested2)
50
+ }
51
+ return populate
52
+ }
53
+ }
54
+
55
+ export default new BuildPopulateSingleFlowItem
@@ -12,7 +12,7 @@ class BuildSelectPopulateFlowItem {
12
12
  return undefined
13
13
  }
14
14
 
15
- if (isEmpty(projection[path]) || isNaN(projection[path]) === false) {
15
+ if (isEmpty(projection) || isEmpty(projection[path]) || isNaN(projection[path]) === false) {
16
16
  return undefined
17
17
  }
18
18
  return projection[path];