sonamu 0.0.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/.pnp.cjs +15552 -0
- package/.pnp.loader.mjs +285 -0
- package/.vscode/extensions.json +6 -0
- package/.vscode/settings.json +9 -0
- package/.yarnrc.yml +5 -0
- package/dist/bin/cli.d.ts +2 -0
- package/dist/bin/cli.d.ts.map +1 -0
- package/dist/bin/cli.js +123 -0
- package/dist/bin/cli.js.map +1 -0
- package/dist/index.js +34 -0
- package/package.json +60 -0
- package/src/api/caster.ts +72 -0
- package/src/api/code-converters.ts +552 -0
- package/src/api/context.ts +20 -0
- package/src/api/decorators.ts +63 -0
- package/src/api/index.ts +5 -0
- package/src/api/init.ts +128 -0
- package/src/bin/cli.ts +115 -0
- package/src/database/base-model.ts +287 -0
- package/src/database/db.ts +95 -0
- package/src/database/knex-plugins/knex-on-duplicate-update.ts +41 -0
- package/src/database/upsert-builder.ts +231 -0
- package/src/exceptions/error-handler.ts +29 -0
- package/src/exceptions/so-exceptions.ts +91 -0
- package/src/index.ts +17 -0
- package/src/shared/web.shared.ts.txt +119 -0
- package/src/smd/migrator.ts +1462 -0
- package/src/smd/smd-manager.ts +141 -0
- package/src/smd/smd-utils.ts +266 -0
- package/src/smd/smd.ts +533 -0
- package/src/syncer/index.ts +1 -0
- package/src/syncer/syncer.ts +1283 -0
- package/src/templates/base-template.ts +19 -0
- package/src/templates/generated.template.ts +247 -0
- package/src/templates/generated_http.template.ts +114 -0
- package/src/templates/index.ts +1 -0
- package/src/templates/init_enums.template.ts +71 -0
- package/src/templates/init_generated.template.ts +44 -0
- package/src/templates/init_types.template.ts +38 -0
- package/src/templates/model.template.ts +168 -0
- package/src/templates/model_test.template.ts +39 -0
- package/src/templates/service.template.ts +263 -0
- package/src/templates/smd.template.ts +49 -0
- package/src/templates/view_enums_buttonset.template.ts +34 -0
- package/src/templates/view_enums_dropdown.template.ts +67 -0
- package/src/templates/view_enums_select.template.ts +60 -0
- package/src/templates/view_form.template.ts +397 -0
- package/src/templates/view_id_all_select.template.ts +34 -0
- package/src/templates/view_id_async_select.template.ts +113 -0
- package/src/templates/view_list.template.ts +652 -0
- package/src/templates/view_list_columns.template.ts +59 -0
- package/src/templates/view_search_input.template.ts +67 -0
- package/src/testing/fixture-manager.ts +271 -0
- package/src/types/types.ts +668 -0
- package/src/typings/knex.d.ts +24 -0
- package/src/utils/controller.ts +21 -0
- package/src/utils/lodash-able.ts +11 -0
- package/src/utils/model.ts +33 -0
- package/src/utils/utils.ts +28 -0
- package/tsconfig.json +47 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { TemplateOptions } from "../types/types";
|
|
2
|
+
import { SMDManager, SMDNamesRecord } from "../smd/smd-manager";
|
|
3
|
+
import { Template } from "./base-template";
|
|
4
|
+
|
|
5
|
+
export class Template__view_search_input extends Template {
|
|
6
|
+
constructor() {
|
|
7
|
+
super("view_search_input");
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
getTargetAndPath(names: SMDNamesRecord) {
|
|
11
|
+
return {
|
|
12
|
+
target: "web/src/components",
|
|
13
|
+
path: `${names.fs}/${names.capital}SearchInput.tsx`,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
render({ smdId }: TemplateOptions["view_search_input"]) {
|
|
18
|
+
const names = SMDManager.getNamesFromId(smdId);
|
|
19
|
+
|
|
20
|
+
return {
|
|
21
|
+
...this.getTargetAndPath(names),
|
|
22
|
+
body: `
|
|
23
|
+
import React from "react";
|
|
24
|
+
import { useState } from "react";
|
|
25
|
+
import { DropdownProps, Input, InputProps } from "semantic-ui-react";
|
|
26
|
+
import { ${names.capital}SearchFieldDropdown } from "src/components/${names.fs}/${names.capital}SearchFieldDropdown";
|
|
27
|
+
|
|
28
|
+
export function ${names.capital}SearchInput({
|
|
29
|
+
input: { value: inputValue, onChange: inputOnChange, ...inputProps },
|
|
30
|
+
dropdown: dropdownProps,
|
|
31
|
+
}: {
|
|
32
|
+
input: InputProps;
|
|
33
|
+
dropdown: DropdownProps;
|
|
34
|
+
}) {
|
|
35
|
+
const [keyword, setKeyword] = useState<string>(inputValue ?? '');
|
|
36
|
+
|
|
37
|
+
const handleKeyDown = (e: { code: string }) => {
|
|
38
|
+
if (inputOnChange && e.code === 'Enter') {
|
|
39
|
+
inputOnChange(e as any, {
|
|
40
|
+
value: keyword,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<Input
|
|
47
|
+
size="small"
|
|
48
|
+
placeholder="검색..."
|
|
49
|
+
style={{ margin: 0 }}
|
|
50
|
+
label={<${names.capital}SearchFieldDropdown {...dropdownProps} />}
|
|
51
|
+
labelPosition="left"
|
|
52
|
+
action={{
|
|
53
|
+
icon: 'search',
|
|
54
|
+
onClick: () => handleKeyDown({ code: 'Enter' }),
|
|
55
|
+
}}
|
|
56
|
+
{...inputProps}
|
|
57
|
+
value={keyword}
|
|
58
|
+
onChange={(e, { value }) => setKeyword(value)}
|
|
59
|
+
onKeyDown={handleKeyDown}
|
|
60
|
+
/>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
`.trim(),
|
|
64
|
+
importKeys: [],
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { execSync } from "child_process";
|
|
3
|
+
import knex, { Knex } from "knex";
|
|
4
|
+
import { uniq } from "lodash";
|
|
5
|
+
import { BaseModel } from "../database/base-model";
|
|
6
|
+
import { DB, SonamuDBConfig } from "../database/db";
|
|
7
|
+
import { SMDManager } from "../smd/smd-manager";
|
|
8
|
+
import {
|
|
9
|
+
isBelongsToOneRelationProp,
|
|
10
|
+
isOneToOneRelationProp,
|
|
11
|
+
} from "../types/types";
|
|
12
|
+
|
|
13
|
+
export class FixtureManager {
|
|
14
|
+
private tdb: Knex;
|
|
15
|
+
private fdb: Knex;
|
|
16
|
+
private knexfile: SonamuDBConfig;
|
|
17
|
+
|
|
18
|
+
constructor(public usingTables?: string[]) {
|
|
19
|
+
this.knexfile = DB.getKnexfile();
|
|
20
|
+
this.tdb = knex(this.knexfile.test);
|
|
21
|
+
this.fdb = knex(this.knexfile.fixture_local);
|
|
22
|
+
|
|
23
|
+
if (process.env.NODE_ENV === "test") {
|
|
24
|
+
beforeEach(async () => {
|
|
25
|
+
await this.cleanAndSeed();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
afterAll(async () => {
|
|
29
|
+
await this.destory();
|
|
30
|
+
await BaseModel.destroy();
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async cleanAndSeed() {
|
|
36
|
+
// console.time("FIXTURE-CleanAndSeed");
|
|
37
|
+
|
|
38
|
+
let tableNames: string[] = [];
|
|
39
|
+
|
|
40
|
+
if (this.usingTables === undefined) {
|
|
41
|
+
const [tables] = await this.tdb.raw(
|
|
42
|
+
"SHOW TABLE STATUS WHERE Engine IS NOT NULL"
|
|
43
|
+
);
|
|
44
|
+
tableNames = tables.map((tableInfo: any) => tableInfo["Name"]);
|
|
45
|
+
} else {
|
|
46
|
+
tableNames = this.usingTables;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
await this.tdb.raw(`SET FOREIGN_KEY_CHECKS = 0`);
|
|
50
|
+
for (let tableName of tableNames) {
|
|
51
|
+
if (tableName == "migrations") {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const [[fdbChecksumRow]] = await this.fdb.raw(
|
|
56
|
+
`CHECKSUM TABLE ${tableName}`
|
|
57
|
+
);
|
|
58
|
+
const fdbChecksum = fdbChecksumRow["Checksum"];
|
|
59
|
+
|
|
60
|
+
const [[tdbChecksumRow]] = await this.tdb.raw(
|
|
61
|
+
`CHECKSUM TABLE ${tableName}`
|
|
62
|
+
);
|
|
63
|
+
const tdbChecksum = tdbChecksumRow["Checksum"];
|
|
64
|
+
|
|
65
|
+
if (fdbChecksum !== tdbChecksum) {
|
|
66
|
+
await this.tdb(tableName).truncate();
|
|
67
|
+
const rawQuery = `INSERT INTO ${
|
|
68
|
+
(this.knexfile.test.connection as Knex.ConnectionConfig).database
|
|
69
|
+
}.${tableName}
|
|
70
|
+
SELECT * FROM ${
|
|
71
|
+
(this.knexfile.fixture_local.connection as Knex.ConnectionConfig)
|
|
72
|
+
.database
|
|
73
|
+
}.${tableName}`;
|
|
74
|
+
await this.tdb.raw(rawQuery);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
await this.tdb.raw(`SET FOREIGN_KEY_CHECKS = 1`);
|
|
78
|
+
|
|
79
|
+
// console.timeEnd("FIXTURE-CleanAndSeed");
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// TODO: 추후 작업
|
|
83
|
+
async initFixtureDB() {
|
|
84
|
+
const connectArgs = `-uDB_USER -pDB_PASS`;
|
|
85
|
+
|
|
86
|
+
console.log("DUMP...");
|
|
87
|
+
execSync(
|
|
88
|
+
`mysqldump -hwdb.closedshops.com ${connectArgs} --single-transaction -d --no-create-db --triggers --ignore-table=closedshops.pm_backup closedshops > /tmp/closedshops_scheme.sql`
|
|
89
|
+
);
|
|
90
|
+
console.log("SYNC to (TESTING) LOCAL closedshops...");
|
|
91
|
+
execSync(
|
|
92
|
+
`mysql -hlocal.closedshops.com ${connectArgs} -e 'DROP DATABASE closedshops'`
|
|
93
|
+
);
|
|
94
|
+
execSync(
|
|
95
|
+
`mysql -hlocal.closedshops.com ${connectArgs} -e 'CREATE DATABASE closedshops'`
|
|
96
|
+
);
|
|
97
|
+
execSync(
|
|
98
|
+
`mysql -hlocal.closedshops.com ${connectArgs} closedshops < /tmp/closedshops_scheme.sql;`
|
|
99
|
+
);
|
|
100
|
+
console.log("SED database names...");
|
|
101
|
+
execSync(
|
|
102
|
+
`sed -i'' -e 's/\`closedshops\`/\`closedshops_fixture\`/g' /tmp/closedshops_scheme.sql`
|
|
103
|
+
);
|
|
104
|
+
console.log("SYNC to (REMOTE FIXTURE) REMOTE closedshops_fixture...");
|
|
105
|
+
execSync(
|
|
106
|
+
`mysql -hwdb.closedshops.com ${connectArgs} -e 'DROP DATABASE closedshops_fixture'`
|
|
107
|
+
);
|
|
108
|
+
execSync(
|
|
109
|
+
`mysql -hwdb.closedshops.com ${connectArgs} -e 'CREATE DATABASE closedshops_fixture'`
|
|
110
|
+
);
|
|
111
|
+
execSync(
|
|
112
|
+
`mysql -hwdb.closedshops.com ${connectArgs} closedshops_fixture < /tmp/closedshops_scheme.sql;`
|
|
113
|
+
);
|
|
114
|
+
console.log("SYNC to (LOCAL FIXTURE) closedshops_fixture...");
|
|
115
|
+
execSync(
|
|
116
|
+
`mysql -hlocal.closedshops.com ${connectArgs} -e 'DROP DATABASE closedshops_fixture'`
|
|
117
|
+
);
|
|
118
|
+
execSync(
|
|
119
|
+
`mysql -hlocal.closedshops.com ${connectArgs} -e 'CREATE DATABASE closedshops_fixture'`
|
|
120
|
+
);
|
|
121
|
+
execSync(
|
|
122
|
+
`mysql -hlocal.closedshops.com ${connectArgs} closedshops_fixture < /tmp/closedshops_scheme.sql;`
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
async getChecksum(db: Knex, tableName: string) {
|
|
127
|
+
const [[checksumRow]] = await db.raw(`CHECKSUM TABLE ${tableName}`);
|
|
128
|
+
return checksumRow.Checksum;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
async sync() {
|
|
132
|
+
const frdb = knex(this.knexfile.fixture_remote);
|
|
133
|
+
|
|
134
|
+
const [tables] = await this.fdb.raw(
|
|
135
|
+
"SHOW TABLE STATUS WHERE Engine IS NOT NULL"
|
|
136
|
+
);
|
|
137
|
+
const tableNames: string[] = tables.map(
|
|
138
|
+
(table: any) => table.Name as string
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
console.log(chalk.magenta("SYNC..."));
|
|
142
|
+
await Promise.all(
|
|
143
|
+
tableNames.map(async (tableName) => {
|
|
144
|
+
if (tableName.startsWith("knex_migrations")) {
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const remoteChecksum = await this.getChecksum(frdb, tableName);
|
|
149
|
+
const localChecksum = await this.getChecksum(this.fdb, tableName);
|
|
150
|
+
|
|
151
|
+
if (remoteChecksum !== localChecksum) {
|
|
152
|
+
await this.fdb.transaction(async (transaction) => {
|
|
153
|
+
await transaction.raw(`SET FOREIGN_KEY_CHECKS = 0`);
|
|
154
|
+
await transaction(tableName).truncate();
|
|
155
|
+
|
|
156
|
+
const rows = await frdb(tableName);
|
|
157
|
+
console.log(chalk.blue(tableName), rows.length);
|
|
158
|
+
await transaction
|
|
159
|
+
.insert(
|
|
160
|
+
rows.map((row) => {
|
|
161
|
+
Object.keys(row).map((key) => {
|
|
162
|
+
if (Array.isArray(row[key])) {
|
|
163
|
+
row[key] = JSON.stringify(row[key]);
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
return row;
|
|
167
|
+
})
|
|
168
|
+
)
|
|
169
|
+
.into(tableName);
|
|
170
|
+
console.log("OK");
|
|
171
|
+
await transaction.raw(`SET FOREIGN_KEY_CHECKS = 0`);
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
})
|
|
175
|
+
);
|
|
176
|
+
console.log(chalk.magenta("DONE!"));
|
|
177
|
+
|
|
178
|
+
await frdb.destroy();
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
async importFixture(smdId: string, ids: number[]) {
|
|
182
|
+
const queries = uniq(
|
|
183
|
+
(
|
|
184
|
+
await Promise.all(
|
|
185
|
+
ids.map(async (id) => {
|
|
186
|
+
return await this.getImportQueries(smdId, "id", id);
|
|
187
|
+
})
|
|
188
|
+
)
|
|
189
|
+
).flat()
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
const wdb = BaseModel.getDB("w");
|
|
193
|
+
for (let query of queries) {
|
|
194
|
+
const [rsh] = await wdb.raw(query);
|
|
195
|
+
console.log({
|
|
196
|
+
query,
|
|
197
|
+
info: rsh.info,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
async getImportQueries(
|
|
203
|
+
smdId: string,
|
|
204
|
+
field: string,
|
|
205
|
+
id: number
|
|
206
|
+
): Promise<string[]> {
|
|
207
|
+
console.log({ smdId, field, id });
|
|
208
|
+
const smd = SMDManager.get(smdId);
|
|
209
|
+
const wdb = BaseModel.getDB("w");
|
|
210
|
+
|
|
211
|
+
// 여기서 실DB의 row 가져옴
|
|
212
|
+
const [row] = await wdb(smd.table).where(field, id).limit(1);
|
|
213
|
+
if (row === undefined) {
|
|
214
|
+
throw new Error(`${smdId}#${id} row를 찾을 수 없습니다.`);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// 픽스쳐DB, 실DB
|
|
218
|
+
const fixtureDatabase = (this.knexfile.fixture_remote.connection as any)
|
|
219
|
+
.database;
|
|
220
|
+
const realDatabase = (this.knexfile.production_master.connection as any)
|
|
221
|
+
.database;
|
|
222
|
+
|
|
223
|
+
const selfQuery = `INSERT IGNORE INTO \`${fixtureDatabase}\`.\`${smd.table}\` (SELECT * FROM \`${realDatabase}\`.\`${smd.table}\` WHERE \`id\` = ${id})`;
|
|
224
|
+
|
|
225
|
+
const args = Object.entries(smd.relations)
|
|
226
|
+
.filter(
|
|
227
|
+
([, relation]) =>
|
|
228
|
+
isBelongsToOneRelationProp(relation) ||
|
|
229
|
+
(isOneToOneRelationProp(relation) &&
|
|
230
|
+
relation.customJoinClause === undefined)
|
|
231
|
+
)
|
|
232
|
+
.map(([, relation]) => {
|
|
233
|
+
/*
|
|
234
|
+
BelongsToOne인 경우
|
|
235
|
+
Category / 'id' / row[category_id] 호출
|
|
236
|
+
OneToOne에 joinColumn === true 인 경우
|
|
237
|
+
Profile / 'id' / row[profile_id] 호출
|
|
238
|
+
OneToOne에 joinColumn === false 인 경우
|
|
239
|
+
Profile / 'profile_id' / row['id'] 호출
|
|
240
|
+
*/
|
|
241
|
+
let field: string;
|
|
242
|
+
let id: number;
|
|
243
|
+
if (isOneToOneRelationProp(relation) && !relation.hasJoinColumn) {
|
|
244
|
+
field = `${relation.name}_id`;
|
|
245
|
+
id = row["id"];
|
|
246
|
+
} else {
|
|
247
|
+
field = "id";
|
|
248
|
+
id = row[`${relation.name}_id`];
|
|
249
|
+
}
|
|
250
|
+
return {
|
|
251
|
+
smdId: relation.with,
|
|
252
|
+
field,
|
|
253
|
+
id,
|
|
254
|
+
};
|
|
255
|
+
})
|
|
256
|
+
.filter((arg) => arg.id !== null);
|
|
257
|
+
|
|
258
|
+
const relQueries = await Promise.all(
|
|
259
|
+
args.map(async (args) => {
|
|
260
|
+
return this.getImportQueries(args.smdId, args.field, args.id);
|
|
261
|
+
})
|
|
262
|
+
);
|
|
263
|
+
|
|
264
|
+
return [...uniq(relQueries.reverse().flat()), selfQuery];
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
async destory() {
|
|
268
|
+
await this.tdb.destroy();
|
|
269
|
+
await this.fdb.destroy();
|
|
270
|
+
}
|
|
271
|
+
}
|