@lenne.tech/nest-server 9.0.10 → 9.0.11

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lenne.tech/nest-server",
3
- "version": "9.0.10",
3
+ "version": "9.0.11",
4
4
  "description": "Modern, fast, powerful Node.js web framework in TypeScript based on Nest with a GraphQL API and a connection to MongoDB (or other databases).",
5
5
  "keywords": [
6
6
  "node",
@@ -102,12 +102,12 @@
102
102
  "@types/jest": "29.1.2",
103
103
  "@types/lodash": "4.14.186",
104
104
  "@types/multer": "1.4.7",
105
- "@types/node": "18.8.3",
105
+ "@types/node": "18.8.4",
106
106
  "@types/nodemailer": "6.4.6",
107
107
  "@types/passport": "1.0.11",
108
108
  "@types/supertest": "2.0.12",
109
- "@typescript-eslint/eslint-plugin": "5.39.0",
110
- "@typescript-eslint/parser": "5.39.0",
109
+ "@typescript-eslint/eslint-plugin": "5.40.0",
110
+ "@typescript-eslint/parser": "5.40.0",
111
111
  "coffeescript": "2.7.0",
112
112
  "eslint": "8.25.0",
113
113
  "eslint-config-prettier": "8.5.0",
package/src/config.env.ts CHANGED
@@ -11,6 +11,7 @@ const config: { [env: string]: IServerOptions } = {
11
11
  // Local environment
12
12
  // ===========================================================================
13
13
  local: {
14
+ automaticObjectIdFiltering: true,
14
15
  cronJobs: {
15
16
  sayHello: {
16
17
  cronTime: CronExpression.EVERY_10_SECONDS,
@@ -72,6 +73,7 @@ const config: { [env: string]: IServerOptions } = {
72
73
  // Development environment
73
74
  // ===========================================================================
74
75
  development: {
76
+ automaticObjectIdFiltering: true,
75
77
  email: {
76
78
  smtp: {
77
79
  auth: {
@@ -124,6 +126,7 @@ const config: { [env: string]: IServerOptions } = {
124
126
  // Production environment
125
127
  // ===========================================================================
126
128
  production: {
129
+ automaticObjectIdFiltering: true,
127
130
  email: {
128
131
  smtp: {
129
132
  auth: {
@@ -1,6 +1,6 @@
1
1
  import { FieldNode, GraphQLResolveInfo, SelectionNode } from 'graphql';
2
2
  import * as _ from 'lodash';
3
- import { Document, Model, PopulateOptions, Query, SchemaType, Types } from 'mongoose';
3
+ import { Document, Model, PopulateOptions, Query, Types } from 'mongoose';
4
4
  import { ResolveSelector } from '../interfaces/resolve-selector.interface';
5
5
  import { CoreModel } from '../models/core-model.model';
6
6
  import { FieldSelection } from '../types/field-selection.type';
@@ -79,6 +79,24 @@ export function addIds(
79
79
  return result;
80
80
  }
81
81
 
82
+ /**
83
+ * Checks if string is a valid ID or if the string array contains only valid IDs that can be used in mongodb ObjectId
84
+ */
85
+ export function checkStringIds(ids: string | string[]): boolean {
86
+ if (!Array.isArray(ids)) {
87
+ ids = [ids];
88
+ }
89
+ try {
90
+ for (const id of ids) {
91
+ if (typeof id !== 'string' || id.length !== 24 || !Types.ObjectId.isValid(id)) {
92
+ return false;
93
+ }
94
+ }
95
+ return true;
96
+ } catch (e) {}
97
+ return false;
98
+ }
99
+
82
100
  /**
83
101
  * Checks if all IDs are equal
84
102
  */
@@ -5,8 +5,9 @@ import { LogicalOperatorEnum } from '../enums/logical-operator.enum';
5
5
  import { SortOrderEnum } from '../enums/sort-order.emum';
6
6
  import { FilterInput } from '../inputs/filter.input';
7
7
  import { SortInput } from '../inputs/sort.input';
8
- import { getObjectIds } from './db.helper';
9
- import { assignPlain } from './input.helper';
8
+ import { ConfigService } from '../services/config.service';
9
+ import { checkStringIds, getObjectIds } from './db.helper';
10
+ import { assignPlain, clone } from './input.helper';
10
11
 
11
12
  /**
12
13
  * Helper for filter handling
@@ -110,12 +111,21 @@ export function convertFilterArgsToQuery<T = any>(filterArgs: Partial<FilterArgs
110
111
  /**
111
112
  * Generate filter query
112
113
  */
113
- export function generateFilterQuery<T = any>(filter?: Partial<FilterInput>): FilterQuery<T> | any {
114
+ export function generateFilterQuery<T = any>(
115
+ filter?: Partial<FilterInput>,
116
+ options?: { automaticObjectIdFiltering?: boolean }
117
+ ): FilterQuery<T> | any {
114
118
  // Check filter
115
119
  if (!filter) {
116
120
  return undefined;
117
121
  }
118
122
 
123
+ // Configuration
124
+ const config = {
125
+ automaticObjectIdFiltering: ConfigService.get('automaticObjectIdFiltering'),
126
+ ...options,
127
+ };
128
+
119
129
  // Init result
120
130
  const result: any = {};
121
131
 
@@ -124,15 +134,15 @@ export function generateFilterQuery<T = any>(filter?: Partial<FilterInput>): Fil
124
134
  switch (filter.combinedFilter.logicalOperator) {
125
135
  case LogicalOperatorEnum.AND:
126
136
  return {
127
- $and: filter.combinedFilter.filters.map((item: FilterInput) => generateFilterQuery(item)),
137
+ $and: filter.combinedFilter.filters.map((item: FilterInput) => generateFilterQuery(item, options)),
128
138
  };
129
139
  case LogicalOperatorEnum.NOR:
130
140
  return {
131
- $nor: filter.combinedFilter.filters.map((item: FilterInput) => generateFilterQuery(item)),
141
+ $nor: filter.combinedFilter.filters.map((item: FilterInput) => generateFilterQuery(item, options)),
132
142
  };
133
143
  case LogicalOperatorEnum.OR:
134
144
  return {
135
- $or: filter.combinedFilter.filters.map((item: FilterInput) => generateFilterQuery(item)),
145
+ $or: filter.combinedFilter.filters.map((item: FilterInput) => generateFilterQuery(item, options)),
136
146
  };
137
147
  }
138
148
  }
@@ -140,14 +150,27 @@ export function generateFilterQuery<T = any>(filter?: Partial<FilterInput>): Fil
140
150
  // Process single filter
141
151
  if (filter.singleFilter) {
142
152
  // Init variables
143
- const { not, options, field, convertToObjectId } = filter.singleFilter;
153
+ const { not, options, field, convertToObjectId, isReference } = filter.singleFilter;
144
154
  let value = filter.singleFilter.value;
145
155
 
146
156
  // Convert value to object ID(s)
147
- if (convertToObjectId) {
157
+ if (convertToObjectId || isReference) {
148
158
  value = getObjectIds(value);
149
159
  }
150
160
 
161
+ // Check if value is a string ID and automatic ObjectID filtering is activated
162
+ else if (config.automaticObjectIdFiltering && checkStringIds(value)) {
163
+ // Set both the string filter and the ObjectID filtering in an OR construction
164
+ const alternativeQuery = clone(filter.singleFilter, { circles: false });
165
+ alternativeQuery.value = getObjectIds(value);
166
+ return {
167
+ $or: [
168
+ generateFilterQuery(filter.singleFilter, Object.assign({}, config, { automaticObjectIdFiltering: false })),
169
+ generateFilterQuery(alternativeQuery, Object.assign({}, config, { automaticObjectIdFiltering: false })),
170
+ ],
171
+ };
172
+ }
173
+
151
174
  // Convert filter
152
175
  switch (filter.singleFilter.operator) {
153
176
  case ComparisonOperatorEnum.EQ:
@@ -23,6 +23,15 @@ export class SingleFilterInput extends CoreInput {
23
23
  @Field({ description: 'Name of the property to be used for the filter' })
24
24
  field: string = undefined;
25
25
 
26
+ /**
27
+ * Process value as reference
28
+ */
29
+ @Field({
30
+ description: 'Process value as reference',
31
+ nullable: true,
32
+ })
33
+ isReference?: boolean = undefined;
34
+
26
35
  /**
27
36
  * [Negate operator](https://docs.mongodb.com/manual/reference/operator/query/not/)
28
37
  */
@@ -13,6 +13,13 @@ import { MailjetOptions } from './mailjet-options.interface';
13
13
  * Options for the server
14
14
  */
15
15
  export interface IServerOptions {
16
+ /**
17
+ * Automatically detect ObjectIds in string values in FilterQueries
18
+ * and expand them as OR query with string and ObjectId
19
+ * See generateFilterQuery in Filter helper (src/core/common/helpers/filter.helper.ts)
20
+ */
21
+ automaticObjectIdFiltering?: boolean;
22
+
16
23
  /**
17
24
  * Cron jobs configuration object with the name of the cron job function as key
18
25
  * and the cron expression or config as value