directus 9.7.1 → 9.9.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 (103) hide show
  1. package/dist/__mocks__/cache.d.ts +5 -0
  2. package/dist/__mocks__/cache.js +7 -0
  3. package/dist/auth/drivers/ldap.js +10 -11
  4. package/dist/auth/drivers/oauth2.js +9 -4
  5. package/dist/auth/drivers/openid.js +7 -4
  6. package/dist/cache.js +2 -2
  7. package/dist/cli/commands/schema/apply.js +9 -3
  8. package/dist/controllers/assets.js +5 -0
  9. package/dist/controllers/files.d.ts +2 -0
  10. package/dist/controllers/files.js +13 -5
  11. package/dist/database/helpers/date/dialects/default.d.ts +3 -0
  12. package/dist/database/helpers/date/dialects/default.js +7 -0
  13. package/dist/database/helpers/date/dialects/mssql.d.ts +1 -9
  14. package/dist/database/helpers/date/dialects/mssql.js +4 -23
  15. package/dist/database/helpers/date/dialects/mysql.d.ts +2 -9
  16. package/dist/database/helpers/date/dialects/mysql.js +7 -22
  17. package/dist/database/helpers/date/dialects/oracle.d.ts +1 -9
  18. package/dist/database/helpers/date/dialects/oracle.js +7 -23
  19. package/dist/database/helpers/date/dialects/sqlite.d.ts +1 -9
  20. package/dist/database/helpers/date/dialects/sqlite.js +8 -24
  21. package/dist/database/helpers/date/index.d.ts +4 -4
  22. package/dist/database/helpers/date/index.js +9 -9
  23. package/dist/database/helpers/date/types.d.ts +3 -9
  24. package/dist/database/helpers/date/types.js +10 -0
  25. package/dist/database/helpers/fn/dialects/mssql.d.ts +13 -0
  26. package/dist/database/helpers/fn/dialects/mssql.js +42 -0
  27. package/dist/database/helpers/{date/dialects/postgres.d.ts → fn/dialects/mysql.d.ts} +3 -2
  28. package/dist/database/helpers/fn/dialects/mysql.js +42 -0
  29. package/dist/database/helpers/fn/dialects/oracle.d.ts +13 -0
  30. package/dist/database/helpers/fn/dialects/oracle.js +42 -0
  31. package/dist/database/helpers/fn/dialects/postgres.d.ts +13 -0
  32. package/dist/database/helpers/{date → fn}/dialects/postgres.js +18 -3
  33. package/dist/database/helpers/fn/dialects/sqlite.d.ts +13 -0
  34. package/dist/database/helpers/fn/dialects/sqlite.js +42 -0
  35. package/dist/database/helpers/fn/index.d.ts +7 -0
  36. package/dist/database/helpers/fn/index.js +17 -0
  37. package/dist/database/helpers/fn/types.d.ts +18 -0
  38. package/dist/database/helpers/fn/types.js +27 -0
  39. package/dist/database/helpers/index.d.ts +4 -1
  40. package/dist/database/helpers/index.js +7 -1
  41. package/dist/database/migrations/20220308A-add-bookmark-icon-and-color.d.ts +3 -0
  42. package/dist/database/migrations/20220308A-add-bookmark-icon-and-color.js +17 -0
  43. package/dist/database/migrations/20220322A-rename-field-typecast-flags.js +6 -2
  44. package/dist/database/migrations/20220323A-add-field-validation.d.ts +3 -0
  45. package/dist/database/migrations/20220323A-add-field-validation.js +17 -0
  46. package/dist/database/migrations/20220325A-fix-typecast-flags.d.ts +3 -0
  47. package/dist/database/migrations/20220325A-fix-typecast-flags.js +49 -0
  48. package/dist/database/migrations/20220325B-add-default-language.d.ts +3 -0
  49. package/dist/database/migrations/20220325B-add-default-language.js +28 -0
  50. package/dist/database/migrations/20220402A-remove-default-value-panel-icon.d.ts +3 -0
  51. package/dist/database/migrations/20220402A-remove-default-value-panel-icon.js +22 -0
  52. package/dist/database/run-ast.js +7 -5
  53. package/dist/database/system-data/fields/activity.yaml +4 -4
  54. package/dist/database/system-data/fields/collections.yaml +1 -1
  55. package/dist/database/system-data/fields/fields.yaml +9 -0
  56. package/dist/database/system-data/fields/presets.yaml +14 -0
  57. package/dist/database/system-data/fields/settings.yaml +12 -1
  58. package/dist/database/system-data/fields/users.yaml +3 -0
  59. package/dist/env.js +5 -3
  60. package/dist/exceptions/index.d.ts +1 -0
  61. package/dist/exceptions/index.js +1 -0
  62. package/dist/exceptions/token-expired.d.ts +4 -0
  63. package/dist/exceptions/token-expired.js +10 -0
  64. package/dist/logger.js +2 -1
  65. package/dist/middleware/cache.js +10 -0
  66. package/dist/services/activity.js +4 -1
  67. package/dist/services/authorization.d.ts +1 -1
  68. package/dist/services/authorization.js +174 -48
  69. package/dist/services/collections.d.ts +2 -0
  70. package/dist/services/collections.js +232 -198
  71. package/dist/services/fields.js +210 -174
  72. package/dist/services/files.d.ts +5 -1
  73. package/dist/services/files.js +59 -40
  74. package/dist/services/graphql.d.ts +2 -3
  75. package/dist/services/graphql.js +53 -10
  76. package/dist/services/items.js +5 -3
  77. package/dist/services/payload.d.ts +2 -1
  78. package/dist/services/payload.js +28 -21
  79. package/dist/services/relations.js +93 -81
  80. package/dist/services/server.js +1 -0
  81. package/dist/services/shares.js +2 -1
  82. package/dist/services/specifications.js +1 -3
  83. package/dist/services/users.js +7 -2
  84. package/dist/types/files.d.ts +8 -0
  85. package/dist/utils/apply-query.js +38 -10
  86. package/dist/utils/apply-snapshot.d.ts +3 -1
  87. package/dist/utils/apply-snapshot.js +34 -5
  88. package/dist/utils/get-ast-from-query.js +15 -3
  89. package/dist/utils/get-column.d.ts +6 -5
  90. package/dist/utils/get-column.js +16 -8
  91. package/dist/utils/get-graphql-type.js +1 -0
  92. package/dist/utils/get-local-type.js +5 -0
  93. package/dist/utils/get-schema.d.ts +1 -1
  94. package/dist/utils/get-schema.js +18 -10
  95. package/dist/utils/jwt.js +1 -1
  96. package/dist/utils/reduce-schema.js +20 -12
  97. package/dist/utils/track.js +3 -2
  98. package/dist/utils/url.d.ts +1 -1
  99. package/dist/utils/url.js +1 -1
  100. package/dist/utils/validate-query.js +19 -15
  101. package/dist/utils/validate-storage.js +3 -1
  102. package/example.env +4 -0
  103. package/package.json +14 -13
@@ -32,9 +32,12 @@ const env_1 = __importDefault(require("../env"));
32
32
  const exceptions_1 = require("../exceptions");
33
33
  const fields_1 = require("../services/fields");
34
34
  const items_1 = require("../services/items");
35
+ const utils_1 = require("@directus/shared/utils");
36
+ const helpers_1 = require("../database/helpers");
35
37
  class CollectionsService {
36
38
  constructor(options) {
37
39
  this.knex = options.knex || (0, database_1.default)();
40
+ this.helpers = (0, helpers_1.getHelpers)(this.knex);
38
41
  this.accountability = options.accountability || null;
39
42
  this.schemaInspector = options.knex ? (0, schema_1.default)(options.knex) : (0, database_1.getSchemaInspector)();
40
43
  this.schema = options.schema;
@@ -55,105 +58,118 @@ class CollectionsService {
55
58
  if (payload.collection.startsWith('directus_')) {
56
59
  throw new exceptions_1.InvalidPayloadException(`Collections can't start with "directus_"`);
57
60
  }
58
- const existingCollections = [
59
- ...((_b = (_a = (await this.knex.select('collection').from('directus_collections'))) === null || _a === void 0 ? void 0 : _a.map(({ collection }) => collection)) !== null && _b !== void 0 ? _b : []),
60
- ...Object.keys(this.schema.collections),
61
- ];
62
- if (existingCollections.includes(payload.collection)) {
63
- throw new exceptions_1.InvalidPayloadException(`Collection "${payload.collection}" already exists.`);
64
- }
65
- // Create the collection/fields in a transaction so it'll be reverted in case of errors or
66
- // permission problems. This might not work reliably in MySQL, as it doesn't support DDL in
67
- // transactions.
68
- await this.knex.transaction(async (trx) => {
69
- if (payload.schema) {
70
- // Directus heavily relies on the primary key of a collection, so we have to make sure that
71
- // every collection that is created has a primary key. If no primary key field is created
72
- // while making the collection, we default to an auto incremented id named `id`
73
- if (!payload.fields)
74
- payload.fields = [
75
- {
76
- field: 'id',
77
- type: 'integer',
78
- meta: {
79
- hidden: true,
80
- interface: 'numeric',
81
- readonly: true,
82
- },
83
- schema: {
84
- is_primary_key: true,
85
- has_auto_increment: true,
61
+ try {
62
+ const existingCollections = [
63
+ ...((_b = (_a = (await this.knex.select('collection').from('directus_collections'))) === null || _a === void 0 ? void 0 : _a.map(({ collection }) => collection)) !== null && _b !== void 0 ? _b : []),
64
+ ...Object.keys(this.schema.collections),
65
+ ];
66
+ if (existingCollections.includes(payload.collection)) {
67
+ throw new exceptions_1.InvalidPayloadException(`Collection "${payload.collection}" already exists.`);
68
+ }
69
+ // Create the collection/fields in a transaction so it'll be reverted in case of errors or
70
+ // permission problems. This might not work reliably in MySQL, as it doesn't support DDL in
71
+ // transactions.
72
+ await this.knex.transaction(async (trx) => {
73
+ if (payload.schema) {
74
+ // Directus heavily relies on the primary key of a collection, so we have to make sure that
75
+ // every collection that is created has a primary key. If no primary key field is created
76
+ // while making the collection, we default to an auto incremented id named `id`
77
+ if (!payload.fields)
78
+ payload.fields = [
79
+ {
80
+ field: 'id',
81
+ type: 'integer',
82
+ meta: {
83
+ hidden: true,
84
+ interface: 'numeric',
85
+ readonly: true,
86
+ },
87
+ schema: {
88
+ is_primary_key: true,
89
+ has_auto_increment: true,
90
+ },
86
91
  },
87
- },
88
- ];
89
- // Ensure that every field meta has the field/collection fields filled correctly
90
- payload.fields = payload.fields.map((field) => {
91
- if (field.meta) {
92
- field.meta = {
93
- ...field.meta,
94
- field: field.field,
95
- collection: payload.collection,
96
- };
97
- }
98
- return field;
99
- });
100
- const fieldsService = new fields_1.FieldsService({ knex: trx, schema: this.schema });
101
- await trx.schema.createTable(payload.collection, (table) => {
102
- for (const field of payload.fields) {
103
- if (field.type && constants_1.ALIAS_TYPES.includes(field.type) === false) {
104
- fieldsService.addColumnToTable(table, field);
92
+ ];
93
+ // Ensure that every field meta has the field/collection fields filled correctly
94
+ payload.fields = payload.fields.map((field) => {
95
+ if (field.meta) {
96
+ field.meta = {
97
+ ...field.meta,
98
+ field: field.field,
99
+ collection: payload.collection,
100
+ };
105
101
  }
106
- }
107
- });
108
- const fieldItemsService = new items_1.ItemsService('directus_fields', {
109
- knex: trx,
110
- accountability: this.accountability,
111
- schema: this.schema,
112
- });
113
- const fieldPayloads = payload.fields.filter((field) => field.meta).map((field) => field.meta);
114
- await fieldItemsService.createMany(fieldPayloads);
115
- }
116
- if (payload.meta) {
117
- const collectionItemsService = new items_1.ItemsService('directus_collections', {
118
- knex: trx,
119
- accountability: this.accountability,
120
- schema: this.schema,
121
- });
122
- await collectionItemsService.createOne({
123
- ...payload.meta,
124
- collection: payload.collection,
125
- });
126
- }
102
+ // Add flag for specific database type overrides
103
+ const flagToAdd = this.helpers.date.fieldFlagForField(field.type);
104
+ if (flagToAdd) {
105
+ (0, utils_1.addFieldFlag)(field, flagToAdd);
106
+ }
107
+ return field;
108
+ });
109
+ const fieldsService = new fields_1.FieldsService({ knex: trx, schema: this.schema });
110
+ await trx.schema.createTable(payload.collection, (table) => {
111
+ for (const field of payload.fields) {
112
+ if (field.type && constants_1.ALIAS_TYPES.includes(field.type) === false) {
113
+ fieldsService.addColumnToTable(table, field);
114
+ }
115
+ }
116
+ });
117
+ const fieldItemsService = new items_1.ItemsService('directus_fields', {
118
+ knex: trx,
119
+ accountability: this.accountability,
120
+ schema: this.schema,
121
+ });
122
+ const fieldPayloads = payload.fields.filter((field) => field.meta).map((field) => field.meta);
123
+ await fieldItemsService.createMany(fieldPayloads);
124
+ }
125
+ if (payload.meta) {
126
+ const collectionItemsService = new items_1.ItemsService('directus_collections', {
127
+ knex: trx,
128
+ accountability: this.accountability,
129
+ schema: this.schema,
130
+ });
131
+ await collectionItemsService.createOne({
132
+ ...payload.meta,
133
+ collection: payload.collection,
134
+ });
135
+ }
136
+ return payload.collection;
137
+ });
127
138
  return payload.collection;
128
- });
129
- if (this.cache && env_1.default.CACHE_AUTO_PURGE && (opts === null || opts === void 0 ? void 0 : opts.autoPurgeCache) !== false) {
130
- await this.cache.clear();
131
139
  }
132
- await (0, cache_1.clearSystemCache)();
133
- return payload.collection;
140
+ finally {
141
+ if (this.cache && env_1.default.CACHE_AUTO_PURGE && (opts === null || opts === void 0 ? void 0 : opts.autoPurgeCache) !== false) {
142
+ await this.cache.clear();
143
+ }
144
+ await (0, cache_1.clearSystemCache)();
145
+ }
134
146
  }
135
147
  /**
136
148
  * Create multiple new collections
137
149
  */
138
150
  async createMany(payloads, opts) {
139
- const collections = await this.knex.transaction(async (trx) => {
140
- const service = new CollectionsService({
141
- schema: this.schema,
142
- accountability: this.accountability,
143
- knex: trx,
151
+ try {
152
+ const collections = await this.knex.transaction(async (trx) => {
153
+ const service = new CollectionsService({
154
+ schema: this.schema,
155
+ accountability: this.accountability,
156
+ knex: trx,
157
+ });
158
+ const collectionNames = [];
159
+ for (const payload of payloads) {
160
+ const name = await service.createOne(payload, { autoPurgeCache: false });
161
+ collectionNames.push(name);
162
+ }
163
+ return collectionNames;
144
164
  });
145
- const collectionNames = [];
146
- for (const payload of payloads) {
147
- const name = await service.createOne(payload, { autoPurgeCache: false });
148
- collectionNames.push(name);
165
+ return collections;
166
+ }
167
+ finally {
168
+ if (this.cache && env_1.default.CACHE_AUTO_PURGE && (opts === null || opts === void 0 ? void 0 : opts.autoPurgeCache) !== false) {
169
+ await this.cache.clear();
149
170
  }
150
- return collectionNames;
151
- });
152
- if (this.cache && env_1.default.CACHE_AUTO_PURGE && (opts === null || opts === void 0 ? void 0 : opts.autoPurgeCache) !== false) {
153
- await this.cache.clear();
171
+ await (0, cache_1.clearSystemCache)();
154
172
  }
155
- await (0, cache_1.clearSystemCache)();
156
- return collections;
157
173
  }
158
174
  /**
159
175
  * Read all collections. Currently doesn't support any query.
@@ -223,6 +239,8 @@ class CollectionsService {
223
239
  */
224
240
  async readOne(collectionKey) {
225
241
  const result = await this.readMany([collectionKey]);
242
+ if (result.length === 0)
243
+ throw new exceptions_1.ForbiddenException();
226
244
  return result[0];
227
245
  }
228
246
  /**
@@ -252,31 +270,35 @@ class CollectionsService {
252
270
  if (this.accountability && this.accountability.admin !== true) {
253
271
  throw new exceptions_1.ForbiddenException();
254
272
  }
255
- const collectionItemsService = new items_1.ItemsService('directus_collections', {
256
- knex: this.knex,
257
- accountability: this.accountability,
258
- schema: this.schema,
259
- });
260
- const payload = data;
261
- if (!payload.meta) {
273
+ try {
274
+ const collectionItemsService = new items_1.ItemsService('directus_collections', {
275
+ knex: this.knex,
276
+ accountability: this.accountability,
277
+ schema: this.schema,
278
+ });
279
+ const payload = data;
280
+ if (!payload.meta) {
281
+ return collectionKey;
282
+ }
283
+ const exists = !!(await this.knex
284
+ .select('collection')
285
+ .from('directus_collections')
286
+ .where({ collection: collectionKey })
287
+ .first());
288
+ if (exists) {
289
+ await collectionItemsService.updateOne(collectionKey, payload.meta, opts);
290
+ }
291
+ else {
292
+ await collectionItemsService.createOne({ ...payload.meta, collection: collectionKey }, opts);
293
+ }
262
294
  return collectionKey;
263
295
  }
264
- const exists = !!(await this.knex
265
- .select('collection')
266
- .from('directus_collections')
267
- .where({ collection: collectionKey })
268
- .first());
269
- if (exists) {
270
- await collectionItemsService.updateOne(collectionKey, payload.meta, opts);
271
- }
272
- else {
273
- await collectionItemsService.createOne({ ...payload.meta, collection: collectionKey }, opts);
274
- }
275
- if (this.cache && env_1.default.CACHE_AUTO_PURGE && (opts === null || opts === void 0 ? void 0 : opts.autoPurgeCache) !== false) {
276
- await this.cache.clear();
296
+ finally {
297
+ if (this.cache && env_1.default.CACHE_AUTO_PURGE && (opts === null || opts === void 0 ? void 0 : opts.autoPurgeCache) !== false) {
298
+ await this.cache.clear();
299
+ }
300
+ await (0, cache_1.clearSystemCache)();
277
301
  }
278
- await (0, cache_1.clearSystemCache)();
279
- return collectionKey;
280
302
  }
281
303
  /**
282
304
  * Update multiple collections by name
@@ -285,21 +307,25 @@ class CollectionsService {
285
307
  if (this.accountability && this.accountability.admin !== true) {
286
308
  throw new exceptions_1.ForbiddenException();
287
309
  }
288
- await this.knex.transaction(async (trx) => {
289
- const service = new CollectionsService({
290
- schema: this.schema,
291
- accountability: this.accountability,
292
- knex: trx,
310
+ try {
311
+ await this.knex.transaction(async (trx) => {
312
+ const service = new CollectionsService({
313
+ schema: this.schema,
314
+ accountability: this.accountability,
315
+ knex: trx,
316
+ });
317
+ for (const collectionKey of collectionKeys) {
318
+ await service.updateOne(collectionKey, data, { autoPurgeCache: false });
319
+ }
293
320
  });
294
- for (const collectionKey of collectionKeys) {
295
- await service.updateOne(collectionKey, data, { autoPurgeCache: false });
321
+ return collectionKeys;
322
+ }
323
+ finally {
324
+ if (this.cache && env_1.default.CACHE_AUTO_PURGE && (opts === null || opts === void 0 ? void 0 : opts.autoPurgeCache) !== false) {
325
+ await this.cache.clear();
296
326
  }
297
- });
298
- if (this.cache && env_1.default.CACHE_AUTO_PURGE && (opts === null || opts === void 0 ? void 0 : opts.autoPurgeCache) !== false) {
299
- await this.cache.clear();
327
+ await (0, cache_1.clearSystemCache)();
300
328
  }
301
- await (0, cache_1.clearSystemCache)();
302
- return collectionKeys;
303
329
  }
304
330
  /**
305
331
  * Delete a single collection This will delete the table and all records within. It'll also
@@ -309,78 +335,82 @@ class CollectionsService {
309
335
  if (this.accountability && this.accountability.admin !== true) {
310
336
  throw new exceptions_1.ForbiddenException();
311
337
  }
312
- const collections = await this.readByQuery();
313
- const collectionToBeDeleted = collections.find((collection) => collection.collection === collectionKey);
314
- if (!!collectionToBeDeleted === false) {
315
- throw new exceptions_1.ForbiddenException();
316
- }
317
- await this.knex.transaction(async (trx) => {
318
- var _a;
319
- if (collectionToBeDeleted.schema) {
320
- await trx.schema.dropTable(collectionKey);
321
- }
322
- // Make sure this collection isn't used as a group in any other collections
323
- await trx('directus_collections').update({ group: null }).where({ group: collectionKey });
324
- if (collectionToBeDeleted.meta) {
325
- const collectionItemsService = new items_1.ItemsService('directus_collections', {
326
- knex: trx,
327
- accountability: this.accountability,
328
- schema: this.schema,
329
- });
330
- await collectionItemsService.deleteOne(collectionKey);
338
+ try {
339
+ const collections = await this.readByQuery();
340
+ const collectionToBeDeleted = collections.find((collection) => collection.collection === collectionKey);
341
+ if (!!collectionToBeDeleted === false) {
342
+ throw new exceptions_1.ForbiddenException();
331
343
  }
332
- if (collectionToBeDeleted.schema) {
333
- const fieldsService = new fields_1.FieldsService({
334
- knex: trx,
335
- accountability: this.accountability,
336
- schema: this.schema,
337
- });
338
- await trx('directus_fields').delete().where('collection', '=', collectionKey);
339
- await trx('directus_presets').delete().where('collection', '=', collectionKey);
340
- const revisionsToDelete = await trx
341
- .select('id')
342
- .from('directus_revisions')
343
- .where({ collection: collectionKey });
344
- if (revisionsToDelete.length > 0) {
345
- const keys = revisionsToDelete.map((record) => record.id);
346
- await trx('directus_revisions').update({ parent: null }).whereIn('parent', keys);
344
+ await this.knex.transaction(async (trx) => {
345
+ var _a;
346
+ if (collectionToBeDeleted.schema) {
347
+ await trx.schema.dropTable(collectionKey);
347
348
  }
348
- await trx('directus_revisions').delete().where('collection', '=', collectionKey);
349
- await trx('directus_activity').delete().where('collection', '=', collectionKey);
350
- await trx('directus_permissions').delete().where('collection', '=', collectionKey);
351
- await trx('directus_relations').delete().where({ many_collection: collectionKey });
352
- const relations = this.schema.relations.filter((relation) => {
353
- return relation.collection === collectionKey || relation.related_collection === collectionKey;
354
- });
355
- for (const relation of relations) {
356
- // Delete related o2m fields that point to current collection
357
- if (relation.related_collection && ((_a = relation.meta) === null || _a === void 0 ? void 0 : _a.one_field)) {
358
- await fieldsService.deleteField(relation.related_collection, relation.meta.one_field);
349
+ // Make sure this collection isn't used as a group in any other collections
350
+ await trx('directus_collections').update({ group: null }).where({ group: collectionKey });
351
+ if (collectionToBeDeleted.meta) {
352
+ const collectionItemsService = new items_1.ItemsService('directus_collections', {
353
+ knex: trx,
354
+ accountability: this.accountability,
355
+ schema: this.schema,
356
+ });
357
+ await collectionItemsService.deleteOne(collectionKey);
358
+ }
359
+ if (collectionToBeDeleted.schema) {
360
+ const fieldsService = new fields_1.FieldsService({
361
+ knex: trx,
362
+ accountability: this.accountability,
363
+ schema: this.schema,
364
+ });
365
+ await trx('directus_fields').delete().where('collection', '=', collectionKey);
366
+ await trx('directus_presets').delete().where('collection', '=', collectionKey);
367
+ const revisionsToDelete = await trx
368
+ .select('id')
369
+ .from('directus_revisions')
370
+ .where({ collection: collectionKey });
371
+ if (revisionsToDelete.length > 0) {
372
+ const keys = revisionsToDelete.map((record) => record.id);
373
+ await trx('directus_revisions').update({ parent: null }).whereIn('parent', keys);
374
+ }
375
+ await trx('directus_revisions').delete().where('collection', '=', collectionKey);
376
+ await trx('directus_activity').delete().where('collection', '=', collectionKey);
377
+ await trx('directus_permissions').delete().where('collection', '=', collectionKey);
378
+ await trx('directus_relations').delete().where({ many_collection: collectionKey });
379
+ const relations = this.schema.relations.filter((relation) => {
380
+ return relation.collection === collectionKey || relation.related_collection === collectionKey;
381
+ });
382
+ for (const relation of relations) {
383
+ // Delete related o2m fields that point to current collection
384
+ if (relation.related_collection && ((_a = relation.meta) === null || _a === void 0 ? void 0 : _a.one_field)) {
385
+ await fieldsService.deleteField(relation.related_collection, relation.meta.one_field);
386
+ }
387
+ // Delete related m2o fields that point to current collection
388
+ if (relation.related_collection === collectionKey) {
389
+ await fieldsService.deleteField(relation.collection, relation.field);
390
+ }
359
391
  }
360
- // Delete related m2o fields that point to current collection
361
- if (relation.related_collection === collectionKey) {
362
- await fieldsService.deleteField(relation.collection, relation.field);
392
+ const a2oRelationsThatIncludeThisCollection = this.schema.relations.filter((relation) => {
393
+ var _a, _b;
394
+ return (_b = (_a = relation.meta) === null || _a === void 0 ? void 0 : _a.one_allowed_collections) === null || _b === void 0 ? void 0 : _b.includes(collectionKey);
395
+ });
396
+ for (const relation of a2oRelationsThatIncludeThisCollection) {
397
+ const newAllowedCollections = relation
398
+ .meta.one_allowed_collections.filter((collection) => collectionKey !== collection)
399
+ .join(',');
400
+ await trx('directus_relations')
401
+ .update({ one_allowed_collections: newAllowedCollections })
402
+ .where({ id: relation.meta.id });
363
403
  }
364
404
  }
365
- const a2oRelationsThatIncludeThisCollection = this.schema.relations.filter((relation) => {
366
- var _a, _b;
367
- return (_b = (_a = relation.meta) === null || _a === void 0 ? void 0 : _a.one_allowed_collections) === null || _b === void 0 ? void 0 : _b.includes(collectionKey);
368
- });
369
- for (const relation of a2oRelationsThatIncludeThisCollection) {
370
- const newAllowedCollections = relation
371
- .meta.one_allowed_collections.filter((collection) => collectionKey !== collection)
372
- .join(',');
373
- await trx('directus_relations')
374
- .update({ one_allowed_collections: newAllowedCollections })
375
- .where({ id: relation.meta.id });
376
- }
405
+ });
406
+ return collectionKey;
407
+ }
408
+ finally {
409
+ if (this.cache && env_1.default.CACHE_AUTO_PURGE && (opts === null || opts === void 0 ? void 0 : opts.autoPurgeCache) !== false) {
410
+ await this.cache.clear();
377
411
  }
378
- });
379
- if (this.cache && env_1.default.CACHE_AUTO_PURGE && (opts === null || opts === void 0 ? void 0 : opts.autoPurgeCache) !== false) {
380
- await this.cache.clear();
412
+ await (0, cache_1.clearSystemCache)();
381
413
  }
382
- await (0, cache_1.clearSystemCache)();
383
- return collectionKey;
384
414
  }
385
415
  /**
386
416
  * Delete multiple collections by key
@@ -389,21 +419,25 @@ class CollectionsService {
389
419
  if (this.accountability && this.accountability.admin !== true) {
390
420
  throw new exceptions_1.ForbiddenException();
391
421
  }
392
- await this.knex.transaction(async (trx) => {
393
- const service = new CollectionsService({
394
- schema: this.schema,
395
- accountability: this.accountability,
396
- knex: trx,
422
+ try {
423
+ await this.knex.transaction(async (trx) => {
424
+ const service = new CollectionsService({
425
+ schema: this.schema,
426
+ accountability: this.accountability,
427
+ knex: trx,
428
+ });
429
+ for (const collectionKey of collectionKeys) {
430
+ await service.deleteOne(collectionKey, { autoPurgeCache: false });
431
+ }
397
432
  });
398
- for (const collectionKey of collectionKeys) {
399
- await service.deleteOne(collectionKey, { autoPurgeCache: false });
433
+ return collectionKeys;
434
+ }
435
+ finally {
436
+ if (this.cache && env_1.default.CACHE_AUTO_PURGE && (opts === null || opts === void 0 ? void 0 : opts.autoPurgeCache) !== false) {
437
+ await this.cache.clear();
400
438
  }
401
- });
402
- if (this.cache && env_1.default.CACHE_AUTO_PURGE && (opts === null || opts === void 0 ? void 0 : opts.autoPurgeCache) !== false) {
403
- await this.cache.clear();
439
+ await (0, cache_1.clearSystemCache)();
404
440
  }
405
- await (0, cache_1.clearSystemCache)();
406
- return collectionKeys;
407
441
  }
408
442
  }
409
443
  exports.CollectionsService = CollectionsService;