directus 9.9.0 → 9.11.0

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.
Files changed (132) hide show
  1. package/README.md +1 -1
  2. package/dist/app.js +3 -0
  3. package/dist/auth/drivers/oauth2.d.ts +1 -1
  4. package/dist/auth/drivers/oauth2.js +14 -11
  5. package/dist/auth/drivers/openid.d.ts +1 -1
  6. package/dist/auth/drivers/openid.js +14 -11
  7. package/dist/cli/commands/schema/apply.js +4 -3
  8. package/dist/controllers/assets.js +8 -9
  9. package/dist/controllers/files.js +3 -0
  10. package/dist/database/helpers/date/dialects/sqlite.js +6 -2
  11. package/dist/database/helpers/fn/dialects/postgres.js +5 -1
  12. package/dist/database/migrations/20210225A-add-relations-sort-field.js +2 -1
  13. package/dist/database/migrations/20210506A-rename-interfaces.js +2 -1
  14. package/dist/database/migrations/20210802A-replace-groups.js +2 -1
  15. package/dist/database/migrations/20210805A-update-groups.js +2 -1
  16. package/dist/database/migrations/20210805B-change-image-metadata-structure.js +3 -2
  17. package/dist/database/migrations/20211007A-update-presets.js +5 -4
  18. package/dist/database/run-ast.js +11 -15
  19. package/dist/database/system-data/fields/collections.yaml +1 -1
  20. package/dist/env.js +8 -3
  21. package/dist/exceptions/index.d.ts +1 -0
  22. package/dist/exceptions/index.js +1 -0
  23. package/dist/exceptions/invalid-provider.d.ts +4 -0
  24. package/dist/exceptions/invalid-provider.js +10 -0
  25. package/dist/exceptions/range-not-satisfiable.d.ts +2 -2
  26. package/dist/exceptions/range-not-satisfiable.js +5 -1
  27. package/dist/middleware/graphql.js +2 -1
  28. package/dist/services/assets.js +27 -1
  29. package/dist/services/authentication.js +4 -1
  30. package/dist/services/collections.js +2 -0
  31. package/dist/services/fields.js +17 -8
  32. package/dist/services/graphql.js +75 -34
  33. package/dist/services/import-export.d.ts +1 -1
  34. package/dist/services/import-export.js +14 -11
  35. package/dist/services/items.d.ts +3 -3
  36. package/dist/services/items.js +20 -6
  37. package/dist/services/payload.d.ts +3 -3
  38. package/dist/services/payload.js +11 -8
  39. package/dist/services/specifications.js +1 -3
  40. package/dist/services/users.d.ts +4 -0
  41. package/dist/services/users.js +24 -1
  42. package/dist/utils/{apply-query.d.ts → apply-query/index.d.ts} +2 -1
  43. package/dist/utils/apply-query/index.js +394 -0
  44. package/dist/utils/apply-query/operators/between.operator.d.ts +2 -0
  45. package/dist/utils/apply-query/operators/between.operator.js +16 -0
  46. package/dist/utils/apply-query/operators/contains.operator.d.ts +2 -0
  47. package/dist/utils/apply-query/operators/contains.operator.js +9 -0
  48. package/dist/utils/apply-query/operators/ends-with.operator.d.ts +2 -0
  49. package/dist/utils/apply-query/operators/ends-with.operator.js +9 -0
  50. package/dist/utils/apply-query/operators/equals.operator.d.ts +2 -0
  51. package/dist/utils/apply-query/operators/equals.operator.js +9 -0
  52. package/dist/utils/apply-query/operators/greather-than-equals.operator.d.ts +2 -0
  53. package/dist/utils/apply-query/operators/greather-than-equals.operator.js +9 -0
  54. package/dist/utils/apply-query/operators/greather-than.operator.d.ts +2 -0
  55. package/dist/utils/apply-query/operators/greather-than.operator.js +9 -0
  56. package/dist/utils/apply-query/operators/in.operator.d.ts +2 -0
  57. package/dist/utils/apply-query/operators/in.operator.js +14 -0
  58. package/dist/utils/apply-query/operators/index.d.ts +3 -0
  59. package/dist/utils/apply-query/operators/index.js +72 -0
  60. package/dist/utils/apply-query/operators/insensitive-contains.operator.d.ts +2 -0
  61. package/dist/utils/apply-query/operators/insensitive-contains.operator.js +9 -0
  62. package/dist/utils/apply-query/operators/insensitive-ends-with.operator.d.ts +2 -0
  63. package/dist/utils/apply-query/operators/insensitive-ends-with.operator.js +9 -0
  64. package/dist/utils/apply-query/operators/insensitive-equals.operator.d.ts +2 -0
  65. package/dist/utils/apply-query/operators/insensitive-equals.operator.js +9 -0
  66. package/dist/utils/apply-query/operators/insensitive-not-contains.operator.d.ts +2 -0
  67. package/dist/utils/apply-query/operators/insensitive-not-contains.operator.js +9 -0
  68. package/dist/utils/apply-query/operators/insensitive-not-ends-with.operator.d.ts +2 -0
  69. package/dist/utils/apply-query/operators/insensitive-not-ends-with.operator.js +9 -0
  70. package/dist/utils/apply-query/operators/insensitive-not-equals.operator.d.ts +2 -0
  71. package/dist/utils/apply-query/operators/insensitive-not-equals.operator.js +9 -0
  72. package/dist/utils/apply-query/operators/insensitive-not-starts-with.operator.d.ts +2 -0
  73. package/dist/utils/apply-query/operators/insensitive-not-starts-with.operator.js +9 -0
  74. package/dist/utils/apply-query/operators/insensitive-starts-with.operator.d.ts +2 -0
  75. package/dist/utils/apply-query/operators/insensitive-starts-with.operator.js +9 -0
  76. package/dist/utils/apply-query/operators/intersects-bbox.operator.d.ts +2 -0
  77. package/dist/utils/apply-query/operators/intersects-bbox.operator.js +9 -0
  78. package/dist/utils/apply-query/operators/intersects.operator.d.ts +2 -0
  79. package/dist/utils/apply-query/operators/intersects.operator.js +9 -0
  80. package/dist/utils/apply-query/operators/is-empty.operator.d.ts +2 -0
  81. package/dist/utils/apply-query/operators/is-empty.operator.js +14 -0
  82. package/dist/utils/apply-query/operators/is-not-empty.operator.d.ts +2 -0
  83. package/dist/utils/apply-query/operators/is-not-empty.operator.js +14 -0
  84. package/dist/utils/apply-query/operators/is-not-null.operator.d.ts +2 -0
  85. package/dist/utils/apply-query/operators/is-not-null.operator.js +14 -0
  86. package/dist/utils/apply-query/operators/is-null.operator.d.ts +2 -0
  87. package/dist/utils/apply-query/operators/is-null.operator.js +14 -0
  88. package/dist/utils/apply-query/operators/less-than-equals.operator.d.ts +2 -0
  89. package/dist/utils/apply-query/operators/less-than-equals.operator.js +9 -0
  90. package/dist/utils/apply-query/operators/less-than.operator.d.ts +2 -0
  91. package/dist/utils/apply-query/operators/less-than.operator.js +9 -0
  92. package/dist/utils/apply-query/operators/not-between.operator.d.ts +2 -0
  93. package/dist/utils/apply-query/operators/not-between.operator.js +16 -0
  94. package/dist/utils/apply-query/operators/not-contains.operator.d.ts +2 -0
  95. package/dist/utils/apply-query/operators/not-contains.operator.js +9 -0
  96. package/dist/utils/apply-query/operators/not-ends-with.operator.d.ts +2 -0
  97. package/dist/utils/apply-query/operators/not-ends-with.operator.js +9 -0
  98. package/dist/utils/apply-query/operators/not-equals.operator.d.ts +2 -0
  99. package/dist/utils/apply-query/operators/not-equals.operator.js +9 -0
  100. package/dist/utils/apply-query/operators/not-in.operator.d.ts +2 -0
  101. package/dist/utils/apply-query/operators/not-in.operator.js +14 -0
  102. package/dist/utils/apply-query/operators/not-intersects-bbox.operator.d.ts +2 -0
  103. package/dist/utils/apply-query/operators/not-intersects-bbox.operator.js +9 -0
  104. package/dist/utils/apply-query/operators/not-intersects.operator.d.ts +2 -0
  105. package/dist/utils/apply-query/operators/not-intersects.operator.js +9 -0
  106. package/dist/utils/apply-query/operators/not-starts-with.operator.d.ts +2 -0
  107. package/dist/utils/apply-query/operators/not-starts-with.operator.js +9 -0
  108. package/dist/utils/apply-query/operators/operator-register.d.ts +13 -0
  109. package/dist/utils/apply-query/operators/operator-register.js +7 -0
  110. package/dist/utils/apply-query/operators/starts-with.operator.d.ts +2 -0
  111. package/dist/utils/apply-query/operators/starts-with.operator.js +9 -0
  112. package/dist/utils/apply-snapshot.d.ts +3 -3
  113. package/dist/utils/apply-snapshot.js +64 -49
  114. package/dist/utils/get-ast-from-query.js +10 -4
  115. package/dist/utils/get-column-path.d.ts +16 -0
  116. package/dist/utils/get-column-path.js +46 -0
  117. package/dist/utils/get-default-value.js +4 -3
  118. package/dist/utils/get-permissions.d.ts +1 -1
  119. package/dist/utils/get-permissions.js +9 -8
  120. package/dist/utils/get-relation-info.d.ts +7 -0
  121. package/dist/utils/get-relation-info.js +45 -0
  122. package/dist/utils/get-relation-type.d.ts +1 -1
  123. package/dist/utils/get-schema.js +5 -1
  124. package/dist/utils/get-snapshot.js +22 -4
  125. package/dist/utils/merge-permissions-for-share.js +1 -1
  126. package/dist/utils/parse-json.d.ts +5 -0
  127. package/dist/utils/parse-json.js +19 -0
  128. package/dist/utils/reduce-schema.js +18 -11
  129. package/dist/utils/sanitize-query.d.ts +1 -2
  130. package/dist/utils/sanitize-query.js +6 -5
  131. package/package.json +16 -18
  132. package/dist/utils/apply-query.js +0 -498
@@ -1,9 +1,10 @@
1
- import { Knex } from 'knex';
2
1
  import { Aggregate, Filter, Query, SchemaOverview } from '@directus/shared/types';
2
+ import { Knex } from 'knex';
3
3
  /**
4
4
  * Apply the Query to a given Knex query builder instance
5
5
  */
6
6
  export default function applyQuery(knex: Knex, collection: string, dbQuery: Knex.QueryBuilder, query: Query, schema: SchemaOverview, subQuery?: boolean): Knex.QueryBuilder;
7
+ export declare function applySort(knex: Knex, schema: SchemaOverview, rootQuery: Knex.QueryBuilder, rootSort: string[], collection: string, subQuery?: boolean): void;
7
8
  export declare function applyFilter(knex: Knex, schema: SchemaOverview, rootQuery: Knex.QueryBuilder, rootFilter: Filter, collection: string, subQuery?: boolean): Knex.QueryBuilder<any, any>;
8
9
  export declare function applySearch(schema: SchemaOverview, dbQuery: Knex.QueryBuilder, searchQuery: string, collection: string): Promise<void>;
9
10
  export declare function applyAggregate(dbQuery: Knex.QueryBuilder, aggregate: Aggregate, collection: string): void;
@@ -0,0 +1,394 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.applyAggregate = exports.applySearch = exports.applyFilter = exports.applySort = void 0;
7
+ const lodash_1 = require("lodash");
8
+ const nanoid_1 = require("nanoid");
9
+ const uuid_validate_1 = __importDefault(require("uuid-validate"));
10
+ const helpers_1 = require("../../database/helpers");
11
+ const invalid_query_1 = require("../../exceptions/invalid-query");
12
+ const get_column_1 = require("../get-column");
13
+ const get_column_path_1 = require("../get-column-path");
14
+ const get_relation_info_1 = require("../get-relation-info");
15
+ const operators_1 = __importDefault(require("./operators"));
16
+ const generateAlias = (0, nanoid_1.customAlphabet)('abcdefghijklmnopqrstuvwxyz', 5);
17
+ /**
18
+ * Apply the Query to a given Knex query builder instance
19
+ */
20
+ function applyQuery(knex, collection, dbQuery, query, schema, subQuery = false) {
21
+ if (query.sort) {
22
+ applySort(knex, schema, dbQuery, query.sort, collection, subQuery);
23
+ }
24
+ if (typeof query.limit === 'number' && query.limit !== -1) {
25
+ dbQuery.limit(query.limit);
26
+ }
27
+ if (query.offset) {
28
+ dbQuery.offset(query.offset);
29
+ }
30
+ if (query.page && query.limit && query.limit !== -1) {
31
+ dbQuery.offset(query.limit * (query.page - 1));
32
+ }
33
+ if (query.search) {
34
+ applySearch(schema, dbQuery, query.search, collection);
35
+ }
36
+ if (query.group) {
37
+ dbQuery.groupBy(query.group.map((column) => (0, get_column_1.getColumn)(knex, collection, column, false, schema)));
38
+ }
39
+ if (query.aggregate) {
40
+ applyAggregate(dbQuery, query.aggregate, collection);
41
+ }
42
+ if (query.filter) {
43
+ applyFilter(knex, schema, dbQuery, query.filter, collection, subQuery);
44
+ }
45
+ return dbQuery;
46
+ }
47
+ exports.default = applyQuery;
48
+ function addJoin({ path, collection, aliasMap, rootQuery, subQuery, schema, relations, knex }) {
49
+ path = (0, lodash_1.clone)(path);
50
+ followRelation(path);
51
+ function followRelation(pathParts, parentCollection = collection, parentAlias) {
52
+ /**
53
+ * For A2M fields, the path can contain an optional collection scope <field>:<scope>
54
+ */
55
+ const pathRoot = pathParts[0].split(':')[0];
56
+ const { relation, relationType } = (0, get_relation_info_1.getRelationInfo)(relations, parentCollection, pathRoot);
57
+ if (!relation) {
58
+ return;
59
+ }
60
+ const alias = generateAlias();
61
+ (0, lodash_1.set)(aliasMap, parentAlias ? [parentAlias, ...pathParts] : pathParts, alias);
62
+ if (relationType === 'm2o') {
63
+ rootQuery.leftJoin({ [alias]: relation.related_collection }, `${parentAlias || parentCollection}.${relation.field}`, `${alias}.${schema.collections[relation.related_collection].primary}`);
64
+ }
65
+ if (relationType === 'a2o') {
66
+ const pathScope = pathParts[0].split(':')[1];
67
+ if (!pathScope) {
68
+ throw new invalid_query_1.InvalidQueryException(`You have to provide a collection scope when sorting or filtering on a many-to-any item`);
69
+ }
70
+ rootQuery.leftJoin({ [alias]: pathScope }, (joinClause) => {
71
+ joinClause
72
+ .onVal(relation.meta.one_collection_field, '=', pathScope)
73
+ .andOn(`${parentAlias || parentCollection}.${relation.field}`, '=', knex.raw(`CAST(?? AS CHAR(255))`, `${alias}.${schema.collections[pathScope].primary}`));
74
+ });
75
+ }
76
+ if (relationType === 'o2a') {
77
+ rootQuery.leftJoin({ [alias]: relation.collection }, (joinClause) => {
78
+ joinClause
79
+ .onVal(relation.meta.one_collection_field, '=', parentCollection)
80
+ .andOn(`${alias}.${relation.field}`, '=', knex.raw(`CAST(?? AS CHAR(255))`, `${parentAlias || parentCollection}.${schema.collections[parentCollection].primary}`));
81
+ });
82
+ }
83
+ // Still join o2m relations when in subquery OR when the o2m relation is not at the root level
84
+ if (relationType === 'o2m' && (subQuery === true || parentAlias !== undefined)) {
85
+ rootQuery.leftJoin({ [alias]: relation.collection }, `${parentAlias || parentCollection}.${schema.collections[relation.related_collection].primary}`, `${alias}.${relation.field}`);
86
+ }
87
+ if (relationType === 'm2o' || subQuery === true || (relationType === 'o2m' && parentAlias !== undefined)) {
88
+ let parent;
89
+ if (relationType === 'm2o') {
90
+ parent = relation.related_collection;
91
+ }
92
+ else if (relationType === 'a2o') {
93
+ const pathScope = pathParts[0].split(':')[1];
94
+ if (!pathScope) {
95
+ throw new invalid_query_1.InvalidQueryException(`You have to provide a collection scope when sorting or filtering on a many-to-any item`);
96
+ }
97
+ parent = pathScope;
98
+ }
99
+ else {
100
+ parent = relation.collection;
101
+ }
102
+ pathParts.shift();
103
+ if (pathParts.length) {
104
+ followRelation(pathParts, parent, alias);
105
+ }
106
+ }
107
+ }
108
+ }
109
+ function applySort(knex, schema, rootQuery, rootSort, collection, subQuery = false) {
110
+ const relations = schema.relations;
111
+ const aliasMap = {};
112
+ rootQuery.orderBy(rootSort.map((sortField) => {
113
+ const column = sortField.split('.');
114
+ let order = 'asc';
115
+ if (column.length > 1) {
116
+ if (sortField.startsWith('-')) {
117
+ order = 'desc';
118
+ }
119
+ if (column[0].startsWith('-')) {
120
+ column[0] = column[0].substring(1);
121
+ }
122
+ addJoin({
123
+ path: column,
124
+ collection,
125
+ aliasMap,
126
+ rootQuery,
127
+ subQuery,
128
+ schema,
129
+ relations,
130
+ knex,
131
+ });
132
+ const colPath = (0, get_column_path_1.getColumnPath)({ path: column, collection, aliasMap, relations }) || '';
133
+ const [alias, field] = colPath.split('.');
134
+ return {
135
+ order,
136
+ column: (0, get_column_1.getColumn)(knex, alias, field, false, schema),
137
+ };
138
+ }
139
+ let col = column[0];
140
+ if (sortField.startsWith('-')) {
141
+ col = column[0].substring(1);
142
+ order = 'desc';
143
+ }
144
+ return {
145
+ order,
146
+ column: (0, get_column_1.getColumn)(knex, collection, col, false, schema),
147
+ };
148
+ }));
149
+ }
150
+ exports.applySort = applySort;
151
+ function applyFilter(knex, schema, rootQuery, rootFilter, collection, subQuery = false) {
152
+ const helpers = (0, helpers_1.getHelpers)(knex);
153
+ const relations = schema.relations;
154
+ const aliasMap = {};
155
+ addJoins(rootQuery, rootFilter, collection);
156
+ addWhereClauses(knex, rootQuery, rootFilter, collection);
157
+ return rootQuery;
158
+ function isNegativeOperator(operator) {
159
+ return operator.indexOf('_n') === 0;
160
+ }
161
+ function addJoins(dbQuery, filter, collection) {
162
+ for (const [key, value] of Object.entries(filter)) {
163
+ if (key === '_or' || key === '_and') {
164
+ // If the _or array contains an empty object (full permissions), we should short-circuit and ignore all other
165
+ // permission checks, as {} already matches full permissions.
166
+ if (key === '_or' && value.some((subFilter) => Object.keys(subFilter).length === 0))
167
+ continue;
168
+ value.forEach((subFilter) => {
169
+ addJoins(dbQuery, subFilter, collection);
170
+ });
171
+ continue;
172
+ }
173
+ const filterPath = getFilterPath(key, value);
174
+ if (filterPath.length > 1) {
175
+ addJoin({
176
+ path: filterPath,
177
+ collection,
178
+ knex,
179
+ schema,
180
+ relations,
181
+ subQuery,
182
+ rootQuery,
183
+ aliasMap,
184
+ });
185
+ }
186
+ }
187
+ }
188
+ function callbackSubqueryRelation(relation, value) {
189
+ return function (subQueryKnex) {
190
+ const field = relation.field;
191
+ const collection = relation.collection;
192
+ const column = `${collection}.${field}`;
193
+ subQueryKnex.from(collection).whereRaw(`${field} = ${column}`);
194
+ applyQuery(knex, relation.collection, subQueryKnex, {
195
+ filter: value,
196
+ }, schema, true);
197
+ };
198
+ }
199
+ function inverseFilters(value) {
200
+ for (const field in value) {
201
+ for (const operator in value[field]) {
202
+ let inverseOperator = operator;
203
+ if (isNegativeOperator(operator)) {
204
+ inverseOperator = '_' + operator.substring(2);
205
+ }
206
+ else {
207
+ inverseOperator = '_n' + operator.substring(1);
208
+ }
209
+ value[field][inverseOperator] = value[field][operator];
210
+ delete value[field][operator];
211
+ }
212
+ }
213
+ }
214
+ function addWhereClauses(knex, dbQuery, filter, collection, logical = 'and') {
215
+ for (const [key, value] of Object.entries(filter)) {
216
+ if (key === '_or' || key === '_and') {
217
+ // If the _or array contains an empty object (full permissions), we should short-circuit and ignore all other
218
+ // permission checks, as {} already matches full permissions.
219
+ if (key === '_or' && value.some((subFilter) => Object.keys(subFilter).length === 0)) {
220
+ continue;
221
+ }
222
+ /** @NOTE this callback function isn't called until Knex runs the query */
223
+ dbQuery[logical].where((subQuery) => {
224
+ value.forEach((subFilter) => {
225
+ addWhereClauses(knex, subQuery, subFilter, collection, key === '_and' ? 'and' : 'or');
226
+ });
227
+ });
228
+ continue;
229
+ }
230
+ const filterPath = getFilterPath(key, value);
231
+ /**
232
+ * For A2M fields, the path can contain an optional collection scope <field>:<scope>
233
+ */
234
+ const pathRoot = filterPath[0].split(':')[0];
235
+ const { relation, relationType } = (0, get_relation_info_1.getRelationInfo)(relations, collection, pathRoot);
236
+ const { operator: filterOperator, value: filterValue } = getOperation(key, value);
237
+ if (relationType === 'm2o' || relationType === 'a2o' || relationType === null) {
238
+ if (filterPath.length > 1) {
239
+ const columnName = (0, get_column_path_1.getColumnPath)({ path: filterPath, collection, relations, aliasMap });
240
+ if (!columnName)
241
+ continue;
242
+ applyFilterToQuery(columnName, filterOperator, filterValue, logical);
243
+ }
244
+ else {
245
+ applyFilterToQuery(`${collection}.${filterPath[0]}`, filterOperator, filterValue, logical);
246
+ }
247
+ }
248
+ else if (subQuery === false || filterPath.length > 1) {
249
+ if (!relation)
250
+ continue;
251
+ let pkField = `${collection}.${schema.collections[relation.related_collection].primary}`;
252
+ if (relationType === 'o2a') {
253
+ pkField = knex.raw(`CAST(?? AS CHAR(255))`, [pkField]);
254
+ }
255
+ if (isNegativeOperator(filterOperator)) {
256
+ inverseFilters(value);
257
+ dbQuery[logical].whereNotExists(callbackSubqueryRelation(relation, value));
258
+ }
259
+ else {
260
+ dbQuery[logical].whereExists(callbackSubqueryRelation(relation, value));
261
+ }
262
+ }
263
+ }
264
+ function applyFilterToQuery(key, operator, compareValue, logical = 'and') {
265
+ const [table, column] = key.split('.');
266
+ // Is processed through Knex.Raw, so should be safe to string-inject into these where queries
267
+ const selectionRaw = (0, get_column_1.getColumn)(knex, table, column, false, schema);
268
+ // Knex supports "raw" in the columnName parameter, but isn't typed as such. Too bad..
269
+ // See https://github.com/knex/knex/issues/4518 @TODO remove as any once knex is updated
270
+ const [collection, field] = key.split('.');
271
+ if (collection in schema.collections && field in schema.collections[collection].fields) {
272
+ const type = schema.collections[collection].fields[field].type;
273
+ if (['date', 'dateTime', 'time', 'timestamp'].includes(type)) {
274
+ if (Array.isArray(compareValue)) {
275
+ compareValue = compareValue.map((val) => helpers.date.parse(val));
276
+ }
277
+ else {
278
+ compareValue = helpers.date.parse(compareValue);
279
+ }
280
+ }
281
+ if (['bigInteger', 'integer', 'float', 'decimal'].includes(type)) {
282
+ if (Array.isArray(compareValue)) {
283
+ compareValue = compareValue.map((val) => Number(val));
284
+ }
285
+ else {
286
+ compareValue = Number(compareValue);
287
+ }
288
+ }
289
+ }
290
+ // The following fields however, require a value to be run. If no value is passed, we
291
+ // ignore them. This allows easier use in GraphQL, where you wouldn't be able to
292
+ // conditionally build out your filter structure (#4471)
293
+ if (compareValue === undefined)
294
+ return;
295
+ if (Array.isArray(compareValue)) {
296
+ // Tip: when using a `[Type]` type in GraphQL, but don't provide the variable, it'll be
297
+ // reported as [undefined].
298
+ // We need to remove any undefined values, as they are useless
299
+ compareValue = compareValue.filter((val) => val !== undefined);
300
+ }
301
+ if (operator in operators_1.default) {
302
+ operators_1.default[operator].apply({
303
+ query: dbQuery[logical],
304
+ helpers,
305
+ selectionRaw,
306
+ compareValue,
307
+ });
308
+ }
309
+ else {
310
+ throw new Error(`Operator ${operator} not supported`);
311
+ }
312
+ }
313
+ }
314
+ }
315
+ exports.applyFilter = applyFilter;
316
+ async function applySearch(schema, dbQuery, searchQuery, collection) {
317
+ const fields = Object.entries(schema.collections[collection].fields);
318
+ dbQuery.andWhere(function () {
319
+ fields.forEach(([name, field]) => {
320
+ if (['text', 'string'].includes(field.type)) {
321
+ this.orWhereRaw(`LOWER(??) LIKE ?`, [`${collection}.${name}`, `%${searchQuery.toLowerCase()}%`]);
322
+ }
323
+ else if (['bigInteger', 'integer', 'decimal', 'float'].includes(field.type)) {
324
+ const number = Number(searchQuery);
325
+ if (!isNaN(number))
326
+ this.orWhere({ [`${collection}.${name}`]: number });
327
+ }
328
+ else if (field.type === 'uuid' && (0, uuid_validate_1.default)(searchQuery)) {
329
+ this.orWhere({ [`${collection}.${name}`]: searchQuery });
330
+ }
331
+ });
332
+ });
333
+ }
334
+ exports.applySearch = applySearch;
335
+ function applyAggregate(dbQuery, aggregate, collection) {
336
+ for (const [operation, fields] of Object.entries(aggregate)) {
337
+ if (!fields)
338
+ continue;
339
+ for (const field of fields) {
340
+ if (operation === 'avg') {
341
+ dbQuery.avg(`${collection}.${field}`, { as: `avg->${field}` });
342
+ }
343
+ if (operation === 'avgDistinct') {
344
+ dbQuery.avgDistinct(`${collection}.${field}`, { as: `avgDistinct->${field}` });
345
+ }
346
+ if (operation === 'countAll') {
347
+ dbQuery.count('*', { as: 'countAll' });
348
+ }
349
+ if (operation === 'count') {
350
+ if (field === '*') {
351
+ dbQuery.count('*', { as: 'count' });
352
+ }
353
+ else {
354
+ dbQuery.count(`${collection}.${field}`, { as: `count->${field}` });
355
+ }
356
+ }
357
+ if (operation === 'countDistinct') {
358
+ dbQuery.countDistinct(`${collection}.${field}`, { as: `countDistinct->${field}` });
359
+ }
360
+ if (operation === 'sum') {
361
+ dbQuery.sum(`${collection}.${field}`, { as: `sum->${field}` });
362
+ }
363
+ if (operation === 'sumDistinct') {
364
+ dbQuery.sumDistinct(`${collection}.${field}`, { as: `sumDistinct->${field}` });
365
+ }
366
+ if (operation === 'min') {
367
+ dbQuery.min(`${collection}.${field}`, { as: `min->${field}` });
368
+ }
369
+ if (operation === 'max') {
370
+ dbQuery.max(`${collection}.${field}`, { as: `max->${field}` });
371
+ }
372
+ }
373
+ }
374
+ }
375
+ exports.applyAggregate = applyAggregate;
376
+ function getFilterPath(key, value) {
377
+ const path = [key];
378
+ if (typeof Object.keys(value)[0] === 'string' && Object.keys(value)[0].startsWith('_') === true) {
379
+ return path;
380
+ }
381
+ if ((0, lodash_1.isPlainObject)(value)) {
382
+ path.push(...getFilterPath(Object.keys(value)[0], Object.values(value)[0]));
383
+ }
384
+ return path;
385
+ }
386
+ function getOperation(key, value) {
387
+ if (key.startsWith('_') && key !== '_and' && key !== '_or') {
388
+ return { operator: key, value };
389
+ }
390
+ else if ((0, lodash_1.isPlainObject)(value) === false) {
391
+ return { operator: '_eq', value };
392
+ }
393
+ return getOperation(Object.keys(value)[0], Object.values(value)[0]);
394
+ }
@@ -0,0 +1,2 @@
1
+ declare const _default: import("./operator-register").OperatorRegister;
2
+ export default _default;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const operator_register_1 = require("./operator-register");
4
+ exports.default = (0, operator_register_1.registerOperator)({
5
+ operator: '_between',
6
+ apply: ({ query, selectionRaw, compareValue }) => {
7
+ let value = compareValue;
8
+ if (typeof value === 'string')
9
+ value = value.split(',');
10
+ if (!(value instanceof Array))
11
+ throw new Error('Invalid value for between operator');
12
+ if (value.length !== 2)
13
+ throw new Error('Expected two values for between operator');
14
+ query.whereBetween(selectionRaw, value);
15
+ },
16
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("./operator-register").OperatorRegister;
2
+ export default _default;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const operator_register_1 = require("./operator-register");
4
+ exports.default = (0, operator_register_1.registerOperator)({
5
+ operator: '_contains',
6
+ apply: ({ query, selectionRaw, compareValue }) => {
7
+ query.where(selectionRaw, 'like', `%${compareValue}%`);
8
+ },
9
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("./operator-register").OperatorRegister;
2
+ export default _default;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const operator_register_1 = require("./operator-register");
4
+ exports.default = (0, operator_register_1.registerOperator)({
5
+ operator: '_ends_with',
6
+ apply: ({ query, selectionRaw, compareValue }) => {
7
+ query.where(selectionRaw, 'like', `%${compareValue}`);
8
+ },
9
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("./operator-register").OperatorRegister;
2
+ export default _default;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const operator_register_1 = require("./operator-register");
4
+ exports.default = (0, operator_register_1.registerOperator)({
5
+ operator: '_eq',
6
+ apply: ({ query, selectionRaw, compareValue }) => {
7
+ query.where(selectionRaw, '=', compareValue);
8
+ },
9
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("./operator-register").OperatorRegister;
2
+ export default _default;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const operator_register_1 = require("./operator-register");
4
+ exports.default = (0, operator_register_1.registerOperator)({
5
+ operator: '_gte',
6
+ apply: ({ query, selectionRaw, compareValue }) => {
7
+ query.where(selectionRaw, '>=', compareValue);
8
+ },
9
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("./operator-register").OperatorRegister;
2
+ export default _default;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const operator_register_1 = require("./operator-register");
4
+ exports.default = (0, operator_register_1.registerOperator)({
5
+ operator: '_gt',
6
+ apply: ({ query, selectionRaw, compareValue }) => {
7
+ query.where(selectionRaw, '>', compareValue);
8
+ },
9
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("./operator-register").OperatorRegister;
2
+ export default _default;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const operator_register_1 = require("./operator-register");
4
+ exports.default = (0, operator_register_1.registerOperator)({
5
+ operator: '_in',
6
+ apply: ({ query, selectionRaw, compareValue }) => {
7
+ let value = compareValue;
8
+ if (typeof value === 'string')
9
+ value = value.split(',');
10
+ if (!(value instanceof Array))
11
+ throw new Error('Invalid value for in operator');
12
+ query.whereIn(selectionRaw, value);
13
+ },
14
+ });
@@ -0,0 +1,3 @@
1
+ import { OperatorRegister } from './operator-register';
2
+ declare const _default: Record<string, OperatorRegister>;
3
+ export default _default;
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const between_operator_1 = __importDefault(require("./between.operator"));
7
+ const contains_operator_1 = __importDefault(require("./contains.operator"));
8
+ const ends_with_operator_1 = __importDefault(require("./ends-with.operator"));
9
+ const equals_operator_1 = __importDefault(require("./equals.operator"));
10
+ const greather_than_equals_operator_1 = __importDefault(require("./greather-than-equals.operator"));
11
+ const greather_than_operator_1 = __importDefault(require("./greather-than.operator"));
12
+ const in_operator_1 = __importDefault(require("./in.operator"));
13
+ const insensitive_contains_operator_1 = __importDefault(require("./insensitive-contains.operator"));
14
+ const insensitive_ends_with_operator_1 = __importDefault(require("./insensitive-ends-with.operator"));
15
+ const insensitive_equals_operator_1 = __importDefault(require("./insensitive-equals.operator"));
16
+ const insensitive_not_contains_operator_1 = __importDefault(require("./insensitive-not-contains.operator"));
17
+ const insensitive_not_ends_with_operator_1 = __importDefault(require("./insensitive-not-ends-with.operator"));
18
+ const insensitive_not_equals_operator_1 = __importDefault(require("./insensitive-not-equals.operator"));
19
+ const insensitive_not_starts_with_operator_1 = __importDefault(require("./insensitive-not-starts-with.operator"));
20
+ const insensitive_starts_with_operator_1 = __importDefault(require("./insensitive-starts-with.operator"));
21
+ const intersects_bbox_operator_1 = __importDefault(require("./intersects-bbox.operator"));
22
+ const intersects_operator_1 = __importDefault(require("./intersects.operator"));
23
+ const is_empty_operator_1 = __importDefault(require("./is-empty.operator"));
24
+ const is_not_empty_operator_1 = __importDefault(require("./is-not-empty.operator"));
25
+ const is_not_null_operator_1 = __importDefault(require("./is-not-null.operator"));
26
+ const is_null_operator_1 = __importDefault(require("./is-null.operator"));
27
+ const less_than_equals_operator_1 = __importDefault(require("./less-than-equals.operator"));
28
+ const less_than_operator_1 = __importDefault(require("./less-than.operator"));
29
+ const not_between_operator_1 = __importDefault(require("./not-between.operator"));
30
+ const not_contains_operator_1 = __importDefault(require("./not-contains.operator"));
31
+ const not_ends_with_operator_1 = __importDefault(require("./not-ends-with.operator"));
32
+ const not_equals_operator_1 = __importDefault(require("./not-equals.operator"));
33
+ const not_in_operator_1 = __importDefault(require("./not-in.operator"));
34
+ const not_intersects_bbox_operator_1 = __importDefault(require("./not-intersects-bbox.operator"));
35
+ const not_intersects_operator_1 = __importDefault(require("./not-intersects.operator"));
36
+ const not_starts_with_operator_1 = __importDefault(require("./not-starts-with.operator"));
37
+ const starts_with_operator_1 = __importDefault(require("./starts-with.operator"));
38
+ const operators = [
39
+ is_null_operator_1.default,
40
+ is_not_null_operator_1.default,
41
+ is_empty_operator_1.default,
42
+ is_not_empty_operator_1.default,
43
+ equals_operator_1.default,
44
+ not_equals_operator_1.default,
45
+ contains_operator_1.default,
46
+ not_contains_operator_1.default,
47
+ starts_with_operator_1.default,
48
+ not_starts_with_operator_1.default,
49
+ ends_with_operator_1.default,
50
+ not_ends_with_operator_1.default,
51
+ greather_than_operator_1.default,
52
+ greather_than_equals_operator_1.default,
53
+ less_than_operator_1.default,
54
+ less_than_equals_operator_1.default,
55
+ in_operator_1.default,
56
+ not_in_operator_1.default,
57
+ between_operator_1.default,
58
+ not_between_operator_1.default,
59
+ intersects_operator_1.default,
60
+ not_intersects_operator_1.default,
61
+ intersects_bbox_operator_1.default,
62
+ not_intersects_bbox_operator_1.default,
63
+ insensitive_contains_operator_1.default,
64
+ insensitive_not_contains_operator_1.default,
65
+ insensitive_equals_operator_1.default,
66
+ insensitive_not_equals_operator_1.default,
67
+ insensitive_starts_with_operator_1.default,
68
+ insensitive_not_starts_with_operator_1.default,
69
+ insensitive_ends_with_operator_1.default,
70
+ insensitive_not_ends_with_operator_1.default,
71
+ ];
72
+ exports.default = operators.reduce((a, b) => ({ ...a, [b.operator]: b }), {});
@@ -0,0 +1,2 @@
1
+ declare const _default: import("./operator-register").OperatorRegister;
2
+ export default _default;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const operator_register_1 = require("./operator-register");
4
+ exports.default = (0, operator_register_1.registerOperator)({
5
+ operator: '_icontains',
6
+ apply: ({ query, selectionRaw, compareValue }) => {
7
+ query.whereRaw(`LOWER(??) LIKE ?`, [selectionRaw, `%${compareValue === null || compareValue === void 0 ? void 0 : compareValue.toLowerCase()}%`]);
8
+ },
9
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("./operator-register").OperatorRegister;
2
+ export default _default;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const operator_register_1 = require("./operator-register");
4
+ exports.default = (0, operator_register_1.registerOperator)({
5
+ operator: '_iends_with',
6
+ apply: ({ query, selectionRaw, compareValue }) => {
7
+ query.whereRaw(`LOWER(??) LIKE ?`, [selectionRaw, `%${compareValue === null || compareValue === void 0 ? void 0 : compareValue.toLowerCase()}`]);
8
+ },
9
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("./operator-register").OperatorRegister;
2
+ export default _default;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const operator_register_1 = require("./operator-register");
4
+ exports.default = (0, operator_register_1.registerOperator)({
5
+ operator: '_ieq',
6
+ apply: ({ query, selectionRaw, compareValue }) => {
7
+ query.whereRaw(`LOWER(??) = ?`, [selectionRaw, `${compareValue === null || compareValue === void 0 ? void 0 : compareValue.toLowerCase()}`]);
8
+ },
9
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("./operator-register").OperatorRegister;
2
+ export default _default;