@strapi/database 4.15.0-alpha.0 → 4.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (242) hide show
  1. package/README.md +3 -0
  2. package/dist/connection.d.ts +3 -0
  3. package/dist/connection.d.ts.map +1 -0
  4. package/dist/dialects/dialect.d.ts +27 -0
  5. package/dist/dialects/dialect.d.ts.map +1 -0
  6. package/dist/dialects/index.d.ts +5 -0
  7. package/dist/dialects/index.d.ts.map +1 -0
  8. package/dist/dialects/mysql/constants.d.ts +3 -0
  9. package/dist/dialects/mysql/constants.d.ts.map +1 -0
  10. package/dist/dialects/mysql/database-inspector.d.ts +12 -0
  11. package/dist/dialects/mysql/database-inspector.d.ts.map +1 -0
  12. package/dist/dialects/mysql/index.d.ts +20 -0
  13. package/dist/dialects/mysql/index.d.ts.map +1 -0
  14. package/dist/dialects/mysql/schema-inspector.d.ts +13 -0
  15. package/dist/dialects/mysql/schema-inspector.d.ts.map +1 -0
  16. package/dist/dialects/postgresql/index.d.ts +14 -0
  17. package/dist/dialects/postgresql/index.d.ts.map +1 -0
  18. package/dist/dialects/postgresql/schema-inspector.d.ts +14 -0
  19. package/dist/dialects/postgresql/schema-inspector.d.ts.map +1 -0
  20. package/dist/dialects/sqlite/index.d.ts +19 -0
  21. package/dist/dialects/sqlite/index.d.ts.map +1 -0
  22. package/dist/dialects/sqlite/schema-inspector.d.ts +13 -0
  23. package/dist/dialects/sqlite/schema-inspector.d.ts.map +1 -0
  24. package/dist/entity-manager/entity-repository.d.ts +4 -0
  25. package/dist/entity-manager/entity-repository.d.ts.map +1 -0
  26. package/dist/entity-manager/index.d.ts +5 -0
  27. package/dist/entity-manager/index.d.ts.map +1 -0
  28. package/dist/entity-manager/morph-relations.d.ts +13 -0
  29. package/dist/entity-manager/morph-relations.d.ts.map +1 -0
  30. package/dist/entity-manager/regular-relations.d.ts +83 -0
  31. package/dist/entity-manager/regular-relations.d.ts.map +1 -0
  32. package/dist/entity-manager/relations/cloning/regular-relations.d.ts +17 -0
  33. package/dist/entity-manager/relations/cloning/regular-relations.d.ts.map +1 -0
  34. package/dist/entity-manager/relations-orderer.d.ts +73 -0
  35. package/dist/entity-manager/relations-orderer.d.ts.map +1 -0
  36. package/dist/entity-manager/types.d.ts +97 -0
  37. package/dist/entity-manager/types.d.ts.map +1 -0
  38. package/dist/errors/database.d.ts +5 -0
  39. package/dist/errors/database.d.ts.map +1 -0
  40. package/dist/errors/index.d.ts +8 -0
  41. package/dist/errors/index.d.ts.map +1 -0
  42. package/dist/errors/invalid-date.d.ts +5 -0
  43. package/dist/errors/invalid-date.d.ts.map +1 -0
  44. package/dist/errors/invalid-datetime.d.ts +5 -0
  45. package/dist/errors/invalid-datetime.d.ts.map +1 -0
  46. package/dist/errors/invalid-relation.d.ts +5 -0
  47. package/dist/errors/invalid-relation.d.ts.map +1 -0
  48. package/dist/errors/invalid-time.d.ts +5 -0
  49. package/dist/errors/invalid-time.d.ts.map +1 -0
  50. package/dist/errors/not-null.d.ts +7 -0
  51. package/dist/errors/not-null.d.ts.map +1 -0
  52. package/dist/fields/biginteger.d.ts +4 -0
  53. package/dist/fields/biginteger.d.ts.map +1 -0
  54. package/dist/fields/boolean.d.ts +6 -0
  55. package/dist/fields/boolean.d.ts.map +1 -0
  56. package/dist/fields/date.d.ts +6 -0
  57. package/dist/fields/date.d.ts.map +1 -0
  58. package/dist/fields/datetime.d.ts +6 -0
  59. package/dist/fields/datetime.d.ts.map +1 -0
  60. package/dist/fields/field.d.ts +7 -0
  61. package/dist/fields/field.d.ts.map +1 -0
  62. package/dist/fields/index.d.ts +4 -0
  63. package/dist/fields/index.d.ts.map +1 -0
  64. package/dist/fields/json.d.ts +6 -0
  65. package/dist/fields/json.d.ts.map +1 -0
  66. package/dist/fields/number.d.ts +6 -0
  67. package/dist/fields/number.d.ts.map +1 -0
  68. package/dist/fields/shared/parsers.d.ts +4 -0
  69. package/dist/fields/shared/parsers.d.ts.map +1 -0
  70. package/dist/fields/string.d.ts +6 -0
  71. package/dist/fields/string.d.ts.map +1 -0
  72. package/dist/fields/time.d.ts +6 -0
  73. package/dist/fields/time.d.ts.map +1 -0
  74. package/dist/fields/timestamp.d.ts +6 -0
  75. package/dist/fields/timestamp.d.ts.map +1 -0
  76. package/dist/index.d.ts +46 -0
  77. package/dist/index.d.ts.map +1 -0
  78. package/dist/index.js +6189 -0
  79. package/dist/index.js.map +1 -0
  80. package/dist/index.mjs +6157 -0
  81. package/dist/index.mjs.map +1 -0
  82. package/dist/lifecycles/index.d.ts +17 -0
  83. package/dist/lifecycles/index.d.ts.map +1 -0
  84. package/dist/lifecycles/subscribers/index.d.ts +5 -0
  85. package/dist/lifecycles/subscribers/index.d.ts.map +1 -0
  86. package/dist/lifecycles/subscribers/models-lifecycles.d.ts +6 -0
  87. package/dist/lifecycles/subscribers/models-lifecycles.d.ts.map +1 -0
  88. package/dist/lifecycles/subscribers/timestamps.d.ts +3 -0
  89. package/dist/lifecycles/subscribers/timestamps.d.ts.map +1 -0
  90. package/dist/lifecycles/types.d.ts +25 -0
  91. package/dist/lifecycles/types.d.ts.map +1 -0
  92. package/dist/metadata/index.d.ts +10 -0
  93. package/dist/metadata/index.d.ts.map +1 -0
  94. package/dist/metadata/metadata.d.ts +22 -0
  95. package/dist/metadata/metadata.d.ts.map +1 -0
  96. package/dist/metadata/relations.d.ts +16 -0
  97. package/dist/metadata/relations.d.ts.map +1 -0
  98. package/dist/migrations/index.d.ts +12 -0
  99. package/dist/migrations/index.d.ts.map +1 -0
  100. package/dist/migrations/storage.d.ts +15 -0
  101. package/dist/migrations/storage.d.ts.map +1 -0
  102. package/dist/query/helpers/index.d.ts +8 -0
  103. package/dist/query/helpers/index.d.ts.map +1 -0
  104. package/dist/query/helpers/join.d.ts +30 -0
  105. package/dist/query/helpers/join.d.ts.map +1 -0
  106. package/dist/query/helpers/order-by.d.ts +14 -0
  107. package/dist/query/helpers/order-by.d.ts.map +1 -0
  108. package/dist/query/helpers/populate/apply.d.ts +11 -0
  109. package/dist/query/helpers/populate/apply.d.ts.map +1 -0
  110. package/dist/query/helpers/populate/index.d.ts +4 -0
  111. package/dist/query/helpers/populate/index.d.ts.map +1 -0
  112. package/dist/query/helpers/populate/process.d.ts +24 -0
  113. package/dist/query/helpers/populate/process.d.ts.map +1 -0
  114. package/dist/query/helpers/search.d.ts +4 -0
  115. package/dist/query/helpers/search.d.ts.map +1 -0
  116. package/dist/query/helpers/streams/index.d.ts +2 -0
  117. package/dist/query/helpers/streams/index.d.ts.map +1 -0
  118. package/dist/query/helpers/streams/readable.d.ts +39 -0
  119. package/dist/query/helpers/streams/readable.d.ts.map +1 -0
  120. package/dist/query/helpers/transform.d.ts +8 -0
  121. package/dist/query/helpers/transform.d.ts.map +1 -0
  122. package/dist/query/helpers/where.d.ts +19 -0
  123. package/dist/query/helpers/where.d.ts.map +1 -0
  124. package/dist/query/index.d.ts +3 -0
  125. package/dist/query/index.d.ts.map +1 -0
  126. package/dist/query/query-builder.d.ts +79 -0
  127. package/dist/query/query-builder.d.ts.map +1 -0
  128. package/dist/query/types.d.ts +8 -0
  129. package/dist/query/types.d.ts.map +1 -0
  130. package/dist/schema/builder.d.ts +33 -0
  131. package/dist/schema/builder.d.ts.map +1 -0
  132. package/dist/schema/diff.d.ts +7 -0
  133. package/dist/schema/diff.d.ts.map +1 -0
  134. package/dist/schema/index.d.ts +20 -0
  135. package/dist/schema/index.d.ts.map +1 -0
  136. package/dist/schema/schema.d.ts +4 -0
  137. package/dist/schema/schema.d.ts.map +1 -0
  138. package/dist/schema/storage.d.ts +10 -0
  139. package/dist/schema/storage.d.ts.map +1 -0
  140. package/dist/schema/types.d.ts +103 -0
  141. package/dist/schema/types.d.ts.map +1 -0
  142. package/dist/transaction-context.d.ts +22 -0
  143. package/dist/transaction-context.d.ts.map +1 -0
  144. package/dist/types/index.d.ts +169 -0
  145. package/dist/types/index.d.ts.map +1 -0
  146. package/dist/utils/content-types.d.ts +13 -0
  147. package/dist/utils/content-types.d.ts.map +1 -0
  148. package/dist/utils/knex.d.ts +12 -0
  149. package/dist/utils/knex.d.ts.map +1 -0
  150. package/dist/utils/types.d.ts +10 -0
  151. package/dist/utils/types.d.ts.map +1 -0
  152. package/dist/validations/index.d.ts +6 -0
  153. package/dist/validations/index.d.ts.map +1 -0
  154. package/dist/validations/relations/bidirectional.d.ts +12 -0
  155. package/dist/validations/relations/bidirectional.d.ts.map +1 -0
  156. package/dist/validations/relations/index.d.ts +7 -0
  157. package/dist/validations/relations/index.d.ts.map +1 -0
  158. package/package.json +21 -9
  159. package/.eslintignore +0 -2
  160. package/.eslintrc.js +0 -4
  161. package/jest.config.js +0 -6
  162. package/lib/__tests__/index.test.js +0 -93
  163. package/lib/__tests__/lifecycles.test.js +0 -55
  164. package/lib/connection.js +0 -64
  165. package/lib/dialects/dialect.js +0 -63
  166. package/lib/dialects/index.js +0 -53
  167. package/lib/dialects/mysql/constants.js +0 -6
  168. package/lib/dialects/mysql/database-inspector.js +0 -37
  169. package/lib/dialects/mysql/index.js +0 -92
  170. package/lib/dialects/mysql/schema-inspector.js +0 -234
  171. package/lib/dialects/postgresql/index.js +0 -65
  172. package/lib/dialects/postgresql/schema-inspector.js +0 -283
  173. package/lib/dialects/sqlite/index.js +0 -87
  174. package/lib/dialects/sqlite/schema-inspector.js +0 -151
  175. package/lib/entity-manager/__tests__/relations-orderer.test.js +0 -186
  176. package/lib/entity-manager/__tests__/sort-connect-array.test.js +0 -79
  177. package/lib/entity-manager/entity-repository.js +0 -164
  178. package/lib/entity-manager/index.js +0 -1385
  179. package/lib/entity-manager/morph-relations.js +0 -63
  180. package/lib/entity-manager/regular-relations.js +0 -506
  181. package/lib/entity-manager/relations/cloning/regular-relations.js +0 -76
  182. package/lib/entity-manager/relations-orderer.js +0 -225
  183. package/lib/errors/database.js +0 -12
  184. package/lib/errors/index.js +0 -17
  185. package/lib/errors/invalid-date.js +0 -14
  186. package/lib/errors/invalid-datetime.js +0 -14
  187. package/lib/errors/invalid-relation.js +0 -14
  188. package/lib/errors/invalid-time.js +0 -14
  189. package/lib/errors/not-null.js +0 -15
  190. package/lib/fields/biginteger.js +0 -17
  191. package/lib/fields/boolean.js +0 -39
  192. package/lib/fields/date.js +0 -16
  193. package/lib/fields/datetime.js +0 -19
  194. package/lib/fields/field.js +0 -17
  195. package/lib/fields/index.d.ts +0 -9
  196. package/lib/fields/index.js +0 -50
  197. package/lib/fields/json.js +0 -21
  198. package/lib/fields/number.js +0 -23
  199. package/lib/fields/shared/parsers.js +0 -71
  200. package/lib/fields/string.js +0 -17
  201. package/lib/fields/time.js +0 -17
  202. package/lib/fields/timestamp.js +0 -19
  203. package/lib/index.d.ts +0 -198
  204. package/lib/index.js +0 -129
  205. package/lib/lifecycles/index.d.ts +0 -51
  206. package/lib/lifecycles/index.js +0 -90
  207. package/lib/lifecycles/subscribers/index.d.ts +0 -11
  208. package/lib/lifecycles/subscribers/models-lifecycles.js +0 -19
  209. package/lib/lifecycles/subscribers/timestamps.js +0 -65
  210. package/lib/metadata/index.js +0 -244
  211. package/lib/metadata/relations.js +0 -578
  212. package/lib/migrations/index.d.ts +0 -9
  213. package/lib/migrations/index.js +0 -75
  214. package/lib/migrations/storage.js +0 -44
  215. package/lib/query/helpers/index.js +0 -11
  216. package/lib/query/helpers/join.js +0 -96
  217. package/lib/query/helpers/order-by.js +0 -70
  218. package/lib/query/helpers/populate/apply.js +0 -664
  219. package/lib/query/helpers/populate/index.js +0 -9
  220. package/lib/query/helpers/populate/process.js +0 -102
  221. package/lib/query/helpers/search.js +0 -84
  222. package/lib/query/helpers/streams/index.js +0 -5
  223. package/lib/query/helpers/streams/readable.js +0 -174
  224. package/lib/query/helpers/transform.js +0 -84
  225. package/lib/query/helpers/where.js +0 -365
  226. package/lib/query/index.js +0 -7
  227. package/lib/query/query-builder.js +0 -514
  228. package/lib/schema/__tests__/schema-diff.test.js +0 -231
  229. package/lib/schema/builder.js +0 -386
  230. package/lib/schema/diff.js +0 -399
  231. package/lib/schema/index.d.ts +0 -49
  232. package/lib/schema/index.js +0 -94
  233. package/lib/schema/schema.js +0 -202
  234. package/lib/schema/storage.js +0 -76
  235. package/lib/transaction-context.js +0 -68
  236. package/lib/types/index.d.ts +0 -6
  237. package/lib/types/index.js +0 -35
  238. package/lib/utils/content-types.js +0 -40
  239. package/lib/utils/knex.js +0 -22
  240. package/lib/validations/index.js +0 -20
  241. package/lib/validations/relations/bidirectional.js +0 -89
  242. package/lib/validations/relations/index.js +0 -14
@@ -1,63 +0,0 @@
1
- 'use strict';
2
-
3
- const { groupBy, pipe, mapValues, map, isEmpty } = require('lodash/fp');
4
- const { createQueryBuilder } = require('../query');
5
-
6
- const getMorphToManyRowsLinkedToMorphOne = (rows, { uid, attributeName, typeColumn, db }) =>
7
- rows.filter((row) => {
8
- const relatedType = row[typeColumn.name];
9
- const field = row.field;
10
-
11
- const targetAttribute = db.metadata.get(relatedType).attributes[field];
12
-
13
- // ensure targeted field is the right one + check if it is a morphOne
14
- return (
15
- targetAttribute?.target === uid &&
16
- targetAttribute?.morphBy === attributeName &&
17
- targetAttribute?.relation === 'morphOne'
18
- );
19
- });
20
-
21
- const deleteRelatedMorphOneRelationsAfterMorphToManyUpdate = async (
22
- rows,
23
- { uid, attributeName, joinTable, db, transaction: trx }
24
- ) => {
25
- const { morphColumn } = joinTable;
26
- const { idColumn, typeColumn } = morphColumn;
27
-
28
- const morphOneRows = getMorphToManyRowsLinkedToMorphOne(rows, {
29
- uid,
30
- attributeName,
31
- typeColumn,
32
- db,
33
- });
34
-
35
- const groupByType = groupBy(typeColumn.name);
36
- const groupByField = groupBy('field');
37
-
38
- const typeAndFieldIdsGrouped = pipe(groupByType, mapValues(groupByField))(morphOneRows);
39
-
40
- const orWhere = [];
41
-
42
- for (const [type, v] of Object.entries(typeAndFieldIdsGrouped)) {
43
- for (const [field, arr] of Object.entries(v)) {
44
- orWhere.push({
45
- [typeColumn.name]: type,
46
- field,
47
- [idColumn.name]: { $in: map(idColumn.name, arr) },
48
- });
49
- }
50
- }
51
-
52
- if (!isEmpty(orWhere)) {
53
- await createQueryBuilder(joinTable.name, db)
54
- .delete()
55
- .where({ $or: orWhere })
56
- .transacting(trx)
57
- .execute();
58
- }
59
- };
60
-
61
- module.exports = {
62
- deleteRelatedMorphOneRelationsAfterMorphToManyUpdate,
63
- };
@@ -1,506 +0,0 @@
1
- 'use strict';
2
-
3
- const { randomBytes } = require('crypto');
4
- const { map, isEmpty } = require('lodash/fp');
5
-
6
- const {
7
- isBidirectional,
8
- isOneToAny,
9
- isManyToAny,
10
- isAnyToOne,
11
- hasOrderColumn,
12
- hasInverseOrderColumn,
13
- } = require('../metadata/relations');
14
- const { createQueryBuilder } = require('../query');
15
- const { addSchema } = require('../utils/knex');
16
-
17
- /**
18
- * If some relations currently exist for this oneToX relation, on the one side, this function removes them and update the inverse order if needed.
19
- * @param {Object} params
20
- * @param {string} params.id - entity id on which the relations for entities relIdsToadd are created
21
- * @param {string} params.attribute - attribute of the relation
22
- * @param {string} params.inverseRelIds - entity ids of the inverse side for which the current relations will be deleted
23
- * @param {string} params.db - database instance
24
- */
25
- const deletePreviousOneToAnyRelations = async ({
26
- id,
27
- attribute,
28
- relIdsToadd,
29
- db,
30
- transaction: trx,
31
- }) => {
32
- if (!(isBidirectional(attribute) && isOneToAny(attribute))) {
33
- throw new Error(
34
- 'deletePreviousOneToAnyRelations can only be called for bidirectional oneToAny relations'
35
- );
36
- }
37
- const { joinTable } = attribute;
38
- const { joinColumn, inverseJoinColumn } = joinTable;
39
-
40
- await createQueryBuilder(joinTable.name, db)
41
- .delete()
42
- .where({
43
- [inverseJoinColumn.name]: relIdsToadd,
44
- [joinColumn.name]: { $ne: id },
45
- })
46
- .where(joinTable.on || {})
47
- .transacting(trx)
48
- .execute();
49
-
50
- await cleanOrderColumns({ attribute, db, inverseRelIds: relIdsToadd, transaction: trx });
51
- };
52
-
53
- /**
54
- * If a relation currently exists for this xToOne relations, this function removes it and update the inverse order if needed.
55
- * @param {Object} params
56
- * @param {string} params.id - entity id on which the relation for entity relIdToadd is created
57
- * @param {string} params.attribute - attribute of the relation
58
- * @param {string} params.relIdToadd - entity id of the new relation
59
- * @param {string} params.db - database instance
60
- */
61
- const deletePreviousAnyToOneRelations = async ({
62
- id,
63
- attribute,
64
- relIdToadd,
65
- db,
66
- transaction: trx,
67
- }) => {
68
- const { joinTable } = attribute;
69
- const { joinColumn, inverseJoinColumn } = joinTable;
70
-
71
- if (!isAnyToOne(attribute)) {
72
- throw new Error('deletePreviousAnyToOneRelations can only be called for anyToOne relations');
73
- }
74
- // handling manyToOne
75
- if (isManyToAny(attribute)) {
76
- // if the database integrity was not broken relsToDelete is supposed to be of length 1
77
- const relsToDelete = await createQueryBuilder(joinTable.name, db)
78
- .select(inverseJoinColumn.name)
79
- .where({
80
- [joinColumn.name]: id,
81
- [inverseJoinColumn.name]: { $ne: relIdToadd },
82
- })
83
- .where(joinTable.on || {})
84
- .transacting(trx)
85
- .execute();
86
-
87
- const relIdsToDelete = map(inverseJoinColumn.name, relsToDelete);
88
-
89
- await createQueryBuilder(joinTable.name, db)
90
- .delete()
91
- .where({
92
- [joinColumn.name]: id,
93
- [inverseJoinColumn.name]: { $in: relIdsToDelete },
94
- })
95
- .where(joinTable.on || {})
96
- .transacting(trx)
97
- .execute();
98
-
99
- await cleanOrderColumns({ attribute, db, inverseRelIds: relIdsToDelete, transaction: trx });
100
-
101
- // handling oneToOne
102
- } else {
103
- await createQueryBuilder(joinTable.name, db)
104
- .delete()
105
- .where({
106
- [joinColumn.name]: id,
107
- [inverseJoinColumn.name]: { $ne: relIdToadd },
108
- })
109
- .where(joinTable.on || {})
110
- .transacting(trx)
111
- .execute();
112
- }
113
- };
114
-
115
- /**
116
- * Delete all or some relations of entity field
117
- * @param {Object} params
118
- * @param {string} params.id - entity id for which the relations will be deleted
119
- * @param {string} params.attribute - attribute of the relation
120
- * @param {string} params.db - database instance
121
- * @param {string} params.relIdsToDelete - ids of entities to remove from the relations. Also accepts 'all'
122
- * @param {string} params.relIdsToNotDelete - ids of entities to not remove from the relation when relIdsToDelete equals 'all'
123
- */
124
- const deleteRelations = async ({
125
- id,
126
- attribute,
127
- db,
128
- relIdsToNotDelete = [],
129
- relIdsToDelete = [],
130
- transaction: trx,
131
- }) => {
132
- const { joinTable } = attribute;
133
- const { joinColumn, inverseJoinColumn } = joinTable;
134
- const all = relIdsToDelete === 'all';
135
-
136
- if (hasOrderColumn(attribute) || hasInverseOrderColumn(attribute)) {
137
- let lastId = 0;
138
- let done = false;
139
- const batchSize = 100;
140
- while (!done) {
141
- const batchToDelete = await createQueryBuilder(joinTable.name, db)
142
- .select(inverseJoinColumn.name)
143
- .where({
144
- [joinColumn.name]: id,
145
- id: { $gt: lastId },
146
- [inverseJoinColumn.name]: { $notIn: relIdsToNotDelete },
147
- ...(all ? {} : { [inverseJoinColumn.name]: { $in: relIdsToDelete } }),
148
- })
149
- .where(joinTable.on || {})
150
- .orderBy('id')
151
- .limit(batchSize)
152
- .transacting(trx)
153
- .execute();
154
- done = batchToDelete.length < batchSize;
155
- lastId = batchToDelete[batchToDelete.length - 1]?.id || 0;
156
-
157
- const batchIds = map(inverseJoinColumn.name, batchToDelete);
158
-
159
- await createQueryBuilder(joinTable.name, db)
160
- .delete()
161
- .where({
162
- [joinColumn.name]: id,
163
- [inverseJoinColumn.name]: { $in: batchIds },
164
- })
165
- .where(joinTable.on || {})
166
- .transacting(trx)
167
- .execute();
168
-
169
- await cleanOrderColumns({ attribute, db, id, inverseRelIds: batchIds, transaction: trx });
170
- }
171
- } else {
172
- await createQueryBuilder(joinTable.name, db)
173
- .delete()
174
- .where({
175
- [joinColumn.name]: id,
176
- [inverseJoinColumn.name]: { $notIn: relIdsToNotDelete },
177
- ...(all ? {} : { [inverseJoinColumn.name]: { $in: relIdsToDelete } }),
178
- })
179
- .where(joinTable.on || {})
180
- .transacting(trx)
181
- .execute();
182
- }
183
- };
184
-
185
- /**
186
- * Clean the order columns by ensuring the order value are continuous (ex: 1, 2, 3 and not 1, 5, 10)
187
- * @param {Object} params
188
- * @param {string} params.id - entity id for which the clean will be done
189
- * @param {string} params.attribute - attribute of the relation
190
- * @param {string} params.db - database instance
191
- * @param {string} params.inverseRelIds - entity ids of the inverse side for which the clean will be done
192
- */
193
- const cleanOrderColumns = async ({ id, attribute, db, inverseRelIds, transaction: trx }) => {
194
- if (
195
- !(hasOrderColumn(attribute) && id) &&
196
- !(hasInverseOrderColumn(attribute) && !isEmpty(inverseRelIds))
197
- ) {
198
- return;
199
- }
200
-
201
- // Handle databases that don't support window function ROW_NUMBER (here it's MySQL 5)
202
- if (!strapi.db.dialect.supportsWindowFunctions()) {
203
- await cleanOrderColumnsForOldDatabases({ id, attribute, db, inverseRelIds, transaction: trx });
204
- return;
205
- }
206
-
207
- const { joinTable } = attribute;
208
- const { joinColumn, inverseJoinColumn, orderColumnName, inverseOrderColumnName } = joinTable;
209
-
210
- /**
211
- UPDATE :joinTable: as a,
212
- (
213
- SELECT
214
- id,
215
- ROW_NUMBER() OVER ( PARTITION BY :joinColumn: ORDER BY :orderColumn:) AS src_order,
216
- FROM :joinTable:
217
- WHERE :joinColumn: = :id
218
- ) AS b
219
- SET :orderColumn: = b.src_order
220
- WHERE b.id = a.id;
221
- */
222
- const updateOrderColumn = async () => {
223
- if (!hasOrderColumn(attribute) || !id) return;
224
-
225
- const selectRowsToOrder = (joinTableName) =>
226
- db
227
- .connection(joinTableName)
228
- .select('id')
229
- .rowNumber('src_order', orderColumnName, joinColumn.name)
230
- .where(joinColumn.name, id)
231
- .toSQL();
232
-
233
- switch (strapi.db.dialect.client) {
234
- case 'mysql': {
235
- // Here it's MariaDB and MySQL 8
236
- const select = selectRowsToOrder(joinTable.name);
237
-
238
- await db
239
- .getConnection()
240
- .raw(
241
- `UPDATE ?? as a, ( ${select.sql} ) AS b
242
- SET ?? = b.src_order
243
- WHERE b.id = a.id`,
244
- [joinTable.name, ...select.bindings, orderColumnName]
245
- )
246
- .transacting(trx);
247
-
248
- break;
249
- }
250
- default: {
251
- const joinTableName = addSchema(joinTable.name);
252
- const select = selectRowsToOrder(joinTableName);
253
-
254
- // raw query as knex doesn't allow updating from a subquery
255
- await db.connection
256
- .raw(
257
- `UPDATE ?? as a
258
- SET ?? = b.src_order
259
- FROM ( ${select.sql} ) AS b
260
- WHERE b.id = a.id`,
261
- [joinTableName, orderColumnName, ...select.bindings]
262
- )
263
- .transacting(trx);
264
- }
265
- }
266
- };
267
-
268
- /**
269
- UPDATE :joinTable: as a,
270
- (
271
- SELECT
272
- id,
273
- ROW_NUMBER() OVER ( PARTITION BY :inverseJoinColumn: ORDER BY :inverseOrderColumn:) AS inv_order
274
- FROM :joinTable:
275
- WHERE :inverseJoinColumn: IN (:inverseRelIds)
276
- ) AS b
277
- SET :inverseOrderColumn: = b.inv_order
278
- WHERE b.id = a.id;
279
- */
280
- const updateInverseOrderColumn = async () => {
281
- if (!hasInverseOrderColumn(attribute) || isEmpty(inverseRelIds)) return;
282
-
283
- const selectRowsToOrder = (joinTableName) =>
284
- db
285
- .connection(joinTableName)
286
- .select('id')
287
- .rowNumber('inv_order', inverseOrderColumnName, inverseJoinColumn.name)
288
- .where(inverseJoinColumn.name, 'in', inverseRelIds)
289
- .toSQL();
290
-
291
- switch (strapi.db.dialect.client) {
292
- case 'mysql': {
293
- // Here it's MariaDB and MySQL 8
294
- const select = selectRowsToOrder(joinTable.name);
295
-
296
- await db
297
- .getConnection()
298
- .raw(
299
- `UPDATE ?? as a, ( ${select.sql} ) AS b
300
- SET ?? = b.inv_order
301
- WHERE b.id = a.id`,
302
- [joinTable.name, ...select.bindings, inverseOrderColumnName]
303
- )
304
- .transacting(trx);
305
- break;
306
- }
307
- default: {
308
- const joinTableName = addSchema(joinTable.name);
309
- const select = selectRowsToOrder(joinTableName);
310
-
311
- // raw query as knex doesn't allow updating from a subquery
312
- await db.connection
313
- .raw(
314
- `UPDATE ?? as a
315
- SET ?? = b.inv_order
316
- FROM ( ${select.sql} ) AS b
317
- WHERE b.id = a.id`,
318
- [joinTableName, inverseOrderColumnName, ...select.bindings]
319
- )
320
- .transacting(trx);
321
- }
322
- }
323
- };
324
-
325
- return Promise.all([updateOrderColumn(), updateInverseOrderColumn()]);
326
- };
327
-
328
- /*
329
- * Ensure that orders are following a 1, 2, 3 sequence, without gap.
330
- * The use of a session variable instead of a window function makes the query compatible with MySQL 5
331
- */
332
- const cleanOrderColumnsForOldDatabases = async ({
333
- id,
334
- attribute,
335
- db,
336
- inverseRelIds,
337
- transaction: trx,
338
- }) => {
339
- const { joinTable } = attribute;
340
- const { joinColumn, inverseJoinColumn, orderColumnName, inverseOrderColumnName } = joinTable;
341
-
342
- const randomSuffix = `${new Date().valueOf()}_${randomBytes(16).toString('hex')}`;
343
-
344
- if (hasOrderColumn(attribute) && id) {
345
- // raw query as knex doesn't allow updating from a subquery
346
- // https://github.com/knex/knex/issues/2504
347
- const orderVar = `order_${randomSuffix}`;
348
- await db.connection.raw(`SET @${orderVar} = 0;`).transacting(trx);
349
- await db.connection
350
- .raw(
351
- `UPDATE :joinTableName: as a, (
352
- SELECT id, (@${orderVar}:=@${orderVar} + 1) AS src_order
353
- FROM :joinTableName:
354
- WHERE :joinColumnName: = :id
355
- ORDER BY :orderColumnName:
356
- ) AS b
357
- SET :orderColumnName: = b.src_order
358
- WHERE a.id = b.id
359
- AND a.:joinColumnName: = :id`,
360
- {
361
- joinTableName: joinTable.name,
362
- orderColumnName,
363
- joinColumnName: joinColumn.name,
364
- id,
365
- }
366
- )
367
- .transacting(trx);
368
- }
369
-
370
- if (hasInverseOrderColumn(attribute) && !isEmpty(inverseRelIds)) {
371
- const orderVar = `order_${randomSuffix}`;
372
- const columnVar = `col_${randomSuffix}`;
373
- await db.connection.raw(`SET @${orderVar} = 0;`).transacting(trx);
374
- await db.connection
375
- .raw(
376
- `UPDATE ?? as a, (
377
- SELECT
378
- id,
379
- @${orderVar}:=CASE WHEN @${columnVar} = ?? THEN @${orderVar} + 1 ELSE 1 END AS inv_order,
380
- @${columnVar}:=?? ??
381
- FROM ?? a
382
- WHERE ?? IN(${inverseRelIds.map(() => '?').join(', ')})
383
- ORDER BY ??, ??
384
- ) AS b
385
- SET ?? = b.inv_order
386
- WHERE a.id = b.id
387
- AND a.?? IN(${inverseRelIds.map(() => '?').join(', ')})`,
388
- [
389
- joinTable.name,
390
- inverseJoinColumn.name,
391
- inverseJoinColumn.name,
392
- inverseJoinColumn.name,
393
- joinTable.name,
394
- inverseJoinColumn.name,
395
- ...inverseRelIds,
396
- inverseJoinColumn.name,
397
- joinColumn.name,
398
- inverseOrderColumnName,
399
- inverseJoinColumn.name,
400
- ...inverseRelIds,
401
- ]
402
- )
403
- .transacting(trx);
404
- }
405
- };
406
-
407
- /**
408
- * Use this when a relation is added or removed and its inverse order column
409
- * needs to be re-calculated
410
- *
411
- * Example: In this following table
412
- *
413
- * | joinColumn | inverseJoinColumn | order | inverseOrder |
414
- * | --------------- | -------- | ----------- | ------------------ |
415
- * | 1 | 1 | 1 | 1 |
416
- * | 2 | 1 | 3 | 2 |
417
- * | 2 | 2 | 3 | 1 |
418
- *
419
- * You add a new relation { joinColumn: 1, inverseJoinColumn: 2 }
420
- *
421
- * | joinColumn | inverseJoinColumn | order | inverseOrder |
422
- * | --------------- | -------- | ----------- | ------------------ |
423
- * | 1 | 1 | 1 | 1 |
424
- * | 1 | 2 | 2 | 1 | <- inverseOrder should be 2
425
- * | 2 | 1 | 3 | 2 |
426
- * | 2 | 2 | 3 | 1 |
427
- *
428
- * This function would make such update, so all inverse order columns related
429
- * to the given id (1 in this example) are following a 1, 2, 3 sequence, without gap.
430
- *
431
- * @param {Object} params
432
- * @param {string} params.id - entity id to find which inverse order column to clean
433
- * @param {Object} params.attribute - attribute of the relation
434
- * @param {Object} params.trx - knex transaction
435
- *
436
- */
437
-
438
- const cleanInverseOrderColumn = async ({ id, attribute, trx }) => {
439
- const con = strapi.db.connection;
440
- const { joinTable } = attribute;
441
- const { joinColumn, inverseJoinColumn, inverseOrderColumnName } = joinTable;
442
-
443
- switch (strapi.db.dialect.client) {
444
- /*
445
- UPDATE `:joinTableName` AS `t1`
446
- JOIN (
447
- SELECT
448
- `inverseJoinColumn`,
449
- MAX(`:inverseOrderColumnName`) AS `max_inv_order`
450
- FROM `:joinTableName`
451
- GROUP BY `:inverseJoinColumn`
452
- ) AS `t2`
453
- ON `t1`.`:inverseJoinColumn` = `t2`.`:inverseJoinColumn`
454
- SET `t1`.`:inverseOrderColumnNAme` = `t2`.`max_inv_order` + 1
455
- WHERE `t1`.`:joinColumnName` = :id;
456
- */
457
- case 'mysql': {
458
- // Group by the inverse join column and get the max value of the inverse order column
459
- const subQuery = con(joinTable.name)
460
- .select(inverseJoinColumn.name)
461
- .max(inverseOrderColumnName, { as: 'max_inv_order' })
462
- .groupBy(inverseJoinColumn.name)
463
- .as('t2');
464
-
465
- // Update ids with the new inverse order
466
- await con(`${joinTable.name} as t1`)
467
- .join(subQuery, `t1.${inverseJoinColumn.name}`, '=', `t2.${inverseJoinColumn.name}`)
468
- .where(joinColumn.name, id)
469
- .update({
470
- [inverseOrderColumnName]: con.raw('t2.max_inv_order + 1'),
471
- })
472
- .transacting(trx);
473
- break;
474
- }
475
- default: {
476
- /*
477
- UPDATE `:joinTableName` as `t1`
478
- SET `:inverseOrderColumnName` = (
479
- SELECT max(`:inverseOrderColumnName`) + 1
480
- FROM `:joinTableName` as `t2`
481
- WHERE t2.:inverseJoinColumn = t1.:inverseJoinColumn
482
- )
483
- WHERE `t1`.`:joinColumnName` = :id
484
- */
485
- // New inverse order will be the max value + 1
486
- const selectMaxInverseOrder = con.raw(`max(${inverseOrderColumnName}) + 1`);
487
-
488
- const subQuery = con(`${joinTable.name} as t2`)
489
- .select(selectMaxInverseOrder)
490
- .whereRaw(`t2.${inverseJoinColumn.name} = t1.${inverseJoinColumn.name}`);
491
-
492
- await con(`${joinTable.name} as t1`)
493
- .where(`t1.${joinColumn.name}`, id)
494
- .update({ [inverseOrderColumnName]: subQuery })
495
- .transacting(trx);
496
- }
497
- }
498
- };
499
-
500
- module.exports = {
501
- deletePreviousOneToAnyRelations,
502
- deletePreviousAnyToOneRelations,
503
- deleteRelations,
504
- cleanOrderColumns,
505
- cleanInverseOrderColumn,
506
- };
@@ -1,76 +0,0 @@
1
- 'use strict';
2
-
3
- const { cleanInverseOrderColumn } = require('../../regular-relations');
4
-
5
- const replaceRegularRelations = async ({
6
- targetId,
7
- sourceId,
8
- attribute,
9
- omitIds,
10
- transaction: trx,
11
- }) => {
12
- const { joinTable } = attribute;
13
- const { joinColumn, inverseJoinColumn } = joinTable;
14
-
15
- // We are effectively stealing the relation from the cloned entity
16
- await strapi.db.entityManager
17
- .createQueryBuilder(joinTable.name)
18
- .update({ [joinColumn.name]: targetId })
19
- .where({ [joinColumn.name]: sourceId })
20
- .where({ $not: { [inverseJoinColumn.name]: omitIds } })
21
- .onConflict([joinColumn.name, inverseJoinColumn.name])
22
- .ignore()
23
- .transacting(trx)
24
- .execute();
25
- };
26
-
27
- const cloneRegularRelations = async ({ targetId, sourceId, attribute, transaction: trx }) => {
28
- const { joinTable } = attribute;
29
- const { joinColumn, inverseJoinColumn, orderColumnName, inverseOrderColumnName } = joinTable;
30
- const connection = strapi.db.getConnection();
31
-
32
- // Get the columns to select
33
- const columns = [joinColumn.name, inverseJoinColumn.name];
34
- if (orderColumnName) columns.push(orderColumnName);
35
- if (inverseOrderColumnName) columns.push(inverseOrderColumnName);
36
- if (joinTable.on) columns.push(...Object.keys(joinTable.on));
37
-
38
- const selectStatement = connection
39
- .select(
40
- // Override joinColumn with the new id
41
- { [joinColumn.name]: targetId },
42
- // The rest of columns will be the same
43
- ...columns.slice(1)
44
- )
45
- .where(joinColumn.name, sourceId)
46
- .from(joinTable.name)
47
- .toSQL();
48
-
49
- // Insert the clone relations
50
- await strapi.db.entityManager
51
- .createQueryBuilder(joinTable.name)
52
- .insert(
53
- strapi.db.connection.raw(
54
- `(${columns.join(',')}) ${selectStatement.sql}`,
55
- selectStatement.bindings
56
- )
57
- )
58
- .onConflict([joinColumn.name, inverseJoinColumn.name])
59
- .ignore()
60
- .transacting(trx)
61
- .execute();
62
-
63
- // Clean the inverse order column
64
- if (inverseOrderColumnName) {
65
- await cleanInverseOrderColumn({
66
- id: targetId,
67
- attribute,
68
- trx,
69
- });
70
- }
71
- };
72
-
73
- module.exports = {
74
- replaceRegularRelations,
75
- cloneRegularRelations,
76
- };