sonamu 0.3.1 → 0.4.2

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 (83) hide show
  1. package/.pnp.cjs +11 -0
  2. package/dist/base-model-BzMJ2E_I.d.mts +43 -0
  3. package/dist/base-model-CWRKUX49.d.ts +43 -0
  4. package/dist/bin/cli.js +118 -89
  5. package/dist/bin/cli.js.map +1 -1
  6. package/dist/bin/cli.mjs +74 -45
  7. package/dist/bin/cli.mjs.map +1 -1
  8. package/dist/chunk-6HSW7OS3.js +1567 -0
  9. package/dist/chunk-6HSW7OS3.js.map +1 -0
  10. package/dist/chunk-FLPD24HS.mjs +231 -0
  11. package/dist/chunk-FLPD24HS.mjs.map +1 -0
  12. package/dist/{chunk-MPXE4IHO.mjs → chunk-PP2PSSAG.mjs} +5284 -5617
  13. package/dist/chunk-PP2PSSAG.mjs.map +1 -0
  14. package/dist/chunk-QK5XXJUX.mjs +280 -0
  15. package/dist/chunk-QK5XXJUX.mjs.map +1 -0
  16. package/dist/chunk-S6FYTR3V.mjs +1567 -0
  17. package/dist/chunk-S6FYTR3V.mjs.map +1 -0
  18. package/dist/chunk-U636LQJJ.js +231 -0
  19. package/dist/chunk-U636LQJJ.js.map +1 -0
  20. package/dist/chunk-W7KDVJLQ.js +280 -0
  21. package/dist/chunk-W7KDVJLQ.js.map +1 -0
  22. package/dist/{chunk-YXILRRDT.js → chunk-XT6LHCX5.js} +5252 -5585
  23. package/dist/chunk-XT6LHCX5.js.map +1 -0
  24. package/dist/database/drivers/knex/base-model.d.mts +16 -0
  25. package/dist/database/drivers/knex/base-model.d.ts +16 -0
  26. package/dist/database/drivers/knex/base-model.js +55 -0
  27. package/dist/database/drivers/knex/base-model.js.map +1 -0
  28. package/dist/database/drivers/knex/base-model.mjs +56 -0
  29. package/dist/database/drivers/knex/base-model.mjs.map +1 -0
  30. package/dist/database/drivers/kysely/base-model.d.mts +22 -0
  31. package/dist/database/drivers/kysely/base-model.d.ts +22 -0
  32. package/dist/database/drivers/kysely/base-model.js +64 -0
  33. package/dist/database/drivers/kysely/base-model.js.map +1 -0
  34. package/dist/database/drivers/kysely/base-model.mjs +65 -0
  35. package/dist/database/drivers/kysely/base-model.mjs.map +1 -0
  36. package/dist/index.d.mts +222 -928
  37. package/dist/index.d.ts +222 -928
  38. package/dist/index.js +13 -26
  39. package/dist/index.js.map +1 -1
  40. package/dist/index.mjs +18 -31
  41. package/dist/index.mjs.map +1 -1
  42. package/dist/model-CAH_4oQh.d.mts +1042 -0
  43. package/dist/model-CAH_4oQh.d.ts +1042 -0
  44. package/import-to-require.js +27 -0
  45. package/package.json +24 -3
  46. package/src/api/caster.ts +6 -0
  47. package/src/api/code-converters.ts +3 -1
  48. package/src/api/sonamu.ts +41 -22
  49. package/src/bin/cli.ts +79 -46
  50. package/src/database/_batch_update.ts +16 -11
  51. package/src/database/base-model.abstract.ts +97 -0
  52. package/src/database/base-model.ts +214 -280
  53. package/src/database/code-generator.ts +72 -0
  54. package/src/database/db.abstract.ts +75 -0
  55. package/src/database/db.ts +21 -82
  56. package/src/database/drivers/knex/base-model.ts +55 -0
  57. package/src/database/drivers/knex/client.ts +209 -0
  58. package/src/database/drivers/knex/db.ts +227 -0
  59. package/src/database/drivers/knex/generator.ts +659 -0
  60. package/src/database/drivers/kysely/base-model.ts +89 -0
  61. package/src/database/drivers/kysely/client.ts +309 -0
  62. package/src/database/drivers/kysely/db.ts +238 -0
  63. package/src/database/drivers/kysely/generator.ts +714 -0
  64. package/src/database/types.ts +117 -0
  65. package/src/database/upsert-builder.ts +31 -18
  66. package/src/entity/entity-utils.ts +1 -1
  67. package/src/entity/migrator.ts +148 -711
  68. package/src/index.ts +1 -1
  69. package/src/syncer/syncer.ts +69 -27
  70. package/src/templates/generated_http.template.ts +14 -0
  71. package/src/templates/kysely_types.template.ts +205 -0
  72. package/src/templates/model.template.ts +2 -139
  73. package/src/templates/service.template.ts +3 -1
  74. package/src/testing/_relation-graph.ts +111 -0
  75. package/src/testing/fixture-manager.ts +216 -332
  76. package/src/types/types.ts +56 -6
  77. package/src/utils/utils.ts +56 -4
  78. package/src/utils/zod-error.ts +189 -0
  79. package/tsconfig.json +2 -2
  80. package/tsup.config.js +11 -10
  81. package/dist/chunk-MPXE4IHO.mjs.map +0 -1
  82. package/dist/chunk-YXILRRDT.js.map +0 -1
  83. /package/src/database/{knex-plugins → drivers/knex/plugins}/knex-on-duplicate-update.ts +0 -0
@@ -0,0 +1,117 @@
1
+ import { Knex } from "knex";
2
+ import {
3
+ FileMigrationProviderProps,
4
+ Kysely,
5
+ MysqlDialectConfig,
6
+ ReferenceExpression,
7
+ SelectQueryBuilder,
8
+ } from "kysely";
9
+ import { KnexClient } from "./drivers/knex/client";
10
+ import { KyselyClient } from "./drivers/kysely/client";
11
+ import { PoolOptions } from "mysql2";
12
+
13
+ export type DBPreset = "w" | "r";
14
+
15
+ export type DatabaseDriver = keyof DriverSpec;
16
+ /**
17
+ * core: 실제 데이터베이스 라이브러리 인스턴스
18
+ * adapter: Sonamu의 래퍼 클라이언트 구현체
19
+ * queryBuilder: 쿼리빌더 인스턴스
20
+ * table/column: 테이블과 컬럼 타입 정보
21
+ */
22
+ export interface DriverSpec {
23
+ knex: {
24
+ core: Knex;
25
+ adapter: KnexClient;
26
+ queryBuilder: Knex.QueryBuilder;
27
+ table: string;
28
+ column: string;
29
+ };
30
+ kysely: {
31
+ core: Kysely<Database>;
32
+ adapter: KyselyClient;
33
+ queryBuilder: SelectQueryBuilder<Database, keyof Database, {}>;
34
+ table: keyof Database;
35
+ column: ReferenceExpression<Database, keyof Database>;
36
+ };
37
+ }
38
+
39
+ export type WhereClause = [string, string, any];
40
+
41
+ export interface DatabaseClient<T extends DatabaseDriver> {
42
+ from(table: string): DriverSpec[T]["adapter"];
43
+ innerJoin(table: string, k1: string, k2: string): DriverSpec[T]["adapter"];
44
+ leftJoin(table: string, k1: string, k2: string): DriverSpec[T]["adapter"];
45
+ select(columns: string | string[]): DriverSpec[T]["adapter"];
46
+ where(o: WhereClause): DriverSpec[T]["adapter"];
47
+ orWhere(o: WhereClause | WhereClause[]): DriverSpec[T]["adapter"];
48
+ insert(table: string, data: Record<string, any>): Promise<void>;
49
+ first(): DriverSpec[T]["adapter"];
50
+ execute(): Promise<any[]>;
51
+
52
+ raw<R>(query: string, bindings?: any[]): Promise<R[]>;
53
+ truncate(table: string): Promise<void>;
54
+ trx<T>(callback: (trx: any) => Promise<T>): Promise<T>;
55
+ destroy(): Promise<void>;
56
+
57
+ getMigrations(): Promise<string[]>;
58
+ }
59
+
60
+ //
61
+
62
+ export type Environment =
63
+ | "development"
64
+ | "development_slave"
65
+ | "production"
66
+ | "production_slave";
67
+ type EnvironmentConfigs<T> = {
68
+ [K in Environment]?: Partial<T>;
69
+ };
70
+
71
+ // Knex 설정을 위한 타입
72
+ export type KnexConfig = Knex.Config & {
73
+ connection: Knex.MySql2ConnectionConfig;
74
+ };
75
+ export type KnexBaseConfig = {
76
+ client: "knex";
77
+ database: string;
78
+ defaultOptions?: Partial<KnexConfig>;
79
+ environments?: EnvironmentConfigs<KnexConfig>;
80
+ };
81
+
82
+ // Kysely 설정을 위한 타입
83
+ export type KyselyConfig = PoolOptions &
84
+ Pick<MysqlDialectConfig, "onCreateConnection"> & {
85
+ migration?: FileMigrationProviderProps;
86
+ };
87
+ export type KyselyBaseConfig = {
88
+ client: "kysely";
89
+ database: string;
90
+ defaultOptions: KyselyConfig;
91
+ environments?: EnvironmentConfigs<KyselyConfig>;
92
+ types?: {
93
+ enabled?: boolean; // 인터페이스 자동 생성 활성화 (기본값: true)
94
+ outDir?: string; // 생성될 파일 경로 (기본값: src/typings)
95
+ fileName?: string; // 생성될 파일명 (기본값: database.types.ts)
96
+ };
97
+ };
98
+ // export type SonamuDBBaseConfig = KnexBaseConfig | KyselyBaseConfig;
99
+ export type SonamuDBBaseConfig<
100
+ T extends "knex" | "kysely" = "knex" | "kysely",
101
+ > = T extends "knex" ? KnexBaseConfig : KyselyBaseConfig;
102
+
103
+ export type SonamuDBFullConfig<T extends KnexConfig | KyselyConfig> = {
104
+ development_master: T;
105
+ development_slave: T;
106
+ test: T;
107
+ fixture_local: T;
108
+ fixture_remote: T;
109
+ production_master: T;
110
+ production_slave: T;
111
+ };
112
+ export type SonamuKnexDBConfig = SonamuDBFullConfig<KnexConfig>;
113
+ export type SonamuKyselyDBConfig = SonamuDBFullConfig<KyselyConfig>;
114
+ export type SonamuDBConfig = SonamuKnexDBConfig | SonamuKyselyDBConfig;
115
+
116
+ export interface DatabaseExtend {}
117
+ export type Database = DatabaseExtend & {};
@@ -1,9 +1,12 @@
1
1
  import { v4 as uuidv4 } from "uuid";
2
2
  import _ from "lodash";
3
3
  import { Knex } from "knex";
4
+ import { Kysely } from "kysely";
4
5
  import { EntityManager } from "../entity/entity-manager";
5
6
  import { nonNullable } from "../utils/utils";
6
7
  import { RowWithId, batchUpdate } from "./_batch_update";
8
+ import { Database, DatabaseDriver, DriverSpec } from "./types";
9
+ import { DB } from "./db";
7
10
 
8
11
  type TableData = {
9
12
  references: Set<string>;
@@ -25,7 +28,7 @@ export function isRefField(field: any): field is UBRef {
25
28
  );
26
29
  }
27
30
 
28
- export class UpsertBuilder {
31
+ export class UpsertBuilder<D extends DatabaseDriver> {
29
32
  tables: Map<string, TableData>;
30
33
  constructor() {
31
34
  this.tables = new Map();
@@ -58,7 +61,7 @@ export class UpsertBuilder {
58
61
  }
59
62
 
60
63
  register<T extends string>(
61
- tableName: string,
64
+ tableName: DriverSpec[D]["table"],
62
65
  row: {
63
66
  [key in T]?:
64
67
  | UBRef
@@ -145,23 +148,23 @@ export class UpsertBuilder {
145
148
  }
146
149
 
147
150
  async upsert(
148
- wdb: Knex,
149
- tableName: string,
151
+ wdb: DriverSpec[D]["core"],
152
+ tableName: DriverSpec[D]["table"],
150
153
  chunkSize?: number
151
154
  ): Promise<number[]> {
152
155
  return this.upsertOrInsert(wdb, tableName, "upsert", chunkSize);
153
156
  }
154
157
  async insertOnly(
155
- wdb: Knex,
156
- tableName: string,
158
+ wdb: DriverSpec[D]["core"],
159
+ tableName: DriverSpec[D]["table"],
157
160
  chunkSize?: number
158
161
  ): Promise<number[]> {
159
162
  return this.upsertOrInsert(wdb, tableName, "insert", chunkSize);
160
163
  }
161
164
 
162
165
  async upsertOrInsert(
163
- wdb: Knex,
164
- tableName: string,
166
+ _wdb: DriverSpec[D]["core"],
167
+ tableName: DriverSpec[D]["table"],
165
168
  mode: "upsert" | "insert",
166
169
  chunkSize?: number
167
170
  ): Promise<number[]> {
@@ -186,6 +189,8 @@ export class UpsertBuilder {
186
189
  throw new Error(`${tableName} 해결되지 않은 참조가 있습니다.`);
187
190
  }
188
191
 
192
+ const wdb = DB.toClient(_wdb);
193
+
189
194
  // 전체 테이블 순회하여 현재 테이블 참조하는 모든 테이블 추출
190
195
  const { references, refTables } = Array.from(this.tables).reduce(
191
196
  (r, [, table]) => {
@@ -221,18 +226,20 @@ export class UpsertBuilder {
221
226
  const uuidMap = new Map<string, any>();
222
227
 
223
228
  for (const chunk of chunks) {
224
- const q = wdb.insert(chunk).into(tableName);
225
229
  if (mode === "insert") {
226
- await q;
230
+ await wdb.insert(tableName, chunk);
227
231
  } else if (mode === "upsert") {
228
- await q.onDuplicateUpdate.apply(q, Object.keys(normalRows[0]));
232
+ await wdb.upsert(tableName, chunk);
233
+ // await q.onDuplicateUpdate.apply(q, Object.keys(normalRows[0]));
229
234
  }
230
235
 
231
236
  // upsert된 row들을 다시 조회하여 uuidMap에 저장
232
237
  const uuids = chunk.map((row) => row.uuid);
233
- const upsertedRows = await wdb(tableName)
238
+ const upsertedRows = await wdb
239
+ .from(tableName)
234
240
  .select(_.uniq(["uuid", "id", ...extractFields]))
235
- .whereIn("uuid", uuids);
241
+ .where(["uuid", "in", uuids])
242
+ .execute();
236
243
  upsertedRows.forEach((row: any) => {
237
244
  uuidMap.set(row.uuid, row);
238
245
  });
@@ -264,7 +271,7 @@ export class UpsertBuilder {
264
271
  if (selfRefRows.length > 0) {
265
272
  // 처리된 데이터를 제외하고 다시 upsert
266
273
  table.rows = selfRefRows;
267
- const selfRefIds = await this.upsert(wdb, tableName, chunkSize);
274
+ const selfRefIds = await this.upsert(_wdb, tableName, chunkSize);
268
275
  allIds.push(...selfRefIds);
269
276
  }
270
277
 
@@ -272,11 +279,11 @@ export class UpsertBuilder {
272
279
  }
273
280
 
274
281
  async updateBatch(
275
- wdb: Knex,
276
- tableName: string,
282
+ wdb: Knex | Kysely<Database>,
283
+ tableName: DriverSpec[D]["table"],
277
284
  options?: {
278
285
  chunkSize?: number;
279
- where?: string | string[];
286
+ where?: DriverSpec[D]["column"] | DriverSpec[D]["column"][];
280
287
  }
281
288
  ): Promise<void> {
282
289
  options = _.defaults(options, {
@@ -300,6 +307,12 @@ export class UpsertBuilder {
300
307
  return row as RowWithId<string>;
301
308
  });
302
309
 
303
- await batchUpdate(wdb, tableName, whereColumns, rows, options.chunkSize);
310
+ await batchUpdate(
311
+ DB.toClient(wdb),
312
+ tableName,
313
+ whereColumns as string[],
314
+ rows,
315
+ options.chunkSize
316
+ );
304
317
  }
305
318
  }
@@ -155,7 +155,7 @@ function dateTime(
155
155
  }
156
156
  return {
157
157
  name,
158
- type: "dateTime",
158
+ type: "datetime",
159
159
  ...option,
160
160
  };
161
161
  }