@depup/typeorm-extension 3.9.0-depup.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/LICENSE +21 -0
  2. package/README.MD +674 -0
  3. package/README.md +34 -0
  4. package/bin/cli.cjs +275 -0
  5. package/bin/cli.mjs +273 -0
  6. package/changes.json +22 -0
  7. package/dist/cli/commands/database/create.d.ts +27 -0
  8. package/dist/cli/commands/database/drop.d.ts +23 -0
  9. package/dist/cli/commands/database/index.d.ts +2 -0
  10. package/dist/cli/commands/index.d.ts +2 -0
  11. package/dist/cli/commands/seed/create.d.ts +21 -0
  12. package/dist/cli/commands/seed/index.d.ts +2 -0
  13. package/dist/cli/commands/seed/run.d.ts +24 -0
  14. package/dist/cli/index.d.ts +2 -0
  15. package/dist/data-source/find/index.d.ts +2 -0
  16. package/dist/data-source/find/module.d.ts +3 -0
  17. package/dist/data-source/find/type.d.ts +22 -0
  18. package/dist/data-source/index.d.ts +4 -0
  19. package/dist/data-source/options/index.d.ts +4 -0
  20. package/dist/data-source/options/module.d.ts +8 -0
  21. package/dist/data-source/options/singleton.d.ts +4 -0
  22. package/dist/data-source/options/type.d.ts +26 -0
  23. package/dist/data-source/options/utils/env.d.ts +4 -0
  24. package/dist/data-source/options/utils/index.d.ts +2 -0
  25. package/dist/data-source/options/utils/merge.d.ts +2 -0
  26. package/dist/data-source/singleton.d.ts +5 -0
  27. package/dist/data-source/type.d.ts +2 -0
  28. package/dist/database/driver/cockroachdb.d.ts +4 -0
  29. package/dist/database/driver/index.d.ts +9 -0
  30. package/dist/database/driver/mongodb.d.ts +6 -0
  31. package/dist/database/driver/mssql.d.ts +6 -0
  32. package/dist/database/driver/mysql.d.ts +7 -0
  33. package/dist/database/driver/oracle.d.ts +6 -0
  34. package/dist/database/driver/postgres.d.ts +8 -0
  35. package/dist/database/driver/sqlite.d.ts +3 -0
  36. package/dist/database/driver/types.d.ts +20 -0
  37. package/dist/database/driver/utils/build.d.ts +3 -0
  38. package/dist/database/driver/utils/character-set.d.ts +2 -0
  39. package/dist/database/driver/utils/charset.d.ts +2 -0
  40. package/dist/database/driver/utils/create.d.ts +2 -0
  41. package/dist/database/driver/utils/index.d.ts +4 -0
  42. package/dist/database/index.d.ts +3 -0
  43. package/dist/database/methods/check/index.d.ts +2 -0
  44. package/dist/database/methods/check/module.d.ts +7 -0
  45. package/dist/database/methods/check/types.d.ts +51 -0
  46. package/dist/database/methods/create/index.d.ts +1 -0
  47. package/dist/database/methods/create/module.d.ts +10 -0
  48. package/dist/database/methods/drop/index.d.ts +1 -0
  49. package/dist/database/methods/drop/module.d.ts +10 -0
  50. package/dist/database/methods/index.d.ts +4 -0
  51. package/dist/database/methods/type.d.ts +43 -0
  52. package/dist/database/utils/context.d.ts +3 -0
  53. package/dist/database/utils/index.d.ts +5 -0
  54. package/dist/database/utils/migration.d.ts +2 -0
  55. package/dist/database/utils/query.d.ts +3 -0
  56. package/dist/database/utils/schema.d.ts +3 -0
  57. package/dist/database/utils/type.d.ts +32 -0
  58. package/dist/env/constants.d.ts +68 -0
  59. package/dist/env/index.d.ts +3 -0
  60. package/dist/env/module.d.ts +4 -0
  61. package/dist/env/type.d.ts +36 -0
  62. package/dist/env/utils.d.ts +3 -0
  63. package/dist/errors/base.d.ts +2 -0
  64. package/dist/errors/driver.d.ts +6 -0
  65. package/dist/errors/index.d.ts +3 -0
  66. package/dist/errors/options.d.ts +7 -0
  67. package/dist/helpers/entity/error.d.ts +20 -0
  68. package/dist/helpers/entity/index.d.ts +5 -0
  69. package/dist/helpers/entity/join-columns.d.ts +16 -0
  70. package/dist/helpers/entity/metadata.d.ts +10 -0
  71. package/dist/helpers/entity/property-names.d.ts +11 -0
  72. package/dist/helpers/entity/uniqueness.d.ts +28 -0
  73. package/dist/helpers/index.d.ts +1 -0
  74. package/dist/index.cjs +3258 -0
  75. package/dist/index.cjs.map +1 -0
  76. package/dist/index.d.ts +9 -0
  77. package/dist/index.mjs +3136 -0
  78. package/dist/index.mjs.map +1 -0
  79. package/dist/query/index.d.ts +4 -0
  80. package/dist/query/module.d.ts +5 -0
  81. package/dist/query/parameter/fields/index.d.ts +2 -0
  82. package/dist/query/parameter/fields/module.d.ts +25 -0
  83. package/dist/query/parameter/fields/type.d.ts +6 -0
  84. package/dist/query/parameter/filters/index.d.ts +2 -0
  85. package/dist/query/parameter/filters/module.d.ts +35 -0
  86. package/dist/query/parameter/filters/type.d.ts +12 -0
  87. package/dist/query/parameter/index.d.ts +5 -0
  88. package/dist/query/parameter/pagination/index.d.ts +2 -0
  89. package/dist/query/parameter/pagination/module.d.ts +26 -0
  90. package/dist/query/parameter/pagination/type.d.ts +3 -0
  91. package/dist/query/parameter/relations/index.d.ts +2 -0
  92. package/dist/query/parameter/relations/module.d.ts +27 -0
  93. package/dist/query/parameter/relations/type.d.ts +8 -0
  94. package/dist/query/parameter/sort/index.d.ts +2 -0
  95. package/dist/query/parameter/sort/module.d.ts +26 -0
  96. package/dist/query/parameter/sort/type.d.ts +6 -0
  97. package/dist/query/type.d.ts +16 -0
  98. package/dist/query/utils/alias.d.ts +2 -0
  99. package/dist/query/utils/index.d.ts +3 -0
  100. package/dist/query/utils/key.d.ts +1 -0
  101. package/dist/query/utils/option.d.ts +1 -0
  102. package/dist/seeder/entity.d.ts +42 -0
  103. package/dist/seeder/executor.d.ts +24 -0
  104. package/dist/seeder/factory/index.d.ts +4 -0
  105. package/dist/seeder/factory/manager.d.ts +8 -0
  106. package/dist/seeder/factory/module.d.ts +17 -0
  107. package/dist/seeder/factory/type.d.ts +12 -0
  108. package/dist/seeder/factory/utils.d.ts +7 -0
  109. package/dist/seeder/index.d.ts +6 -0
  110. package/dist/seeder/module.d.ts +5 -0
  111. package/dist/seeder/type.d.ts +44 -0
  112. package/dist/seeder/utils/file-path.d.ts +7 -0
  113. package/dist/seeder/utils/index.d.ts +3 -0
  114. package/dist/seeder/utils/prepare.d.ts +2 -0
  115. package/dist/seeder/utils/template.d.ts +1 -0
  116. package/dist/utils/code-transformation/constants.d.ts +4 -0
  117. package/dist/utils/code-transformation/index.d.ts +2 -0
  118. package/dist/utils/code-transformation/module.d.ts +3 -0
  119. package/dist/utils/entity.d.ts +2 -0
  120. package/dist/utils/file-path.d.ts +9 -0
  121. package/dist/utils/file-system.d.ts +1 -0
  122. package/dist/utils/has-property.d.ts +2 -0
  123. package/dist/utils/index.d.ts +10 -0
  124. package/dist/utils/object.d.ts +2 -0
  125. package/dist/utils/promise.d.ts +1 -0
  126. package/dist/utils/separator.d.ts +3 -0
  127. package/dist/utils/slash.d.ts +2 -0
  128. package/dist/utils/tsconfig/index.d.ts +2 -0
  129. package/dist/utils/tsconfig/module.d.ts +2 -0
  130. package/dist/utils/tsconfig/type.d.ts +13 -0
  131. package/package.json +134 -0
package/dist/index.cjs ADDED
@@ -0,0 +1,3258 @@
1
+ 'use strict';
2
+
3
+ var locter = require('locter');
4
+ var rapiq = require('rapiq');
5
+ var process$1 = require('node:process');
6
+ var typeorm = require('typeorm');
7
+ var path = require('node:path');
8
+ var fs = require('node:fs');
9
+ var consola = require('consola');
10
+ var envix = require('envix');
11
+ var smob = require('smob');
12
+ var DriverUtils = require('typeorm/driver/DriverUtils');
13
+ var DriverFactory = require('typeorm/driver/DriverFactory');
14
+ var pascalCase = require('pascal-case');
15
+ var MigrationGenerateCommand = require('typeorm/commands/MigrationGenerateCommand');
16
+
17
+ class TypeormExtensionError extends Error {
18
+ }
19
+
20
+ class DriverError extends TypeormExtensionError {
21
+ constructor(message){
22
+ super(message || 'A database driver related error has occurred.');
23
+ }
24
+ static undeterminable() {
25
+ return new DriverError('The driver could not be determined.');
26
+ }
27
+ static notSupported(driverName) {
28
+ return new DriverError(`The driver ${driverName} is not supported yet.`);
29
+ }
30
+ }
31
+
32
+ class OptionsError extends TypeormExtensionError {
33
+ constructor(message){
34
+ super(message || 'A database options related error has occurred');
35
+ }
36
+ static undeterminable() {
37
+ return new OptionsError('The database options could not be determined.');
38
+ }
39
+ static notFound() {
40
+ return new OptionsError('The database options could not be located/loaded.');
41
+ }
42
+ static databaseNotDefined() {
43
+ return new OptionsError('The database name to connect to is not defined.');
44
+ }
45
+ }
46
+
47
+ var CodeTransformation = /*#__PURE__*/ function(CodeTransformation) {
48
+ CodeTransformation["JUST_IN_TIME"] = "jit";
49
+ CodeTransformation["NONE"] = "none";
50
+ return CodeTransformation;
51
+ }({});
52
+
53
+ function detectCodeTransformation() {
54
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
55
+ // @ts-ignore
56
+ if (process$1[Symbol.for('ts-node.register.instance')]) {
57
+ return CodeTransformation.JUST_IN_TIME;
58
+ }
59
+ return CodeTransformation.NONE;
60
+ }
61
+ function isCodeTransformation(input) {
62
+ return detectCodeTransformation() === input;
63
+ }
64
+
65
+ function getEntityName(entity) {
66
+ if (typeof entity === 'function') {
67
+ return entity.name;
68
+ }
69
+ if (typeorm.InstanceChecker.isEntitySchema(entity)) {
70
+ return entity.options.name;
71
+ }
72
+ return new entity().constructor.name;
73
+ }
74
+
75
+ function canReplaceWindowsSeparator(input) {
76
+ // https://superuser.com/questions/176388/why-does-windows-use-backslashes-for-paths-and-unix-forward-slashes/176395#176395
77
+ if (input.startsWith('\\\\?\\')) {
78
+ return false;
79
+ }
80
+ let characterIndex;
81
+ const specialCharacters = [
82
+ '[',
83
+ '{',
84
+ '(',
85
+ '^',
86
+ '$',
87
+ '.',
88
+ '|',
89
+ '?',
90
+ '*',
91
+ '+'
92
+ ];
93
+ for(let i = 0; i < specialCharacters.length; i++){
94
+ characterIndex = input.indexOf(specialCharacters[i]);
95
+ if (characterIndex !== -1) {
96
+ // special character is prefixed with \, no transformation allowed
97
+ if (characterIndex !== 0 && input[characterIndex - 1] === '\\') {
98
+ return false;
99
+ }
100
+ }
101
+ }
102
+ return true;
103
+ }
104
+ function replaceWindowSeparator(input) {
105
+ return input.replace(/\\/g, '/');
106
+ }
107
+ function safeReplaceWindowsSeparator(input) {
108
+ if (input.indexOf('\\') === -1 || !canReplaceWindowsSeparator(input)) {
109
+ return input;
110
+ }
111
+ return replaceWindowSeparator(input);
112
+ }
113
+
114
+ const TRAILING_SLASH_RE = /\/$|\/\?/;
115
+ function hasTrailingSlash(input = '', queryParams = false) {
116
+ if (!queryParams) {
117
+ return input.endsWith('/');
118
+ }
119
+ return TRAILING_SLASH_RE.test(input);
120
+ }
121
+ function withoutTrailingSlash(input = '', queryParams = false) {
122
+ if (!queryParams) {
123
+ return (hasTrailingSlash(input) ? input.slice(0, -1) : input) || '/';
124
+ }
125
+ if (!hasTrailingSlash(input, true)) {
126
+ return input || '/';
127
+ }
128
+ const [s0, ...s] = input.split('?');
129
+ return (s0.slice(0, -1) || '/') + (s.length ? `?${s.join('?')}` : '');
130
+ }
131
+
132
+ async function readTSConfig(input) {
133
+ input = input || process.cwd();
134
+ input = path.isAbsolute(input) ? input : path.resolve(process.cwd(), input);
135
+ const filePath = input.indexOf('.json') === -1 ? path.join(input, 'tsconfig.json') : input;
136
+ try {
137
+ const tsConfig = await locter.load(filePath);
138
+ if (locter.isObject(tsConfig)) {
139
+ return tsConfig;
140
+ }
141
+ } catch (e) {
142
+ // don't do anything ;)
143
+ }
144
+ return {};
145
+ }
146
+
147
+ const stripLeadingModifier = (text)=>{
148
+ if (text.startsWith('./')) {
149
+ text = text.substring(2);
150
+ }
151
+ return text;
152
+ };
153
+ function transformFilePath(input, dist, src) {
154
+ let separator = path.sep;
155
+ const windowsSeparatorReplaceable = canReplaceWindowsSeparator(input);
156
+ if (windowsSeparatorReplaceable) {
157
+ separator = '/';
158
+ input = replaceWindowSeparator(input);
159
+ }
160
+ let base = input;
161
+ let baseIndex = input.lastIndexOf(separator);
162
+ if (baseIndex !== -1) {
163
+ base = base.substring(baseIndex + 1);
164
+ }
165
+ if (src) {
166
+ if (windowsSeparatorReplaceable) {
167
+ src = replaceWindowSeparator(src);
168
+ }
169
+ src = withoutTrailingSlash(stripLeadingModifier(src));
170
+ }
171
+ src = src || 'src';
172
+ if (dist) {
173
+ if (windowsSeparatorReplaceable) {
174
+ dist = replaceWindowSeparator(dist);
175
+ }
176
+ dist = withoutTrailingSlash(stripLeadingModifier(dist));
177
+ }
178
+ dist = dist || 'dist';
179
+ if (input.indexOf(src) !== -1 && input.indexOf(dist) === -1) {
180
+ const lastIndex = input.lastIndexOf(src);
181
+ const prevCharacter = input.substring(lastIndex - 1, lastIndex);
182
+ if (!prevCharacter || prevCharacter === separator) {
183
+ input = input.substring(0, lastIndex) + dist + input.substring(lastIndex + src.length);
184
+ baseIndex = input.lastIndexOf(separator);
185
+ }
186
+ }
187
+ // if the path already contains a js file extension, we are done
188
+ const jsExtensions = [
189
+ 'js',
190
+ 'cjs',
191
+ 'mjs'
192
+ ];
193
+ for(let i = 0; i < jsExtensions.length; i++){
194
+ if (base.indexOf(jsExtensions[i]) !== -1) {
195
+ return input;
196
+ }
197
+ }
198
+ const tsExtensions = [
199
+ 'ts',
200
+ 'cts',
201
+ 'mts'
202
+ ];
203
+ for(let i = 0; i < tsExtensions.length; i++){
204
+ const regex = new RegExp(`(\\.${tsExtensions[i]}|${tsExtensions[i]})`, 'g');
205
+ let matchesSum;
206
+ const matches = base.match(regex);
207
+ if (Array.isArray(matches)) {
208
+ matchesSum = matches.length;
209
+ }
210
+ let matchesCounter = 0;
211
+ const bracketIndex = base.lastIndexOf('{');
212
+ base = base.replace(regex, (...args)=>{
213
+ matchesCounter++;
214
+ // if the file extension name comes after the last bracket index,
215
+ // we can be pretty sure that the extension name is not part of a filename
216
+ if (args[2] >= bracketIndex && bracketIndex !== -1 || bracketIndex === -1 && matchesCounter === matchesSum) {
217
+ return args[0].startsWith('.') ? `.${jsExtensions[i]}` : jsExtensions[i];
218
+ }
219
+ return args[0];
220
+ });
221
+ }
222
+ if (baseIndex !== -1) {
223
+ base = input.substring(0, baseIndex + 1) + base;
224
+ }
225
+ return stripLeadingModifier(base);
226
+ }
227
+ async function adjustFilePath(input, tsconfig) {
228
+ if (isCodeTransformation(CodeTransformation.JUST_IN_TIME)) {
229
+ return input;
230
+ }
231
+ if (!locter.isObject(tsconfig)) {
232
+ tsconfig = await readTSConfig(tsconfig);
233
+ }
234
+ const { compilerOptions } = tsconfig;
235
+ if (typeof input === 'string') {
236
+ return transformFilePath(input, compilerOptions?.outDir);
237
+ }
238
+ if (Array.isArray(input)) {
239
+ for(let i = 0; i < input.length; i++){
240
+ if (typeof input[i] === 'string') {
241
+ input[i] = transformFilePath(input[i], compilerOptions?.outDir);
242
+ }
243
+ }
244
+ }
245
+ return input;
246
+ }
247
+ async function adjustFilePaths(input, keys, tsconfig) {
248
+ if (isCodeTransformation(CodeTransformation.JUST_IN_TIME)) {
249
+ return input;
250
+ }
251
+ if (!locter.isObject(tsconfig)) {
252
+ tsconfig = await readTSConfig(tsconfig);
253
+ }
254
+ keys = keys || Object.keys(input);
255
+ for(let i = 0; i < keys.length; i++){
256
+ input[keys[i]] = await adjustFilePath(input[keys[i]], tsconfig);
257
+ }
258
+ return input;
259
+ }
260
+ function resolveFilePath(filePath, root) {
261
+ if (path.isAbsolute(filePath)) {
262
+ return filePath;
263
+ }
264
+ return filePath.startsWith('/') ? filePath : path.resolve(root || process.cwd(), filePath);
265
+ }
266
+ function parseFilePath(filePath, root) {
267
+ const fullPath = resolveFilePath(filePath, root);
268
+ const directory = path.dirname(fullPath);
269
+ const name = path.basename(fullPath);
270
+ return {
271
+ directory,
272
+ name
273
+ };
274
+ }
275
+
276
+ async function isDirectory(input) {
277
+ try {
278
+ const stat = await fs.promises.stat(input);
279
+ return stat.isDirectory();
280
+ } catch (e) {
281
+ return false;
282
+ }
283
+ }
284
+
285
+ function hasOwnProperty(obj, prop) {
286
+ return Object.prototype.hasOwnProperty.call(obj, prop);
287
+ }
288
+ function hasStringProperty(obj, prop) {
289
+ return hasOwnProperty(obj, prop) && typeof obj[prop] === 'string';
290
+ }
291
+
292
+ function pickRecord(data, keys) {
293
+ const output = {};
294
+ for(let i = 0; i < keys.length; i++){
295
+ output[keys[i]] = data[keys[i]];
296
+ }
297
+ return output;
298
+ }
299
+ function extendObject(target, source) {
300
+ const keys = Object.keys(source);
301
+ for(let i = 0; i < keys.length; i++){
302
+ target[keys[i]] = source[keys[i]];
303
+ }
304
+ return target;
305
+ }
306
+
307
+ function isPromise(p) {
308
+ return locter.isObject(p) && (p instanceof Promise || // eslint-disable-next-line @typescript-eslint/ban-ts-comment
309
+ // @ts-ignore
310
+ typeof p.then === 'function');
311
+ }
312
+
313
+ function getAliasForPath(items, path) {
314
+ if (typeof path === 'undefined' || typeof items === 'undefined') {
315
+ return undefined;
316
+ }
317
+ for(let i = 0; i < items.length; i++){
318
+ if (items[i].key === path) {
319
+ return items[i].value;
320
+ }
321
+ }
322
+ return undefined;
323
+ }
324
+
325
+ function buildKeyWithPrefix(name, prefix) {
326
+ if (prefix) {
327
+ return `${prefix}.${name}`;
328
+ }
329
+ return name;
330
+ }
331
+
332
+ function isQueryOptionDefined(input, option) {
333
+ if (typeof input === 'boolean') {
334
+ return false;
335
+ }
336
+ const options = Array.isArray(option) ? option : [
337
+ option
338
+ ];
339
+ for(let i = 0; i < options.length; i++){
340
+ if (hasOwnProperty(input, options[i])) {
341
+ return true;
342
+ }
343
+ }
344
+ return false;
345
+ }
346
+
347
+ /**
348
+ * Apply parsed fields parameter data on the db query.
349
+ *
350
+ * @param query
351
+ * @param data
352
+ */ /* istanbul ignore next */ function applyQueryFieldsParseOutput(query, data, options = {}) {
353
+ if (data.length === 0) {
354
+ return data;
355
+ }
356
+ query.select(data.map((field)=>{
357
+ const alias = getAliasForPath(options.relations, field.path) || options.defaultAlias || options.defaultPath;
358
+ return buildKeyWithPrefix(field.key, alias);
359
+ }));
360
+ return data;
361
+ }
362
+ /**
363
+ * Apply raw fields parameter data on the db query.
364
+ *
365
+ * @param query
366
+ * @param data
367
+ * @param options
368
+ */ function applyQueryFields(query, data, options) {
369
+ options = options || {};
370
+ if (options.defaultAlias) {
371
+ options.defaultPath = options.defaultAlias;
372
+ }
373
+ return applyQueryFieldsParseOutput(query, rapiq.parseQueryFields(data, options), options);
374
+ }
375
+ /**
376
+ * Apply raw fields parameter data on the db query.
377
+ *
378
+ * @param query
379
+ * @param data
380
+ * @param options
381
+ */ function applyFields(query, data, options) {
382
+ return applyQueryFields(query, data, options);
383
+ }
384
+
385
+ // --------------------------------------------------
386
+ function transformParsedFilters(data, options = {}) {
387
+ const items = [];
388
+ for(let i = 0; i < data.length; i++){
389
+ const alias = getAliasForPath(options.relations, data[i].path) || options.defaultAlias || options.defaultPath;
390
+ const fullKey = buildKeyWithPrefix(data[i].key, alias);
391
+ const filter = data[i];
392
+ const statement = [
393
+ fullKey
394
+ ];
395
+ let bindingKey;
396
+ if (options.bindingKey) {
397
+ bindingKey = options.bindingKey(fullKey).replace('.', '_');
398
+ } else {
399
+ bindingKey = `filter_${fullKey.replace('.', '_')}`;
400
+ }
401
+ if (filter.value === null || typeof filter.value === 'undefined') {
402
+ statement.push('IS');
403
+ if (filter.operator === rapiq.FilterComparisonOperator.NOT_EQUAL) {
404
+ statement.push('NOT');
405
+ }
406
+ statement.push('NULL');
407
+ items.push({
408
+ statement: statement.join(' '),
409
+ binding: {}
410
+ });
411
+ continue;
412
+ }
413
+ switch(filter.operator){
414
+ case rapiq.FilterComparisonOperator.EQUAL:
415
+ case rapiq.FilterComparisonOperator.NOT_EQUAL:
416
+ {
417
+ if (filter.operator === rapiq.FilterComparisonOperator.EQUAL) {
418
+ statement.push('=');
419
+ } else {
420
+ statement.push('!=');
421
+ }
422
+ statement.push(`:${bindingKey}`);
423
+ break;
424
+ }
425
+ case rapiq.FilterComparisonOperator.LIKE:
426
+ case rapiq.FilterComparisonOperator.NOT_LIKE:
427
+ {
428
+ if (filter.operator === rapiq.FilterComparisonOperator.NOT_LIKE) {
429
+ statement.push('NOT');
430
+ }
431
+ statement.push('LIKE');
432
+ statement.push(`:${bindingKey}`);
433
+ filter.value += '%';
434
+ break;
435
+ }
436
+ case rapiq.FilterComparisonOperator.IN:
437
+ case rapiq.FilterComparisonOperator.NOT_IN:
438
+ {
439
+ if (filter.operator === rapiq.FilterComparisonOperator.NOT_IN) {
440
+ statement.push('NOT');
441
+ }
442
+ statement.push('IN');
443
+ statement.push(`(:...${bindingKey})`);
444
+ if (Array.isArray(filter.value)) {
445
+ const nullIndex = filter.value.indexOf(null);
446
+ if (nullIndex !== -1) {
447
+ filter.value.splice(nullIndex, 1);
448
+ statement.unshift('(');
449
+ if (filter.operator === rapiq.FilterComparisonOperator.NOT_IN) {
450
+ statement.push('AND');
451
+ } else {
452
+ statement.push('OR');
453
+ }
454
+ statement.push(fullKey);
455
+ statement.push('IS');
456
+ if (filter.operator === rapiq.FilterComparisonOperator.NOT_IN) {
457
+ statement.push('NOT');
458
+ }
459
+ statement.push('NULL');
460
+ statement.push(')');
461
+ }
462
+ }
463
+ break;
464
+ }
465
+ case rapiq.FilterComparisonOperator.LESS_THAN:
466
+ case rapiq.FilterComparisonOperator.LESS_THAN_EQUAL:
467
+ case rapiq.FilterComparisonOperator.GREATER_THAN:
468
+ case rapiq.FilterComparisonOperator.GREATER_THAN_EQUAL:
469
+ {
470
+ if (filter.operator === rapiq.FilterComparisonOperator.LESS_THAN) {
471
+ statement.push('<');
472
+ } else if (filter.operator === rapiq.FilterComparisonOperator.LESS_THAN_EQUAL) {
473
+ statement.push('<=');
474
+ } else if (filter.operator === rapiq.FilterComparisonOperator.GREATER_THAN) {
475
+ statement.push('>');
476
+ } else {
477
+ statement.push('>=');
478
+ }
479
+ statement.push(`:${bindingKey}`);
480
+ break;
481
+ }
482
+ }
483
+ items.push({
484
+ statement: statement.join(' '),
485
+ binding: {
486
+ [bindingKey]: filter.value
487
+ }
488
+ });
489
+ }
490
+ return items;
491
+ }
492
+ /**
493
+ * Apply transformed filter[s] parameter data on the db query.
494
+ *
495
+ * @param query
496
+ * @param data
497
+ */ function applyFiltersTransformed(query, data) {
498
+ if (data.length === 0) {
499
+ return data;
500
+ }
501
+ /* istanbul ignore next */ query.andWhere(new typeorm.Brackets((qb)=>{
502
+ for(let i = 0; i < data.length; i++){
503
+ if (i === 0) {
504
+ qb.where(data[i].statement, data[i].binding);
505
+ } else {
506
+ qb.andWhere(data[i].statement, data[i].binding);
507
+ }
508
+ }
509
+ }));
510
+ return data;
511
+ }
512
+ /**
513
+ * Apply parsed filter[s] parameter data on the db query.
514
+ *
515
+ * @param query
516
+ * @param data
517
+ * @param options
518
+ */ function applyQueryFiltersParseOutput(query, data, options) {
519
+ applyFiltersTransformed(query, transformParsedFilters(data, options));
520
+ return data;
521
+ }
522
+ // --------------------------------------------------
523
+ /**
524
+ * Apply raw filter[s] parameter data on the db query.
525
+ *
526
+ * @param query
527
+ * @param data
528
+ * @param options
529
+ */ function applyQueryFilters(query, data, options) {
530
+ options = options || {};
531
+ if (options.defaultAlias) {
532
+ options.defaultPath = options.defaultAlias;
533
+ }
534
+ return applyQueryFiltersParseOutput(query, rapiq.parseQueryFilters(data, options), options);
535
+ }
536
+ /**
537
+ * Apply raw filter[s] parameter data on the db query.
538
+ *
539
+ * @param query
540
+ * @param data
541
+ * @param options
542
+ */ function applyFilters(query, data, options) {
543
+ return applyQueryFilters(query, data, options);
544
+ }
545
+
546
+ /**
547
+ * Apply parsed page/pagination parameter data on the db query.
548
+ *
549
+ * @param query
550
+ * @param data
551
+ */ function applyQueryPaginationParseOutput(query, data) {
552
+ /* istanbul ignore next */ if (typeof data.limit !== 'undefined') {
553
+ query.take(data.limit);
554
+ if (typeof data.offset === 'undefined') {
555
+ query.skip(0);
556
+ }
557
+ }
558
+ /* istanbul ignore next */ if (typeof data.offset !== 'undefined') {
559
+ query.skip(data.offset);
560
+ }
561
+ return data;
562
+ }
563
+ /**
564
+ * Apply raw page/pagination parameter data on the db query.
565
+ *
566
+ * @param query
567
+ * @param data
568
+ * @param options
569
+ */ function applyQueryPagination(query, data, options) {
570
+ return applyQueryPaginationParseOutput(query, rapiq.parseQueryPagination(data, options));
571
+ }
572
+ /**
573
+ * Apply raw page/pagination parameter data on the db query.
574
+ *
575
+ * @param query
576
+ * @param data
577
+ * @param options
578
+ */ function applyPagination(query, data, options) {
579
+ return applyQueryPagination(query, data, options);
580
+ }
581
+
582
+ /**
583
+ * Apply parsed include/relation parameter data on the db query.
584
+ *
585
+ * @param query
586
+ * @param data
587
+ * @param options
588
+ */ function applyQueryRelationsParseOutput(query, data, options = {}) {
589
+ for(let i = 0; i < data.length; i++){
590
+ const parts = data[i].key.split('.');
591
+ let key;
592
+ if (parts.length > 1) {
593
+ key = parts.slice(-2).join('.');
594
+ } else {
595
+ key = buildKeyWithPrefix(data[i].key, options.defaultAlias);
596
+ }
597
+ data[i].key = key;
598
+ /* istanbul ignore next */ query.leftJoinAndSelect(key, data[i].value);
599
+ if (options.onJoin) {
600
+ options.onJoin(key, data[i].value, query);
601
+ }
602
+ }
603
+ return data;
604
+ }
605
+ /**
606
+ * Apply raw include/relations parameter data on the db query.
607
+ *
608
+ * @param query
609
+ * @param data
610
+ * @param options
611
+ */ function applyQueryRelations(query, data, options = {}) {
612
+ return applyQueryRelationsParseOutput(query, rapiq.parseQueryRelations(data, options), options);
613
+ }
614
+ /**
615
+ * Apply raw include/relations parameter data on the db query.
616
+ *
617
+ * @param query
618
+ * @param data
619
+ * @param options
620
+ */ function applyRelations(query, data, options = {}) {
621
+ return applyQueryRelations(query, data, options);
622
+ }
623
+
624
+ // --------------------------------------------------
625
+ /**
626
+ * Apply parsed sort parameter data on the db query.
627
+ *
628
+ * @param query
629
+ * @param data
630
+ */ function applyQuerySortParseOutput(query, data) {
631
+ if (data.length === 0) {
632
+ return data;
633
+ }
634
+ const sort = {};
635
+ for(let i = 0; i < data.length; i++){
636
+ const key = buildKeyWithPrefix(data[i].key, data[i].path);
637
+ sort[key] = data[i].value;
638
+ }
639
+ query.orderBy(sort);
640
+ return data;
641
+ }
642
+ /**
643
+ * Apply raw sort parameter data on the db query.
644
+ *
645
+ * @param query
646
+ * @param data
647
+ * @param options
648
+ */ function applyQuerySort(query, data, options) {
649
+ options = options || {};
650
+ if (options.defaultAlias) {
651
+ options.defaultPath = options.defaultAlias;
652
+ }
653
+ return applyQuerySortParseOutput(query, rapiq.parseQuerySort(data, options));
654
+ }
655
+ /**
656
+ * Apply raw sort parameter data on the db query.
657
+ *
658
+ * @param query
659
+ * @param data
660
+ * @param options
661
+ */ function applySort(query, data, options) {
662
+ return applyQuerySort(query, data, options);
663
+ }
664
+
665
+ function applyQueryParseOutput(query, context, options = {}) {
666
+ if (context.fields) {
667
+ applyQueryFieldsParseOutput(query, context.fields, {
668
+ defaultAlias: context.defaultPath,
669
+ relations: context.relations
670
+ });
671
+ }
672
+ if (context.filters) {
673
+ applyQueryFiltersParseOutput(query, context.filters, {
674
+ defaultAlias: context.defaultPath,
675
+ relations: context.relations
676
+ });
677
+ }
678
+ if (context.pagination) {
679
+ applyQueryPaginationParseOutput(query, context.pagination);
680
+ }
681
+ if (context.relations) {
682
+ const relations = {
683
+ defaultAlias: context.defaultPath
684
+ };
685
+ if (locter.isObject(options.relations)) {
686
+ extendObject(relations, options.relations);
687
+ }
688
+ applyQueryRelationsParseOutput(query, context.relations, relations);
689
+ }
690
+ if (context.sort) {
691
+ applyQuerySortParseOutput(query, context.sort);
692
+ }
693
+ return context;
694
+ }
695
+ function applyQuery(query, input, options = {}) {
696
+ if (options.defaultAlias) {
697
+ options.defaultPath = options.defaultAlias;
698
+ }
699
+ if (typeof options.fields === 'undefined' || !isQueryOptionDefined(options.fields, [
700
+ 'allowed',
701
+ 'default'
702
+ ])) {
703
+ options.fields = false;
704
+ }
705
+ if (typeof options.filters === 'undefined' || !isQueryOptionDefined(options.filters, [
706
+ 'allowed',
707
+ 'default'
708
+ ])) {
709
+ options.filters = false;
710
+ }
711
+ if (options.pagination) {
712
+ if (!input.pagination && !input.page) {
713
+ input.pagination = input.pagination || {};
714
+ }
715
+ } else {
716
+ options.pagination = false;
717
+ }
718
+ if (typeof options.relations === 'undefined' || !isQueryOptionDefined(options.relations, [
719
+ 'allowed'
720
+ ])) {
721
+ options.relations = false;
722
+ }
723
+ if (typeof options.sort === 'undefined' || !isQueryOptionDefined(options.sort, [
724
+ 'allowed',
725
+ 'default'
726
+ ])) {
727
+ options.sort = false;
728
+ }
729
+ const output = applyQueryParseOutput(query, rapiq.parseQuery(input, options), options);
730
+ return {
731
+ ...output,
732
+ ...options.defaultAlias ? {
733
+ defaultAlias: options.defaultAlias
734
+ } : {}
735
+ };
736
+ }
737
+
738
+ async function findDataSource(context = {}) {
739
+ let tsconfig;
740
+ if (!context.preserveFilePaths) {
741
+ if (locter.isObject(context.tsconfig)) {
742
+ tsconfig = context.tsconfig;
743
+ } else {
744
+ tsconfig = await readTSConfig(context.tsconfig);
745
+ }
746
+ }
747
+ const files = [
748
+ 'data-source'
749
+ ];
750
+ if (context.fileName) {
751
+ context.fileName = locter.removeFileNameExtension(context.fileName, [
752
+ '.ts',
753
+ '.mts',
754
+ '.cts',
755
+ '.js',
756
+ '.mjs',
757
+ '.cjs'
758
+ ]);
759
+ if (context.fileName !== 'data-source') {
760
+ files.unshift(context.fileName);
761
+ }
762
+ }
763
+ let { directory } = context;
764
+ let directoryIsPattern = false;
765
+ if (context.directory) {
766
+ if (path.isAbsolute(context.directory)) {
767
+ directory = context.directory;
768
+ } else {
769
+ directoryIsPattern = true;
770
+ directory = safeReplaceWindowsSeparator(context.directory);
771
+ }
772
+ if (!context.preserveFilePaths) {
773
+ directory = await adjustFilePath(directory, tsconfig);
774
+ }
775
+ }
776
+ const lookupPaths = [];
777
+ for(let j = 0; j < files.length; j++){
778
+ if (directory && directoryIsPattern) {
779
+ lookupPaths.push(path.posix.join(directory, files[j]));
780
+ }
781
+ lookupPaths.push(...[
782
+ path.posix.join('src', files[j]),
783
+ path.posix.join('src/{db,database}', files[j])
784
+ ]);
785
+ }
786
+ files.push(...lookupPaths);
787
+ if (!context.preserveFilePaths) {
788
+ for(let j = 0; j < files.length; j++){
789
+ files[j] = await adjustFilePath(files[j], tsconfig);
790
+ }
791
+ }
792
+ for(let i = 0; i < files.length; i++){
793
+ const info = await locter.locate(`${files[i]}.{js,cjs,mjs,ts,cts,mts}`, {
794
+ path: [
795
+ process.cwd(),
796
+ ...directory && !directoryIsPattern ? [
797
+ directory
798
+ ] : []
799
+ ],
800
+ ignore: [
801
+ '**/*.d.ts'
802
+ ]
803
+ });
804
+ if (info) {
805
+ let moduleRecord = await locter.load(info);
806
+ if (isPromise(moduleRecord)) {
807
+ moduleRecord = await moduleRecord;
808
+ }
809
+ if (typeorm.InstanceChecker.isDataSource(moduleRecord)) {
810
+ return moduleRecord;
811
+ }
812
+ if (!locter.isObject(moduleRecord)) {
813
+ continue;
814
+ }
815
+ const keys = Object.keys(moduleRecord);
816
+ for(let j = 0; j < keys.length; j++){
817
+ let value = moduleRecord[keys[j]];
818
+ if (isPromise(value)) {
819
+ value = await value;
820
+ }
821
+ if (typeorm.InstanceChecker.isDataSource(value)) {
822
+ return value;
823
+ }
824
+ }
825
+ }
826
+ }
827
+ return undefined;
828
+ }
829
+
830
+ /*
831
+ * Copyright (c) 2023-2023.
832
+ * Author Peter Placzek (tada5hi)
833
+ * For the full copyright and license information,
834
+ * view the LICENSE file that was distributed with this source code.
835
+ */ var EnvironmentName = /*#__PURE__*/ function(EnvironmentName) {
836
+ EnvironmentName["DEVELOPMENT"] = "development";
837
+ EnvironmentName["PRODUCTION"] = "production";
838
+ EnvironmentName["TEST"] = "test";
839
+ return EnvironmentName;
840
+ }({});
841
+ var EnvironmentVariableName = /*#__PURE__*/ function(EnvironmentVariableName) {
842
+ EnvironmentVariableName["ENV"] = "NODE_ENV";
843
+ // Seeder
844
+ EnvironmentVariableName["SEEDS"] = "DB_SEEDS";
845
+ EnvironmentVariableName["SEEDS_ALT"] = "TYPEORM_SEEDING_SEEDS";
846
+ EnvironmentVariableName["FACTORIES"] = "DB_FACTORIES";
847
+ EnvironmentVariableName["FACTORIES_ALT"] = "TYPEORM_SEEDING_FACTORIES";
848
+ // Database
849
+ EnvironmentVariableName["TYPE"] = "DB_TYPE";
850
+ EnvironmentVariableName["TYPE_ALT"] = "TYPEORM_CONNECTION";
851
+ EnvironmentVariableName["URL"] = "DB_URL";
852
+ EnvironmentVariableName["URL_ALT"] = "TYPEORM_URL";
853
+ EnvironmentVariableName["HOST"] = "DB_HOST";
854
+ EnvironmentVariableName["HOST_ALT"] = "TYPEORM_HOST";
855
+ EnvironmentVariableName["PORT"] = "DB_PORT";
856
+ EnvironmentVariableName["PORT_ALT"] = "TYPEORM_PORT";
857
+ EnvironmentVariableName["USERNAME"] = "DB_USERNAME";
858
+ EnvironmentVariableName["USERNAME_ALT"] = "TYPEORM_USERNAME";
859
+ EnvironmentVariableName["PASSWORD"] = "DB_PASSWORD";
860
+ EnvironmentVariableName["PASSWORD_ALT"] = "TYPEORM_PASSWORD";
861
+ EnvironmentVariableName["DATABASE"] = "DB_DATABASE";
862
+ EnvironmentVariableName["DATABASE_ALT"] = "TYPEORM_DATABASE";
863
+ EnvironmentVariableName["SID"] = "DB_SID";
864
+ EnvironmentVariableName["SID_ALT"] = "TYPEORM_SID";
865
+ EnvironmentVariableName["SCHEMA"] = "DB_SCHEMA";
866
+ EnvironmentVariableName["SCHEMA_ALT"] = "TYPEORM_SCHEMA";
867
+ EnvironmentVariableName["SCHEMA_DROP"] = "DB_DROP_SCHEMA";
868
+ EnvironmentVariableName["SCHEMA_DROP_ALT"] = "TYPEORM_DROP_SCHEMA";
869
+ EnvironmentVariableName["DRIVER_EXTRA"] = "DB_DRIVER_EXTRA";
870
+ EnvironmentVariableName["DRIVER_EXTRA_ALT"] = "TYPEORM_DRIVER_EXTRA";
871
+ EnvironmentVariableName["SYNCHRONIZE"] = "DB_SYNCHRONIZE";
872
+ EnvironmentVariableName["SYNCHRONIZE_ALT"] = "TYPEORM_SYNCHRONIZE";
873
+ EnvironmentVariableName["MIGRATIONS"] = "DB_MIGRATIONS";
874
+ EnvironmentVariableName["MIGRATIONS_ALT"] = "TYPEORM_MIGRATIONS";
875
+ EnvironmentVariableName["MIGRATIONS_RUN"] = "DB_MIGRATIONS_RUN";
876
+ EnvironmentVariableName["MIGRATIONS_RUN_ALT"] = "TYPEORM_MIGRATIONS_RUN";
877
+ EnvironmentVariableName["MIGRATIONS_TABLE_NAME"] = "DB_MIGRATIONS_TABLE_NAME";
878
+ EnvironmentVariableName["MIGRATIONS_TABLE_NAME_ALT"] = "TYPEORM_MIGRATIONS_TABLE_NAME";
879
+ EnvironmentVariableName["ENTITIES"] = "DB_ENTITIES";
880
+ EnvironmentVariableName["ENTITIES_ALT"] = "TYPEORM_ENTITIES";
881
+ EnvironmentVariableName["ENTITY_PREFIX"] = "DB_ENTITY_PREFIX";
882
+ EnvironmentVariableName["ENTITY_PREFIX_ALT"] = "TYPEORM_ENTITY_PREFIX";
883
+ EnvironmentVariableName["METADATA_TABLE_NAME"] = "DB_METADATA_TABLE_NAME";
884
+ EnvironmentVariableName["METADATA_TABLE_NAME_ALT"] = "TYPEORM_METADATA_TABLE_NAME";
885
+ EnvironmentVariableName["SUBSCRIBERS"] = "DB_SUBSCRIBERS";
886
+ EnvironmentVariableName["SUBSCRIBERS_ALT"] = "TYPEORM_SUBSCRIBERS";
887
+ EnvironmentVariableName["LOGGING"] = "DB_LOGGING";
888
+ EnvironmentVariableName["LOGGING_ALT"] = "TYPEORM_LOGGING";
889
+ EnvironmentVariableName["LOGGER"] = "DB_LOGGER";
890
+ EnvironmentVariableName["LOGGER_ALT"] = "TYPEORM_LOGGER";
891
+ EnvironmentVariableName["MAX_QUERY_EXECUTION_TIME"] = "DB_MAX_QUERY_EXECUTION_TIME";
892
+ EnvironmentVariableName["MAX_QUERY_EXECUTION_TIME_ALT"] = "TYPEORM_MAX_QUERY_EXECUTION_TIME";
893
+ EnvironmentVariableName["DEBUG"] = "DB_DEBUG";
894
+ EnvironmentVariableName["DEBUG_ALT"] = "TYPEORM_DEBUG";
895
+ EnvironmentVariableName["UUID_EXTENSION"] = "DB_UUID_EXTENSION";
896
+ EnvironmentVariableName["UUID_EXTENSION_ALT"] = "TYPEORM_UUID_EXTENSION";
897
+ EnvironmentVariableName["CACHE"] = "DB_CACHE";
898
+ EnvironmentVariableName["CACHE_ALT"] = "TYPEORM_CACHE";
899
+ EnvironmentVariableName["CACHE_ALWAYS_ENABLED"] = "DB_CACHE_ALWAYS_ENABLED";
900
+ EnvironmentVariableName["CACHE_ALWAYS_ENABLED_ALT"] = "TYPEORM_CACHE_ALWAYS_ENABLED";
901
+ EnvironmentVariableName["CACHE_OPTIONS"] = "DB_CACHE_OPTIONS";
902
+ EnvironmentVariableName["CACHE_OPTIONS_ALT"] = "TYPEORM_CACHE_OPTIONS";
903
+ EnvironmentVariableName["CACHE_DURATION"] = "DB_CACHE_DURATION";
904
+ EnvironmentVariableName["CACHE_DURATION_ALT"] = "TYPEORM_CACHE_DURATION";
905
+ return EnvironmentVariableName;
906
+ }({});
907
+
908
+ function transformLogging(input) {
909
+ const value = envix.toBool(input);
910
+ if (typeof value === 'boolean') {
911
+ return value;
912
+ }
913
+ if (input === 'all') {
914
+ return 'all';
915
+ }
916
+ return envix.toArray(input) ?? [];
917
+ }
918
+ function transformCache(input) {
919
+ const value = envix.toBool(input);
920
+ if (typeof value === 'boolean') {
921
+ return value;
922
+ }
923
+ if (input === 'redis' || input === 'ioredis' || input === 'database' || input === 'ioredis/cluster') {
924
+ let options;
925
+ const envCacheOptions = envix.oneOf([
926
+ envix.read(EnvironmentVariableName.CACHE_OPTIONS),
927
+ envix.read(EnvironmentVariableName.CACHE_OPTIONS_ALT)
928
+ ]);
929
+ if (envCacheOptions) {
930
+ options = JSON.parse(envCacheOptions);
931
+ }
932
+ return {
933
+ type: input,
934
+ options,
935
+ alwaysEnabled: envix.oneOf([
936
+ envix.readBool(EnvironmentVariableName.CACHE_ALWAYS_ENABLED),
937
+ envix.readBool(EnvironmentVariableName.CACHE_ALWAYS_ENABLED_ALT)
938
+ ]),
939
+ duration: envix.oneOf([
940
+ envix.readInt(EnvironmentVariableName.CACHE_DURATION),
941
+ envix.readInt(EnvironmentVariableName.CACHE_DURATION_ALT)
942
+ ])
943
+ };
944
+ }
945
+ return undefined;
946
+ }
947
+
948
+ let instance$1;
949
+ function useEnv(key) {
950
+ if (typeof instance$1 !== 'undefined') {
951
+ if (typeof key === 'string') {
952
+ return instance$1[key];
953
+ }
954
+ return instance$1;
955
+ }
956
+ const output = {
957
+ env: envix.read(EnvironmentVariableName.ENV, EnvironmentName.DEVELOPMENT),
958
+ // Seeder
959
+ seeds: envix.oneOf([
960
+ envix.readArray(EnvironmentVariableName.SEEDS),
961
+ envix.readArray(EnvironmentVariableName.SEEDS_ALT)
962
+ ]) ?? [],
963
+ factories: envix.oneOf([
964
+ envix.readArray(EnvironmentVariableName.FACTORIES),
965
+ envix.readArray(EnvironmentVariableName.FACTORIES_ALT)
966
+ ]) ?? [],
967
+ // Database
968
+ url: envix.oneOf([
969
+ envix.read(EnvironmentVariableName.URL),
970
+ envix.read(EnvironmentVariableName.URL_ALT)
971
+ ]),
972
+ host: envix.oneOf([
973
+ envix.read(EnvironmentVariableName.HOST),
974
+ envix.read(EnvironmentVariableName.HOST_ALT)
975
+ ]),
976
+ port: envix.oneOf([
977
+ envix.readInt(EnvironmentVariableName.PORT),
978
+ envix.readInt(EnvironmentVariableName.PORT_ALT)
979
+ ]),
980
+ username: envix.oneOf([
981
+ envix.read(EnvironmentVariableName.USERNAME),
982
+ envix.read(EnvironmentVariableName.USERNAME_ALT)
983
+ ]),
984
+ password: envix.oneOf([
985
+ envix.read(EnvironmentVariableName.PASSWORD),
986
+ envix.read(EnvironmentVariableName.PASSWORD_ALT)
987
+ ]),
988
+ database: envix.oneOf([
989
+ envix.read(EnvironmentVariableName.DATABASE),
990
+ envix.read(EnvironmentVariableName.DATABASE_ALT)
991
+ ]),
992
+ sid: envix.oneOf([
993
+ envix.read(EnvironmentVariableName.SID),
994
+ envix.read(EnvironmentVariableName.SID_ALT)
995
+ ]),
996
+ schema: envix.oneOf([
997
+ envix.read(EnvironmentVariableName.SCHEMA),
998
+ envix.read(EnvironmentVariableName.SCHEMA_ALT)
999
+ ]),
1000
+ extra: envix.oneOf([
1001
+ envix.read(EnvironmentVariableName.DRIVER_EXTRA),
1002
+ envix.read(EnvironmentVariableName.DRIVER_EXTRA_ALT)
1003
+ ]),
1004
+ synchronize: envix.oneOf([
1005
+ envix.readBool(EnvironmentVariableName.SYNCHRONIZE),
1006
+ envix.readBool(EnvironmentVariableName.SYNCHRONIZE_ALT)
1007
+ ]),
1008
+ schemaDrop: envix.oneOf([
1009
+ envix.readBool(EnvironmentVariableName.SCHEMA_DROP),
1010
+ envix.readBool(EnvironmentVariableName.SCHEMA_DROP_ALT)
1011
+ ]),
1012
+ migrationsRun: envix.oneOf([
1013
+ envix.readBool(EnvironmentVariableName.MIGRATIONS_RUN),
1014
+ envix.readBool(EnvironmentVariableName.MIGRATIONS_RUN_ALT)
1015
+ ]),
1016
+ entities: envix.oneOf([
1017
+ envix.readArray(EnvironmentVariableName.ENTITIES),
1018
+ envix.readArray(EnvironmentVariableName.ENTITIES_ALT)
1019
+ ]) ?? [],
1020
+ migrations: envix.oneOf([
1021
+ envix.readArray(EnvironmentVariableName.MIGRATIONS),
1022
+ envix.readArray(EnvironmentVariableName.MIGRATIONS_ALT)
1023
+ ]) ?? [],
1024
+ migrationsTableName: envix.oneOf([
1025
+ envix.read(EnvironmentVariableName.MIGRATIONS_TABLE_NAME),
1026
+ envix.read(EnvironmentVariableName.MIGRATIONS_TABLE_NAME_ALT)
1027
+ ]),
1028
+ metadataTableName: envix.oneOf([
1029
+ envix.read(EnvironmentVariableName.METADATA_TABLE_NAME),
1030
+ envix.read(EnvironmentVariableName.METADATA_TABLE_NAME_ALT)
1031
+ ]),
1032
+ subscribers: envix.oneOf([
1033
+ envix.readArray(EnvironmentVariableName.SUBSCRIBERS),
1034
+ envix.readArray(EnvironmentVariableName.SUBSCRIBERS_ALT)
1035
+ ]) ?? [],
1036
+ logging: transformLogging(envix.oneOf([
1037
+ envix.read(EnvironmentVariableName.LOGGING),
1038
+ envix.read(EnvironmentVariableName.LOGGING_ALT)
1039
+ ])),
1040
+ logger: envix.oneOf([
1041
+ envix.read(EnvironmentVariableName.LOGGER),
1042
+ envix.read(EnvironmentVariableName.LOGGER_ALT)
1043
+ ]),
1044
+ entityPrefix: envix.oneOf([
1045
+ envix.read(EnvironmentVariableName.ENTITY_PREFIX),
1046
+ envix.read(EnvironmentVariableName.ENTITY_PREFIX_ALT)
1047
+ ]),
1048
+ maxQueryExecutionTime: envix.oneOf([
1049
+ envix.readInt(EnvironmentVariableName.MAX_QUERY_EXECUTION_TIME),
1050
+ envix.readInt(EnvironmentVariableName.MAX_QUERY_EXECUTION_TIME_ALT)
1051
+ ]),
1052
+ debug: envix.oneOf([
1053
+ envix.read(EnvironmentVariableName.DEBUG),
1054
+ envix.read(EnvironmentVariableName.DEBUG_ALT)
1055
+ ]),
1056
+ cache: transformCache(envix.oneOf([
1057
+ envix.read(EnvironmentVariableName.CACHE),
1058
+ envix.read(EnvironmentVariableName.CACHE_ALT)
1059
+ ])),
1060
+ uuidExtension: envix.oneOf([
1061
+ envix.read(EnvironmentVariableName.UUID_EXTENSION),
1062
+ envix.read(EnvironmentVariableName.UUID_EXTENSION_ALT)
1063
+ ])
1064
+ };
1065
+ if (output.extra) {
1066
+ output.extra = JSON.parse(output.extra); // todo: ensure record<string,any> ??
1067
+ }
1068
+ let type;
1069
+ const envType = envix.oneOf([
1070
+ envix.read(EnvironmentVariableName.TYPE),
1071
+ envix.read(EnvironmentVariableName.TYPE_ALT)
1072
+ ]);
1073
+ if (envType) {
1074
+ type = envType;
1075
+ } else {
1076
+ const envURL = envix.oneOf([
1077
+ envix.read(EnvironmentVariableName.URL),
1078
+ envix.read(EnvironmentVariableName.URL_ALT)
1079
+ ]);
1080
+ if (envURL) {
1081
+ [type] = envURL.split('://');
1082
+ }
1083
+ }
1084
+ if (type) {
1085
+ output.type = type; // todo: maybe validation here
1086
+ }
1087
+ instance$1 = output;
1088
+ if (typeof key === 'string') {
1089
+ return output[key];
1090
+ }
1091
+ return instance$1;
1092
+ }
1093
+ function resetEnv() {
1094
+ if (typeof instance$1 !== 'undefined') {
1095
+ instance$1 = undefined;
1096
+ }
1097
+ }
1098
+
1099
+ const merge = smob.createMerger({
1100
+ strategy: (target, key, value)=>{
1101
+ if (typeof target[key] === 'undefined') {
1102
+ target[key] = value;
1103
+ return target;
1104
+ }
1105
+ return undefined;
1106
+ }
1107
+ });
1108
+ function mergeDataSourceOptions(target, source) {
1109
+ if (target.type !== source.type) {
1110
+ return target;
1111
+ }
1112
+ return merge(target, source);
1113
+ }
1114
+
1115
+ function hasEnvDataSourceOptions() {
1116
+ return !!useEnv('type');
1117
+ }
1118
+ /* istanbul ignore next */ function readDataSourceOptionsFromEnv() {
1119
+ if (!hasEnvDataSourceOptions()) {
1120
+ return undefined;
1121
+ }
1122
+ // todo: include seeder options
1123
+ const base = {
1124
+ type: useEnv('type'),
1125
+ entities: useEnv('entities'),
1126
+ subscribers: useEnv('subscribers'),
1127
+ migrations: useEnv('migrations'),
1128
+ migrationsTableName: useEnv('migrationsTableName'),
1129
+ // migrationsTransactionMode: useEnv('migra')
1130
+ metadataTableName: useEnv('metadataTableName'),
1131
+ logging: useEnv('logging'),
1132
+ logger: useEnv('logger'),
1133
+ maxQueryExecutionTime: useEnv('maxQueryExecutionTime'),
1134
+ synchronize: useEnv('synchronize'),
1135
+ migrationsRun: useEnv('migrationsRun'),
1136
+ dropSchema: useEnv('schemaDrop'),
1137
+ entityPrefix: useEnv('entityPrefix'),
1138
+ extra: useEnv('extra'),
1139
+ cache: useEnv('cache')
1140
+ };
1141
+ const credentialOptions = {
1142
+ url: useEnv('url'),
1143
+ host: useEnv('host'),
1144
+ port: useEnv('port'),
1145
+ username: useEnv('username'),
1146
+ password: useEnv('password'),
1147
+ database: useEnv('database')
1148
+ };
1149
+ if (base.type === 'mysql' || base.type === 'mariadb') {
1150
+ return {
1151
+ ...base,
1152
+ ...credentialOptions,
1153
+ type: base.type
1154
+ };
1155
+ }
1156
+ if (base.type === 'postgres') {
1157
+ return {
1158
+ ...base,
1159
+ ...credentialOptions,
1160
+ type: base.type,
1161
+ schema: useEnv('schema'),
1162
+ uuidExtension: useEnv('uuidExtension')
1163
+ };
1164
+ }
1165
+ if (base.type === 'cockroachdb') {
1166
+ return {
1167
+ ...base,
1168
+ ...credentialOptions,
1169
+ type: base.type,
1170
+ schema: useEnv('schema'),
1171
+ timeTravelQueries: true
1172
+ };
1173
+ }
1174
+ if (base.type === 'sqlite') {
1175
+ return {
1176
+ ...base,
1177
+ type: base.type,
1178
+ database: useEnv('database') || 'db.sqlite'
1179
+ };
1180
+ }
1181
+ if (base.type === 'better-sqlite3') {
1182
+ return {
1183
+ ...base,
1184
+ type: base.type,
1185
+ database: useEnv('database') || 'db.sqlite'
1186
+ };
1187
+ }
1188
+ if (base.type === 'mssql') {
1189
+ return {
1190
+ ...base,
1191
+ ...credentialOptions,
1192
+ type: base.type,
1193
+ schema: useEnv('schema')
1194
+ };
1195
+ }
1196
+ if (base.type === 'oracle') {
1197
+ return {
1198
+ ...base,
1199
+ ...credentialOptions,
1200
+ type: base.type,
1201
+ sid: useEnv('sid')
1202
+ };
1203
+ }
1204
+ return {
1205
+ ...base,
1206
+ ...credentialOptions
1207
+ };
1208
+ }
1209
+ function mergeDataSourceOptionsWithEnv(options) {
1210
+ const env = readDataSourceOptionsFromEnv();
1211
+ if (!env) {
1212
+ return options;
1213
+ }
1214
+ return mergeDataSourceOptions(env, options);
1215
+ }
1216
+
1217
+ /**
1218
+ * Build DataSourceOptions from DataSource or from configuration.
1219
+ *
1220
+ * @param context
1221
+ */ async function buildDataSourceOptions(context = {}) {
1222
+ const directory = context.directory || process.cwd();
1223
+ let tsconfig;
1224
+ if (!context.preserveFilePaths) {
1225
+ if (locter.isObject(context.tsconfig)) {
1226
+ tsconfig = context.tsconfig;
1227
+ } else {
1228
+ tsconfig = await readTSConfig(context.tsconfig);
1229
+ }
1230
+ }
1231
+ const dataSource = await findDataSource({
1232
+ directory,
1233
+ fileName: context.dataSourceName,
1234
+ tsconfig
1235
+ });
1236
+ if (dataSource) {
1237
+ if (context.preserveFilePaths) {
1238
+ return mergeDataSourceOptionsWithEnv(dataSource.options);
1239
+ }
1240
+ const options = await adjustFilePaths(dataSource.options, [
1241
+ 'entities',
1242
+ 'migrations',
1243
+ 'subscribers'
1244
+ ], tsconfig);
1245
+ return mergeDataSourceOptionsWithEnv(options);
1246
+ }
1247
+ const options = readDataSourceOptionsFromEnv();
1248
+ if (options) {
1249
+ if (context.preserveFilePaths) {
1250
+ return options;
1251
+ }
1252
+ return adjustFilePaths(options, [
1253
+ 'entities',
1254
+ 'migrations',
1255
+ 'subscribers'
1256
+ ], tsconfig);
1257
+ }
1258
+ throw OptionsError.notFound();
1259
+ }
1260
+
1261
+ const instances$1 = {};
1262
+ const instancePromises = {};
1263
+ function setDataSourceOptions(options, alias) {
1264
+ instances$1[alias || 'default'] = options;
1265
+ }
1266
+ function hasDataSourceOptions(alias) {
1267
+ return Object.prototype.hasOwnProperty.call(instances$1, alias || 'default');
1268
+ }
1269
+ async function useDataSourceOptions(alias) {
1270
+ alias = alias || 'default';
1271
+ if (Object.prototype.hasOwnProperty.call(instances$1, alias)) {
1272
+ return instances$1[alias];
1273
+ }
1274
+ /* istanbul ignore next */ if (!Object.prototype.hasOwnProperty.call(instancePromises, alias)) {
1275
+ instancePromises[alias] = buildDataSourceOptions().catch((e)=>{
1276
+ if (alias) {
1277
+ delete instancePromises[alias];
1278
+ }
1279
+ throw e;
1280
+ });
1281
+ }
1282
+ instances$1[alias] = await instancePromises[alias];
1283
+ return instances$1[alias];
1284
+ }
1285
+
1286
+ const instances = {};
1287
+ const initializePromises = {};
1288
+ const optionsPromises = {};
1289
+ function setDataSource(dataSource, alias) {
1290
+ alias = alias || 'default';
1291
+ instances[alias] = dataSource;
1292
+ }
1293
+ function hasDataSource(alias) {
1294
+ alias = alias || 'default';
1295
+ return Object.prototype.hasOwnProperty.call(instances, alias);
1296
+ }
1297
+ function unsetDataSource(alias) {
1298
+ alias = alias || 'default';
1299
+ if (Object.prototype.hasOwnProperty.call(instances, alias)) {
1300
+ delete instances[alias];
1301
+ }
1302
+ /* istanbul ignore next */ if (Object.prototype.hasOwnProperty.call(optionsPromises, alias)) {
1303
+ delete optionsPromises[alias];
1304
+ }
1305
+ /* istanbul ignore next */ if (Object.prototype.hasOwnProperty.call(initializePromises, alias)) {
1306
+ delete initializePromises[alias];
1307
+ }
1308
+ }
1309
+ async function useDataSource(alias) {
1310
+ alias = alias || 'default';
1311
+ if (Object.prototype.hasOwnProperty.call(instances, alias)) {
1312
+ if (!instances[alias].isInitialized) {
1313
+ /* istanbul ignore next */ if (!Object.prototype.hasOwnProperty.call(initializePromises, alias)) {
1314
+ initializePromises[alias] = instances[alias].initialize().catch((e)=>{
1315
+ if (alias) {
1316
+ delete initializePromises[alias];
1317
+ }
1318
+ throw e;
1319
+ });
1320
+ }
1321
+ await initializePromises[alias];
1322
+ }
1323
+ return instances[alias];
1324
+ }
1325
+ /* istanbul ignore next */ if (!Object.prototype.hasOwnProperty.call(optionsPromises, alias)) {
1326
+ optionsPromises[alias] = useDataSourceOptions(alias).catch((e)=>{
1327
+ if (alias) {
1328
+ delete optionsPromises[alias];
1329
+ }
1330
+ throw e;
1331
+ });
1332
+ }
1333
+ const options = await optionsPromises[alias];
1334
+ const dataSource = new typeorm.DataSource(options);
1335
+ /* istanbul ignore next */ if (!Object.prototype.hasOwnProperty.call(initializePromises, alias)) {
1336
+ initializePromises[alias] = dataSource.initialize().catch((e)=>{
1337
+ if (alias) {
1338
+ delete initializePromises[alias];
1339
+ }
1340
+ throw e;
1341
+ });
1342
+ }
1343
+ await initializePromises[alias];
1344
+ instances[alias] = dataSource;
1345
+ return dataSource;
1346
+ }
1347
+
1348
+ /**
1349
+ * Check database setup progress.
1350
+ *
1351
+ * @param context
1352
+ */ async function checkDatabase(context = {}) {
1353
+ const result = {
1354
+ exists: true,
1355
+ schema: false,
1356
+ migrationsPending: []
1357
+ };
1358
+ let dataSource;
1359
+ let dataSourceCleanup;
1360
+ if (typeof context.dataSource === 'undefined' && typeof context.options === 'undefined' && hasDataSource(context.alias)) {
1361
+ dataSource = await useDataSource(context.alias);
1362
+ if (dataSource.options.synchronize || dataSource.options.migrationsRun) {
1363
+ dataSource = new typeorm.DataSource({
1364
+ ...dataSource.options,
1365
+ synchronize: false,
1366
+ migrationsRun: false
1367
+ });
1368
+ dataSourceCleanup = true;
1369
+ } else {
1370
+ dataSourceCleanup = false;
1371
+ }
1372
+ } else {
1373
+ let dataSourceOptions;
1374
+ if (context.options) {
1375
+ dataSourceOptions = context.options;
1376
+ } else {
1377
+ dataSourceOptions = await useDataSourceOptions(context.alias);
1378
+ }
1379
+ dataSource = new typeorm.DataSource({
1380
+ ...dataSourceOptions,
1381
+ synchronize: false,
1382
+ migrationsRun: false
1383
+ });
1384
+ dataSourceCleanup = context.dataSourceCleanup ?? true;
1385
+ }
1386
+ try {
1387
+ if (!dataSource.isInitialized) {
1388
+ await dataSource.initialize();
1389
+ }
1390
+ } catch (e) {
1391
+ result.exists = false;
1392
+ return result;
1393
+ }
1394
+ const queryRunner = dataSource.createQueryRunner();
1395
+ if (dataSource.migrations && dataSource.migrations.length > 0) {
1396
+ const migrationExecutor = new typeorm.MigrationExecutor(dataSource, queryRunner);
1397
+ result.migrationsPending = await migrationExecutor.getPendingMigrations();
1398
+ result.schema = result.migrationsPending.length === 0;
1399
+ } else {
1400
+ let schema;
1401
+ if (hasStringProperty(dataSource.driver.options, 'schema')) {
1402
+ schema = dataSource.driver.options.schema;
1403
+ }
1404
+ const migrationsTableName = dataSource.driver.buildTableName(dataSource.options.migrationsTableName || 'migrations', schema, dataSource.driver.database);
1405
+ const migrationsTableExists = await queryRunner.hasTable(migrationsTableName);
1406
+ if (migrationsTableExists) {
1407
+ result.schema = dataSource.entityMetadatas.length === 0;
1408
+ } else {
1409
+ const tableNames = dataSource.entityMetadatas.map((entityMetadata)=>entityMetadata.tablePath);
1410
+ const tables = await queryRunner.getTables(tableNames);
1411
+ if (tables.length === dataSource.entityMetadatas.length) {
1412
+ const { upQueries } = await dataSource.driver.createSchemaBuilder().log();
1413
+ result.schema = upQueries.length === 0;
1414
+ } else {
1415
+ result.schema = false;
1416
+ }
1417
+ }
1418
+ }
1419
+ await queryRunner.release();
1420
+ if (dataSourceCleanup) {
1421
+ await dataSource.destroy();
1422
+ }
1423
+ return result;
1424
+ }
1425
+
1426
+ function getCharsetFromDataSourceOptions(options) {
1427
+ if (hasOwnProperty(options, 'charset') && typeof options.charset === 'string') {
1428
+ return options.charset;
1429
+ }
1430
+ if (typeof options?.extra?.charset === 'string') {
1431
+ return options.extra.charset;
1432
+ }
1433
+ return undefined;
1434
+ }
1435
+
1436
+ function getCharacterSetFromDataSourceOptions(options) {
1437
+ if (hasOwnProperty(options, 'characterSet') && typeof options.characterSet === 'string') {
1438
+ return options.characterSet;
1439
+ }
1440
+ if (typeof options?.extra?.characterSet === 'string') {
1441
+ return options.extra.characterSet;
1442
+ }
1443
+ return undefined;
1444
+ }
1445
+
1446
+ function buildDriverOptions(options) {
1447
+ let driverOptions;
1448
+ switch(options.type){
1449
+ case 'mysql':
1450
+ case 'mariadb':
1451
+ case 'postgres':
1452
+ case 'cockroachdb':
1453
+ case 'mssql':
1454
+ case 'oracle':
1455
+ driverOptions = DriverUtils.DriverUtils.buildDriverOptions(options.replication ? options.replication.master : options);
1456
+ break;
1457
+ case 'mongodb':
1458
+ driverOptions = DriverUtils.DriverUtils.buildMongoDBDriverOptions(options);
1459
+ break;
1460
+ default:
1461
+ driverOptions = DriverUtils.DriverUtils.buildDriverOptions(options);
1462
+ }
1463
+ const charset = getCharsetFromDataSourceOptions(options);
1464
+ const characterSet = getCharacterSetFromDataSourceOptions(options);
1465
+ return {
1466
+ host: driverOptions.host,
1467
+ user: driverOptions.user || driverOptions.username,
1468
+ password: driverOptions.password,
1469
+ database: driverOptions.database,
1470
+ port: driverOptions.port,
1471
+ ...charset ? {
1472
+ charset
1473
+ } : {},
1474
+ ...characterSet ? {
1475
+ characterSet
1476
+ } : {},
1477
+ ...driverOptions.ssl ? {
1478
+ ssl: driverOptions.ssl
1479
+ } : {},
1480
+ ...driverOptions.url ? {
1481
+ url: driverOptions.url
1482
+ } : {},
1483
+ ...driverOptions.connectString ? {
1484
+ connectString: driverOptions.connectString
1485
+ } : {},
1486
+ ...driverOptions.sid ? {
1487
+ sid: driverOptions.sid
1488
+ } : {},
1489
+ ...driverOptions.serviceName ? {
1490
+ serviceName: driverOptions.serviceName
1491
+ } : {},
1492
+ ...driverOptions.template ? {
1493
+ template: driverOptions.template
1494
+ } : {},
1495
+ ...options.extra ? {
1496
+ extra: options.extra
1497
+ } : {},
1498
+ ...driverOptions.domain ? {
1499
+ domain: driverOptions.domain
1500
+ } : {},
1501
+ ...driverOptions.schema ? {
1502
+ schema: driverOptions.schema
1503
+ } : {}
1504
+ };
1505
+ }
1506
+
1507
+ const driversRequireDatabaseOption = [
1508
+ 'sqlite',
1509
+ 'better-sqlite3'
1510
+ ];
1511
+ function createDriver(connectionOptions) {
1512
+ const fakeConnection = {
1513
+ options: {
1514
+ type: connectionOptions.type,
1515
+ ...driversRequireDatabaseOption.indexOf(connectionOptions.type) !== -1 ? {
1516
+ database: connectionOptions.database
1517
+ } : {}
1518
+ }
1519
+ };
1520
+ const driverFactory = new DriverFactory.DriverFactory();
1521
+ return driverFactory.create(fakeConnection);
1522
+ }
1523
+
1524
+ async function normalizeDataSourceOptions(context) {
1525
+ let options;
1526
+ if (context.options) {
1527
+ options = {
1528
+ ...context.options
1529
+ };
1530
+ } else {
1531
+ const dataSource = await findDataSource(context.findOptions);
1532
+ if (dataSource) {
1533
+ options = {
1534
+ ...dataSource.options
1535
+ };
1536
+ }
1537
+ if (!options) {
1538
+ options = {
1539
+ ...await buildDataSourceOptions()
1540
+ };
1541
+ }
1542
+ }
1543
+ return {
1544
+ ...options,
1545
+ subscribers: [],
1546
+ synchronize: false,
1547
+ migrationsRun: false,
1548
+ dropSchema: false
1549
+ };
1550
+ }
1551
+ async function buildDatabaseCreateContext(input = {}) {
1552
+ return {
1553
+ ...input,
1554
+ options: await normalizeDataSourceOptions(input),
1555
+ synchronize: input.synchronize ?? true,
1556
+ ifNotExist: input.ifNotExist ?? true
1557
+ };
1558
+ }
1559
+ async function buildDatabaseDropContext(input = {}) {
1560
+ return {
1561
+ ...input,
1562
+ options: await normalizeDataSourceOptions(input),
1563
+ ifExist: input.ifExist ?? true
1564
+ };
1565
+ }
1566
+
1567
+ class GenerateCommand extends MigrationGenerateCommand.MigrationGenerateCommand {
1568
+ static prettify(query) {
1569
+ return this.prettifyQuery(query);
1570
+ }
1571
+ }
1572
+ function queryParams(parameters) {
1573
+ if (!parameters || !parameters.length) {
1574
+ return '';
1575
+ }
1576
+ return `, ${JSON.stringify(parameters)}`;
1577
+ }
1578
+ function buildTemplate(name, timestamp, upStatements, downStatements) {
1579
+ const migrationName = `${pascalCase.pascalCase(name)}${timestamp}`;
1580
+ const up = upStatements.map((statement)=>` ${statement}`);
1581
+ const down = downStatements.map((statement)=>` ${statement}`);
1582
+ return `import type { MigrationInterface, QueryRunner } from 'typeorm';
1583
+
1584
+ export class ${migrationName} implements MigrationInterface {
1585
+ name = '${migrationName}';
1586
+
1587
+ public async up(queryRunner: QueryRunner): Promise<void> {
1588
+ ${up.join(`
1589
+ `)}
1590
+ }
1591
+ public async down(queryRunner: QueryRunner): Promise<void> {
1592
+ ${down.join(`
1593
+ `)}
1594
+ }
1595
+ }
1596
+ `;
1597
+ }
1598
+ async function generateMigration(context) {
1599
+ context.name = context.name || 'Default';
1600
+ const timestamp = context.timestamp || new Date().getTime();
1601
+ const fileName = `${timestamp}-${context.name}.ts`;
1602
+ const { dataSource } = context;
1603
+ const up = [];
1604
+ const down = [];
1605
+ const sqlInMemory = await dataSource.driver.createSchemaBuilder().log();
1606
+ if (context.prettify) {
1607
+ sqlInMemory.upQueries.forEach((upQuery)=>{
1608
+ upQuery.query = GenerateCommand.prettify(upQuery.query);
1609
+ });
1610
+ sqlInMemory.downQueries.forEach((downQuery)=>{
1611
+ downQuery.query = GenerateCommand.prettify(downQuery.query);
1612
+ });
1613
+ }
1614
+ sqlInMemory.upQueries.forEach((upQuery)=>{
1615
+ up.push(`await queryRunner.query(\`${upQuery.query.replace(/`/g, '\\`')}\`${queryParams(upQuery.parameters)});`);
1616
+ });
1617
+ sqlInMemory.downQueries.forEach((downQuery)=>{
1618
+ down.push(`await queryRunner.query(\`${downQuery.query.replace(/`/g, '\\`')}\`${queryParams(downQuery.parameters)});`);
1619
+ });
1620
+ if (up.length === 0 && down.length === 0) {
1621
+ return {
1622
+ up,
1623
+ down
1624
+ };
1625
+ }
1626
+ const content = buildTemplate(context.name, timestamp, up, down.reverse());
1627
+ if (!context.preview) {
1628
+ let directoryPath;
1629
+ if (context.directoryPath) {
1630
+ if (!path.isAbsolute(context.directoryPath)) {
1631
+ directoryPath = path.join(process$1.cwd(), context.directoryPath);
1632
+ } else {
1633
+ directoryPath = context.directoryPath;
1634
+ }
1635
+ } else {
1636
+ directoryPath = path.join(process$1.cwd(), 'migrations');
1637
+ }
1638
+ try {
1639
+ await fs.promises.access(directoryPath, fs.constants.R_OK | fs.constants.W_OK);
1640
+ } catch (e) {
1641
+ await fs.promises.mkdir(directoryPath, {
1642
+ recursive: true
1643
+ });
1644
+ }
1645
+ await fs.promises.writeFile(path.join(directoryPath, fileName), content, {
1646
+ encoding: 'utf-8'
1647
+ });
1648
+ }
1649
+ return {
1650
+ up,
1651
+ down,
1652
+ content
1653
+ };
1654
+ }
1655
+
1656
+ /* istanbul ignore next */ function existsQuery(builder, inverse = false) {
1657
+ return `${inverse ? 'not ' : ''}exists (${builder.getQuery()})`;
1658
+ }
1659
+
1660
+ async function synchronizeDatabaseSchema(input) {
1661
+ let dataSource;
1662
+ let options;
1663
+ if (typeorm.InstanceChecker.isDataSource(input)) {
1664
+ dataSource = input;
1665
+ options = dataSource.options;
1666
+ } else {
1667
+ options = input;
1668
+ dataSource = new typeorm.DataSource(options);
1669
+ }
1670
+ if (!dataSource.isInitialized) {
1671
+ await dataSource.initialize();
1672
+ }
1673
+ let migrationsCount = 0;
1674
+ if (options.migrations) {
1675
+ migrationsCount = Array.isArray(options.migrations) ? options.migrations.length : Object.keys(options.migrations).length;
1676
+ }
1677
+ let migrations = [];
1678
+ if (migrationsCount > 0) {
1679
+ migrations = await dataSource.runMigrations({
1680
+ transaction: options.migrationsTransactionMode
1681
+ });
1682
+ } else {
1683
+ await dataSource.synchronize(false);
1684
+ }
1685
+ if (!typeorm.InstanceChecker.isDataSource(input)) {
1686
+ await dataSource.destroy();
1687
+ }
1688
+ return migrations;
1689
+ }
1690
+
1691
+ async function createSimplePostgresConnection(driver, options, operationContext) {
1692
+ /**
1693
+ * pg library
1694
+ */ const { Client } = driver.postgres;
1695
+ const data = {
1696
+ host: options.host,
1697
+ port: options.port,
1698
+ user: options.user,
1699
+ password: options.password,
1700
+ ssl: options.ssl,
1701
+ schema: options.schema,
1702
+ ...options.extra ? options.extra : {}
1703
+ };
1704
+ if (typeof operationContext.initialDatabase === 'string') {
1705
+ data.database = operationContext.initialDatabase;
1706
+ }
1707
+ const client = new Client(data);
1708
+ await client.connect();
1709
+ return client;
1710
+ }
1711
+ async function executeSimplePostgresQuery(connection, query, endConnection = true) {
1712
+ return new Promise((resolve, reject)=>{
1713
+ connection.query(query, (queryErr, queryResult)=>{
1714
+ if (endConnection) {
1715
+ connection.end();
1716
+ }
1717
+ if (queryErr) {
1718
+ reject(queryErr);
1719
+ }
1720
+ resolve(queryResult);
1721
+ });
1722
+ });
1723
+ }
1724
+ async function createPostgresDatabase(input = {}) {
1725
+ const context = await buildDatabaseCreateContext(input);
1726
+ const options = buildDriverOptions(context.options);
1727
+ const driver = createDriver(context.options);
1728
+ const connection = await createSimplePostgresConnection(driver, options, context);
1729
+ if (context.ifNotExist) {
1730
+ const existQuery = `SELECT * FROM pg_database WHERE lower(datname) = lower('${options.database}');`;
1731
+ const existResult = await executeSimplePostgresQuery(connection, existQuery, false);
1732
+ if (locter.isObject(existResult) && hasOwnProperty(existResult, 'rows') && Array.isArray(existResult.rows) && existResult.rows.length > 0) {
1733
+ await connection.end();
1734
+ return Promise.resolve();
1735
+ }
1736
+ }
1737
+ /**
1738
+ * @link https://github.com/typeorm/typeorm/blob/master/src/driver/postgres/PostgresQueryRunner.ts#L326
1739
+ */ let query = `CREATE DATABASE "${options.database}"`;
1740
+ if (typeof options.template === 'string') {
1741
+ query += ` TEMPLATE "${options.template}"`;
1742
+ } else if (typeof options.characterSet === 'string') {
1743
+ query += ` WITH ENCODING '${options.characterSet}'`;
1744
+ }
1745
+ const result = await executeSimplePostgresQuery(connection, query);
1746
+ if (typeof options.schema === 'string' && options.schema !== 'public') {
1747
+ const schemaConnection = await createSimplePostgresConnection(driver, options, {
1748
+ ...context,
1749
+ initialDatabase: options.database
1750
+ });
1751
+ const schemaQuery = `CREATE SCHEMA IF NOT EXISTS "${options.schema}"`;
1752
+ await executeSimplePostgresQuery(schemaConnection, schemaQuery);
1753
+ }
1754
+ if (context.synchronize) {
1755
+ await synchronizeDatabaseSchema(context.options);
1756
+ }
1757
+ return result;
1758
+ }
1759
+ async function dropPostgresDatabase(input = {}) {
1760
+ const context = await buildDatabaseDropContext(input);
1761
+ const options = buildDriverOptions(context.options);
1762
+ const driver = createDriver(context.options);
1763
+ const connection = await createSimplePostgresConnection(driver, options, context);
1764
+ /**
1765
+ * @link https://github.com/typeorm/typeorm/blob/master/src/driver/postgres/PostgresQueryRunner.ts#L343
1766
+ */ const query = context.ifExist ? `DROP DATABASE IF EXISTS "${options.database}"` : `DROP DATABASE "${options.database}"`;
1767
+ return executeSimplePostgresQuery(connection, query);
1768
+ }
1769
+
1770
+ async function executeSimpleCockroachDBQuery(connection, query, endConnection = true) {
1771
+ return new Promise((resolve, reject)=>{
1772
+ connection.query(query, (queryErr, queryResult)=>{
1773
+ if (endConnection) {
1774
+ connection.end();
1775
+ }
1776
+ if (queryErr) {
1777
+ reject(queryErr);
1778
+ }
1779
+ resolve(queryResult);
1780
+ });
1781
+ });
1782
+ }
1783
+ async function createCockroachDBDatabase(input = {}) {
1784
+ const context = await buildDatabaseCreateContext(input);
1785
+ const options = buildDriverOptions(context.options);
1786
+ const driver = createDriver(context.options);
1787
+ const connection = await createSimplePostgresConnection(driver, options, context);
1788
+ /**
1789
+ * @link https://github.com/typeorm/typeorm/blob/master/src/driver/cockroachdb/CockroachQueryRunner.ts#L347
1790
+ */ const query = `CREATE DATABASE ${context.ifNotExist ? 'IF NOT EXISTS ' : ''} "${options.database}"`;
1791
+ const result = await executeSimpleCockroachDBQuery(connection, query);
1792
+ if (context.synchronize) {
1793
+ await synchronizeDatabaseSchema(context.options);
1794
+ }
1795
+ return result;
1796
+ }
1797
+ async function dropCockroachDBDatabase(input = {}) {
1798
+ const context = await buildDatabaseDropContext(input);
1799
+ const options = buildDriverOptions(context.options);
1800
+ const driver = createDriver(context.options);
1801
+ const connection = await createSimplePostgresConnection(driver, options, context);
1802
+ /**
1803
+ * @link https://github.com/typeorm/typeorm/blob/master/src/driver/cockroachdb/CockroachQueryRunner.ts#L356
1804
+ */ const query = `DROP DATABASE ${context.ifExist ? 'IF EXISTS ' : ''} "${options.database}"`;
1805
+ return executeSimpleCockroachDBQuery(connection, query);
1806
+ }
1807
+
1808
+ async function createSimpleMongoDBConnection(driver, options) {
1809
+ /**
1810
+ * mongodb library
1811
+ */ const { MongoClient } = driver.mongodb;
1812
+ let url = 'mongodb://';
1813
+ if (options.user && options.password) {
1814
+ url += `${options.user}:${options.password}@`;
1815
+ }
1816
+ url += `${options.host || '127.0.0.1'}:${options.port || 27017}/${options.database}`;
1817
+ if (options.ssl) {
1818
+ url += '?tls=true';
1819
+ }
1820
+ const client = new MongoClient(url);
1821
+ await client.connect();
1822
+ return client;
1823
+ }
1824
+ async function createMongoDBDatabase(input = {}) {
1825
+ const context = await buildDatabaseCreateContext(input);
1826
+ const options = buildDriverOptions(context.options);
1827
+ const driver = createDriver(context.options);
1828
+ // connection setup, will create the database on the fly.
1829
+ const client = await createSimpleMongoDBConnection(driver, options);
1830
+ await client.close();
1831
+ if (context.synchronize) {
1832
+ await synchronizeDatabaseSchema(context.options);
1833
+ }
1834
+ }
1835
+ async function dropMongoDBDatabase(input = {}) {
1836
+ const context = await buildDatabaseDropContext(input);
1837
+ const options = buildDriverOptions(context.options);
1838
+ const driver = createDriver(context.options);
1839
+ const client = await createSimpleMongoDBConnection(driver, options);
1840
+ const result = await client.dropDatabase();
1841
+ await client.close();
1842
+ return result;
1843
+ }
1844
+
1845
+ async function createSimpleMsSQLConnection(driver, options) {
1846
+ const option = {
1847
+ user: options.user,
1848
+ password: options.password,
1849
+ server: options.host,
1850
+ port: options.port || 1433,
1851
+ ...options.extra ? options.extra : {},
1852
+ ...options.domain ? {
1853
+ domain: options.domain
1854
+ } : {}
1855
+ };
1856
+ await driver.mssql.connect(option);
1857
+ return driver.mssql;
1858
+ }
1859
+ async function createMsSQLDatabase(input = {}) {
1860
+ const context = await buildDatabaseCreateContext(input);
1861
+ const options = buildDriverOptions(context.options);
1862
+ const driver = createDriver(context.options);
1863
+ const connection = await createSimpleMsSQLConnection(driver, options);
1864
+ /**
1865
+ * @link https://github.com/typeorm/typeorm/blob/master/src/driver/sqlserver/SqlServerQueryRunner.ts#L416
1866
+ */ let query = context.ifNotExist ? `IF DB_ID('${options.database}') IS NULL CREATE DATABASE "${options.database}"` : `CREATE DATABASE "${options.database}"`;
1867
+ if (typeof options.characterSet === 'string') {
1868
+ query += ` CHARACTER SET ${options.characterSet}`;
1869
+ }
1870
+ const result = await connection.query(query);
1871
+ if (context.synchronize) {
1872
+ await synchronizeDatabaseSchema(context.options);
1873
+ }
1874
+ return result;
1875
+ }
1876
+ async function dropMsSQLDatabase(input = {}) {
1877
+ const context = await buildDatabaseDropContext(input);
1878
+ const options = buildDriverOptions(context.options);
1879
+ const driver = createDriver(context.options);
1880
+ const connection = await createSimpleMsSQLConnection(driver, options);
1881
+ /**
1882
+ * @link https://github.com/typeorm/typeorm/blob/master/src/driver/sqlserver/SqlServerQueryRunner.ts#L425
1883
+ */ const query = context.ifExist ? `IF DB_ID('${options.database}') IS NOT NULL DROP DATABASE "${options.database}"` : `DROP DATABASE "${options.database}"`;
1884
+ return connection.query(query);
1885
+ }
1886
+
1887
+ async function createSimpleMySQLConnection(driver, options) {
1888
+ /**
1889
+ * mysql|mysql2 library
1890
+ */ const { createConnection } = driver.mysql;
1891
+ const option = {
1892
+ host: options.host,
1893
+ user: options.user,
1894
+ password: options.password,
1895
+ port: options.port,
1896
+ ssl: options.ssl,
1897
+ ...options.extra ? options.extra : {}
1898
+ };
1899
+ return createConnection(option);
1900
+ }
1901
+ async function executeSimpleMysqlQuery(connection, query, endConnection = true) {
1902
+ return new Promise((resolve, reject)=>{
1903
+ connection.query(query, (queryErr, queryResult)=>{
1904
+ if (endConnection) connection.end();
1905
+ if (queryErr) {
1906
+ reject(queryErr);
1907
+ }
1908
+ resolve(queryResult);
1909
+ });
1910
+ });
1911
+ }
1912
+ async function createMySQLDatabase(input = {}) {
1913
+ const context = await buildDatabaseCreateContext(input);
1914
+ const options = buildDriverOptions(context.options);
1915
+ const driver = createDriver(context.options);
1916
+ const connection = await createSimpleMySQLConnection(driver, options);
1917
+ /**
1918
+ * @link https://github.com/typeorm/typeorm/blob/master/src/driver/mysql/MysqlQueryRunner.ts#L297
1919
+ */ let query = context.ifNotExist ? `CREATE DATABASE IF NOT EXISTS \`${options.database}\`` : `CREATE DATABASE \`${options.database}\``;
1920
+ if (typeof options.charset === 'string') {
1921
+ const { charset } = options;
1922
+ let { characterSet } = options;
1923
+ if (typeof characterSet === 'undefined') {
1924
+ if (charset.toLowerCase().startsWith('utf8mb4')) {
1925
+ characterSet = 'utf8mb4';
1926
+ } else if (charset.toLowerCase().startsWith('utf8')) {
1927
+ characterSet = 'utf8';
1928
+ }
1929
+ }
1930
+ if (typeof characterSet === 'string') {
1931
+ query += ` CHARACTER SET ${characterSet} COLLATE ${charset}`;
1932
+ }
1933
+ }
1934
+ const result = await executeSimpleMysqlQuery(connection, query);
1935
+ if (context.synchronize) {
1936
+ await synchronizeDatabaseSchema(context.options);
1937
+ }
1938
+ return result;
1939
+ }
1940
+ async function dropMySQLDatabase(input = {}) {
1941
+ const context = await buildDatabaseDropContext(input);
1942
+ const options = buildDriverOptions(context.options);
1943
+ const driver = createDriver(context.options);
1944
+ const connection = await createSimpleMySQLConnection(driver, options);
1945
+ /**
1946
+ * @link https://github.com/typeorm/typeorm/blob/master/src/driver/mysql/MysqlQueryRunner.ts#L306
1947
+ */ const query = context.ifExist ? `DROP DATABASE IF EXISTS \`${options.database}\`` : `DROP DATABASE \`${options.database}\``;
1948
+ await executeSimpleMysqlQuery(connection, 'SET FOREIGN_KEY_CHECKS=0;', false);
1949
+ const result = await executeSimpleMysqlQuery(connection, query, false);
1950
+ await executeSimpleMysqlQuery(connection, 'SET FOREIGN_KEY_CHECKS=1;');
1951
+ return result;
1952
+ }
1953
+
1954
+ function createSimpleOracleConnection(driver, options) {
1955
+ const { getConnection } = driver.oracle;
1956
+ if (!options.connectString) {
1957
+ let address = '(PROTOCOL=TCP)';
1958
+ if (options.host) {
1959
+ address += `(HOST=${options.host})`;
1960
+ }
1961
+ if (options.port) {
1962
+ address += `(PORT=${options.port})`;
1963
+ }
1964
+ let connectData = '(SERVER=DEDICATED)';
1965
+ if (options.sid) {
1966
+ connectData += `(SID=${options.sid})`;
1967
+ }
1968
+ if (options.serviceName) {
1969
+ connectData += `(SERVICE_NAME=${options.serviceName})`;
1970
+ }
1971
+ options.connectString = `(DESCRIPTION=(ADDRESS=${address})(CONNECT_DATA=${connectData}))`;
1972
+ }
1973
+ return getConnection({
1974
+ user: options.user,
1975
+ password: options.password,
1976
+ connectString: options.connectString || options.url,
1977
+ ...options.extra ? options.extra : {}
1978
+ });
1979
+ }
1980
+ async function createOracleDatabase(input = {}) {
1981
+ const context = await buildDatabaseCreateContext(input);
1982
+ const options = buildDriverOptions(context.options);
1983
+ const driver = createDriver(context.options);
1984
+ const connection = createSimpleOracleConnection(driver, options);
1985
+ /**
1986
+ * @link https://github.com/typeorm/typeorm/blob/master/src/driver/oracle/OracleQueryRunner.ts#L295
1987
+ */ const query = `CREATE DATABASE IF NOT EXISTS ${options.database}`;
1988
+ const result = await connection.execute(query);
1989
+ if (context.synchronize) {
1990
+ await synchronizeDatabaseSchema(context.options);
1991
+ }
1992
+ return result;
1993
+ }
1994
+ async function dropOracleDatabase(_context = {}) {
1995
+ /**
1996
+ * @link https://github.com/typeorm/typeorm/blob/master/src/driver/oracle/OracleQueryRunner.ts#L295
1997
+ */ return Promise.resolve();
1998
+ }
1999
+
2000
+ async function createSQLiteDatabase(input = {}) {
2001
+ const context = await buildDatabaseCreateContext(input);
2002
+ const options = buildDriverOptions(context.options);
2003
+ if (!options.database) {
2004
+ throw OptionsError.databaseNotDefined();
2005
+ }
2006
+ const filePath = path.isAbsolute(options.database) ? options.database : path.join(process.cwd(), options.database);
2007
+ const directoryPath = path.dirname(filePath);
2008
+ await fs.promises.access(directoryPath, fs.constants.W_OK);
2009
+ if (context.synchronize) {
2010
+ await synchronizeDatabaseSchema(context.options);
2011
+ }
2012
+ }
2013
+ async function dropSQLiteDatabase(input = {}) {
2014
+ const context = await buildDatabaseDropContext(input);
2015
+ const options = buildDriverOptions(context.options);
2016
+ if (!options.database) {
2017
+ throw OptionsError.databaseNotDefined();
2018
+ }
2019
+ const filePath = path.isAbsolute(options.database) ? options.database : path.join(process.cwd(), options.database);
2020
+ try {
2021
+ await fs.promises.access(filePath, fs.constants.F_OK | fs.constants.W_OK);
2022
+ if (context.ifExist) {
2023
+ await fs.promises.unlink(filePath);
2024
+ }
2025
+ } catch (e) {
2026
+ // ...
2027
+ }
2028
+ }
2029
+
2030
+ /**
2031
+ * Create database for specified driver in ConnectionOptions.
2032
+ *
2033
+ * @throws DriverError
2034
+ * @throws OptionsError
2035
+ *
2036
+ * @param input
2037
+ */ async function createDatabase(input = {}) {
2038
+ const context = await buildDatabaseCreateContext(input);
2039
+ let output;
2040
+ switch(context.options.type){
2041
+ case 'mongodb':
2042
+ output = await createMongoDBDatabase(context);
2043
+ break;
2044
+ case 'mysql':
2045
+ case 'mariadb':
2046
+ output = await createMySQLDatabase(context);
2047
+ break;
2048
+ case 'postgres':
2049
+ output = await createPostgresDatabase(context);
2050
+ break;
2051
+ case 'cockroachdb':
2052
+ output = await createCockroachDBDatabase(context);
2053
+ break;
2054
+ case 'sqlite':
2055
+ case 'better-sqlite3':
2056
+ output = await createSQLiteDatabase(context);
2057
+ break;
2058
+ case 'oracle':
2059
+ output = await createOracleDatabase(context);
2060
+ break;
2061
+ case 'mssql':
2062
+ output = await createMsSQLDatabase(context);
2063
+ break;
2064
+ default:
2065
+ throw DriverError.notSupported(context.options.type);
2066
+ }
2067
+ return output;
2068
+ }
2069
+
2070
+ /**
2071
+ * Drop database for specified driver in ConnectionOptions.
2072
+ *
2073
+ * @throws DriverError
2074
+ * @throws OptionsError
2075
+ *
2076
+ * @param input
2077
+ */ async function dropDatabase(input = {}) {
2078
+ const context = await buildDatabaseDropContext(input);
2079
+ let output;
2080
+ switch(context.options.type){
2081
+ case 'mongodb':
2082
+ output = await dropMongoDBDatabase(context);
2083
+ break;
2084
+ case 'mysql':
2085
+ case 'mariadb':
2086
+ output = await dropMySQLDatabase(context);
2087
+ break;
2088
+ case 'postgres':
2089
+ output = await dropPostgresDatabase(context);
2090
+ break;
2091
+ case 'cockroachdb':
2092
+ output = await dropCockroachDBDatabase(context);
2093
+ break;
2094
+ case 'sqlite':
2095
+ case 'better-sqlite3':
2096
+ output = await dropSQLiteDatabase(context);
2097
+ break;
2098
+ case 'oracle':
2099
+ output = await dropOracleDatabase(context);
2100
+ break;
2101
+ case 'mssql':
2102
+ output = await dropMsSQLDatabase(context);
2103
+ break;
2104
+ default:
2105
+ throw DriverError.notSupported(context.options.type);
2106
+ }
2107
+ return output;
2108
+ }
2109
+
2110
+ class DatabaseCreateCommand {
2111
+ builder(args) {
2112
+ return args.option('preserveFilePaths', {
2113
+ default: false,
2114
+ type: 'boolean',
2115
+ describe: 'This option indicates if file paths should be preserved.'
2116
+ }).option('root', {
2117
+ alias: 'r',
2118
+ default: process.cwd(),
2119
+ describe: 'Root directory of the project.'
2120
+ }).option('tsconfig', {
2121
+ alias: 'tc',
2122
+ default: 'tsconfig.json',
2123
+ describe: 'Name (or relative path incl. name) of the tsconfig file.'
2124
+ }).option('dataSource', {
2125
+ alias: 'd',
2126
+ default: 'data-source',
2127
+ describe: 'Name (or relative path incl. name) of the data-source file.'
2128
+ }).option('synchronize', {
2129
+ alias: 's',
2130
+ default: 'yes',
2131
+ describe: 'Create database schema for all entities.',
2132
+ choices: [
2133
+ 'yes',
2134
+ 'no'
2135
+ ]
2136
+ }).option('initialDatabase', {
2137
+ describe: 'Specify the initial database to connect to.'
2138
+ });
2139
+ }
2140
+ async handler(raw) {
2141
+ const args = raw;
2142
+ let tsconfig;
2143
+ let sourcePath = resolveFilePath(args.dataSource, args.root);
2144
+ if (!args.preserveFilePaths) {
2145
+ tsconfig = await readTSConfig(resolveFilePath(args.root, args.tsconfig));
2146
+ sourcePath = await adjustFilePath(sourcePath, tsconfig);
2147
+ }
2148
+ const source = parseFilePath(sourcePath);
2149
+ consola.consola.info(`DataSource Directory: ${source.directory}`);
2150
+ consola.consola.info(`DataSource Name: ${source.name}`);
2151
+ const dataSourceOptions = await buildDataSourceOptions({
2152
+ directory: source.directory,
2153
+ dataSourceName: source.name,
2154
+ tsconfig,
2155
+ preserveFilePaths: args.preserveFilePaths
2156
+ });
2157
+ const context = {
2158
+ ifNotExist: true,
2159
+ options: dataSourceOptions,
2160
+ synchronize: args.synchronize === 'yes'
2161
+ };
2162
+ if (typeof args.initialDatabase === 'string' && args.initialDatabase !== '') {
2163
+ context.initialDatabase = args.initialDatabase;
2164
+ }
2165
+ try {
2166
+ await createDatabase(context);
2167
+ consola.consola.success('Created database.');
2168
+ process.exit(0);
2169
+ } catch (e) {
2170
+ consola.consola.warn('Failed to create database.');
2171
+ consola.consola.error(e);
2172
+ process.exit(1);
2173
+ }
2174
+ }
2175
+ constructor(){
2176
+ this.command = 'db:create';
2177
+ this.describe = 'Create database.';
2178
+ }
2179
+ }
2180
+
2181
+ class DatabaseDropCommand {
2182
+ builder(args) {
2183
+ return args.option('preserveFilePaths', {
2184
+ default: false,
2185
+ type: 'boolean',
2186
+ describe: 'This option indicates if file paths should be preserved.'
2187
+ }).option('root', {
2188
+ alias: 'r',
2189
+ default: process.cwd(),
2190
+ describe: 'Root directory of the project.'
2191
+ }).option('tsconfig', {
2192
+ alias: 'tc',
2193
+ default: 'tsconfig.json',
2194
+ describe: 'Name (or relative path incl. name) of the tsconfig file.'
2195
+ }).option('dataSource', {
2196
+ alias: 'd',
2197
+ default: 'data-source',
2198
+ describe: 'Name (or relative path incl. name) of the data-source file.'
2199
+ }).option('initialDatabase', {
2200
+ describe: 'Specify the initial database to connect to.'
2201
+ });
2202
+ }
2203
+ async handler(raw) {
2204
+ const args = raw;
2205
+ let tsconfig;
2206
+ let sourcePath = resolveFilePath(args.dataSource, args.root);
2207
+ if (!args.preserveFilePaths) {
2208
+ tsconfig = await readTSConfig(resolveFilePath(args.root, args.tsconfig));
2209
+ sourcePath = await adjustFilePath(sourcePath, tsconfig);
2210
+ }
2211
+ const source = parseFilePath(sourcePath);
2212
+ consola.consola.info(`DataSource Directory: ${source.directory}`);
2213
+ consola.consola.info(`DataSource Name: ${source.name}`);
2214
+ const dataSourceOptions = await buildDataSourceOptions({
2215
+ directory: source.directory,
2216
+ dataSourceName: source.name,
2217
+ tsconfig,
2218
+ preserveFilePaths: args.preserveFilePaths
2219
+ });
2220
+ const context = {
2221
+ ifExist: true,
2222
+ options: dataSourceOptions
2223
+ };
2224
+ if (typeof args.initialDatabase === 'string' && args.initialDatabase !== '') {
2225
+ context.initialDatabase = args.initialDatabase;
2226
+ }
2227
+ try {
2228
+ await dropDatabase(context);
2229
+ consola.consola.success('Dropped database.');
2230
+ process.exit(0);
2231
+ } catch (e) {
2232
+ consola.consola.warn('Failed to drop database.');
2233
+ consola.consola.error(e);
2234
+ process.exit(1);
2235
+ }
2236
+ }
2237
+ constructor(){
2238
+ this.command = 'db:drop';
2239
+ this.describe = 'Drop database.';
2240
+ }
2241
+ }
2242
+
2243
+ class SeederEntity {
2244
+ constructor(ctx){
2245
+ this.id = ctx.id;
2246
+ this.timestamp = ctx.timestamp;
2247
+ this.name = ctx.name;
2248
+ if (ctx.constructor) {
2249
+ this.instance = new ctx.constructor();
2250
+ }
2251
+ this.fileName = ctx.fileName;
2252
+ this.filePath = ctx.filePath;
2253
+ }
2254
+ get trackExecution() {
2255
+ if (typeof this.instance === 'undefined') {
2256
+ return undefined;
2257
+ }
2258
+ return this.instance.track;
2259
+ }
2260
+ }
2261
+
2262
+ class SeederFactory {
2263
+ // --------------------------------------------------------------
2264
+ constructor(context){
2265
+ this.context = context;
2266
+ }
2267
+ // --------------------------------------------------------------
2268
+ setMeta(value) {
2269
+ this.meta = value;
2270
+ return this;
2271
+ }
2272
+ setLocale(value) {
2273
+ this.faker = undefined;
2274
+ this.locale = Array.isArray(value) ? value : [
2275
+ value
2276
+ ];
2277
+ }
2278
+ // --------------------------------------------------------------
2279
+ async make(params, save) {
2280
+ const faker = await this.useFaker();
2281
+ const factoryFn = this.context.factoryFn(faker, this.meta);
2282
+ let entity;
2283
+ if (isPromise(factoryFn)) {
2284
+ entity = await this.resolve(await factoryFn, save);
2285
+ } else {
2286
+ entity = await this.resolve(factoryFn, save);
2287
+ }
2288
+ if (params) {
2289
+ const keys = Object.keys(params);
2290
+ for(let i = 0; i < keys.length; i++){
2291
+ entity[keys[i]] = params[keys[i]];
2292
+ }
2293
+ }
2294
+ return entity;
2295
+ }
2296
+ // --------------------------------------------------------------
2297
+ async save(params, options) {
2298
+ const dataSource = await useDataSource();
2299
+ const entity = await this.make(params, true);
2300
+ const entityManager = dataSource.getRepository(this.context.entity);
2301
+ return entityManager.save(entity, options);
2302
+ }
2303
+ async saveMany(amount, params, options) {
2304
+ const promises = [];
2305
+ for(let i = 0; i < amount; i++){
2306
+ const item = this.save(params, options);
2307
+ promises.push(item);
2308
+ }
2309
+ return Promise.all(promises);
2310
+ }
2311
+ // --------------------------------------------------------------
2312
+ async resolve(entity, save) {
2313
+ const keys = Object.keys(entity);
2314
+ for(let i = 0; i < keys.length; i++){
2315
+ const key = keys[i];
2316
+ const value = entity[key];
2317
+ if (!hasOwnProperty(entity, key)) {
2318
+ continue;
2319
+ }
2320
+ if (typeof value === 'object' && // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2321
+ // @ts-ignore
2322
+ value instanceof SeederFactory) {
2323
+ if (save) {
2324
+ entity[key] = await value.save();
2325
+ } else {
2326
+ entity[key] = await value.make();
2327
+ }
2328
+ }
2329
+ if (value && hasOwnProperty(value, 'then') && typeof value.then === 'function') {
2330
+ entity[key] = await value;
2331
+ }
2332
+ }
2333
+ return entity;
2334
+ }
2335
+ async useFaker() {
2336
+ if (typeof this.faker !== 'undefined') {
2337
+ return this.faker;
2338
+ }
2339
+ const options = {
2340
+ locale: []
2341
+ };
2342
+ const fakerExports = await locter.load('@faker-js/faker');
2343
+ let names;
2344
+ if (this.locale) {
2345
+ names = Array.isArray(this.locale) ? this.locale : [
2346
+ this.locale
2347
+ ];
2348
+ } else {
2349
+ names = [
2350
+ 'en'
2351
+ ];
2352
+ }
2353
+ for(let i = 0; i < names.length; i++){
2354
+ if (hasOwnProperty(fakerExports, 'default') && locter.isObject(fakerExports.default) && hasOwnProperty(fakerExports.default, names[i])) {
2355
+ options.locale.push(fakerExports.default[names[i]]);
2356
+ continue;
2357
+ }
2358
+ if (hasOwnProperty(fakerExports, names[i])) {
2359
+ options.locale.push(fakerExports[names[i]]);
2360
+ }
2361
+ }
2362
+ this.faker = new fakerExports.Faker(options);
2363
+ return this.faker;
2364
+ }
2365
+ }
2366
+
2367
+ class SeederFactoryManager {
2368
+ set(entity, factoryFn) {
2369
+ const name = getEntityName(entity);
2370
+ this.items[name] = {
2371
+ factoryFn,
2372
+ entity
2373
+ };
2374
+ return this.items[name];
2375
+ }
2376
+ get(entity) {
2377
+ const name = getEntityName(entity);
2378
+ if (!hasOwnProperty(this.items, name)) {
2379
+ throw new Error(`No seeder factory is registered for the entity: ${name}`);
2380
+ }
2381
+ return new SeederFactory({
2382
+ factoryFn: this.items[name].factoryFn,
2383
+ entity,
2384
+ name
2385
+ });
2386
+ }
2387
+ constructor(){
2388
+ this.items = {};
2389
+ }
2390
+ }
2391
+
2392
+ async function resolveFilePatterns(filesPattern, root) {
2393
+ return locter.locateMany(filesPattern, {
2394
+ ...root ? {
2395
+ path: root
2396
+ } : {},
2397
+ ignore: [
2398
+ '**/*.d.ts'
2399
+ ]
2400
+ }).then(buildFilePathname);
2401
+ }
2402
+ function resolveFilePaths(filePaths, root) {
2403
+ return filePaths.map((filePath)=>path.isAbsolute(filePath) ? filePath : path.resolve(root || process.cwd(), filePath));
2404
+ }
2405
+ /**
2406
+ * Exported only for testing purposes
2407
+ */ function buildFilePathname(files) {
2408
+ return(// sorting by name so that we can define the order of execution using file names
2409
+ files.sort((a, b)=>a.name > b.name ? 1 : -1).map((el)=>path.join(el.path, el.name + el.extension)));
2410
+ }
2411
+
2412
+ async function prepareSeederSeeds(input, root) {
2413
+ const items = [];
2414
+ let seedFiles = [];
2415
+ const seedConstructors = [];
2416
+ for(let i = 0; i < input.length; i++){
2417
+ const value = input[i];
2418
+ if (typeof value === 'string') {
2419
+ seedFiles.push(value);
2420
+ } else {
2421
+ seedConstructors.push(value);
2422
+ }
2423
+ }
2424
+ if (seedFiles.length > 0) {
2425
+ seedFiles = await resolveFilePatterns(seedFiles, root);
2426
+ seedFiles = resolveFilePaths(seedFiles, root);
2427
+ for(let i = 0; i < seedFiles.length; i++){
2428
+ const moduleExports = await locter.load(seedFiles[i]);
2429
+ let clazzConstructor;
2430
+ const exportKeys = Object.keys(moduleExports);
2431
+ for(let j = 0; j < exportKeys.length; j++){
2432
+ const moduleExport = moduleExports[exportKeys[j]];
2433
+ if (typeof moduleExport === 'function' && moduleExport.prototype) {
2434
+ clazzConstructor = moduleExport;
2435
+ }
2436
+ }
2437
+ if (clazzConstructor) {
2438
+ const fileName = path.basename(seedFiles[i]);
2439
+ const filePath = seedFiles[i];
2440
+ const match = fileName.match(/^([0-9]{13,})-(.*)$/);
2441
+ let timestamp;
2442
+ if (match) {
2443
+ timestamp = parseInt(match[1], 10);
2444
+ }
2445
+ items.push({
2446
+ constructor: clazzConstructor,
2447
+ fileName,
2448
+ filePath,
2449
+ ...timestamp ? {
2450
+ timestamp
2451
+ } : {}
2452
+ });
2453
+ }
2454
+ }
2455
+ }
2456
+ if (seedConstructors.length > 0) {
2457
+ for(let i = 0; i < seedConstructors.length; i++){
2458
+ items.push({
2459
+ constructor: seedConstructors[i]
2460
+ });
2461
+ }
2462
+ }
2463
+ return items;
2464
+ }
2465
+
2466
+ function buildSeederFileTemplate(name, timestamp) {
2467
+ const className = `${pascalCase.pascalCase(name)}${timestamp}`;
2468
+ return `import { DataSource } from 'typeorm';
2469
+ import { Seeder, SeederFactoryManager } from 'typeorm-extension';
2470
+
2471
+ export class ${className} implements Seeder {
2472
+ track = false;
2473
+
2474
+ public async run(
2475
+ dataSource: DataSource,
2476
+ factoryManager: SeederFactoryManager
2477
+ ): Promise<any> {
2478
+
2479
+ }
2480
+ }
2481
+ `;
2482
+ }
2483
+
2484
+ let instance;
2485
+ function useSeederFactoryManager() {
2486
+ if (typeof instance !== 'undefined') {
2487
+ return instance;
2488
+ }
2489
+ instance = new SeederFactoryManager();
2490
+ return instance;
2491
+ }
2492
+ function setSeederFactory(entity, factoryFn) {
2493
+ const manager = useSeederFactoryManager();
2494
+ return manager.set(entity, factoryFn);
2495
+ }
2496
+ function useSeederFactory(entity) {
2497
+ const manager = useSeederFactoryManager();
2498
+ return manager.get(entity);
2499
+ }
2500
+ async function prepareSeederFactories(items, root) {
2501
+ let factoryFiles = [];
2502
+ const factoryConfigs = [];
2503
+ for(let i = 0; i < items.length; i++){
2504
+ const value = items[i];
2505
+ if (typeof value === 'string') {
2506
+ factoryFiles.push(value);
2507
+ } else {
2508
+ factoryConfigs.push(value);
2509
+ }
2510
+ }
2511
+ if (factoryFiles.length > 0) {
2512
+ factoryFiles = await resolveFilePatterns(factoryFiles, root);
2513
+ factoryFiles = resolveFilePaths(factoryFiles, root);
2514
+ for(let i = 0; i < factoryFiles.length; i++){
2515
+ await locter.load(factoryFiles[i]);
2516
+ }
2517
+ }
2518
+ if (factoryConfigs.length > 0) {
2519
+ const factoryManager = useSeederFactoryManager();
2520
+ for(let i = 0; i < factoryConfigs.length; i++){
2521
+ factoryManager.set(factoryConfigs[i].entity, factoryConfigs[i].factoryFn);
2522
+ }
2523
+ }
2524
+ }
2525
+
2526
+ class SeederExecutor {
2527
+ constructor(dataSource, options){
2528
+ this.dataSource = dataSource;
2529
+ this.options = options || {};
2530
+ setDataSource(dataSource);
2531
+ this.tableName = this.dataSourceOptions.seedTableName || 'seeds';
2532
+ }
2533
+ async execute(input = {}) {
2534
+ const options = await this.buildOptions(input);
2535
+ if (!options.seeds || options.seeds.length === 0) {
2536
+ return [];
2537
+ }
2538
+ if (options.factories) {
2539
+ await prepareSeederFactories(options.factories, this.options.root);
2540
+ }
2541
+ const seederElements = await prepareSeederSeeds(options.seeds, this.options.root);
2542
+ const all = await this.buildEntities(seederElements);
2543
+ let tracking = !!options.seedTracking;
2544
+ if (!tracking) {
2545
+ tracking = all.some((seed)=>!!seed.trackExecution);
2546
+ }
2547
+ let queryRunner;
2548
+ let existing = [];
2549
+ if (tracking) {
2550
+ queryRunner = this.dataSource.createQueryRunner();
2551
+ await this.createTableIfNotExist(queryRunner);
2552
+ existing = await this.loadExisting(queryRunner);
2553
+ }
2554
+ const isMatch = (seed)=>{
2555
+ if (!options.seedName) {
2556
+ return true;
2557
+ }
2558
+ if (seed.name === options.seedName || seed.fileName === options.seedName) {
2559
+ return true;
2560
+ }
2561
+ if (!seed.filePath) {
2562
+ return false;
2563
+ }
2564
+ if (seed.filePath === options.seedName) {
2565
+ return true;
2566
+ }
2567
+ return resolveFilePath(options.seedName, this.options.root) === seed.filePath;
2568
+ };
2569
+ const pending = all.filter((seed)=>{
2570
+ if (!isMatch(seed)) {
2571
+ return false;
2572
+ }
2573
+ const index = existing.findIndex((el)=>el.name === seed.name);
2574
+ if (index === -1) {
2575
+ return true;
2576
+ }
2577
+ let seedTracking;
2578
+ if (typeof seed.trackExecution !== 'undefined') {
2579
+ seedTracking = seed.trackExecution;
2580
+ } else {
2581
+ seedTracking = options.seedTracking;
2582
+ }
2583
+ return !seedTracking;
2584
+ });
2585
+ if (pending.length === 0) {
2586
+ if (queryRunner) {
2587
+ await queryRunner.release();
2588
+ }
2589
+ return [];
2590
+ }
2591
+ this.dataSource.logger.logSchemaBuild(`${existing.length} seeds are already present in the database.`);
2592
+ this.dataSource.logger.logSchemaBuild(`${all.length} seeds were found in the source code.`);
2593
+ const factoryManager = useSeederFactoryManager();
2594
+ const executed = [];
2595
+ try {
2596
+ for(let i = 0; i < pending.length; i++){
2597
+ const seeder = pending[i].instance;
2598
+ if (!seeder) {
2599
+ continue;
2600
+ }
2601
+ pending[i].result = await seeder.run(this.dataSource, factoryManager);
2602
+ let seedTracking;
2603
+ if (typeof pending[i].trackExecution !== 'undefined') {
2604
+ seedTracking = pending[i].trackExecution;
2605
+ } else {
2606
+ seedTracking = options.seedTracking;
2607
+ }
2608
+ if (queryRunner && seedTracking) {
2609
+ await this.track(queryRunner, pending[i]);
2610
+ }
2611
+ this.dataSource.logger.logSchemaBuild(`Seed ${pending[i].name} has been executed successfully.`);
2612
+ executed.push(pending[i]);
2613
+ }
2614
+ } finally{
2615
+ if (queryRunner) {
2616
+ await queryRunner.release();
2617
+ }
2618
+ }
2619
+ return executed;
2620
+ }
2621
+ async loadExisting(queryRunner) {
2622
+ if (this.dataSource.driver.options.type === 'mongodb') {
2623
+ const mongoRunner = queryRunner;
2624
+ return mongoRunner.cursor(this.tableName, {}).sort({
2625
+ _id: -1
2626
+ }).toArray();
2627
+ }
2628
+ const raw = await this.dataSource.manager.createQueryBuilder(queryRunner).select().orderBy(this.dataSource.driver.escape('id'), 'DESC').from(this.table, this.tableName).getRawMany();
2629
+ return raw.map((migrationRaw)=>new SeederEntity({
2630
+ id: parseInt(migrationRaw.id, 10),
2631
+ timestamp: parseInt(migrationRaw.timestamp, 10),
2632
+ name: migrationRaw.name,
2633
+ constructor: undefined
2634
+ }));
2635
+ }
2636
+ /**
2637
+ * Gets all migrations that setup for this connection.
2638
+ */ async buildEntities(seeds) {
2639
+ if (!seeds) {
2640
+ return [];
2641
+ }
2642
+ let timestampCounter = 0;
2643
+ const entities = seeds.map((element)=>{
2644
+ const { constructor: seed, fileName, filePath } = element;
2645
+ let { timestamp } = element;
2646
+ const className = seed.name || seed.constructor.name;
2647
+ if (!timestamp) {
2648
+ timestamp = this.classNameToTimestamp(className);
2649
+ }
2650
+ const entity = new SeederEntity({
2651
+ fileName,
2652
+ filePath,
2653
+ timestamp: timestamp || timestampCounter,
2654
+ name: className,
2655
+ constructor: seed
2656
+ });
2657
+ timestampCounter++;
2658
+ return entity;
2659
+ });
2660
+ this.checkForDuplicates(entities);
2661
+ // sort them by file name than by timestamp
2662
+ return entities.sort((a, b)=>{
2663
+ if (typeof a.fileName !== 'undefined' && typeof b.fileName !== 'undefined') {
2664
+ return a.fileName > b.fileName ? 1 : -1;
2665
+ }
2666
+ return a.timestamp - b.timestamp;
2667
+ });
2668
+ }
2669
+ checkForDuplicates(entities) {
2670
+ const names = entities.map((migration)=>migration.name);
2671
+ const duplicates = Array.from(new Set(names.filter((migrationName, index)=>names.indexOf(migrationName) < index)));
2672
+ if (duplicates.length > 0) {
2673
+ throw Error(`Duplicate seeds: ${duplicates.join(', ')}`);
2674
+ }
2675
+ }
2676
+ async createTableIfNotExist(queryRunner) {
2677
+ // If driver is mongo no need to create
2678
+ if (this.dataSource.driver.options.type === 'mongodb') {
2679
+ return;
2680
+ }
2681
+ const tableExist = await queryRunner.hasTable(this.table);
2682
+ if (!tableExist) {
2683
+ await queryRunner.createTable(new typeorm.Table({
2684
+ database: this.database,
2685
+ schema: this.schema,
2686
+ name: this.table,
2687
+ columns: [
2688
+ {
2689
+ name: 'id',
2690
+ type: this.dataSource.driver.normalizeType({
2691
+ type: this.dataSource.driver.mappedDataTypes.migrationId
2692
+ }),
2693
+ isGenerated: true,
2694
+ generationStrategy: 'increment',
2695
+ isPrimary: true,
2696
+ isNullable: false
2697
+ },
2698
+ {
2699
+ name: 'timestamp',
2700
+ type: this.dataSource.driver.normalizeType({
2701
+ type: this.dataSource.driver.mappedDataTypes.migrationTimestamp
2702
+ }),
2703
+ isPrimary: false,
2704
+ isNullable: false
2705
+ },
2706
+ {
2707
+ name: 'name',
2708
+ type: this.dataSource.driver.normalizeType({
2709
+ type: this.dataSource.driver.mappedDataTypes.migrationName
2710
+ }),
2711
+ isNullable: false
2712
+ }
2713
+ ]
2714
+ }));
2715
+ }
2716
+ }
2717
+ async track(queryRunner, seederEntity) {
2718
+ const values = {};
2719
+ if (this.dataSource.driver.options.type === 'mssql') {
2720
+ values.timestamp = new typeorm.MssqlParameter(seederEntity.timestamp, this.dataSource.driver.normalizeType({
2721
+ type: this.dataSource.driver.mappedDataTypes.migrationTimestamp
2722
+ }));
2723
+ values.name = new typeorm.MssqlParameter(seederEntity.name, this.dataSource.driver.normalizeType({
2724
+ type: this.dataSource.driver.mappedDataTypes.migrationName
2725
+ }));
2726
+ } else {
2727
+ values.timestamp = seederEntity.timestamp;
2728
+ values.name = seederEntity.name;
2729
+ }
2730
+ if (this.dataSource.driver.options.type === 'mongodb') {
2731
+ const mongoRunner = queryRunner;
2732
+ await mongoRunner.databaseConnection.db(this.dataSource.driver.database).collection(this.tableName).insertOne(values);
2733
+ } else {
2734
+ const qb = queryRunner.manager.createQueryBuilder();
2735
+ await qb.insert().into(this.table).values(values).execute();
2736
+ }
2737
+ }
2738
+ get dataSourceOptions() {
2739
+ return this.dataSource.options;
2740
+ }
2741
+ get database() {
2742
+ return this.dataSource.driver.database;
2743
+ }
2744
+ get schema() {
2745
+ return this.dataSource.driver.schema;
2746
+ }
2747
+ get table() {
2748
+ return this.dataSource.driver.buildTableName(this.tableName, this.schema, this.database);
2749
+ }
2750
+ async buildOptions(input = {}) {
2751
+ const options = {
2752
+ ...input,
2753
+ seeds: input.seeds || [],
2754
+ factories: input.factories || [],
2755
+ seedTracking: input.seedTracking ?? false
2756
+ };
2757
+ if (!options.seeds || options.seeds.length === 0) {
2758
+ options.seeds = this.dataSourceOptions.seeds;
2759
+ }
2760
+ if (!options.seeds || options.seeds.length === 0) {
2761
+ options.seeds = useEnv('seeds');
2762
+ }
2763
+ if (!options.seeds || options.seeds.length === 0) {
2764
+ options.seeds = [
2765
+ 'src/database/seeds/**/*{.ts,.js}'
2766
+ ];
2767
+ }
2768
+ if (!options.factories || options.factories.length === 0) {
2769
+ options.factories = this.dataSourceOptions.factories;
2770
+ }
2771
+ if (!options.factories || options.factories.length === 0) {
2772
+ options.factories = useEnv('factories');
2773
+ }
2774
+ if (!options.factories || options.factories.length === 0) {
2775
+ options.factories = [
2776
+ 'src/database/factories/**/*{.ts,.js}'
2777
+ ];
2778
+ }
2779
+ if (typeof options.seedTracking === 'undefined') {
2780
+ options.seedTracking = this.dataSourceOptions.seedTracking;
2781
+ }
2782
+ if (!this.options.preserveFilePaths) {
2783
+ let tsConfig;
2784
+ if (locter.isObject(this.options.tsconfig)) {
2785
+ tsConfig = this.options.tsconfig;
2786
+ } else {
2787
+ tsConfig = await readTSConfig(resolveFilePath(this.options.tsconfig || 'tsconfig.json', this.options.root));
2788
+ }
2789
+ await adjustFilePaths(options, [
2790
+ 'seeds',
2791
+ 'seedName',
2792
+ 'factories'
2793
+ ], tsConfig);
2794
+ }
2795
+ return options;
2796
+ }
2797
+ classNameToTimestamp(className) {
2798
+ const match = className.match(/^(.*)([0-9]{13,})$/);
2799
+ if (match) {
2800
+ return parseInt(match[2], 10);
2801
+ }
2802
+ return undefined;
2803
+ }
2804
+ }
2805
+
2806
+ async function runSeeder(dataSource, seeder, options = {}) {
2807
+ if (typeof seeder === 'string') {
2808
+ options.seedName = seeder;
2809
+ } else {
2810
+ options.seeds = [
2811
+ seeder
2812
+ ];
2813
+ }
2814
+ const executor = new SeederExecutor(dataSource);
2815
+ const output = await executor.execute(options);
2816
+ return output.pop();
2817
+ }
2818
+ async function runSeeders(dataSource, options) {
2819
+ const executor = new SeederExecutor(dataSource);
2820
+ return executor.execute(options);
2821
+ }
2822
+
2823
+ class SeedCreateCommand {
2824
+ builder(args) {
2825
+ return args.option('root', {
2826
+ alias: 'r',
2827
+ default: process.cwd(),
2828
+ describe: 'Root directory of the project.'
2829
+ }).option('timestamp', {
2830
+ alias: 't',
2831
+ type: 'number',
2832
+ describe: 'Custom timestamp for the seeder name.'
2833
+ }).option('javascript', {
2834
+ alias: 'j',
2835
+ type: 'boolean',
2836
+ default: false,
2837
+ describe: 'Generate a seeder file for JavaScript instead of TypeScript.'
2838
+ }).option('name', {
2839
+ alias: 'n',
2840
+ describe: 'Name (or relative path incl. name) of the seeder.',
2841
+ demandOption: true
2842
+ });
2843
+ }
2844
+ async handler(raw) {
2845
+ const args = raw;
2846
+ let timestamp;
2847
+ if (Number.isNaN(args.timestamp) || !args.timestamp) {
2848
+ timestamp = Date.now();
2849
+ } else {
2850
+ timestamp = args.timestamp;
2851
+ }
2852
+ const sourcePath = parseFilePath(args.name, args.root);
2853
+ const dirNameIsDirectory = await isDirectory(sourcePath.directory);
2854
+ if (!dirNameIsDirectory) {
2855
+ consola.consola.warn(`The output directory ${sourcePath.directory} does not exist.`);
2856
+ process.exit(1);
2857
+ }
2858
+ const extension = args.javascript ? '.js' : '.ts';
2859
+ const nameExtension = locter.getFileNameExtension(sourcePath.name);
2860
+ const nameWithoutExtension = locter.removeFileNameExtension(sourcePath.name);
2861
+ let fileName;
2862
+ if (nameExtension) {
2863
+ fileName = `${timestamp}-${sourcePath.name}`;
2864
+ } else {
2865
+ fileName = `${timestamp}-${sourcePath.name}${extension}`;
2866
+ }
2867
+ const filePath = sourcePath.directory + path.sep + fileName;
2868
+ const template = buildSeederFileTemplate(nameWithoutExtension, timestamp);
2869
+ consola.consola.info(`Seed Directory: ${sourcePath.directory}`);
2870
+ consola.consola.info(`Seed FileName: ${fileName}`);
2871
+ consola.consola.info(`Seed Name: ${pascalCase.pascalCase(nameWithoutExtension)}`);
2872
+ try {
2873
+ await fs.promises.writeFile(filePath, template, {
2874
+ encoding: 'utf-8'
2875
+ });
2876
+ } catch (e) {
2877
+ consola.consola.warn(`The seed could not be written to the path ${filePath}.`);
2878
+ process.exit(1);
2879
+ }
2880
+ process.exit(0);
2881
+ }
2882
+ constructor(){
2883
+ this.command = 'seed:create';
2884
+ this.describe = 'Create a seeder file.';
2885
+ }
2886
+ }
2887
+
2888
+ class SeedRunCommand {
2889
+ builder(args) {
2890
+ return args.option('preserveFilePaths', {
2891
+ default: false,
2892
+ type: 'boolean',
2893
+ describe: 'This option indicates if file paths should be preserved.'
2894
+ }).option('root', {
2895
+ alias: 'r',
2896
+ default: process.cwd(),
2897
+ describe: 'Root directory of the project.'
2898
+ }).option('tsconfig', {
2899
+ alias: 'tc',
2900
+ default: 'tsconfig.json',
2901
+ describe: 'Name (or relative path incl. name) of the tsconfig file.'
2902
+ }).option('dataSource', {
2903
+ alias: 'd',
2904
+ default: 'data-source',
2905
+ describe: 'Name (or relative path incl. name) of the data-source file.'
2906
+ }).option('name', {
2907
+ alias: 'n',
2908
+ describe: 'Name (or relative path incl. name) of the seeder.'
2909
+ });
2910
+ }
2911
+ async handler(raw) {
2912
+ const args = raw;
2913
+ let tsconfig;
2914
+ let sourcePath = resolveFilePath(args.dataSource, args.root);
2915
+ if (!args.preserveFilePaths) {
2916
+ tsconfig = await readTSConfig(args.root);
2917
+ sourcePath = await adjustFilePath(sourcePath, tsconfig);
2918
+ args.name = await adjustFilePath(args.name, tsconfig);
2919
+ }
2920
+ const source = parseFilePath(sourcePath);
2921
+ consola.consola.info(`DataSource Directory: ${source.directory}`);
2922
+ consola.consola.info(`DataSource Name: ${source.name}`);
2923
+ const dataSourceOptions = await buildDataSourceOptions({
2924
+ dataSourceName: source.name,
2925
+ directory: source.directory,
2926
+ tsconfig,
2927
+ preserveFilePaths: args.preserveFilePaths
2928
+ });
2929
+ setDataSourceOptions(dataSourceOptions);
2930
+ if (args.name) {
2931
+ consola.consola.info(`Seed Name: ${args.name}`);
2932
+ }
2933
+ const dataSource = await useDataSource();
2934
+ const executor = new SeederExecutor(dataSource, {
2935
+ root: args.root,
2936
+ tsconfig,
2937
+ preserveFilePaths: args.preserveFilePaths
2938
+ });
2939
+ await executor.execute({
2940
+ seedName: args.name
2941
+ });
2942
+ process.exit(0);
2943
+ }
2944
+ constructor(){
2945
+ this.command = 'seed:run';
2946
+ this.describe = 'Populate the database with an initial data set or generated data by a factory.';
2947
+ }
2948
+ }
2949
+
2950
+ class EntityRelationLookupError extends TypeormExtensionError {
2951
+ constructor(options){
2952
+ super(options.message);
2953
+ this.relation = options.relation;
2954
+ this.columns = options.columns;
2955
+ }
2956
+ static notReferenced(relation, columns) {
2957
+ return new EntityRelationLookupError({
2958
+ message: `${relation} entity is not referenced by ${columns.join(', ')}`,
2959
+ relation,
2960
+ columns
2961
+ });
2962
+ }
2963
+ static notFound(relation, columns) {
2964
+ return new EntityRelationLookupError({
2965
+ message: `Can't find ${relation} entity by ${columns.join(', ')}`,
2966
+ relation,
2967
+ columns
2968
+ });
2969
+ }
2970
+ }
2971
+
2972
+ /**
2973
+ * Receive metadata for a given repository or entity-target.
2974
+ *
2975
+ * @experimental
2976
+ * @param input
2977
+ * @param dataSource
2978
+ */ async function getEntityMetadata(input, dataSource) {
2979
+ if (input instanceof typeorm.Repository) {
2980
+ return input.metadata;
2981
+ }
2982
+ dataSource = dataSource || await useDataSource();
2983
+ const index = dataSource.entityMetadatas.findIndex((entityMetadata)=>entityMetadata.target === input);
2984
+ if (index === -1) {
2985
+ throw new Error(`The entity ${input} is not registered.`);
2986
+ }
2987
+ return dataSource.entityMetadatas[index];
2988
+ }
2989
+
2990
+ /**
2991
+ * Get (relation-) property names of a given entity.
2992
+ *
2993
+ * @experimental
2994
+ * @param input
2995
+ * @param dataSource
2996
+ */ async function getEntityPropertyNames(input, dataSource) {
2997
+ let entityMetadata;
2998
+ if (input instanceof typeorm.Repository) {
2999
+ entityMetadata = input.metadata;
3000
+ } else {
3001
+ entityMetadata = await getEntityMetadata(input, dataSource);
3002
+ }
3003
+ const items = [];
3004
+ for(let i = 0; i < entityMetadata.columns.length; i++){
3005
+ items.push(entityMetadata.columns[i].propertyName);
3006
+ }
3007
+ for(let i = 0; i < entityMetadata.relations.length; i++){
3008
+ items.push(entityMetadata.relations[i].propertyName);
3009
+ }
3010
+ return items;
3011
+ }
3012
+
3013
+ /**
3014
+ * Validate join columns of a given entity.
3015
+ * It will look up and append the referenced entities to the input entity.
3016
+ *
3017
+ * @experimental
3018
+ * @param entity
3019
+ * @param options
3020
+ */ async function validateEntityJoinColumns(entity, options) {
3021
+ const dataSource = options.dataSource || await useDataSource();
3022
+ const entityMetadata = await getEntityMetadata(options.entityTarget, dataSource);
3023
+ const relations = {};
3024
+ for(let i = 0; i < entityMetadata.relations.length; i++){
3025
+ const relation = entityMetadata.relations[i];
3026
+ let skipRelation = false;
3027
+ const where = {};
3028
+ const columns = [];
3029
+ for(let j = 0; j < relation.joinColumns.length; j++){
3030
+ const joinColumn = relation.joinColumns[j];
3031
+ if (typeof entity[joinColumn.propertyName] === 'undefined') {
3032
+ continue;
3033
+ }
3034
+ if (joinColumn.isNullable && entity[joinColumn.propertyName] === null) {
3035
+ skipRelation = true;
3036
+ break;
3037
+ }
3038
+ if (joinColumn.referencedColumn) {
3039
+ where[joinColumn.referencedColumn.propertyName] = entity[joinColumn.propertyName];
3040
+ columns.push(joinColumn.propertyName);
3041
+ } else {
3042
+ throw EntityRelationLookupError.notReferenced(relation.propertyName, [
3043
+ joinColumn.propertyName
3044
+ ]);
3045
+ }
3046
+ }
3047
+ if (skipRelation || columns.length === 0) {
3048
+ continue;
3049
+ }
3050
+ const repository = dataSource.getRepository(relation.type);
3051
+ const item = await repository.findOne({
3052
+ where
3053
+ });
3054
+ if (!item) {
3055
+ throw EntityRelationLookupError.notFound(relation.propertyName, columns);
3056
+ }
3057
+ relations[relation.propertyName] = item;
3058
+ }
3059
+ const relationKeys = Object.keys(relations);
3060
+ for(let i = 0; i < relationKeys.length; i++){
3061
+ const relationKey = relationKeys[i];
3062
+ entity[relationKey] = relations[relationKey];
3063
+ }
3064
+ return entity;
3065
+ }
3066
+
3067
+ function transformUndefinedToNull(input) {
3068
+ if (typeof input === 'undefined') {
3069
+ return null;
3070
+ }
3071
+ return input;
3072
+ }
3073
+ function applyWhereExpression(qb, data, type) {
3074
+ const elements = [];
3075
+ const keys = Object.keys(data);
3076
+ for(let i = 0; i < keys.length; i++){
3077
+ elements.push({
3078
+ key: keys[i],
3079
+ value: transformUndefinedToNull(data[keys[i]]),
3080
+ operator: type === 'target' ? rapiq.FilterComparisonOperator.EQUAL : rapiq.FilterComparisonOperator.NOT_EQUAL
3081
+ });
3082
+ }
3083
+ const queryFilters = transformParsedFilters(elements, {
3084
+ bindingKey (key) {
3085
+ if (type === 'source') {
3086
+ return `filter_source_${key}`;
3087
+ }
3088
+ return `filter_target_${key}`;
3089
+ }
3090
+ });
3091
+ applyFiltersTransformed(qb, queryFilters);
3092
+ return queryFilters;
3093
+ }
3094
+ /**
3095
+ * Check if a given entity does not already exist.
3096
+ * Composite unique keys on a null column can only be present once.
3097
+ *
3098
+ * @experimental
3099
+ * @param options
3100
+ */ async function isEntityUnique(options) {
3101
+ const dataSource = options.dataSource || await useDataSource();
3102
+ const metadata = await getEntityMetadata(options.entityTarget, dataSource);
3103
+ const repository = dataSource.getRepository(metadata.target);
3104
+ const primaryColumnNames = metadata.primaryColumns.map((c)=>c.propertyName);
3105
+ const columnGroups = [];
3106
+ if (metadata.ownUniques && metadata.ownUniques.length > 0) {
3107
+ for(let i = 0; i < metadata.ownUniques.length; i++){
3108
+ columnGroups.push(metadata.ownUniques[i].columns.map((column)=>column.propertyName));
3109
+ }
3110
+ } else {
3111
+ for(let i = 0; i < metadata.indices.length; i++){
3112
+ const index = metadata.indices[i];
3113
+ if (!index.isUnique || index.entityMetadata.target !== metadata.target) {
3114
+ continue;
3115
+ }
3116
+ columnGroups.push(index.columns.map((column)=>column.propertyName));
3117
+ }
3118
+ }
3119
+ for(let i = 0; i < columnGroups.length; i++){
3120
+ const queryBuilder = repository.createQueryBuilder('entity');
3121
+ queryBuilder.where(new typeorm.Brackets((qb)=>{
3122
+ applyWhereExpression(qb, pickRecord(options.entity, columnGroups[i]), 'target');
3123
+ }));
3124
+ if (options.entityExisting) {
3125
+ queryBuilder.andWhere(new typeorm.Brackets((qb)=>{
3126
+ applyWhereExpression(qb, pickRecord(options.entityExisting, primaryColumnNames), 'source');
3127
+ }));
3128
+ }
3129
+ const entity = await queryBuilder.getOne();
3130
+ if (entity) {
3131
+ return false;
3132
+ }
3133
+ }
3134
+ return true;
3135
+ }
3136
+
3137
+ exports.CodeTransformation = CodeTransformation;
3138
+ exports.DatabaseCreateCommand = DatabaseCreateCommand;
3139
+ exports.DatabaseDropCommand = DatabaseDropCommand;
3140
+ exports.DriverError = DriverError;
3141
+ exports.EntityRelationLookupError = EntityRelationLookupError;
3142
+ exports.EnvironmentName = EnvironmentName;
3143
+ exports.EnvironmentVariableName = EnvironmentVariableName;
3144
+ exports.OptionsError = OptionsError;
3145
+ exports.SeedCreateCommand = SeedCreateCommand;
3146
+ exports.SeedRunCommand = SeedRunCommand;
3147
+ exports.SeederEntity = SeederEntity;
3148
+ exports.SeederExecutor = SeederExecutor;
3149
+ exports.SeederFactory = SeederFactory;
3150
+ exports.SeederFactoryManager = SeederFactoryManager;
3151
+ exports.TypeormExtensionError = TypeormExtensionError;
3152
+ exports.adjustFilePath = adjustFilePath;
3153
+ exports.adjustFilePaths = adjustFilePaths;
3154
+ exports.applyFields = applyFields;
3155
+ exports.applyFilters = applyFilters;
3156
+ exports.applyFiltersTransformed = applyFiltersTransformed;
3157
+ exports.applyPagination = applyPagination;
3158
+ exports.applyQuery = applyQuery;
3159
+ exports.applyQueryFields = applyQueryFields;
3160
+ exports.applyQueryFieldsParseOutput = applyQueryFieldsParseOutput;
3161
+ exports.applyQueryFilters = applyQueryFilters;
3162
+ exports.applyQueryFiltersParseOutput = applyQueryFiltersParseOutput;
3163
+ exports.applyQueryPagination = applyQueryPagination;
3164
+ exports.applyQueryPaginationParseOutput = applyQueryPaginationParseOutput;
3165
+ exports.applyQueryParseOutput = applyQueryParseOutput;
3166
+ exports.applyQueryRelations = applyQueryRelations;
3167
+ exports.applyQueryRelationsParseOutput = applyQueryRelationsParseOutput;
3168
+ exports.applyQuerySort = applyQuerySort;
3169
+ exports.applyQuerySortParseOutput = applyQuerySortParseOutput;
3170
+ exports.applyRelations = applyRelations;
3171
+ exports.applySort = applySort;
3172
+ exports.buildDataSourceOptions = buildDataSourceOptions;
3173
+ exports.buildDatabaseCreateContext = buildDatabaseCreateContext;
3174
+ exports.buildDatabaseDropContext = buildDatabaseDropContext;
3175
+ exports.buildDriverOptions = buildDriverOptions;
3176
+ exports.buildFilePathname = buildFilePathname;
3177
+ exports.buildKeyWithPrefix = buildKeyWithPrefix;
3178
+ exports.buildSeederFileTemplate = buildSeederFileTemplate;
3179
+ exports.canReplaceWindowsSeparator = canReplaceWindowsSeparator;
3180
+ exports.checkDatabase = checkDatabase;
3181
+ exports.createCockroachDBDatabase = createCockroachDBDatabase;
3182
+ exports.createDatabase = createDatabase;
3183
+ exports.createDriver = createDriver;
3184
+ exports.createMongoDBDatabase = createMongoDBDatabase;
3185
+ exports.createMsSQLDatabase = createMsSQLDatabase;
3186
+ exports.createMySQLDatabase = createMySQLDatabase;
3187
+ exports.createOracleDatabase = createOracleDatabase;
3188
+ exports.createPostgresDatabase = createPostgresDatabase;
3189
+ exports.createSQLiteDatabase = createSQLiteDatabase;
3190
+ exports.createSimpleMongoDBConnection = createSimpleMongoDBConnection;
3191
+ exports.createSimpleMsSQLConnection = createSimpleMsSQLConnection;
3192
+ exports.createSimpleMySQLConnection = createSimpleMySQLConnection;
3193
+ exports.createSimpleOracleConnection = createSimpleOracleConnection;
3194
+ exports.createSimplePostgresConnection = createSimplePostgresConnection;
3195
+ exports.detectCodeTransformation = detectCodeTransformation;
3196
+ exports.dropCockroachDBDatabase = dropCockroachDBDatabase;
3197
+ exports.dropDatabase = dropDatabase;
3198
+ exports.dropMongoDBDatabase = dropMongoDBDatabase;
3199
+ exports.dropMsSQLDatabase = dropMsSQLDatabase;
3200
+ exports.dropMySQLDatabase = dropMySQLDatabase;
3201
+ exports.dropOracleDatabase = dropOracleDatabase;
3202
+ exports.dropPostgresDatabase = dropPostgresDatabase;
3203
+ exports.dropSQLiteDatabase = dropSQLiteDatabase;
3204
+ exports.executeSimpleCockroachDBQuery = executeSimpleCockroachDBQuery;
3205
+ exports.executeSimpleMysqlQuery = executeSimpleMysqlQuery;
3206
+ exports.executeSimplePostgresQuery = executeSimplePostgresQuery;
3207
+ exports.existsQuery = existsQuery;
3208
+ exports.extendObject = extendObject;
3209
+ exports.findDataSource = findDataSource;
3210
+ exports.generateMigration = generateMigration;
3211
+ exports.getAliasForPath = getAliasForPath;
3212
+ exports.getCharacterSetFromDataSourceOptions = getCharacterSetFromDataSourceOptions;
3213
+ exports.getCharsetFromDataSourceOptions = getCharsetFromDataSourceOptions;
3214
+ exports.getEntityMetadata = getEntityMetadata;
3215
+ exports.getEntityName = getEntityName;
3216
+ exports.getEntityPropertyNames = getEntityPropertyNames;
3217
+ exports.hasDataSource = hasDataSource;
3218
+ exports.hasDataSourceOptions = hasDataSourceOptions;
3219
+ exports.hasEnvDataSourceOptions = hasEnvDataSourceOptions;
3220
+ exports.hasOwnProperty = hasOwnProperty;
3221
+ exports.hasStringProperty = hasStringProperty;
3222
+ exports.hasTrailingSlash = hasTrailingSlash;
3223
+ exports.isCodeTransformation = isCodeTransformation;
3224
+ exports.isDirectory = isDirectory;
3225
+ exports.isEntityUnique = isEntityUnique;
3226
+ exports.isPromise = isPromise;
3227
+ exports.isQueryOptionDefined = isQueryOptionDefined;
3228
+ exports.mergeDataSourceOptions = mergeDataSourceOptions;
3229
+ exports.mergeDataSourceOptionsWithEnv = mergeDataSourceOptionsWithEnv;
3230
+ exports.parseFilePath = parseFilePath;
3231
+ exports.pickRecord = pickRecord;
3232
+ exports.prepareSeederFactories = prepareSeederFactories;
3233
+ exports.prepareSeederSeeds = prepareSeederSeeds;
3234
+ exports.readDataSourceOptionsFromEnv = readDataSourceOptionsFromEnv;
3235
+ exports.readTSConfig = readTSConfig;
3236
+ exports.replaceWindowSeparator = replaceWindowSeparator;
3237
+ exports.resetEnv = resetEnv;
3238
+ exports.resolveFilePath = resolveFilePath;
3239
+ exports.resolveFilePaths = resolveFilePaths;
3240
+ exports.resolveFilePatterns = resolveFilePatterns;
3241
+ exports.runSeeder = runSeeder;
3242
+ exports.runSeeders = runSeeders;
3243
+ exports.safeReplaceWindowsSeparator = safeReplaceWindowsSeparator;
3244
+ exports.setDataSource = setDataSource;
3245
+ exports.setDataSourceOptions = setDataSourceOptions;
3246
+ exports.setSeederFactory = setSeederFactory;
3247
+ exports.synchronizeDatabaseSchema = synchronizeDatabaseSchema;
3248
+ exports.transformFilePath = transformFilePath;
3249
+ exports.transformParsedFilters = transformParsedFilters;
3250
+ exports.unsetDataSource = unsetDataSource;
3251
+ exports.useDataSource = useDataSource;
3252
+ exports.useDataSourceOptions = useDataSourceOptions;
3253
+ exports.useEnv = useEnv;
3254
+ exports.useSeederFactory = useSeederFactory;
3255
+ exports.useSeederFactoryManager = useSeederFactoryManager;
3256
+ exports.validateEntityJoinColumns = validateEntityJoinColumns;
3257
+ exports.withoutTrailingSlash = withoutTrailingSlash;
3258
+ //# sourceMappingURL=index.cjs.map