@directus/api 20.0.0-rc.1 → 20.1.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 (294) 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 +3 -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 +458 -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 +27 -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.d.ts +3 -3
  62. package/dist/services/items.js +44 -115
  63. package/dist/services/meta.js +23 -60
  64. package/dist/services/payload.d.ts +10 -9
  65. package/dist/services/payload.js +3 -18
  66. package/dist/services/{permissions.d.ts → permissions/index.d.ts} +7 -5
  67. package/dist/services/{permissions.js → permissions/index.js} +54 -30
  68. package/dist/{permissions → services/permissions}/lib/with-app-minimal-permissions.d.ts +1 -1
  69. package/dist/services/permissions/lib/with-app-minimal-permissions.js +13 -0
  70. package/dist/services/relations.d.ts +6 -0
  71. package/dist/services/relations.js +29 -26
  72. package/dist/services/roles.d.ts +12 -4
  73. package/dist/services/roles.js +424 -57
  74. package/dist/services/server.js +6 -0
  75. package/dist/services/shares.d.ts +2 -0
  76. package/dist/services/shares.js +8 -12
  77. package/dist/services/specifications.d.ts +2 -2
  78. package/dist/services/specifications.js +27 -39
  79. package/dist/services/tus/data-store.d.ts +36 -0
  80. package/dist/services/tus/data-store.js +216 -0
  81. package/dist/services/tus/index.d.ts +2 -0
  82. package/dist/services/tus/index.js +2 -0
  83. package/dist/services/tus/lockers.d.ts +36 -0
  84. package/dist/services/tus/lockers.js +83 -0
  85. package/dist/services/tus/server.d.ts +8 -0
  86. package/dist/services/tus/server.js +80 -0
  87. package/dist/services/tus/utils/wait-timeout.d.ts +1 -0
  88. package/dist/services/tus/utils/wait-timeout.js +13 -0
  89. package/dist/services/users.d.ts +5 -1
  90. package/dist/services/users.js +161 -78
  91. package/dist/services/utils.js +7 -11
  92. package/dist/services/versions.d.ts +2 -0
  93. package/dist/services/versions.js +10 -34
  94. package/dist/storage/register-locations.js +5 -1
  95. package/dist/telemetry/lib/get-report.js +2 -2
  96. package/dist/telemetry/utils/check-increased-user-limits.d.ts +7 -0
  97. package/dist/telemetry/utils/check-increased-user-limits.js +25 -0
  98. package/dist/telemetry/utils/get-role-counts-by-roles.d.ts +6 -0
  99. package/dist/telemetry/utils/get-role-counts-by-roles.js +27 -0
  100. package/dist/telemetry/utils/get-role-counts-by-users.d.ts +11 -0
  101. package/dist/telemetry/utils/get-role-counts-by-users.js +34 -0
  102. package/dist/telemetry/utils/get-user-count.d.ts +8 -0
  103. package/dist/telemetry/utils/get-user-count.js +33 -0
  104. package/dist/telemetry/utils/get-user-counts-by-roles.d.ts +7 -0
  105. package/dist/telemetry/utils/get-user-counts-by-roles.js +35 -0
  106. package/dist/types/ast.d.ts +1 -43
  107. package/dist/types/items.d.ts +0 -11
  108. package/dist/utils/apply-query.d.ts +3 -4
  109. package/dist/utils/apply-query.js +8 -37
  110. package/dist/utils/get-accountability-for-role.js +25 -16
  111. package/dist/utils/get-accountability-for-token.js +16 -17
  112. package/dist/utils/get-ast-from-query.d.ts +13 -0
  113. package/dist/utils/get-ast-from-query.js +297 -0
  114. package/dist/utils/get-cache-key.d.ts +1 -1
  115. package/dist/utils/get-cache-key.js +1 -12
  116. package/dist/utils/get-column.d.ts +1 -2
  117. package/dist/utils/get-column.js +0 -1
  118. package/dist/utils/get-permissions.d.ts +2 -0
  119. package/dist/utils/get-permissions.js +150 -0
  120. package/dist/utils/get-service.js +1 -5
  121. package/dist/utils/merge-permissions-for-share.d.ts +4 -0
  122. package/dist/utils/merge-permissions-for-share.js +109 -0
  123. package/dist/utils/merge-permissions.d.ts +3 -0
  124. package/dist/utils/merge-permissions.js +95 -0
  125. package/dist/utils/reduce-schema.d.ts +6 -4
  126. package/dist/utils/reduce-schema.js +34 -14
  127. package/dist/utils/verify-session-jwt.js +2 -1
  128. package/dist/websocket/authenticate.d.ts +2 -0
  129. package/dist/websocket/authenticate.js +12 -0
  130. package/dist/websocket/controllers/base.d.ts +1 -1
  131. package/dist/websocket/controllers/base.js +20 -16
  132. package/dist/websocket/controllers/graphql.js +4 -1
  133. package/dist/websocket/controllers/hooks.js +0 -4
  134. package/dist/websocket/controllers/rest.js +2 -0
  135. package/dist/websocket/handlers/subscribe.js +2 -0
  136. package/dist/websocket/utils/items.d.ts +1 -1
  137. package/package.json +39 -37
  138. package/dist/controllers/access.js +0 -148
  139. package/dist/controllers/policies.d.ts +0 -2
  140. package/dist/controllers/policies.js +0 -169
  141. package/dist/database/get-ast-from-query/get-ast-from-query.d.ts +0 -16
  142. package/dist/database/get-ast-from-query/get-ast-from-query.js +0 -82
  143. package/dist/database/get-ast-from-query/lib/convert-wildcards.d.ts +0 -13
  144. package/dist/database/get-ast-from-query/lib/convert-wildcards.js +0 -69
  145. package/dist/database/get-ast-from-query/lib/parse-fields.d.ts +0 -15
  146. package/dist/database/get-ast-from-query/lib/parse-fields.js +0 -190
  147. package/dist/database/get-ast-from-query/utils/get-deep-query.d.ts +0 -14
  148. package/dist/database/get-ast-from-query/utils/get-deep-query.js +0 -17
  149. package/dist/database/get-ast-from-query/utils/get-related-collection.d.ts +0 -2
  150. package/dist/database/get-ast-from-query/utils/get-related-collection.js +0 -13
  151. package/dist/database/get-ast-from-query/utils/get-relation.d.ts +0 -2
  152. package/dist/database/get-ast-from-query/utils/get-relation.js +0 -7
  153. package/dist/database/migrations/20240619A-permissions-policies.js +0 -164
  154. package/dist/database/run-ast/lib/get-db-query.d.ts +0 -4
  155. package/dist/database/run-ast/lib/get-db-query.js +0 -194
  156. package/dist/database/run-ast/lib/parse-current-level.d.ts +0 -7
  157. package/dist/database/run-ast/lib/parse-current-level.js +0 -41
  158. package/dist/database/run-ast/run-ast.d.ts +0 -7
  159. package/dist/database/run-ast/run-ast.js +0 -107
  160. package/dist/database/run-ast/types.js +0 -1
  161. package/dist/database/run-ast/utils/apply-case-when.d.ts +0 -16
  162. package/dist/database/run-ast/utils/apply-case-when.js +0 -26
  163. package/dist/database/run-ast/utils/apply-parent-filters.d.ts +0 -3
  164. package/dist/database/run-ast/utils/apply-parent-filters.js +0 -55
  165. package/dist/database/run-ast/utils/get-column-pre-processor.d.ts +0 -10
  166. package/dist/database/run-ast/utils/get-column-pre-processor.js +0 -57
  167. package/dist/database/run-ast/utils/get-field-alias.d.ts +0 -2
  168. package/dist/database/run-ast/utils/get-field-alias.js +0 -4
  169. package/dist/database/run-ast/utils/get-inner-query-column-pre-processor.d.ts +0 -5
  170. package/dist/database/run-ast/utils/get-inner-query-column-pre-processor.js +0 -23
  171. package/dist/database/run-ast/utils/merge-with-parent-items.d.ts +0 -3
  172. package/dist/database/run-ast/utils/merge-with-parent-items.js +0 -87
  173. package/dist/database/run-ast/utils/remove-temporary-fields.d.ts +0 -3
  174. package/dist/database/run-ast/utils/remove-temporary-fields.js +0 -73
  175. package/dist/permissions/cache.d.ts +0 -2
  176. package/dist/permissions/cache.js +0 -23
  177. package/dist/permissions/lib/fetch-permissions.d.ts +0 -10
  178. package/dist/permissions/lib/fetch-permissions.js +0 -55
  179. package/dist/permissions/lib/fetch-policies.d.ts +0 -7
  180. package/dist/permissions/lib/fetch-policies.js +0 -28
  181. package/dist/permissions/lib/fetch-roles-tree.d.ts +0 -3
  182. package/dist/permissions/lib/fetch-roles-tree.js +0 -28
  183. package/dist/permissions/lib/with-app-minimal-permissions.js +0 -10
  184. package/dist/permissions/modules/fetch-accountability-collection-access/fetch-accountability-collection-access.d.ts +0 -7
  185. package/dist/permissions/modules/fetch-accountability-collection-access/fetch-accountability-collection-access.js +0 -56
  186. package/dist/permissions/modules/fetch-accountability-policy-globals/fetch-accountability-policy-globals.d.ts +0 -3
  187. package/dist/permissions/modules/fetch-accountability-policy-globals/fetch-accountability-policy-globals.js +0 -16
  188. package/dist/permissions/modules/fetch-allowed-collections/fetch-allowed-collections.d.ts +0 -8
  189. package/dist/permissions/modules/fetch-allowed-collections/fetch-allowed-collections.js +0 -24
  190. package/dist/permissions/modules/fetch-allowed-field-map/fetch-allowed-field-map.d.ts +0 -9
  191. package/dist/permissions/modules/fetch-allowed-field-map/fetch-allowed-field-map.js +0 -31
  192. package/dist/permissions/modules/fetch-allowed-fields/fetch-allowed-fields.d.ts +0 -16
  193. package/dist/permissions/modules/fetch-allowed-fields/fetch-allowed-fields.js +0 -27
  194. package/dist/permissions/modules/fetch-global-access/fetch-global-access.d.ts +0 -10
  195. package/dist/permissions/modules/fetch-global-access/fetch-global-access.js +0 -23
  196. package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-roles.d.ts +0 -5
  197. package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-roles.js +0 -7
  198. package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-user.d.ts +0 -5
  199. package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-user.js +0 -10
  200. package/dist/permissions/modules/fetch-global-access/types.d.ts +0 -4
  201. package/dist/permissions/modules/fetch-global-access/types.js +0 -1
  202. package/dist/permissions/modules/fetch-global-access/utils/fetch-global-access-for-query.d.ts +0 -4
  203. package/dist/permissions/modules/fetch-global-access/utils/fetch-global-access-for-query.js +0 -27
  204. package/dist/permissions/modules/fetch-inconsistent-field-map/fetch-inconsistent-field-map.d.ts +0 -12
  205. package/dist/permissions/modules/fetch-inconsistent-field-map/fetch-inconsistent-field-map.js +0 -32
  206. package/dist/permissions/modules/fetch-policies-ip-access/fetch-policies-ip-access.d.ts +0 -4
  207. package/dist/permissions/modules/fetch-policies-ip-access/fetch-policies-ip-access.js +0 -29
  208. package/dist/permissions/modules/process-ast/lib/extract-fields-from-children.d.ts +0 -4
  209. package/dist/permissions/modules/process-ast/lib/extract-fields-from-children.js +0 -49
  210. package/dist/permissions/modules/process-ast/lib/extract-fields-from-query.d.ts +0 -3
  211. package/dist/permissions/modules/process-ast/lib/extract-fields-from-query.js +0 -56
  212. package/dist/permissions/modules/process-ast/lib/field-map-from-ast.d.ts +0 -4
  213. package/dist/permissions/modules/process-ast/lib/field-map-from-ast.js +0 -8
  214. package/dist/permissions/modules/process-ast/lib/inject-cases.d.ts +0 -9
  215. package/dist/permissions/modules/process-ast/lib/inject-cases.js +0 -93
  216. package/dist/permissions/modules/process-ast/process-ast.d.ts +0 -9
  217. package/dist/permissions/modules/process-ast/process-ast.js +0 -39
  218. package/dist/permissions/modules/process-ast/types.d.ts +0 -24
  219. package/dist/permissions/modules/process-ast/types.js +0 -1
  220. package/dist/permissions/modules/process-ast/utils/collections-in-field-map.d.ts +0 -2
  221. package/dist/permissions/modules/process-ast/utils/collections-in-field-map.js +0 -7
  222. package/dist/permissions/modules/process-ast/utils/dedupe-access.d.ts +0 -12
  223. package/dist/permissions/modules/process-ast/utils/dedupe-access.js +0 -30
  224. package/dist/permissions/modules/process-ast/utils/extract-paths-from-query.d.ts +0 -15
  225. package/dist/permissions/modules/process-ast/utils/extract-paths-from-query.js +0 -50
  226. package/dist/permissions/modules/process-ast/utils/find-related-collection.d.ts +0 -3
  227. package/dist/permissions/modules/process-ast/utils/find-related-collection.js +0 -9
  228. package/dist/permissions/modules/process-ast/utils/flatten-filter.d.ts +0 -3
  229. package/dist/permissions/modules/process-ast/utils/flatten-filter.js +0 -24
  230. package/dist/permissions/modules/process-ast/utils/format-a2o-key.d.ts +0 -1
  231. package/dist/permissions/modules/process-ast/utils/format-a2o-key.js +0 -3
  232. package/dist/permissions/modules/process-ast/utils/get-info-for-path.d.ts +0 -5
  233. package/dist/permissions/modules/process-ast/utils/get-info-for-path.js +0 -7
  234. package/dist/permissions/modules/process-ast/utils/has-item-permissions.d.ts +0 -2
  235. package/dist/permissions/modules/process-ast/utils/has-item-permissions.js +0 -3
  236. package/dist/permissions/modules/process-ast/utils/stringify-query-path.d.ts +0 -2
  237. package/dist/permissions/modules/process-ast/utils/stringify-query-path.js +0 -3
  238. package/dist/permissions/modules/process-ast/utils/validate-path/create-error.d.ts +0 -3
  239. package/dist/permissions/modules/process-ast/utils/validate-path/create-error.js +0 -16
  240. package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-existence.d.ts +0 -2
  241. package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-existence.js +0 -12
  242. package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-permissions.d.ts +0 -2
  243. package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-permissions.js +0 -28
  244. package/dist/permissions/modules/process-payload/lib/is-field-nullable.d.ts +0 -5
  245. package/dist/permissions/modules/process-payload/lib/is-field-nullable.js +0 -12
  246. package/dist/permissions/modules/process-payload/process-payload.d.ts +0 -13
  247. package/dist/permissions/modules/process-payload/process-payload.js +0 -77
  248. package/dist/permissions/modules/validate-access/lib/validate-collection-access.d.ts +0 -12
  249. package/dist/permissions/modules/validate-access/lib/validate-collection-access.js +0 -11
  250. package/dist/permissions/modules/validate-access/lib/validate-item-access.d.ts +0 -9
  251. package/dist/permissions/modules/validate-access/lib/validate-item-access.js +0 -33
  252. package/dist/permissions/modules/validate-access/validate-access.d.ts +0 -14
  253. package/dist/permissions/modules/validate-access/validate-access.js +0 -28
  254. package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-count.d.ts +0 -1
  255. package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-count.js +0 -8
  256. package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-users.d.ts +0 -5
  257. package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-users.js +0 -10
  258. package/dist/permissions/types.d.ts +0 -6
  259. package/dist/permissions/types.js +0 -1
  260. package/dist/permissions/utils/create-default-accountability.d.ts +0 -2
  261. package/dist/permissions/utils/create-default-accountability.js +0 -11
  262. package/dist/permissions/utils/extract-required-dynamic-variable-context.d.ts +0 -8
  263. package/dist/permissions/utils/extract-required-dynamic-variable-context.js +0 -27
  264. package/dist/permissions/utils/fetch-dynamic-variable-context.d.ts +0 -9
  265. package/dist/permissions/utils/fetch-dynamic-variable-context.js +0 -43
  266. package/dist/permissions/utils/filter-policies-by-ip.d.ts +0 -2
  267. package/dist/permissions/utils/filter-policies-by-ip.js +0 -15
  268. package/dist/permissions/utils/get-unaliased-field-key.d.ts +0 -5
  269. package/dist/permissions/utils/get-unaliased-field-key.js +0 -17
  270. package/dist/permissions/utils/process-permissions.d.ts +0 -7
  271. package/dist/permissions/utils/process-permissions.js +0 -9
  272. package/dist/permissions/utils/with-cache.d.ts +0 -10
  273. package/dist/permissions/utils/with-cache.js +0 -25
  274. package/dist/services/access.d.ts +0 -10
  275. package/dist/services/access.js +0 -43
  276. package/dist/services/policies.d.ts +0 -12
  277. package/dist/services/policies.js +0 -87
  278. package/dist/telemetry/utils/check-user-limits.d.ts +0 -5
  279. package/dist/telemetry/utils/check-user-limits.js +0 -19
  280. package/dist/utils/fetch-user-count/fetch-access-lookup.d.ts +0 -17
  281. package/dist/utils/fetch-user-count/fetch-access-lookup.js +0 -22
  282. package/dist/utils/fetch-user-count/fetch-access-roles.d.ts +0 -16
  283. package/dist/utils/fetch-user-count/fetch-access-roles.js +0 -37
  284. package/dist/utils/fetch-user-count/fetch-active-users.d.ts +0 -6
  285. package/dist/utils/fetch-user-count/fetch-active-users.js +0 -3
  286. package/dist/utils/fetch-user-count/fetch-user-count.d.ts +0 -12
  287. package/dist/utils/fetch-user-count/fetch-user-count.js +0 -57
  288. package/dist/utils/fetch-user-count/get-user-count-query.d.ts +0 -20
  289. package/dist/utils/fetch-user-count/get-user-count-query.js +0 -17
  290. package/dist/utils/validate-user-count-integrity.d.ts +0 -13
  291. package/dist/utils/validate-user-count-integrity.js +0 -29
  292. /package/dist/database/migrations/{20240619A-permissions-policies.d.ts → 20240701A-add-tus-data.d.ts} +0 -0
  293. /package/dist/{utils → services/files/utils}/parse-image-metadata.d.ts +0 -0
  294. /package/dist/{utils → services/files/utils}/parse-image-metadata.js +0 -0
@@ -1,190 +0,0 @@
1
- import { REGEX_BETWEEN_PARENS } from '@directus/constants';
2
- import { isEmpty } from 'lodash-es';
3
- import { fetchPermissions } from '../../../permissions/lib/fetch-permissions.js';
4
- import { fetchPolicies } from '../../../permissions/lib/fetch-policies.js';
5
- import { getRelationType } from '../../../utils/get-relation-type.js';
6
- import { getDeepQuery } from '../utils/get-deep-query.js';
7
- import { getRelatedCollection } from '../utils/get-related-collection.js';
8
- import { getRelation } from '../utils/get-relation.js';
9
- import { convertWildcards } from './convert-wildcards.js';
10
- export async function parseFields(options, context) {
11
- let { fields } = options;
12
- if (!fields)
13
- return [];
14
- fields = await convertWildcards({
15
- fields,
16
- parentCollection: options.parentCollection,
17
- query: options.query,
18
- accountability: options.accountability,
19
- }, context);
20
- if (!fields || !Array.isArray(fields))
21
- return [];
22
- const children = [];
23
- const policies = options.accountability && options.accountability.admin === false
24
- ? await fetchPolicies(options.accountability, context)
25
- : null;
26
- const relationalStructure = Object.create(null);
27
- for (const fieldKey of fields) {
28
- let name = fieldKey;
29
- if (options.query.alias) {
30
- // check for field alias (is one of the key)
31
- if (name in options.query.alias) {
32
- name = options.query.alias[fieldKey];
33
- }
34
- }
35
- const isRelational = name.includes('.') ||
36
- // We'll always treat top level o2m fields as a related item. This is an alias field, otherwise it won't return
37
- // anything
38
- !!context.schema.relations.find((relation) => relation.related_collection === options.parentCollection && relation.meta?.one_field === name);
39
- if (isRelational) {
40
- // field is relational
41
- const parts = fieldKey.split('.');
42
- let rootField = parts[0];
43
- let collectionScope = null;
44
- // a2o related collection scoped field selector `fields=sections.section_id:headings.title`
45
- if (rootField.includes(':')) {
46
- const [key, scope] = rootField.split(':');
47
- rootField = key;
48
- collectionScope = scope;
49
- }
50
- if (rootField in relationalStructure === false) {
51
- if (collectionScope) {
52
- relationalStructure[rootField] = { [collectionScope]: [] };
53
- }
54
- else {
55
- relationalStructure[rootField] = [];
56
- }
57
- }
58
- if (parts.length > 1) {
59
- const childKey = parts.slice(1).join('.');
60
- if (collectionScope) {
61
- if (collectionScope in relationalStructure[rootField] === false) {
62
- relationalStructure[rootField][collectionScope] = [];
63
- }
64
- relationalStructure[rootField][collectionScope].push(childKey);
65
- }
66
- else {
67
- relationalStructure[rootField].push(childKey);
68
- }
69
- }
70
- }
71
- else {
72
- if (name.includes('(') && name.includes(')')) {
73
- const columnName = name.match(REGEX_BETWEEN_PARENS)[1];
74
- const foundField = context.schema.collections[options.parentCollection].fields[columnName];
75
- if (foundField && foundField.type === 'alias') {
76
- const foundRelation = context.schema.relations.find((relation) => relation.related_collection === options.parentCollection && relation.meta?.one_field === columnName);
77
- if (foundRelation) {
78
- children.push({
79
- type: 'functionField',
80
- name,
81
- fieldKey,
82
- query: {},
83
- relatedCollection: foundRelation.collection,
84
- whenCase: [],
85
- cases: [],
86
- });
87
- continue;
88
- }
89
- }
90
- }
91
- children.push({ type: 'field', name, fieldKey, whenCase: [] });
92
- }
93
- }
94
- for (const [fieldKey, nestedFields] of Object.entries(relationalStructure)) {
95
- let fieldName = fieldKey;
96
- if (options.query.alias && fieldKey in options.query.alias) {
97
- fieldName = options.query.alias[fieldKey];
98
- }
99
- const relatedCollection = getRelatedCollection(context.schema, options.parentCollection, fieldName);
100
- const relation = getRelation(context.schema, options.parentCollection, fieldName);
101
- if (!relation)
102
- continue;
103
- const relationType = getRelationType({
104
- relation,
105
- collection: options.parentCollection,
106
- field: fieldName,
107
- });
108
- if (!relationType)
109
- continue;
110
- let child = null;
111
- if (relationType === 'a2o') {
112
- const allowedCollections = relation.meta.one_allowed_collections;
113
- child = {
114
- type: 'a2o',
115
- names: allowedCollections,
116
- children: {},
117
- query: {},
118
- relatedKey: {},
119
- parentKey: context.schema.collections[options.parentCollection].primary,
120
- fieldKey: fieldKey,
121
- relation: relation,
122
- cases: {},
123
- whenCase: [],
124
- };
125
- for (const relatedCollection of allowedCollections) {
126
- child.children[relatedCollection] = await parseFields({
127
- parentCollection: relatedCollection,
128
- fields: Array.isArray(nestedFields)
129
- ? nestedFields
130
- : nestedFields[relatedCollection] || [],
131
- query: options.query,
132
- deep: options.deep?.[`${fieldKey}:${relatedCollection}`],
133
- accountability: options.accountability,
134
- }, context);
135
- child.query[relatedCollection] = getDeepQuery(options.deep?.[`${fieldKey}:${relatedCollection}`] || {});
136
- child.relatedKey[relatedCollection] = context.schema.collections[relatedCollection].primary;
137
- }
138
- }
139
- else if (relatedCollection) {
140
- if (options.accountability && options.accountability.admin === false && policies) {
141
- const permissions = await fetchPermissions({
142
- action: 'read',
143
- collections: [relatedCollection],
144
- policies: policies,
145
- accountability: options.accountability,
146
- }, context);
147
- // Skip related collection if no permissions
148
- if (permissions.length === 0) {
149
- continue;
150
- }
151
- }
152
- // update query alias for children parseFields
153
- const deepAlias = getDeepQuery(options.deep?.[fieldKey] || {})?.['alias'];
154
- if (!isEmpty(deepAlias))
155
- options.query.alias = deepAlias;
156
- child = {
157
- type: relationType,
158
- name: relatedCollection,
159
- fieldKey: fieldKey,
160
- parentKey: context.schema.collections[options.parentCollection].primary,
161
- relatedKey: context.schema.collections[relatedCollection].primary,
162
- relation: relation,
163
- query: getDeepQuery(options.deep?.[fieldKey] || {}),
164
- children: await parseFields({
165
- parentCollection: relatedCollection,
166
- fields: nestedFields,
167
- query: options.query,
168
- deep: options.deep?.[fieldKey] || {},
169
- accountability: options.accountability,
170
- }, context),
171
- cases: [],
172
- whenCase: [],
173
- };
174
- if (relationType === 'o2m' && !child.query.sort) {
175
- child.query.sort = [relation.meta?.sort_field || context.schema.collections[relation.collection].primary];
176
- }
177
- }
178
- if (child) {
179
- children.push(child);
180
- }
181
- }
182
- // Deduplicate any children fields that are included both as a regular field, and as a nested m2o field
183
- const nestedCollectionNodes = children.filter((childNode) => childNode.type !== 'field');
184
- return children.filter((childNode) => {
185
- const existsAsNestedRelational = !!nestedCollectionNodes.find((nestedCollectionNode) => childNode.fieldKey === nestedCollectionNode.fieldKey);
186
- if (childNode.type === 'field' && existsAsNestedRelational)
187
- return false;
188
- return true;
189
- });
190
- }
@@ -1,14 +0,0 @@
1
- /**
2
- * Convert Deep query object to regular query object by ignoring all nested fields and returning the
3
- * `_` prefixed fields as top level query fields
4
- *
5
- * @example
6
- *
7
- * ```js
8
- * getDeepQuery({
9
- * _sort: ['a']
10
- * });
11
- * // => { sort: ['a'] }
12
- * ```
13
- */
14
- export declare function getDeepQuery(query: Record<string, any>): Record<string, any>;
@@ -1,17 +0,0 @@
1
- import { mapKeys, omitBy } from 'lodash-es';
2
- /**
3
- * Convert Deep query object to regular query object by ignoring all nested fields and returning the
4
- * `_` prefixed fields as top level query fields
5
- *
6
- * @example
7
- *
8
- * ```js
9
- * getDeepQuery({
10
- * _sort: ['a']
11
- * });
12
- * // => { sort: ['a'] }
13
- * ```
14
- */
15
- export function getDeepQuery(query) {
16
- return mapKeys(omitBy(query, (_value, key) => key.startsWith('_') === false), (_value, key) => key.substring(1));
17
- }
@@ -1,2 +0,0 @@
1
- import type { SchemaOverview } from '@directus/types';
2
- export declare function getRelatedCollection(schema: SchemaOverview, collection: string, field: string): string | null;
@@ -1,13 +0,0 @@
1
- import { getRelation } from './get-relation.js';
2
- export function getRelatedCollection(schema, collection, field) {
3
- const relation = getRelation(schema, collection, field);
4
- if (!relation)
5
- return null;
6
- if (relation.collection === collection && relation.field === field) {
7
- return relation.related_collection || null;
8
- }
9
- if (relation.related_collection === collection && relation.meta?.one_field === field) {
10
- return relation.collection || null;
11
- }
12
- return null;
13
- }
@@ -1,2 +0,0 @@
1
- import type { SchemaOverview } from '@directus/types';
2
- export declare function getRelation(schema: SchemaOverview, collection: string, field: string): import("@directus/types").Relation | undefined;
@@ -1,7 +0,0 @@
1
- export function getRelation(schema, collection, field) {
2
- const relation = schema.relations.find((relation) => {
3
- return ((relation.collection === collection && relation.field === field) ||
4
- (relation.related_collection === collection && relation.meta?.one_field === field));
5
- });
6
- return relation;
7
- }
@@ -1,164 +0,0 @@
1
- import { randomUUID } from 'node:crypto';
2
- import { processChunk } from '@directus/utils';
3
- /**
4
- * The public role used to be `null`, we gotta create a single new policy for the permissions
5
- * previously attached to the public role (marked through `role = null`).
6
- */
7
- const PUBLIC_POLICY_ID = 'abf8a154-5b1c-4a46-ac9c-7300570f4f17';
8
- export async function up(knex) {
9
- /////////////////////////////////////////////////////////////////////////////////////////////////
10
- // Create new policies table that mirrors previous Roles
11
- await knex.schema.createTable('directus_policies', (table) => {
12
- table.uuid('id').primary();
13
- table.string('name', 100).notNullable();
14
- table.string('icon', 64).notNullable().defaultTo('badge');
15
- table.text('description');
16
- table.text('ip_access');
17
- table.boolean('enforce_tfa').defaultTo(false).notNullable();
18
- table.boolean('admin_access').defaultTo(false).notNullable();
19
- table.boolean('app_access').defaultTo(false).notNullable();
20
- });
21
- /////////////////////////////////////////////////////////////////////////////////////////////////
22
- // Copy over all existing roles into new policies
23
- const roles = await knex
24
- .select('id', 'name', 'icon', 'description', 'ip_access', 'enforce_tfa', 'admin_access', 'app_access')
25
- .from('directus_roles');
26
- if (roles.length > 0) {
27
- await processChunk(roles, 100, async (chunk) => {
28
- await knex('directus_policies').insert(chunk);
29
- });
30
- }
31
- await knex
32
- .insert({
33
- id: PUBLIC_POLICY_ID,
34
- name: '$t:public_label',
35
- icon: 'public',
36
- description: '$t:public_description',
37
- app_access: false,
38
- })
39
- .into('directus_policies');
40
- // Change the admin policy description to $t:admin_policy_description
41
- await knex('directus_policies')
42
- .update({
43
- description: '$t:admin_policy_description',
44
- })
45
- .where('description', 'LIKE', '$t:admin_description');
46
- /////////////////////////////////////////////////////////////////////////////////////////////////
47
- // Remove access control + add nesting to roles
48
- await knex.schema.alterTable('directus_roles', (table) => {
49
- table.dropColumn('ip_access');
50
- table.dropColumn('enforce_tfa');
51
- table.dropColumn('admin_access');
52
- table.dropColumn('app_access');
53
- table.uuid('parent').references('directus_roles.id');
54
- });
55
- /////////////////////////////////////////////////////////////////////////////////////////////////
56
- // Link permissions to policies instead of roles
57
- await knex.schema.alterTable('directus_permissions', (table) => {
58
- table.uuid('policy').references('directus_policies.id').onDelete('CASCADE');
59
- // Drop the foreign key constraint here in order to update `null` role to public policy ID
60
- table.dropForeign('role');
61
- });
62
- await knex('directus_permissions')
63
- .update({
64
- role: PUBLIC_POLICY_ID,
65
- })
66
- .whereNull('role');
67
- await knex('directus_permissions').update({
68
- policy: knex.ref('role'),
69
- });
70
- await knex.schema.alterTable('directus_permissions', (table) => {
71
- table.dropColumns('role');
72
- table.dropNullable('policy');
73
- });
74
- /////////////////////////////////////////////////////////////////////////////////////////////////
75
- // Setup junction table between roles/users and policies
76
- // This could be a A2O style setup with a collection/item field rather than individual foreign
77
- // keys, but we want to be able to show the reverse-relationship on the individual policies as
78
- // well, which would require the O2A type to exist in Directus which currently doesn't.
79
- // Shouldn't be the end of the world here, as we know we're only attaching policies to two other
80
- // collections.
81
- await knex.schema.createTable('directus_access', (table) => {
82
- table.uuid('id').primary();
83
- table.uuid('role').references('directus_roles.id').nullable().onDelete('CASCADE');
84
- table.uuid('user').references('directus_users.id').nullable().onDelete('CASCADE');
85
- table.uuid('policy').references('directus_policies.id').notNullable().onDelete('CASCADE');
86
- table.integer('sort');
87
- });
88
- /////////////////////////////////////////////////////////////////////////////////////////////////
89
- // Attach policies to existing roles for backwards compatibility
90
- const policyAttachments = roles.map((role) => ({
91
- id: randomUUID(),
92
- role: role.id,
93
- user: null,
94
- policy: role.id,
95
- sort: 1,
96
- }));
97
- await processChunk(policyAttachments, 100, async (chunk) => {
98
- await knex('directus_access').insert(chunk);
99
- });
100
- await knex('directus_access').insert({
101
- id: randomUUID(),
102
- role: null,
103
- user: null,
104
- policy: PUBLIC_POLICY_ID,
105
- sort: 1,
106
- });
107
- }
108
- export async function down(knex) {
109
- /////////////////////////////////////////////////////////////////////////////////////////////////
110
- // Reinstate access control fields on directus roles + remove nesting
111
- await knex.schema.alterTable('directus_roles', (table) => {
112
- table.text('ip_access');
113
- table.boolean('enforce_tfa').defaultTo(false).notNullable();
114
- table.boolean('admin_access').defaultTo(false).notNullable();
115
- table.boolean('app_access').defaultTo(true).notNullable();
116
- table.dropForeign('parent');
117
- table.dropColumn('parent');
118
- });
119
- /////////////////////////////////////////////////////////////////////////////////////////////////
120
- // Copy policy access control rules back to roles
121
- const policies = await knex
122
- .select('id', 'ip_access', 'enforce_tfa', 'admin_access', 'app_access')
123
- .from('directus_policies')
124
- .whereNot({ id: PUBLIC_POLICY_ID });
125
- for (const policy of policies) {
126
- await knex('directus_roles')
127
- .update({
128
- ip_access: policy.ip_access,
129
- enforce_tfa: policy.enforce_tfa,
130
- admin_access: policy.admin_access,
131
- app_access: policy.app_access,
132
- })
133
- .where({ id: policy.id });
134
- }
135
- /////////////////////////////////////////////////////////////////////////////////////////////////
136
- // Drop all permissions that are only attached to a user
137
- // TODO query all policies that are attached to a user and delete their permissions,
138
- // since we don't know were to put them now and it'll cause a foreign key problem
139
- // as soon as we reference directus_roles in directus_permissions again
140
- /////////////////////////////////////////////////////////////////////////////////////////////////
141
- // Drop policy attachments
142
- await knex.schema.dropTable('directus_access');
143
- /////////////////////////////////////////////////////////////////////////////////////////////////
144
- // Reattach permissions to roles instead of policies
145
- await knex.schema.alterTable('directus_permissions', (table) => {
146
- table.uuid('role').nullable();
147
- });
148
- await knex('directus_permissions').update({
149
- role: knex.ref('policy'),
150
- });
151
- await knex('directus_permissions')
152
- .update({
153
- role: null,
154
- })
155
- .where({ role: PUBLIC_POLICY_ID });
156
- await knex.schema.alterTable('directus_permissions', (table) => {
157
- table.uuid('role').references('directus_roles.id').alter();
158
- table.dropForeign('policy');
159
- table.dropColumn('policy');
160
- });
161
- /////////////////////////////////////////////////////////////////////////////////////////////////
162
- // Drop policies table
163
- await knex.schema.dropTable('directus_policies');
164
- }
@@ -1,4 +0,0 @@
1
- import type { Filter, Query, SchemaOverview } from '@directus/types';
2
- import type { Knex } from 'knex';
3
- import type { FieldNode, FunctionFieldNode, O2MNode } from '../../../types/ast.js';
4
- export declare function getDBQuery(schema: SchemaOverview, knex: Knex, table: string, fieldNodes: (FieldNode | FunctionFieldNode)[], o2mNodes: O2MNode[], query: Query, cases: Filter[]): Knex.QueryBuilder;
@@ -1,194 +0,0 @@
1
- import { useEnv } from '@directus/env';
2
- import { cloneDeep } from 'lodash-es';
3
- import applyQuery, { applyLimit, applySort, generateAlias } from '../../../utils/apply-query.js';
4
- import { getCollectionFromAlias } from '../../../utils/get-collection-from-alias.js';
5
- import { getColumn } from '../../../utils/get-column.js';
6
- import { getHelpers } from '../../helpers/index.js';
7
- import { applyCaseWhen } from '../utils/apply-case-when.js';
8
- import { getColumnPreprocessor } from '../utils/get-column-pre-processor.js';
9
- import { getNodeAlias } from '../utils/get-field-alias.js';
10
- import { getInnerQueryColumnPreProcessor } from '../utils/get-inner-query-column-pre-processor.js';
11
- export function getDBQuery(schema, knex, table, fieldNodes, o2mNodes, query, cases) {
12
- const aliasMap = Object.create(null);
13
- const env = useEnv();
14
- const preProcess = getColumnPreprocessor(knex, schema, table, cases, aliasMap);
15
- const queryCopy = cloneDeep(query);
16
- const helpers = getHelpers(knex);
17
- const hasCaseWhen = o2mNodes.some((node) => node.whenCase && node.whenCase.length > 0) ||
18
- fieldNodes.some((node) => node.whenCase && node.whenCase.length > 0);
19
- queryCopy.limit = typeof queryCopy.limit === 'number' ? queryCopy.limit : Number(env['QUERY_LIMIT_DEFAULT']);
20
- // Queries with aggregates and groupBy will not have duplicate result
21
- if (queryCopy.aggregate || queryCopy.group) {
22
- const flatQuery = knex.from(table).select(fieldNodes.map((node) => preProcess(node)));
23
- return applyQuery(knex, table, flatQuery, queryCopy, schema, cases).query;
24
- }
25
- const primaryKey = schema.collections[table].primary;
26
- let dbQuery = knex.from(table);
27
- let sortRecords;
28
- const innerQuerySortRecords = [];
29
- let hasMultiRelationalSort;
30
- if (queryCopy.sort) {
31
- const sortResult = applySort(knex, schema, dbQuery, queryCopy, table, aliasMap, true);
32
- if (sortResult) {
33
- sortRecords = sortResult.sortRecords;
34
- hasMultiRelationalSort = sortResult.hasMultiRelationalSort;
35
- }
36
- }
37
- const { hasMultiRelationalFilter } = applyQuery(knex, table, dbQuery, queryCopy, schema, cases, {
38
- aliasMap,
39
- isInnerQuery: true,
40
- hasMultiRelationalSort,
41
- });
42
- const needsInnerQuery = hasMultiRelationalSort || hasMultiRelationalFilter;
43
- if (needsInnerQuery) {
44
- dbQuery.select(`${table}.${primaryKey}`);
45
- // Only add distinct if there are no case/when constructs, since otherwise we rely on group by
46
- if (!hasCaseWhen)
47
- dbQuery.distinct();
48
- }
49
- else {
50
- dbQuery.select(fieldNodes.map((node) => preProcess(node)));
51
- // Add flags for o2m fields with case/when to the let the DB to the partial item permissions
52
- dbQuery.select(o2mNodes
53
- .filter((node) => node.whenCase && node.whenCase.length > 0)
54
- .map((node) => {
55
- const columnCases = node.whenCase.map((index) => cases[index]);
56
- return applyCaseWhen({
57
- column: knex.raw(1),
58
- columnCases,
59
- aliasMap,
60
- cases,
61
- table,
62
- alias: node.fieldKey,
63
- }, { knex, schema });
64
- }));
65
- }
66
- if (sortRecords) {
67
- // Clears the order if any, eg: from MSSQL offset
68
- dbQuery.clear('order');
69
- if (needsInnerQuery) {
70
- let orderByString = '';
71
- const orderByFields = [];
72
- sortRecords.map((sortRecord) => {
73
- if (orderByString.length !== 0) {
74
- orderByString += ', ';
75
- }
76
- const sortAlias = `sort_${generateAlias()}`;
77
- if (sortRecord.column.includes('.')) {
78
- const [alias, field] = sortRecord.column.split('.');
79
- const originalCollectionName = getCollectionFromAlias(alias, aliasMap);
80
- dbQuery.select(getColumn(knex, alias, field, sortAlias, schema, { originalCollectionName }));
81
- orderByString += `?? ${sortRecord.order}`;
82
- orderByFields.push(getColumn(knex, alias, field, false, schema, { originalCollectionName }));
83
- }
84
- else {
85
- dbQuery.select(getColumn(knex, table, sortRecord.column, sortAlias, schema));
86
- orderByString += `?? ${sortRecord.order}`;
87
- orderByFields.push(getColumn(knex, table, sortRecord.column, false, schema));
88
- }
89
- innerQuerySortRecords.push({ alias: sortAlias, order: sortRecord.order });
90
- });
91
- dbQuery.orderByRaw(orderByString, orderByFields);
92
- if (hasMultiRelationalSort) {
93
- dbQuery = helpers.schema.applyMultiRelationalSort(knex, dbQuery, table, primaryKey, orderByString, orderByFields);
94
- }
95
- }
96
- else {
97
- sortRecords.map((sortRecord) => {
98
- if (sortRecord.column.includes('.')) {
99
- const [alias, field] = sortRecord.column.split('.');
100
- sortRecord.column = getColumn(knex, alias, field, false, schema, {
101
- originalCollectionName: getCollectionFromAlias(alias, aliasMap),
102
- });
103
- }
104
- else {
105
- sortRecord.column = getColumn(knex, table, sortRecord.column, false, schema);
106
- }
107
- });
108
- dbQuery.orderBy(sortRecords);
109
- }
110
- }
111
- if (!needsInnerQuery)
112
- return dbQuery;
113
- const innerCaseWhenAliasPrefix = generateAlias();
114
- if (hasCaseWhen) {
115
- /* If there are cases, we need to employ a trick in order to evaluate the case/when structure in the inner query,
116
- while passing the result of the evaluation to the outer query. The case/when needs to be evaluated in the inner
117
- query since only there all joined in tables, that might be required for the case/when, are available.
118
-
119
- The problem is, that the resulting columns can not be directly selected in the inner query,
120
- as a `SELECT DISTINCT` does not work for all datatypes in all vendors.
121
-
122
- So instead of having an inner query which might look like this:
123
-
124
- SELECT DISTINCT ...,
125
- CASE WHEN <condition> THEN <actual-column> END AS <alias>
126
-
127
- Another problem is that all not all rows with the same primary key are guaranteed to have the same value for
128
- the columns with the case/when, so we to `or` those together, but counting the number of flags in a group by
129
- operation. This way the flag is set to > 0 if any of the rows in the group allows access to the column.
130
-
131
- The inner query only evaluates the condition and passes up or-ed flag, that is used in the wrapper query to select
132
- the actual column:
133
-
134
- SELECT ...,
135
- COUNT (CASE WHEN <condition> THEN 1 END) AS <random-prefix>_<alias>
136
- ...
137
- GROUP BY <primary-key>
138
-
139
- Then, in the wrapper query there is no need to evaluate the condition again, but instead rely on the flag:
140
-
141
- SELECT ...,
142
- CASE WHEN `inner`.<random-prefix>_<alias> > 0 THEN <actual-column> END AS <alias>
143
- */
144
- const innerPreprocess = getInnerQueryColumnPreProcessor(knex, schema, table, cases, aliasMap, innerCaseWhenAliasPrefix);
145
- // To optimize the query we avoid having unnecessary columns in the inner query, that don't have a caseWhen, since
146
- // they are selected in the outer query directly
147
- dbQuery.select(fieldNodes.map(innerPreprocess).filter((x) => x !== null));
148
- // In addition to the regular columns select a flag that indicates if a user has access to o2m related field
149
- // based on the case/when of that field.
150
- dbQuery.select(o2mNodes.map(innerPreprocess).filter((x) => x !== null));
151
- dbQuery.groupByRaw(`${table}.${primaryKey}`);
152
- }
153
- const wrapperQuery = knex
154
- .from(table)
155
- .innerJoin(knex.raw('??', dbQuery.as('inner')), `${table}.${primaryKey}`, `inner.${primaryKey}`);
156
- if (!hasCaseWhen) {
157
- // No need for case/when in the wrapper query, just select the preprocessed columns
158
- wrapperQuery.select(fieldNodes.map((node) => preProcess(node)));
159
- }
160
- else {
161
- // This applies a simplified case/when construct in the wrapper query, that only looks at flag > 1
162
- // Distinguish between column with and without case/when and handle them differently
163
- const plainColumns = fieldNodes.filter((fieldNode) => !fieldNode.whenCase || fieldNode.whenCase.length === 0);
164
- const whenCaseColumns = fieldNodes.filter((fieldNode) => fieldNode.whenCase && fieldNode.whenCase.length > 0);
165
- // Select the plain columns
166
- wrapperQuery.select(plainColumns.map((node) => preProcess(node)));
167
- // Select the case/when columns based on the flag from the inner query
168
- wrapperQuery.select(whenCaseColumns.map((fieldNode) => {
169
- const alias = getNodeAlias(fieldNode);
170
- const innerAlias = `${innerCaseWhenAliasPrefix}_${alias}`;
171
- // Preprocess the column without the case/when, since that is applied in a simpler fashion in the select
172
- const column = preProcess({ ...fieldNode, whenCase: [] }, { noAlias: true });
173
- return knex.raw(`CASE WHEN ??.?? > 0 THEN ?? END as ??`, ['inner', innerAlias, column, alias]);
174
- }));
175
- // Pass the flags of o2m fields up through the wrapper query
176
- wrapperQuery.select(o2mNodes
177
- .filter((node) => node.whenCase && node.whenCase.length > 0)
178
- .map((node) => {
179
- const alias = node.fieldKey;
180
- const innerAlias = `${innerCaseWhenAliasPrefix}_${alias}`;
181
- return knex.raw(`CASE WHEN ??.?? > 0 THEN 1 END as ??`, ['inner', innerAlias, alias]);
182
- }));
183
- }
184
- if (sortRecords && needsInnerQuery) {
185
- innerQuerySortRecords.map((innerQuerySortRecord) => {
186
- wrapperQuery.orderBy(`inner.${innerQuerySortRecord.alias}`, innerQuerySortRecord.order);
187
- });
188
- if (hasMultiRelationalSort) {
189
- wrapperQuery.where('inner.directus_row_number', '=', 1);
190
- applyLimit(knex, wrapperQuery, queryCopy.limit);
191
- }
192
- }
193
- return wrapperQuery;
194
- }
@@ -1,7 +0,0 @@
1
- import type { Query, SchemaOverview } from '@directus/types';
2
- import type { FieldNode, FunctionFieldNode, NestedCollectionNode } from '../../../types/ast.js';
3
- export declare function parseCurrentLevel(schema: SchemaOverview, collection: string, children: (NestedCollectionNode | FieldNode | FunctionFieldNode)[], query: Query): Promise<{
4
- fieldNodes: FieldNode[];
5
- nestedCollectionNodes: NestedCollectionNode[];
6
- primaryKeyField: string;
7
- }>;