directus 9.12.0 → 9.13.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 (133) hide show
  1. package/dist/app.js +11 -1
  2. package/dist/auth/drivers/index.js +5 -1
  3. package/dist/auth/drivers/ldap.js +5 -1
  4. package/dist/auth/drivers/oauth2.js +15 -23
  5. package/dist/auth/drivers/openid.js +16 -24
  6. package/dist/cli/commands/bootstrap/index.js +5 -1
  7. package/dist/cli/commands/schema/apply.js +7 -3
  8. package/dist/cli/commands/schema/snapshot.d.ts +1 -1
  9. package/dist/cli/commands/schema/snapshot.js +33 -25
  10. package/dist/cli/index.js +1 -1
  11. package/dist/cli/utils/create-env/env-stub.liquid +11 -11
  12. package/dist/constants.d.ts +1 -0
  13. package/dist/constants.js +5 -1
  14. package/dist/controllers/assets.js +5 -5
  15. package/dist/controllers/dashboards.js +4 -1
  16. package/dist/controllers/files.js +8 -5
  17. package/dist/controllers/flows.js +4 -1
  18. package/dist/controllers/folders.js +4 -1
  19. package/dist/controllers/items.js +4 -1
  20. package/dist/controllers/notifications.js +4 -1
  21. package/dist/controllers/operations.js +4 -1
  22. package/dist/controllers/panels.js +4 -1
  23. package/dist/controllers/permissions.js +4 -1
  24. package/dist/controllers/presets.js +4 -1
  25. package/dist/controllers/roles.js +4 -1
  26. package/dist/controllers/shares.js +4 -1
  27. package/dist/controllers/users.js +75 -3
  28. package/dist/controllers/utils.js +3 -3
  29. package/dist/database/helpers/date/dialects/sqlite.js +3 -0
  30. package/dist/database/helpers/fn/dialects/oracle.d.ts +9 -9
  31. package/dist/database/helpers/fn/dialects/oracle.js +22 -16
  32. package/dist/database/helpers/fn/dialects/sqlite.d.ts +9 -9
  33. package/dist/database/helpers/fn/dialects/sqlite.js +46 -16
  34. package/dist/database/helpers/fn/types.d.ts +12 -9
  35. package/dist/database/helpers/index.js +5 -1
  36. package/dist/database/index.js +2 -0
  37. package/dist/database/migrations/20210225A-add-relations-sort-field.js +2 -2
  38. package/dist/database/migrations/20210506A-rename-interfaces.js +2 -2
  39. package/dist/database/migrations/20210802A-replace-groups.js +2 -2
  40. package/dist/database/migrations/20210805A-update-groups.js +2 -2
  41. package/dist/database/migrations/20210805B-change-image-metadata-structure.js +3 -3
  42. package/dist/database/migrations/20211007A-update-presets.js +5 -5
  43. package/dist/database/migrations/20220429A-add-flows.js +1 -2
  44. package/dist/database/migrations/20220614A-rename-hook-trigger-to-event.d.ts +3 -0
  45. package/dist/database/migrations/20220614A-rename-hook-trigger-to-event.js +11 -0
  46. package/dist/database/system-data/fields/dashboards.yaml +1 -0
  47. package/dist/database/system-data/fields/flows.yaml +1 -1
  48. package/dist/env.d.ts +1 -1
  49. package/dist/env.js +8 -3
  50. package/dist/exceptions/database/translate.js +5 -1
  51. package/dist/exceptions/index.js +5 -1
  52. package/dist/extensions.d.ts +2 -1
  53. package/dist/extensions.js +31 -23
  54. package/dist/flows.d.ts +5 -0
  55. package/dist/flows.js +66 -40
  56. package/dist/index.js +5 -1
  57. package/dist/logger.js +5 -1
  58. package/dist/messenger.js +2 -2
  59. package/dist/middleware/graphql.js +2 -2
  60. package/dist/middleware/respond.js +10 -1
  61. package/dist/middleware/validate-batch.js +3 -1
  62. package/dist/operations/item-create/index.js +1 -2
  63. package/dist/operations/item-delete/index.d.ts +1 -0
  64. package/dist/operations/item-delete/index.js +8 -7
  65. package/dist/operations/item-read/index.js +7 -6
  66. package/dist/operations/item-update/index.d.ts +1 -0
  67. package/dist/operations/item-update/index.js +9 -8
  68. package/dist/operations/log/index.js +1 -2
  69. package/dist/operations/notification/index.js +1 -2
  70. package/dist/operations/request/index.d.ts +4 -1
  71. package/dist/operations/request/index.js +5 -1
  72. package/dist/operations/transform/index.js +1 -2
  73. package/dist/operations/trigger/index.js +1 -2
  74. package/dist/server.js +5 -1
  75. package/dist/services/assets.js +5 -1
  76. package/dist/services/collections.js +5 -1
  77. package/dist/services/fields.d.ts +3 -3
  78. package/dist/services/fields.js +25 -17
  79. package/dist/services/files.js +5 -1
  80. package/dist/services/flows.d.ts +1 -2
  81. package/dist/services/flows.js +19 -8
  82. package/dist/services/{graphql.d.ts → graphql/index.d.ts} +3 -5
  83. package/dist/services/{graphql.js → graphql/index.js} +115 -102
  84. package/dist/services/graphql/types/date.d.ts +2 -0
  85. package/dist/services/graphql/types/date.js +9 -0
  86. package/dist/services/graphql/types/geojson.d.ts +2 -0
  87. package/dist/services/graphql/types/geojson.js +10 -0
  88. package/dist/services/graphql/types/string-or-float.d.ts +5 -0
  89. package/dist/services/graphql/types/string-or-float.js +34 -0
  90. package/dist/services/graphql/types/void.d.ts +2 -0
  91. package/dist/services/graphql/types/void.js +17 -0
  92. package/dist/services/graphql/utils/add-path-to-validation-error.d.ts +2 -0
  93. package/dist/services/graphql/utils/add-path-to-validation-error.js +20 -0
  94. package/dist/services/import-export.js +13 -10
  95. package/dist/services/index.js +5 -1
  96. package/dist/services/items.d.ts +5 -1
  97. package/dist/services/items.js +22 -2
  98. package/dist/services/mail/index.js +8 -6
  99. package/dist/services/operations.d.ts +1 -2
  100. package/dist/services/operations.js +19 -8
  101. package/dist/services/payload.js +2 -3
  102. package/dist/services/permissions.d.ts +1 -0
  103. package/dist/services/permissions.js +5 -0
  104. package/dist/services/relations.js +5 -1
  105. package/dist/services/roles.d.ts +1 -0
  106. package/dist/services/roles.js +9 -0
  107. package/dist/services/server.js +5 -1
  108. package/dist/services/users.d.ts +1 -0
  109. package/dist/services/users.js +22 -0
  110. package/dist/types/index.js +5 -1
  111. package/dist/utils/apply-query.js +24 -15
  112. package/dist/utils/apply-snapshot.js +3 -0
  113. package/dist/utils/calculate-field-depth.d.ts +33 -0
  114. package/dist/utils/calculate-field-depth.js +75 -0
  115. package/dist/utils/get-column.js +1 -1
  116. package/dist/utils/get-default-value.js +3 -13
  117. package/dist/utils/get-graphql-type.js +4 -3
  118. package/dist/utils/get-local-type.d.ts +6 -3
  119. package/dist/utils/get-permissions.js +3 -4
  120. package/dist/utils/get-schema.js +1 -2
  121. package/dist/utils/get-string-byte-size.d.ts +4 -0
  122. package/dist/utils/get-string-byte-size.js +10 -0
  123. package/dist/utils/job-queue.d.ts +9 -0
  124. package/dist/utils/job-queue.js +24 -0
  125. package/dist/utils/jwt.js +5 -1
  126. package/dist/utils/sanitize-query.js +4 -5
  127. package/dist/utils/validate-query.js +50 -0
  128. package/dist/webhooks.js +5 -1
  129. package/package.json +75 -74
  130. package/dist/utils/operation-options.d.ts +0 -3
  131. package/dist/utils/operation-options.js +0 -45
  132. package/dist/utils/parse-json.d.ts +0 -5
  133. package/dist/utils/parse-json.js +0 -19
@@ -32,7 +32,7 @@ const multipartHandler = (req, res, next) => {
32
32
  'content-type': 'application/octet-stream',
33
33
  };
34
34
  }
35
- const busboy = new busboy_1.default({ headers });
35
+ const busboy = (0, busboy_1.default)({ headers });
36
36
  const savedFiles = [];
37
37
  const service = new services_1.FilesService({ accountability: req.accountability, schema: req.schema });
38
38
  const existingPrimaryKey = req.params.pk || undefined;
@@ -57,7 +57,7 @@ const multipartHandler = (req, res, next) => {
57
57
  }
58
58
  payload[fieldname] = fieldValue;
59
59
  });
60
- busboy.on('file', async (fieldname, fileStream, filename, encoding, mimetype) => {
60
+ busboy.on('file', async (_fieldname, fileStream, { filename, mimeType }) => {
61
61
  if (!filename) {
62
62
  return busboy.emit('error', new exceptions_1.InvalidPayloadException(`File is missing filename`));
63
63
  }
@@ -68,7 +68,7 @@ const multipartHandler = (req, res, next) => {
68
68
  const payloadWithRequiredFields = {
69
69
  ...payload,
70
70
  filename_download: filename,
71
- type: mimetype,
71
+ type: mimeType,
72
72
  storage: payload.storage || disk,
73
73
  };
74
74
  // Clear the payload for the next to-be-uploaded file
@@ -85,7 +85,7 @@ const multipartHandler = (req, res, next) => {
85
85
  busboy.on('error', (error) => {
86
86
  next(error);
87
87
  });
88
- busboy.on('finish', () => {
88
+ busboy.on('close', () => {
89
89
  tryDone();
90
90
  });
91
91
  req.pipe(busboy);
@@ -204,7 +204,10 @@ router.patch('/', (0, validate_batch_1.validateBatch)('update'), (0, async_handl
204
204
  schema: req.schema,
205
205
  });
206
206
  let keys = [];
207
- if (req.body.keys) {
207
+ if (Array.isArray(req.body)) {
208
+ keys = await service.updateBatch(req.body);
209
+ }
210
+ else if (req.body.keys) {
208
211
  keys = await service.updateMany(req.body.keys, req.body.data);
209
212
  }
210
213
  else {
@@ -94,7 +94,10 @@ router.patch('/', (0, validate_batch_1.validateBatch)('update'), (0, async_handl
94
94
  schema: req.schema,
95
95
  });
96
96
  let keys = [];
97
- if (req.body.keys) {
97
+ if (Array.isArray(req.body)) {
98
+ keys = await service.updateBatch(req.body);
99
+ }
100
+ else if (req.body.keys) {
98
101
  keys = await service.updateMany(req.body.keys, req.body.data);
99
102
  }
100
103
  else {
@@ -84,7 +84,10 @@ router.patch('/', (0, validate_batch_1.validateBatch)('update'), (0, async_handl
84
84
  schema: req.schema,
85
85
  });
86
86
  let keys = [];
87
- if (req.body.keys) {
87
+ if (Array.isArray(req.body)) {
88
+ keys = await service.updateBatch(req.body);
89
+ }
90
+ else if (req.body.keys) {
88
91
  keys = await service.updateMany(req.body.keys, req.body.data);
89
92
  }
90
93
  else {
@@ -105,7 +105,10 @@ router.patch('/:collection', collection_exists_1.default, (0, validate_batch_1.v
105
105
  return next();
106
106
  }
107
107
  let keys = [];
108
- if (req.body.keys) {
108
+ if (Array.isArray(req.body)) {
109
+ keys = await service.updateBatch(req.body);
110
+ }
111
+ else if (req.body.keys) {
109
112
  keys = await service.updateMany(req.body.keys, req.body.data);
110
113
  }
111
114
  else {
@@ -84,7 +84,10 @@ router.patch('/', (0, validate_batch_1.validateBatch)('update'), (0, async_handl
84
84
  schema: req.schema,
85
85
  });
86
86
  let keys = [];
87
- if (req.body.keys) {
87
+ if (Array.isArray(req.body)) {
88
+ keys = await service.updateBatch(req.body);
89
+ }
90
+ else if (req.body.keys) {
88
91
  keys = await service.updateMany(req.body.keys, req.body.data);
89
92
  }
90
93
  else {
@@ -75,7 +75,10 @@ router.patch('/', (0, validate_batch_1.validateBatch)('update'), (0, async_handl
75
75
  schema: req.schema,
76
76
  });
77
77
  let keys = [];
78
- if (req.body.keys) {
78
+ if (Array.isArray(req.body)) {
79
+ keys = await service.updateBatch(req.body);
80
+ }
81
+ else if (req.body.keys) {
79
82
  keys = await service.updateMany(req.body.keys, req.body.data);
80
83
  }
81
84
  else {
@@ -75,7 +75,10 @@ router.patch('/', (0, validate_batch_1.validateBatch)('update'), (0, async_handl
75
75
  schema: req.schema,
76
76
  });
77
77
  let keys = [];
78
- if (req.body.keys) {
78
+ if (Array.isArray(req.body)) {
79
+ keys = await service.updateBatch(req.body);
80
+ }
81
+ else if (req.body.keys) {
79
82
  keys = await service.updateMany(req.body.keys, req.body.data);
80
83
  }
81
84
  else {
@@ -86,7 +86,10 @@ router.patch('/', (0, validate_batch_1.validateBatch)('update'), (0, async_handl
86
86
  schema: req.schema,
87
87
  });
88
88
  let keys = [];
89
- if (req.body.keys) {
89
+ if (Array.isArray(req.body)) {
90
+ keys = await service.updateBatch(req.body);
91
+ }
92
+ else if (req.body.keys) {
90
93
  keys = await service.updateMany(req.body.keys, req.body.data);
91
94
  }
92
95
  else {
@@ -84,7 +84,10 @@ router.patch('/', (0, validate_batch_1.validateBatch)('update'), (0, async_handl
84
84
  schema: req.schema,
85
85
  });
86
86
  let keys = [];
87
- if (req.body.keys) {
87
+ if (Array.isArray(req.body)) {
88
+ keys = await service.updateBatch(req.body);
89
+ }
90
+ else if (req.body.keys) {
88
91
  keys = await service.updateMany(req.body.keys, req.body.data);
89
92
  }
90
93
  else {
@@ -75,7 +75,10 @@ router.patch('/', (0, validate_batch_1.validateBatch)('update'), (0, async_handl
75
75
  schema: req.schema,
76
76
  });
77
77
  let keys = [];
78
- if (req.body.keys) {
78
+ if (Array.isArray(req.body)) {
79
+ keys = await service.updateBatch(req.body);
80
+ }
81
+ else if (req.body.keys) {
79
82
  keys = await service.updateMany(req.body.keys, req.body.data);
80
83
  }
81
84
  else {
@@ -149,7 +149,10 @@ router.patch('/', (0, validate_batch_1.validateBatch)('update'), (0, async_handl
149
149
  schema: req.schema,
150
150
  });
151
151
  let keys = [];
152
- if (req.body.keys) {
152
+ if (Array.isArray(req.body)) {
153
+ keys = await service.updateBatch(req.body);
154
+ }
155
+ else if (req.body.keys) {
153
156
  keys = await service.updateMany(req.body.keys, req.body.data);
154
157
  }
155
158
  else {
@@ -138,7 +138,10 @@ router.patch('/', (0, validate_batch_1.validateBatch)('update'), (0, async_handl
138
138
  schema: req.schema,
139
139
  });
140
140
  let keys = [];
141
- if (req.body.keys) {
141
+ if (Array.isArray(req.body)) {
142
+ keys = await service.updateBatch(req.body);
143
+ }
144
+ else if (req.body.keys) {
142
145
  keys = await service.updateMany(req.body.keys, req.body.data);
143
146
  }
144
147
  else {
@@ -251,7 +254,7 @@ router.post('/me/tfa/generate/', (0, async_handler_1.default)(async (req, res, n
251
254
  return next();
252
255
  }), respond_1.respond);
253
256
  router.post('/me/tfa/enable/', (0, async_handler_1.default)(async (req, _res, next) => {
254
- var _a;
257
+ var _a, _b;
255
258
  if (!((_a = req.accountability) === null || _a === void 0 ? void 0 : _a.user)) {
256
259
  throw new exceptions_1.InvalidCredentialsException();
257
260
  }
@@ -261,6 +264,33 @@ router.post('/me/tfa/enable/', (0, async_handler_1.default)(async (req, _res, ne
261
264
  if (!req.body.otp) {
262
265
  throw new exceptions_1.InvalidPayloadException(`"otp" is required`);
263
266
  }
267
+ // Override permissions only when enforce TFA is enabled in role
268
+ if (req.accountability.role) {
269
+ const rolesService = new services_1.RolesService({
270
+ schema: req.schema,
271
+ });
272
+ const role = (await rolesService.readOne(req.accountability.role));
273
+ if (role && role.enforce_tfa) {
274
+ const existingPermission = await ((_b = req.accountability.permissions) === null || _b === void 0 ? void 0 : _b.find((p) => p.collection === 'directus_users' && p.action === 'update'));
275
+ if (existingPermission) {
276
+ existingPermission.fields = ['tfa_secret'];
277
+ existingPermission.permissions = { id: { _eq: req.accountability.user } };
278
+ existingPermission.presets = null;
279
+ existingPermission.validation = null;
280
+ }
281
+ else {
282
+ (req.accountability.permissions || (req.accountability.permissions = [])).push({
283
+ action: 'update',
284
+ collection: 'directus_users',
285
+ fields: ['tfa_secret'],
286
+ permissions: { id: { _eq: req.accountability.user } },
287
+ presets: null,
288
+ role: req.accountability.role,
289
+ validation: null,
290
+ });
291
+ }
292
+ }
293
+ }
264
294
  const service = new services_1.TFAService({
265
295
  accountability: req.accountability,
266
296
  schema: req.schema,
@@ -269,13 +299,40 @@ router.post('/me/tfa/enable/', (0, async_handler_1.default)(async (req, _res, ne
269
299
  return next();
270
300
  }), respond_1.respond);
271
301
  router.post('/me/tfa/disable', (0, async_handler_1.default)(async (req, _res, next) => {
272
- var _a;
302
+ var _a, _b;
273
303
  if (!((_a = req.accountability) === null || _a === void 0 ? void 0 : _a.user)) {
274
304
  throw new exceptions_1.InvalidCredentialsException();
275
305
  }
276
306
  if (!req.body.otp) {
277
307
  throw new exceptions_1.InvalidPayloadException(`"otp" is required`);
278
308
  }
309
+ // Override permissions only when enforce TFA is enabled in role
310
+ if (req.accountability.role) {
311
+ const rolesService = new services_1.RolesService({
312
+ schema: req.schema,
313
+ });
314
+ const role = (await rolesService.readOne(req.accountability.role));
315
+ if (role && role.enforce_tfa) {
316
+ const existingPermission = await ((_b = req.accountability.permissions) === null || _b === void 0 ? void 0 : _b.find((p) => p.collection === 'directus_users' && p.action === 'update'));
317
+ if (existingPermission) {
318
+ existingPermission.fields = ['tfa_secret'];
319
+ existingPermission.permissions = { id: { _eq: req.accountability.user } };
320
+ existingPermission.presets = null;
321
+ existingPermission.validation = null;
322
+ }
323
+ else {
324
+ (req.accountability.permissions || (req.accountability.permissions = [])).push({
325
+ action: 'update',
326
+ collection: 'directus_users',
327
+ fields: ['tfa_secret'],
328
+ permissions: { id: { _eq: req.accountability.user } },
329
+ presets: null,
330
+ role: req.accountability.role,
331
+ validation: null,
332
+ });
333
+ }
334
+ }
335
+ }
279
336
  const service = new services_1.TFAService({
280
337
  accountability: req.accountability,
281
338
  schema: req.schema,
@@ -287,4 +344,19 @@ router.post('/me/tfa/disable', (0, async_handler_1.default)(async (req, _res, ne
287
344
  await service.disableTFA(req.accountability.user);
288
345
  return next();
289
346
  }), respond_1.respond);
347
+ router.post('/:pk/tfa/disable', (0, async_handler_1.default)(async (req, _res, next) => {
348
+ var _a;
349
+ if (!((_a = req.accountability) === null || _a === void 0 ? void 0 : _a.user)) {
350
+ throw new exceptions_1.InvalidCredentialsException();
351
+ }
352
+ if (!req.accountability.admin || !req.params.pk) {
353
+ throw new exceptions_1.ForbiddenException();
354
+ }
355
+ const service = new services_1.TFAService({
356
+ accountability: req.accountability,
357
+ schema: req.schema,
358
+ });
359
+ await service.disableTFA(req.params.pk);
360
+ return next();
361
+ }), respond_1.respond);
290
362
  exports.default = router;
@@ -82,10 +82,10 @@ router.post('/import/:collection', collection_exists_1.default, (0, async_handle
82
82
  'content-type': 'application/octet-stream',
83
83
  };
84
84
  }
85
- const busboy = new busboy_1.default({ headers });
86
- busboy.on('file', async (fieldname, fileStream, filename, encoding, mimetype) => {
85
+ const busboy = (0, busboy_1.default)({ headers });
86
+ busboy.on('file', async (_fieldname, fileStream, { mimeType }) => {
87
87
  try {
88
- await service.import(req.params.collection, mimetype, fileStream);
88
+ await service.import(req.params.collection, mimeType, fileStream);
89
89
  }
90
90
  catch (err) {
91
91
  return next(err);
@@ -4,6 +4,9 @@ exports.DateHelperSQLite = void 0;
4
4
  const types_1 = require("../types");
5
5
  class DateHelperSQLite extends types_1.DateHelper {
6
6
  parse(date) {
7
+ if (!date) {
8
+ return date;
9
+ }
7
10
  // Return the time as string
8
11
  if (date.length <= 8 && date.includes(':')) {
9
12
  return date;
@@ -1,13 +1,13 @@
1
- import { FnHelper } from '../types';
1
+ import { FnHelper, FnHelperOptions } from '../types';
2
2
  import { Knex } from 'knex';
3
3
  export declare class FnHelperOracle extends FnHelper {
4
- year(table: string, column: string): Knex.Raw;
5
- month(table: string, column: string): Knex.Raw;
6
- week(table: string, column: string): Knex.Raw;
7
- day(table: string, column: string): Knex.Raw;
8
- weekday(table: string, column: string): Knex.Raw;
9
- hour(table: string, column: string): Knex.Raw;
10
- minute(table: string, column: string): Knex.Raw;
11
- second(table: string, column: string): Knex.Raw;
4
+ year(table: string, column: string, options: FnHelperOptions): Knex.Raw;
5
+ month(table: string, column: string, options: FnHelperOptions): Knex.Raw;
6
+ week(table: string, column: string, options: FnHelperOptions): Knex.Raw;
7
+ day(table: string, column: string, options: FnHelperOptions): Knex.Raw;
8
+ weekday(table: string, column: string, options: FnHelperOptions): Knex.Raw;
9
+ hour(table: string, column: string, options: FnHelperOptions): Knex.Raw;
10
+ minute(table: string, column: string, options: FnHelperOptions): Knex.Raw;
11
+ second(table: string, column: string, options: FnHelperOptions): Knex.Raw;
12
12
  count(table: string, column: string): Knex.Raw<any>;
13
13
  }
@@ -2,30 +2,36 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.FnHelperOracle = void 0;
4
4
  const types_1 = require("../types");
5
+ const parseLocaltime = (columnType) => {
6
+ if (columnType === 'timestamp') {
7
+ return ` AT TIME ZONE 'UTC'`;
8
+ }
9
+ return '';
10
+ };
5
11
  class FnHelperOracle extends types_1.FnHelper {
6
- year(table, column) {
7
- return this.knex.raw("TO_CHAR(??.??, 'IYYY')", [table, column]);
12
+ year(table, column, options) {
13
+ return this.knex.raw(`TO_CHAR(??.??${parseLocaltime(options === null || options === void 0 ? void 0 : options.type)}, 'IYYY')`, [table, column]);
8
14
  }
9
- month(table, column) {
10
- return this.knex.raw("TO_CHAR(??.??, 'MM')", [table, column]);
15
+ month(table, column, options) {
16
+ return this.knex.raw(`TO_CHAR(??.??${parseLocaltime(options === null || options === void 0 ? void 0 : options.type)}, 'MM')`, [table, column]);
11
17
  }
12
- week(table, column) {
13
- return this.knex.raw("TO_CHAR(??.??, 'IW')", [table, column]);
18
+ week(table, column, options) {
19
+ return this.knex.raw(`TO_CHAR(??.??${parseLocaltime(options === null || options === void 0 ? void 0 : options.type)}, 'IW')`, [table, column]);
14
20
  }
15
- day(table, column) {
16
- return this.knex.raw("TO_CHAR(??.??, 'DD')", [table, column]);
21
+ day(table, column, options) {
22
+ return this.knex.raw(`TO_CHAR(??.??${parseLocaltime(options === null || options === void 0 ? void 0 : options.type)}, 'DD')`, [table, column]);
17
23
  }
18
- weekday(table, column) {
19
- return this.knex.raw("TO_CHAR(??.??, 'D')", [table, column]);
24
+ weekday(table, column, options) {
25
+ return this.knex.raw(`TO_CHAR(??.??${parseLocaltime(options === null || options === void 0 ? void 0 : options.type)}, 'D')`, [table, column]);
20
26
  }
21
- hour(table, column) {
22
- return this.knex.raw("TO_CHAR(??.??, 'HH24')", [table, column]);
27
+ hour(table, column, options) {
28
+ return this.knex.raw(`TO_CHAR(??.??${parseLocaltime(options === null || options === void 0 ? void 0 : options.type)}, 'HH24')`, [table, column]);
23
29
  }
24
- minute(table, column) {
25
- return this.knex.raw("TO_CHAR(??.??, 'MI')", [table, column]);
30
+ minute(table, column, options) {
31
+ return this.knex.raw(`TO_CHAR(??.??${parseLocaltime(options === null || options === void 0 ? void 0 : options.type)}, 'MI')`, [table, column]);
26
32
  }
27
- second(table, column) {
28
- return this.knex.raw("TO_CHAR(??.??, 'SS')", [table, column]);
33
+ second(table, column, options) {
34
+ return this.knex.raw(`TO_CHAR(??.??${parseLocaltime(options === null || options === void 0 ? void 0 : options.type)}, 'SS')`, [table, column]);
29
35
  }
30
36
  count(table, column) {
31
37
  var _a, _b, _c, _d, _e;
@@ -1,13 +1,13 @@
1
- import { FnHelper } from '../types';
1
+ import { FnHelper, FnHelperOptions } from '../types';
2
2
  import { Knex } from 'knex';
3
3
  export declare class FnHelperSQLite extends FnHelper {
4
- year(table: string, column: string): Knex.Raw;
5
- month(table: string, column: string): Knex.Raw;
6
- week(table: string, column: string): Knex.Raw;
7
- day(table: string, column: string): Knex.Raw;
8
- weekday(table: string, column: string): Knex.Raw;
9
- hour(table: string, column: string): Knex.Raw;
10
- minute(table: string, column: string): Knex.Raw;
11
- second(table: string, column: string): Knex.Raw;
4
+ year(table: string, column: string, options?: FnHelperOptions): Knex.Raw;
5
+ month(table: string, column: string, options?: FnHelperOptions): Knex.Raw;
6
+ week(table: string, column: string, options?: FnHelperOptions): Knex.Raw;
7
+ day(table: string, column: string, options?: FnHelperOptions): Knex.Raw;
8
+ weekday(table: string, column: string, options?: FnHelperOptions): Knex.Raw;
9
+ hour(table: string, column: string, options?: FnHelperOptions): Knex.Raw;
10
+ minute(table: string, column: string, options?: FnHelperOptions): Knex.Raw;
11
+ second(table: string, column: string, options?: FnHelperOptions): Knex.Raw;
12
12
  count(table: string, column: string): Knex.Raw<any>;
13
13
  }
@@ -2,30 +2,60 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.FnHelperSQLite = void 0;
4
4
  const types_1 = require("../types");
5
+ const parseLocaltime = (columnType) => {
6
+ if (columnType === 'timestamp') {
7
+ return '';
8
+ }
9
+ return `, 'localtime'`;
10
+ };
5
11
  class FnHelperSQLite extends types_1.FnHelper {
6
- year(table, column) {
7
- return this.knex.raw("CAST(strftime('%Y', ??.?? / 1000, 'unixepoch') AS INTEGER)", [table, column]);
12
+ year(table, column, options) {
13
+ return this.knex.raw(`CAST(strftime('%Y', ??.?? / 1000, 'unixepoch'${parseLocaltime(options === null || options === void 0 ? void 0 : options.type)}) AS INTEGER)`, [
14
+ table,
15
+ column,
16
+ ]);
8
17
  }
9
- month(table, column) {
10
- return this.knex.raw("CAST(strftime('%m', ??.?? / 1000, 'unixepoch') AS INTEGER)", [table, column]);
18
+ month(table, column, options) {
19
+ return this.knex.raw(`CAST(strftime('%m', ??.?? / 1000, 'unixepoch'${parseLocaltime(options === null || options === void 0 ? void 0 : options.type)}) AS INTEGER)`, [
20
+ table,
21
+ column,
22
+ ]);
11
23
  }
12
- week(table, column) {
13
- return this.knex.raw("CAST(strftime('%W', ??.?? / 1000, 'unixepoch') AS INTEGER)", [table, column]);
24
+ week(table, column, options) {
25
+ return this.knex.raw(`CAST(strftime('%W', ??.?? / 1000, 'unixepoch'${parseLocaltime(options === null || options === void 0 ? void 0 : options.type)}) AS INTEGER)`, [
26
+ table,
27
+ column,
28
+ ]);
14
29
  }
15
- day(table, column) {
16
- return this.knex.raw("CAST(strftime('%d', ??.?? / 1000, 'unixepoch') AS INTEGER)", [table, column]);
30
+ day(table, column, options) {
31
+ return this.knex.raw(`CAST(strftime('%d', ??.?? / 1000, 'unixepoch'${parseLocaltime(options === null || options === void 0 ? void 0 : options.type)}) AS INTEGER)`, [
32
+ table,
33
+ column,
34
+ ]);
17
35
  }
18
- weekday(table, column) {
19
- return this.knex.raw("CAST(strftime('%w', ??.?? / 1000, 'unixepoch') AS INTEGER)", [table, column]);
36
+ weekday(table, column, options) {
37
+ return this.knex.raw(`CAST(strftime('%w', ??.?? / 1000, 'unixepoch'${parseLocaltime(options === null || options === void 0 ? void 0 : options.type)}) AS INTEGER)`, [
38
+ table,
39
+ column,
40
+ ]);
20
41
  }
21
- hour(table, column) {
22
- return this.knex.raw("CAST(strftime('%H', ??.?? / 1000, 'unixepoch') AS INTEGER)", [table, column]);
42
+ hour(table, column, options) {
43
+ return this.knex.raw(`CAST(strftime('%H', ??.?? / 1000, 'unixepoch'${parseLocaltime(options === null || options === void 0 ? void 0 : options.type)}) AS INTEGER)`, [
44
+ table,
45
+ column,
46
+ ]);
23
47
  }
24
- minute(table, column) {
25
- return this.knex.raw("CAST(strftime('%M', ??.?? / 1000, 'unixepoch') AS INTEGER)", [table, column]);
48
+ minute(table, column, options) {
49
+ return this.knex.raw(`CAST(strftime('%M', ??.?? / 1000, 'unixepoch'${parseLocaltime(options === null || options === void 0 ? void 0 : options.type)}) AS INTEGER)`, [
50
+ table,
51
+ column,
52
+ ]);
26
53
  }
27
- second(table, column) {
28
- return this.knex.raw("CAST(strftime('%S', ??.?? / 1000, 'unixepoch') AS INTEGER)", [table, column]);
54
+ second(table, column, options) {
55
+ return this.knex.raw(`CAST(strftime('%S', ??.?? / 1000, 'unixepoch'${parseLocaltime(options === null || options === void 0 ? void 0 : options.type)}) AS INTEGER)`, [
56
+ table,
57
+ column,
58
+ ]);
29
59
  }
30
60
  count(table, column) {
31
61
  var _a, _b, _c, _d, _e;
@@ -1,18 +1,21 @@
1
1
  import { SchemaOverview } from '@directus/shared/types';
2
2
  import { Knex } from 'knex';
3
3
  import { DatabaseHelper } from '../types';
4
+ export declare type FnHelperOptions = {
5
+ type?: string;
6
+ };
4
7
  export declare abstract class FnHelper extends DatabaseHelper {
5
8
  protected knex: Knex;
6
9
  protected schema: SchemaOverview;
7
10
  constructor(knex: Knex, schema: SchemaOverview);
8
- abstract year(table: string, column: string): Knex.Raw;
9
- abstract month(table: string, column: string): Knex.Raw;
10
- abstract week(table: string, column: string): Knex.Raw;
11
- abstract day(table: string, column: string): Knex.Raw;
12
- abstract weekday(table: string, column: string): Knex.Raw;
13
- abstract hour(table: string, column: string): Knex.Raw;
14
- abstract minute(table: string, column: string): Knex.Raw;
15
- abstract second(table: string, column: string): Knex.Raw;
16
- abstract count(table: string, column: string): Knex.Raw;
11
+ abstract year(table: string, column: string, options?: FnHelperOptions): Knex.Raw;
12
+ abstract month(table: string, column: string, options?: FnHelperOptions): Knex.Raw;
13
+ abstract week(table: string, column: string, options?: FnHelperOptions): Knex.Raw;
14
+ abstract day(table: string, column: string, options?: FnHelperOptions): Knex.Raw;
15
+ abstract weekday(table: string, column: string, options?: FnHelperOptions): Knex.Raw;
16
+ abstract hour(table: string, column: string, options?: FnHelperOptions): Knex.Raw;
17
+ abstract minute(table: string, column: string, options?: FnHelperOptions): Knex.Raw;
18
+ abstract second(table: string, column: string, options?: FnHelperOptions): Knex.Raw;
19
+ abstract count(table: string, column: string, options?: FnHelperOptions): Knex.Raw;
17
20
  protected _relationalCount(table: string, column: string): Knex.Raw;
18
21
  }
@@ -1,7 +1,11 @@
1
1
  "use strict";
2
2
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
3
  if (k2 === undefined) k2 = k;
4
- Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[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);
5
9
  }) : (function(o, m, k, k2) {
6
10
  if (k2 === undefined) k2 = k;
7
11
  o[k2] = m[k];
@@ -64,6 +64,8 @@ function getDatabase() {
64
64
  // Ignore warnings about returning not being supported in some DBs
65
65
  if (msg.startsWith('.returning()'))
66
66
  return;
67
+ if (msg.endsWith('does not currently support RETURNING clause'))
68
+ return;
67
69
  // Ignore warning about MySQL not supporting TRX for DDL
68
70
  if (msg.startsWith('Transaction was implicitly committed, do not mix transactions and DDL with MySQL'))
69
71
  return;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.down = exports.up = void 0;
4
- const parse_json_1 = require("../../utils/parse-json");
4
+ const utils_1 = require("@directus/shared/utils");
5
5
  async function up(knex) {
6
6
  var _a;
7
7
  await knex.schema.alterTable('directus_relations', (table) => {
@@ -12,7 +12,7 @@ async function up(knex) {
12
12
  .from('directus_fields')
13
13
  .whereIn('interface', ['one-to-many', 'm2a-builder', 'many-to-many']);
14
14
  for (const field of fieldsWithSort) {
15
- const options = typeof field.options === 'string' ? (0, parse_json_1.parseJSON)(field.options) : (_a = field.options) !== null && _a !== void 0 ? _a : {};
15
+ const options = typeof field.options === 'string' ? (0, utils_1.parseJSON)(field.options) : (_a = field.options) !== null && _a !== void 0 ? _a : {};
16
16
  if ('sortField' in options) {
17
17
  await knex('directus_relations')
18
18
  .update({
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.down = exports.up = void 0;
4
- const parse_json_1 = require("../../utils/parse-json");
4
+ const utils_1 = require("@directus/shared/utils");
5
5
  // [before, after, after-option additions]
6
6
  const changes = [
7
7
  ['button-links', 'presentation-links'],
@@ -55,7 +55,7 @@ async function up(knex) {
55
55
  .from('directus_fields')
56
56
  .where({ interface: before });
57
57
  for (const { id, options: existingOptionsRaw } of fields) {
58
- const existingOptions = typeof existingOptionsRaw === 'string' ? (0, parse_json_1.parseJSON)(existingOptionsRaw) : existingOptionsRaw;
58
+ const existingOptions = typeof existingOptionsRaw === 'string' ? (0, utils_1.parseJSON)(existingOptionsRaw) : existingOptionsRaw;
59
59
  const newOptions = {
60
60
  ...(existingOptions || {}),
61
61
  ...options,
@@ -4,15 +4,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.down = exports.up = void 0;
7
+ const utils_1 = require("@directus/shared/utils");
7
8
  const logger_1 = __importDefault(require("../../logger"));
8
- const parse_json_1 = require("../../utils/parse-json");
9
9
  async function up(knex) {
10
10
  const dividerGroups = await knex.select('*').from('directus_fields').where('interface', '=', 'group-divider');
11
11
  for (const dividerGroup of dividerGroups) {
12
12
  const newOptions = { showHeader: true };
13
13
  if (dividerGroup.options) {
14
14
  try {
15
- const options = typeof dividerGroup.options === 'string' ? (0, parse_json_1.parseJSON)(dividerGroup.options) : dividerGroup.options;
15
+ const options = typeof dividerGroup.options === 'string' ? (0, utils_1.parseJSON)(dividerGroup.options) : dividerGroup.options;
16
16
  if (options.icon)
17
17
  newOptions.headerIcon = options.icon;
18
18
  if (options.color)
@@ -1,13 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.down = exports.up = void 0;
4
- const parse_json_1 = require("../../utils/parse-json");
4
+ const utils_1 = require("@directus/shared/utils");
5
5
  async function up(knex) {
6
6
  const groups = await knex.select('*').from('directus_fields').where({ interface: 'group-standard' });
7
7
  const raw = [];
8
8
  const detail = [];
9
9
  for (const group of groups) {
10
- const options = typeof group.options === 'string' ? (0, parse_json_1.parseJSON)(group.options) : group.options || {};
10
+ const options = typeof group.options === 'string' ? (0, utils_1.parseJSON)(group.options) : group.options || {};
11
11
  if (options.showHeader === true) {
12
12
  detail.push(group);
13
13
  }