directus 9.14.5 → 9.16.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 (129) hide show
  1. package/dist/__utils__/items-utils.d.ts +2 -0
  2. package/dist/__utils__/items-utils.js +36 -0
  3. package/dist/__utils__/schemas.d.ts +13 -0
  4. package/dist/__utils__/schemas.js +304 -0
  5. package/dist/__utils__/snapshots.d.ts +5 -0
  6. package/dist/__utils__/snapshots.js +897 -0
  7. package/dist/app.js +2 -1
  8. package/dist/auth/drivers/ldap.js +18 -8
  9. package/dist/auth/drivers/oauth2.js +19 -9
  10. package/dist/auth/drivers/openid.js +19 -9
  11. package/dist/cache.d.ts +3 -0
  12. package/dist/cache.js +21 -2
  13. package/dist/cli/index.test.d.ts +1 -0
  14. package/dist/cli/index.test.js +58 -0
  15. package/dist/cli/utils/create-env/env-stub.liquid +2 -2
  16. package/dist/constants.d.ts +1 -0
  17. package/dist/constants.js +2 -1
  18. package/dist/controllers/assets.js +27 -1
  19. package/dist/controllers/extensions.js +3 -2
  20. package/dist/controllers/files.test.d.ts +1 -0
  21. package/dist/controllers/files.test.js +49 -0
  22. package/dist/controllers/server.js +0 -1
  23. package/dist/database/helpers/schema/dialects/cockroachdb.d.ts +3 -14
  24. package/dist/database/helpers/schema/dialects/cockroachdb.js +2 -8
  25. package/dist/database/helpers/schema/dialects/oracle.d.ts +3 -10
  26. package/dist/database/helpers/schema/dialects/oracle.js +2 -5
  27. package/dist/database/helpers/schema/types.d.ts +8 -18
  28. package/dist/database/helpers/schema/types.js +7 -36
  29. package/dist/database/migrations/20201105B-change-webhook-url-type.js +3 -2
  30. package/dist/database/migrations/20210312A-webhooks-collections-text.js +3 -2
  31. package/dist/database/migrations/20210415A-make-filesize-nullable.js +2 -2
  32. package/dist/database/migrations/20210510A-restructure-relations.js +3 -3
  33. package/dist/database/migrations/20210903A-add-auth-provider.js +2 -2
  34. package/dist/database/migrations/20210907A-webhooks-collections-not-null.js +4 -2
  35. package/dist/database/migrations/20210920A-webhooks-url-not-null.js +2 -2
  36. package/dist/database/migrations/20220303A-remove-default-project-color.js +2 -2
  37. package/dist/database/migrations/20220325B-add-default-language.js +2 -2
  38. package/dist/database/migrations/20220402A-remove-default-value-panel-icon.js +2 -2
  39. package/dist/database/migrations/20220801A-update-notifications-timestamp-column.d.ts +3 -0
  40. package/dist/database/migrations/20220801A-update-notifications-timestamp-column.js +19 -0
  41. package/dist/database/migrations/20220802A-add-custom-aspect-ratios.d.ts +3 -0
  42. package/dist/database/migrations/20220802A-add-custom-aspect-ratios.js +15 -0
  43. package/dist/database/migrations/run.test.d.ts +1 -0
  44. package/dist/database/migrations/run.test.js +92 -0
  45. package/dist/database/system-data/fields/settings.yaml +33 -0
  46. package/dist/env.js +8 -0
  47. package/dist/env.test.d.ts +8 -0
  48. package/dist/env.test.js +39 -0
  49. package/dist/extensions.d.ts +2 -2
  50. package/dist/extensions.js +10 -9
  51. package/dist/flows.js +2 -1
  52. package/dist/logger.js +0 -1
  53. package/dist/middleware/authenticate.test.d.ts +1 -0
  54. package/dist/middleware/authenticate.test.js +174 -0
  55. package/dist/middleware/cache.js +3 -3
  56. package/dist/middleware/extract-token.test.d.ts +1 -0
  57. package/dist/middleware/extract-token.test.js +60 -0
  58. package/dist/middleware/respond.js +2 -2
  59. package/dist/operations/exec/index.d.ts +5 -0
  60. package/dist/operations/exec/index.js +26 -0
  61. package/dist/operations/exec/index.test.d.ts +1 -0
  62. package/dist/operations/exec/index.test.js +95 -0
  63. package/dist/operations/item-create/index.js +1 -1
  64. package/dist/operations/item-delete/index.js +2 -2
  65. package/dist/operations/item-read/index.js +2 -2
  66. package/dist/operations/item-update/index.js +3 -3
  67. package/dist/operations/notification/index.js +9 -6
  68. package/dist/operations/request/index.js +22 -3
  69. package/dist/services/assets.d.ts +1 -1
  70. package/dist/services/assets.js +7 -2
  71. package/dist/services/authorization.js +2 -1
  72. package/dist/services/files.js +3 -2
  73. package/dist/services/files.test.d.ts +1 -0
  74. package/dist/services/files.test.js +53 -0
  75. package/dist/services/flows.js +4 -0
  76. package/dist/services/graphql/index.d.ts +2 -2
  77. package/dist/services/graphql/index.js +59 -40
  78. package/dist/services/graphql/types/hash.d.ts +2 -0
  79. package/dist/services/graphql/types/hash.js +9 -0
  80. package/dist/services/items.js +83 -39
  81. package/dist/services/items.test.d.ts +1 -0
  82. package/dist/services/items.test.js +765 -0
  83. package/dist/services/payload.d.ts +7 -4
  84. package/dist/services/payload.js +35 -8
  85. package/dist/services/payload.test.d.ts +1 -0
  86. package/dist/services/payload.test.js +94 -0
  87. package/dist/services/server.js +5 -3
  88. package/dist/services/specifications.js +1 -6
  89. package/dist/services/specifications.test.d.ts +1 -0
  90. package/dist/services/specifications.test.js +96 -0
  91. package/dist/types/items.d.ts +11 -0
  92. package/dist/utils/apply-query.js +15 -0
  93. package/dist/utils/apply-snapshot.js +15 -0
  94. package/dist/utils/apply-snapshot.test.d.ts +1 -0
  95. package/dist/utils/apply-snapshot.test.js +305 -0
  96. package/dist/utils/calculate-field-depth.test.d.ts +1 -0
  97. package/dist/utils/calculate-field-depth.test.js +76 -0
  98. package/dist/utils/compress.d.ts +3 -0
  99. package/dist/utils/compress.js +17 -0
  100. package/dist/utils/filter-items.test.d.ts +1 -0
  101. package/dist/utils/filter-items.test.js +60 -0
  102. package/dist/utils/get-ast-from-query.js +1 -1
  103. package/dist/utils/get-cache-key.test.d.ts +1 -0
  104. package/dist/utils/get-cache-key.test.js +53 -0
  105. package/dist/utils/get-column-path.test.d.ts +1 -0
  106. package/dist/utils/get-column-path.test.js +136 -0
  107. package/dist/utils/get-config-from-env.test.d.ts +1 -0
  108. package/dist/utils/get-config-from-env.test.js +19 -0
  109. package/dist/utils/get-graphql-type.d.ts +1 -1
  110. package/dist/utils/get-graphql-type.js +7 -1
  111. package/dist/utils/get-os-info.d.ts +9 -0
  112. package/dist/utils/get-os-info.js +47 -0
  113. package/dist/utils/get-permissions.js +2 -2
  114. package/dist/utils/get-relation-info.test.d.ts +1 -0
  115. package/dist/utils/get-relation-info.test.js +88 -0
  116. package/dist/utils/get-relation-type.test.d.ts +1 -0
  117. package/dist/utils/get-relation-type.test.js +69 -0
  118. package/dist/utils/get-schema.js +1 -2
  119. package/dist/utils/get-string-byte-size.test.d.ts +1 -0
  120. package/dist/utils/get-string-byte-size.test.js +8 -0
  121. package/dist/utils/is-directus-jwt.test.d.ts +1 -0
  122. package/dist/utils/is-directus-jwt.test.js +26 -0
  123. package/dist/utils/jwt.test.d.ts +1 -0
  124. package/dist/utils/jwt.test.js +36 -0
  125. package/dist/utils/merge-permissions.test.d.ts +1 -0
  126. package/dist/utils/merge-permissions.test.js +80 -0
  127. package/dist/utils/validate-keys.test.d.ts +1 -0
  128. package/dist/utils/validate-keys.test.js +97 -0
  129. package/package.json +12 -11
@@ -0,0 +1,305 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ const knex_1 = __importDefault(require("knex"));
30
+ const knex_mock_client_1 = require("knex-mock-client");
31
+ const schemas_1 = require("../__utils__/schemas");
32
+ const services_1 = require("../services");
33
+ const apply_snapshot_1 = require("./apply-snapshot");
34
+ const getSchema = __importStar(require("./get-schema"));
35
+ const snapshots_1 = require("../__utils__/snapshots");
36
+ jest.mock('../../src/database/index', () => {
37
+ return {
38
+ getDatabaseClient: jest.fn().mockReturnValue('postgres'),
39
+ };
40
+ });
41
+ jest.requireMock('../../src/database/index');
42
+ class Client_PG extends knex_mock_client_1.MockClient {
43
+ }
44
+ describe('applySnapshot', () => {
45
+ let db;
46
+ let tracker;
47
+ beforeEach(() => {
48
+ db = (0, knex_1.default)({ client: Client_PG });
49
+ tracker = (0, knex_mock_client_1.getTracker)();
50
+ });
51
+ afterEach(() => {
52
+ tracker.reset();
53
+ jest.clearAllMocks();
54
+ });
55
+ describe('Creating new collection(s)', () => {
56
+ it('Creates new top-level collection(s)', async () => {
57
+ const expected = {
58
+ collection: 'test_table_2',
59
+ meta: {
60
+ accountability: 'all',
61
+ collection: 'test_table_2',
62
+ group: null,
63
+ hidden: true,
64
+ icon: 'import_export',
65
+ item_duplication_fields: null,
66
+ note: null,
67
+ singleton: false,
68
+ translations: {},
69
+ },
70
+ schema: { comment: null, name: 'test_table_2', schema: 'public' },
71
+ fields: [
72
+ {
73
+ collection: 'test_table_2',
74
+ field: 'id',
75
+ meta: {
76
+ collection: 'test_table_2',
77
+ conditions: null,
78
+ display: null,
79
+ display_options: null,
80
+ field: 'id',
81
+ group: null,
82
+ hidden: true,
83
+ interface: null,
84
+ note: null,
85
+ options: null,
86
+ readonly: false,
87
+ required: false,
88
+ sort: null,
89
+ special: null,
90
+ translations: {},
91
+ validation: null,
92
+ validation_message: null,
93
+ width: 'full',
94
+ },
95
+ schema: {
96
+ comment: null,
97
+ data_type: 'uuid',
98
+ default_value: null,
99
+ foreign_key_column: null,
100
+ foreign_key_schema: null,
101
+ foreign_key_table: null,
102
+ generation_expression: null,
103
+ has_auto_increment: false,
104
+ is_generated: false,
105
+ is_nullable: false,
106
+ is_primary_key: true,
107
+ is_unique: true,
108
+ max_length: null,
109
+ name: 'id',
110
+ numeric_precision: null,
111
+ numeric_scale: null,
112
+ schema: 'public',
113
+ table: 'test_table_2',
114
+ },
115
+ type: 'uuid',
116
+ },
117
+ ],
118
+ };
119
+ // Stop call to db later on in apply-snapshot
120
+ jest.spyOn(getSchema, 'getSchema').mockReturnValue(Promise.resolve(schemas_1.snapshotApplyTestSchema));
121
+ // We are not actually testing that createOne works, just that is is called correctly
122
+ const createOneCollectionSpy = jest
123
+ .spyOn(services_1.CollectionsService.prototype, 'createOne')
124
+ .mockImplementation(jest.fn());
125
+ const createFieldSpy = jest.spyOn(services_1.FieldsService.prototype, 'createField').mockImplementation(jest.fn());
126
+ await (0, apply_snapshot_1.applySnapshot)(snapshots_1.snapshotCreateCollectionNotNested, {
127
+ database: db,
128
+ current: snapshots_1.snapshotBeforeCreateCollection,
129
+ schema: schemas_1.snapshotApplyTestSchema,
130
+ });
131
+ expect(createOneCollectionSpy).toHaveBeenCalledTimes(1);
132
+ expect(createOneCollectionSpy).toHaveBeenCalledWith(expected);
133
+ // There should be no fields left to create
134
+ // they will get filtered in createCollections
135
+ expect(createFieldSpy).toHaveBeenCalledTimes(0);
136
+ });
137
+ it('Creates the highest-level nested collection(s) with existing parents and any children', async () => {
138
+ const expected = {
139
+ collection: 'test_table_2',
140
+ meta: {
141
+ accountability: 'all',
142
+ collection: 'test_table_2',
143
+ group: 'test_table',
144
+ hidden: true,
145
+ icon: 'import_export',
146
+ item_duplication_fields: null,
147
+ note: null,
148
+ singleton: false,
149
+ translations: {},
150
+ },
151
+ schema: { comment: null, name: 'test_table_2', schema: 'public' },
152
+ fields: [
153
+ {
154
+ collection: 'test_table_2',
155
+ field: 'id',
156
+ meta: {
157
+ collection: 'test_table_2',
158
+ conditions: null,
159
+ display: null,
160
+ display_options: null,
161
+ field: 'id',
162
+ group: null,
163
+ hidden: true,
164
+ interface: null,
165
+ note: null,
166
+ options: null,
167
+ readonly: false,
168
+ required: false,
169
+ sort: null,
170
+ special: null,
171
+ translations: {},
172
+ validation: null,
173
+ validation_message: null,
174
+ width: 'full',
175
+ },
176
+ schema: {
177
+ comment: null,
178
+ data_type: 'uuid',
179
+ default_value: null,
180
+ foreign_key_column: null,
181
+ foreign_key_schema: null,
182
+ foreign_key_table: null,
183
+ generation_expression: null,
184
+ has_auto_increment: false,
185
+ is_generated: false,
186
+ is_nullable: false,
187
+ is_primary_key: true,
188
+ is_unique: true,
189
+ max_length: null,
190
+ name: 'id',
191
+ numeric_precision: null,
192
+ numeric_scale: null,
193
+ schema: 'public',
194
+ table: 'test_table_2',
195
+ },
196
+ type: 'uuid',
197
+ },
198
+ ],
199
+ };
200
+ const expected2 = {
201
+ collection: 'test_table_3',
202
+ fields: [
203
+ {
204
+ collection: 'test_table_3',
205
+ field: 'id',
206
+ meta: {
207
+ collection: 'test_table_3',
208
+ conditions: null,
209
+ display: null,
210
+ display_options: null,
211
+ field: 'id',
212
+ group: null,
213
+ hidden: true,
214
+ interface: null,
215
+ note: null,
216
+ options: null,
217
+ readonly: false,
218
+ required: false,
219
+ sort: null,
220
+ special: null,
221
+ translations: {},
222
+ validation: null,
223
+ validation_message: null,
224
+ width: 'full',
225
+ },
226
+ schema: {
227
+ comment: null,
228
+ data_type: 'uuid',
229
+ default_value: null,
230
+ foreign_key_column: null,
231
+ foreign_key_schema: null,
232
+ foreign_key_table: null,
233
+ generation_expression: null,
234
+ has_auto_increment: false,
235
+ is_generated: false,
236
+ is_nullable: false,
237
+ is_primary_key: true,
238
+ is_unique: true,
239
+ max_length: null,
240
+ name: 'id',
241
+ numeric_precision: null,
242
+ numeric_scale: null,
243
+ schema: 'public',
244
+ table: 'test_table_3',
245
+ },
246
+ type: 'uuid',
247
+ },
248
+ ],
249
+ meta: {
250
+ accountability: 'all',
251
+ collection: 'test_table_3',
252
+ group: 'test_table_2',
253
+ hidden: true,
254
+ icon: 'import_export',
255
+ item_duplication_fields: null,
256
+ note: null,
257
+ singleton: false,
258
+ translations: {},
259
+ },
260
+ schema: { comment: null, name: 'test_table_3', schema: 'public' },
261
+ };
262
+ // Stop call to db later on in apply-snapshot
263
+ jest.spyOn(getSchema, 'getSchema').mockReturnValue(Promise.resolve(schemas_1.snapshotApplyTestSchema));
264
+ // We are not actually testing that createOne works, just that is is called correctly
265
+ const createOneCollectionSpy = jest
266
+ .spyOn(services_1.CollectionsService.prototype, 'createOne')
267
+ .mockImplementation(jest.fn());
268
+ const createFieldSpy = jest.spyOn(services_1.FieldsService.prototype, 'createField').mockImplementation(jest.fn());
269
+ await (0, apply_snapshot_1.applySnapshot)(snapshots_1.snapshotCreateCollection, {
270
+ database: db,
271
+ current: snapshots_1.snapshotBeforeCreateCollection,
272
+ schema: schemas_1.snapshotApplyTestSchema,
273
+ });
274
+ expect(createOneCollectionSpy).toHaveBeenCalledTimes(2);
275
+ expect(createOneCollectionSpy).toHaveBeenCalledWith(expected);
276
+ expect(createOneCollectionSpy).toHaveBeenCalledWith(expected2);
277
+ // There should be no fields left to create
278
+ // they will get filtered in createCollections
279
+ expect(createFieldSpy).toHaveBeenCalledTimes(0);
280
+ });
281
+ });
282
+ describe('Delete collections', () => {
283
+ it('Deletes interrelated collections', async () => {
284
+ const snapshotToApply = {
285
+ version: 1,
286
+ directus: '0.0.0',
287
+ collections: [],
288
+ fields: [],
289
+ relations: [],
290
+ };
291
+ // Stop call to db later on in apply-snapshot
292
+ jest.spyOn(getSchema, 'getSchema').mockReturnValue(Promise.resolve(schemas_1.snapshotApplyTestSchema));
293
+ // We are not actually testing that deleteOne works, just that is is called correctly
294
+ const deleteOneCollectionSpy = jest
295
+ .spyOn(services_1.CollectionsService.prototype, 'deleteOne')
296
+ .mockImplementation(jest.fn());
297
+ await (0, apply_snapshot_1.applySnapshot)(snapshotToApply, {
298
+ database: db,
299
+ current: snapshots_1.snapshotBeforeDeleteCollection,
300
+ schema: schemas_1.snapshotApplyTestSchema,
301
+ });
302
+ expect(deleteOneCollectionSpy).toHaveBeenCalledTimes(3);
303
+ });
304
+ });
305
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const calculate_field_depth_1 = require("../../src/utils/calculate-field-depth");
4
+ test('Calculates basic depth', () => {
5
+ const filter = {
6
+ name: {
7
+ _eq: 'test',
8
+ },
9
+ };
10
+ const result = (0, calculate_field_depth_1.calculateFieldDepth)(filter);
11
+ expect(result).toBe(1);
12
+ });
13
+ test('Calculates relational depth', () => {
14
+ const filter = {
15
+ author: {
16
+ name: {
17
+ _eq: 'test',
18
+ },
19
+ },
20
+ };
21
+ const result = (0, calculate_field_depth_1.calculateFieldDepth)(filter);
22
+ expect(result).toBe(2);
23
+ });
24
+ test('Ignores _and/_or', () => {
25
+ const filter = {
26
+ _and: [
27
+ {
28
+ _or: [
29
+ {
30
+ author: {
31
+ name: {
32
+ _eq: 'Directus',
33
+ },
34
+ },
35
+ },
36
+ {
37
+ status: {
38
+ _eq: 'published',
39
+ },
40
+ },
41
+ ],
42
+ },
43
+ {
44
+ category: {
45
+ _eq: 'recipes',
46
+ },
47
+ },
48
+ ],
49
+ };
50
+ const result = (0, calculate_field_depth_1.calculateFieldDepth)(filter);
51
+ expect(result).toBe(2);
52
+ });
53
+ test('Skips underscore prefix in tree', () => {
54
+ const deep = {
55
+ translations: {
56
+ _filter: {
57
+ language_id: {
58
+ code: {
59
+ _eq: 'nl-NL',
60
+ },
61
+ },
62
+ },
63
+ },
64
+ };
65
+ const result = (0, calculate_field_depth_1.calculateFieldDepth)(deep);
66
+ expect(result).toBe(3);
67
+ });
68
+ test('Calculates _sort in deep correctly', () => {
69
+ const deep = {
70
+ articles: {
71
+ _sort: ['sort', 'category.type.sort'],
72
+ },
73
+ };
74
+ const result = (0, calculate_field_depth_1.calculateFieldDepth)(deep, ['_sort']);
75
+ expect(result).toBe(4);
76
+ });
@@ -0,0 +1,3 @@
1
+ /// <reference types="node" />
2
+ export declare function compress(raw: Record<string, any> | Record<string, any>[]): Promise<Buffer>;
3
+ export declare function decompress(compressed: Buffer): Promise<any>;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.decompress = exports.compress = void 0;
4
+ const snappy_1 = require("snappy");
5
+ const utils_1 = require("@directus/shared/utils");
6
+ async function compress(raw) {
7
+ if (!raw)
8
+ return raw;
9
+ return await (0, snappy_1.compress)((0, utils_1.compress)(raw));
10
+ }
11
+ exports.compress = compress;
12
+ async function decompress(compressed) {
13
+ if (!compressed)
14
+ return compressed;
15
+ return (0, utils_1.decompress)((await (0, snappy_1.uncompress)(compressed, { asBuffer: false })));
16
+ }
17
+ exports.decompress = decompress;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const filter_items_1 = require("../../src/utils/filter-items");
4
+ const items = [
5
+ {
6
+ role: '9bc9fea0-f761-4107-bfb7-b3d06c125e98',
7
+ permissions: {},
8
+ validation: null,
9
+ presets: null,
10
+ fields: ['*'],
11
+ system: true,
12
+ collection: 'directus_settings',
13
+ action: 'read',
14
+ },
15
+ {
16
+ role: '9bc9fea0-f761-4107-bfb7-b3d06c125e98',
17
+ permissions: {
18
+ user: {
19
+ _eq: '$CURRENT_USER',
20
+ },
21
+ },
22
+ validation: null,
23
+ presets: null,
24
+ fields: ['*'],
25
+ system: true,
26
+ collection: 'directus_presets',
27
+ action: 'delete',
28
+ },
29
+ ];
30
+ describe('filter items', () => {
31
+ test('return items when no filter', () => {
32
+ const result = (0, filter_items_1.filterItems)(items, undefined);
33
+ expect(result).toStrictEqual(items);
34
+ });
35
+ test('return items when empty filter used', () => {
36
+ const result = (0, filter_items_1.filterItems)(items, {});
37
+ expect(result).toStrictEqual(items);
38
+ });
39
+ test('return filtered items when nested empty filter used', () => {
40
+ const result = (0, filter_items_1.filterItems)(items, {
41
+ _and: [
42
+ {
43
+ action: {
44
+ _eq: 'read',
45
+ },
46
+ },
47
+ {},
48
+ ],
49
+ });
50
+ expect(result).toStrictEqual(items.filter((item) => item.action === 'read'));
51
+ });
52
+ test('return filtered items', () => {
53
+ const result = (0, filter_items_1.filterItems)(items, {
54
+ action: {
55
+ _eq: 'read',
56
+ },
57
+ });
58
+ expect(result).toStrictEqual(items.filter((item) => item.action === 'read'));
59
+ });
60
+ });
@@ -70,7 +70,7 @@ async function getASTFromQuery(collection, query, schema, options) {
70
70
  if (!fields)
71
71
  return [];
72
72
  fields = await convertWildcards(parentCollection, fields);
73
- if (!fields)
73
+ if (!fields || !Array.isArray(fields))
74
74
  return [];
75
75
  const children = [];
76
76
  const relationalStructure = {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const get_cache_key_1 = require("../../src/utils/get-cache-key");
4
+ const restUrl = 'http://localhost/items/example';
5
+ const graphQlUrl = 'http://localhost/graphql';
6
+ const accountability = { user: '00000000-0000-0000-0000-000000000000' };
7
+ const requests = [
8
+ {
9
+ name: 'as unauthenticated request',
10
+ params: { originalUrl: restUrl },
11
+ key: '17da8272c9a0ec6eea38a37d6d78bddeb7c79045',
12
+ },
13
+ {
14
+ name: 'as authenticated request',
15
+ params: { originalUrl: restUrl, accountability },
16
+ key: '99a6394222a3d7d149ac1662fc2fff506932db58',
17
+ },
18
+ {
19
+ name: 'a request with a fields query',
20
+ params: { originalUrl: restUrl, sanitizedQuery: { fields: ['id', 'name'] } },
21
+ key: 'aa6e2d8a78de4dfb4af6eaa230d1cd9b7d31ed19',
22
+ },
23
+ {
24
+ name: 'a request with a filter query',
25
+ params: { originalUrl: restUrl, sanitizedQuery: { filter: { name: { _eq: 'test' } } } },
26
+ key: 'd7eb8970f0429e1cf85e12eb5bb8669f618b09d3',
27
+ },
28
+ {
29
+ name: 'a GraphQL query request',
30
+ params: { originalUrl: graphQlUrl, query: { query: 'query { test { id } }' } },
31
+ key: '201731b75c627c60554512d819b6935b54c73814',
32
+ },
33
+ ];
34
+ const cases = requests.map(({ name, params, key }) => [name, params, key]);
35
+ describe('get cache key', () => {
36
+ test.each(cases)('should create a cache key for %s', (_, params, key) => {
37
+ expect((0, get_cache_key_1.getCacheKey)(params)).toEqual(key);
38
+ });
39
+ test('should create a unique key for each request', () => {
40
+ const keys = requests.map((r) => r.key);
41
+ const hasDuplicate = keys.some((key) => keys.indexOf(key) !== keys.lastIndexOf(key));
42
+ expect(hasDuplicate).toBeFalsy();
43
+ });
44
+ test('should create a unique key for GraphQL requests with different variables', () => {
45
+ const query = 'query Test ($name: String) { test (filter: { name: { _eq: $name } }) { id } }';
46
+ const operationName = 'test';
47
+ const variables1 = JSON.stringify({ name: 'test 1' });
48
+ const variables2 = JSON.stringify({ name: 'test 2' });
49
+ const req1 = { originalUrl: graphQlUrl, query: { query, operationName, variables: variables1 } };
50
+ const req2 = { originalUrl: graphQlUrl, query: { query, operationName, variables: variables2 } };
51
+ expect((0, get_cache_key_1.getCacheKey)(req1)).not.toEqual((0, get_cache_key_1.getCacheKey)(req2));
52
+ });
53
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,136 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const get_column_path_1 = require("../../src/utils/get-column-path");
4
+ const exceptions_1 = require("../../src/exceptions");
5
+ /*
6
+ {
7
+ path: [ 'author', 'role', 'name' ],
8
+ collection: 'articles',
9
+ aliasMap: {
10
+ author: { role: { name: 'ljnsv' } },
11
+ ljnsv: { role: { name: 'grenv' } }
12
+ },
13
+ relations: []
14
+
15
+ grenv.name
16
+
17
+ {
18
+ path: [ 'author', 'first_name' ],
19
+ collection: 'articles',
20
+ aliasMap: { author: { first_name: 'rnmxt' } },
21
+ relations: []
22
+
23
+ rnmxt.first_name
24
+
25
+ {
26
+ path: [ 'item:headings', 'text' ],
27
+ collection: 'pages_sections',
28
+ aliasMap: { 'item:headings': { text: 'yllus' } },
29
+ relations: [
30
+ */
31
+ test('Throws an error when the field path is not known in relations', () => {
32
+ const input = {
33
+ path: ['author', 'first_name'],
34
+ collection: 'articles',
35
+ aliasMap: { author: { first_name: 'bjoyu' } },
36
+ relations: [],
37
+ };
38
+ expect(() => (0, get_column_path_1.getColumnPath)(input)).toThrowError(exceptions_1.InvalidQueryException);
39
+ });
40
+ test('Throws an error when an a2o is used without a collection scope', () => {
41
+ const input = {
42
+ path: ['item', 'type'],
43
+ collection: 'pages',
44
+ aliasMap: {},
45
+ relations: [
46
+ {
47
+ collection: 'pages',
48
+ field: 'item',
49
+ related_collection: null,
50
+ meta: {
51
+ one_collection_field: 'collection',
52
+ one_allowed_collections: ['paragraphs', 'headings'],
53
+ },
54
+ },
55
+ ],
56
+ };
57
+ expect(() => (0, get_column_path_1.getColumnPath)(input)).toThrowError(exceptions_1.InvalidQueryException);
58
+ });
59
+ test('Extracts path scope and returns correct alias for a2o', () => {
60
+ const input = {
61
+ path: ['item:headings', 'text'],
62
+ collection: 'pages',
63
+ aliasMap: { 'item:headings': { text: 'abcdef' } },
64
+ relations: [
65
+ {
66
+ collection: 'pages',
67
+ field: 'item',
68
+ related_collection: null,
69
+ meta: {
70
+ one_collection_field: 'collection',
71
+ one_allowed_collections: ['paragraphs', 'headings'],
72
+ },
73
+ },
74
+ ],
75
+ };
76
+ const result = (0, get_column_path_1.getColumnPath)(input);
77
+ expect(result.columnPath).toBe('abcdef.text');
78
+ expect(result.targetCollection).toBe('headings');
79
+ });
80
+ test('Returns correct alias for m2o', () => {
81
+ const input = {
82
+ path: ['author', 'role', 'name'],
83
+ collection: 'articles',
84
+ aliasMap: {
85
+ author: { role: { name: 'ljnsv' } },
86
+ ljnsv: { role: { name: 'grenv' } },
87
+ },
88
+ relations: [
89
+ {
90
+ collection: 'articles',
91
+ field: 'author',
92
+ related_collection: 'directus_users',
93
+ meta: null,
94
+ schema: null,
95
+ },
96
+ {
97
+ collection: 'directus_users',
98
+ field: 'role',
99
+ related_collection: 'directus_roles',
100
+ meta: null,
101
+ schema: null,
102
+ },
103
+ ],
104
+ };
105
+ const result = (0, get_column_path_1.getColumnPath)(input);
106
+ expect(result.columnPath).toBe('grenv.name');
107
+ expect(result.targetCollection).toBe('directus_roles');
108
+ });
109
+ test('Returns correct alias for o2m (& uses the table name if no alias exists)', () => {
110
+ const input = {
111
+ path: ['categories', 'category_id', 'name'],
112
+ collection: 'articles',
113
+ aliasMap: {},
114
+ relations: [
115
+ {
116
+ collection: 'categories_articles',
117
+ field: 'category_id',
118
+ related_collection: 'categories',
119
+ meta: null,
120
+ schema: null,
121
+ },
122
+ {
123
+ collection: 'categories_articles',
124
+ field: 'article_id',
125
+ related_collection: 'articles',
126
+ meta: {
127
+ one_field: 'categories',
128
+ },
129
+ schema: null,
130
+ },
131
+ ],
132
+ };
133
+ const result = (0, get_column_path_1.getColumnPath)(input);
134
+ expect(result.columnPath).toBe('categories.name');
135
+ expect(result.targetCollection).toBe('categories');
136
+ });
@@ -0,0 +1 @@
1
+ export {};