directus 9.1.0 → 9.2.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.
Files changed (86) hide show
  1. package/dist/auth/drivers/ldap.js +5 -2
  2. package/dist/auth/drivers/oauth2.d.ts +1 -1
  3. package/dist/auth/drivers/oauth2.js +46 -19
  4. package/dist/auth/drivers/openid.d.ts +1 -1
  5. package/dist/auth/drivers/openid.js +34 -17
  6. package/dist/auth.js +5 -3
  7. package/dist/cli/commands/database/install.js +2 -4
  8. package/dist/cli/commands/schema/apply.js +26 -10
  9. package/dist/controllers/assets.js +0 -27
  10. package/dist/controllers/auth.js +7 -2
  11. package/dist/controllers/extensions.js +1 -1
  12. package/dist/database/{functions/types.d.ts → helpers/date/dialects/mssql.d.ts} +2 -1
  13. package/dist/database/{functions → helpers/date}/dialects/mssql.js +4 -6
  14. package/dist/database/{functions → helpers/date}/dialects/mysql.d.ts +2 -4
  15. package/dist/database/{functions → helpers/date}/dialects/mysql.js +4 -6
  16. package/dist/database/{functions/dialects/mssql.d.ts → helpers/date/dialects/oracle.d.ts} +2 -4
  17. package/dist/database/{functions → helpers/date}/dialects/oracle.js +4 -6
  18. package/dist/database/helpers/date/dialects/postgres.d.ts +12 -0
  19. package/dist/database/{functions → helpers/date}/dialects/postgres.js +4 -6
  20. package/dist/database/{functions → helpers/date}/dialects/sqlite.d.ts +3 -4
  21. package/dist/database/helpers/date/dialects/sqlite.js +35 -0
  22. package/dist/database/helpers/date/index.d.ts +6 -0
  23. package/dist/database/helpers/date/index.js +15 -0
  24. package/dist/database/helpers/date/types.d.ts +13 -0
  25. package/dist/database/helpers/date/types.js +10 -0
  26. package/dist/database/helpers/geometry/dialects/mssql.d.ts +14 -0
  27. package/dist/database/helpers/geometry/dialects/mssql.js +36 -0
  28. package/dist/database/helpers/geometry/dialects/mysql.d.ts +7 -0
  29. package/dist/database/helpers/geometry/dialects/mysql.js +16 -0
  30. package/dist/database/helpers/geometry/dialects/oracle.d.ts +15 -0
  31. package/dist/database/helpers/geometry/dialects/oracle.js +39 -0
  32. package/dist/database/helpers/geometry/dialects/postgres.d.ts +10 -0
  33. package/dist/database/helpers/geometry/dialects/postgres.js +23 -0
  34. package/dist/database/helpers/geometry/dialects/redshift.d.ts +7 -0
  35. package/dist/database/helpers/geometry/dialects/redshift.js +16 -0
  36. package/dist/database/helpers/geometry/dialects/sqlite.d.ts +6 -0
  37. package/dist/database/helpers/geometry/dialects/sqlite.js +14 -0
  38. package/dist/database/helpers/geometry/index.d.ts +6 -0
  39. package/dist/database/helpers/geometry/index.js +15 -0
  40. package/dist/database/helpers/{geometry.d.ts → geometry/types.d.ts} +3 -7
  41. package/dist/database/helpers/geometry/types.js +54 -0
  42. package/dist/database/helpers/index.d.ts +8 -0
  43. package/dist/database/helpers/index.js +33 -0
  44. package/dist/database/helpers/types.d.ts +5 -0
  45. package/dist/database/helpers/types.js +9 -0
  46. package/dist/database/index.js +6 -6
  47. package/dist/database/run-ast.js +5 -5
  48. package/dist/database/seeds/run.js +3 -3
  49. package/dist/database/system-data/fields/notifications.yaml +1 -0
  50. package/dist/env.js +1 -0
  51. package/dist/exceptions/index.d.ts +1 -0
  52. package/dist/exceptions/index.js +1 -0
  53. package/dist/exceptions/invalid-token.d.ts +4 -0
  54. package/dist/exceptions/invalid-token.js +10 -0
  55. package/dist/extensions.js +17 -2
  56. package/dist/middleware/sanitize-query.js +1 -1
  57. package/dist/services/activity.js +7 -2
  58. package/dist/services/assets.js +14 -0
  59. package/dist/services/fields.d.ts +2 -0
  60. package/dist/services/fields.js +57 -26
  61. package/dist/services/files.d.ts +1 -1
  62. package/dist/services/files.js +13 -11
  63. package/dist/services/graphql.js +3 -0
  64. package/dist/services/items.js +18 -29
  65. package/dist/services/payload.d.ts +2 -0
  66. package/dist/services/payload.js +3 -3
  67. package/dist/utils/apply-query.js +9 -12
  68. package/dist/utils/apply-snapshot.js +27 -28
  69. package/dist/utils/get-column.js +2 -2
  70. package/dist/utils/get-default-index-name.js +2 -2
  71. package/dist/utils/get-local-type.js +1 -12
  72. package/dist/utils/sanitize-query.js +1 -12
  73. package/dist/utils/validate-query.js +1 -1
  74. package/dist/webhooks.js +16 -24
  75. package/package.json +15 -15
  76. package/dist/database/functions/dialects/oracle.d.ts +0 -14
  77. package/dist/database/functions/dialects/postgres.d.ts +0 -14
  78. package/dist/database/functions/dialects/sqlite.js +0 -33
  79. package/dist/database/functions/index.d.ts +0 -3
  80. package/dist/database/functions/index.js +0 -26
  81. package/dist/database/functions/types.js +0 -2
  82. package/dist/database/helpers/date.d.ts +0 -8
  83. package/dist/database/helpers/date.js +0 -44
  84. package/dist/database/helpers/geometry.js +0 -189
  85. package/dist/utils/get-simple-hash.d.ts +0 -5
  86. package/dist/utils/get-simple-hash.js +0 -15
@@ -0,0 +1,4 @@
1
+ import { BaseException } from '@directus/shared/exceptions';
2
+ export declare class InvalidTokenException extends BaseException {
3
+ constructor(message?: string);
4
+ }
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.InvalidTokenException = void 0;
4
+ const exceptions_1 = require("@directus/shared/exceptions");
5
+ class InvalidTokenException extends exceptions_1.BaseException {
6
+ constructor(message = 'Invalid token') {
7
+ super(message, 403, 'INVALID_TOKEN');
8
+ }
9
+ }
10
+ exports.InvalidTokenException = InvalidTokenException;
@@ -31,6 +31,7 @@ const database_1 = __importDefault(require("./database"));
31
31
  const emitter_1 = __importDefault(require("./emitter"));
32
32
  const env_1 = __importDefault(require("./env"));
33
33
  const exceptions = __importStar(require("./exceptions"));
34
+ const sharedExceptions = __importStar(require("@directus/shared/exceptions"));
34
35
  const logger_1 = __importDefault(require("./logger"));
35
36
  const fs_extra_1 = __importDefault(require("fs-extra"));
36
37
  const get_schema_1 = require("./utils/get-schema");
@@ -231,7 +232,14 @@ class ExtensionManager {
231
232
  }
232
233
  },
233
234
  };
234
- register(registerFunctions, { services, exceptions, env: env_1.default, database: (0, database_1.default)(), logger: logger_1.default, getSchema: get_schema_1.getSchema });
235
+ register(registerFunctions, {
236
+ services,
237
+ exceptions: { ...exceptions, ...sharedExceptions },
238
+ env: env_1.default,
239
+ database: (0, database_1.default)(),
240
+ logger: logger_1.default,
241
+ getSchema: get_schema_1.getSchema,
242
+ });
235
243
  }
236
244
  registerEndpoint(endpoint, router) {
237
245
  const endpointPath = path_1.default.resolve(endpoint.path, endpoint.entrypoint || '');
@@ -241,7 +249,14 @@ class ExtensionManager {
241
249
  const routeName = typeof mod === 'function' ? endpoint.name : mod.id;
242
250
  const scopedRouter = express_1.default.Router();
243
251
  router.use(`/${routeName}`, scopedRouter);
244
- register(scopedRouter, { services, exceptions, env: env_1.default, database: (0, database_1.default)(), logger: logger_1.default, getSchema: get_schema_1.getSchema });
252
+ register(scopedRouter, {
253
+ services,
254
+ exceptions: { ...exceptions, ...sharedExceptions },
255
+ env: env_1.default,
256
+ database: (0, database_1.default)(),
257
+ logger: logger_1.default,
258
+ getSchema: get_schema_1.getSchema,
259
+ });
245
260
  this.apiEndpoints.push({
246
261
  path: endpointPath,
247
262
  });
@@ -6,7 +6,7 @@
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  const sanitize_query_1 = require("../utils/sanitize-query");
8
8
  const validate_query_1 = require("../utils/validate-query");
9
- const sanitizeQueryMiddleware = (req, res, next) => {
9
+ const sanitizeQueryMiddleware = (req, _res, next) => {
10
10
  req.sanitizedQuery = {};
11
11
  if (!req.query)
12
12
  return;
@@ -15,6 +15,7 @@ const logger_1 = __importDefault(require("../logger"));
15
15
  const user_name_1 = require("../utils/user-name");
16
16
  const lodash_1 = require("lodash");
17
17
  const env_1 = __importDefault(require("../env"));
18
+ const uuid_validate_1 = __importDefault(require("uuid-validate"));
18
19
  class ActivityService extends index_1.ItemsService {
19
20
  constructor(options) {
20
21
  super('directus_activity', options);
@@ -55,9 +56,13 @@ class ActivityService extends index_1.ItemsService {
55
56
  }, {});
56
57
  let comment = data.comment;
57
58
  for (const mention of mentions) {
58
- comment = comment.replace(mention, (_h = userPreviews[mention.substring(1)]) !== null && _h !== void 0 ? _h : '@Unknown User');
59
+ const uuid = mention.substring(1);
60
+ // We only match on UUIDs in the first place. This is just an extra sanity check
61
+ if ((0, uuid_validate_1.default)(uuid) === false)
62
+ continue;
63
+ comment = comment.replace(new RegExp(mention, 'gm'), (_h = userPreviews[uuid]) !== null && _h !== void 0 ? _h : '@Unknown User');
59
64
  }
60
- comment = `> ${comment}`;
65
+ comment = `> ${comment.replace(/\n+/gm, '\n> ')}`;
61
66
  const message = `
62
67
  Hello ${(0, user_name_1.userName)(user)},
63
68
 
@@ -34,6 +34,7 @@ const exceptions_1 = require("../exceptions");
34
34
  const storage_1 = __importDefault(require("../storage"));
35
35
  const authorization_1 = require("./authorization");
36
36
  const TransformationUtils = __importStar(require("../utils/transformations"));
37
+ const uuid_validate_1 = __importDefault(require("uuid-validate"));
37
38
  sharp_1.default.concurrency(1);
38
39
  // Note: don't put this in the service. The service can be initialized in multiple places, but they
39
40
  // should all share the same semaphore instance.
@@ -54,7 +55,20 @@ class AssetsService {
54
55
  if (systemPublicKeys.includes(id) === false && ((_a = this.accountability) === null || _a === void 0 ? void 0 : _a.admin) !== true) {
55
56
  await this.authorizationService.checkAccess('read', 'directus_files', id);
56
57
  }
58
+ /**
59
+ * This is a little annoying. Postgres will error out if you're trying to search in `where`
60
+ * with a wrong type. In case of directus_files where id is a uuid, we'll have to verify the
61
+ * validity of the uuid ahead of time.
62
+ */
63
+ const isValidUUID = (0, uuid_validate_1.default)(id, 4);
64
+ if (isValidUUID === false)
65
+ throw new exceptions_1.ForbiddenException();
57
66
  const file = (await this.knex.select('*').from('directus_files').where({ id }).first());
67
+ if (!file)
68
+ throw new exceptions_1.ForbiddenException();
69
+ const { exists } = await storage_1.default.disk(file.storage).exists(file.filename_disk);
70
+ if (!exists)
71
+ throw new exceptions_1.ForbiddenException();
58
72
  if (range) {
59
73
  if (range.start >= file.filesize || (range.end && range.end >= file.filesize)) {
60
74
  throw new exceptions_1.RangeNotSatisfiableException(range);
@@ -6,9 +6,11 @@ import { PayloadService } from '../services/payload';
6
6
  import { AbstractServiceOptions, SchemaOverview } from '../types';
7
7
  import { Accountability } from '@directus/shared/types';
8
8
  import { Field, RawField, Type } from '@directus/shared/types';
9
+ import { Helpers } from '../database/helpers';
9
10
  import Keyv from 'keyv';
10
11
  export declare class FieldsService {
11
12
  knex: Knex;
13
+ helpers: Helpers;
12
14
  accountability: Accountability | null;
13
15
  itemsService: ItemsService;
14
16
  payloadService: PayloadService;
@@ -39,10 +39,11 @@ const get_local_type_1 = __importDefault(require("../utils/get-local-type"));
39
39
  const utils_1 = require("@directus/shared/utils");
40
40
  const lodash_1 = require("lodash");
41
41
  const relations_1 = require("./relations");
42
- const geometry_1 = require("../database/helpers/geometry");
42
+ const helpers_1 = require("../database/helpers");
43
43
  class FieldsService {
44
44
  constructor(options) {
45
45
  this.knex = options.knex || (0, database_1.default)();
46
+ this.helpers = (0, helpers_1.getHelpers)(this.knex);
46
47
  this.schemaInspector = options.knex ? (0, schema_1.default)(options.knex) : (0, database_1.getSchemaInspector)();
47
48
  this.accountability = options.accountability || null;
48
49
  this.itemsService = new items_1.ItemsService('directus_fields', options);
@@ -211,23 +212,39 @@ class FieldsService {
211
212
  accountability: this.accountability,
212
213
  schema: this.schema,
213
214
  });
214
- if (field.type && constants_1.ALIAS_TYPES.includes(field.type) === false) {
215
+ const hookAdjustedField = await emitter_1.default.emitFilter(`fields.create`, field, {
216
+ collection: collection,
217
+ }, {
218
+ database: trx,
219
+ schema: this.schema,
220
+ accountability: this.accountability,
221
+ });
222
+ if (hookAdjustedField.type && constants_1.ALIAS_TYPES.includes(hookAdjustedField.type) === false) {
215
223
  if (table) {
216
- this.addColumnToTable(table, field);
224
+ this.addColumnToTable(table, hookAdjustedField);
217
225
  }
218
226
  else {
219
227
  await trx.schema.alterTable(collection, (table) => {
220
- this.addColumnToTable(table, field);
228
+ this.addColumnToTable(table, hookAdjustedField);
221
229
  });
222
230
  }
223
231
  }
224
- if (field.meta) {
232
+ if (hookAdjustedField.meta) {
225
233
  await itemsService.createOne({
226
- ...field.meta,
234
+ ...hookAdjustedField.meta,
227
235
  collection: collection,
228
- field: field.field,
229
- });
236
+ field: hookAdjustedField.field,
237
+ }, { emitEvents: false });
230
238
  }
239
+ emitter_1.default.emitAction(`fields.create`, {
240
+ payload: hookAdjustedField,
241
+ key: hookAdjustedField.field,
242
+ collection: collection,
243
+ }, {
244
+ database: (0, database_1.default)(),
245
+ schema: this.schema,
246
+ accountability: this.accountability,
247
+ });
231
248
  });
232
249
  if (this.cache && env_1.default.CACHE_AUTO_PURGE) {
233
250
  await this.cache.clear();
@@ -238,12 +255,23 @@ class FieldsService {
238
255
  if (this.accountability && this.accountability.admin !== true) {
239
256
  throw new exceptions_1.ForbiddenException();
240
257
  }
241
- if (field.schema) {
242
- const existingColumn = await this.schemaInspector.columnInfo(collection, field.field);
243
- if (!(0, lodash_1.isEqual)(existingColumn, field.schema)) {
258
+ const hookAdjustedField = await emitter_1.default.emitFilter(`fields.update`, field, {
259
+ keys: [field.field],
260
+ collection: collection,
261
+ }, {
262
+ database: this.knex,
263
+ schema: this.schema,
264
+ accountability: this.accountability,
265
+ });
266
+ const record = field.meta
267
+ ? await this.knex.select('id').from('directus_fields').where({ collection, field: field.field }).first()
268
+ : null;
269
+ if (hookAdjustedField.schema) {
270
+ const existingColumn = await this.schemaInspector.columnInfo(collection, hookAdjustedField.field);
271
+ if (!(0, lodash_1.isEqual)(existingColumn, hookAdjustedField.schema)) {
244
272
  try {
245
273
  await this.knex.schema.alterTable(collection, (table) => {
246
- if (!field.schema)
274
+ if (!hookAdjustedField.schema)
247
275
  return;
248
276
  this.addColumnToTable(table, field, existingColumn);
249
277
  });
@@ -253,31 +281,35 @@ class FieldsService {
253
281
  }
254
282
  }
255
283
  }
256
- if (field.meta) {
257
- const record = await this.knex
258
- .select('id')
259
- .from('directus_fields')
260
- .where({ collection, field: field.field })
261
- .first();
284
+ if (hookAdjustedField.meta) {
262
285
  if (record) {
263
286
  await this.itemsService.updateOne(record.id, {
264
- ...field.meta,
287
+ ...hookAdjustedField.meta,
265
288
  collection: collection,
266
- field: field.field,
267
- });
289
+ field: hookAdjustedField.field,
290
+ }, { emitEvents: false });
268
291
  }
269
292
  else {
270
293
  await this.itemsService.createOne({
271
- ...field.meta,
294
+ ...hookAdjustedField.meta,
272
295
  collection: collection,
273
- field: field.field,
274
- });
296
+ field: hookAdjustedField.field,
297
+ }, { emitEvents: false });
275
298
  }
276
299
  }
277
300
  if (this.cache && env_1.default.CACHE_AUTO_PURGE) {
278
301
  await this.cache.clear();
279
302
  }
280
303
  await this.systemCache.clear();
304
+ emitter_1.default.emitAction(`fields.update`, {
305
+ payload: hookAdjustedField,
306
+ keys: [hookAdjustedField.field],
307
+ collection: collection,
308
+ }, {
309
+ database: (0, database_1.default)(),
310
+ schema: this.schema,
311
+ accountability: this.accountability,
312
+ });
281
313
  return field.field;
282
314
  }
283
315
  async deleteField(collection, field) {
@@ -402,8 +434,7 @@ class FieldsService {
402
434
  column = table.timestamp(field.field, { useTz: true });
403
435
  }
404
436
  else if (field.type.startsWith('geometry')) {
405
- const helper = (0, geometry_1.getGeometryHelper)();
406
- column = helper.createColumn(table, field);
437
+ column = this.helpers.st.createColumn(table, field);
407
438
  }
408
439
  else {
409
440
  // @ts-ignore
@@ -9,7 +9,7 @@ export declare class FilesService extends ItemsService {
9
9
  uploadOne(stream: NodeJS.ReadableStream, data: Partial<File> & {
10
10
  filename_download: string;
11
11
  storage: string;
12
- }, primaryKey?: PrimaryKey): Promise<PrimaryKey>;
12
+ }, primaryKey?: PrimaryKey, opts?: MutationOptions): Promise<PrimaryKey>;
13
13
  /**
14
14
  * Import a single file from an external URL
15
15
  */
@@ -26,7 +26,7 @@ class FilesService extends items_1.ItemsService {
26
26
  /**
27
27
  * Upload a single new file to the configured storage adapter
28
28
  */
29
- async uploadOne(stream, data, primaryKey) {
29
+ async uploadOne(stream, data, primaryKey, opts) {
30
30
  var _a, _b, _c, _d, _e, _f;
31
31
  const payload = (0, lodash_1.clone)(data);
32
32
  if ('folder' in payload === false) {
@@ -109,15 +109,17 @@ class FilesService extends items_1.ItemsService {
109
109
  if (this.cache && env_1.default.CACHE_AUTO_PURGE) {
110
110
  await this.cache.clear();
111
111
  }
112
- emitter_1.default.emitAction('files.upload', {
113
- payload,
114
- key: primaryKey,
115
- collection: this.collection,
116
- }, {
117
- database: this.knex,
118
- schema: this.schema,
119
- accountability: this.accountability,
120
- });
112
+ if ((opts === null || opts === void 0 ? void 0 : opts.emitEvents) !== false) {
113
+ emitter_1.default.emitAction('files.upload', {
114
+ payload,
115
+ key: primaryKey,
116
+ collection: this.collection,
117
+ }, {
118
+ database: this.knex,
119
+ schema: this.schema,
120
+ accountability: this.accountability,
121
+ });
122
+ }
121
123
  return primaryKey;
122
124
  }
123
125
  /**
@@ -126,7 +128,7 @@ class FilesService extends items_1.ItemsService {
126
128
  async importOne(importURL, body) {
127
129
  var _a, _b, _c;
128
130
  const fileCreatePermissions = (_b = (_a = this.accountability) === null || _a === void 0 ? void 0 : _a.permissions) === null || _b === void 0 ? void 0 : _b.find((permission) => permission.collection === 'directus_files' && permission.action === 'create');
129
- if (((_c = this.accountability) === null || _c === void 0 ? void 0 : _c.admin) !== true && !fileCreatePermissions) {
131
+ if (this.accountability && ((_c = this.accountability) === null || _c === void 0 ? void 0 : _c.admin) !== true && !fileCreatePermissions) {
130
132
  throw new exceptions_1.ForbiddenException();
131
133
  }
132
134
  let fileResponse;
@@ -726,6 +726,9 @@ class GraphQLService {
726
726
  args: {
727
727
  groupBy: new graphql_1.GraphQLList(graphql_1.GraphQLString),
728
728
  filter: ReadableCollectionFilterTypes[collection.collection],
729
+ limit: {
730
+ type: graphql_1.GraphQLInt,
731
+ },
729
732
  search: {
730
733
  type: graphql_1.GraphQLString,
731
734
  },
@@ -213,8 +213,16 @@ class ItemsService {
213
213
  if (records === null) {
214
214
  throw new exceptions_1.ForbiddenException();
215
215
  }
216
+ const filteredRecords = await emitter_1.default.emitFilter(`${this.eventScope}.read`, records, {
217
+ query,
218
+ collection: this.collection,
219
+ }, {
220
+ database: this.knex,
221
+ schema: this.schema,
222
+ accountability: this.accountability,
223
+ });
216
224
  emitter_1.default.emitAction(`${this.eventScope}.read`, {
217
- payload: records,
225
+ payload: filteredRecords,
218
226
  query,
219
227
  collection: this.collection,
220
228
  }, {
@@ -222,23 +230,15 @@ class ItemsService {
222
230
  schema: this.schema,
223
231
  accountability: this.accountability,
224
232
  });
225
- return records;
233
+ return filteredRecords;
226
234
  }
227
235
  /**
228
236
  * Get single item by primary key
229
237
  */
230
- async readOne(key, query, opts) {
231
- query = query !== null && query !== void 0 ? query : {};
238
+ async readOne(key, query = {}, opts) {
232
239
  const primaryKeyField = this.schema.collections[this.collection].primary;
233
- const queryWithKey = {
234
- ...query,
235
- filter: {
236
- ...(query.filter || {}),
237
- [primaryKeyField]: {
238
- _eq: key,
239
- },
240
- },
241
- };
240
+ const filterWithKey = (0, lodash_1.assign)({}, query.filter, { [primaryKeyField]: { _eq: key } });
241
+ const queryWithKey = (0, lodash_1.assign)({}, query, { filter: filterWithKey });
242
242
  const results = await this.readByQuery(queryWithKey, opts);
243
243
  if (results.length === 0) {
244
244
  throw new exceptions_1.ForbiddenException();
@@ -248,23 +248,12 @@ class ItemsService {
248
248
  /**
249
249
  * Get multiple items by primary keys
250
250
  */
251
- async readMany(keys, query, opts) {
252
- query = query !== null && query !== void 0 ? query : {};
251
+ async readMany(keys, query = {}, opts) {
252
+ var _a;
253
253
  const primaryKeyField = this.schema.collections[this.collection].primary;
254
- const queryWithKeys = {
255
- ...query,
256
- filter: {
257
- _and: [
258
- query.filter || {},
259
- {
260
- [primaryKeyField]: {
261
- _in: keys,
262
- },
263
- },
264
- ],
265
- },
266
- };
267
- const results = await this.readByQuery(queryWithKeys, opts);
254
+ const filterWithKey = { _and: [{ [primaryKeyField]: { _in: keys } }, (_a = query.filter) !== null && _a !== void 0 ? _a : {}] };
255
+ const queryWithKey = (0, lodash_1.assign)({}, query, { filter: filterWithKey });
256
+ const results = await this.readByQuery(queryWithKey, opts);
268
257
  return results;
269
258
  }
270
259
  /**
@@ -1,6 +1,7 @@
1
1
  import { Knex } from 'knex';
2
2
  import { AbstractServiceOptions, Item, PrimaryKey, SchemaOverview } from '../types';
3
3
  import { Accountability } from '@directus/shared/types';
4
+ import { Helpers } from '../database/helpers';
4
5
  declare type Action = 'create' | 'read' | 'update';
5
6
  declare type Transformers = {
6
7
  [type: string]: (context: {
@@ -18,6 +19,7 @@ declare type Transformers = {
18
19
  export declare class PayloadService {
19
20
  accountability: Accountability | null;
20
21
  knex: Knex;
22
+ helpers: Helpers;
21
23
  collection: string;
22
24
  schema: SchemaOverview;
23
25
  constructor(collection: string, options: AbstractServiceOptions);
@@ -13,7 +13,7 @@ const exceptions_1 = require("../exceptions");
13
13
  const utils_1 = require("@directus/shared/utils");
14
14
  const items_1 = require("./items");
15
15
  const flat_1 = require("flat");
16
- const geometry_1 = require("../database/helpers/geometry");
16
+ const helpers_1 = require("../database/helpers");
17
17
  const wellknown_1 = require("wellknown");
18
18
  const generate_hash_1 = require("../utils/generate-hash");
19
19
  /**
@@ -111,6 +111,7 @@ class PayloadService {
111
111
  };
112
112
  this.accountability = options.accountability || null;
113
113
  this.knex = options.knex || (0, database_1.default)();
114
+ this.helpers = (0, helpers_1.getHelpers)(this.knex);
114
115
  this.collection = collection;
115
116
  this.schema = options.schema;
116
117
  return this;
@@ -188,10 +189,9 @@ class PayloadService {
188
189
  * to check if the value is a raw instance before stringifying it in the next step.
189
190
  */
190
191
  processGeometries(payloads, action) {
191
- const helper = (0, geometry_1.getGeometryHelper)();
192
192
  const process = action == 'read'
193
193
  ? (value) => (typeof value === 'string' ? (0, wellknown_1.parse)(value) : value)
194
- : (value) => helper.fromGeoJSON(typeof value == 'string' ? JSON.parse(value) : value);
194
+ : (value) => this.helpers.st.fromGeoJSON(typeof value == 'string' ? JSON.parse(value) : value);
195
195
  const fieldsInCollection = Object.entries(this.schema.collections[this.collection].fields);
196
196
  const geometryColumns = fieldsInCollection.filter(([_, field]) => field.type.startsWith('geometry'));
197
197
  for (const [name] of geometryColumns) {
@@ -8,11 +8,9 @@ const lodash_1 = require("lodash");
8
8
  const nanoid_1 = require("nanoid");
9
9
  const uuid_validate_1 = __importDefault(require("uuid-validate"));
10
10
  const exceptions_1 = require("../exceptions");
11
- const apply_function_to_column_name_1 = require("./apply-function-to-column-name");
12
11
  const get_column_1 = require("./get-column");
13
12
  const get_relation_type_1 = require("./get-relation-type");
14
- const geometry_1 = require("../database/helpers/geometry");
15
- const date_1 = require("../database/helpers/date");
13
+ const helpers_1 = require("../database/helpers");
16
14
  const generateAlias = (0, nanoid_1.customAlphabet)('abcdefghijklmnopqrstuvwxyz', 5);
17
15
  /**
18
16
  * Apply the Query to a given Knex query builder instance
@@ -45,7 +43,7 @@ function applyQuery(knex, collection, dbQuery, query, schema, subQuery = false)
45
43
  applySearch(schema, dbQuery, query.search, collection);
46
44
  }
47
45
  if (query.group) {
48
- dbQuery.groupBy(query.group.map(apply_function_to_column_name_1.applyFunctionToColumnName));
46
+ dbQuery.groupBy(query.group.map((column) => (0, get_column_1.getColumn)(knex, collection, column, false)));
49
47
  }
50
48
  if (query.aggregate) {
51
49
  applyAggregate(dbQuery, query.aggregate, collection);
@@ -117,6 +115,7 @@ exports.default = applyQuery;
117
115
  * ```
118
116
  */
119
117
  function applyFilter(knex, schema, rootQuery, rootFilter, collection, subQuery = false) {
118
+ const helpers = (0, helpers_1.getHelpers)(knex);
120
119
  const relations = schema.relations;
121
120
  const aliasMap = {};
122
121
  addJoins(rootQuery, rootFilter, collection);
@@ -273,16 +272,15 @@ function applyFilter(knex, schema, rootQuery, rootFilter, collection, subQuery =
273
272
  query.where(key, '!=', '');
274
273
  });
275
274
  }
276
- const dateHelper = (0, date_1.getDateHelper)();
277
275
  const [collection, field] = key.split('.');
278
276
  if (collection in schema.collections && field in schema.collections[collection].fields) {
279
277
  const type = schema.collections[collection].fields[field].type;
280
278
  if (['date', 'dateTime', 'time', 'timestamp'].includes(type)) {
281
279
  if (Array.isArray(compareValue)) {
282
- compareValue = compareValue.map((val) => dateHelper.parseDate(val));
280
+ compareValue = compareValue.map((val) => helpers.date.parse(val));
283
281
  }
284
282
  else {
285
- compareValue = dateHelper.parseDate(compareValue);
283
+ compareValue = helpers.date.parse(compareValue);
286
284
  }
287
285
  }
288
286
  }
@@ -361,18 +359,17 @@ function applyFilter(knex, schema, rootQuery, rootFilter, collection, subQuery =
361
359
  value = value.split(',');
362
360
  dbQuery[logical].whereNotBetween(selectionRaw, value);
363
361
  }
364
- const geometryHelper = (0, geometry_1.getGeometryHelper)();
365
362
  if (operator == '_intersects') {
366
- dbQuery[logical].whereRaw(geometryHelper.intersects(key, compareValue));
363
+ dbQuery[logical].whereRaw(helpers.st.intersects(key, compareValue));
367
364
  }
368
365
  if (operator == '_nintersects') {
369
- dbQuery[logical].whereRaw(geometryHelper.nintersects(key, compareValue));
366
+ dbQuery[logical].whereRaw(helpers.st.nintersects(key, compareValue));
370
367
  }
371
368
  if (operator == '_intersects_bbox') {
372
- dbQuery[logical].whereRaw(geometryHelper.intersects_bbox(key, compareValue));
369
+ dbQuery[logical].whereRaw(helpers.st.intersects_bbox(key, compareValue));
373
370
  }
374
371
  if (operator == '_nintersects_bbox') {
375
- dbQuery[logical].whereRaw(geometryHelper.nintersects_bbox(key, compareValue));
372
+ dbQuery[logical].whereRaw(helpers.st.nintersects_bbox(key, compareValue));
376
373
  }
377
374
  }
378
375
  function getWhereColumn(path, collection) {
@@ -36,14 +36,13 @@ async function applySnapshot(snapshot, options) {
36
36
  // edits
37
37
  snapshotDiff.fields = snapshotDiff.fields.filter((fieldDiff) => fieldDiff.collection !== collection);
38
38
  }
39
- if ((diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'E') {
40
- const updates = diff.reduce((acc, edit) => {
41
- if (edit.kind !== 'E')
42
- return acc;
43
- (0, lodash_1.set)(acc, edit.path, edit.rhs);
44
- return acc;
45
- }, {});
46
- await collectionsService.updateOne(collection, updates);
39
+ if ((diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'E' || (diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'A') {
40
+ const newValues = snapshot.collections.find((field) => {
41
+ return field.collection === collection;
42
+ });
43
+ if (newValues) {
44
+ await collectionsService.updateOne(collection, newValues);
45
+ }
47
46
  }
48
47
  }
49
48
  const fieldsService = new services_1.FieldsService({ knex: trx, schema: await (0, get_schema_1.getSchema)({ database: trx }) });
@@ -51,18 +50,15 @@ async function applySnapshot(snapshot, options) {
51
50
  if ((diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'N') {
52
51
  await fieldsService.createField(collection, diff[0].rhs);
53
52
  }
54
- if ((diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'E') {
55
- const updates = diff.reduce((acc, edit) => {
56
- if (edit.kind !== 'E')
57
- return acc;
58
- (0, lodash_1.set)(acc, edit.path, edit.rhs);
59
- return acc;
60
- }, {});
61
- await fieldsService.updateField(collection, {
62
- field,
63
- type: 'unknown',
64
- ...updates,
53
+ if ((diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'E' || (diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'A') {
54
+ const newValues = snapshot.fields.find((snapshotField) => {
55
+ return snapshotField.collection === collection && snapshotField.field === field;
65
56
  });
57
+ if (newValues) {
58
+ await fieldsService.updateField(collection, {
59
+ ...newValues,
60
+ });
61
+ }
66
62
  }
67
63
  if ((diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'D') {
68
64
  await fieldsService.deleteField(collection, field);
@@ -72,18 +68,21 @@ async function applySnapshot(snapshot, options) {
72
68
  }
73
69
  }
74
70
  const relationsService = new services_1.RelationsService({ knex: trx, schema: await (0, get_schema_1.getSchema)({ database: trx }) });
75
- for (const { collection, field, diff, related_collection } of snapshotDiff.relations) {
71
+ for (const { collection, field, diff } of snapshotDiff.relations) {
72
+ const structure = {};
73
+ for (const diffEdit of diff) {
74
+ (0, lodash_1.set)(structure, diffEdit.path, undefined);
75
+ }
76
76
  if ((diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'N') {
77
77
  await relationsService.createOne(diff[0].rhs);
78
78
  }
79
- if ((diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'E') {
80
- const updates = diff.reduce((acc, edit) => {
81
- if (edit.kind !== 'E')
82
- return acc;
83
- (0, lodash_1.set)(acc, edit.path, edit.rhs);
84
- return acc;
85
- }, { collection, field, related_collection });
86
- await relationsService.updateOne(collection, field, updates);
79
+ if ((diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'E' || (diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'A') {
80
+ const newValues = snapshot.relations.find((relation) => {
81
+ return relation.collection === collection && relation.field === field;
82
+ });
83
+ if (newValues) {
84
+ await relationsService.updateOne(collection, field, newValues);
85
+ }
87
86
  }
88
87
  if ((diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'D') {
89
88
  await relationsService.deleteOne(collection, field);
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getColumn = void 0;
4
- const functions_1 = require("../database/functions");
4
+ const helpers_1 = require("../database/helpers");
5
5
  const constants_1 = require("@directus/shared/constants");
6
6
  const apply_function_to_column_name_1 = require("./apply-function-to-column-name");
7
7
  /**
@@ -15,7 +15,7 @@ const apply_function_to_column_name_1 = require("./apply-function-to-column-name
15
15
  * @returns Knex raw instance
16
16
  */
17
17
  function getColumn(knex, table, column, alias = (0, apply_function_to_column_name_1.applyFunctionToColumnName)(column)) {
18
- const fn = (0, functions_1.FunctionsHelper)(knex);
18
+ const { date: fn } = (0, helpers_1.getHelpers)(knex);
19
19
  if (column.includes('(') && column.includes(')')) {
20
20
  const functionName = column.split('(')[0];
21
21
  const columnName = column.match(constants_1.REGEX_BETWEEN_PARENS)[1];