sonamu 0.2.31 → 0.2.33

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 (46) hide show
  1. package/.pnp.cjs +11 -10
  2. package/.vscode/settings.json +1 -1
  3. package/dist/api/sonamu.d.ts.map +1 -1
  4. package/dist/api/sonamu.js +3 -0
  5. package/dist/api/sonamu.js.map +1 -1
  6. package/dist/bin/cli.js +7 -4
  7. package/dist/bin/cli.js.map +1 -1
  8. package/dist/database/_batch_update.d.ts +15 -0
  9. package/dist/database/_batch_update.d.ts.map +1 -0
  10. package/dist/database/_batch_update.js +89 -0
  11. package/dist/database/_batch_update.js.map +1 -0
  12. package/dist/database/base-model.d.ts +2 -1
  13. package/dist/database/base-model.d.ts.map +1 -1
  14. package/dist/database/base-model.js +45 -31
  15. package/dist/database/base-model.js.map +1 -1
  16. package/dist/database/upsert-builder.d.ts.map +1 -1
  17. package/dist/database/upsert-builder.js +11 -54
  18. package/dist/database/upsert-builder.js.map +1 -1
  19. package/dist/entity/entity.js +1 -1
  20. package/dist/entity/entity.js.map +1 -1
  21. package/dist/entity/migrator.d.ts +4 -4
  22. package/dist/entity/migrator.d.ts.map +1 -1
  23. package/dist/entity/migrator.js +213 -205
  24. package/dist/entity/migrator.js.map +1 -1
  25. package/dist/syncer/syncer.d.ts.map +1 -1
  26. package/dist/syncer/syncer.js +26 -26
  27. package/dist/syncer/syncer.js.map +1 -1
  28. package/dist/templates/base-template.d.ts +1 -1
  29. package/dist/templates/base-template.d.ts.map +1 -1
  30. package/dist/templates/generated_http.template.d.ts +2 -2
  31. package/dist/templates/generated_http.template.d.ts.map +1 -1
  32. package/dist/templates/generated_http.template.js +49 -38
  33. package/dist/templates/generated_http.template.js.map +1 -1
  34. package/dist/templates/view_form.template.d.ts +2 -2
  35. package/dist/templates/view_list.template.d.ts +2 -2
  36. package/package.json +3 -3
  37. package/src/api/sonamu.ts +4 -0
  38. package/src/bin/cli.ts +11 -6
  39. package/src/database/_batch_update.ts +106 -0
  40. package/src/database/base-model.ts +66 -42
  41. package/src/database/upsert-builder.ts +16 -12
  42. package/src/entity/entity.ts +1 -1
  43. package/src/entity/migrator.ts +106 -103
  44. package/src/syncer/syncer.ts +58 -58
  45. package/src/templates/base-template.ts +1 -1
  46. package/src/templates/generated_http.template.ts +37 -35
@@ -1,4 +1,13 @@
1
1
  "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
2
11
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
13
  };
@@ -22,45 +31,47 @@ class Template__generated_http extends base_template_1.Template {
22
31
  };
23
32
  }
24
33
  render({}) {
25
- const { syncer: { types, apis }, config: { route: { prefix }, }, } = sonamu_1.Sonamu;
26
- const lines = apis.map((api) => {
27
- var _a, _b;
28
- const reqObject = this.resolveApiParams(api, types);
29
- const dataLines = (() => {
30
- var _a;
31
- if (((_a = api.options.httpMethod) !== null && _a !== void 0 ? _a : "GET") === "GET") {
32
- return {
33
- querystring: [
34
- qs_1.default
35
- .stringify(reqObject, { encode: false })
36
- .split("&")
37
- .join("\n\t&"),
38
- ],
39
- body: [],
40
- };
41
- }
42
- else {
43
- return {
44
- querystring: [],
45
- body: [
46
- "",
47
- prettier_1.default.format(JSON.stringify(reqObject), {
48
- parser: "json",
49
- }),
50
- ],
51
- };
52
- }
53
- })();
54
- return [
55
- [
56
- `${(_a = api.options.httpMethod) !== null && _a !== void 0 ? _a : "GET"} {{baseUrl}}${prefix}${api.path}`,
57
- ...dataLines.querystring,
58
- ].join("\n\t?"),
59
- `Content-Type: ${(_b = api.options.contentType) !== null && _b !== void 0 ? _b : "application/json"}`,
60
- ...dataLines.body,
61
- ].join("\n");
34
+ return __awaiter(this, void 0, void 0, function* () {
35
+ const { syncer: { types, apis }, config: { route: { prefix }, }, } = sonamu_1.Sonamu;
36
+ const lines = yield Promise.all(apis.map((api) => __awaiter(this, void 0, void 0, function* () {
37
+ var _a, _b;
38
+ const reqObject = this.resolveApiParams(api, types);
39
+ const dataLines = yield (() => __awaiter(this, void 0, void 0, function* () {
40
+ var _c;
41
+ if (((_c = api.options.httpMethod) !== null && _c !== void 0 ? _c : "GET") === "GET") {
42
+ return {
43
+ querystring: [
44
+ qs_1.default
45
+ .stringify(reqObject, { encode: false })
46
+ .split("&")
47
+ .join("\n\t&"),
48
+ ],
49
+ body: [],
50
+ };
51
+ }
52
+ else {
53
+ return {
54
+ querystring: [],
55
+ body: [
56
+ "",
57
+ yield prettier_1.default.format(JSON.stringify(reqObject), {
58
+ parser: "json",
59
+ }),
60
+ ],
61
+ };
62
+ }
63
+ }))();
64
+ return [
65
+ [
66
+ `${(_a = api.options.httpMethod) !== null && _a !== void 0 ? _a : "GET"} {{baseUrl}}${prefix}${api.path}`,
67
+ ...dataLines.querystring,
68
+ ].join("\n\t?"),
69
+ `Content-Type: ${(_b = api.options.contentType) !== null && _b !== void 0 ? _b : "application/json"}`,
70
+ ...dataLines.body,
71
+ ].join("\n");
72
+ })));
73
+ return Object.assign(Object.assign({}, this.getTargetAndPath()), { body: lines.join("\n\n###\n\n"), importKeys: [] });
62
74
  });
63
- return Object.assign(Object.assign({}, this.getTargetAndPath()), { body: lines.join("\n\n###\n\n"), importKeys: [] });
64
75
  }
65
76
  zodTypeToReqDefault(zodType, name) {
66
77
  var _a;
@@ -1 +1 @@
1
- {"version":3,"file":"generated_http.template.js","sourceRoot":"","sources":["../../src/templates/generated_http.template.ts"],"names":[],"mappings":";;;;;;AAAA,4CAAoB;AACpB,6BAAwB;AAExB,4DAA6D;AAE7D,mDAA2C;AAC3C,wDAAgC;AAChC,0CAAuC;AAEvC,MAAa,wBAAyB,SAAQ,wBAAQ;IACpD;QACE,KAAK,CAAC,gBAAgB,CAAC,CAAC;IAC1B,CAAC;IAED,gBAAgB;QACd,MAAM,EAAE,GAAG,EAAE,GAAG,eAAM,CAAC,MAAM,CAAC,GAAG,CAAC;QAElC,OAAO;YACL,MAAM,EAAE,GAAG,GAAG,kBAAkB;YAChC,IAAI,EAAE,uBAAuB;SAC9B,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,EAAqC;QAC1C,MAAM,EACJ,MAAM,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EACvB,MAAM,EAAE,EACN,KAAK,EAAE,EAAE,MAAM,EAAE,GAClB,GACF,GAAG,eAAM,CAAC;QAEX,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;;YAC7B,MAAM,SAAS,GAAG,IAAI,CAAC,gBAAgB,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YAEpD,MAAM,SAAS,GAAG,CAAC,GAAG,EAAE;;gBACtB,IAAI,CAAC,MAAA,GAAG,CAAC,OAAO,CAAC,UAAU,mCAAI,KAAK,CAAC,KAAK,KAAK,EAAE;oBAC/C,OAAO;wBACL,WAAW,EAAE;4BACX,YAAE;iCACC,SAAS,CAAC,SAAS,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;iCACvC,KAAK,CAAC,GAAG,CAAC;iCACV,IAAI,CAAC,OAAO,CAAC;yBACjB;wBACD,IAAI,EAAE,EAAE;qBACT,CAAC;iBACH;qBAAM;oBACL,OAAO;wBACL,WAAW,EAAE,EAAE;wBACf,IAAI,EAAE;4BACJ,EAAE;4BACF,kBAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE;gCACzC,MAAM,EAAE,MAAM;6BACf,CAAC;yBACH;qBACF,CAAC;iBACH;YACH,CAAC,CAAC,EAAE,CAAC;YAEL,OAAO;gBACL;oBACE,GAAG,MAAA,GAAG,CAAC,OAAO,CAAC,UAAU,mCAAI,KAAK,eAAe,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE;oBACpE,GAAG,SAAS,CAAC,WAAW;iBACzB,CAAC,IAAI,CAAC,OAAO,CAAC;gBACf,iBAAiB,MAAA,GAAG,CAAC,OAAO,CAAC,WAAW,mCAAI,kBAAkB,EAAE;gBAChE,GAAG,SAAS,CAAC,IAAI;aAClB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACf,CAAC,CAAC,CAAC;QAEH,uCACK,IAAI,CAAC,gBAAgB,EAAE,KAC1B,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,EAC/B,UAAU,EAAE,EAAE,IACd;IACJ,CAAC;IAED,mBAAmB,CAAC,OAA2B,EAAE,IAAY;;QAC3D,IAAI,OAAO,YAAY,OAAC,CAAC,SAAS,EAAE;YAClC,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC;gBACtC,GAAG;gBACH,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC;aAClD,CAAC,CACH,CAAC;SACH;aAAM,IAAI,OAAO,YAAY,OAAC,CAAC,QAAQ,EAAE;YACxC,OAAO,CAAC,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;SAC1D;aAAM,IAAI,OAAO,YAAY,OAAC,CAAC,SAAS,EAAE;YACzC,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,IAAI,KAAK,OAAO,EAAE;gBACtE,OAAO,YAAY,CAAC;aACrB;iBAAM;gBACL,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC;aAC3B;SACF;aAAM,IAAI,OAAO,YAAY,OAAC,CAAC,SAAS,EAAE;YACzC,IAAI,IAAI,KAAK,KAAK,EAAE;gBAClB,OAAO,EAAE,CAAC;aACX;YACD,OAAO,MAAA,OAAO,CAAC,QAAQ,mCAAI,CAAC,CAAC;SAC9B;aAAM,IAAI,OAAO,YAAY,OAAC,CAAC,UAAU,EAAE;YAC1C,OAAO,KAAK,CAAC;SACd;aAAM,IAAI,OAAO,YAAY,OAAC,CAAC,OAAO,EAAE;YACvC,OAAO,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;SAC3B;aAAM,IAAI,OAAO,YAAY,OAAC,CAAC,WAAW,EAAE;YAC3C,OAAO,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;SAC/D;aAAM,IAAI,OAAO,YAAY,OAAC,CAAC,WAAW,EAAE;YAC3C,OAAO,IAAI,CAAC;SACb;aAAM,IAAI,OAAO,YAAY,OAAC,CAAC,QAAQ,EAAE;YACxC,OAAO,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;SAChE;aAAM,IAAI,OAAO,YAAY,OAAC,CAAC,UAAU,EAAE;YAC1C,OAAO,SAAS,CAAC;SAClB;aAAM,IAAI,OAAO,YAAY,OAAC,CAAC,QAAQ,EAAE;YACxC,OAAO,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAS,EAAE,EAAE,CAC1C,IAAI,CAAC,mBAAmB,CAAC,IAAI,EAAE,IAAI,CAAC,CACrC,CAAC;SACH;aAAM;YACL,wBAAwB;YACxB,OAAO,WAAW,OAAO,CAAC,KAAK,EAAE,CAAC;SACnC;IACH,CAAC;IAED,gBAAgB,CACd,GAAgB,EAChB,UAAoD;QAEpD,MAAM,OAAO,GAAG,IAAA,qCAAmB,EAAC,GAAG,EAAE,UAAU,CAAC,CAAC;QACrD,OAAO,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE,aAAa,CAErD,CAAC;IACJ,CAAC;CACF;AAtHD,4DAsHC"}
1
+ {"version":3,"file":"generated_http.template.js","sourceRoot":"","sources":["../../src/templates/generated_http.template.ts"],"names":[],"mappings":"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"}
@@ -18,8 +18,8 @@ export declare class Template__view_form extends Template {
18
18
  preTemplates: {
19
19
  key: "entity" | "init_types" | "generated" | "generated_sso" | "generated_http" | "model" | "model_test" | "bridge" | "service" | "view_list" | "view_list_columns" | "view_search_input" | "view_form" | "view_id_all_select" | "view_id_async_select" | "view_enums_select" | "view_enums_dropdown" | "view_enums_buttonset";
20
20
  options: {
21
- entityId: string;
22
21
  title: string;
22
+ entityId: string;
23
23
  parentId?: string | undefined;
24
24
  table?: string | undefined;
25
25
  } | {
@@ -40,12 +40,12 @@ export declare class Template__view_form extends Template {
40
40
  entityId: string;
41
41
  extra?: unknown;
42
42
  } | {
43
+ entityId: string;
43
44
  columns: {
44
45
  name: string;
45
46
  label: string;
46
47
  tc: string;
47
48
  }[];
48
- entityId: string;
49
49
  columnImports: string;
50
50
  } | {
51
51
  entityId: string;
@@ -23,8 +23,8 @@ export declare class Template__view_list extends Template {
23
23
  preTemplates: {
24
24
  key: "entity" | "init_types" | "generated" | "generated_sso" | "generated_http" | "model" | "model_test" | "bridge" | "service" | "view_list" | "view_list_columns" | "view_search_input" | "view_form" | "view_id_all_select" | "view_id_async_select" | "view_enums_select" | "view_enums_dropdown" | "view_enums_buttonset";
25
25
  options: {
26
- entityId: string;
27
26
  title: string;
27
+ entityId: string;
28
28
  parentId?: string | undefined;
29
29
  table?: string | undefined;
30
30
  } | {
@@ -45,12 +45,12 @@ export declare class Template__view_list extends Template {
45
45
  entityId: string;
46
46
  extra?: unknown;
47
47
  } | {
48
+ entityId: string;
48
49
  columns: {
49
50
  name: string;
50
51
  label: string;
51
52
  tc: string;
52
53
  }[];
53
- entityId: string;
54
54
  columnImports: string;
55
55
  } | {
56
56
  entityId: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sonamu",
3
- "version": "0.2.31",
3
+ "version": "0.2.33",
4
4
  "description": "Sonamu — TypeScript Fullstack API Framework",
5
5
  "keywords": [
6
6
  "typescript",
@@ -48,11 +48,11 @@
48
48
  "@types/lodash": "^4.14.198",
49
49
  "@types/luxon": "^3.0.1",
50
50
  "@types/node": "^20.6.3",
51
- "@types/prettier": "^2.7.0",
51
+ "@types/prettier": "^3.0.0",
52
52
  "@types/prompts": "^2.0.14",
53
53
  "@types/qs": "^6.9.7",
54
54
  "@types/uuid": "^8.3.4",
55
- "prettier": "^2.7.1",
55
+ "prettier": "^3.2.5",
56
56
  "source-map-support": "^0.5.21",
57
57
  "typescript": "^5.2.2"
58
58
  },
package/src/api/sonamu.ts CHANGED
@@ -152,6 +152,10 @@ class SonamuClass {
152
152
 
153
153
  if (isLocal() && !isTest() && enableSync) {
154
154
  await this.syncer.sync();
155
+
156
+ fetch("http://localhost:57001/api/reload", {
157
+ method: "GET",
158
+ }).catch(() => console.log("Failed to reload Sonamu UI"));
155
159
  }
156
160
 
157
161
  this.isInitialized = true;
package/src/bin/cli.ts CHANGED
@@ -29,7 +29,7 @@ import process from "process";
29
29
  let migrator: Migrator;
30
30
 
31
31
  async function bootstrap() {
32
- await Sonamu.init();
32
+ await Sonamu.init(false, false);
33
33
 
34
34
  await tsicli(process.argv, {
35
35
  types: {
@@ -210,10 +210,15 @@ async function fixture_init() {
210
210
  // 3. knex migration 정보 복사
211
211
  await Promise.all(
212
212
  ["knex_migrations", "knex_migrations_lock"].map(async (tableName) => {
213
- await db.raw(
214
- `INSERT INTO \`${conn.database}\`.${tableName}
215
- SELECT * FROM \`${srcConn.database}\`.${tableName}`
213
+ const [table] = await db.raw(
214
+ `SHOW TABLES FROM \`${srcConn.database}\` LIKE '${tableName}'`
216
215
  );
216
+ if (table?.length) {
217
+ await db.raw(
218
+ `INSERT INTO \`${conn.database}\`.${tableName}
219
+ SELECT * FROM \`${srcConn.database}\`.${tableName}`
220
+ );
221
+ }
217
222
  })
218
223
  );
219
224
 
@@ -310,7 +315,7 @@ async function ui() {
310
315
  const sonamuUI: {
311
316
  startServers: (appRootPath: string) => void;
312
317
  } = await import("@sonamu-kit/ui" as string);
313
- sonamuUI.startServers(Sonamu.appRootPath);
318
+ sonamuUI.startServers(Sonamu.apiRootPath);
314
319
  } catch (e: unknown) {
315
320
  if (e instanceof Error && e.message.includes("isn't declared")) {
316
321
  console.log(`You need to install ${chalk.blue(`@sonamu-kit/ui`)} first.`);
@@ -365,7 +370,7 @@ async function smd_migration() {
365
370
  `${names.fs}.entity.json`
366
371
  );
367
372
 
368
- const formatted = prettier.format(JSON.stringify(entityJson), {
373
+ const formatted = await prettier.format(JSON.stringify(entityJson), {
369
374
  parser: "json",
370
375
  });
371
376
  writeFileSync(dstPath, formatted);
@@ -0,0 +1,106 @@
1
+ /*
2
+ 아래의 링크에서 참고해서 가져온 소스코드
3
+ https://github.com/knex/knex/issues/5716
4
+ */
5
+
6
+ import { Knex } from "knex";
7
+
8
+ export type RowWithId<Id extends string> = {
9
+ [key in Id]: any;
10
+ } & Record<string, any>;
11
+
12
+ /**
13
+ * Batch update rows in a table. Technically its a patch since it only updates the specified columns. Any omitted columns will not be affected
14
+ * @param knex
15
+ * @param tableName
16
+ * @param id
17
+ * @param rows
18
+ * @param chunkSize
19
+ * @param trx
20
+ */
21
+ export async function batchUpdate<Id extends string>(
22
+ knex: Knex,
23
+ tableName: string,
24
+ id: Id,
25
+ rows: RowWithId<Id>[],
26
+ chunkSize = 50,
27
+ trx: Knex.Transaction | null = null
28
+ ) {
29
+ const chunks: RowWithId<Id>[][] = [];
30
+ for (let i = 0; i < rows.length; i += chunkSize) {
31
+ chunks.push(rows.slice(i, i + chunkSize));
32
+ }
33
+
34
+ const executeUpdate = async (
35
+ chunk: RowWithId<Id>[],
36
+ transaction: Knex.Transaction
37
+ ) => {
38
+ const sql = generateBatchUpdateSQL(knex, tableName, chunk, id);
39
+ return knex.raw(sql).transacting(transaction);
40
+ };
41
+
42
+ if (trx) {
43
+ for (const chunk of chunks) {
44
+ await executeUpdate(chunk, trx);
45
+ }
46
+ } else {
47
+ await knex.transaction(async (newTrx) => {
48
+ for (const chunk of chunks) {
49
+ await executeUpdate(chunk, newTrx);
50
+ }
51
+ });
52
+ }
53
+ }
54
+
55
+ /**
56
+ * Generate a set of unique keys in a data array
57
+ *
58
+ * Example:
59
+ * [ { a: 1, b: 2 }, { a: 3, c: 4 } ] => Set([ "a", "b", "c" ])
60
+ * @param data
61
+ */
62
+ function generateKeySetFromData(data: Record<string, any>[]) {
63
+ const keySet: Set<string> = new Set();
64
+ for (const row of data) {
65
+ for (const key of Object.keys(row)) {
66
+ keySet.add(key);
67
+ }
68
+ }
69
+ return keySet;
70
+ }
71
+
72
+ function generateBatchUpdateSQL<Id extends string>(
73
+ knex: Knex,
74
+ tableName: string,
75
+ data: Record<string, any>[],
76
+ identifier: Id
77
+ ) {
78
+ const keySet = generateKeySetFromData(data);
79
+ const bindings = [];
80
+
81
+ const cases = [];
82
+ for (const key of keySet) {
83
+ if (key === identifier) continue;
84
+
85
+ const rows = [];
86
+ for (const row of data) {
87
+ if (Object.hasOwnProperty.call(row, key)) {
88
+ rows.push(`WHEN \`${identifier}\` = ? THEN ?`);
89
+ bindings.push(row[identifier], row[key]);
90
+ }
91
+ }
92
+
93
+ const whenThen = rows.join(" ");
94
+ cases.push(`\`${key}\` = CASE ${whenThen} ELSE \`${key}\` END`);
95
+ }
96
+
97
+ const whereInIds = data.map((row) => row[identifier]);
98
+ const whereInPlaceholders = whereInIds.map(() => "?").join(", ");
99
+ const sql = knex.raw(
100
+ `UPDATE \`${tableName}\` SET ${cases.join(
101
+ ", "
102
+ )} WHERE ${identifier} IN (${whereInPlaceholders})`,
103
+ [...bindings, ...whereInIds]
104
+ );
105
+ return sql.toString();
106
+ }
@@ -202,6 +202,7 @@ export class BaseModelClass {
202
202
  build,
203
203
  debug,
204
204
  db: _db,
205
+ optimizeCountQuery,
205
206
  }: {
206
207
  subset: U;
207
208
  params: T;
@@ -216,6 +217,7 @@ export class BaseModelClass {
216
217
  baseTable?: string;
217
218
  debug?: boolean | "list" | "count";
218
219
  db?: Knex;
220
+ optimizeCountQuery?: boolean;
219
221
  }): Promise<{
220
222
  rows: any[];
221
223
  total?: number | undefined;
@@ -236,20 +238,70 @@ export class BaseModelClass {
236
238
  virtual,
237
239
  });
238
240
 
239
- // join
240
- joins.map((join) => {
241
- if (join.join == "inner") {
242
- qb.innerJoin(
243
- `${join.table} as ${join.as}`,
244
- this.getJoinClause(db, join)
241
+ const applyJoinClause = (
242
+ qb: Knex.QueryBuilder,
243
+ joins: SubsetQuery["joins"]
244
+ ) => {
245
+ joins.map((join) => {
246
+ if (join.join == "inner") {
247
+ qb.innerJoin(
248
+ `${join.table} as ${join.as}`,
249
+ this.getJoinClause(db, join)
250
+ );
251
+ } else if (join.join == "outer") {
252
+ qb.leftOuterJoin(
253
+ `${join.table} as ${join.as}`,
254
+ this.getJoinClause(db, join)
255
+ );
256
+ }
257
+ });
258
+ };
259
+
260
+ // countQuery
261
+ const total = await (async () => {
262
+ if (queryMode === "list") {
263
+ return undefined;
264
+ }
265
+
266
+ const clonedQb = qb.clone().clear("order").clear("offset").clear("limit");
267
+
268
+ // optmizeCountQuery가 true인 경우 다른 clause에 영향을 주지 않는 모든 join을 제외함
269
+ if (optimizeCountQuery) {
270
+ const queryThatNotYetAppliedJoins = clonedQb.toQuery();
271
+ const afterWhereClause = queryThatNotYetAppliedJoins.split("where")[1];
272
+ applyJoinClause(
273
+ clonedQb,
274
+ joins.filter((j) => {
275
+ return afterWhereClause.includes(`\`${j.as}\``);
276
+ })
245
277
  );
246
- } else if (join.join == "outer") {
247
- qb.leftOuterJoin(
248
- `${join.table} as ${join.as}`,
249
- this.getJoinClause(db, join)
278
+ } else {
279
+ applyJoinClause(clonedQb, joins);
280
+ }
281
+
282
+ const [, matched] =
283
+ clonedQb
284
+ .toQuery()
285
+ .toLowerCase()
286
+ .match(/select (distinct .+) from/) ?? [];
287
+ const countQuery = matched
288
+ ? clonedQb
289
+ .clear("select")
290
+ .select(db.raw(`COUNT(${matched.split(",")[0]}) as total`))
291
+ .first()
292
+ : clonedQb.clear("select").count("*", { as: "total" }).first();
293
+ const countRow: { total?: number } = await countQuery;
294
+
295
+ // debug: countQuery
296
+ if (debug === true || debug === "count") {
297
+ console.debug(
298
+ "DEBUG: count query",
299
+ chalk.blue(countQuery.toQuery().toString())
250
300
  );
251
301
  }
252
- });
302
+
303
+ return countRow?.total ?? 0;
304
+ })();
253
305
 
254
306
  // listQuery
255
307
  const rows = await (async () => {
@@ -266,6 +318,9 @@ export class BaseModelClass {
266
318
  // select, rows
267
319
  const listQuery = qb.clone().select(select);
268
320
 
321
+ // join
322
+ applyJoinClause(listQuery, joins);
323
+
269
324
  let rows = await listQuery;
270
325
  // debug: listQuery
271
326
  if (debug === true || debug === "list") {
@@ -280,37 +335,6 @@ export class BaseModelClass {
280
335
  return rows;
281
336
  })();
282
337
 
283
- // countQuery
284
- const total = await (async () => {
285
- if (queryMode === "list") {
286
- return undefined;
287
- }
288
-
289
- const clonedQb = qb.clone().clear("order").clear("offset").clear("limit");
290
- const [, matched] =
291
- clonedQb
292
- .toQuery()
293
- .toLowerCase()
294
- .match(/select (distinct .+) from/) ?? [];
295
- const countQuery = matched
296
- ? clonedQb
297
- .clear("select")
298
- .select(db.raw(`COUNT(${matched.split(",")[0]}) as total`))
299
- .first()
300
- : clonedQb.clear("select").count("*", { as: "total" }).first();
301
- const countRow: { total?: number } = await countQuery;
302
-
303
- // debug: countQuery
304
- if (debug === true || debug === "count") {
305
- console.debug(
306
- "DEBUG: count query",
307
- chalk.blue(countQuery.toQuery().toString())
308
- );
309
- }
310
-
311
- return countRow?.total ?? 0;
312
- })();
313
-
314
338
  return { rows, total, subsetQuery, qb };
315
339
  }
316
340
 
@@ -1,8 +1,9 @@
1
1
  import { v4 as uuidv4 } from "uuid";
2
- import _, { chunk, defaults, groupBy } from "lodash";
2
+ import { defaults, groupBy, uniq } from "lodash";
3
3
  import { Knex } from "knex";
4
4
  import { EntityManager } from "../entity/entity-manager";
5
5
  import { nonNullable } from "../utils/utils";
6
+ import { RowWithId, batchUpdate } from "./_batch_update";
6
7
 
7
8
  type TableData = {
8
9
  references: Set<string>;
@@ -213,14 +214,14 @@ export class UpsertBuilder {
213
214
  }
214
215
  );
215
216
 
216
- const extractFields = _.uniq(references).map(
217
+ const extractFields = uniq(references).map(
217
218
  (reference) => reference.split(".")[1]
218
219
  );
219
220
 
220
221
  // UUID 기준으로 id 추출
221
222
  const uuids = table.rows.map((row) => row.uuid);
222
223
  const upsertedRows = await wdb(tableName)
223
- .select(_.uniq(["uuid", "id", ...extractFields]))
224
+ .select(uniq(["uuid", "id", ...extractFields]))
224
225
  .whereIn("uuid", uuids);
225
226
  const uuidMap = new Map<string, any>(
226
227
  upsertedRows.map((row: any) => [row.uuid, row])
@@ -266,6 +267,7 @@ export class UpsertBuilder {
266
267
  ): Promise<void> {
267
268
  options = defaults(options, {
268
269
  chunkSize: 500,
270
+ where: "id",
269
271
  });
270
272
 
271
273
  if (this.hasTable(tableName) === false) {
@@ -276,14 +278,16 @@ export class UpsertBuilder {
276
278
  return;
277
279
  }
278
280
 
279
- const chunks = chunk(table.rows, options.chunkSize);
280
- for await (const chunk of chunks) {
281
- await Promise.all(
282
- chunk.map(async ({ id, ...row }) => {
283
- const { uuid, ...update } = row;
284
- return await wdb(tableName).where("id", id).update(update);
285
- })
286
- );
287
- }
281
+ const rows = table.rows.map((_row) => {
282
+ const { uuid, ...row } = _row;
283
+ return row as RowWithId<string>;
284
+ });
285
+ await batchUpdate(
286
+ wdb,
287
+ tableName,
288
+ options.where ?? "id",
289
+ rows,
290
+ options.chunkSize
291
+ );
288
292
  }
289
293
  }
@@ -631,7 +631,7 @@ export class Entity {
631
631
  const json = this.toJson();
632
632
  writeFileSync(
633
633
  jsonPath,
634
- prettier.format(JSON.stringify(json), {
634
+ await prettier.format(JSON.stringify(json), {
635
635
  parser: "json",
636
636
  })
637
637
  );