@strapi/database 5.12.1 → 5.12.3

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 (321) hide show
  1. package/dist/connection.js +43 -0
  2. package/dist/connection.js.map +1 -0
  3. package/dist/connection.mjs +41 -0
  4. package/dist/connection.mjs.map +1 -0
  5. package/dist/dialects/dialect.js +54 -0
  6. package/dist/dialects/dialect.js.map +1 -0
  7. package/dist/dialects/dialect.mjs +52 -0
  8. package/dist/dialects/dialect.mjs.map +1 -0
  9. package/dist/dialects/index.js +44 -0
  10. package/dist/dialects/index.js.map +1 -0
  11. package/dist/dialects/index.mjs +42 -0
  12. package/dist/dialects/index.mjs.map +1 -0
  13. package/dist/dialects/mysql/constants.js +8 -0
  14. package/dist/dialects/mysql/constants.js.map +1 -0
  15. package/dist/dialects/mysql/constants.mjs +5 -0
  16. package/dist/dialects/mysql/constants.mjs.map +1 -0
  17. package/dist/dialects/mysql/database-inspector.js +35 -0
  18. package/dist/dialects/mysql/database-inspector.js.map +1 -0
  19. package/dist/dialects/mysql/database-inspector.mjs +33 -0
  20. package/dist/dialects/mysql/database-inspector.mjs.map +1 -0
  21. package/dist/dialects/mysql/index.js +75 -0
  22. package/dist/dialects/mysql/index.js.map +1 -0
  23. package/dist/dialects/mysql/index.mjs +73 -0
  24. package/dist/dialects/mysql/index.mjs.map +1 -0
  25. package/dist/dialects/mysql/schema-inspector.js +297 -0
  26. package/dist/dialects/mysql/schema-inspector.js.map +1 -0
  27. package/dist/dialects/mysql/schema-inspector.mjs +295 -0
  28. package/dist/dialects/mysql/schema-inspector.mjs.map +1 -0
  29. package/dist/dialects/postgresql/index.js +62 -0
  30. package/dist/dialects/postgresql/index.js.map +1 -0
  31. package/dist/dialects/postgresql/index.mjs +60 -0
  32. package/dist/dialects/postgresql/index.mjs.map +1 -0
  33. package/dist/dialects/postgresql/schema-inspector.js +316 -0
  34. package/dist/dialects/postgresql/schema-inspector.js.map +1 -0
  35. package/dist/dialects/postgresql/schema-inspector.mjs +314 -0
  36. package/dist/dialects/postgresql/schema-inspector.mjs.map +1 -0
  37. package/dist/dialects/sqlite/index.js +82 -0
  38. package/dist/dialects/sqlite/index.js.map +1 -0
  39. package/dist/dialects/sqlite/index.mjs +80 -0
  40. package/dist/dialects/sqlite/index.mjs.map +1 -0
  41. package/dist/dialects/sqlite/schema-inspector.js +211 -0
  42. package/dist/dialects/sqlite/schema-inspector.js.map +1 -0
  43. package/dist/dialects/sqlite/schema-inspector.mjs +209 -0
  44. package/dist/dialects/sqlite/schema-inspector.mjs.map +1 -0
  45. package/dist/entity-manager/entity-repository.js +139 -0
  46. package/dist/entity-manager/entity-repository.js.map +1 -0
  47. package/dist/entity-manager/entity-repository.mjs +137 -0
  48. package/dist/entity-manager/entity-repository.mjs.map +1 -0
  49. package/dist/entity-manager/index.js +1186 -0
  50. package/dist/entity-manager/index.js.map +1 -0
  51. package/dist/entity-manager/index.mjs +1184 -0
  52. package/dist/entity-manager/index.mjs.map +1 -0
  53. package/dist/entity-manager/morph-relations.js +73 -0
  54. package/dist/entity-manager/morph-relations.js.map +1 -0
  55. package/dist/entity-manager/morph-relations.mjs +69 -0
  56. package/dist/entity-manager/morph-relations.mjs.map +1 -0
  57. package/dist/entity-manager/regular-relations.js +247 -0
  58. package/dist/entity-manager/regular-relations.js.map +1 -0
  59. package/dist/entity-manager/regular-relations.mjs +242 -0
  60. package/dist/entity-manager/regular-relations.mjs.map +1 -0
  61. package/dist/entity-manager/relations-orderer.js +221 -0
  62. package/dist/entity-manager/relations-orderer.js.map +1 -0
  63. package/dist/entity-manager/relations-orderer.mjs +218 -0
  64. package/dist/entity-manager/relations-orderer.mjs.map +1 -0
  65. package/dist/errors/database.js +13 -0
  66. package/dist/errors/database.js.map +1 -0
  67. package/dist/errors/database.mjs +11 -0
  68. package/dist/errors/database.mjs.map +1 -0
  69. package/dist/errors/index.js +18 -0
  70. package/dist/errors/index.js.map +1 -0
  71. package/dist/errors/index.mjs +7 -0
  72. package/dist/errors/index.mjs.map +1 -0
  73. package/dist/errors/invalid-date.js +13 -0
  74. package/dist/errors/invalid-date.js.map +1 -0
  75. package/dist/errors/invalid-date.mjs +11 -0
  76. package/dist/errors/invalid-date.mjs.map +1 -0
  77. package/dist/errors/invalid-datetime.js +13 -0
  78. package/dist/errors/invalid-datetime.js.map +1 -0
  79. package/dist/errors/invalid-datetime.mjs +11 -0
  80. package/dist/errors/invalid-datetime.mjs.map +1 -0
  81. package/dist/errors/invalid-relation.js +13 -0
  82. package/dist/errors/invalid-relation.js.map +1 -0
  83. package/dist/errors/invalid-relation.mjs +11 -0
  84. package/dist/errors/invalid-relation.mjs.map +1 -0
  85. package/dist/errors/invalid-time.js +13 -0
  86. package/dist/errors/invalid-time.js.map +1 -0
  87. package/dist/errors/invalid-time.mjs +11 -0
  88. package/dist/errors/invalid-time.mjs.map +1 -0
  89. package/dist/errors/not-null.js +17 -0
  90. package/dist/errors/not-null.js.map +1 -0
  91. package/dist/errors/not-null.mjs +15 -0
  92. package/dist/errors/not-null.mjs.map +1 -0
  93. package/dist/fields/biginteger.js +9 -0
  94. package/dist/fields/biginteger.js.map +1 -0
  95. package/dist/fields/biginteger.mjs +7 -0
  96. package/dist/fields/biginteger.mjs.map +1 -0
  97. package/dist/fields/boolean.js +48 -0
  98. package/dist/fields/boolean.js.map +1 -0
  99. package/dist/fields/boolean.mjs +46 -0
  100. package/dist/fields/boolean.mjs.map +1 -0
  101. package/dist/fields/date.js +16 -0
  102. package/dist/fields/date.js.map +1 -0
  103. package/dist/fields/date.mjs +14 -0
  104. package/dist/fields/date.mjs.map +1 -0
  105. package/dist/fields/datetime.js +37 -0
  106. package/dist/fields/datetime.js.map +1 -0
  107. package/dist/fields/datetime.mjs +16 -0
  108. package/dist/fields/datetime.mjs.map +1 -0
  109. package/dist/fields/field.js +16 -0
  110. package/dist/fields/field.js.map +1 -0
  111. package/dist/fields/field.mjs +14 -0
  112. package/dist/fields/field.mjs.map +1 -0
  113. package/dist/fields/index.js +45 -0
  114. package/dist/fields/index.js.map +1 -0
  115. package/dist/fields/index.mjs +43 -0
  116. package/dist/fields/index.mjs.map +1 -0
  117. package/dist/fields/json.js +36 -0
  118. package/dist/fields/json.js.map +1 -0
  119. package/dist/fields/json.mjs +34 -0
  120. package/dist/fields/json.mjs.map +1 -0
  121. package/dist/fields/number.js +20 -0
  122. package/dist/fields/number.js.map +1 -0
  123. package/dist/fields/number.mjs +18 -0
  124. package/dist/fields/number.mjs.map +1 -0
  125. package/dist/fields/shared/parsers.js +91 -0
  126. package/dist/fields/shared/parsers.js.map +1 -0
  127. package/dist/fields/shared/parsers.mjs +68 -0
  128. package/dist/fields/shared/parsers.mjs.map +1 -0
  129. package/dist/fields/string.js +16 -0
  130. package/dist/fields/string.js.map +1 -0
  131. package/dist/fields/string.mjs +14 -0
  132. package/dist/fields/string.mjs.map +1 -0
  133. package/dist/fields/time.js +17 -0
  134. package/dist/fields/time.js.map +1 -0
  135. package/dist/fields/time.mjs +15 -0
  136. package/dist/fields/time.mjs.map +1 -0
  137. package/dist/fields/timestamp.js +37 -0
  138. package/dist/fields/timestamp.js.map +1 -0
  139. package/dist/fields/timestamp.mjs +16 -0
  140. package/dist/fields/timestamp.mjs.map +1 -0
  141. package/dist/index.js +33 -8569
  142. package/dist/index.js.map +1 -1
  143. package/dist/index.mjs +16 -8532
  144. package/dist/index.mjs.map +1 -1
  145. package/dist/lifecycles/index.js +73 -0
  146. package/dist/lifecycles/index.js.map +1 -0
  147. package/dist/lifecycles/index.mjs +71 -0
  148. package/dist/lifecycles/index.mjs.map +1 -0
  149. package/dist/lifecycles/subscribers/index.js +10 -0
  150. package/dist/lifecycles/subscribers/index.js.map +1 -0
  151. package/dist/lifecycles/subscribers/index.mjs +8 -0
  152. package/dist/lifecycles/subscribers/index.mjs.map +1 -0
  153. package/dist/lifecycles/subscribers/models-lifecycles.js +13 -0
  154. package/dist/lifecycles/subscribers/models-lifecycles.js.map +1 -0
  155. package/dist/lifecycles/subscribers/models-lifecycles.mjs +11 -0
  156. package/dist/lifecycles/subscribers/models-lifecycles.mjs.map +1 -0
  157. package/dist/lifecycles/subscribers/timestamps.js +55 -0
  158. package/dist/lifecycles/subscribers/timestamps.js.map +1 -0
  159. package/dist/lifecycles/subscribers/timestamps.mjs +53 -0
  160. package/dist/lifecycles/subscribers/timestamps.mjs.map +1 -0
  161. package/dist/metadata/index.js +24 -0
  162. package/dist/metadata/index.js.map +1 -0
  163. package/dist/metadata/index.mjs +16 -0
  164. package/dist/metadata/index.mjs.map +1 -0
  165. package/dist/metadata/metadata.js +100 -0
  166. package/dist/metadata/metadata.js.map +1 -0
  167. package/dist/metadata/metadata.mjs +98 -0
  168. package/dist/metadata/metadata.mjs.map +1 -0
  169. package/dist/metadata/relations.js +545 -0
  170. package/dist/metadata/relations.js.map +1 -0
  171. package/dist/metadata/relations.mjs +536 -0
  172. package/dist/metadata/relations.mjs.map +1 -0
  173. package/dist/migrations/common.js +8 -0
  174. package/dist/migrations/common.js.map +1 -0
  175. package/dist/migrations/common.mjs +6 -0
  176. package/dist/migrations/common.mjs.map +1 -0
  177. package/dist/migrations/index.js +39 -0
  178. package/dist/migrations/index.js.map +1 -0
  179. package/dist/migrations/index.mjs +37 -0
  180. package/dist/migrations/index.mjs.map +1 -0
  181. package/dist/migrations/internal-migrations/5.0.0-01-convert-identifiers-long-than-max-length.js +179 -0
  182. package/dist/migrations/internal-migrations/5.0.0-01-convert-identifiers-long-than-max-length.js.map +1 -0
  183. package/dist/migrations/internal-migrations/5.0.0-01-convert-identifiers-long-than-max-length.mjs +177 -0
  184. package/dist/migrations/internal-migrations/5.0.0-01-convert-identifiers-long-than-max-length.mjs.map +1 -0
  185. package/dist/migrations/internal-migrations/5.0.0-02-document-id.js +125 -0
  186. package/dist/migrations/internal-migrations/5.0.0-02-document-id.js.map +1 -0
  187. package/dist/migrations/internal-migrations/5.0.0-02-document-id.mjs +123 -0
  188. package/dist/migrations/internal-migrations/5.0.0-02-document-id.mjs.map +1 -0
  189. package/dist/migrations/internal-migrations/5.0.0-03-locale.js +41 -0
  190. package/dist/migrations/internal-migrations/5.0.0-03-locale.js.map +1 -0
  191. package/dist/migrations/internal-migrations/5.0.0-03-locale.mjs +39 -0
  192. package/dist/migrations/internal-migrations/5.0.0-03-locale.mjs.map +1 -0
  193. package/dist/migrations/internal-migrations/5.0.0-04-published-at.js +45 -0
  194. package/dist/migrations/internal-migrations/5.0.0-04-published-at.js.map +1 -0
  195. package/dist/migrations/internal-migrations/5.0.0-04-published-at.mjs +43 -0
  196. package/dist/migrations/internal-migrations/5.0.0-04-published-at.mjs.map +1 -0
  197. package/dist/migrations/internal-migrations/5.0.0-05-drop-slug-unique-index.js +43 -0
  198. package/dist/migrations/internal-migrations/5.0.0-05-drop-slug-unique-index.js.map +1 -0
  199. package/dist/migrations/internal-migrations/5.0.0-05-drop-slug-unique-index.mjs +41 -0
  200. package/dist/migrations/internal-migrations/5.0.0-05-drop-slug-unique-index.mjs.map +1 -0
  201. package/dist/migrations/internal-migrations/index.js +26 -0
  202. package/dist/migrations/internal-migrations/index.js.map +1 -0
  203. package/dist/migrations/internal-migrations/index.mjs +24 -0
  204. package/dist/migrations/internal-migrations/index.mjs.map +1 -0
  205. package/dist/migrations/internal.js +63 -0
  206. package/dist/migrations/internal.js.map +1 -0
  207. package/dist/migrations/internal.mjs +61 -0
  208. package/dist/migrations/internal.mjs.map +1 -0
  209. package/dist/migrations/logger.js +24 -0
  210. package/dist/migrations/logger.js.map +1 -0
  211. package/dist/migrations/logger.mjs +22 -0
  212. package/dist/migrations/logger.mjs.map +1 -0
  213. package/dist/migrations/storage.js +39 -0
  214. package/dist/migrations/storage.js.map +1 -0
  215. package/dist/migrations/storage.mjs +37 -0
  216. package/dist/migrations/storage.mjs.map +1 -0
  217. package/dist/migrations/users.js +87 -0
  218. package/dist/migrations/users.js.map +1 -0
  219. package/dist/migrations/users.mjs +85 -0
  220. package/dist/migrations/users.mjs.map +1 -0
  221. package/dist/query/helpers/join.js +127 -0
  222. package/dist/query/helpers/join.js.map +1 -0
  223. package/dist/query/helpers/join.mjs +122 -0
  224. package/dist/query/helpers/join.mjs.map +1 -0
  225. package/dist/query/helpers/order-by.js +167 -0
  226. package/dist/query/helpers/order-by.js.map +1 -0
  227. package/dist/query/helpers/order-by.mjs +163 -0
  228. package/dist/query/helpers/order-by.mjs.map +1 -0
  229. package/dist/query/helpers/populate/apply.js +592 -0
  230. package/dist/query/helpers/populate/apply.js.map +1 -0
  231. package/dist/query/helpers/populate/apply.mjs +590 -0
  232. package/dist/query/helpers/populate/apply.mjs.map +1 -0
  233. package/dist/query/helpers/populate/process.js +92 -0
  234. package/dist/query/helpers/populate/process.js.map +1 -0
  235. package/dist/query/helpers/populate/process.mjs +90 -0
  236. package/dist/query/helpers/populate/process.mjs.map +1 -0
  237. package/dist/query/helpers/search.js +67 -0
  238. package/dist/query/helpers/search.js.map +1 -0
  239. package/dist/query/helpers/search.mjs +65 -0
  240. package/dist/query/helpers/search.mjs.map +1 -0
  241. package/dist/query/helpers/streams/readable.js +131 -0
  242. package/dist/query/helpers/streams/readable.js.map +1 -0
  243. package/dist/query/helpers/streams/readable.mjs +129 -0
  244. package/dist/query/helpers/streams/readable.mjs.map +1 -0
  245. package/dist/query/helpers/transform.js +77 -0
  246. package/dist/query/helpers/transform.js.map +1 -0
  247. package/dist/query/helpers/transform.mjs +73 -0
  248. package/dist/query/helpers/transform.mjs.map +1 -0
  249. package/dist/query/helpers/where.js +372 -0
  250. package/dist/query/helpers/where.js.map +1 -0
  251. package/dist/query/helpers/where.mjs +369 -0
  252. package/dist/query/helpers/where.mjs.map +1 -0
  253. package/dist/query/query-builder.js +507 -0
  254. package/dist/query/query-builder.js.map +1 -0
  255. package/dist/query/query-builder.mjs +505 -0
  256. package/dist/query/query-builder.mjs.map +1 -0
  257. package/dist/repairs/index.js +13 -0
  258. package/dist/repairs/index.js.map +1 -0
  259. package/dist/repairs/index.mjs +11 -0
  260. package/dist/repairs/index.mjs.map +1 -0
  261. package/dist/repairs/operations/remove-orphan-morph-types.js +54 -0
  262. package/dist/repairs/operations/remove-orphan-morph-types.js.map +1 -0
  263. package/dist/repairs/operations/remove-orphan-morph-types.mjs +52 -0
  264. package/dist/repairs/operations/remove-orphan-morph-types.mjs.map +1 -0
  265. package/dist/schema/builder.js +354 -0
  266. package/dist/schema/builder.js.map +1 -0
  267. package/dist/schema/builder.mjs +352 -0
  268. package/dist/schema/builder.mjs.map +1 -0
  269. package/dist/schema/diff.js +379 -0
  270. package/dist/schema/diff.js.map +1 -0
  271. package/dist/schema/diff.mjs +377 -0
  272. package/dist/schema/diff.mjs.map +1 -0
  273. package/dist/schema/index.js +93 -0
  274. package/dist/schema/index.js.map +1 -0
  275. package/dist/schema/index.mjs +91 -0
  276. package/dist/schema/index.mjs.map +1 -0
  277. package/dist/schema/schema.js +266 -0
  278. package/dist/schema/schema.js.map +1 -0
  279. package/dist/schema/schema.mjs +264 -0
  280. package/dist/schema/schema.mjs.map +1 -0
  281. package/dist/schema/storage.js +58 -0
  282. package/dist/schema/storage.js.map +1 -0
  283. package/dist/schema/storage.mjs +56 -0
  284. package/dist/schema/storage.mjs.map +1 -0
  285. package/dist/transaction-context.js +65 -0
  286. package/dist/transaction-context.js.map +1 -0
  287. package/dist/transaction-context.mjs +63 -0
  288. package/dist/transaction-context.mjs.map +1 -0
  289. package/dist/utils/async-curry.js +19 -0
  290. package/dist/utils/async-curry.js.map +1 -0
  291. package/dist/utils/async-curry.mjs +17 -0
  292. package/dist/utils/async-curry.mjs.map +1 -0
  293. package/dist/utils/identifiers/hash.js +30 -0
  294. package/dist/utils/identifiers/hash.js.map +1 -0
  295. package/dist/utils/identifiers/hash.mjs +28 -0
  296. package/dist/utils/identifiers/hash.mjs.map +1 -0
  297. package/dist/utils/identifiers/index.js +414 -0
  298. package/dist/utils/identifiers/index.js.map +1 -0
  299. package/dist/utils/identifiers/index.mjs +411 -0
  300. package/dist/utils/identifiers/index.mjs.map +1 -0
  301. package/dist/utils/knex.js +21 -0
  302. package/dist/utils/knex.js.map +1 -0
  303. package/dist/utils/knex.mjs +18 -0
  304. package/dist/utils/knex.mjs.map +1 -0
  305. package/dist/utils/types.js +51 -0
  306. package/dist/utils/types.js.map +1 -0
  307. package/dist/utils/types.mjs +44 -0
  308. package/dist/utils/types.mjs.map +1 -0
  309. package/dist/validations/index.js +12 -0
  310. package/dist/validations/index.js.map +1 -0
  311. package/dist/validations/index.mjs +10 -0
  312. package/dist/validations/index.mjs.map +1 -0
  313. package/dist/validations/relations/bidirectional.js +64 -0
  314. package/dist/validations/relations/bidirectional.js.map +1 -0
  315. package/dist/validations/relations/bidirectional.mjs +62 -0
  316. package/dist/validations/relations/bidirectional.mjs.map +1 -0
  317. package/dist/validations/relations/index.js +13 -0
  318. package/dist/validations/relations/index.js.map +1 -0
  319. package/dist/validations/relations/index.mjs +11 -0
  320. package/dist/validations/relations/index.mjs.map +1 -0
  321. package/package.json +4 -4
@@ -0,0 +1,411 @@
1
+ import _, { snakeCase, isInteger, partition, sumBy } from 'lodash/fp';
2
+ import { createHash } from './hash.mjs';
3
+
4
+ /**
5
+ * This file contains utility functions for generating names used in the database.
6
+ * These names include table names, column names, join table names, index names, and more.
7
+ * The generated names can be customized with prefixes, suffixes, and maximum length.
8
+ * These utility functions are used throughout the codebase to ensure consistent and standardized naming conventions in the database.
9
+ *
10
+ * The reason for checking maxLength for suffixes and prefixes and using the long ones from Strapi 4 is so that we always
11
+ * have access to the full length names, in particular for migration purposes, but also so that (in theory) the feature
12
+ * could be disabled and stay compatible with v4 database structure.
13
+ */ function _class_private_field_loose_base(receiver, privateKey) {
14
+ if (!Object.prototype.hasOwnProperty.call(receiver, privateKey)) {
15
+ throw new TypeError("attempted to use private field on non-instance");
16
+ }
17
+ return receiver;
18
+ }
19
+ var id = 0;
20
+ function _class_private_field_loose_key(name) {
21
+ return "__private_" + id++ + "_" + name;
22
+ }
23
+ const IDENTIFIER_MAX_LENGTH = 55;
24
+ var // Fixed compression map for suffixes and prefixes
25
+ _replacementMap = /*#__PURE__*/ _class_private_field_loose_key("_replacementMap"), _options = /*#__PURE__*/ _class_private_field_loose_key("_options");
26
+ class Identifiers {
27
+ get replacementMap() {
28
+ return _class_private_field_loose_base(this, _replacementMap)[_replacementMap];
29
+ }
30
+ get options() {
31
+ return _class_private_field_loose_base(this, _options)[_options];
32
+ }
33
+ constructor(options){
34
+ Object.defineProperty(this, _replacementMap, {
35
+ writable: true,
36
+ value: void 0
37
+ });
38
+ Object.defineProperty(this, _options, {
39
+ writable: true,
40
+ value: void 0
41
+ });
42
+ this.ID_COLUMN = 'id';
43
+ this.ORDER_COLUMN = 'order';
44
+ this.FIELD_COLUMN = 'field';
45
+ this.HASH_LENGTH = 5;
46
+ this.HASH_SEPARATOR = '' // no separator is needed, we will just attach hash directly to shortened name
47
+ ;
48
+ this.IDENTIFIER_SEPARATOR = '_';
49
+ this.MIN_TOKEN_LENGTH = 3 // the min characters required at the beginning of a name part
50
+ ;
51
+ _class_private_field_loose_base(this, _replacementMap)[_replacementMap] = {
52
+ links: 'lnk',
53
+ order_inv_fk: 'oifk',
54
+ order: 'ord',
55
+ morphs: 'mph',
56
+ index: 'idx',
57
+ inv_fk: 'ifk',
58
+ order_fk: 'ofk',
59
+ id_column_index: 'idix',
60
+ order_index: 'oidx',
61
+ unique: 'uq',
62
+ primary: 'pk'
63
+ };
64
+ this.mapshortNames = (name)=>{
65
+ if (name in this.replacementMap) {
66
+ return this.replacementMap[name];
67
+ }
68
+ return undefined;
69
+ };
70
+ // Generic name handler that must be used by all helper functions
71
+ /**
72
+ * TODO: we should be requiring snake_case inputs for all names here, but we
73
+ * aren't and it will require some refactoring to make it work. Currently if
74
+ * we get names 'myModel' and 'my_model' they would be converted to the same
75
+ * final string my_model which generally works but is not entirely safe
76
+ * */ this.getName = (names, options)=>{
77
+ const tokens = _.castArray(names).map((name)=>{
78
+ return {
79
+ name,
80
+ compressible: true
81
+ };
82
+ });
83
+ if (options?.suffix) {
84
+ tokens.push({
85
+ name: options.suffix,
86
+ compressible: false,
87
+ shortName: this.mapshortNames(options.suffix)
88
+ });
89
+ }
90
+ if (options?.prefix) {
91
+ tokens.unshift({
92
+ name: options.prefix,
93
+ compressible: false,
94
+ shortName: this.mapshortNames(options.prefix)
95
+ });
96
+ }
97
+ return this.getNameFromTokens(tokens);
98
+ };
99
+ /**
100
+ * TABLES
101
+ */ this.getTableName = (name, options)=>{
102
+ return this.getName(name, options);
103
+ };
104
+ this.getJoinTableName = (collectionName, attributeName, options)=>{
105
+ return this.getName([
106
+ collectionName,
107
+ attributeName
108
+ ], {
109
+ suffix: 'links',
110
+ ...options
111
+ });
112
+ };
113
+ this.getMorphTableName = (collectionName, attributeName, options)=>{
114
+ return this.getName([
115
+ snakeCase(collectionName),
116
+ snakeCase(attributeName)
117
+ ], {
118
+ suffix: 'morphs',
119
+ ...options
120
+ });
121
+ };
122
+ /**
123
+ * COLUMNS
124
+ */ this.getColumnName = (attributeName, options)=>{
125
+ return this.getName(attributeName, options);
126
+ };
127
+ this.getJoinColumnAttributeIdName = (attributeName, options)=>{
128
+ return this.getName(attributeName, {
129
+ suffix: 'id',
130
+ ...options
131
+ });
132
+ };
133
+ this.getInverseJoinColumnAttributeIdName = (attributeName, options)=>{
134
+ return this.getName(snakeCase(attributeName), {
135
+ suffix: 'id',
136
+ prefix: 'inv',
137
+ ...options
138
+ });
139
+ };
140
+ this.getOrderColumnName = (singularName, options)=>{
141
+ return this.getName(singularName, {
142
+ suffix: 'order',
143
+ ...options
144
+ });
145
+ };
146
+ this.getInverseOrderColumnName = (singularName, options)=>{
147
+ return this.getName(singularName, {
148
+ suffix: 'order',
149
+ prefix: 'inv',
150
+ ...options
151
+ });
152
+ };
153
+ /**
154
+ * Morph Join Tables
155
+ */ this.getMorphColumnJoinTableIdName = (singularName, options)=>{
156
+ return this.getName(snakeCase(singularName), {
157
+ suffix: 'id',
158
+ ...options
159
+ });
160
+ };
161
+ this.getMorphColumnAttributeIdName = (attributeName, options)=>{
162
+ return this.getName(snakeCase(attributeName), {
163
+ suffix: 'id',
164
+ ...options
165
+ });
166
+ };
167
+ this.getMorphColumnTypeName = (attributeName, options)=>{
168
+ return this.getName(snakeCase(attributeName), {
169
+ suffix: 'type',
170
+ ...options
171
+ });
172
+ };
173
+ /**
174
+ * INDEXES
175
+ * Note that these methods are generally used to reference full table names + attribute(s), which
176
+ * may already be shortened strings rather than individual parts.
177
+ * That is fine and expected to compress the previously incompressible parts of those strings,
178
+ * because in these cases the relevant information is the table name and we can't really do
179
+ * any better; shortening the individual parts again might make it even more confusing.
180
+ *
181
+ * So for example, the fk for the table `mytable_myattr4567d_localizations` will become
182
+ * mytable_myattr4567d_loc63bf2_fk
183
+ */ // base index types
184
+ this.getIndexName = (names, options)=>{
185
+ return this.getName(names, {
186
+ suffix: 'index',
187
+ ...options
188
+ });
189
+ };
190
+ this.getFkIndexName = (names, options)=>{
191
+ return this.getName(names, {
192
+ suffix: 'fk',
193
+ ...options
194
+ });
195
+ };
196
+ this.getUniqueIndexName = (names, options)=>{
197
+ return this.getName(names, {
198
+ suffix: 'unique',
199
+ ...options
200
+ });
201
+ };
202
+ this.getPrimaryIndexName = (names, options)=>{
203
+ return this.getName(names, {
204
+ suffix: 'primary',
205
+ ...options
206
+ });
207
+ };
208
+ // custom index types
209
+ this.getInverseFkIndexName = (names, options)=>{
210
+ return this.getName(names, {
211
+ suffix: 'inv_fk',
212
+ ...options
213
+ });
214
+ };
215
+ this.getOrderFkIndexName = (names, options)=>{
216
+ return this.getName(names, {
217
+ suffix: 'order_fk',
218
+ ...options
219
+ });
220
+ };
221
+ this.getOrderInverseFkIndexName = (names, options)=>{
222
+ return this.getName(names, {
223
+ suffix: 'order_inv_fk',
224
+ ...options
225
+ });
226
+ };
227
+ this.getIdColumnIndexName = (names, options)=>{
228
+ return this.getName(names, {
229
+ suffix: 'id_column_index',
230
+ ...options
231
+ });
232
+ };
233
+ this.getOrderIndexName = (names, options)=>{
234
+ return this.getName(names, {
235
+ suffix: 'order_index',
236
+ ...options
237
+ });
238
+ };
239
+ /**
240
+ * Generates a string with a max length, appending a hash at the end if necessary to keep it unique
241
+ *
242
+ * @example
243
+ * // if we have strings such as "longstring1" and "longstring2" with a max length of 9,
244
+ * // we don't want to end up with "longstrin" and "longstrin"
245
+ * // we want something such as "longs0b23" and "longs953f"
246
+ * const token1 = generateToken("longstring1", 9); // "longs0b23"
247
+ * const token2 = generateToken("longstring2", 9); // "longs953f"
248
+ *
249
+ * @param name - The base name
250
+ * @param len - The desired length of the token.
251
+ * @returns The generated token with hash.
252
+ * @throws Error if the length is not a positive integer, or if the length is too short for the token.
253
+ * @internal
254
+ */ this.getShortenedName = (name, len)=>{
255
+ if (!isInteger(len) || len <= 0) {
256
+ throw new Error(`tokenWithHash length must be a positive integer, received ${len}`);
257
+ }
258
+ if (name.length <= len) {
259
+ return name;
260
+ }
261
+ if (len < this.MIN_TOKEN_LENGTH + this.HASH_LENGTH) {
262
+ throw new Error(`length for part of identifier too short, minimum is hash length (${this.HASH_LENGTH}) plus min token length (${this.MIN_TOKEN_LENGTH}), received ${len} for token ${name}`);
263
+ }
264
+ const availableLength = len - this.HASH_LENGTH - this.HASH_SEPARATOR.length;
265
+ if (availableLength < this.MIN_TOKEN_LENGTH) {
266
+ throw new Error(`length for part of identifier minimum is less than min token length (${this.MIN_TOKEN_LENGTH}), received ${len} for token ${name}`);
267
+ }
268
+ return `${name.substring(0, availableLength)}${this.HASH_SEPARATOR}${createHash(name, this.HASH_LENGTH)}`;
269
+ };
270
+ /**
271
+ * Constructs a name from an array of name tokens within a specified maximum length. It ensures the final name does not exceed
272
+ * this limit by selectively compressing tokens marked as compressible. If the name exceeds the maximum length and cannot be
273
+ * compressed sufficiently, an error is thrown. This function supports dynamic adjustment of token lengths to fit within the
274
+ * maxLength constraint (that is, it will always make use of all available space), while also ensuring the preservation of
275
+ * incompressible tokens.
276
+ * @internal
277
+ */ this.getNameFromTokens = (nameTokens)=>{
278
+ const { maxLength } = this.options;
279
+ if (!isInteger(maxLength) || maxLength < 0) {
280
+ throw new Error('maxLength must be a positive integer or 0 (for unlimited length)');
281
+ }
282
+ const unshortenedName = nameTokens.map((token)=>{
283
+ return token.name;
284
+ }).join(this.IDENTIFIER_SEPARATOR);
285
+ // if maxLength == 0 we want the legacy v4 name without any shortening
286
+ if (maxLength === 0) {
287
+ this.setUnshortenedName(unshortenedName, unshortenedName);
288
+ return unshortenedName;
289
+ }
290
+ // check the full length name (but with incompressible tokens using shortNames if available)
291
+ const fullLengthName = nameTokens.map((token)=>{
292
+ if (token.compressible) {
293
+ return token.name;
294
+ }
295
+ return token.shortName ?? token.name;
296
+ }).join(this.IDENTIFIER_SEPARATOR);
297
+ if (fullLengthName.length <= maxLength) {
298
+ this.setUnshortenedName(fullLengthName, unshortenedName);
299
+ return fullLengthName;
300
+ }
301
+ // Split tokens by compressibility
302
+ const [compressible, incompressible] = partition((token)=>token.compressible, nameTokens);
303
+ const totalIncompressibleLength = sumBy((token)=>token.compressible === false && token.shortName !== undefined ? token.shortName.length : token.name.length)(incompressible);
304
+ const totalSeparatorsLength = nameTokens.length * this.IDENTIFIER_SEPARATOR.length - 1;
305
+ const available = maxLength - totalIncompressibleLength - totalSeparatorsLength;
306
+ const availablePerToken = Math.floor(available / compressible.length);
307
+ if (totalIncompressibleLength + totalSeparatorsLength > maxLength || availablePerToken < this.MIN_TOKEN_LENGTH) {
308
+ throw new Error('Maximum length is too small to accommodate all tokens');
309
+ }
310
+ // Calculate the remainder from the division and add it to the surplus
311
+ let surplus = available % compressible.length;
312
+ // Check that it's even possible to proceed
313
+ const minHashedLength = this.HASH_LENGTH + this.HASH_SEPARATOR.length + this.MIN_TOKEN_LENGTH;
314
+ const totalLength = nameTokens.reduce((total, token)=>{
315
+ if (token.compressible) {
316
+ if (token.name.length < availablePerToken) {
317
+ return total + token.name.length;
318
+ }
319
+ return total + minHashedLength;
320
+ }
321
+ const tokenName = token.shortName ?? token.name;
322
+ return total + tokenName.length;
323
+ }, nameTokens.length * this.IDENTIFIER_SEPARATOR.length - 1);
324
+ // TODO: this is the weakest thing of the shortener, but fortunately it can be improved later without a breaking change if it turns out to be a problem (for example, if there is some case we need 6+ name parts in one identifier). We could take this "shortest string we could generate" that is too long and apply the hash directly to that, which would work fine even though it would be very difficult to determine what it was actually referring to
325
+ // Check if the maximum length is less than the total length
326
+ if (maxLength < totalLength) {
327
+ throw new Error('Maximum length is too small to accommodate all tokens');
328
+ }
329
+ // Calculate total surplus length from shorter strings and total deficit length from longer strings
330
+ let deficits = [];
331
+ compressible.forEach((token)=>{
332
+ const actualLength = token.name.length;
333
+ if (actualLength < availablePerToken) {
334
+ surplus += availablePerToken - actualLength;
335
+ token.allocatedLength = actualLength;
336
+ } else {
337
+ token.allocatedLength = availablePerToken;
338
+ deficits.push(token);
339
+ }
340
+ });
341
+ // Redistribute surplus length to longer strings, one character at a time
342
+ // This way we avoid issues with greed and trying to handle floating points by dividing available length
343
+ function filterAndIncreaseLength(token) {
344
+ if (token.allocatedLength < token.name.length && surplus > 0) {
345
+ token.allocatedLength += 1;
346
+ surplus -= 1;
347
+ // if it hasn't reached its full length, keep it in array for next round
348
+ return token.allocatedLength < token.name.length;
349
+ }
350
+ return false; // Remove this token from the deficits array
351
+ }
352
+ // Redistribute surplus length to longer strings, one character at a time
353
+ let previousSurplus = surplus + 1; // infinite loop protection
354
+ while(surplus > 0 && deficits.length > 0){
355
+ deficits = deficits.filter((token)=>filterAndIncreaseLength(token));
356
+ // infinite loop protection; if the surplus hasn't changed, there was nothing left to distribute it to
357
+ if (surplus === previousSurplus) {
358
+ break;
359
+ }
360
+ previousSurplus = surplus;
361
+ }
362
+ // Build final string
363
+ const shortenedName = nameTokens.map((token)=>{
364
+ // if it is compressible, shorten it
365
+ if (token.compressible && 'allocatedLength' in token && token.allocatedLength !== undefined) {
366
+ return this.getShortenedName(token.name, token.allocatedLength);
367
+ }
368
+ // if is is only compressible as a fixed value, use that
369
+ if (token.compressible === false && token.shortName) {
370
+ return token.shortName;
371
+ }
372
+ // otherwise return it as-is
373
+ return token.name;
374
+ }).join(this.IDENTIFIER_SEPARATOR);
375
+ // this should be unreachable, but add a final check for potential edge cases we missed
376
+ if (shortenedName.length > maxLength) {
377
+ throw new Error(`name shortening failed to generate a name of the correct maxLength; name ${shortenedName}`);
378
+ }
379
+ this.setUnshortenedName(shortenedName, unshortenedName);
380
+ return shortenedName;
381
+ };
382
+ // We need to be able to find the full-length name for any shortened name, primarily for migration purposes
383
+ // Therefore we store every name that passes through so we can retrieve the original later
384
+ this.nameMap = new Map();
385
+ this.getUnshortenedName = (shortName)=>{
386
+ return this.nameMap.get(this.serializeKey(shortName)) ?? shortName;
387
+ };
388
+ this.setUnshortenedName = (shortName, fullName)=>{
389
+ // This is protection against cases where a name is shortened twice, for example shortened in a model outside of createMetadata
390
+ // and then run through the shortener against inside createMetadata, which would do nothing at all but replace the original
391
+ // name in this mapping
392
+ if (this.nameMap.get(this.serializeKey(shortName)) && shortName === fullName) {
393
+ return;
394
+ }
395
+ // set the name
396
+ this.nameMap.set(this.serializeKey(shortName), fullName);
397
+ };
398
+ this.serializeKey = (shortName)=>{
399
+ return `${shortName}.${this.options.maxLength}`;
400
+ };
401
+ _class_private_field_loose_base(this, _options)[_options] = options;
402
+ }
403
+ }
404
+ // TODO: instead of instantiating this here as a global metadata should create its own to use
405
+ // However, that would require refactoring all of the metadata methods to be instantiated to keep a centralized identifiers
406
+ const identifiers = new Identifiers({
407
+ maxLength: IDENTIFIER_MAX_LENGTH
408
+ });
409
+
410
+ export { Identifiers, identifiers };
411
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","sources":["../../../src/utils/identifiers/index.ts"],"sourcesContent":["/**\n * This file contains utility functions for generating names used in the database.\n * These names include table names, column names, join table names, index names, and more.\n * The generated names can be customized with prefixes, suffixes, and maximum length.\n * These utility functions are used throughout the codebase to ensure consistent and standardized naming conventions in the database.\n *\n * The reason for checking maxLength for suffixes and prefixes and using the long ones from Strapi 4 is so that we always\n * have access to the full length names, in particular for migration purposes, but also so that (in theory) the feature\n * could be disabled and stay compatible with v4 database structure.\n */\nimport _, { isInteger, partition, snakeCase, sumBy } from 'lodash/fp';\nimport { createHash } from './hash';\nimport {\n IdentifiersOptions,\n NameInput,\n NameOptions,\n NameToken,\n NameTokenWithAllocation,\n} from './types';\n\nconst IDENTIFIER_MAX_LENGTH = 55 as const;\n\nexport class Identifiers {\n ID_COLUMN = 'id' as const;\n\n ORDER_COLUMN = 'order' as const;\n\n FIELD_COLUMN = 'field' as const;\n\n HASH_LENGTH = 5 as const;\n\n HASH_SEPARATOR = '' as const; // no separator is needed, we will just attach hash directly to shortened name\n\n IDENTIFIER_SEPARATOR = '_' as const;\n\n MIN_TOKEN_LENGTH = 3 as const; // the min characters required at the beginning of a name part\n\n // Fixed compression map for suffixes and prefixes\n #replacementMap = {\n links: 'lnk',\n order_inv_fk: 'oifk',\n order: 'ord',\n morphs: 'mph',\n index: 'idx',\n inv_fk: 'ifk',\n order_fk: 'ofk',\n id_column_index: 'idix',\n order_index: 'oidx',\n unique: 'uq',\n primary: 'pk',\n };\n\n #options: IdentifiersOptions;\n\n constructor(options: { maxLength: number }) {\n this.#options = options;\n }\n\n get replacementMap() {\n return this.#replacementMap;\n }\n\n get options() {\n return this.#options;\n }\n\n mapshortNames = (name: string): string | undefined => {\n if (name in this.replacementMap) {\n return (this.replacementMap as any)[name];\n }\n return undefined;\n };\n\n // Generic name handler that must be used by all helper functions\n /**\n * TODO: we should be requiring snake_case inputs for all names here, but we\n * aren't and it will require some refactoring to make it work. Currently if\n * we get names 'myModel' and 'my_model' they would be converted to the same\n * final string my_model which generally works but is not entirely safe\n * */\n getName = (names: NameInput, options?: NameOptions) => {\n const tokens: NameToken[] = _.castArray(names).map((name) => {\n return {\n name,\n compressible: true,\n };\n });\n\n if (options?.suffix) {\n tokens.push({\n name: options.suffix,\n compressible: false,\n shortName: this.mapshortNames(options.suffix),\n });\n }\n\n if (options?.prefix) {\n tokens.unshift({\n name: options.prefix,\n compressible: false,\n shortName: this.mapshortNames(options.prefix),\n });\n }\n\n return this.getNameFromTokens(tokens);\n };\n\n /**\n * TABLES\n */\n\n getTableName = (name: string, options?: NameOptions) => {\n return this.getName(name, options);\n };\n\n getJoinTableName = (collectionName: string, attributeName: string, options?: NameOptions) => {\n return this.getName([collectionName, attributeName], {\n suffix: 'links',\n ...options,\n });\n };\n\n getMorphTableName = (collectionName: string, attributeName: string, options?: NameOptions) => {\n return this.getName([snakeCase(collectionName), snakeCase(attributeName)], {\n suffix: 'morphs',\n ...options,\n });\n };\n\n /**\n * COLUMNS\n */\n\n getColumnName = (attributeName: string, options?: NameOptions) => {\n return this.getName(attributeName, options);\n };\n\n getJoinColumnAttributeIdName = (attributeName: string, options?: NameOptions) => {\n return this.getName(attributeName, { suffix: 'id', ...options });\n };\n\n getInverseJoinColumnAttributeIdName = (attributeName: string, options?: NameOptions) => {\n return this.getName(snakeCase(attributeName), { suffix: 'id', prefix: 'inv', ...options });\n };\n\n getOrderColumnName = (singularName: string, options?: NameOptions) => {\n return this.getName(singularName, { suffix: 'order', ...options });\n };\n\n getInverseOrderColumnName = (singularName: string, options?: NameOptions) => {\n return this.getName(singularName, {\n suffix: 'order',\n prefix: 'inv',\n ...options,\n });\n };\n\n /**\n * Morph Join Tables\n */\n getMorphColumnJoinTableIdName = (singularName: string, options?: NameOptions) => {\n return this.getName(snakeCase(singularName), { suffix: 'id', ...options });\n };\n\n getMorphColumnAttributeIdName = (attributeName: string, options?: NameOptions) => {\n return this.getName(snakeCase(attributeName), { suffix: 'id', ...options });\n };\n\n getMorphColumnTypeName = (attributeName: string, options?: NameOptions) => {\n return this.getName(snakeCase(attributeName), { suffix: 'type', ...options });\n };\n\n /**\n * INDEXES\n * Note that these methods are generally used to reference full table names + attribute(s), which\n * may already be shortened strings rather than individual parts.\n * That is fine and expected to compress the previously incompressible parts of those strings,\n * because in these cases the relevant information is the table name and we can't really do\n * any better; shortening the individual parts again might make it even more confusing.\n *\n * So for example, the fk for the table `mytable_myattr4567d_localizations` will become\n * mytable_myattr4567d_loc63bf2_fk\n */\n\n // base index types\n getIndexName = (names: NameInput, options?: NameOptions) => {\n return this.getName(names, { suffix: 'index', ...options });\n };\n\n getFkIndexName = (names: NameInput, options?: NameOptions) => {\n return this.getName(names, { suffix: 'fk', ...options });\n };\n\n getUniqueIndexName = (names: NameInput, options?: NameOptions) => {\n return this.getName(names, { suffix: 'unique', ...options });\n };\n\n getPrimaryIndexName = (names: NameInput, options?: NameOptions) => {\n return this.getName(names, { suffix: 'primary', ...options });\n };\n\n // custom index types\n getInverseFkIndexName = (names: NameInput, options?: NameOptions) => {\n return this.getName(names, { suffix: 'inv_fk', ...options });\n };\n\n getOrderFkIndexName = (names: NameInput, options?: NameOptions) => {\n return this.getName(names, { suffix: 'order_fk', ...options });\n };\n\n getOrderInverseFkIndexName = (names: NameInput, options?: NameOptions) => {\n return this.getName(names, { suffix: 'order_inv_fk', ...options });\n };\n\n getIdColumnIndexName = (names: NameInput, options?: NameOptions) => {\n return this.getName(names, { suffix: 'id_column_index', ...options });\n };\n\n getOrderIndexName = (names: NameInput, options?: NameOptions) => {\n return this.getName(names, { suffix: 'order_index', ...options });\n };\n\n /**\n * Generates a string with a max length, appending a hash at the end if necessary to keep it unique\n *\n * @example\n * // if we have strings such as \"longstring1\" and \"longstring2\" with a max length of 9,\n * // we don't want to end up with \"longstrin\" and \"longstrin\"\n * // we want something such as \"longs0b23\" and \"longs953f\"\n * const token1 = generateToken(\"longstring1\", 9); // \"longs0b23\"\n * const token2 = generateToken(\"longstring2\", 9); // \"longs953f\"\n *\n * @param name - The base name\n * @param len - The desired length of the token.\n * @returns The generated token with hash.\n * @throws Error if the length is not a positive integer, or if the length is too short for the token.\n * @internal\n */\n getShortenedName = (name: string, len: number) => {\n if (!isInteger(len) || len <= 0) {\n throw new Error(`tokenWithHash length must be a positive integer, received ${len}`);\n }\n if (name.length <= len) {\n return name;\n }\n if (len < this.MIN_TOKEN_LENGTH + this.HASH_LENGTH) {\n throw new Error(\n `length for part of identifier too short, minimum is hash length (${this.HASH_LENGTH}) plus min token length (${this.MIN_TOKEN_LENGTH}), received ${len} for token ${name}`\n );\n }\n\n const availableLength = len - this.HASH_LENGTH - this.HASH_SEPARATOR.length;\n if (availableLength < this.MIN_TOKEN_LENGTH) {\n throw new Error(\n `length for part of identifier minimum is less than min token length (${this.MIN_TOKEN_LENGTH}), received ${len} for token ${name}`\n );\n }\n\n return `${name.substring(0, availableLength)}${this.HASH_SEPARATOR}${createHash(\n name,\n this.HASH_LENGTH\n )}`;\n };\n\n /**\n * Constructs a name from an array of name tokens within a specified maximum length. It ensures the final name does not exceed\n * this limit by selectively compressing tokens marked as compressible. If the name exceeds the maximum length and cannot be\n * compressed sufficiently, an error is thrown. This function supports dynamic adjustment of token lengths to fit within the\n * maxLength constraint (that is, it will always make use of all available space), while also ensuring the preservation of\n * incompressible tokens.\n * @internal\n */\n getNameFromTokens = (nameTokens: NameToken[]): string => {\n const { maxLength } = this.options;\n\n if (!isInteger(maxLength) || maxLength < 0) {\n throw new Error('maxLength must be a positive integer or 0 (for unlimited length)');\n }\n\n const unshortenedName = nameTokens\n .map((token) => {\n return token.name;\n })\n .join(this.IDENTIFIER_SEPARATOR);\n\n // if maxLength == 0 we want the legacy v4 name without any shortening\n if (maxLength === 0) {\n this.setUnshortenedName(unshortenedName, unshortenedName);\n return unshortenedName;\n }\n\n // check the full length name (but with incompressible tokens using shortNames if available)\n const fullLengthName = nameTokens\n .map((token) => {\n if (token.compressible) {\n return token.name;\n }\n return token.shortName ?? token.name;\n })\n .join(this.IDENTIFIER_SEPARATOR);\n\n if (fullLengthName.length <= maxLength) {\n this.setUnshortenedName(fullLengthName, unshortenedName);\n return fullLengthName;\n }\n\n // Split tokens by compressibility\n const [compressible, incompressible] = partition(\n (token: NameToken) => token.compressible,\n nameTokens\n );\n\n const totalIncompressibleLength = sumBy((token: NameToken) =>\n token.compressible === false && token.shortName !== undefined\n ? token.shortName.length\n : token.name.length\n )(incompressible);\n const totalSeparatorsLength = nameTokens.length * this.IDENTIFIER_SEPARATOR.length - 1;\n const available = maxLength - totalIncompressibleLength - totalSeparatorsLength;\n const availablePerToken = Math.floor(available / compressible.length);\n\n if (\n totalIncompressibleLength + totalSeparatorsLength > maxLength ||\n availablePerToken < this.MIN_TOKEN_LENGTH\n ) {\n throw new Error('Maximum length is too small to accommodate all tokens');\n }\n\n // Calculate the remainder from the division and add it to the surplus\n let surplus = available % compressible.length;\n\n // Check that it's even possible to proceed\n const minHashedLength = this.HASH_LENGTH + this.HASH_SEPARATOR.length + this.MIN_TOKEN_LENGTH;\n const totalLength = nameTokens.reduce(\n (total, token) => {\n if (token.compressible) {\n if (token.name.length < availablePerToken) {\n return total + token.name.length;\n }\n return total + minHashedLength;\n }\n const tokenName = token.shortName ?? token.name;\n return total + tokenName.length;\n },\n nameTokens.length * this.IDENTIFIER_SEPARATOR.length - 1\n );\n\n // TODO: this is the weakest thing of the shortener, but fortunately it can be improved later without a breaking change if it turns out to be a problem (for example, if there is some case we need 6+ name parts in one identifier). We could take this \"shortest string we could generate\" that is too long and apply the hash directly to that, which would work fine even though it would be very difficult to determine what it was actually referring to\n // Check if the maximum length is less than the total length\n if (maxLength < totalLength) {\n throw new Error('Maximum length is too small to accommodate all tokens');\n }\n\n // Calculate total surplus length from shorter strings and total deficit length from longer strings\n let deficits: NameTokenWithAllocation[] = [];\n compressible.forEach((token) => {\n const actualLength = token.name.length;\n if (actualLength < availablePerToken) {\n surplus += availablePerToken - actualLength;\n token.allocatedLength = actualLength;\n } else {\n token.allocatedLength = availablePerToken;\n deficits.push(token as NameTokenWithAllocation);\n }\n });\n\n // Redistribute surplus length to longer strings, one character at a time\n // This way we avoid issues with greed and trying to handle floating points by dividing available length\n function filterAndIncreaseLength(token: NameTokenWithAllocation) {\n if (token.allocatedLength < token.name.length && surplus > 0) {\n token.allocatedLength += 1;\n surplus -= 1;\n // if it hasn't reached its full length, keep it in array for next round\n return token.allocatedLength < token.name.length;\n }\n return false; // Remove this token from the deficits array\n }\n\n // Redistribute surplus length to longer strings, one character at a time\n let previousSurplus = surplus + 1; // infinite loop protection\n while (surplus > 0 && deficits.length > 0) {\n deficits = deficits.filter((token) => filterAndIncreaseLength(token));\n\n // infinite loop protection; if the surplus hasn't changed, there was nothing left to distribute it to\n if (surplus === previousSurplus) {\n break;\n }\n previousSurplus = surplus;\n }\n\n // Build final string\n const shortenedName = nameTokens\n .map((token) => {\n // if it is compressible, shorten it\n if (\n token.compressible &&\n 'allocatedLength' in token &&\n token.allocatedLength !== undefined\n ) {\n return this.getShortenedName(token.name, token.allocatedLength);\n }\n\n // if is is only compressible as a fixed value, use that\n if (token.compressible === false && token.shortName) {\n return token.shortName;\n }\n\n // otherwise return it as-is\n return token.name;\n })\n .join(this.IDENTIFIER_SEPARATOR);\n\n // this should be unreachable, but add a final check for potential edge cases we missed\n if (shortenedName.length > maxLength) {\n throw new Error(\n `name shortening failed to generate a name of the correct maxLength; name ${shortenedName}`\n );\n }\n\n this.setUnshortenedName(shortenedName, unshortenedName);\n return shortenedName;\n };\n\n // We need to be able to find the full-length name for any shortened name, primarily for migration purposes\n // Therefore we store every name that passes through so we can retrieve the original later\n nameMap = new Map<string, string>();\n\n getUnshortenedName = (shortName: string) => {\n return this.nameMap.get(this.serializeKey(shortName)) ?? shortName;\n };\n\n setUnshortenedName = (shortName: string, fullName: string) => {\n // This is protection against cases where a name is shortened twice, for example shortened in a model outside of createMetadata\n // and then run through the shortener against inside createMetadata, which would do nothing at all but replace the original\n // name in this mapping\n if (this.nameMap.get(this.serializeKey(shortName)) && shortName === fullName) {\n return;\n }\n\n // set the name\n this.nameMap.set(this.serializeKey(shortName), fullName);\n };\n\n serializeKey = (shortName: string) => {\n return `${shortName}.${this.options.maxLength}`;\n };\n}\n\n// TODO: instead of instantiating this here as a global metadata should create its own to use\n// However, that would require refactoring all of the metadata methods to be instantiated to keep a centralized identifiers\nexport const identifiers = new Identifiers({ maxLength: IDENTIFIER_MAX_LENGTH });\n"],"names":["IDENTIFIER_MAX_LENGTH","Identifiers","replacementMap","options","constructor","ID_COLUMN","ORDER_COLUMN","FIELD_COLUMN","HASH_LENGTH","HASH_SEPARATOR","IDENTIFIER_SEPARATOR","MIN_TOKEN_LENGTH","links","order_inv_fk","order","morphs","index","inv_fk","order_fk","id_column_index","order_index","unique","primary","mapshortNames","name","undefined","getName","names","tokens","_","castArray","map","compressible","suffix","push","shortName","prefix","unshift","getNameFromTokens","getTableName","getJoinTableName","collectionName","attributeName","getMorphTableName","snakeCase","getColumnName","getJoinColumnAttributeIdName","getInverseJoinColumnAttributeIdName","getOrderColumnName","singularName","getInverseOrderColumnName","getMorphColumnJoinTableIdName","getMorphColumnAttributeIdName","getMorphColumnTypeName","getIndexName","getFkIndexName","getUniqueIndexName","getPrimaryIndexName","getInverseFkIndexName","getOrderFkIndexName","getOrderInverseFkIndexName","getIdColumnIndexName","getOrderIndexName","getShortenedName","len","isInteger","Error","length","availableLength","substring","createHash","nameTokens","maxLength","unshortenedName","token","join","setUnshortenedName","fullLengthName","incompressible","partition","totalIncompressibleLength","sumBy","totalSeparatorsLength","available","availablePerToken","Math","floor","surplus","minHashedLength","totalLength","reduce","total","tokenName","deficits","forEach","actualLength","allocatedLength","filterAndIncreaseLength","previousSurplus","filter","shortenedName","nameMap","Map","getUnshortenedName","get","serializeKey","fullName","set","identifiers"],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ 'use strict';
2
+
3
+ var KnexBuilder = require('knex/lib/query/querybuilder');
4
+ var KnexRaw = require('knex/lib/raw');
5
+
6
+ /**
7
+ * @internal
8
+ */ function isKnexQuery(value) {
9
+ return value instanceof KnexBuilder || value instanceof KnexRaw;
10
+ }
11
+ /**
12
+ * Adds the name of the schema to the table name if the schema was defined by the user.
13
+ * Users can set the db schema only for Postgres in strapi database config.
14
+ */ const addSchema = (db, tableName)=>{
15
+ const schemaName = db.getSchemaName();
16
+ return schemaName ? `${schemaName}.${tableName}` : tableName;
17
+ };
18
+
19
+ exports.addSchema = addSchema;
20
+ exports.isKnexQuery = isKnexQuery;
21
+ //# sourceMappingURL=knex.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"knex.js","sources":["../../src/utils/knex.ts"],"sourcesContent":["import type { Knex } from 'knex';\n\nimport KnexBuilder from 'knex/lib/query/querybuilder';\nimport KnexRaw from 'knex/lib/raw';\n\nimport type { Database } from '..';\n\n/**\n * @internal\n */\nexport function isKnexQuery(value: unknown): value is Knex.Raw | Knex.QueryBuilder {\n return value instanceof KnexBuilder || value instanceof KnexRaw;\n}\n\n/**\n * Adds the name of the schema to the table name if the schema was defined by the user.\n * Users can set the db schema only for Postgres in strapi database config.\n */\nexport const addSchema = (db: Database, tableName: string): string => {\n const schemaName = db.getSchemaName();\n return schemaName ? `${schemaName}.${tableName}` : tableName;\n};\n"],"names":["isKnexQuery","value","KnexBuilder","KnexRaw","addSchema","db","tableName","schemaName","getSchemaName"],"mappings":";;;;;AAOA;;IAGO,SAASA,WAAAA,CAAYC,KAAc,EAAA;IACxC,OAAOA,KAAAA,YAAiBC,eAAeD,KAAiBE,YAAAA,OAAAA;AAC1D;AAEA;;;AAGC,IACM,MAAMC,SAAY,GAAA,CAACC,EAAcC,EAAAA,SAAAA,GAAAA;IACtC,MAAMC,UAAAA,GAAaF,GAAGG,aAAa,EAAA;IACnC,OAAOD,UAAAA,GAAa,CAAC,EAAEA,UAAAA,CAAW,CAAC,EAAED,SAAAA,CAAU,CAAC,GAAGA,SAAAA;AACrD;;;;;"}
@@ -0,0 +1,18 @@
1
+ import KnexBuilder from 'knex/lib/query/querybuilder';
2
+ import KnexRaw from 'knex/lib/raw';
3
+
4
+ /**
5
+ * @internal
6
+ */ function isKnexQuery(value) {
7
+ return value instanceof KnexBuilder || value instanceof KnexRaw;
8
+ }
9
+ /**
10
+ * Adds the name of the schema to the table name if the schema was defined by the user.
11
+ * Users can set the db schema only for Postgres in strapi database config.
12
+ */ const addSchema = (db, tableName)=>{
13
+ const schemaName = db.getSchemaName();
14
+ return schemaName ? `${schemaName}.${tableName}` : tableName;
15
+ };
16
+
17
+ export { addSchema, isKnexQuery };
18
+ //# sourceMappingURL=knex.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"knex.mjs","sources":["../../src/utils/knex.ts"],"sourcesContent":["import type { Knex } from 'knex';\n\nimport KnexBuilder from 'knex/lib/query/querybuilder';\nimport KnexRaw from 'knex/lib/raw';\n\nimport type { Database } from '..';\n\n/**\n * @internal\n */\nexport function isKnexQuery(value: unknown): value is Knex.Raw | Knex.QueryBuilder {\n return value instanceof KnexBuilder || value instanceof KnexRaw;\n}\n\n/**\n * Adds the name of the schema to the table name if the schema was defined by the user.\n * Users can set the db schema only for Postgres in strapi database config.\n */\nexport const addSchema = (db: Database, tableName: string): string => {\n const schemaName = db.getSchemaName();\n return schemaName ? `${schemaName}.${tableName}` : tableName;\n};\n"],"names":["isKnexQuery","value","KnexBuilder","KnexRaw","addSchema","db","tableName","schemaName","getSchemaName"],"mappings":";;;AAOA;;IAGO,SAASA,WAAAA,CAAYC,KAAc,EAAA;IACxC,OAAOA,KAAAA,YAAiBC,eAAeD,KAAiBE,YAAAA,OAAAA;AAC1D;AAEA;;;AAGC,IACM,MAAMC,SAAY,GAAA,CAACC,EAAcC,EAAAA,SAAAA,GAAAA;IACtC,MAAMC,UAAAA,GAAaF,GAAGG,aAAa,EAAA;IACnC,OAAOD,UAAAA,GAAa,CAAC,EAAEA,UAAAA,CAAW,CAAC,EAAED,SAAAA,CAAU,CAAC,GAAGA,SAAAA;AACrD;;;;"}
@@ -0,0 +1,51 @@
1
+ 'use strict';
2
+
3
+ const SCALAR_TYPES = [
4
+ 'increments',
5
+ 'password',
6
+ 'email',
7
+ 'string',
8
+ 'uid',
9
+ 'richtext',
10
+ 'text',
11
+ 'json',
12
+ 'enumeration',
13
+ 'integer',
14
+ 'biginteger',
15
+ 'float',
16
+ 'decimal',
17
+ 'date',
18
+ 'time',
19
+ 'datetime',
20
+ 'timestamp',
21
+ 'boolean',
22
+ 'blocks'
23
+ ];
24
+ const STRING_TYPES = [
25
+ 'string',
26
+ 'text',
27
+ 'uid',
28
+ 'email',
29
+ 'enumeration',
30
+ 'richtext'
31
+ ];
32
+ const NUMBER_TYPES = [
33
+ 'biginteger',
34
+ 'integer',
35
+ 'decimal',
36
+ 'float'
37
+ ];
38
+ const isString = (type)=>STRING_TYPES.includes(type);
39
+ const isNumber = (type)=>NUMBER_TYPES.includes(type);
40
+ const isScalar = (type)=>SCALAR_TYPES.includes(type);
41
+ const isRelation = (type)=>type === 'relation';
42
+ const isScalarAttribute = (attribute)=>isScalar(attribute.type);
43
+ const isRelationalAttribute = (attribute)=>isRelation(attribute.type);
44
+
45
+ exports.isNumber = isNumber;
46
+ exports.isRelation = isRelation;
47
+ exports.isRelationalAttribute = isRelationalAttribute;
48
+ exports.isScalar = isScalar;
49
+ exports.isScalarAttribute = isScalarAttribute;
50
+ exports.isString = isString;
51
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sources":["../../src/utils/types.ts"],"sourcesContent":["import type { Attribute, ScalarAttribute, RelationalAttribute } from '../types';\n\nconst SCALAR_TYPES = [\n 'increments',\n 'password',\n 'email',\n 'string',\n 'uid',\n 'richtext',\n 'text',\n 'json',\n 'enumeration',\n 'integer',\n 'biginteger',\n 'float',\n 'decimal',\n 'date',\n 'time',\n 'datetime',\n 'timestamp',\n 'boolean',\n 'blocks',\n];\n\nconst STRING_TYPES = ['string', 'text', 'uid', 'email', 'enumeration', 'richtext'];\nconst NUMBER_TYPES = ['biginteger', 'integer', 'decimal', 'float'];\n\nexport const isString = (type: string) => STRING_TYPES.includes(type);\nexport const isNumber = (type: string) => NUMBER_TYPES.includes(type);\nexport const isScalar = (type: string) => SCALAR_TYPES.includes(type);\nexport const isRelation = (type: string) => type === 'relation';\nexport const isScalarAttribute = (attribute: Attribute): attribute is ScalarAttribute =>\n isScalar(attribute.type);\nexport const isRelationalAttribute = (attribute: Attribute): attribute is RelationalAttribute =>\n isRelation(attribute.type);\n"],"names":["SCALAR_TYPES","STRING_TYPES","NUMBER_TYPES","isString","type","includes","isNumber","isScalar","isRelation","isScalarAttribute","attribute","isRelationalAttribute"],"mappings":";;AAEA,MAAMA,YAAe,GAAA;AACnB,IAAA,YAAA;AACA,IAAA,UAAA;AACA,IAAA,OAAA;AACA,IAAA,QAAA;AACA,IAAA,KAAA;AACA,IAAA,UAAA;AACA,IAAA,MAAA;AACA,IAAA,MAAA;AACA,IAAA,aAAA;AACA,IAAA,SAAA;AACA,IAAA,YAAA;AACA,IAAA,OAAA;AACA,IAAA,SAAA;AACA,IAAA,MAAA;AACA,IAAA,MAAA;AACA,IAAA,UAAA;AACA,IAAA,WAAA;AACA,IAAA,SAAA;AACA,IAAA;AACD,CAAA;AAED,MAAMC,YAAe,GAAA;AAAC,IAAA,QAAA;AAAU,IAAA,MAAA;AAAQ,IAAA,KAAA;AAAO,IAAA,OAAA;AAAS,IAAA,aAAA;AAAe,IAAA;AAAW,CAAA;AAClF,MAAMC,YAAe,GAAA;AAAC,IAAA,YAAA;AAAc,IAAA,SAAA;AAAW,IAAA,SAAA;AAAW,IAAA;AAAQ,CAAA;MAErDC,QAAW,GAAA,CAACC,OAAiBH,YAAaI,CAAAA,QAAQ,CAACD,IAAM;MACzDE,QAAW,GAAA,CAACF,OAAiBF,YAAaG,CAAAA,QAAQ,CAACD,IAAM;MACzDG,QAAW,GAAA,CAACH,OAAiBJ,YAAaK,CAAAA,QAAQ,CAACD,IAAM;AACzDI,MAAAA,UAAAA,GAAa,CAACJ,IAAAA,GAAiBA,SAAS;MACxCK,iBAAoB,GAAA,CAACC,YAChCH,QAASG,CAAAA,SAAAA,CAAUN,IAAI;MACZO,qBAAwB,GAAA,CAACD,YACpCF,UAAWE,CAAAA,SAAAA,CAAUN,IAAI;;;;;;;;;"}
@@ -0,0 +1,44 @@
1
+ const SCALAR_TYPES = [
2
+ 'increments',
3
+ 'password',
4
+ 'email',
5
+ 'string',
6
+ 'uid',
7
+ 'richtext',
8
+ 'text',
9
+ 'json',
10
+ 'enumeration',
11
+ 'integer',
12
+ 'biginteger',
13
+ 'float',
14
+ 'decimal',
15
+ 'date',
16
+ 'time',
17
+ 'datetime',
18
+ 'timestamp',
19
+ 'boolean',
20
+ 'blocks'
21
+ ];
22
+ const STRING_TYPES = [
23
+ 'string',
24
+ 'text',
25
+ 'uid',
26
+ 'email',
27
+ 'enumeration',
28
+ 'richtext'
29
+ ];
30
+ const NUMBER_TYPES = [
31
+ 'biginteger',
32
+ 'integer',
33
+ 'decimal',
34
+ 'float'
35
+ ];
36
+ const isString = (type)=>STRING_TYPES.includes(type);
37
+ const isNumber = (type)=>NUMBER_TYPES.includes(type);
38
+ const isScalar = (type)=>SCALAR_TYPES.includes(type);
39
+ const isRelation = (type)=>type === 'relation';
40
+ const isScalarAttribute = (attribute)=>isScalar(attribute.type);
41
+ const isRelationalAttribute = (attribute)=>isRelation(attribute.type);
42
+
43
+ export { isNumber, isRelation, isRelationalAttribute, isScalar, isScalarAttribute, isString };
44
+ //# sourceMappingURL=types.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.mjs","sources":["../../src/utils/types.ts"],"sourcesContent":["import type { Attribute, ScalarAttribute, RelationalAttribute } from '../types';\n\nconst SCALAR_TYPES = [\n 'increments',\n 'password',\n 'email',\n 'string',\n 'uid',\n 'richtext',\n 'text',\n 'json',\n 'enumeration',\n 'integer',\n 'biginteger',\n 'float',\n 'decimal',\n 'date',\n 'time',\n 'datetime',\n 'timestamp',\n 'boolean',\n 'blocks',\n];\n\nconst STRING_TYPES = ['string', 'text', 'uid', 'email', 'enumeration', 'richtext'];\nconst NUMBER_TYPES = ['biginteger', 'integer', 'decimal', 'float'];\n\nexport const isString = (type: string) => STRING_TYPES.includes(type);\nexport const isNumber = (type: string) => NUMBER_TYPES.includes(type);\nexport const isScalar = (type: string) => SCALAR_TYPES.includes(type);\nexport const isRelation = (type: string) => type === 'relation';\nexport const isScalarAttribute = (attribute: Attribute): attribute is ScalarAttribute =>\n isScalar(attribute.type);\nexport const isRelationalAttribute = (attribute: Attribute): attribute is RelationalAttribute =>\n isRelation(attribute.type);\n"],"names":["SCALAR_TYPES","STRING_TYPES","NUMBER_TYPES","isString","type","includes","isNumber","isScalar","isRelation","isScalarAttribute","attribute","isRelationalAttribute"],"mappings":"AAEA,MAAMA,YAAe,GAAA;AACnB,IAAA,YAAA;AACA,IAAA,UAAA;AACA,IAAA,OAAA;AACA,IAAA,QAAA;AACA,IAAA,KAAA;AACA,IAAA,UAAA;AACA,IAAA,MAAA;AACA,IAAA,MAAA;AACA,IAAA,aAAA;AACA,IAAA,SAAA;AACA,IAAA,YAAA;AACA,IAAA,OAAA;AACA,IAAA,SAAA;AACA,IAAA,MAAA;AACA,IAAA,MAAA;AACA,IAAA,UAAA;AACA,IAAA,WAAA;AACA,IAAA,SAAA;AACA,IAAA;AACD,CAAA;AAED,MAAMC,YAAe,GAAA;AAAC,IAAA,QAAA;AAAU,IAAA,MAAA;AAAQ,IAAA,KAAA;AAAO,IAAA,OAAA;AAAS,IAAA,aAAA;AAAe,IAAA;AAAW,CAAA;AAClF,MAAMC,YAAe,GAAA;AAAC,IAAA,YAAA;AAAc,IAAA,SAAA;AAAW,IAAA,SAAA;AAAW,IAAA;AAAQ,CAAA;MAErDC,QAAW,GAAA,CAACC,OAAiBH,YAAaI,CAAAA,QAAQ,CAACD,IAAM;MACzDE,QAAW,GAAA,CAACF,OAAiBF,YAAaG,CAAAA,QAAQ,CAACD,IAAM;MACzDG,QAAW,GAAA,CAACH,OAAiBJ,YAAaK,CAAAA,QAAQ,CAACD,IAAM;AACzDI,MAAAA,UAAAA,GAAa,CAACJ,IAAAA,GAAiBA,SAAS;MACxCK,iBAAoB,GAAA,CAACC,YAChCH,QAASG,CAAAA,SAAAA,CAAUN,IAAI;MACZO,qBAAwB,GAAA,CAACD,YACpCF,UAAWE,CAAAA,SAAAA,CAAUN,IAAI;;;;"}