c2-mongoose 2.1.229 → 2.1.230

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.
@@ -1,6 +1,5 @@
1
1
  import mongoose from "mongoose";
2
2
  import { SearchOptions, SearchResponse } from "../types/SearchResponse";
3
- import SearchFlow from "./SearchFlow";
4
3
  export interface IPopulate {
5
4
  [key: string]: any;
6
5
  path: string;
@@ -19,12 +18,13 @@ declare class SearcherFlow<D> {
19
18
  private select;
20
19
  private populate;
21
20
  private filters;
22
- constructor(repository: mongoose.Model<any>, search?: SearchFlow);
21
+ constructor(repository: mongoose.Model<any>);
23
22
  prepareSearch(search: any): void;
24
- search(model: mongoose.Model<any>, options: SearchOptions): Promise<SearchResponse<D>>;
23
+ search(options: SearchOptions): Promise<SearchResponse<D>>;
25
24
  transformObject(originalObject: any): any;
26
25
  buildDefaultFilters(objectSearch: any): any;
27
26
  isValidObjectId(value: string): boolean;
28
27
  buildOrdenation(): any;
28
+ buildRegex(searchText: string): RegExp;
29
29
  }
30
30
  export default SearcherFlow;
@@ -56,7 +56,7 @@ var Utils_1 = require("../utils/Utils");
56
56
  var BuildPopulateSingleFlowItem_1 = __importDefault(require("./item/BuildPopulateSingleFlowItem"));
57
57
  var BuildSelectSingleFlowItem_1 = __importDefault(require("./item/BuildSelectSingleFlowItem"));
58
58
  var SearcherFlow = /** @class */ (function () {
59
- function SearcherFlow(repository, search) {
59
+ function SearcherFlow(repository) {
60
60
  this.searchText = "";
61
61
  this.orderSense = "desc";
62
62
  this.orderBy = "_id";
@@ -67,9 +67,6 @@ var SearcherFlow = /** @class */ (function () {
67
67
  this.populate = [""];
68
68
  this.filters = undefined;
69
69
  this.model = repository;
70
- for (var key in search) {
71
- this[key] = search[key];
72
- }
73
70
  }
74
71
  SearcherFlow.prototype.prepareSearch = function (search) {
75
72
  for (var key in search) {
@@ -78,17 +75,13 @@ var SearcherFlow = /** @class */ (function () {
78
75
  this.filters = this.buildDefaultFilters(this);
79
76
  this.page = Number(this.page);
80
77
  this.limit = Number(this.limit);
81
- // this.projection = this.buildProjections()
82
- // this.populate = this.buildPopulate()
83
- // this.buildOrdenation()
84
78
  };
85
- SearcherFlow.prototype.search = function (model, options) {
79
+ SearcherFlow.prototype.search = function (options) {
86
80
  return __awaiter(this, void 0, void 0, function () {
87
81
  var stagesItems, stagesPaging, stagesMetadata, facet, _i, stagesMetadata_1, metadata, result, _a, resultAux;
88
82
  return __generator(this, function (_b) {
89
83
  switch (_b.label) {
90
84
  case 0:
91
- console.log("new searcher");
92
85
  stagesItems = [];
93
86
  if ((0, Utils_1.isNotEmpty)(options.pipelines)) {
94
87
  stagesItems.push.apply(stagesItems, options.pipelines);
@@ -98,7 +91,7 @@ var SearcherFlow = /** @class */ (function () {
98
91
  }
99
92
  stagesItems.push({ $match: this.filters });
100
93
  if ((0, Utils_1.isNotEmpty)(this.select)) {
101
- stagesItems.push({ $project: BuildSelectSingleFlowItem_1.default.build(model, this.select) });
94
+ stagesItems.push({ $project: BuildSelectSingleFlowItem_1.default.build(this.model, this.select) });
102
95
  }
103
96
  stagesItems.push({ $sort: this.buildOrdenation() });
104
97
  if (this.pageable === true) {
@@ -142,7 +135,7 @@ var SearcherFlow = /** @class */ (function () {
142
135
  metadata = stagesMetadata_1[_i];
143
136
  facet[metadata.id] = metadata.conditions;
144
137
  }
145
- return [4 /*yield*/, model.aggregate([
138
+ return [4 /*yield*/, this.model.aggregate([
146
139
  {
147
140
  $facet: facet
148
141
  },
@@ -156,7 +149,7 @@ var SearcherFlow = /** @class */ (function () {
156
149
  result = _b.sent();
157
150
  if (!(0, Utils_1.isNotEmpty)(this.populate)) return [3 /*break*/, 3];
158
151
  _a = result[0];
159
- return [4 /*yield*/, model.populate(result[0].items, BuildPopulateSingleFlowItem_1.default.buildPopulate(model, this.populate, this.select))];
152
+ return [4 /*yield*/, this.model.populate(result[0].items, BuildPopulateSingleFlowItem_1.default.buildPopulate(this.model, this.populate, this.select))];
160
153
  case 2:
161
154
  _a.items = _b.sent();
162
155
  _b.label = 3;
@@ -187,6 +180,10 @@ var SearcherFlow = /** @class */ (function () {
187
180
  };
188
181
  SearcherFlow.prototype.buildDefaultFilters = function (objectSearch) {
189
182
  var _this = this;
183
+ // Recuperar todos os campos do tipo String
184
+ var camposString = Object.keys(this.model.schema.paths).filter(function (campo) {
185
+ return _this.model.schema.paths[campo].instance === 'String';
186
+ });
190
187
  var filters = { $and: [] };
191
188
  Object.entries(objectSearch).forEach(function (_a) {
192
189
  var key = _a[0], value = _a[1];
@@ -276,6 +273,17 @@ var SearcherFlow = /** @class */ (function () {
276
273
  }
277
274
  }
278
275
  });
276
+ if ((0, Utils_1.isNotEmpty)(this.searchText) && (0, Utils_1.isNotEmpty)(camposString)) {
277
+ var regex = this.buildRegex(this.searchText);
278
+ var conditions = { $or: [] };
279
+ for (var _i = 0, camposString_1 = camposString; _i < camposString_1.length; _i++) {
280
+ var fieldString = camposString_1[_i];
281
+ var conditionAux = {};
282
+ conditionAux[fieldString] = { $regex: regex };
283
+ conditions.$or.push(conditionAux);
284
+ }
285
+ filters.$and.push(conditions);
286
+ }
279
287
  if (filters.$and.length === 0)
280
288
  delete filters['$and'];
281
289
  return filters;
@@ -290,6 +298,22 @@ var SearcherFlow = /** @class */ (function () {
290
298
  order[this.orderBy] = this.orderSense === "desc" ? -1 : 1;
291
299
  return order;
292
300
  };
301
+ SearcherFlow.prototype.buildRegex = function (searchText) {
302
+ var regexExpression = searchText
303
+ .replace(/[+?^${}()|[\]\\]/g, '\\$&') //Tratar os caracteres que podem ser chaves, escape os demais q podem ser regex
304
+ .replace(/^"/, '^').replace(/"$/, '$') //Replace aspas duplas para busca exata
305
+ .replace(/^%22/, '^').replace(/%22$/, '$') //Replace aspas duplas para busca exata
306
+ .replace(/%20/, ' ') //Replace espaço em branco para nao quebrar o proximo replace
307
+ .replace(/\*/g, '.*?') //Replace % para o padrão regex (% é muito utilizado como o .*? e é mais simples para o usuario digitar)
308
+ .replace(/%/g, '.*?') //Replace % para o padrão regex (% é muito utilizado como o .*? e é mais simples para o usuario digitar)
309
+ .replace(/[ç|Ç|c|C]/g, '[c,C,ç,Ç]')
310
+ .replace(/[a|á|à|ä|â|A|Á|Â|Ã|Ä]/g, '[a,á,à,ä,â,A,Á,Â,Ã,Ä]')
311
+ .replace(/[e|é|ë|è|E|É|Ë|È]/g, '[e,é,ë,è,E,É,Ë,È]')
312
+ .replace(/[i|í|ï|ì|I|Í|Ï|Ì]/g, '[i,í,ï,ì,I,Í,Ï,Ì]')
313
+ .replace(/[o|ó|ö|ò|õ|O|Ó|Ö|Ô|Õ]/g, '[o,ó,ö,ò,õ,O,Ó,Ö,Ô,Õ]')
314
+ .replace(/[u|ü|ú|ù|U|Ú|Ü|Ù]/g, '[u,ü,ú,ù,U,Ú,Ü,Ù]');
315
+ return new RegExp("".concat(regexExpression), 'i');
316
+ };
293
317
  return SearcherFlow;
294
318
  }());
295
319
  exports.default = SearcherFlow;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "c2-mongoose",
3
- "version": "2.1.229",
3
+ "version": "2.1.230",
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",
@@ -28,11 +28,8 @@ class SearcherFlow<D> {
28
28
  private populate: string[] = [""]
29
29
  private filters: any = undefined
30
30
 
31
- constructor(repository: mongoose.Model<any>, search?: SearchFlow) {
31
+ constructor(repository: mongoose.Model<any>) {
32
32
  this.model = repository
33
- for (const key in search) {
34
- this[key] = search[key];
35
- }
36
33
  }
37
34
 
38
35
  public prepareSearch(search: any) {
@@ -43,14 +40,10 @@ class SearcherFlow<D> {
43
40
  this.filters = this.buildDefaultFilters(this)
44
41
  this.page = Number(this.page)
45
42
  this.limit = Number(this.limit)
46
- // this.projection = this.buildProjections()
47
- // this.populate = this.buildPopulate()
48
- // this.buildOrdenation()
49
43
  }
50
44
 
51
- async search(model: mongoose.Model<any>, options: SearchOptions): Promise<SearchResponse<D>> {
45
+ async search(options: SearchOptions): Promise<SearchResponse<D>> {
52
46
 
53
- console.log("new searcher")
54
47
  let stagesItems: any[] = []
55
48
 
56
49
  if (isNotEmpty(options.pipelines)) {
@@ -63,7 +56,7 @@ class SearcherFlow<D> {
63
56
  stagesItems.push({ $match: this.filters })
64
57
 
65
58
  if (isNotEmpty(this.select)) {
66
- stagesItems.push({ $project: BuildSelectSingleFlowItem.build(model, this.select) })
59
+ stagesItems.push({ $project: BuildSelectSingleFlowItem.build(this.model, this.select) })
67
60
  }
68
61
 
69
62
  stagesItems.push({ $sort: this.buildOrdenation() })
@@ -114,7 +107,7 @@ class SearcherFlow<D> {
114
107
  facet[metadata.id] = metadata.conditions
115
108
  }
116
109
 
117
- const result = await model.aggregate(
110
+ const result = await this.model.aggregate(
118
111
  [
119
112
  {
120
113
  $facet: facet
@@ -128,7 +121,7 @@ class SearcherFlow<D> {
128
121
 
129
122
 
130
123
  if (isNotEmpty(this.populate)) {
131
- result[0].items = await model.populate(result[0].items, BuildPopulateSingleFlowItem.buildPopulate(model, this.populate, this.select))
124
+ result[0].items = await this.model.populate(result[0].items, BuildPopulateSingleFlowItem.buildPopulate(this.model, this.populate, this.select))
132
125
  }
133
126
 
134
127
  let resultAux = this.transformObject(result[0])
@@ -161,6 +154,13 @@ class SearcherFlow<D> {
161
154
  }
162
155
 
163
156
  public buildDefaultFilters(objectSearch: any) {
157
+
158
+ // Recuperar todos os campos do tipo String
159
+ const camposString = Object.keys(this.model.schema.paths).filter((campo: string) => {
160
+ return this.model.schema.paths[campo].instance === 'String';
161
+ });
162
+
163
+
164
164
  let filters = { $and: [] } as any
165
165
  Object.entries(objectSearch).forEach(([key, value]) => {
166
166
  if (isNotEmpty(value)) {
@@ -258,6 +258,18 @@ class SearcherFlow<D> {
258
258
  }
259
259
  })
260
260
 
261
+ if (isNotEmpty(this.searchText) && isNotEmpty(camposString)) {
262
+ let regex = this.buildRegex(this.searchText)
263
+ let conditions = { $or: [] as any }
264
+ for (let fieldString of camposString) {
265
+ let conditionAux: { [key: string]: any } = {}
266
+ conditionAux[fieldString] = { $regex: regex }
267
+
268
+ conditions.$or.push(conditionAux)
269
+ }
270
+ filters.$and.push(conditions)
271
+ }
272
+
261
273
  if (filters.$and.length === 0)
262
274
  delete filters['$and']
263
275
 
@@ -274,7 +286,24 @@ class SearcherFlow<D> {
274
286
  this.orderBy = this.orderBy
275
287
  order[this.orderBy] = this.orderSense === "desc" ? -1 : 1
276
288
  return order
277
- }
289
+ }
290
+
291
+ buildRegex(searchText: string): RegExp {
292
+ let regexExpression = searchText
293
+ .replace(/[+?^${}()|[\]\\]/g, '\\$&') //Tratar os caracteres que podem ser chaves, escape os demais q podem ser regex
294
+ .replace(/^"/, '^').replace(/"$/, '$') //Replace aspas duplas para busca exata
295
+ .replace(/^%22/, '^').replace(/%22$/, '$') //Replace aspas duplas para busca exata
296
+ .replace(/%20/, ' ') //Replace espaço em branco para nao quebrar o proximo replace
297
+ .replace(/\*/g, '.*?') //Replace % para o padrão regex (% é muito utilizado como o .*? e é mais simples para o usuario digitar)
298
+ .replace(/%/g, '.*?') //Replace % para o padrão regex (% é muito utilizado como o .*? e é mais simples para o usuario digitar)
299
+ .replace(/[ç|Ç|c|C]/g, '[c,C,ç,Ç]')
300
+ .replace(/[a|á|à|ä|â|A|Á|Â|Ã|Ä]/g, '[a,á,à,ä,â,A,Á,Â,Ã,Ä]')
301
+ .replace(/[e|é|ë|è|E|É|Ë|È]/g, '[e,é,ë,è,E,É,Ë,È]')
302
+ .replace(/[i|í|ï|ì|I|Í|Ï|Ì]/g, '[i,í,ï,ì,I,Í,Ï,Ì]')
303
+ .replace(/[o|ó|ö|ò|õ|O|Ó|Ö|Ô|Õ]/g, '[o,ó,ö,ò,õ,O,Ó,Ö,Ô,Õ]')
304
+ .replace(/[u|ü|ú|ù|U|Ú|Ü|Ù]/g, '[u,ü,ú,ù,U,Ú,Ü,Ù]')
305
+ return new RegExp(`${regexExpression}`, 'i');
306
+ }
278
307
  }
279
308
 
280
309
  export default SearcherFlow