sonamu 0.5.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/context.d.ts +4 -1
- package/dist/api/context.d.ts.map +1 -1
- package/dist/api/decorators.d.ts.map +1 -1
- package/dist/api/decorators.js +1 -1
- package/dist/api/decorators.js.map +1 -1
- package/dist/api/sonamu.d.ts +7 -6
- package/dist/api/sonamu.d.ts.map +1 -1
- package/dist/api/sonamu.js +1 -1
- package/dist/api/sonamu.js.map +1 -1
- package/dist/bin/build-config.d.ts +4 -0
- package/dist/bin/build-config.d.ts.map +1 -1
- package/dist/bin/build-config.js +1 -1
- package/dist/bin/build-config.js.map +1 -1
- package/dist/bin/cli-wrapper.js +1 -1
- package/dist/bin/cli-wrapper.js.map +1 -1
- package/dist/bin/cli.js +1 -1
- package/dist/bin/cli.js.map +1 -1
- package/dist/database/base-model.d.ts +8 -1
- package/dist/database/base-model.d.ts.map +1 -1
- package/dist/database/base-model.js +1 -1
- package/dist/database/base-model.js.map +1 -1
- package/dist/database/db.js +1 -1
- package/dist/database/db.js.map +1 -1
- package/dist/file-storage/driver.d.ts +3 -0
- package/dist/file-storage/driver.d.ts.map +1 -1
- package/dist/file-storage/driver.js +1 -1
- package/dist/file-storage/driver.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/stream/index.d.ts +2 -0
- package/dist/stream/index.d.ts.map +1 -0
- package/dist/stream/index.js +2 -0
- package/dist/stream/index.js.map +1 -0
- package/dist/stream/sse.d.ts +13 -0
- package/dist/stream/sse.d.ts.map +1 -0
- package/dist/stream/sse.js +2 -0
- package/dist/stream/sse.js.map +1 -0
- package/dist/types/types.d.ts +5 -3
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/types.js.map +1 -1
- package/package.json +6 -4
- package/src/api/context.ts +10 -5
- package/src/api/decorators.ts +1 -3
- package/src/api/sonamu.ts +60 -26
- package/src/bin/build-config.ts +5 -0
- package/src/bin/cli-wrapper.ts +20 -6
- package/src/bin/cli.ts +16 -21
- package/src/database/base-model.ts +29 -3
- package/src/database/db.ts +1 -1
- package/src/file-storage/driver.ts +10 -0
- package/src/index.ts +1 -0
- package/src/stream/index.ts +1 -0
- package/src/stream/sse.ts +49 -0
- package/src/types/types.ts +10 -4
- package/tsconfig.json +4 -0
- package/dist/api/sonamu.types.d.ts +0 -30
- package/dist/api/sonamu.types.d.ts.map +0 -1
- package/dist/api/sonamu.types.js +0 -2
- package/dist/api/sonamu.types.js.map +0 -1
- package/dist/base-model-CEB0H0aO.d.mts +0 -43
- package/dist/base-model-CrqDMYhI.d.ts +0 -43
- package/dist/bin/cli-wrapper.d.mts +0 -1
- package/dist/bin/cli-wrapper.mjs +0 -43
- package/dist/bin/cli-wrapper.mjs.map +0 -1
- package/dist/bin/cli.d.mts +0 -2
- package/dist/bin/cli.mjs +0 -907
- package/dist/bin/cli.mjs.map +0 -1
- package/dist/chunk-2WAC2GER.js +0 -7625
- package/dist/chunk-2WAC2GER.js.map +0 -1
- package/dist/chunk-C3IPIF6O.mjs +0 -1581
- package/dist/chunk-C3IPIF6O.mjs.map +0 -1
- package/dist/chunk-EXHKSVTE.js +0 -280
- package/dist/chunk-EXHKSVTE.js.map +0 -1
- package/dist/chunk-FCERKIIF.mjs +0 -7623
- package/dist/chunk-FCERKIIF.mjs.map +0 -1
- package/dist/chunk-HGIBJYOU.mjs +0 -231
- package/dist/chunk-HGIBJYOU.mjs.map +0 -1
- package/dist/chunk-JKSOJRQA.mjs +0 -280
- package/dist/chunk-JKSOJRQA.mjs.map +0 -1
- package/dist/chunk-OTKKFP3Y.js +0 -1581
- package/dist/chunk-OTKKFP3Y.js.map +0 -1
- package/dist/chunk-PTFDTOJU.mjs +0 -19
- package/dist/chunk-PTFDTOJU.mjs.map +0 -1
- package/dist/chunk-UZ2IY5VE.js +0 -231
- package/dist/chunk-UZ2IY5VE.js.map +0 -1
- package/dist/database/drivers/knex/base-model.d.mts +0 -16
- package/dist/database/drivers/knex/base-model.d.ts +0 -16
- package/dist/database/drivers/knex/base-model.js +0 -55
- package/dist/database/drivers/knex/base-model.js.map +0 -1
- package/dist/database/drivers/knex/base-model.mjs +0 -56
- package/dist/database/drivers/knex/base-model.mjs.map +0 -1
- package/dist/database/drivers/kysely/base-model.d.mts +0 -22
- package/dist/database/drivers/kysely/base-model.d.ts +0 -22
- package/dist/database/drivers/kysely/base-model.js +0 -64
- package/dist/database/drivers/kysely/base-model.js.map +0 -1
- package/dist/database/drivers/kysely/base-model.mjs +0 -65
- package/dist/database/drivers/kysely/base-model.mjs.map +0 -1
- package/dist/database/types.d.ts +0 -39
- package/dist/database/types.d.ts.map +0 -1
- package/dist/database/types.js +0 -2
- package/dist/database/types.js.map +0 -1
- package/dist/index.d.mts +0 -813
- package/dist/index.mjs +0 -435
- package/dist/index.mjs.map +0 -1
- package/dist/model-aFgomcdc.d.mts +0 -1112
- package/dist/model-aFgomcdc.d.ts +0 -1112
- package/dist/smd/smd-manager.d.ts +0 -28
- package/dist/smd/smd-manager.d.ts.map +0 -1
- package/dist/smd/smd-manager.js +0 -2
- package/dist/smd/smd-manager.js.map +0 -1
- package/dist/smd/smd.d.ts +0 -40
- package/dist/smd/smd.d.ts.map +0 -1
- package/dist/smd/smd.js +0 -2
- package/dist/smd/smd.js.map +0 -1
package/dist/chunk-OTKKFP3Y.js
DELETED
|
@@ -1,1581 +0,0 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2;
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
var _chunk2WAC2GERjs = require('./chunk-2WAC2GER.js');
|
|
20
|
-
|
|
21
|
-
// src/entity/migrator.ts
|
|
22
|
-
var _lodash = require('lodash'); var _lodash2 = _interopRequireDefault(_lodash);
|
|
23
|
-
var _chalk = require('chalk'); var _chalk2 = _interopRequireDefault(_chalk);
|
|
24
|
-
var _luxon = require('luxon');
|
|
25
|
-
var _fsextra = require('fs-extra'); var _fsextra2 = _interopRequireDefault(_fsextra);
|
|
26
|
-
var _fastdeepequal = require('fast-deep-equal'); var _fastdeepequal2 = _interopRequireDefault(_fastdeepequal);
|
|
27
|
-
var _inflection = require('inflection'); var _inflection2 = _interopRequireDefault(_inflection);
|
|
28
|
-
var _prompts = require('prompts'); var _prompts2 = _interopRequireDefault(_prompts);
|
|
29
|
-
var _child_process = require('child_process');
|
|
30
|
-
var _path = require('path'); var _path2 = _interopRequireDefault(_path);
|
|
31
|
-
var Migrator = class {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
constructor(options) {
|
|
35
|
-
this.mode = options.mode;
|
|
36
|
-
if (this.mode === "dev") {
|
|
37
|
-
const devDB = _chunk2WAC2GERjs.DB.getClient("development_master");
|
|
38
|
-
const testDB = _chunk2WAC2GERjs.DB.getClient("test");
|
|
39
|
-
const fixtureLocalDB = _chunk2WAC2GERjs.DB.getClient("fixture_local");
|
|
40
|
-
const uniqConfigs = _chunk2WAC2GERjs.DB.getUniqueConfigs([
|
|
41
|
-
"development_master",
|
|
42
|
-
"test",
|
|
43
|
-
"fixture_local",
|
|
44
|
-
"fixture_remote"
|
|
45
|
-
]);
|
|
46
|
-
const applyDBs = [devDB, testDB, fixtureLocalDB];
|
|
47
|
-
if (uniqConfigs.length === 4) {
|
|
48
|
-
const fixtureRemoteDB = _chunk2WAC2GERjs.DB.getClient("fixture_remote");
|
|
49
|
-
applyDBs.push(fixtureRemoteDB);
|
|
50
|
-
}
|
|
51
|
-
this.targets = {
|
|
52
|
-
compare: devDB,
|
|
53
|
-
pending: devDB,
|
|
54
|
-
shadow: testDB,
|
|
55
|
-
apply: applyDBs
|
|
56
|
-
};
|
|
57
|
-
} else if (this.mode === "deploy") {
|
|
58
|
-
const productionDB = _chunk2WAC2GERjs.DB.getClient("production_master");
|
|
59
|
-
const testDB = _chunk2WAC2GERjs.DB.getClient("test");
|
|
60
|
-
this.targets = {
|
|
61
|
-
pending: productionDB,
|
|
62
|
-
shadow: testDB,
|
|
63
|
-
apply: [productionDB]
|
|
64
|
-
};
|
|
65
|
-
} else {
|
|
66
|
-
throw new Error(`\uC798\uBABB\uB41C \uBAA8\uB4DC ${this.mode} \uC785\uB825`);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
async getMigrationCodes() {
|
|
70
|
-
const srcMigrationsDir = `${_chunk2WAC2GERjs.Sonamu.apiRootPath}/src/migrations`;
|
|
71
|
-
const distMigrationsDir = `${_chunk2WAC2GERjs.Sonamu.apiRootPath}/dist/migrations`;
|
|
72
|
-
if (_fsextra2.default.existsSync(srcMigrationsDir) === false) {
|
|
73
|
-
_fsextra2.default.mkdirSync(srcMigrationsDir, {
|
|
74
|
-
recursive: true
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
if (_fsextra2.default.existsSync(distMigrationsDir) === false) {
|
|
78
|
-
_fsextra2.default.mkdirSync(distMigrationsDir, {
|
|
79
|
-
recursive: true
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
const srcMigrations = _fsextra2.default.readdirSync(srcMigrationsDir).filter((f) => f.endsWith(".ts")).map((f) => f.split(".")[0]);
|
|
83
|
-
const distMigrations = _fsextra2.default.readdirSync(distMigrationsDir).filter((f) => f.endsWith(".js")).map((f) => f.split(".")[0]);
|
|
84
|
-
const normal = _lodash2.default.intersection(srcMigrations, distMigrations).map((filename) => {
|
|
85
|
-
return {
|
|
86
|
-
name: filename,
|
|
87
|
-
path: _path2.default.join(srcMigrationsDir, filename) + ".ts"
|
|
88
|
-
};
|
|
89
|
-
}).sort((a, b) => a > b ? 1 : -1);
|
|
90
|
-
const onlyTs = _lodash2.default.difference(srcMigrations, distMigrations).map(
|
|
91
|
-
(filename) => {
|
|
92
|
-
return {
|
|
93
|
-
name: filename,
|
|
94
|
-
path: _path2.default.join(srcMigrationsDir, filename) + ".ts"
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
);
|
|
98
|
-
const onlyJs = _lodash2.default.difference(distMigrations, srcMigrations).map(
|
|
99
|
-
(filename) => {
|
|
100
|
-
return {
|
|
101
|
-
name: filename,
|
|
102
|
-
path: _path2.default.join(distMigrationsDir, filename) + ".js"
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
);
|
|
106
|
-
return {
|
|
107
|
-
normal,
|
|
108
|
-
onlyTs,
|
|
109
|
-
onlyJs
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
async getStatus() {
|
|
113
|
-
const { normal, onlyTs, onlyJs } = await this.getMigrationCodes();
|
|
114
|
-
if (onlyTs.length > 0) {
|
|
115
|
-
console.debug({ onlyTs });
|
|
116
|
-
throw new (0, _chunk2WAC2GERjs.ServiceUnavailableException)(
|
|
117
|
-
`There are un-compiled TS migration files.
|
|
118
|
-
Please compile them first.
|
|
119
|
-
|
|
120
|
-
${onlyTs.map((f) => f.name).join("\n")}`
|
|
121
|
-
);
|
|
122
|
-
}
|
|
123
|
-
if (onlyJs.length > 0) {
|
|
124
|
-
console.debug({ onlyJs });
|
|
125
|
-
await Promise.all(
|
|
126
|
-
onlyJs.map(async (f) => {
|
|
127
|
-
_child_process.execSync.call(void 0,
|
|
128
|
-
`rm -f ${f.path.replace("/src/", "/dist/").replace(".ts", ".js")}`
|
|
129
|
-
);
|
|
130
|
-
})
|
|
131
|
-
);
|
|
132
|
-
}
|
|
133
|
-
const connKeys = Object.keys(_chunk2WAC2GERjs.DB.fullConfig).filter(
|
|
134
|
-
(key) => key.endsWith("_slave") === false
|
|
135
|
-
);
|
|
136
|
-
const statuses = await Promise.all(
|
|
137
|
-
connKeys.map(async (connKey) => {
|
|
138
|
-
const tConn = _chunk2WAC2GERjs.DB.getClient(connKey);
|
|
139
|
-
const status = await (async () => {
|
|
140
|
-
try {
|
|
141
|
-
return await tConn.status();
|
|
142
|
-
} catch (err) {
|
|
143
|
-
console.error(err);
|
|
144
|
-
return "error";
|
|
145
|
-
}
|
|
146
|
-
})();
|
|
147
|
-
const pending = await (async () => {
|
|
148
|
-
try {
|
|
149
|
-
return await tConn.getMigrations();
|
|
150
|
-
} catch (err) {
|
|
151
|
-
console.error(err);
|
|
152
|
-
return [];
|
|
153
|
-
}
|
|
154
|
-
})();
|
|
155
|
-
const currentVersion = await (async () => {
|
|
156
|
-
return "error";
|
|
157
|
-
})();
|
|
158
|
-
const info = tConn.connectionInfo;
|
|
159
|
-
await tConn.destroy();
|
|
160
|
-
return {
|
|
161
|
-
name: connKey.replace("_master", ""),
|
|
162
|
-
connKey,
|
|
163
|
-
connString: `mysql2://${_nullishCoalesce(info.user, () => ( ""))}@${info.host}:${info.port}/${info.database}`,
|
|
164
|
-
currentVersion,
|
|
165
|
-
status,
|
|
166
|
-
pending
|
|
167
|
-
};
|
|
168
|
-
})
|
|
169
|
-
);
|
|
170
|
-
const preparedCodes = await (async () => {
|
|
171
|
-
const status0conn = statuses.find((status) => status.status === 0);
|
|
172
|
-
if (status0conn === void 0) {
|
|
173
|
-
return [];
|
|
174
|
-
}
|
|
175
|
-
const compareDBconn = _chunk2WAC2GERjs.DB.getClient(status0conn.connKey);
|
|
176
|
-
const genCodes = await this.compareMigrations(compareDBconn);
|
|
177
|
-
await compareDBconn.destroy();
|
|
178
|
-
return genCodes;
|
|
179
|
-
})();
|
|
180
|
-
return {
|
|
181
|
-
conns: statuses,
|
|
182
|
-
codes: normal,
|
|
183
|
-
preparedCodes
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
async runAction(action, targets) {
|
|
187
|
-
const configs = _chunk2WAC2GERjs.DB.getUniqueConfigs(targets);
|
|
188
|
-
const conns = await Promise.all(
|
|
189
|
-
configs.map(async (config) => ({
|
|
190
|
-
connKey: config.connKey,
|
|
191
|
-
db: _chunk2WAC2GERjs.DB.getClient(config.connKey)
|
|
192
|
-
}))
|
|
193
|
-
);
|
|
194
|
-
const result = await (async () => {
|
|
195
|
-
switch (action) {
|
|
196
|
-
case "latest":
|
|
197
|
-
return Promise.all(
|
|
198
|
-
conns.map(async ({ connKey, db }) => {
|
|
199
|
-
const [batchNo, applied] = await db.migrate();
|
|
200
|
-
return {
|
|
201
|
-
connKey,
|
|
202
|
-
batchNo,
|
|
203
|
-
applied
|
|
204
|
-
};
|
|
205
|
-
})
|
|
206
|
-
);
|
|
207
|
-
case "rollback":
|
|
208
|
-
return Promise.all(
|
|
209
|
-
conns.map(async ({ connKey, db }) => {
|
|
210
|
-
const [batchNo, applied] = await db.rollback();
|
|
211
|
-
return {
|
|
212
|
-
connKey,
|
|
213
|
-
batchNo,
|
|
214
|
-
applied
|
|
215
|
-
};
|
|
216
|
-
})
|
|
217
|
-
);
|
|
218
|
-
}
|
|
219
|
-
})();
|
|
220
|
-
await Promise.all(
|
|
221
|
-
conns.map(({ db }) => {
|
|
222
|
-
return db.destroy();
|
|
223
|
-
})
|
|
224
|
-
);
|
|
225
|
-
return result;
|
|
226
|
-
}
|
|
227
|
-
async delCodes(codeNames) {
|
|
228
|
-
const { conns } = await this.getStatus();
|
|
229
|
-
if (conns.some((conn) => {
|
|
230
|
-
return codeNames.some(
|
|
231
|
-
(codeName) => conn.pending.includes(codeName) === false
|
|
232
|
-
);
|
|
233
|
-
})) {
|
|
234
|
-
throw new Error(
|
|
235
|
-
"You cannot delete a migration file if there is already applied."
|
|
236
|
-
);
|
|
237
|
-
}
|
|
238
|
-
const delFiles = codeNames.map((codeName) => [
|
|
239
|
-
`${_chunk2WAC2GERjs.Sonamu.apiRootPath}/src/migrations/${codeName}.ts`,
|
|
240
|
-
`${_chunk2WAC2GERjs.Sonamu.apiRootPath}/dist/migrations/${codeName}.js`
|
|
241
|
-
]).flat();
|
|
242
|
-
const res = await Promise.all(
|
|
243
|
-
delFiles.map((delFile) => {
|
|
244
|
-
if (_fsextra2.default.existsSync(delFile)) {
|
|
245
|
-
console.log(_chalk2.default.red(`DELETE: ${delFile}`));
|
|
246
|
-
_fsextra2.default.unlinkSync(delFile);
|
|
247
|
-
return delFiles.includes(".ts") ? 1 : 0;
|
|
248
|
-
}
|
|
249
|
-
return 0;
|
|
250
|
-
})
|
|
251
|
-
);
|
|
252
|
-
return _lodash2.default.sum(res);
|
|
253
|
-
}
|
|
254
|
-
async generatePreparedCodes() {
|
|
255
|
-
const { preparedCodes } = await this.getStatus();
|
|
256
|
-
if (preparedCodes.length === 0) {
|
|
257
|
-
console.log(_chalk2.default.green("\n\uD604\uC7AC \uBAA8\uB450 \uC2F1\uD06C\uB41C \uC0C1\uD0DC\uC785\uB2C8\uB2E4."));
|
|
258
|
-
return 0;
|
|
259
|
-
}
|
|
260
|
-
const migrationsDir = `${_chunk2WAC2GERjs.Sonamu.apiRootPath}/src/migrations`;
|
|
261
|
-
preparedCodes.filter((pcode) => pcode.formatted).map((pcode, index) => {
|
|
262
|
-
const dateTag = _luxon.DateTime.local().plus({ seconds: index }).toFormat("yyyyMMddHHmmss");
|
|
263
|
-
const filePath = `${migrationsDir}/${dateTag}_${pcode.title}.ts`;
|
|
264
|
-
_fsextra2.default.writeFileSync(filePath, pcode.formatted);
|
|
265
|
-
console.log(_chalk2.default.green(`MIGRTAION CREATED ${filePath}`));
|
|
266
|
-
});
|
|
267
|
-
return preparedCodes.length;
|
|
268
|
-
}
|
|
269
|
-
async clearPendingList() {
|
|
270
|
-
const pendingList = await this.targets.pending.getMigrations();
|
|
271
|
-
const migrationsDir = `${_chunk2WAC2GERjs.Sonamu.apiRootPath}/src/migrations`;
|
|
272
|
-
const delList = pendingList.map((df) => {
|
|
273
|
-
return _path2.default.join(migrationsDir, `${df}.ts`);
|
|
274
|
-
});
|
|
275
|
-
for (let p of delList) {
|
|
276
|
-
if (_fsextra2.default.existsSync(p)) {
|
|
277
|
-
_fsextra2.default.unlinkSync(p);
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
await this.cleanUpDist(true);
|
|
281
|
-
}
|
|
282
|
-
async check() {
|
|
283
|
-
const codes = await this.compareMigrations(this.targets.compare);
|
|
284
|
-
if (codes.length === 0) {
|
|
285
|
-
console.log(_chalk2.default.green("\n\uD604\uC7AC \uBAA8\uB450 \uC2F1\uD06C\uB41C \uC0C1\uD0DC\uC785\uB2C8\uB2E4."));
|
|
286
|
-
return;
|
|
287
|
-
}
|
|
288
|
-
console.table(codes, ["type", "title"]);
|
|
289
|
-
console.log(codes[0]);
|
|
290
|
-
}
|
|
291
|
-
async run() {
|
|
292
|
-
const pendingList = await this.targets.pending.getMigrations();
|
|
293
|
-
if (pendingList.length > 0) {
|
|
294
|
-
console.log(
|
|
295
|
-
_chalk2.default.red("pending \uB41C \uB9C8\uC774\uADF8\uB808\uC774\uC158\uC774 \uC874\uC7AC\uD569\uB2C8\uB2E4."),
|
|
296
|
-
pendingList.map((pending) => pending.file)
|
|
297
|
-
);
|
|
298
|
-
const answer2 = await _prompts2.default.call(void 0, {
|
|
299
|
-
type: "confirm",
|
|
300
|
-
name: "value",
|
|
301
|
-
message: "Shadow DB \uD14C\uC2A4\uD2B8\uB97C \uC9C4\uD589\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?",
|
|
302
|
-
initial: true
|
|
303
|
-
});
|
|
304
|
-
if (answer2.value === false) {
|
|
305
|
-
return;
|
|
306
|
-
}
|
|
307
|
-
console.time(_chalk2.default.blue("Migrator - runShadowTest"));
|
|
308
|
-
await this.runShadowTest();
|
|
309
|
-
console.timeEnd(_chalk2.default.blue("Migrator - runShadowTest"));
|
|
310
|
-
await Promise.all(
|
|
311
|
-
this.targets.apply.map(async (applyDb) => {
|
|
312
|
-
const info = applyDb.connectionInfo;
|
|
313
|
-
const label = _chalk2.default.green(`APPLIED ${info.host} ${info.database}`);
|
|
314
|
-
console.time(label);
|
|
315
|
-
await applyDb.migrate();
|
|
316
|
-
console.timeEnd(label);
|
|
317
|
-
})
|
|
318
|
-
);
|
|
319
|
-
}
|
|
320
|
-
const codes = await this.compareMigrations(this.targets.compare);
|
|
321
|
-
if (codes.length === 0) {
|
|
322
|
-
console.log(_chalk2.default.green("\n\uD604\uC7AC \uBAA8\uB450 \uC2F1\uD06C\uB41C \uC0C1\uD0DC\uC785\uB2C8\uB2E4."));
|
|
323
|
-
return;
|
|
324
|
-
}
|
|
325
|
-
console.table(codes, ["type", "title"]);
|
|
326
|
-
const answer = await _prompts2.default.call(void 0, {
|
|
327
|
-
type: "confirm",
|
|
328
|
-
name: "value",
|
|
329
|
-
message: "\uB9C8\uC774\uADF8\uB808\uC774\uC158 \uCF54\uB4DC\uB97C \uC0DD\uC131\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?",
|
|
330
|
-
initial: false
|
|
331
|
-
});
|
|
332
|
-
if (answer.value === false) {
|
|
333
|
-
return;
|
|
334
|
-
}
|
|
335
|
-
const migrationsDir = `${_chunk2WAC2GERjs.Sonamu.apiRootPath}/src/migrations`;
|
|
336
|
-
codes.filter((code) => code.formatted).map((code, index) => {
|
|
337
|
-
const dateTag = _luxon.DateTime.local().plus({ seconds: index }).toFormat("yyyyMMddHHmmss");
|
|
338
|
-
const filePath = `${migrationsDir}/${dateTag}_${code.title}.ts`;
|
|
339
|
-
_fsextra2.default.writeFileSync(filePath, code.formatted);
|
|
340
|
-
console.log(_chalk2.default.green(`MIGRTAION CREATED ${filePath}`));
|
|
341
|
-
});
|
|
342
|
-
}
|
|
343
|
-
async rollback() {
|
|
344
|
-
console.time(_chalk2.default.red("rollback:"));
|
|
345
|
-
const rollbackAllResult = await Promise.all(
|
|
346
|
-
this.targets.apply.map(async (db) => {
|
|
347
|
-
return db.rollback();
|
|
348
|
-
})
|
|
349
|
-
);
|
|
350
|
-
console.dir({ rollbackAllResult }, { depth: null });
|
|
351
|
-
console.timeEnd(_chalk2.default.red("rollback:"));
|
|
352
|
-
}
|
|
353
|
-
async cleanUpDist(force = false) {
|
|
354
|
-
const files = ["src", "dist"].reduce(
|
|
355
|
-
(r, which) => {
|
|
356
|
-
const migrationPath = _path2.default.join(
|
|
357
|
-
_chunk2WAC2GERjs.Sonamu.apiRootPath,
|
|
358
|
-
which,
|
|
359
|
-
"migrations"
|
|
360
|
-
);
|
|
361
|
-
if (_fsextra2.default.existsSync(migrationPath) === false) {
|
|
362
|
-
_fsextra2.default.mkdirSync(migrationPath, {
|
|
363
|
-
recursive: true
|
|
364
|
-
});
|
|
365
|
-
}
|
|
366
|
-
const files2 = _fsextra2.default.readdirSync(migrationPath).filter((filename) => filename.startsWith(".") === false);
|
|
367
|
-
r[which] = files2;
|
|
368
|
-
return r;
|
|
369
|
-
},
|
|
370
|
-
{
|
|
371
|
-
src: [],
|
|
372
|
-
dist: []
|
|
373
|
-
}
|
|
374
|
-
);
|
|
375
|
-
const diffOnSrc = _lodash2.default.differenceBy(
|
|
376
|
-
files.src,
|
|
377
|
-
files.dist,
|
|
378
|
-
(filename) => filename.split(".")[0]
|
|
379
|
-
);
|
|
380
|
-
if (diffOnSrc.length > 0) {
|
|
381
|
-
throw new Error(
|
|
382
|
-
"\uCEF4\uD30C\uC77C \uB418\uC9C0 \uC54A\uC740 \uD30C\uC77C\uC774 \uC788\uC2B5\uB2C8\uB2E4.\n" + diffOnSrc.join("\n")
|
|
383
|
-
);
|
|
384
|
-
}
|
|
385
|
-
const diffOnDist = _lodash2.default.differenceBy(
|
|
386
|
-
files.dist,
|
|
387
|
-
files.src,
|
|
388
|
-
(filename) => filename.split(".")[0]
|
|
389
|
-
);
|
|
390
|
-
if (diffOnDist.length > 0) {
|
|
391
|
-
console.log(_chalk2.default.red("\uC6D0\uBCF8 ts\uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uB294 js\uD30C\uC77C\uC774 \uC788\uC2B5\uB2C8\uB2E4."));
|
|
392
|
-
console.log(diffOnDist);
|
|
393
|
-
if (!force) {
|
|
394
|
-
const answer = await _prompts2.default.call(void 0, {
|
|
395
|
-
type: "confirm",
|
|
396
|
-
name: "value",
|
|
397
|
-
message: "\uC0AD\uC81C\uB97C \uC9C4\uD589\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?",
|
|
398
|
-
initial: true
|
|
399
|
-
});
|
|
400
|
-
if (answer.value === false) {
|
|
401
|
-
return;
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
const filesToRm = diffOnDist.map((filename) => {
|
|
405
|
-
return _path2.default.join(_chunk2WAC2GERjs.Sonamu.apiRootPath, "dist", "migrations", filename);
|
|
406
|
-
});
|
|
407
|
-
filesToRm.map((filePath) => {
|
|
408
|
-
_fsextra2.default.unlinkSync(filePath);
|
|
409
|
-
});
|
|
410
|
-
console.log(_chalk2.default.green(`${filesToRm.length}\uAC74 \uC0AD\uC81C\uB418\uC5C8\uC2B5\uB2C8\uB2E4!`));
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
async runShadowTest() {
|
|
414
|
-
const tdb = _chunk2WAC2GERjs.DB.getClient("test");
|
|
415
|
-
const tdbConn = tdb.connectionInfo;
|
|
416
|
-
const shadowDatabase = tdbConn.database + "__migration_shadow";
|
|
417
|
-
const tmpSqlPath = `/tmp/${shadowDatabase}.sql`;
|
|
418
|
-
console.log(
|
|
419
|
-
_chalk2.default.magenta(`${tdbConn.database}\uC758 \uB370\uC774\uD130 ${tmpSqlPath}\uB85C \uB364\uD504`)
|
|
420
|
-
);
|
|
421
|
-
_child_process.execSync.call(void 0,
|
|
422
|
-
`mysqldump -h${tdbConn.host} -P${tdbConn.port} -u${tdbConn.user} -p'${tdbConn.password}' ${tdbConn.database} --single-transaction --no-create-db --triggers > ${tmpSqlPath};`
|
|
423
|
-
);
|
|
424
|
-
_child_process.execSync.call(void 0,
|
|
425
|
-
`sed -i'' -e 's/\`${tdbConn.database}\`/\`${shadowDatabase}\`/g' ${tmpSqlPath};`
|
|
426
|
-
);
|
|
427
|
-
console.log(_chalk2.default.magenta(`${shadowDatabase} \uB9AC\uC14B`));
|
|
428
|
-
await tdb.raw(`DROP DATABASE IF EXISTS \`${shadowDatabase}\`;`);
|
|
429
|
-
await tdb.raw(`CREATE DATABASE \`${shadowDatabase}\`;`);
|
|
430
|
-
console.log(_chalk2.default.magenta(`${shadowDatabase} \uB370\uC774\uD130\uBCA0\uC774\uC2A4 \uC0DD\uC131`));
|
|
431
|
-
_child_process.execSync.call(void 0,
|
|
432
|
-
`mysql -h${tdbConn.host} -P${tdbConn.port} -u${tdbConn.user} -p'${tdbConn.password}' ${shadowDatabase} < ${tmpSqlPath};`
|
|
433
|
-
);
|
|
434
|
-
try {
|
|
435
|
-
await tdb.raw(`USE \`${shadowDatabase}\`;`);
|
|
436
|
-
const [batchNo, applied] = await tdb.migrate();
|
|
437
|
-
console.log(_chalk2.default.green("Shadow DB \uD14C\uC2A4\uD2B8\uC5D0 \uC131\uACF5\uD588\uC2B5\uB2C8\uB2E4!"), {
|
|
438
|
-
batchNo,
|
|
439
|
-
applied
|
|
440
|
-
});
|
|
441
|
-
console.log(_chalk2.default.magenta(`${shadowDatabase} \uC0AD\uC81C`));
|
|
442
|
-
await tdb.raw(`DROP DATABASE IF EXISTS \`${shadowDatabase}\`;`);
|
|
443
|
-
return [
|
|
444
|
-
{
|
|
445
|
-
connKey: "shadow",
|
|
446
|
-
batchNo,
|
|
447
|
-
applied
|
|
448
|
-
}
|
|
449
|
-
];
|
|
450
|
-
} catch (e) {
|
|
451
|
-
console.error(e);
|
|
452
|
-
throw new (0, _chunk2WAC2GERjs.ServiceUnavailableException)("Shadow DB \uD14C\uC2A4\uD2B8 \uC9C4\uD589 \uC911 \uC5D0\uB7EC");
|
|
453
|
-
} finally {
|
|
454
|
-
await tdb.destroy();
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
async resetAll() {
|
|
458
|
-
const answer = await _prompts2.default.call(void 0, {
|
|
459
|
-
type: "confirm",
|
|
460
|
-
name: "value",
|
|
461
|
-
message: "\uBAA8\uB4E0 DB\uB97C \uB864\uBC31\uD558\uACE0 \uC804\uCCB4 \uB9C8\uC774\uADF8\uB808\uC774\uC158 \uD30C\uC77C\uC744 \uC0AD\uC81C\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?",
|
|
462
|
-
initial: false
|
|
463
|
-
});
|
|
464
|
-
if (answer.value === false) {
|
|
465
|
-
return;
|
|
466
|
-
}
|
|
467
|
-
console.time(_chalk2.default.red("rollback-all:"));
|
|
468
|
-
const rollbackAllResult = await Promise.all(
|
|
469
|
-
this.targets.apply.map(async (db) => {
|
|
470
|
-
return db.rollbackAll();
|
|
471
|
-
})
|
|
472
|
-
);
|
|
473
|
-
console.log({ rollbackAllResult });
|
|
474
|
-
console.timeEnd(_chalk2.default.red("rollback-all:"));
|
|
475
|
-
const migrationsDir = `${_chunk2WAC2GERjs.Sonamu.apiRootPath}/src/migrations`;
|
|
476
|
-
console.time(_chalk2.default.red("delete migration files"));
|
|
477
|
-
_child_process.execSync.call(void 0, `rm -f ${migrationsDir}/*`);
|
|
478
|
-
_child_process.execSync.call(void 0, `rm -f ${migrationsDir.replace("/src/", "/dist/")}/*`);
|
|
479
|
-
console.timeEnd(_chalk2.default.red("delete migration files"));
|
|
480
|
-
}
|
|
481
|
-
async compareMigrations(compareDB) {
|
|
482
|
-
const entityIds = _chunk2WAC2GERjs.EntityManager.getAllIds();
|
|
483
|
-
const entitySetsWithJoinTable = entityIds.filter((entityId) => {
|
|
484
|
-
const entity = _chunk2WAC2GERjs.EntityManager.get(entityId);
|
|
485
|
-
return entity.props.length > 0;
|
|
486
|
-
}).map((entityId) => {
|
|
487
|
-
const entity = _chunk2WAC2GERjs.EntityManager.get(entityId);
|
|
488
|
-
return this.getMigrationSetFromEntity(entity);
|
|
489
|
-
});
|
|
490
|
-
const joinTablesWithDup = entitySetsWithJoinTable.map((entitySet) => entitySet.joinTables).flat();
|
|
491
|
-
const joinTables = Object.values(
|
|
492
|
-
_lodash2.default.groupBy(joinTablesWithDup, (jt) => jt.table)
|
|
493
|
-
).map((tables) => {
|
|
494
|
-
if (tables.length === 1) {
|
|
495
|
-
return tables[0];
|
|
496
|
-
}
|
|
497
|
-
return {
|
|
498
|
-
...tables[0],
|
|
499
|
-
indexes: _lodash2.default.uniqBy(
|
|
500
|
-
tables.flatMap((t) => t.indexes),
|
|
501
|
-
(index) => [index.type, ...index.columns.sort()].join("-")
|
|
502
|
-
)
|
|
503
|
-
};
|
|
504
|
-
});
|
|
505
|
-
const entitySets = [
|
|
506
|
-
...entitySetsWithJoinTable,
|
|
507
|
-
...joinTables
|
|
508
|
-
];
|
|
509
|
-
const codes = (await Promise.all(
|
|
510
|
-
entitySets.map(async (entitySet) => {
|
|
511
|
-
const dbSet = await this.getMigrationSetFromDB(
|
|
512
|
-
compareDB,
|
|
513
|
-
entitySet.table
|
|
514
|
-
);
|
|
515
|
-
if (dbSet === null) {
|
|
516
|
-
return [
|
|
517
|
-
await _chunk2WAC2GERjs.DB.generator.generateCreateCode_ColumnAndIndexes(
|
|
518
|
-
entitySet.table,
|
|
519
|
-
entitySet.columns,
|
|
520
|
-
entitySet.indexes
|
|
521
|
-
),
|
|
522
|
-
...await _chunk2WAC2GERjs.DB.generator.generateCreateCode_Foreign(
|
|
523
|
-
entitySet.table,
|
|
524
|
-
entitySet.foreigns
|
|
525
|
-
)
|
|
526
|
-
];
|
|
527
|
-
}
|
|
528
|
-
const alterCodes = await Promise.all(
|
|
529
|
-
["columnsAndIndexes", "foreigns"].map((key) => {
|
|
530
|
-
if (key === "columnsAndIndexes") {
|
|
531
|
-
const replaceColumnDefaultTo = (col) => {
|
|
532
|
-
if (col.type === "float" && col.defaultTo && String(col.defaultTo).includes('"') === false) {
|
|
533
|
-
col.defaultTo = `"${Number(col.defaultTo).toFixed(
|
|
534
|
-
_nullishCoalesce(col.scale, () => ( 2))
|
|
535
|
-
)}"`;
|
|
536
|
-
}
|
|
537
|
-
if (col.type === "string" && col.defaultTo === "") {
|
|
538
|
-
col.defaultTo = '""';
|
|
539
|
-
}
|
|
540
|
-
return col;
|
|
541
|
-
};
|
|
542
|
-
const entityColumns = _lodash2.default.sortBy(
|
|
543
|
-
entitySet.columns,
|
|
544
|
-
(a) => a.name
|
|
545
|
-
).map(replaceColumnDefaultTo);
|
|
546
|
-
const dbColumns = _lodash2.default.sortBy(dbSet.columns, (a) => a.name).map(
|
|
547
|
-
replaceColumnDefaultTo
|
|
548
|
-
);
|
|
549
|
-
const entityIndexes = _lodash2.default.sortBy(
|
|
550
|
-
entitySet.indexes,
|
|
551
|
-
(a) => [
|
|
552
|
-
a.type,
|
|
553
|
-
...a.columns.sort((c1, c2) => c1 > c2 ? 1 : -1)
|
|
554
|
-
].join("-")
|
|
555
|
-
);
|
|
556
|
-
const dbIndexes = _lodash2.default.sortBy(
|
|
557
|
-
dbSet.indexes,
|
|
558
|
-
(a) => [
|
|
559
|
-
a.type,
|
|
560
|
-
...a.columns.sort((c1, c2) => c1 > c2 ? 1 : -1)
|
|
561
|
-
].join("-")
|
|
562
|
-
);
|
|
563
|
-
const isEqualColumns = _fastdeepequal2.default.call(void 0, entityColumns, dbColumns);
|
|
564
|
-
const isEqualIndexes = _fastdeepequal2.default.call(void 0, entityIndexes, dbIndexes);
|
|
565
|
-
if (isEqualColumns && isEqualIndexes) {
|
|
566
|
-
return null;
|
|
567
|
-
} else {
|
|
568
|
-
return _chunk2WAC2GERjs.DB.generator.generateAlterCode_ColumnAndIndexes(
|
|
569
|
-
entitySet.table,
|
|
570
|
-
entityColumns,
|
|
571
|
-
entityIndexes,
|
|
572
|
-
dbColumns,
|
|
573
|
-
dbIndexes
|
|
574
|
-
);
|
|
575
|
-
}
|
|
576
|
-
} else {
|
|
577
|
-
const replaceNoActionOnMySQL = (f) => {
|
|
578
|
-
const { onDelete, onUpdate } = f;
|
|
579
|
-
return {
|
|
580
|
-
...f,
|
|
581
|
-
onUpdate: onUpdate === "RESTRICT" ? "NO ACTION" : onUpdate,
|
|
582
|
-
onDelete: onDelete === "RESTRICT" ? "NO ACTION" : onDelete
|
|
583
|
-
};
|
|
584
|
-
};
|
|
585
|
-
const entityForeigns = _lodash2.default.sortBy(
|
|
586
|
-
entitySet.foreigns,
|
|
587
|
-
(a) => [a.to, ...a.columns].join("-")
|
|
588
|
-
).map((f) => replaceNoActionOnMySQL(f));
|
|
589
|
-
const dbForeigns = _lodash2.default.sortBy(
|
|
590
|
-
dbSet.foreigns,
|
|
591
|
-
(a) => [a.to, ...a.columns].join("-")
|
|
592
|
-
).map((f) => replaceNoActionOnMySQL(f));
|
|
593
|
-
if (_fastdeepequal2.default.call(void 0, entityForeigns, dbForeigns) === false) {
|
|
594
|
-
return _chunk2WAC2GERjs.DB.generator.generateAlterCode_Foreigns(
|
|
595
|
-
entitySet.table,
|
|
596
|
-
entityForeigns,
|
|
597
|
-
dbForeigns
|
|
598
|
-
);
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
|
-
return null;
|
|
602
|
-
})
|
|
603
|
-
);
|
|
604
|
-
if (alterCodes.every((alterCode) => alterCode === null)) {
|
|
605
|
-
return null;
|
|
606
|
-
} else {
|
|
607
|
-
return alterCodes.filter((alterCode) => alterCode !== null).flat();
|
|
608
|
-
}
|
|
609
|
-
})
|
|
610
|
-
)).flat().filter((code) => code !== null);
|
|
611
|
-
codes.sort((codeA, codeB) => {
|
|
612
|
-
if (codeA.type === "foreign" && codeB.type == "normal") {
|
|
613
|
-
return 1;
|
|
614
|
-
} else if (codeA.type === "normal" && codeB.type === "foreign") {
|
|
615
|
-
return -1;
|
|
616
|
-
} else {
|
|
617
|
-
return 0;
|
|
618
|
-
}
|
|
619
|
-
});
|
|
620
|
-
return codes;
|
|
621
|
-
}
|
|
622
|
-
/*
|
|
623
|
-
기존 테이블 정보 읽어서 MigrationSet 형식으로 리턴
|
|
624
|
-
*/
|
|
625
|
-
async getMigrationSetFromDB(compareDB, table) {
|
|
626
|
-
let dbColumns, dbIndexes, dbForeigns;
|
|
627
|
-
try {
|
|
628
|
-
[dbColumns, dbIndexes, dbForeigns] = await this.readTable(
|
|
629
|
-
compareDB,
|
|
630
|
-
table
|
|
631
|
-
);
|
|
632
|
-
} catch (e) {
|
|
633
|
-
if (_chunk2WAC2GERjs.isKnexError.call(void 0, e) && e.code === "ER_NO_SUCH_TABLE") {
|
|
634
|
-
return null;
|
|
635
|
-
}
|
|
636
|
-
console.error(e);
|
|
637
|
-
return null;
|
|
638
|
-
}
|
|
639
|
-
const columns = dbColumns.map((dbColumn) => {
|
|
640
|
-
const dbColType = this.resolveDBColType(dbColumn.Type, dbColumn.Field);
|
|
641
|
-
return {
|
|
642
|
-
name: dbColumn.Field,
|
|
643
|
-
nullable: dbColumn.Null !== "NO",
|
|
644
|
-
...dbColType,
|
|
645
|
-
...(() => {
|
|
646
|
-
if (dbColumn.Default !== null) {
|
|
647
|
-
return {
|
|
648
|
-
defaultTo: dbColumn.Default
|
|
649
|
-
};
|
|
650
|
-
}
|
|
651
|
-
return {};
|
|
652
|
-
})()
|
|
653
|
-
};
|
|
654
|
-
});
|
|
655
|
-
const dbIndexesGroup = _lodash2.default.groupBy(
|
|
656
|
-
dbIndexes.filter(
|
|
657
|
-
(dbIndex) => dbIndex.Key_name !== "PRIMARY" && !dbForeigns.find(
|
|
658
|
-
(dbForeign) => dbForeign.keyName === dbIndex.Key_name
|
|
659
|
-
)
|
|
660
|
-
),
|
|
661
|
-
(dbIndex) => dbIndex.Key_name
|
|
662
|
-
);
|
|
663
|
-
const indexes = Object.keys(dbIndexesGroup).map(
|
|
664
|
-
(keyName) => {
|
|
665
|
-
const currentIndexes = dbIndexesGroup[keyName];
|
|
666
|
-
return {
|
|
667
|
-
type: currentIndexes[0].Non_unique === 1 ? "index" : "unique",
|
|
668
|
-
columns: currentIndexes.map(
|
|
669
|
-
(currentIndex) => currentIndex.Column_name
|
|
670
|
-
)
|
|
671
|
-
};
|
|
672
|
-
}
|
|
673
|
-
);
|
|
674
|
-
const foreigns = dbForeigns.map((dbForeign) => {
|
|
675
|
-
return {
|
|
676
|
-
columns: [dbForeign.from],
|
|
677
|
-
to: `${dbForeign.referencesTable}.${dbForeign.referencesField}`,
|
|
678
|
-
onUpdate: dbForeign.onUpdate,
|
|
679
|
-
onDelete: dbForeign.onDelete
|
|
680
|
-
};
|
|
681
|
-
});
|
|
682
|
-
return {
|
|
683
|
-
table,
|
|
684
|
-
columns,
|
|
685
|
-
indexes,
|
|
686
|
-
foreigns
|
|
687
|
-
};
|
|
688
|
-
}
|
|
689
|
-
resolveDBColType(colType, colField) {
|
|
690
|
-
let [rawType, unsigned] = colType.split(" ");
|
|
691
|
-
const matched = rawType.match(/\(([0-9]+)\)/);
|
|
692
|
-
let length;
|
|
693
|
-
if (matched !== null && matched[1]) {
|
|
694
|
-
rawType = rawType.replace(/\(([0-9]+)\)/, "");
|
|
695
|
-
length = parseInt(matched[1]);
|
|
696
|
-
}
|
|
697
|
-
if (rawType === "char" && colField === "uuid") {
|
|
698
|
-
return {
|
|
699
|
-
type: "uuid"
|
|
700
|
-
};
|
|
701
|
-
}
|
|
702
|
-
switch (rawType) {
|
|
703
|
-
case "int":
|
|
704
|
-
return {
|
|
705
|
-
type: "integer",
|
|
706
|
-
unsigned: unsigned === "unsigned"
|
|
707
|
-
};
|
|
708
|
-
case "varchar":
|
|
709
|
-
return {
|
|
710
|
-
type: "string",
|
|
711
|
-
...length !== void 0 && {
|
|
712
|
-
length
|
|
713
|
-
}
|
|
714
|
-
};
|
|
715
|
-
case "text":
|
|
716
|
-
case "mediumtext":
|
|
717
|
-
case "longtext":
|
|
718
|
-
case "timestamp":
|
|
719
|
-
case "json":
|
|
720
|
-
case "date":
|
|
721
|
-
case "time":
|
|
722
|
-
return {
|
|
723
|
-
type: rawType
|
|
724
|
-
};
|
|
725
|
-
case "datetime":
|
|
726
|
-
return {
|
|
727
|
-
type: "datetime"
|
|
728
|
-
};
|
|
729
|
-
case "tinyint":
|
|
730
|
-
return {
|
|
731
|
-
type: "boolean"
|
|
732
|
-
};
|
|
733
|
-
default:
|
|
734
|
-
if (rawType.startsWith("decimal")) {
|
|
735
|
-
const [, precision, scale] = _nullishCoalesce(rawType.match(/decimal\(([0-9]+),([0-9]+)\)/), () => ( []));
|
|
736
|
-
return {
|
|
737
|
-
type: "decimal",
|
|
738
|
-
precision: parseInt(precision),
|
|
739
|
-
scale: parseInt(scale),
|
|
740
|
-
...unsigned === "unsigned" && {
|
|
741
|
-
unsigned: true
|
|
742
|
-
}
|
|
743
|
-
};
|
|
744
|
-
} else if (rawType.startsWith("float")) {
|
|
745
|
-
const [, precision, scale] = _nullishCoalesce(rawType.match(/float\(([0-9]+),([0-9]+)\)/), () => ( []));
|
|
746
|
-
return {
|
|
747
|
-
type: "float",
|
|
748
|
-
precision: parseInt(precision),
|
|
749
|
-
scale: parseInt(scale),
|
|
750
|
-
...unsigned === "unsigned" && {
|
|
751
|
-
unsigned: true
|
|
752
|
-
}
|
|
753
|
-
};
|
|
754
|
-
}
|
|
755
|
-
throw new Error(`resolve \uBD88\uAC00\uB2A5\uD55C DB\uCEEC\uB7FC \uD0C0\uC785 ${colType} ${rawType}`);
|
|
756
|
-
}
|
|
757
|
-
}
|
|
758
|
-
/*
|
|
759
|
-
기존 테이블 읽어서 cols, indexes 반환
|
|
760
|
-
*/
|
|
761
|
-
async readTable(compareDB, tableName) {
|
|
762
|
-
try {
|
|
763
|
-
const _cols = await compareDB.raw(
|
|
764
|
-
`SHOW FIELDS FROM ${tableName}`
|
|
765
|
-
);
|
|
766
|
-
const cols = _cols.map((col) => ({
|
|
767
|
-
...col,
|
|
768
|
-
// Default 값은 숫자나 MySQL Expression이 아닌 경우 ""로 감싸줌
|
|
769
|
-
...col.Default !== null && {
|
|
770
|
-
Default: col.Default.replace(/[0-9]+/g, "").length > 0 && col.Extra !== "DEFAULT_GENERATED" ? `"${col.Default}"` : col.Default
|
|
771
|
-
}
|
|
772
|
-
}));
|
|
773
|
-
const indexes = await compareDB.raw(
|
|
774
|
-
`SHOW INDEX FROM ${tableName}`
|
|
775
|
-
);
|
|
776
|
-
const [row] = await compareDB.raw(`SHOW CREATE TABLE ${tableName}`);
|
|
777
|
-
const ddl = row["Create Table"];
|
|
778
|
-
const matched = ddl.match(/CONSTRAINT .+/g);
|
|
779
|
-
const foreignKeys = (_nullishCoalesce(matched, () => ( []))).map((line) => {
|
|
780
|
-
const matched2 = line.match(
|
|
781
|
-
/CONSTRAINT `(.+)` FOREIGN KEY \(`(.+)`\) REFERENCES `(.+)` \(`(.+)`\)( ON [A-Z ]+)*/
|
|
782
|
-
);
|
|
783
|
-
if (!matched2) {
|
|
784
|
-
throw new Error(`\uC778\uC2DD\uD560 \uC218 \uC5C6\uB294 FOREIGN KEY CONSTRAINT ${line}`);
|
|
785
|
-
}
|
|
786
|
-
const [, keyName, from, referencesTable, referencesField, onClause] = matched2;
|
|
787
|
-
const [onUpdateFull, _onUpdate] = _nullishCoalesce((_nullishCoalesce(onClause, () => ( ""))).match(/ON UPDATE ([A-Z ]+)$/), () => ( []));
|
|
788
|
-
const onUpdate = _nullishCoalesce(_onUpdate, () => ( "NO ACTION"));
|
|
789
|
-
const onDelete = _nullishCoalesce(_optionalChain([(_nullishCoalesce(onClause, () => ( ""))), 'access', _3 => _3.replace, 'call', _4 => _4(_nullishCoalesce(onUpdateFull, () => ( "")), ""), 'access', _5 => _5.match, 'call', _6 => _6(/ON DELETE ([A-Z ]+)/), 'optionalAccess', _7 => _7[1], 'optionalAccess', _8 => _8.trim, 'call', _9 => _9()]), () => ( "NO ACTION"));
|
|
790
|
-
return {
|
|
791
|
-
keyName,
|
|
792
|
-
from,
|
|
793
|
-
referencesTable,
|
|
794
|
-
referencesField,
|
|
795
|
-
onDelete,
|
|
796
|
-
onUpdate
|
|
797
|
-
};
|
|
798
|
-
});
|
|
799
|
-
return [cols, indexes, foreignKeys];
|
|
800
|
-
} catch (e) {
|
|
801
|
-
throw e;
|
|
802
|
-
}
|
|
803
|
-
}
|
|
804
|
-
/*
|
|
805
|
-
Entity 내용 읽어서 MigrationSetAndJoinTable 추출
|
|
806
|
-
*/
|
|
807
|
-
getMigrationSetFromEntity(entity) {
|
|
808
|
-
const migrationSet = entity.props.reduce(
|
|
809
|
-
(r, prop) => {
|
|
810
|
-
if (_chunk2WAC2GERjs.isVirtualProp.call(void 0, prop)) {
|
|
811
|
-
return r;
|
|
812
|
-
}
|
|
813
|
-
if (_chunk2WAC2GERjs.isHasManyRelationProp.call(void 0, prop)) {
|
|
814
|
-
return r;
|
|
815
|
-
}
|
|
816
|
-
if (!_chunk2WAC2GERjs.isRelationProp.call(void 0, prop)) {
|
|
817
|
-
let type;
|
|
818
|
-
if (_chunk2WAC2GERjs.isTextProp.call(void 0, prop)) {
|
|
819
|
-
type = prop.textType;
|
|
820
|
-
} else if (_chunk2WAC2GERjs.isEnumProp.call(void 0, prop)) {
|
|
821
|
-
type = "string";
|
|
822
|
-
} else {
|
|
823
|
-
type = prop.type;
|
|
824
|
-
}
|
|
825
|
-
const column = {
|
|
826
|
-
name: prop.name,
|
|
827
|
-
type,
|
|
828
|
-
..._chunk2WAC2GERjs.isIntegerProp.call(void 0, prop) && { unsigned: prop.unsigned === true },
|
|
829
|
-
...(_chunk2WAC2GERjs.isStringProp.call(void 0, prop) || _chunk2WAC2GERjs.isEnumProp.call(void 0, prop)) && {
|
|
830
|
-
length: prop.length
|
|
831
|
-
},
|
|
832
|
-
nullable: prop.nullable === true,
|
|
833
|
-
...(() => {
|
|
834
|
-
if (prop.dbDefault !== void 0) {
|
|
835
|
-
return {
|
|
836
|
-
defaultTo: prop.dbDefault
|
|
837
|
-
};
|
|
838
|
-
}
|
|
839
|
-
return {};
|
|
840
|
-
})(),
|
|
841
|
-
// FIXME: float(N, M) deprecated
|
|
842
|
-
// Decimal, Float 타입의 경우 precision, scale 추가
|
|
843
|
-
...(_chunk2WAC2GERjs.isDecimalProp.call(void 0, prop) || _chunk2WAC2GERjs.isFloatProp.call(void 0, prop)) && {
|
|
844
|
-
precision: _nullishCoalesce(prop.precision, () => ( 8)),
|
|
845
|
-
scale: _nullishCoalesce(prop.scale, () => ( 2))
|
|
846
|
-
}
|
|
847
|
-
};
|
|
848
|
-
r.columns.push(column);
|
|
849
|
-
}
|
|
850
|
-
if (_chunk2WAC2GERjs.isManyToManyRelationProp.call(void 0, prop)) {
|
|
851
|
-
const relMd = _chunk2WAC2GERjs.EntityManager.get(prop.with);
|
|
852
|
-
const [table1, table2] = prop.joinTable.split("__");
|
|
853
|
-
const join = {
|
|
854
|
-
from: `${entity.table}.id`,
|
|
855
|
-
through: {
|
|
856
|
-
from: `${prop.joinTable}.${_inflection2.default.singularize(table1)}_id`,
|
|
857
|
-
to: `${prop.joinTable}.${_inflection2.default.singularize(table2)}_id`,
|
|
858
|
-
onUpdate: prop.onUpdate,
|
|
859
|
-
onDelete: prop.onDelete
|
|
860
|
-
},
|
|
861
|
-
to: `${relMd.table}.id`
|
|
862
|
-
};
|
|
863
|
-
const through = join.through;
|
|
864
|
-
const fields = [through.from, through.to];
|
|
865
|
-
r.joinTables.push({
|
|
866
|
-
table: through.from.split(".")[0],
|
|
867
|
-
indexes: [
|
|
868
|
-
{
|
|
869
|
-
type: "unique",
|
|
870
|
-
columns: ["uuid"]
|
|
871
|
-
},
|
|
872
|
-
// 조인 테이블에 걸린 인덱스 찾아와서 연결
|
|
873
|
-
...entity.indexes.filter(
|
|
874
|
-
(index) => index.columns.find(
|
|
875
|
-
(col) => col.includes(prop.joinTable + ".")
|
|
876
|
-
)
|
|
877
|
-
).map((index) => ({
|
|
878
|
-
...index,
|
|
879
|
-
columns: index.columns.map(
|
|
880
|
-
(col) => col.replace(prop.joinTable + ".", "")
|
|
881
|
-
)
|
|
882
|
-
}))
|
|
883
|
-
],
|
|
884
|
-
columns: [
|
|
885
|
-
{
|
|
886
|
-
name: "id",
|
|
887
|
-
type: "integer",
|
|
888
|
-
nullable: false,
|
|
889
|
-
unsigned: true
|
|
890
|
-
},
|
|
891
|
-
...fields.map((field) => {
|
|
892
|
-
return {
|
|
893
|
-
name: field.split(".")[1],
|
|
894
|
-
type: "integer",
|
|
895
|
-
nullable: false,
|
|
896
|
-
unsigned: true
|
|
897
|
-
};
|
|
898
|
-
}),
|
|
899
|
-
{
|
|
900
|
-
name: "uuid",
|
|
901
|
-
nullable: true,
|
|
902
|
-
type: "uuid"
|
|
903
|
-
}
|
|
904
|
-
],
|
|
905
|
-
foreigns: fields.map((field) => {
|
|
906
|
-
const col = field.split(".")[1];
|
|
907
|
-
const to = (() => {
|
|
908
|
-
if (_inflection2.default.singularize(join.to.split(".")[0]) + "_id" === col) {
|
|
909
|
-
return join.to;
|
|
910
|
-
} else {
|
|
911
|
-
return join.from;
|
|
912
|
-
}
|
|
913
|
-
})();
|
|
914
|
-
return {
|
|
915
|
-
columns: [col],
|
|
916
|
-
to,
|
|
917
|
-
onUpdate: through.onUpdate,
|
|
918
|
-
onDelete: through.onDelete
|
|
919
|
-
};
|
|
920
|
-
})
|
|
921
|
-
});
|
|
922
|
-
return r;
|
|
923
|
-
} else if (_chunk2WAC2GERjs.isBelongsToOneRelationProp.call(void 0, prop) || _chunk2WAC2GERjs.isOneToOneRelationProp.call(void 0, prop) && prop.hasJoinColumn) {
|
|
924
|
-
const idColumnName = prop.name + "_id";
|
|
925
|
-
r.columns.push({
|
|
926
|
-
name: idColumnName,
|
|
927
|
-
type: "integer",
|
|
928
|
-
unsigned: true,
|
|
929
|
-
nullable: _nullishCoalesce(prop.nullable, () => ( false))
|
|
930
|
-
});
|
|
931
|
-
if ((_nullishCoalesce(prop.useConstraint, () => ( true))) === true) {
|
|
932
|
-
r.foreigns.push({
|
|
933
|
-
columns: [idColumnName],
|
|
934
|
-
to: `${_inflection2.default.underscore(_inflection2.default.pluralize(prop.with)).toLowerCase()}.id`,
|
|
935
|
-
onUpdate: _nullishCoalesce(prop.onUpdate, () => ( "RESTRICT")),
|
|
936
|
-
onDelete: _nullishCoalesce(prop.onDelete, () => ( "RESTRICT"))
|
|
937
|
-
});
|
|
938
|
-
}
|
|
939
|
-
}
|
|
940
|
-
return r;
|
|
941
|
-
},
|
|
942
|
-
{
|
|
943
|
-
table: entity.table,
|
|
944
|
-
columns: [],
|
|
945
|
-
indexes: [],
|
|
946
|
-
foreigns: [],
|
|
947
|
-
joinTables: []
|
|
948
|
-
}
|
|
949
|
-
);
|
|
950
|
-
migrationSet.indexes = entity.indexes.filter(
|
|
951
|
-
(index) => index.columns.find((col) => col.includes(".") === false)
|
|
952
|
-
);
|
|
953
|
-
migrationSet.columns = migrationSet.columns.concat({
|
|
954
|
-
name: "uuid",
|
|
955
|
-
nullable: true,
|
|
956
|
-
type: "uuid"
|
|
957
|
-
});
|
|
958
|
-
migrationSet.indexes = migrationSet.indexes.concat({
|
|
959
|
-
type: "unique",
|
|
960
|
-
columns: ["uuid"]
|
|
961
|
-
});
|
|
962
|
-
return migrationSet;
|
|
963
|
-
}
|
|
964
|
-
/*
|
|
965
|
-
마이그레이션 컬럼 배열 비교용 코드
|
|
966
|
-
*/
|
|
967
|
-
showMigrationSet(which, migrationSet) {
|
|
968
|
-
const { columns, indexes, foreigns } = migrationSet;
|
|
969
|
-
const styledChalk = which === "Entity" ? _chalk2.default.bgGreen.black : _chalk2.default.bgBlue.black;
|
|
970
|
-
console.log(
|
|
971
|
-
styledChalk(
|
|
972
|
-
`${which} ${migrationSet.table} Columns `
|
|
973
|
-
)
|
|
974
|
-
);
|
|
975
|
-
console.table(
|
|
976
|
-
columns.map((column) => {
|
|
977
|
-
return {
|
|
978
|
-
..._lodash2.default.pick(column, [
|
|
979
|
-
"name",
|
|
980
|
-
"type",
|
|
981
|
-
"nullable",
|
|
982
|
-
"unsigned",
|
|
983
|
-
"length",
|
|
984
|
-
"defaultTo",
|
|
985
|
-
"precision",
|
|
986
|
-
"scale"
|
|
987
|
-
])
|
|
988
|
-
};
|
|
989
|
-
}),
|
|
990
|
-
[
|
|
991
|
-
"name",
|
|
992
|
-
"type",
|
|
993
|
-
"nullable",
|
|
994
|
-
"unsigned",
|
|
995
|
-
"length",
|
|
996
|
-
"defaultTo",
|
|
997
|
-
"precision",
|
|
998
|
-
"scale"
|
|
999
|
-
]
|
|
1000
|
-
);
|
|
1001
|
-
if (indexes.length > 0) {
|
|
1002
|
-
console.log(
|
|
1003
|
-
styledChalk(
|
|
1004
|
-
`${which} ${migrationSet.table} Indexes `
|
|
1005
|
-
)
|
|
1006
|
-
);
|
|
1007
|
-
console.table(
|
|
1008
|
-
indexes.map((index) => {
|
|
1009
|
-
return {
|
|
1010
|
-
..._lodash2.default.pick(index, ["type", "columns", "name"])
|
|
1011
|
-
};
|
|
1012
|
-
})
|
|
1013
|
-
);
|
|
1014
|
-
}
|
|
1015
|
-
if (foreigns.length > 0) {
|
|
1016
|
-
console.log(
|
|
1017
|
-
_chalk2.default.bgMagenta.black(
|
|
1018
|
-
`${which} ${migrationSet.table} Foreigns `
|
|
1019
|
-
)
|
|
1020
|
-
);
|
|
1021
|
-
console.table(
|
|
1022
|
-
foreigns.map((foreign) => {
|
|
1023
|
-
return {
|
|
1024
|
-
..._lodash2.default.pick(foreign, ["columns", "to", "onUpdate", "onDelete"])
|
|
1025
|
-
};
|
|
1026
|
-
})
|
|
1027
|
-
);
|
|
1028
|
-
}
|
|
1029
|
-
}
|
|
1030
|
-
async destroy() {
|
|
1031
|
-
await Promise.all(
|
|
1032
|
-
this.targets.apply.map((db) => {
|
|
1033
|
-
return db.destroy();
|
|
1034
|
-
})
|
|
1035
|
-
);
|
|
1036
|
-
}
|
|
1037
|
-
};
|
|
1038
|
-
|
|
1039
|
-
// src/testing/fixture-manager.ts
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
var _fs = require('fs');
|
|
1044
|
-
|
|
1045
|
-
// src/testing/_relation-graph.ts
|
|
1046
|
-
var RelationGraph = (_class = class {constructor() { _class.prototype.__init.call(this); }
|
|
1047
|
-
__init() {this.graph = /* @__PURE__ */ new Map()}
|
|
1048
|
-
buildGraph(fixtures) {
|
|
1049
|
-
this.graph.clear();
|
|
1050
|
-
for (const fixture of fixtures) {
|
|
1051
|
-
this.graph.set(fixture.fixtureId, {
|
|
1052
|
-
fixtureId: fixture.fixtureId,
|
|
1053
|
-
entityId: fixture.entityId,
|
|
1054
|
-
related: /* @__PURE__ */ new Set()
|
|
1055
|
-
});
|
|
1056
|
-
}
|
|
1057
|
-
for (const fixture of fixtures) {
|
|
1058
|
-
const node = this.graph.get(fixture.fixtureId);
|
|
1059
|
-
for (const [, column] of Object.entries(fixture.columns)) {
|
|
1060
|
-
const prop = column.prop;
|
|
1061
|
-
if (_chunk2WAC2GERjs.isRelationProp.call(void 0, prop)) {
|
|
1062
|
-
if (_chunk2WAC2GERjs.isBelongsToOneRelationProp.call(void 0, prop) || _chunk2WAC2GERjs.isOneToOneRelationProp.call(void 0, prop) && prop.hasJoinColumn) {
|
|
1063
|
-
const relatedFixtureId = `${prop.with}#${column.value}`;
|
|
1064
|
-
if (this.graph.has(relatedFixtureId)) {
|
|
1065
|
-
node.related.add(relatedFixtureId);
|
|
1066
|
-
}
|
|
1067
|
-
} else if (_chunk2WAC2GERjs.isManyToManyRelationProp.call(void 0, prop)) {
|
|
1068
|
-
const relatedIds = column.value;
|
|
1069
|
-
for (const relatedId of relatedIds) {
|
|
1070
|
-
const relatedFixtureId = `${prop.with}#${relatedId}`;
|
|
1071
|
-
if (this.graph.has(relatedFixtureId)) {
|
|
1072
|
-
node.related.add(relatedFixtureId);
|
|
1073
|
-
this.graph.get(relatedFixtureId).related.add(fixture.fixtureId);
|
|
1074
|
-
}
|
|
1075
|
-
}
|
|
1076
|
-
}
|
|
1077
|
-
}
|
|
1078
|
-
}
|
|
1079
|
-
}
|
|
1080
|
-
}
|
|
1081
|
-
getInsertionOrder() {
|
|
1082
|
-
const visited = /* @__PURE__ */ new Set();
|
|
1083
|
-
const order = [];
|
|
1084
|
-
const tempVisited = /* @__PURE__ */ new Set();
|
|
1085
|
-
const visit = (fixtureId) => {
|
|
1086
|
-
if (visited.has(fixtureId)) return;
|
|
1087
|
-
if (tempVisited.has(fixtureId)) {
|
|
1088
|
-
console.warn(`Circular dependency detected involving: ${fixtureId}`);
|
|
1089
|
-
return;
|
|
1090
|
-
}
|
|
1091
|
-
tempVisited.add(fixtureId);
|
|
1092
|
-
const node = this.graph.get(fixtureId);
|
|
1093
|
-
const entity = _chunk2WAC2GERjs.EntityManager.get(node.entityId);
|
|
1094
|
-
for (const depId of node.related) {
|
|
1095
|
-
const depNode = this.graph.get(depId);
|
|
1096
|
-
const relationProp = entity.props.find(
|
|
1097
|
-
(prop) => _chunk2WAC2GERjs.isRelationProp.call(void 0, prop) && (_chunk2WAC2GERjs.isBelongsToOneRelationProp.call(void 0, prop) || _chunk2WAC2GERjs.isOneToOneRelationProp.call(void 0, prop) && prop.hasJoinColumn) && prop.with === depNode.entityId
|
|
1098
|
-
);
|
|
1099
|
-
if (relationProp && !relationProp.nullable) {
|
|
1100
|
-
visit(depId);
|
|
1101
|
-
}
|
|
1102
|
-
}
|
|
1103
|
-
tempVisited.delete(fixtureId);
|
|
1104
|
-
visited.add(fixtureId);
|
|
1105
|
-
order.push(fixtureId);
|
|
1106
|
-
};
|
|
1107
|
-
for (const fixtureId of this.graph.keys()) {
|
|
1108
|
-
visit(fixtureId);
|
|
1109
|
-
}
|
|
1110
|
-
for (const fixtureId of this.graph.keys()) {
|
|
1111
|
-
if (!visited.has(fixtureId)) {
|
|
1112
|
-
order.push(fixtureId);
|
|
1113
|
-
}
|
|
1114
|
-
}
|
|
1115
|
-
return order;
|
|
1116
|
-
}
|
|
1117
|
-
}, _class);
|
|
1118
|
-
|
|
1119
|
-
// src/testing/fixture-manager.ts
|
|
1120
|
-
var FixtureManagerClass = (_class2 = class {constructor() { _class2.prototype.__init2.call(this); }
|
|
1121
|
-
__init2() {this.relationGraph = new RelationGraph()}
|
|
1122
|
-
init() {
|
|
1123
|
-
_chunk2WAC2GERjs.DB.testInit();
|
|
1124
|
-
}
|
|
1125
|
-
async cleanAndSeed(usingTables) {
|
|
1126
|
-
const tableNames = await (async () => {
|
|
1127
|
-
if (usingTables) {
|
|
1128
|
-
return usingTables;
|
|
1129
|
-
}
|
|
1130
|
-
const tables = await _chunk2WAC2GERjs.DB.tdb.raw(
|
|
1131
|
-
`SHOW TABLE STATUS WHERE Engine IS NOT NULL`
|
|
1132
|
-
);
|
|
1133
|
-
return tables.map((tableInfo) => tableInfo["Name"]);
|
|
1134
|
-
})();
|
|
1135
|
-
await _chunk2WAC2GERjs.DB.tdb.raw(`SET FOREIGN_KEY_CHECKS = 0`);
|
|
1136
|
-
for await (let tableName of tableNames) {
|
|
1137
|
-
if (tableName == "migrations") {
|
|
1138
|
-
continue;
|
|
1139
|
-
}
|
|
1140
|
-
const [fdbChecksumRow] = await _chunk2WAC2GERjs.DB.fdb.raw(
|
|
1141
|
-
`CHECKSUM TABLE ${tableName}`
|
|
1142
|
-
);
|
|
1143
|
-
const fdbChecksum = fdbChecksumRow["Checksum"];
|
|
1144
|
-
const [tdbChecksumRow] = await _chunk2WAC2GERjs.DB.tdb.raw(
|
|
1145
|
-
`CHECKSUM TABLE ${tableName}`
|
|
1146
|
-
);
|
|
1147
|
-
const tdbChecksum = tdbChecksumRow["Checksum"];
|
|
1148
|
-
if (fdbChecksum !== tdbChecksum) {
|
|
1149
|
-
await _chunk2WAC2GERjs.DB.tdb.truncate(tableName);
|
|
1150
|
-
const rawQuery = `INSERT INTO ${_chunk2WAC2GERjs.DB.connectionInfo.test.database}.${tableName}
|
|
1151
|
-
SELECT * FROM ${_chunk2WAC2GERjs.DB.connectionInfo.fixture_local.database}.${tableName}`;
|
|
1152
|
-
await _chunk2WAC2GERjs.DB.tdb.raw(rawQuery);
|
|
1153
|
-
}
|
|
1154
|
-
}
|
|
1155
|
-
await _chunk2WAC2GERjs.DB.tdb.raw(`SET FOREIGN_KEY_CHECKS = 1`);
|
|
1156
|
-
}
|
|
1157
|
-
async getChecksum(db, tableName) {
|
|
1158
|
-
const [checksumRow] = await db.raw(
|
|
1159
|
-
`CHECKSUM TABLE ${tableName}`
|
|
1160
|
-
);
|
|
1161
|
-
return checksumRow.Checksum;
|
|
1162
|
-
}
|
|
1163
|
-
async sync() {
|
|
1164
|
-
const frdb = _chunk2WAC2GERjs.DB.getClient("fixture_remote");
|
|
1165
|
-
const tables = await _chunk2WAC2GERjs.DB.fdb.raw(
|
|
1166
|
-
"SHOW TABLE STATUS WHERE Engine IS NOT NULL"
|
|
1167
|
-
);
|
|
1168
|
-
const tableNames = tables.map(
|
|
1169
|
-
(table) => table.Name
|
|
1170
|
-
);
|
|
1171
|
-
console.log(_chalk2.default.magenta("SYNC..."));
|
|
1172
|
-
await Promise.all(
|
|
1173
|
-
tableNames.map(async (tableName) => {
|
|
1174
|
-
if (tableName.startsWith(_chunk2WAC2GERjs.DB.migrationTable)) {
|
|
1175
|
-
return;
|
|
1176
|
-
}
|
|
1177
|
-
const remoteChecksum = await this.getChecksum(frdb, tableName);
|
|
1178
|
-
const localChecksum = await this.getChecksum(_chunk2WAC2GERjs.DB.fdb, tableName);
|
|
1179
|
-
if (remoteChecksum !== localChecksum) {
|
|
1180
|
-
await _chunk2WAC2GERjs.DB.fdb.trx(async (transaction) => {
|
|
1181
|
-
await transaction.raw(`SET FOREIGN_KEY_CHECKS = 0`);
|
|
1182
|
-
await transaction.truncate(tableName);
|
|
1183
|
-
const rows = await frdb.raw(`SELECT * FROM ${tableName}`);
|
|
1184
|
-
if (rows.length === 0) {
|
|
1185
|
-
return;
|
|
1186
|
-
}
|
|
1187
|
-
console.log(_chalk2.default.blue(tableName), rows.length);
|
|
1188
|
-
await transaction.raw(
|
|
1189
|
-
`INSERT INTO ${tableName} (${Object.keys(rows[0]).map((k) => `\`${k}\``).join(",")}) VALUES ?`,
|
|
1190
|
-
[
|
|
1191
|
-
rows.map(
|
|
1192
|
-
(row) => Object.values(row).map((v) => {
|
|
1193
|
-
if (v === null) {
|
|
1194
|
-
return null;
|
|
1195
|
-
} else if (typeof v === "boolean") {
|
|
1196
|
-
return v ? 1 : 0;
|
|
1197
|
-
} else if (typeof v === "object") {
|
|
1198
|
-
return JSON.stringify(v);
|
|
1199
|
-
} else {
|
|
1200
|
-
return v;
|
|
1201
|
-
}
|
|
1202
|
-
})
|
|
1203
|
-
)
|
|
1204
|
-
]
|
|
1205
|
-
);
|
|
1206
|
-
console.log("OK");
|
|
1207
|
-
await transaction.raw(`SET FOREIGN_KEY_CHECKS = 1`);
|
|
1208
|
-
});
|
|
1209
|
-
}
|
|
1210
|
-
})
|
|
1211
|
-
);
|
|
1212
|
-
console.log(_chalk2.default.magenta("DONE!"));
|
|
1213
|
-
await frdb.destroy();
|
|
1214
|
-
}
|
|
1215
|
-
async importFixture(entityId, ids) {
|
|
1216
|
-
const queries = _lodash2.default.uniq(
|
|
1217
|
-
(await Promise.all(
|
|
1218
|
-
ids.map(async (id) => {
|
|
1219
|
-
return await this.getImportQueries(entityId, "id", id);
|
|
1220
|
-
})
|
|
1221
|
-
)).flat()
|
|
1222
|
-
);
|
|
1223
|
-
const wdb = _chunk2WAC2GERjs.DB.toClient(_chunk2WAC2GERjs.DB.getDB("w"));
|
|
1224
|
-
for (let query of queries) {
|
|
1225
|
-
const [rsh] = await wdb.raw(query);
|
|
1226
|
-
console.log({
|
|
1227
|
-
query,
|
|
1228
|
-
info: rsh.info
|
|
1229
|
-
});
|
|
1230
|
-
}
|
|
1231
|
-
}
|
|
1232
|
-
async getImportQueries(entityId, field, id) {
|
|
1233
|
-
console.log({ entityId, field, id });
|
|
1234
|
-
const entity = _chunk2WAC2GERjs.EntityManager.get(entityId);
|
|
1235
|
-
const wdb = _chunk2WAC2GERjs.DB.toClient(_chunk2WAC2GERjs.DB.getDB("w"));
|
|
1236
|
-
const [row] = await wdb.raw(
|
|
1237
|
-
`SELECT * FROM ${entity.table} WHERE ${field} = ${id} LIMIT 1`
|
|
1238
|
-
);
|
|
1239
|
-
if (row === void 0) {
|
|
1240
|
-
throw new Error(`${entityId}#${id} row\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.`);
|
|
1241
|
-
}
|
|
1242
|
-
const fixtureDatabase = _chunk2WAC2GERjs.DB.connectionInfo.fixture_remote.database;
|
|
1243
|
-
const realDatabase = _chunk2WAC2GERjs.DB.connectionInfo.production_master.database;
|
|
1244
|
-
const selfQuery = `INSERT IGNORE INTO \`${fixtureDatabase}\`.\`${entity.table}\` (SELECT * FROM \`${realDatabase}\`.\`${entity.table}\` WHERE \`id\` = ${id})`;
|
|
1245
|
-
const args = Object.entries(entity.relations).filter(
|
|
1246
|
-
([, relation]) => _chunk2WAC2GERjs.isBelongsToOneRelationProp.call(void 0, relation) || _chunk2WAC2GERjs.isOneToOneRelationProp.call(void 0, relation) && relation.customJoinClause === void 0
|
|
1247
|
-
).map(([, relation]) => {
|
|
1248
|
-
let field2;
|
|
1249
|
-
let id2;
|
|
1250
|
-
if (_chunk2WAC2GERjs.isOneToOneRelationProp.call(void 0, relation) && !relation.hasJoinColumn) {
|
|
1251
|
-
field2 = `${relation.name}_id`;
|
|
1252
|
-
id2 = row["id"];
|
|
1253
|
-
} else {
|
|
1254
|
-
field2 = "id";
|
|
1255
|
-
id2 = row[`${relation.name}_id`];
|
|
1256
|
-
}
|
|
1257
|
-
return {
|
|
1258
|
-
entityId: relation.with,
|
|
1259
|
-
field: field2,
|
|
1260
|
-
id: id2
|
|
1261
|
-
};
|
|
1262
|
-
}).filter((arg) => arg.id !== null);
|
|
1263
|
-
const relQueries = await Promise.all(
|
|
1264
|
-
args.map(async (args2) => {
|
|
1265
|
-
return this.getImportQueries(args2.entityId, args2.field, args2.id);
|
|
1266
|
-
})
|
|
1267
|
-
);
|
|
1268
|
-
return [..._lodash2.default.uniq(relQueries.reverse().flat()), selfQuery];
|
|
1269
|
-
}
|
|
1270
|
-
async destory() {
|
|
1271
|
-
await _chunk2WAC2GERjs.DB.testDestroy();
|
|
1272
|
-
await _chunk2WAC2GERjs.DB.destroy();
|
|
1273
|
-
}
|
|
1274
|
-
async getFixtures(sourceDBName, targetDBName, searchOptions) {
|
|
1275
|
-
const sourceDB = _chunk2WAC2GERjs.DB.getClient(sourceDBName);
|
|
1276
|
-
const targetDB = _chunk2WAC2GERjs.DB.getClient(targetDBName);
|
|
1277
|
-
const { entityId, field, value, searchType } = searchOptions;
|
|
1278
|
-
const entity = _chunk2WAC2GERjs.EntityManager.get(entityId);
|
|
1279
|
-
const column = _optionalChain([entity, 'access', _10 => _10.props, 'access', _11 => _11.find, 'call', _12 => _12((prop) => prop.name === field), 'optionalAccess', _13 => _13.type]) === "relation" ? `${field}_id` : field;
|
|
1280
|
-
let query = sourceDB.from(entity.table).selectAll();
|
|
1281
|
-
if (searchType === "equals") {
|
|
1282
|
-
query = query.where([column, "=", value]);
|
|
1283
|
-
} else if (searchType === "like") {
|
|
1284
|
-
query = query.where([column, "like", `%${value}%`]);
|
|
1285
|
-
}
|
|
1286
|
-
const rows = await query.execute();
|
|
1287
|
-
if (rows.length === 0) {
|
|
1288
|
-
throw new Error("No records found");
|
|
1289
|
-
}
|
|
1290
|
-
const fixtures = [];
|
|
1291
|
-
for (const row of rows) {
|
|
1292
|
-
const initialRecordsLength = fixtures.length;
|
|
1293
|
-
const newRecords = await this.createFixtureRecord(entity, row);
|
|
1294
|
-
fixtures.push(...newRecords);
|
|
1295
|
-
const currentFixtureRecord = fixtures.find(
|
|
1296
|
-
(r) => r.fixtureId === `${entityId}#${row.id}`
|
|
1297
|
-
);
|
|
1298
|
-
if (currentFixtureRecord) {
|
|
1299
|
-
currentFixtureRecord.fetchedRecords = fixtures.filter((r) => r.fixtureId !== currentFixtureRecord.fixtureId).slice(initialRecordsLength).map((r) => r.fixtureId);
|
|
1300
|
-
}
|
|
1301
|
-
}
|
|
1302
|
-
for await (const fixture of fixtures) {
|
|
1303
|
-
const entity2 = _chunk2WAC2GERjs.EntityManager.get(fixture.entityId);
|
|
1304
|
-
const [row] = await targetDB.from(entity2.table).selectAll().where(["id", "=", fixture.id]).first().execute();
|
|
1305
|
-
if (row) {
|
|
1306
|
-
const [record] = await this.createFixtureRecord(entity2, row, {
|
|
1307
|
-
singleRecord: true,
|
|
1308
|
-
_db: targetDB
|
|
1309
|
-
});
|
|
1310
|
-
fixture.target = record;
|
|
1311
|
-
continue;
|
|
1312
|
-
}
|
|
1313
|
-
const uniqueRow = await this.checkUniqueViolation(
|
|
1314
|
-
targetDB,
|
|
1315
|
-
entity2,
|
|
1316
|
-
fixture
|
|
1317
|
-
);
|
|
1318
|
-
if (uniqueRow) {
|
|
1319
|
-
const [record] = await this.createFixtureRecord(entity2, uniqueRow, {
|
|
1320
|
-
singleRecord: true,
|
|
1321
|
-
_db: targetDB
|
|
1322
|
-
});
|
|
1323
|
-
fixture.unique = record;
|
|
1324
|
-
}
|
|
1325
|
-
}
|
|
1326
|
-
return _lodash2.default.uniqBy(fixtures, (f) => f.fixtureId);
|
|
1327
|
-
}
|
|
1328
|
-
async createFixtureRecord(entity, row, options) {
|
|
1329
|
-
const records = [];
|
|
1330
|
-
const visitedEntities = /* @__PURE__ */ new Set();
|
|
1331
|
-
const create = async (entity2, row2) => {
|
|
1332
|
-
const fixtureId = `${entity2.id}#${row2.id}`;
|
|
1333
|
-
if (visitedEntities.has(fixtureId)) {
|
|
1334
|
-
return;
|
|
1335
|
-
}
|
|
1336
|
-
visitedEntities.add(fixtureId);
|
|
1337
|
-
const record = {
|
|
1338
|
-
fixtureId,
|
|
1339
|
-
entityId: entity2.id,
|
|
1340
|
-
id: row2.id,
|
|
1341
|
-
columns: {},
|
|
1342
|
-
fetchedRecords: [],
|
|
1343
|
-
belongsRecords: []
|
|
1344
|
-
};
|
|
1345
|
-
for (const prop of entity2.props) {
|
|
1346
|
-
if (_chunk2WAC2GERjs.isVirtualProp.call(void 0, prop)) {
|
|
1347
|
-
continue;
|
|
1348
|
-
}
|
|
1349
|
-
record.columns[prop.name] = {
|
|
1350
|
-
prop,
|
|
1351
|
-
value: row2[prop.name]
|
|
1352
|
-
};
|
|
1353
|
-
const db = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _14 => _14._db]), () => ( _chunk2WAC2GERjs.DB.toClient(_chunk2WAC2GERjs.DB.getDB("w"))));
|
|
1354
|
-
if (_chunk2WAC2GERjs.isManyToManyRelationProp.call(void 0, prop)) {
|
|
1355
|
-
const relatedEntity = _chunk2WAC2GERjs.EntityManager.get(prop.with);
|
|
1356
|
-
const throughTable = prop.joinTable;
|
|
1357
|
-
const fromColumn = `${_inflection2.default.singularize(entity2.table)}_id`;
|
|
1358
|
-
const toColumn = `${_inflection2.default.singularize(relatedEntity.table)}_id`;
|
|
1359
|
-
const _relatedIds = await db.from(throughTable).select(toColumn).where([fromColumn, "=", row2.id]).execute();
|
|
1360
|
-
const relatedIds = _relatedIds.map((r) => parseInt(r[toColumn]));
|
|
1361
|
-
record.columns[prop.name].value = relatedIds;
|
|
1362
|
-
} else if (_chunk2WAC2GERjs.isHasManyRelationProp.call(void 0, prop)) {
|
|
1363
|
-
const relatedEntity = _chunk2WAC2GERjs.EntityManager.get(prop.with);
|
|
1364
|
-
const relatedIds = await db.from(relatedEntity.table).select("id").where([prop.joinColumn, "=", row2.id]).pluck("id");
|
|
1365
|
-
record.columns[prop.name].value = relatedIds;
|
|
1366
|
-
} else if (_chunk2WAC2GERjs.isOneToOneRelationProp.call(void 0, prop) && !prop.hasJoinColumn) {
|
|
1367
|
-
const relatedEntity = _chunk2WAC2GERjs.EntityManager.get(prop.with);
|
|
1368
|
-
const relatedProp = relatedEntity.props.find(
|
|
1369
|
-
(p) => _chunk2WAC2GERjs.isRelationProp.call(void 0, p) && p.with === entity2.id
|
|
1370
|
-
);
|
|
1371
|
-
if (relatedProp) {
|
|
1372
|
-
const [relatedRow] = await db.from(relatedEntity.table).select("id").where([relatedProp.name, "=", row2.id]).first().execute();
|
|
1373
|
-
record.columns[prop.name].value = _optionalChain([relatedRow, 'optionalAccess', _15 => _15.id]);
|
|
1374
|
-
}
|
|
1375
|
-
} else if (_chunk2WAC2GERjs.isRelationProp.call(void 0, prop)) {
|
|
1376
|
-
const relatedId = row2[`${prop.name}_id`];
|
|
1377
|
-
record.columns[prop.name].value = relatedId;
|
|
1378
|
-
if (relatedId) {
|
|
1379
|
-
record.belongsRecords.push(`${prop.with}#${relatedId}`);
|
|
1380
|
-
}
|
|
1381
|
-
if (!_optionalChain([options, 'optionalAccess', _16 => _16.singleRecord]) && relatedId) {
|
|
1382
|
-
const relatedEntity = _chunk2WAC2GERjs.EntityManager.get(prop.with);
|
|
1383
|
-
const [relatedRow] = await db.from(relatedEntity.table).selectAll().where(["id", "=", relatedId]).first().execute();
|
|
1384
|
-
if (relatedRow) {
|
|
1385
|
-
await create(relatedEntity, relatedRow);
|
|
1386
|
-
}
|
|
1387
|
-
}
|
|
1388
|
-
}
|
|
1389
|
-
}
|
|
1390
|
-
records.push(record);
|
|
1391
|
-
};
|
|
1392
|
-
await create(entity, row);
|
|
1393
|
-
return records;
|
|
1394
|
-
}
|
|
1395
|
-
async insertFixtures(dbName, _fixtures) {
|
|
1396
|
-
const fixtures = _lodash2.default.uniqBy(_fixtures, (f) => f.fixtureId);
|
|
1397
|
-
this.relationGraph.buildGraph(fixtures);
|
|
1398
|
-
const insertionOrder = this.relationGraph.getInsertionOrder();
|
|
1399
|
-
const db = _chunk2WAC2GERjs.DB.getClient(dbName);
|
|
1400
|
-
await db.trx(async (trx) => {
|
|
1401
|
-
await trx.raw(`SET FOREIGN_KEY_CHECKS = 0`);
|
|
1402
|
-
for (const fixtureId of insertionOrder) {
|
|
1403
|
-
const fixture = fixtures.find((f) => f.fixtureId === fixtureId);
|
|
1404
|
-
const result = await this.insertFixture(trx, fixture);
|
|
1405
|
-
if (result.id !== fixture.id) {
|
|
1406
|
-
console.log(
|
|
1407
|
-
_chalk2.default.yellow(
|
|
1408
|
-
`Unique constraint violation: ${fixture.entityId}#${fixture.id} -> ${fixture.entityId}#${result.id}`
|
|
1409
|
-
)
|
|
1410
|
-
);
|
|
1411
|
-
fixtures.forEach((f) => {
|
|
1412
|
-
Object.values(f.columns).forEach((column) => {
|
|
1413
|
-
if (column.prop.type === "relation" && column.prop.with === result.entityId && column.value === fixture.id) {
|
|
1414
|
-
column.value = result.id;
|
|
1415
|
-
}
|
|
1416
|
-
});
|
|
1417
|
-
});
|
|
1418
|
-
fixture.id = result.id;
|
|
1419
|
-
}
|
|
1420
|
-
}
|
|
1421
|
-
for (const fixtureId of insertionOrder) {
|
|
1422
|
-
const fixture = fixtures.find((f) => f.fixtureId === fixtureId);
|
|
1423
|
-
await this.handleManyToManyRelations(trx, fixture, fixtures);
|
|
1424
|
-
}
|
|
1425
|
-
await trx.raw(`SET FOREIGN_KEY_CHECKS = 1`);
|
|
1426
|
-
});
|
|
1427
|
-
const records = [];
|
|
1428
|
-
for await (const r of fixtures) {
|
|
1429
|
-
const entity = _chunk2WAC2GERjs.EntityManager.get(r.entityId);
|
|
1430
|
-
const [record] = await db.from(entity.table).selectAll().where(["id", "=", r.id]).first().execute();
|
|
1431
|
-
records.push({
|
|
1432
|
-
entityId: r.entityId,
|
|
1433
|
-
data: record
|
|
1434
|
-
});
|
|
1435
|
-
}
|
|
1436
|
-
return _lodash2.default.uniqBy(records, (r) => `${r.entityId}#${r.data.id}`);
|
|
1437
|
-
}
|
|
1438
|
-
prepareInsertData(fixture) {
|
|
1439
|
-
const insertData = {};
|
|
1440
|
-
for (const [propName, column] of Object.entries(fixture.columns)) {
|
|
1441
|
-
if (_chunk2WAC2GERjs.isVirtualProp.call(void 0, column.prop)) {
|
|
1442
|
-
continue;
|
|
1443
|
-
}
|
|
1444
|
-
const prop = column.prop;
|
|
1445
|
-
if (!_chunk2WAC2GERjs.isRelationProp.call(void 0, prop)) {
|
|
1446
|
-
if (prop.type === "json") {
|
|
1447
|
-
insertData[propName] = JSON.stringify(column.value);
|
|
1448
|
-
} else {
|
|
1449
|
-
insertData[propName] = column.value;
|
|
1450
|
-
}
|
|
1451
|
-
} else if (_chunk2WAC2GERjs.isBelongsToOneRelationProp.call(void 0, prop) || _chunk2WAC2GERjs.isOneToOneRelationProp.call(void 0, prop) && prop.hasJoinColumn) {
|
|
1452
|
-
insertData[`${propName}_id`] = column.value;
|
|
1453
|
-
}
|
|
1454
|
-
}
|
|
1455
|
-
return insertData;
|
|
1456
|
-
}
|
|
1457
|
-
async insertFixture(db, fixture) {
|
|
1458
|
-
const insertData = this.prepareInsertData(fixture);
|
|
1459
|
-
const entity = _chunk2WAC2GERjs.EntityManager.get(fixture.entityId);
|
|
1460
|
-
try {
|
|
1461
|
-
const uniqueFound = await this.checkUniqueViolation(db, entity, fixture);
|
|
1462
|
-
if (uniqueFound) {
|
|
1463
|
-
return {
|
|
1464
|
-
entityId: fixture.entityId,
|
|
1465
|
-
id: uniqueFound.id
|
|
1466
|
-
};
|
|
1467
|
-
}
|
|
1468
|
-
const [found] = await db.from(entity.table).select("id").where(["id", "=", fixture.id]).first().execute();
|
|
1469
|
-
if (found && !fixture.override) {
|
|
1470
|
-
return {
|
|
1471
|
-
entityId: fixture.entityId,
|
|
1472
|
-
id: found.id
|
|
1473
|
-
};
|
|
1474
|
-
}
|
|
1475
|
-
await db.upsert(entity.table, [insertData]);
|
|
1476
|
-
return {
|
|
1477
|
-
entityId: fixture.entityId,
|
|
1478
|
-
id: fixture.id
|
|
1479
|
-
};
|
|
1480
|
-
} catch (err) {
|
|
1481
|
-
console.log(err);
|
|
1482
|
-
throw err;
|
|
1483
|
-
}
|
|
1484
|
-
}
|
|
1485
|
-
async handleManyToManyRelations(db, fixture, fixtures) {
|
|
1486
|
-
for (const [, column] of Object.entries(fixture.columns)) {
|
|
1487
|
-
const prop = column.prop;
|
|
1488
|
-
if (_chunk2WAC2GERjs.isManyToManyRelationProp.call(void 0, prop)) {
|
|
1489
|
-
const joinTable = prop.joinTable;
|
|
1490
|
-
const relatedIds = column.value;
|
|
1491
|
-
for (const relatedId of relatedIds) {
|
|
1492
|
-
if (!fixtures.find((f) => f.fixtureId === `${prop.with}#${relatedId}`)) {
|
|
1493
|
-
continue;
|
|
1494
|
-
}
|
|
1495
|
-
const entity = _chunk2WAC2GERjs.EntityManager.get(fixture.entityId);
|
|
1496
|
-
const relatedEntity = _chunk2WAC2GERjs.EntityManager.get(prop.with);
|
|
1497
|
-
if (!entity || !relatedEntity) {
|
|
1498
|
-
throw new Error(
|
|
1499
|
-
`Entity not found: ${fixture.entityId}, ${prop.with}`
|
|
1500
|
-
);
|
|
1501
|
-
}
|
|
1502
|
-
const [found] = await db.from(joinTable).select("id").where([
|
|
1503
|
-
[`${_inflection2.default.singularize(entity.table)}_id`, "=", fixture.id],
|
|
1504
|
-
[
|
|
1505
|
-
`${_inflection2.default.singularize(relatedEntity.table)}_id`,
|
|
1506
|
-
"=",
|
|
1507
|
-
relatedId
|
|
1508
|
-
]
|
|
1509
|
-
]).first().execute();
|
|
1510
|
-
if (found) {
|
|
1511
|
-
continue;
|
|
1512
|
-
}
|
|
1513
|
-
const newIds = await db.insert(joinTable, [
|
|
1514
|
-
{
|
|
1515
|
-
[`${_inflection2.default.singularize(entity.table)}_id`]: fixture.id,
|
|
1516
|
-
[`${_inflection2.default.singularize(relatedEntity.table)}_id`]: relatedId
|
|
1517
|
-
}
|
|
1518
|
-
]);
|
|
1519
|
-
console.log(
|
|
1520
|
-
_chalk2.default.green(
|
|
1521
|
-
`Inserted into ${joinTable}: ${entity.table}(${fixture.id}) - ${relatedEntity.table}(${relatedId}) ID: ${newIds}`
|
|
1522
|
-
)
|
|
1523
|
-
);
|
|
1524
|
-
}
|
|
1525
|
-
}
|
|
1526
|
-
}
|
|
1527
|
-
}
|
|
1528
|
-
async addFixtureLoader(code) {
|
|
1529
|
-
const path2 = _chunk2WAC2GERjs.Sonamu.apiRootPath + "/src/testing/fixture.ts";
|
|
1530
|
-
let content = _fs.readFileSync.call(void 0, path2).toString();
|
|
1531
|
-
const fixtureLoaderStart = content.indexOf("const fixtureLoader = {");
|
|
1532
|
-
const fixtureLoaderEnd = content.indexOf("};", fixtureLoaderStart);
|
|
1533
|
-
if (fixtureLoaderStart !== -1 && fixtureLoaderEnd !== -1) {
|
|
1534
|
-
const newContent = content.slice(0, fixtureLoaderEnd) + " " + code + "\n" + content.slice(fixtureLoaderEnd);
|
|
1535
|
-
_fs.writeFileSync.call(void 0, path2, newContent);
|
|
1536
|
-
} else {
|
|
1537
|
-
throw new Error("Failed to find fixtureLoader in fixture.ts");
|
|
1538
|
-
}
|
|
1539
|
-
}
|
|
1540
|
-
// 해당 픽스쳐의 값으로 유니크 제약에 위배되는 레코드가 있는지 확인
|
|
1541
|
-
async checkUniqueViolation(db, entity, fixture) {
|
|
1542
|
-
const _uniqueIndexes = entity.indexes.filter((i) => i.type === "unique");
|
|
1543
|
-
const uniqueIndexes = _uniqueIndexes.filter(
|
|
1544
|
-
(index) => index.columns.every((column) => !column.startsWith(`${entity.table}__`))
|
|
1545
|
-
);
|
|
1546
|
-
if (uniqueIndexes.length === 0) {
|
|
1547
|
-
return null;
|
|
1548
|
-
}
|
|
1549
|
-
let uniqueQuery = db.from(entity.table).selectAll();
|
|
1550
|
-
const whereClauses = uniqueIndexes.map((index) => {
|
|
1551
|
-
const containsNull = index.columns.some((column) => {
|
|
1552
|
-
const field = column.split("_id")[0];
|
|
1553
|
-
return fixture.columns[field].value === null;
|
|
1554
|
-
});
|
|
1555
|
-
if (containsNull) {
|
|
1556
|
-
return;
|
|
1557
|
-
}
|
|
1558
|
-
return index.columns.map((c) => {
|
|
1559
|
-
const field = c.split("_id")[0];
|
|
1560
|
-
if (Array.isArray(fixture.columns[field].value)) {
|
|
1561
|
-
return [c, "in", fixture.columns[field].value];
|
|
1562
|
-
} else {
|
|
1563
|
-
return [c, "=", fixture.columns[field].value];
|
|
1564
|
-
}
|
|
1565
|
-
});
|
|
1566
|
-
}).filter(Boolean);
|
|
1567
|
-
for (const clauses of whereClauses) {
|
|
1568
|
-
uniqueQuery = uniqueQuery.orWhere(clauses);
|
|
1569
|
-
}
|
|
1570
|
-
const [uniqueFound] = await uniqueQuery.execute();
|
|
1571
|
-
return uniqueFound;
|
|
1572
|
-
}
|
|
1573
|
-
}, _class2);
|
|
1574
|
-
var FixtureManager = new FixtureManagerClass();
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
exports.Migrator = Migrator; exports.FixtureManagerClass = FixtureManagerClass; exports.FixtureManager = FixtureManager;
|
|
1581
|
-
//# sourceMappingURL=chunk-OTKKFP3Y.js.map
|