@directus/api 20.0.0-rc.0 → 20.0.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 (291) hide show
  1. package/dist/app.js +9 -4
  2. package/dist/auth/drivers/ldap.js +4 -4
  3. package/dist/auth/drivers/local.js +4 -4
  4. package/dist/auth/drivers/oauth2.js +4 -4
  5. package/dist/auth/drivers/openid.js +4 -2
  6. package/dist/cache.js +0 -3
  7. package/dist/cli/commands/bootstrap/index.js +2 -8
  8. package/dist/cli/commands/init/index.js +10 -9
  9. package/dist/cli/utils/defaults.d.ts +11 -4
  10. package/dist/cli/utils/defaults.js +1 -7
  11. package/dist/constants.d.ts +9 -1
  12. package/dist/constants.js +10 -0
  13. package/dist/controllers/auth.js +16 -5
  14. package/dist/controllers/permissions.js +2 -14
  15. package/dist/controllers/roles.js +1 -22
  16. package/dist/controllers/{access.d.ts → tus.d.ts} +1 -0
  17. package/dist/controllers/tus.js +72 -0
  18. package/dist/controllers/users.js +55 -0
  19. package/dist/database/helpers/fn/types.d.ts +1 -2
  20. package/dist/database/helpers/fn/types.js +1 -1
  21. package/dist/database/helpers/geometry/dialects/mssql.d.ts +1 -1
  22. package/dist/database/helpers/geometry/dialects/mssql.js +2 -4
  23. package/dist/database/helpers/geometry/dialects/mysql.js +1 -1
  24. package/dist/database/helpers/geometry/dialects/oracle.d.ts +1 -1
  25. package/dist/database/helpers/geometry/dialects/oracle.js +3 -5
  26. package/dist/database/helpers/geometry/types.d.ts +1 -1
  27. package/dist/database/helpers/geometry/types.js +2 -4
  28. package/dist/database/index.js +1 -2
  29. package/dist/database/migrations/20240701A-add-tus-data.js +12 -0
  30. package/dist/database/{run-ast/types.d.ts → run-ast.d.ts} +9 -3
  31. package/dist/database/run-ast.js +450 -0
  32. package/dist/flows.js +4 -3
  33. package/dist/middleware/authenticate.js +7 -2
  34. package/dist/middleware/cache.js +1 -1
  35. package/dist/middleware/check-ip.d.ts +2 -0
  36. package/dist/middleware/check-ip.js +37 -0
  37. package/dist/middleware/get-permissions.d.ts +3 -0
  38. package/dist/middleware/get-permissions.js +10 -0
  39. package/dist/middleware/respond.js +1 -1
  40. package/dist/services/activity.js +10 -22
  41. package/dist/services/assets.d.ts +3 -2
  42. package/dist/services/assets.js +5 -10
  43. package/dist/services/authentication.js +26 -32
  44. package/dist/services/authorization.d.ts +17 -0
  45. package/dist/services/authorization.js +456 -0
  46. package/dist/services/collections.js +17 -18
  47. package/dist/services/fields.d.ts +1 -0
  48. package/dist/services/fields.js +24 -53
  49. package/dist/services/files/lib/extract-metadata.d.ts +3 -0
  50. package/dist/services/files/lib/extract-metadata.js +32 -0
  51. package/dist/services/files/utils/get-metadata.d.ts +5 -0
  52. package/dist/services/files/utils/get-metadata.js +107 -0
  53. package/dist/services/files.d.ts +4 -6
  54. package/dist/services/files.js +24 -140
  55. package/dist/services/graphql/index.d.ts +3 -3
  56. package/dist/services/graphql/index.js +22 -126
  57. package/dist/services/graphql/subscription.js +4 -2
  58. package/dist/services/import-export.js +4 -18
  59. package/dist/services/index.d.ts +2 -3
  60. package/dist/services/index.js +2 -3
  61. package/dist/services/items.js +44 -115
  62. package/dist/services/meta.js +23 -60
  63. package/dist/services/payload.d.ts +10 -9
  64. package/dist/services/payload.js +3 -18
  65. package/dist/services/{permissions.d.ts → permissions/index.d.ts} +7 -5
  66. package/dist/services/{permissions.js → permissions/index.js} +54 -30
  67. package/dist/{permissions → services/permissions}/lib/with-app-minimal-permissions.d.ts +1 -1
  68. package/dist/services/permissions/lib/with-app-minimal-permissions.js +13 -0
  69. package/dist/services/relations.d.ts +6 -0
  70. package/dist/services/relations.js +29 -26
  71. package/dist/services/roles.d.ts +12 -4
  72. package/dist/services/roles.js +424 -57
  73. package/dist/services/server.js +6 -0
  74. package/dist/services/shares.d.ts +2 -0
  75. package/dist/services/shares.js +8 -12
  76. package/dist/services/specifications.d.ts +2 -2
  77. package/dist/services/specifications.js +27 -39
  78. package/dist/services/tus/data-store.d.ts +36 -0
  79. package/dist/services/tus/data-store.js +214 -0
  80. package/dist/services/tus/index.d.ts +2 -0
  81. package/dist/services/tus/index.js +2 -0
  82. package/dist/services/tus/lockers.d.ts +36 -0
  83. package/dist/services/tus/lockers.js +83 -0
  84. package/dist/services/tus/server.d.ts +8 -0
  85. package/dist/services/tus/server.js +80 -0
  86. package/dist/services/tus/utils/wait-timeout.d.ts +1 -0
  87. package/dist/services/tus/utils/wait-timeout.js +13 -0
  88. package/dist/services/users.d.ts +5 -1
  89. package/dist/services/users.js +161 -78
  90. package/dist/services/utils.js +7 -11
  91. package/dist/services/versions.d.ts +2 -0
  92. package/dist/services/versions.js +10 -34
  93. package/dist/storage/register-locations.js +5 -1
  94. package/dist/telemetry/lib/get-report.js +2 -2
  95. package/dist/telemetry/utils/check-increased-user-limits.d.ts +7 -0
  96. package/dist/telemetry/utils/check-increased-user-limits.js +25 -0
  97. package/dist/telemetry/utils/get-role-counts-by-roles.d.ts +6 -0
  98. package/dist/telemetry/utils/get-role-counts-by-roles.js +27 -0
  99. package/dist/telemetry/utils/get-role-counts-by-users.d.ts +11 -0
  100. package/dist/telemetry/utils/get-role-counts-by-users.js +34 -0
  101. package/dist/telemetry/utils/get-user-count.d.ts +8 -0
  102. package/dist/telemetry/utils/get-user-count.js +33 -0
  103. package/dist/telemetry/utils/get-user-counts-by-roles.d.ts +7 -0
  104. package/dist/telemetry/utils/get-user-counts-by-roles.js +35 -0
  105. package/dist/types/ast.d.ts +1 -43
  106. package/dist/types/items.d.ts +0 -11
  107. package/dist/utils/apply-query.d.ts +3 -4
  108. package/dist/utils/apply-query.js +8 -37
  109. package/dist/utils/get-accountability-for-role.js +25 -16
  110. package/dist/utils/get-accountability-for-token.js +16 -17
  111. package/dist/utils/get-ast-from-query.d.ts +13 -0
  112. package/dist/utils/get-ast-from-query.js +297 -0
  113. package/dist/utils/get-cache-key.d.ts +1 -1
  114. package/dist/utils/get-cache-key.js +1 -12
  115. package/dist/utils/get-column.d.ts +1 -2
  116. package/dist/utils/get-column.js +0 -1
  117. package/dist/utils/get-permissions.d.ts +2 -0
  118. package/dist/utils/get-permissions.js +150 -0
  119. package/dist/utils/get-service.js +1 -5
  120. package/dist/utils/merge-permissions-for-share.d.ts +4 -0
  121. package/dist/utils/merge-permissions-for-share.js +109 -0
  122. package/dist/utils/merge-permissions.d.ts +3 -0
  123. package/dist/utils/merge-permissions.js +95 -0
  124. package/dist/utils/reduce-schema.d.ts +6 -4
  125. package/dist/utils/reduce-schema.js +34 -14
  126. package/dist/utils/verify-session-jwt.js +2 -1
  127. package/dist/websocket/authenticate.d.ts +2 -0
  128. package/dist/websocket/authenticate.js +12 -0
  129. package/dist/websocket/controllers/graphql.js +4 -1
  130. package/dist/websocket/controllers/hooks.js +0 -4
  131. package/dist/websocket/controllers/rest.js +2 -0
  132. package/dist/websocket/handlers/subscribe.js +2 -0
  133. package/dist/websocket/utils/items.d.ts +1 -1
  134. package/package.json +35 -33
  135. package/dist/controllers/access.js +0 -148
  136. package/dist/controllers/policies.d.ts +0 -2
  137. package/dist/controllers/policies.js +0 -169
  138. package/dist/database/get-ast-from-query/get-ast-from-query.d.ts +0 -16
  139. package/dist/database/get-ast-from-query/get-ast-from-query.js +0 -82
  140. package/dist/database/get-ast-from-query/lib/convert-wildcards.d.ts +0 -13
  141. package/dist/database/get-ast-from-query/lib/convert-wildcards.js +0 -69
  142. package/dist/database/get-ast-from-query/lib/parse-fields.d.ts +0 -15
  143. package/dist/database/get-ast-from-query/lib/parse-fields.js +0 -190
  144. package/dist/database/get-ast-from-query/utils/get-deep-query.d.ts +0 -14
  145. package/dist/database/get-ast-from-query/utils/get-deep-query.js +0 -17
  146. package/dist/database/get-ast-from-query/utils/get-related-collection.d.ts +0 -2
  147. package/dist/database/get-ast-from-query/utils/get-related-collection.js +0 -13
  148. package/dist/database/get-ast-from-query/utils/get-relation.d.ts +0 -2
  149. package/dist/database/get-ast-from-query/utils/get-relation.js +0 -7
  150. package/dist/database/migrations/20240619A-permissions-policies.js +0 -163
  151. package/dist/database/run-ast/lib/get-db-query.d.ts +0 -4
  152. package/dist/database/run-ast/lib/get-db-query.js +0 -194
  153. package/dist/database/run-ast/lib/parse-current-level.d.ts +0 -7
  154. package/dist/database/run-ast/lib/parse-current-level.js +0 -41
  155. package/dist/database/run-ast/run-ast.d.ts +0 -7
  156. package/dist/database/run-ast/run-ast.js +0 -107
  157. package/dist/database/run-ast/types.js +0 -1
  158. package/dist/database/run-ast/utils/apply-case-when.d.ts +0 -16
  159. package/dist/database/run-ast/utils/apply-case-when.js +0 -26
  160. package/dist/database/run-ast/utils/apply-parent-filters.d.ts +0 -3
  161. package/dist/database/run-ast/utils/apply-parent-filters.js +0 -55
  162. package/dist/database/run-ast/utils/get-column-pre-processor.d.ts +0 -10
  163. package/dist/database/run-ast/utils/get-column-pre-processor.js +0 -57
  164. package/dist/database/run-ast/utils/get-field-alias.d.ts +0 -2
  165. package/dist/database/run-ast/utils/get-field-alias.js +0 -4
  166. package/dist/database/run-ast/utils/get-inner-query-column-pre-processor.d.ts +0 -5
  167. package/dist/database/run-ast/utils/get-inner-query-column-pre-processor.js +0 -23
  168. package/dist/database/run-ast/utils/merge-with-parent-items.d.ts +0 -3
  169. package/dist/database/run-ast/utils/merge-with-parent-items.js +0 -87
  170. package/dist/database/run-ast/utils/remove-temporary-fields.d.ts +0 -3
  171. package/dist/database/run-ast/utils/remove-temporary-fields.js +0 -73
  172. package/dist/permissions/cache.d.ts +0 -2
  173. package/dist/permissions/cache.js +0 -23
  174. package/dist/permissions/lib/fetch-permissions.d.ts +0 -10
  175. package/dist/permissions/lib/fetch-permissions.js +0 -55
  176. package/dist/permissions/lib/fetch-policies.d.ts +0 -7
  177. package/dist/permissions/lib/fetch-policies.js +0 -28
  178. package/dist/permissions/lib/fetch-roles-tree.d.ts +0 -3
  179. package/dist/permissions/lib/fetch-roles-tree.js +0 -28
  180. package/dist/permissions/lib/with-app-minimal-permissions.js +0 -10
  181. package/dist/permissions/modules/fetch-accountability-collection-access/fetch-accountability-collection-access.d.ts +0 -7
  182. package/dist/permissions/modules/fetch-accountability-collection-access/fetch-accountability-collection-access.js +0 -56
  183. package/dist/permissions/modules/fetch-accountability-policy-globals/fetch-accountability-policy-globals.d.ts +0 -3
  184. package/dist/permissions/modules/fetch-accountability-policy-globals/fetch-accountability-policy-globals.js +0 -16
  185. package/dist/permissions/modules/fetch-allowed-collections/fetch-allowed-collections.d.ts +0 -8
  186. package/dist/permissions/modules/fetch-allowed-collections/fetch-allowed-collections.js +0 -24
  187. package/dist/permissions/modules/fetch-allowed-field-map/fetch-allowed-field-map.d.ts +0 -9
  188. package/dist/permissions/modules/fetch-allowed-field-map/fetch-allowed-field-map.js +0 -31
  189. package/dist/permissions/modules/fetch-allowed-fields/fetch-allowed-fields.d.ts +0 -16
  190. package/dist/permissions/modules/fetch-allowed-fields/fetch-allowed-fields.js +0 -27
  191. package/dist/permissions/modules/fetch-global-access/fetch-global-access.d.ts +0 -10
  192. package/dist/permissions/modules/fetch-global-access/fetch-global-access.js +0 -23
  193. package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-roles.d.ts +0 -5
  194. package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-roles.js +0 -7
  195. package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-user.d.ts +0 -5
  196. package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-user.js +0 -10
  197. package/dist/permissions/modules/fetch-global-access/types.d.ts +0 -4
  198. package/dist/permissions/modules/fetch-global-access/types.js +0 -1
  199. package/dist/permissions/modules/fetch-global-access/utils/fetch-global-access-for-query.d.ts +0 -4
  200. package/dist/permissions/modules/fetch-global-access/utils/fetch-global-access-for-query.js +0 -27
  201. package/dist/permissions/modules/fetch-inconsistent-field-map/fetch-inconsistent-field-map.d.ts +0 -12
  202. package/dist/permissions/modules/fetch-inconsistent-field-map/fetch-inconsistent-field-map.js +0 -32
  203. package/dist/permissions/modules/fetch-policies-ip-access/fetch-policies-ip-access.d.ts +0 -4
  204. package/dist/permissions/modules/fetch-policies-ip-access/fetch-policies-ip-access.js +0 -29
  205. package/dist/permissions/modules/process-ast/lib/extract-fields-from-children.d.ts +0 -4
  206. package/dist/permissions/modules/process-ast/lib/extract-fields-from-children.js +0 -49
  207. package/dist/permissions/modules/process-ast/lib/extract-fields-from-query.d.ts +0 -3
  208. package/dist/permissions/modules/process-ast/lib/extract-fields-from-query.js +0 -56
  209. package/dist/permissions/modules/process-ast/lib/field-map-from-ast.d.ts +0 -4
  210. package/dist/permissions/modules/process-ast/lib/field-map-from-ast.js +0 -8
  211. package/dist/permissions/modules/process-ast/lib/inject-cases.d.ts +0 -9
  212. package/dist/permissions/modules/process-ast/lib/inject-cases.js +0 -93
  213. package/dist/permissions/modules/process-ast/process-ast.d.ts +0 -9
  214. package/dist/permissions/modules/process-ast/process-ast.js +0 -39
  215. package/dist/permissions/modules/process-ast/types.d.ts +0 -24
  216. package/dist/permissions/modules/process-ast/types.js +0 -1
  217. package/dist/permissions/modules/process-ast/utils/collections-in-field-map.d.ts +0 -2
  218. package/dist/permissions/modules/process-ast/utils/collections-in-field-map.js +0 -7
  219. package/dist/permissions/modules/process-ast/utils/dedupe-access.d.ts +0 -12
  220. package/dist/permissions/modules/process-ast/utils/dedupe-access.js +0 -30
  221. package/dist/permissions/modules/process-ast/utils/extract-paths-from-query.d.ts +0 -15
  222. package/dist/permissions/modules/process-ast/utils/extract-paths-from-query.js +0 -50
  223. package/dist/permissions/modules/process-ast/utils/find-related-collection.d.ts +0 -3
  224. package/dist/permissions/modules/process-ast/utils/find-related-collection.js +0 -9
  225. package/dist/permissions/modules/process-ast/utils/flatten-filter.d.ts +0 -3
  226. package/dist/permissions/modules/process-ast/utils/flatten-filter.js +0 -24
  227. package/dist/permissions/modules/process-ast/utils/format-a2o-key.d.ts +0 -1
  228. package/dist/permissions/modules/process-ast/utils/format-a2o-key.js +0 -3
  229. package/dist/permissions/modules/process-ast/utils/get-info-for-path.d.ts +0 -5
  230. package/dist/permissions/modules/process-ast/utils/get-info-for-path.js +0 -7
  231. package/dist/permissions/modules/process-ast/utils/has-item-permissions.d.ts +0 -2
  232. package/dist/permissions/modules/process-ast/utils/has-item-permissions.js +0 -3
  233. package/dist/permissions/modules/process-ast/utils/stringify-query-path.d.ts +0 -2
  234. package/dist/permissions/modules/process-ast/utils/stringify-query-path.js +0 -3
  235. package/dist/permissions/modules/process-ast/utils/validate-path/create-error.d.ts +0 -3
  236. package/dist/permissions/modules/process-ast/utils/validate-path/create-error.js +0 -16
  237. package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-existence.d.ts +0 -2
  238. package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-existence.js +0 -12
  239. package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-permissions.d.ts +0 -2
  240. package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-permissions.js +0 -28
  241. package/dist/permissions/modules/process-payload/lib/is-field-nullable.d.ts +0 -5
  242. package/dist/permissions/modules/process-payload/lib/is-field-nullable.js +0 -12
  243. package/dist/permissions/modules/process-payload/process-payload.d.ts +0 -13
  244. package/dist/permissions/modules/process-payload/process-payload.js +0 -77
  245. package/dist/permissions/modules/validate-access/lib/validate-collection-access.d.ts +0 -12
  246. package/dist/permissions/modules/validate-access/lib/validate-collection-access.js +0 -11
  247. package/dist/permissions/modules/validate-access/lib/validate-item-access.d.ts +0 -9
  248. package/dist/permissions/modules/validate-access/lib/validate-item-access.js +0 -33
  249. package/dist/permissions/modules/validate-access/validate-access.d.ts +0 -14
  250. package/dist/permissions/modules/validate-access/validate-access.js +0 -28
  251. package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-count.d.ts +0 -1
  252. package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-count.js +0 -8
  253. package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-users.d.ts +0 -5
  254. package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-users.js +0 -10
  255. package/dist/permissions/types.d.ts +0 -6
  256. package/dist/permissions/types.js +0 -1
  257. package/dist/permissions/utils/create-default-accountability.d.ts +0 -2
  258. package/dist/permissions/utils/create-default-accountability.js +0 -11
  259. package/dist/permissions/utils/extract-required-dynamic-variable-context.d.ts +0 -8
  260. package/dist/permissions/utils/extract-required-dynamic-variable-context.js +0 -27
  261. package/dist/permissions/utils/fetch-dynamic-variable-context.d.ts +0 -9
  262. package/dist/permissions/utils/fetch-dynamic-variable-context.js +0 -43
  263. package/dist/permissions/utils/filter-policies-by-ip.d.ts +0 -2
  264. package/dist/permissions/utils/filter-policies-by-ip.js +0 -15
  265. package/dist/permissions/utils/get-unaliased-field-key.d.ts +0 -5
  266. package/dist/permissions/utils/get-unaliased-field-key.js +0 -17
  267. package/dist/permissions/utils/process-permissions.d.ts +0 -7
  268. package/dist/permissions/utils/process-permissions.js +0 -9
  269. package/dist/permissions/utils/with-cache.d.ts +0 -10
  270. package/dist/permissions/utils/with-cache.js +0 -25
  271. package/dist/services/access.d.ts +0 -10
  272. package/dist/services/access.js +0 -43
  273. package/dist/services/policies.d.ts +0 -12
  274. package/dist/services/policies.js +0 -87
  275. package/dist/telemetry/utils/check-user-limits.d.ts +0 -5
  276. package/dist/telemetry/utils/check-user-limits.js +0 -19
  277. package/dist/utils/fetch-user-count/fetch-access-lookup.d.ts +0 -17
  278. package/dist/utils/fetch-user-count/fetch-access-lookup.js +0 -22
  279. package/dist/utils/fetch-user-count/fetch-access-roles.d.ts +0 -16
  280. package/dist/utils/fetch-user-count/fetch-access-roles.js +0 -37
  281. package/dist/utils/fetch-user-count/fetch-active-users.d.ts +0 -6
  282. package/dist/utils/fetch-user-count/fetch-active-users.js +0 -3
  283. package/dist/utils/fetch-user-count/fetch-user-count.d.ts +0 -12
  284. package/dist/utils/fetch-user-count/fetch-user-count.js +0 -57
  285. package/dist/utils/fetch-user-count/get-user-count-query.d.ts +0 -20
  286. package/dist/utils/fetch-user-count/get-user-count-query.js +0 -17
  287. package/dist/utils/validate-user-count-integrity.d.ts +0 -13
  288. package/dist/utils/validate-user-count-integrity.js +0 -29
  289. /package/dist/database/migrations/{20240619A-permissions-policies.d.ts → 20240701A-add-tus-data.d.ts} +0 -0
  290. /package/dist/{utils → services/files/utils}/parse-image-metadata.d.ts +0 -0
  291. /package/dist/{utils → services/files/utils}/parse-image-metadata.js +0 -0
@@ -6,7 +6,7 @@ export declare class GeometryHelperMSSQL extends GeometryHelper {
6
6
  isTrue(expression: Knex.Raw): Knex.Raw<any>;
7
7
  isFalse(expression: Knex.Raw): Knex.Raw<any>;
8
8
  createColumn(table: Knex.CreateTableBuilder, field: RawField | Field): Knex.ColumnBuilder;
9
- asText(table: string, column: string, alias: string | false): Knex.Raw;
9
+ asText(table: string, column: string): Knex.Raw;
10
10
  fromText(text: string): Knex.Raw;
11
11
  _intersects(key: string, geojson: GeoJSONGeometry): Knex.Raw;
12
12
  _intersects_bbox(key: string, geojson: GeoJSONGeometry): Knex.Raw;
@@ -12,10 +12,8 @@ export class GeometryHelperMSSQL extends GeometryHelper {
12
12
  }
13
13
  return table.specificType(field.field, 'geometry');
14
14
  }
15
- asText(table, column, alias) {
16
- if (alias)
17
- return this.knex.raw('??.??.STAsText() as ??', [table, column, alias]);
18
- return this.knex.raw('??.??.STAsText()', [table, column]);
15
+ asText(table, column) {
16
+ return this.knex.raw('??.??.STAsText() as ??', [table, column, column]);
19
17
  }
20
18
  fromText(text) {
21
19
  return this.knex.raw('geometry::STGeomFromText(?, 4326)', text);
@@ -1,7 +1,7 @@
1
1
  import { GeometryHelper } from '../types.js';
2
2
  export class GeometryHelperMySQL extends GeometryHelper {
3
3
  collect(table, column) {
4
- return this.knex.raw(`concat('geometrycollection(', group_concat(? separator ', '), ')'`, this.asText(table, column, column));
4
+ return this.knex.raw(`concat('geometrycollection(', group_concat(? separator ', '), ')'`, this.asText(table, column));
5
5
  }
6
6
  fromText(text) {
7
7
  return this.knex.raw('st_geomfromtext(?)', text);
@@ -6,7 +6,7 @@ export declare class GeometryHelperOracle extends GeometryHelper {
6
6
  isTrue(expression: Knex.Raw): Knex.Raw<any>;
7
7
  isFalse(expression: Knex.Raw): Knex.Raw<any>;
8
8
  createColumn(table: Knex.CreateTableBuilder, field: RawField | Field): Knex.ColumnBuilder;
9
- asText(table: string, column: string, alias: string | false): Knex.Raw;
9
+ asText(table: string, column: string): Knex.Raw;
10
10
  asGeoJSON(table: string, column: string): Knex.Raw;
11
11
  fromText(text: string): Knex.Raw;
12
12
  _intersects(key: string, geojson: GeoJSONGeometry): Knex.Raw;
@@ -12,10 +12,8 @@ export class GeometryHelperOracle extends GeometryHelper {
12
12
  }
13
13
  return table.specificType(field.field, 'sdo_geometry');
14
14
  }
15
- asText(table, column, alias) {
16
- if (alias)
17
- return this.knex.raw('sdo_util.to_wktgeometry(??.??) as ??', [table, column, alias]);
18
- return this.knex.raw('sdo_util.to_wktgeometry(??.??)', [table, column]);
15
+ asText(table, column) {
16
+ return this.knex.raw('sdo_util.to_wktgeometry(??.??) as ??', [table, column, column]);
19
17
  }
20
18
  asGeoJSON(table, column) {
21
19
  return this.knex.raw('sdo_util.to_geojson(??.??) as ??', [table, column, column]);
@@ -32,6 +30,6 @@ export class GeometryHelperOracle extends GeometryHelper {
32
30
  return this.knex.raw(`sdo_overlapbdyintersect(sdo_geom.sdo_mbr(??), sdo_geom.sdo_mbr(?))`, [key, geometry]);
33
31
  }
34
32
  collect(table, column) {
35
- return this.knex.raw(`concat('geometrycollection(', listagg(?, ', '), ')'`, this.asText(table, column, column));
33
+ return this.knex.raw(`concat('geometrycollection(', listagg(?, ', '), ')'`, this.asText(table, column));
36
34
  }
37
35
  }
@@ -7,7 +7,7 @@ export declare abstract class GeometryHelper extends DatabaseHelper {
7
7
  isTrue(expression: Knex.Raw): Knex.Raw<any>;
8
8
  isFalse(expression: Knex.Raw): Knex.Raw<any>;
9
9
  createColumn(table: Knex.CreateTableBuilder, field: RawField | Field): Knex.ColumnBuilder;
10
- asText(table: string, column: string, alias: string | false): Knex.Raw;
10
+ asText(table: string, column: string): Knex.Raw;
11
11
  fromText(text: string): Knex.Raw;
12
12
  fromGeoJSON(geojson: GeoJSONGeometry): Knex.Raw;
13
13
  _intersects(key: string, geojson: GeoJSONGeometry): Knex.Raw;
@@ -14,10 +14,8 @@ export class GeometryHelper extends DatabaseHelper {
14
14
  const type = field.type.split('.')[1] ?? 'geometry';
15
15
  return table.specificType(field.field, type);
16
16
  }
17
- asText(table, column, alias) {
18
- if (alias)
19
- return this.knex.raw('st_astext(??.??) as ??', [table, column, alias]);
20
- return this.knex.raw('st_astext(??.??)', [table, column]);
17
+ asText(table, column) {
18
+ return this.knex.raw('st_astext(??.??) as ??', [table, column, column]);
21
19
  }
22
20
  fromText(text) {
23
21
  return this.knex.raw('st_geomfromtext(?, 4326)', text);
@@ -106,7 +106,6 @@ export function getDatabase() {
106
106
  };
107
107
  }
108
108
  if (client === 'mysql') {
109
- Object.assign(knexConfig, { client: 'mysql2' });
110
109
  poolConfig.afterCreate = async (conn, callback) => {
111
110
  logger.trace('Retrieving database version');
112
111
  const run = promisify(conn.query.bind(conn));
@@ -186,7 +185,7 @@ export async function validateDatabaseConnection(database) {
186
185
  export function getDatabaseClient(database) {
187
186
  database = database ?? getDatabase();
188
187
  switch (database.client.constructor.name) {
189
- case 'Client_MySQL2':
188
+ case 'Client_MySQL':
190
189
  return 'mysql';
191
190
  case 'Client_PG':
192
191
  return 'postgres';
@@ -0,0 +1,12 @@
1
+ export async function up(knex) {
2
+ await knex.schema.alterTable('directus_files', (table) => {
3
+ table.string('tus_id', 64).nullable();
4
+ table.json('tus_data').nullable();
5
+ });
6
+ }
7
+ export async function down(knex) {
8
+ await knex.schema.alterTable('directus_files', (table) => {
9
+ table.dropColumn('tus_id');
10
+ table.dropColumn('tus_data');
11
+ });
12
+ }
@@ -1,6 +1,7 @@
1
+ import type { Item, SchemaOverview } from '@directus/types';
1
2
  import type { Knex } from 'knex';
2
- import type { AST } from '../../types/ast.js';
3
- export interface RunASTOptions {
3
+ import type { AST, NestedCollectionNode } from '../types/ast.js';
4
+ type RunASTOptions = {
4
5
  /**
5
6
  * Query override for the current level
6
7
  */
@@ -17,4 +18,9 @@ export interface RunASTOptions {
17
18
  * Whether or not to strip out non-requested required fields automatically (eg IDs / FKs)
18
19
  */
19
20
  stripNonRequested?: boolean;
20
- }
21
+ };
22
+ /**
23
+ * Execute a given AST using Knex. Returns array of items based on requested AST.
24
+ */
25
+ export default function runAST(originalAST: AST | NestedCollectionNode, schema: SchemaOverview, options?: RunASTOptions): Promise<null | Item | Item[]>;
26
+ export {};
@@ -0,0 +1,450 @@
1
+ import { useEnv } from '@directus/env';
2
+ import { toArray } from '@directus/utils';
3
+ import { clone, cloneDeep, isNil, merge, pick, uniq } from 'lodash-es';
4
+ import { PayloadService } from '../services/payload.js';
5
+ import { applyFunctionToColumnName } from '../utils/apply-function-to-column-name.js';
6
+ import applyQuery, { applyLimit, applySort, generateAlias } from '../utils/apply-query.js';
7
+ import { getCollectionFromAlias } from '../utils/get-collection-from-alias.js';
8
+ import { getColumn } from '../utils/get-column.js';
9
+ import { parseFilterKey } from '../utils/parse-filter-key.js';
10
+ import { getHelpers } from './helpers/index.js';
11
+ import getDatabase from './index.js';
12
+ /**
13
+ * Execute a given AST using Knex. Returns array of items based on requested AST.
14
+ */
15
+ export default async function runAST(originalAST, schema, options) {
16
+ const ast = cloneDeep(originalAST);
17
+ const knex = options?.knex || getDatabase();
18
+ if (ast.type === 'a2o') {
19
+ const results = {};
20
+ for (const collection of ast.names) {
21
+ results[collection] = await run(collection, ast.children[collection], ast.query[collection]);
22
+ }
23
+ return results;
24
+ }
25
+ else {
26
+ return await run(ast.name, ast.children, options?.query || ast.query);
27
+ }
28
+ async function run(collection, children, query) {
29
+ const env = useEnv();
30
+ // Retrieve the database columns to select in the current AST
31
+ const { fieldNodes, primaryKeyField, nestedCollectionNodes } = await parseCurrentLevel(schema, collection, children, query);
32
+ // The actual knex query builder instance. This is a promise that resolves with the raw items from the db
33
+ const dbQuery = await getDBQuery(schema, knex, collection, fieldNodes, query);
34
+ const rawItems = await dbQuery;
35
+ if (!rawItems)
36
+ return null;
37
+ // Run the items through the special transforms
38
+ const payloadService = new PayloadService(collection, { knex, schema });
39
+ let items = await payloadService.processValues('read', rawItems, query.alias ?? {});
40
+ if (!items || (Array.isArray(items) && items.length === 0))
41
+ return items;
42
+ // Apply the `_in` filters to the nested collection batches
43
+ const nestedNodes = applyParentFilters(schema, nestedCollectionNodes, items);
44
+ for (const nestedNode of nestedNodes) {
45
+ let nestedItems = [];
46
+ if (nestedNode.type === 'o2m') {
47
+ let hasMore = true;
48
+ let batchCount = 0;
49
+ while (hasMore) {
50
+ const node = merge({}, nestedNode, {
51
+ query: {
52
+ limit: env['RELATIONAL_BATCH_SIZE'],
53
+ offset: batchCount * env['RELATIONAL_BATCH_SIZE'],
54
+ page: null,
55
+ },
56
+ });
57
+ nestedItems = (await runAST(node, schema, { knex, nested: true }));
58
+ if (nestedItems) {
59
+ items = mergeWithParentItems(schema, nestedItems, items, nestedNode);
60
+ }
61
+ if (!nestedItems || nestedItems.length < env['RELATIONAL_BATCH_SIZE']) {
62
+ hasMore = false;
63
+ }
64
+ batchCount++;
65
+ }
66
+ }
67
+ else {
68
+ const node = merge({}, nestedNode, {
69
+ query: { limit: -1 },
70
+ });
71
+ nestedItems = (await runAST(node, schema, { knex, nested: true }));
72
+ if (nestedItems) {
73
+ // Merge all fetched nested records with the parent items
74
+ items = mergeWithParentItems(schema, nestedItems, items, nestedNode);
75
+ }
76
+ }
77
+ }
78
+ // During the fetching of data, we have to inject a couple of required fields for the child nesting
79
+ // to work (primary / foreign keys) even if they're not explicitly requested. After all fetching
80
+ // and nesting is done, we parse through the output structure, and filter out all non-requested
81
+ // fields
82
+ if (options?.nested !== true && options?.stripNonRequested !== false) {
83
+ items = removeTemporaryFields(schema, items, originalAST, primaryKeyField);
84
+ }
85
+ return items;
86
+ }
87
+ }
88
+ async function parseCurrentLevel(schema, collection, children, query) {
89
+ const primaryKeyField = schema.collections[collection].primary;
90
+ const columnsInCollection = Object.keys(schema.collections[collection].fields);
91
+ const columnsToSelectInternal = [];
92
+ const nestedCollectionNodes = [];
93
+ for (const child of children) {
94
+ if (child.type === 'field' || child.type === 'functionField') {
95
+ const { fieldName } = parseFilterKey(child.name);
96
+ if (columnsInCollection.includes(fieldName)) {
97
+ columnsToSelectInternal.push(child.fieldKey);
98
+ }
99
+ continue;
100
+ }
101
+ if (!child.relation)
102
+ continue;
103
+ if (child.type === 'm2o') {
104
+ columnsToSelectInternal.push(child.relation.field);
105
+ }
106
+ if (child.type === 'a2o') {
107
+ columnsToSelectInternal.push(child.relation.field);
108
+ columnsToSelectInternal.push(child.relation.meta.one_collection_field);
109
+ }
110
+ nestedCollectionNodes.push(child);
111
+ }
112
+ const isAggregate = (query.group || (query.aggregate && Object.keys(query.aggregate).length > 0)) ?? false;
113
+ /** Always fetch primary key in case there's a nested relation that needs it. Aggregate payloads
114
+ * can't have nested relational fields
115
+ */
116
+ if (isAggregate === false && columnsToSelectInternal.includes(primaryKeyField) === false) {
117
+ columnsToSelectInternal.push(primaryKeyField);
118
+ }
119
+ /** Make sure select list has unique values */
120
+ const columnsToSelect = [...new Set(columnsToSelectInternal)];
121
+ const fieldNodes = columnsToSelect.map((column) => children.find((childNode) => (childNode.type === 'field' || childNode.type === 'functionField') && childNode.fieldKey === column) ?? {
122
+ type: 'field',
123
+ name: column,
124
+ fieldKey: column,
125
+ });
126
+ return { fieldNodes, nestedCollectionNodes, primaryKeyField };
127
+ }
128
+ function getColumnPreprocessor(knex, schema, table) {
129
+ const helpers = getHelpers(knex);
130
+ return function (fieldNode) {
131
+ let alias = undefined;
132
+ if (fieldNode.name !== fieldNode.fieldKey) {
133
+ alias = fieldNode.fieldKey;
134
+ }
135
+ let field;
136
+ if (fieldNode.type === 'field' || fieldNode.type === 'functionField') {
137
+ const { fieldName } = parseFilterKey(fieldNode.name);
138
+ field = schema.collections[table].fields[fieldName];
139
+ }
140
+ else {
141
+ field = schema.collections[fieldNode.relation.collection].fields[fieldNode.relation.field];
142
+ }
143
+ if (field?.type?.startsWith('geometry')) {
144
+ return helpers.st.asText(table, field.field);
145
+ }
146
+ if (fieldNode.type === 'functionField') {
147
+ return getColumn(knex, table, fieldNode.name, alias, schema, { query: fieldNode.query });
148
+ }
149
+ return getColumn(knex, table, fieldNode.name, alias, schema);
150
+ };
151
+ }
152
+ async function getDBQuery(schema, knex, table, fieldNodes, query) {
153
+ const env = useEnv();
154
+ const preProcess = getColumnPreprocessor(knex, schema, table);
155
+ const queryCopy = clone(query);
156
+ const helpers = getHelpers(knex);
157
+ queryCopy.limit = typeof queryCopy.limit === 'number' ? queryCopy.limit : Number(env['QUERY_LIMIT_DEFAULT']);
158
+ // Queries with aggregates and groupBy will not have duplicate result
159
+ if (queryCopy.aggregate || queryCopy.group) {
160
+ const flatQuery = knex.select(fieldNodes.map(preProcess)).from(table);
161
+ return await applyQuery(knex, table, flatQuery, queryCopy, schema).query;
162
+ }
163
+ const primaryKey = schema.collections[table].primary;
164
+ const aliasMap = Object.create(null);
165
+ let dbQuery = knex.from(table);
166
+ let sortRecords;
167
+ const innerQuerySortRecords = [];
168
+ let hasMultiRelationalSort;
169
+ if (queryCopy.sort) {
170
+ const sortResult = applySort(knex, schema, dbQuery, queryCopy, table, aliasMap, true);
171
+ if (sortResult) {
172
+ sortRecords = sortResult.sortRecords;
173
+ hasMultiRelationalSort = sortResult.hasMultiRelationalSort;
174
+ }
175
+ }
176
+ const { hasMultiRelationalFilter } = applyQuery(knex, table, dbQuery, queryCopy, schema, {
177
+ aliasMap,
178
+ isInnerQuery: true,
179
+ hasMultiRelationalSort,
180
+ });
181
+ const needsInnerQuery = hasMultiRelationalSort || hasMultiRelationalFilter;
182
+ if (needsInnerQuery) {
183
+ dbQuery.select(`${table}.${primaryKey}`).distinct();
184
+ }
185
+ else {
186
+ dbQuery.select(fieldNodes.map(preProcess));
187
+ }
188
+ if (sortRecords) {
189
+ // Clears the order if any, eg: from MSSQL offset
190
+ dbQuery.clear('order');
191
+ if (needsInnerQuery) {
192
+ let orderByString = '';
193
+ const orderByFields = [];
194
+ sortRecords.map((sortRecord) => {
195
+ if (orderByString.length !== 0) {
196
+ orderByString += ', ';
197
+ }
198
+ const sortAlias = `sort_${generateAlias()}`;
199
+ if (sortRecord.column.includes('.')) {
200
+ const [alias, field] = sortRecord.column.split('.');
201
+ const originalCollectionName = getCollectionFromAlias(alias, aliasMap);
202
+ dbQuery.select(getColumn(knex, alias, field, sortAlias, schema, { originalCollectionName }));
203
+ orderByString += `?? ${sortRecord.order}`;
204
+ orderByFields.push(getColumn(knex, alias, field, false, schema, { originalCollectionName }));
205
+ }
206
+ else {
207
+ dbQuery.select(getColumn(knex, table, sortRecord.column, sortAlias, schema));
208
+ orderByString += `?? ${sortRecord.order}`;
209
+ orderByFields.push(getColumn(knex, table, sortRecord.column, false, schema));
210
+ }
211
+ innerQuerySortRecords.push({ alias: sortAlias, order: sortRecord.order });
212
+ });
213
+ dbQuery.orderByRaw(orderByString, orderByFields);
214
+ if (hasMultiRelationalSort) {
215
+ dbQuery = helpers.schema.applyMultiRelationalSort(knex, dbQuery, table, primaryKey, orderByString, orderByFields);
216
+ }
217
+ }
218
+ else {
219
+ sortRecords.map((sortRecord) => {
220
+ if (sortRecord.column.includes('.')) {
221
+ const [alias, field] = sortRecord.column.split('.');
222
+ sortRecord.column = getColumn(knex, alias, field, false, schema, {
223
+ originalCollectionName: getCollectionFromAlias(alias, aliasMap),
224
+ });
225
+ }
226
+ else {
227
+ sortRecord.column = getColumn(knex, table, sortRecord.column, false, schema);
228
+ }
229
+ });
230
+ dbQuery.orderBy(sortRecords);
231
+ }
232
+ }
233
+ if (!needsInnerQuery)
234
+ return dbQuery;
235
+ const wrapperQuery = knex
236
+ .select(fieldNodes.map(preProcess))
237
+ .from(table)
238
+ .innerJoin(knex.raw('??', dbQuery.as('inner')), `${table}.${primaryKey}`, `inner.${primaryKey}`);
239
+ if (sortRecords && needsInnerQuery) {
240
+ innerQuerySortRecords.map((innerQuerySortRecord) => {
241
+ wrapperQuery.orderBy(`inner.${innerQuerySortRecord.alias}`, innerQuerySortRecord.order);
242
+ });
243
+ if (hasMultiRelationalSort) {
244
+ wrapperQuery.where('inner.directus_row_number', '=', 1);
245
+ applyLimit(knex, wrapperQuery, queryCopy.limit);
246
+ }
247
+ }
248
+ return wrapperQuery;
249
+ }
250
+ function applyParentFilters(schema, nestedCollectionNodes, parentItem) {
251
+ const parentItems = toArray(parentItem);
252
+ for (const nestedNode of nestedCollectionNodes) {
253
+ if (!nestedNode.relation)
254
+ continue;
255
+ if (nestedNode.type === 'm2o') {
256
+ const foreignField = schema.collections[nestedNode.relation.related_collection].primary;
257
+ const foreignIds = uniq(parentItems.map((res) => res[nestedNode.relation.field])).filter((id) => !isNil(id));
258
+ merge(nestedNode, { query: { filter: { [foreignField]: { _in: foreignIds } } } });
259
+ }
260
+ else if (nestedNode.type === 'o2m') {
261
+ const relatedM2OisFetched = !!nestedNode.children.find((child) => {
262
+ return child.type === 'field' && child.name === nestedNode.relation.field;
263
+ });
264
+ if (relatedM2OisFetched === false) {
265
+ nestedNode.children.push({
266
+ type: 'field',
267
+ name: nestedNode.relation.field,
268
+ fieldKey: nestedNode.relation.field,
269
+ });
270
+ }
271
+ if (nestedNode.relation.meta?.sort_field) {
272
+ nestedNode.children.push({
273
+ type: 'field',
274
+ name: nestedNode.relation.meta.sort_field,
275
+ fieldKey: nestedNode.relation.meta.sort_field,
276
+ });
277
+ }
278
+ const foreignField = nestedNode.relation.field;
279
+ const foreignIds = uniq(parentItems.map((res) => res[nestedNode.parentKey])).filter((id) => !isNil(id));
280
+ merge(nestedNode, { query: { filter: { [foreignField]: { _in: foreignIds } } } });
281
+ }
282
+ else if (nestedNode.type === 'a2o') {
283
+ const keysPerCollection = {};
284
+ for (const parentItem of parentItems) {
285
+ const collection = parentItem[nestedNode.relation.meta.one_collection_field];
286
+ if (!keysPerCollection[collection])
287
+ keysPerCollection[collection] = [];
288
+ keysPerCollection[collection].push(parentItem[nestedNode.relation.field]);
289
+ }
290
+ for (const relatedCollection of nestedNode.names) {
291
+ const foreignField = nestedNode.relatedKey[relatedCollection];
292
+ const foreignIds = uniq(keysPerCollection[relatedCollection]);
293
+ merge(nestedNode, {
294
+ query: { [relatedCollection]: { filter: { [foreignField]: { _in: foreignIds } }, limit: foreignIds.length } },
295
+ });
296
+ }
297
+ }
298
+ }
299
+ return nestedCollectionNodes;
300
+ }
301
+ function mergeWithParentItems(schema, nestedItem, parentItem, nestedNode) {
302
+ const env = useEnv();
303
+ const nestedItems = toArray(nestedItem);
304
+ const parentItems = clone(toArray(parentItem));
305
+ if (nestedNode.type === 'm2o') {
306
+ for (const parentItem of parentItems) {
307
+ const itemChild = nestedItems.find((nestedItem) => {
308
+ return (nestedItem[schema.collections[nestedNode.relation.related_collection].primary] ==
309
+ parentItem[nestedNode.relation.field]);
310
+ });
311
+ parentItem[nestedNode.fieldKey] = itemChild || null;
312
+ }
313
+ }
314
+ else if (nestedNode.type === 'o2m') {
315
+ for (const parentItem of parentItems) {
316
+ if (!parentItem[nestedNode.fieldKey])
317
+ parentItem[nestedNode.fieldKey] = [];
318
+ const itemChildren = nestedItems.filter((nestedItem) => {
319
+ if (nestedItem === null)
320
+ return false;
321
+ if (Array.isArray(nestedItem[nestedNode.relation.field]))
322
+ return true;
323
+ return (nestedItem[nestedNode.relation.field] ==
324
+ parentItem[schema.collections[nestedNode.relation.related_collection].primary] ||
325
+ nestedItem[nestedNode.relation.field]?.[schema.collections[nestedNode.relation.related_collection].primary] == parentItem[schema.collections[nestedNode.relation.related_collection].primary]);
326
+ });
327
+ parentItem[nestedNode.fieldKey].push(...itemChildren);
328
+ const limit = nestedNode.query.limit ?? Number(env['QUERY_LIMIT_DEFAULT']);
329
+ if (nestedNode.query.page && nestedNode.query.page > 1) {
330
+ parentItem[nestedNode.fieldKey] = parentItem[nestedNode.fieldKey].slice(limit * (nestedNode.query.page - 1));
331
+ }
332
+ if (nestedNode.query.offset && nestedNode.query.offset >= 0) {
333
+ parentItem[nestedNode.fieldKey] = parentItem[nestedNode.fieldKey].slice(nestedNode.query.offset);
334
+ }
335
+ if (limit !== -1) {
336
+ parentItem[nestedNode.fieldKey] = parentItem[nestedNode.fieldKey].slice(0, limit);
337
+ }
338
+ parentItem[nestedNode.fieldKey] = parentItem[nestedNode.fieldKey].sort((a, b) => {
339
+ // This is pre-filled in get-ast-from-query
340
+ const sortField = nestedNode.query.sort[0];
341
+ let column = sortField;
342
+ let order = 'asc';
343
+ if (sortField.startsWith('-')) {
344
+ column = sortField.substring(1);
345
+ order = 'desc';
346
+ }
347
+ if (a[column] === b[column])
348
+ return 0;
349
+ if (a[column] === null)
350
+ return 1;
351
+ if (b[column] === null)
352
+ return -1;
353
+ if (order === 'asc') {
354
+ return a[column] < b[column] ? -1 : 1;
355
+ }
356
+ else {
357
+ return a[column] < b[column] ? 1 : -1;
358
+ }
359
+ });
360
+ }
361
+ }
362
+ else if (nestedNode.type === 'a2o') {
363
+ for (const parentItem of parentItems) {
364
+ if (!nestedNode.relation.meta?.one_collection_field) {
365
+ parentItem[nestedNode.fieldKey] = null;
366
+ continue;
367
+ }
368
+ const relatedCollection = parentItem[nestedNode.relation.meta.one_collection_field];
369
+ if (!nestedItem[relatedCollection]) {
370
+ parentItem[nestedNode.fieldKey] = null;
371
+ continue;
372
+ }
373
+ const itemChild = nestedItem[relatedCollection].find((nestedItem) => {
374
+ return nestedItem[nestedNode.relatedKey[relatedCollection]] == parentItem[nestedNode.fieldKey];
375
+ });
376
+ parentItem[nestedNode.fieldKey] = itemChild || null;
377
+ }
378
+ }
379
+ return Array.isArray(parentItem) ? parentItems : parentItems[0];
380
+ }
381
+ function removeTemporaryFields(schema, rawItem, ast, primaryKeyField, parentItem) {
382
+ const rawItems = cloneDeep(toArray(rawItem));
383
+ const items = [];
384
+ if (ast.type === 'a2o') {
385
+ const fields = {};
386
+ const nestedCollectionNodes = {};
387
+ for (const relatedCollection of ast.names) {
388
+ if (!fields[relatedCollection])
389
+ fields[relatedCollection] = [];
390
+ if (!nestedCollectionNodes[relatedCollection])
391
+ nestedCollectionNodes[relatedCollection] = [];
392
+ for (const child of ast.children[relatedCollection]) {
393
+ if (child.type === 'field' || child.type === 'functionField') {
394
+ fields[relatedCollection].push(child.name);
395
+ }
396
+ else {
397
+ fields[relatedCollection].push(child.fieldKey);
398
+ nestedCollectionNodes[relatedCollection].push(child);
399
+ }
400
+ }
401
+ }
402
+ for (const rawItem of rawItems) {
403
+ const relatedCollection = parentItem?.[ast.relation.meta.one_collection_field];
404
+ if (rawItem === null || rawItem === undefined)
405
+ return rawItem;
406
+ let item = rawItem;
407
+ for (const nestedNode of nestedCollectionNodes[relatedCollection]) {
408
+ item[nestedNode.fieldKey] = removeTemporaryFields(schema, item[nestedNode.fieldKey], nestedNode, schema.collections[nestedNode.relation.collection].primary, item);
409
+ }
410
+ const fieldsWithFunctionsApplied = fields[relatedCollection].map((field) => applyFunctionToColumnName(field));
411
+ item =
412
+ fields[relatedCollection].length > 0 ? pick(rawItem, fieldsWithFunctionsApplied) : rawItem[primaryKeyField];
413
+ items.push(item);
414
+ }
415
+ }
416
+ else {
417
+ const fields = [];
418
+ const nestedCollectionNodes = [];
419
+ for (const child of ast.children) {
420
+ fields.push(child.fieldKey);
421
+ if (child.type !== 'field' && child.type !== 'functionField') {
422
+ nestedCollectionNodes.push(child);
423
+ }
424
+ }
425
+ // Make sure any requested aggregate fields are included
426
+ if (ast.query?.aggregate) {
427
+ for (const [operation, aggregateFields] of Object.entries(ast.query.aggregate)) {
428
+ if (!fields)
429
+ continue;
430
+ if (operation === 'count' && aggregateFields.includes('*'))
431
+ fields.push('count');
432
+ fields.push(...aggregateFields.map((field) => `${operation}.${field}`));
433
+ }
434
+ }
435
+ for (const rawItem of rawItems) {
436
+ if (rawItem === null || rawItem === undefined)
437
+ return rawItem;
438
+ let item = rawItem;
439
+ for (const nestedNode of nestedCollectionNodes) {
440
+ item[nestedNode.fieldKey] = removeTemporaryFields(schema, item[nestedNode.fieldKey], nestedNode, nestedNode.type === 'm2o'
441
+ ? schema.collections[nestedNode.relation.related_collection].primary
442
+ : schema.collections[nestedNode.relation.collection].primary, item);
443
+ }
444
+ const fieldsWithFunctionsApplied = fields.map((field) => applyFunctionToColumnName(field));
445
+ item = fields.length > 0 ? pick(rawItem, fieldsWithFunctionsApplied) : rawItem[primaryKeyField];
446
+ items.push(item);
447
+ }
448
+ }
449
+ return Array.isArray(rawItem) ? items : items[0];
450
+ }
package/dist/flows.js CHANGED
@@ -1,9 +1,8 @@
1
1
  import { Action } from '@directus/constants';
2
2
  import { useEnv } from '@directus/env';
3
3
  import { ForbiddenError } from '@directus/errors';
4
- import { isSystemCollection } from '@directus/system-data';
5
4
  import { applyOptionsData, getRedactedString, isValidJSON, parseJSON, toArray } from '@directus/utils';
6
- import { pick } from 'lodash-es';
5
+ import { omit, pick } from 'lodash-es';
7
6
  import { get } from 'micromustache';
8
7
  import { useBus } from './bus/index.js';
9
8
  import getDatabase from './database/index.js';
@@ -19,6 +18,7 @@ import { JobQueue } from './utils/job-queue.js';
19
18
  import { mapValuesDeep } from './utils/map-values-deep.js';
20
19
  import { redactObject } from './utils/redact-object.js';
21
20
  import { scheduleSynchronizedJob, validateCron } from './utils/schedule.js';
21
+ import { isSystemCollection } from '@directus/system-data';
22
22
  let flowManager;
23
23
  export function getFlowManager() {
24
24
  if (flowManager) {
@@ -284,7 +284,8 @@ class FlowManager {
284
284
  item: flow.id,
285
285
  data: {
286
286
  steps: steps.map((step) => redactObject(step, { values: this.envs }, getRedactedString)),
287
- data: redactObject(keyedData, {
287
+ data: redactObject(omit(keyedData, '$accountability.permissions'), // Permissions is a ton of data, and is just a copy of what's in the directus_permissions table
288
+ {
288
289
  keys: [
289
290
  ['**', 'headers', 'authorization'],
290
291
  ['**', 'headers', 'cookie'],
@@ -1,7 +1,6 @@
1
1
  import { isEqual } from 'lodash-es';
2
2
  import getDatabase from '../database/index.js';
3
3
  import emitter from '../emitter.js';
4
- import { createDefaultAccountability } from '../permissions/utils/create-default-accountability.js';
5
4
  import asyncHandler from '../utils/async-handler.js';
6
5
  import { getAccountabilityForToken } from '../utils/get-accountability-for-token.js';
7
6
  import { getIPFromReq } from '../utils/get-ip-from-req.js';
@@ -13,7 +12,13 @@ import { SESSION_COOKIE_OPTIONS } from '../constants.js';
13
12
  */
14
13
  export const handler = async (req, res, next) => {
15
14
  const env = useEnv();
16
- const defaultAccountability = createDefaultAccountability({ ip: getIPFromReq(req) });
15
+ const defaultAccountability = {
16
+ user: null,
17
+ role: null,
18
+ admin: false,
19
+ app: false,
20
+ ip: getIPFromReq(req),
21
+ };
17
22
  const userAgent = req.get('user-agent')?.substring(0, 1024);
18
23
  if (userAgent)
19
24
  defaultAccountability.userAgent = userAgent;
@@ -20,7 +20,7 @@ const checkCacheMiddleware = asyncHandler(async (req, res, next) => {
20
20
  res.setHeader(`${env['CACHE_STATUS_HEADER']}`, 'MISS');
21
21
  return next();
22
22
  }
23
- const key = await getCacheKey(req);
23
+ const key = getCacheKey(req);
24
24
  let cachedData;
25
25
  try {
26
26
  cachedData = await getCacheValue(cache, key);
@@ -0,0 +1,2 @@
1
+ import type { RequestHandler } from 'express';
2
+ export declare const checkIP: RequestHandler;