sonamu 0.4.13 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.swcrc +15 -0
- package/dist/api/base-frame.d.ts +8 -0
- package/dist/api/base-frame.d.ts.map +1 -0
- package/dist/api/base-frame.js +2 -0
- package/dist/api/base-frame.js.map +1 -0
- package/dist/api/caster.d.ts +5 -0
- package/dist/api/caster.d.ts.map +1 -0
- package/dist/api/caster.js +2 -0
- package/dist/api/caster.js.map +1 -0
- package/dist/api/code-converters.d.ts +23 -0
- package/dist/api/code-converters.d.ts.map +1 -0
- package/dist/api/code-converters.js +2 -0
- package/dist/api/code-converters.js.map +1 -0
- package/dist/api/context.d.ts +16 -0
- package/dist/api/context.d.ts.map +1 -0
- package/dist/api/context.js +2 -0
- package/dist/api/context.js.map +1 -0
- package/dist/api/decorators.d.ts +50 -0
- package/dist/api/decorators.d.ts.map +1 -0
- package/dist/api/decorators.js +2 -0
- package/dist/api/decorators.js.map +1 -0
- package/dist/api/index.d.ts +8 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +2 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/sonamu.d.ts +83 -0
- package/dist/api/sonamu.d.ts.map +1 -0
- package/dist/api/sonamu.js +2 -0
- package/dist/api/sonamu.js.map +1 -0
- package/dist/api/sonamu.types.d.ts +30 -0
- package/dist/api/sonamu.types.d.ts.map +1 -0
- package/dist/api/sonamu.types.js +2 -0
- package/dist/api/sonamu.types.js.map +1 -0
- package/dist/bin/build-config.d.ts +5 -0
- package/dist/bin/build-config.d.ts.map +1 -0
- package/dist/bin/build-config.js +2 -0
- package/dist/bin/build-config.js.map +1 -0
- package/dist/bin/cli-wrapper.d.ts +2 -0
- package/dist/bin/cli-wrapper.d.ts.map +1 -0
- package/dist/bin/cli-wrapper.js +1 -38
- package/dist/bin/cli-wrapper.js.map +1 -1
- package/dist/bin/cli.d.ts +2 -2
- package/dist/bin/cli.d.ts.map +1 -0
- package/dist/bin/cli.js +1 -903
- package/dist/bin/cli.js.map +1 -1
- package/dist/bin/cli.mjs +2 -2
- package/dist/{chunk-DMJSNO2L.js → chunk-2WAC2GER.js} +44 -44
- package/dist/{chunk-DMJSNO2L.js.map → chunk-2WAC2GER.js.map} +1 -1
- package/dist/{chunk-NI37CY4T.mjs → chunk-C3IPIF6O.mjs} +2 -2
- package/dist/{chunk-DYFCACHD.js → chunk-EXHKSVTE.js} +7 -7
- package/dist/{chunk-QJFHDCBN.mjs → chunk-FCERKIIF.mjs} +2 -2
- package/dist/chunk-FCERKIIF.mjs.map +1 -0
- package/dist/{chunk-DDJ7T4MA.mjs → chunk-HGIBJYOU.mjs} +2 -2
- package/dist/{chunk-NIFOTHBW.mjs → chunk-JKSOJRQA.mjs} +2 -2
- package/dist/{chunk-CXAVBVKC.js → chunk-OTKKFP3Y.js} +100 -100
- package/dist/{chunk-J6S43O7G.js → chunk-UZ2IY5VE.js} +4 -4
- package/dist/database/_batch_update.d.ts +15 -0
- package/dist/database/_batch_update.d.ts.map +1 -0
- package/dist/database/_batch_update.js +2 -0
- package/dist/database/_batch_update.js.map +1 -0
- package/dist/database/base-model.d.ts +41 -0
- package/dist/database/base-model.d.ts.map +1 -0
- package/dist/database/base-model.js +2 -0
- package/dist/database/base-model.js.map +1 -0
- package/dist/database/code-generator.d.ts +13 -0
- package/dist/database/code-generator.d.ts.map +1 -0
- package/dist/database/code-generator.js +2 -0
- package/dist/database/code-generator.js.map +1 -0
- package/dist/database/db.d.ts +40 -0
- package/dist/database/db.d.ts.map +1 -0
- package/dist/database/db.js +2 -0
- package/dist/database/db.js.map +1 -0
- package/dist/database/drivers/knex/base-model.js +8 -8
- package/dist/database/drivers/knex/base-model.mjs +3 -3
- package/dist/database/drivers/kysely/base-model.js +9 -9
- package/dist/database/drivers/kysely/base-model.mjs +3 -3
- package/dist/database/knex-plugins/knex-on-duplicate-update.d.ts +2 -0
- package/dist/database/knex-plugins/knex-on-duplicate-update.d.ts.map +1 -0
- package/dist/database/knex-plugins/knex-on-duplicate-update.js +2 -0
- package/dist/database/knex-plugins/knex-on-duplicate-update.js.map +1 -0
- package/dist/database/puri-wrapper.d.ts +34 -0
- package/dist/database/puri-wrapper.d.ts.map +1 -0
- package/dist/database/puri-wrapper.js +2 -0
- package/dist/database/puri-wrapper.js.map +1 -0
- package/dist/database/puri.d.ts +83 -0
- package/dist/database/puri.d.ts.map +1 -0
- package/dist/database/puri.js +2 -0
- package/dist/database/puri.js.map +1 -0
- package/dist/database/puri.types.d.ts +60 -0
- package/dist/database/puri.types.d.ts.map +1 -0
- package/dist/database/puri.types.js +2 -0
- package/dist/database/puri.types.js.map +1 -0
- package/dist/database/transaction-context.d.ts +9 -0
- package/dist/database/transaction-context.d.ts.map +1 -0
- package/dist/database/transaction-context.js +2 -0
- package/dist/database/transaction-context.js.map +1 -0
- package/dist/database/types.d.ts +39 -0
- package/dist/database/types.d.ts.map +1 -0
- package/dist/database/types.js +2 -0
- package/dist/database/types.js.map +1 -0
- package/dist/database/upsert-builder.d.ts +34 -0
- package/dist/database/upsert-builder.d.ts.map +1 -0
- package/dist/database/upsert-builder.js +2 -0
- package/dist/database/upsert-builder.js.map +1 -0
- package/dist/entity/entity-manager.d.ts +32 -0
- package/dist/entity/entity-manager.d.ts.map +1 -0
- package/dist/entity/entity-manager.js +2 -0
- package/dist/entity/entity-manager.js.map +1 -0
- package/dist/entity/entity-utils.d.ts +61 -0
- package/dist/entity/entity-utils.d.ts.map +1 -0
- package/dist/entity/entity-utils.js +2 -0
- package/dist/entity/entity-utils.js.map +1 -0
- package/dist/entity/entity.d.ts +62 -0
- package/dist/entity/entity.d.ts.map +1 -0
- package/dist/entity/entity.js +2 -0
- package/dist/entity/entity.js.map +1 -0
- package/dist/entity/migrator.d.ts +135 -0
- package/dist/entity/migrator.d.ts.map +1 -0
- package/dist/entity/migrator.js +2 -0
- package/dist/entity/migrator.js.map +1 -0
- package/dist/exceptions/error-handler.d.ts +3 -0
- package/dist/exceptions/error-handler.d.ts.map +1 -0
- package/dist/exceptions/error-handler.js +2 -0
- package/dist/exceptions/error-handler.js.map +1 -0
- package/dist/exceptions/so-exceptions.d.ts +48 -0
- package/dist/exceptions/so-exceptions.d.ts.map +1 -0
- package/dist/exceptions/so-exceptions.js +2 -0
- package/dist/exceptions/so-exceptions.js.map +1 -0
- package/dist/file-storage/driver.d.ts +45 -0
- package/dist/file-storage/driver.d.ts.map +1 -0
- package/dist/file-storage/driver.js +2 -0
- package/dist/file-storage/driver.js.map +1 -0
- package/dist/file-storage/file-storage.d.ts +50 -0
- package/dist/file-storage/file-storage.d.ts.map +1 -0
- package/dist/file-storage/file-storage.js +2 -0
- package/dist/file-storage/file-storage.js.map +1 -0
- package/dist/index.d.ts +22 -813
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -433
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3 -3
- package/dist/migration/code-generation.d.ts +15 -0
- package/dist/migration/code-generation.d.ts.map +1 -0
- package/dist/migration/code-generation.js +2 -0
- package/dist/migration/code-generation.js.map +1 -0
- package/dist/migration/migration-set.d.ts +17 -0
- package/dist/migration/migration-set.d.ts.map +1 -0
- package/dist/migration/migration-set.js +2 -0
- package/dist/migration/migration-set.js.map +1 -0
- package/dist/migration/migrator.d.ts +130 -0
- package/dist/migration/migrator.d.ts.map +1 -0
- package/dist/migration/migrator.js +2 -0
- package/dist/migration/migrator.js.map +1 -0
- package/dist/migration/types.d.ts +52 -0
- package/dist/migration/types.d.ts.map +1 -0
- package/dist/migration/types.js +2 -0
- package/dist/migration/types.js.map +1 -0
- package/dist/smd/smd-manager.d.ts +28 -0
- package/dist/smd/smd-manager.d.ts.map +1 -0
- package/dist/smd/smd-manager.js +2 -0
- package/dist/smd/smd-manager.js.map +1 -0
- package/dist/smd/smd.d.ts +40 -0
- package/dist/smd/smd.d.ts.map +1 -0
- package/dist/smd/smd.js +2 -0
- package/dist/smd/smd.js.map +1 -0
- package/dist/syncer/index.d.ts +2 -0
- package/dist/syncer/index.d.ts.map +1 -0
- package/dist/syncer/index.js +2 -0
- package/dist/syncer/index.js.map +1 -0
- package/dist/syncer/syncer.d.ts +127 -0
- package/dist/syncer/syncer.d.ts.map +1 -0
- package/dist/syncer/syncer.js +2 -0
- package/dist/syncer/syncer.js.map +1 -0
- package/dist/templates/base-template.d.ts +13 -0
- package/dist/templates/base-template.d.ts.map +1 -0
- package/dist/templates/base-template.js +2 -0
- package/dist/templates/base-template.js.map +1 -0
- package/dist/templates/entity.template.d.ts +17 -0
- package/dist/templates/entity.template.d.ts.map +1 -0
- package/dist/templates/entity.template.js +2 -0
- package/dist/templates/entity.template.js.map +1 -0
- package/dist/templates/generated.template.d.ts +27 -0
- package/dist/templates/generated.template.d.ts.map +1 -0
- package/dist/templates/generated.template.js +2 -0
- package/dist/templates/generated.template.js.map +1 -0
- package/dist/templates/generated_http.template.d.ts +24 -0
- package/dist/templates/generated_http.template.d.ts.map +1 -0
- package/dist/templates/generated_http.template.js +2 -0
- package/dist/templates/generated_http.template.js.map +1 -0
- package/dist/templates/generated_sso.template.d.ts +20 -0
- package/dist/templates/generated_sso.template.d.ts.map +1 -0
- package/dist/templates/generated_sso.template.js +2 -0
- package/dist/templates/generated_sso.template.js.map +1 -0
- package/dist/templates/index.d.ts +2 -0
- package/dist/templates/index.d.ts.map +1 -0
- package/dist/templates/index.js +2 -0
- package/dist/templates/index.js.map +1 -0
- package/dist/templates/init_types.template.d.ts +17 -0
- package/dist/templates/init_types.template.d.ts.map +1 -0
- package/dist/templates/init_types.template.js +2 -0
- package/dist/templates/init_types.template.js.map +1 -0
- package/dist/templates/model.template.d.ts +17 -0
- package/dist/templates/model.template.d.ts.map +1 -0
- package/dist/templates/model.template.js +2 -0
- package/dist/templates/model.template.js.map +1 -0
- package/dist/templates/model_test.template.d.ts +17 -0
- package/dist/templates/model_test.template.d.ts.map +1 -0
- package/dist/templates/model_test.template.js +2 -0
- package/dist/templates/model_test.template.js.map +1 -0
- package/dist/templates/service.template.d.ts +29 -0
- package/dist/templates/service.template.d.ts.map +1 -0
- package/dist/templates/service.template.js +2 -0
- package/dist/templates/service.template.js.map +1 -0
- package/dist/templates/view_enums_buttonset.template.d.ts +17 -0
- package/dist/templates/view_enums_buttonset.template.d.ts.map +1 -0
- package/dist/templates/view_enums_buttonset.template.js +2 -0
- package/dist/templates/view_enums_buttonset.template.js.map +1 -0
- package/dist/templates/view_enums_dropdown.template.d.ts +18 -0
- package/dist/templates/view_enums_dropdown.template.d.ts.map +1 -0
- package/dist/templates/view_enums_dropdown.template.js +2 -0
- package/dist/templates/view_enums_dropdown.template.js.map +1 -0
- package/dist/templates/view_enums_select.template.d.ts +17 -0
- package/dist/templates/view_enums_select.template.d.ts.map +1 -0
- package/dist/templates/view_enums_select.template.js +2 -0
- package/dist/templates/view_enums_select.template.js.map +1 -0
- package/dist/templates/view_form.template.d.ts +26 -0
- package/dist/templates/view_form.template.d.ts.map +1 -0
- package/dist/templates/view_form.template.js +2 -0
- package/dist/templates/view_form.template.js.map +1 -0
- package/dist/templates/view_id_all_select.template.d.ts +17 -0
- package/dist/templates/view_id_all_select.template.d.ts.map +1 -0
- package/dist/templates/view_id_all_select.template.js +2 -0
- package/dist/templates/view_id_all_select.template.js.map +1 -0
- package/dist/templates/view_id_async_select.template.d.ts +17 -0
- package/dist/templates/view_id_async_select.template.d.ts.map +1 -0
- package/dist/templates/view_id_async_select.template.js +2 -0
- package/dist/templates/view_id_async_select.template.js.map +1 -0
- package/dist/templates/view_list.template.d.ts +38 -0
- package/dist/templates/view_list.template.d.ts.map +1 -0
- package/dist/templates/view_list.template.js +2 -0
- package/dist/templates/view_list.template.js.map +1 -0
- package/dist/templates/view_list_columns.template.d.ts +17 -0
- package/dist/templates/view_list_columns.template.d.ts.map +1 -0
- package/dist/templates/view_list_columns.template.js +2 -0
- package/dist/templates/view_list_columns.template.js.map +1 -0
- package/dist/templates/view_search_input.template.d.ts +17 -0
- package/dist/templates/view_search_input.template.d.ts.map +1 -0
- package/dist/templates/view_search_input.template.js +2 -0
- package/dist/templates/view_search_input.template.js.map +1 -0
- package/dist/testing/_relation-graph.d.ts +7 -0
- package/dist/testing/_relation-graph.d.ts.map +1 -0
- package/dist/testing/_relation-graph.js +2 -0
- package/dist/testing/_relation-graph.js.map +1 -0
- package/dist/testing/fixture-manager.d.ts +35 -0
- package/dist/testing/fixture-manager.d.ts.map +1 -0
- package/dist/testing/fixture-manager.js +2 -0
- package/dist/testing/fixture-manager.js.map +1 -0
- package/dist/types/types.d.ts +609 -0
- package/dist/types/types.d.ts.map +1 -0
- package/dist/types/types.js +2 -0
- package/dist/types/types.js.map +1 -0
- package/dist/typings/knex.d.js +2 -0
- package/dist/typings/knex.d.js.map +1 -0
- package/dist/utils/async-utils.d.ts +25 -0
- package/dist/utils/async-utils.d.ts.map +1 -0
- package/dist/utils/async-utils.js +2 -0
- package/dist/utils/async-utils.js.map +1 -0
- package/dist/utils/controller.d.ts +9 -0
- package/dist/utils/controller.d.ts.map +1 -0
- package/dist/utils/controller.js +2 -0
- package/dist/utils/controller.js.map +1 -0
- package/dist/utils/fs-utils.d.ts +9 -0
- package/dist/utils/fs-utils.d.ts.map +1 -0
- package/dist/utils/fs-utils.js +2 -0
- package/dist/utils/fs-utils.js.map +1 -0
- package/dist/utils/lodash-able.d.ts +2 -0
- package/dist/utils/lodash-able.d.ts.map +1 -0
- package/dist/utils/lodash-able.js +2 -0
- package/dist/utils/lodash-able.js.map +1 -0
- package/dist/utils/model.d.ts +17 -0
- package/dist/utils/model.d.ts.map +1 -0
- package/dist/utils/model.js +2 -0
- package/dist/utils/model.js.map +1 -0
- package/dist/utils/sql-parser.d.ts +4 -0
- package/dist/utils/sql-parser.d.ts.map +1 -0
- package/dist/utils/sql-parser.js +2 -0
- package/dist/utils/sql-parser.js.map +1 -0
- package/dist/utils/utils.d.ts +9 -0
- package/dist/utils/utils.d.ts.map +1 -0
- package/dist/utils/utils.js +2 -0
- package/dist/utils/utils.js.map +1 -0
- package/dist/utils/zod-error.d.ts +8 -0
- package/dist/utils/zod-error.d.ts.map +1 -0
- package/dist/utils/zod-error.js +2 -0
- package/dist/utils/zod-error.js.map +1 -0
- package/nodemon.json +6 -0
- package/package.json +29 -44
- package/src/api/base-frame.ts +3 -4
- package/src/api/caster.ts +22 -23
- package/src/api/code-converters.ts +170 -134
- package/src/api/context.ts +13 -6
- package/src/api/decorators.ts +146 -20
- package/src/api/index.ts +2 -0
- package/src/api/sonamu.ts +374 -165
- package/src/bin/build-config.ts +5 -0
- package/src/bin/cli-wrapper.ts +29 -40
- package/src/bin/cli.ts +132 -190
- package/src/database/_batch_update.ts +10 -15
- package/src/database/base-model.ts +300 -216
- package/src/database/db.ts +191 -21
- package/src/database/{drivers/knex/plugins → knex-plugins}/knex-on-duplicate-update.ts +1 -1
- package/src/database/puri-wrapper.ts +129 -0
- package/src/database/puri.ts +808 -0
- package/src/database/puri.types.ts +222 -0
- package/src/database/transaction-context.ts +18 -0
- package/src/database/upsert-builder.ts +32 -35
- package/src/entity/entity-manager.ts +7 -15
- package/src/entity/entity.ts +9 -31
- package/src/entity/migrator-/354/235/264/354/202/254/352/260/224/354/226/264/354/232/224.md +1 -0
- package/src/file-storage/driver.ts +121 -0
- package/src/file-storage/file-storage.ts +100 -0
- package/src/index.ts +14 -11
- package/src/migration/code-generation.ts +777 -0
- package/src/migration/migration-set.ts +453 -0
- package/src/migration/migrator.ts +823 -0
- package/src/migration/types.ts +53 -0
- package/src/shared/web.shared.ts.txt +33 -2
- package/src/syncer/syncer.ts +294 -127
- package/src/templates/generated.template.ts +13 -1
- package/src/templates/generated_http.template.ts +15 -12
- package/src/templates/generated_sso.template.ts +50 -2
- package/src/templates/model.template.ts +138 -2
- package/src/templates/service.template.ts +0 -1
- package/src/templates/view_form.template.ts +11 -7
- package/src/templates/view_list.template.ts +12 -4
- package/src/testing/fixture-manager.ts +229 -174
- package/src/types/types.ts +102 -14
- package/src/utils/async-utils.ts +64 -0
- package/src/utils/fs-utils.ts +17 -0
- package/src/utils/model.ts +0 -2
- package/src/utils/utils.ts +14 -58
- package/src/utils/zod-error.ts +12 -176
- package/tsconfig.json +2 -0
- package/tsup.config.js +4 -2
- package/.pnp.cjs +0 -14363
- package/.pnp.loader.mjs +0 -2047
- package/.vscode/extensions.json +0 -6
- package/.vscode/settings.json +0 -9
- package/.yarnrc.yml +0 -5
- package/dist/chunk-QJFHDCBN.mjs.map +0 -1
- package/src/database/base-model.abstract.ts +0 -97
- package/src/database/db.abstract.ts +0 -75
- package/src/database/drivers/knex/base-model.ts +0 -55
- package/src/database/drivers/knex/client.ts +0 -209
- package/src/database/drivers/knex/db.ts +0 -232
- package/src/database/drivers/knex/generator.ts +0 -659
- package/src/database/drivers/kysely/base-model.ts +0 -89
- package/src/database/drivers/kysely/client.ts +0 -309
- package/src/database/drivers/kysely/db.ts +0 -238
- package/src/database/drivers/kysely/generator.ts +0 -714
- package/src/database/types.ts +0 -118
- package/src/entity/migrator.ts +0 -1400
- package/src/smd/smd-manager.ts +0 -139
- package/src/smd/smd.ts +0 -571
- package/src/templates/kysely_types.template.ts +0 -205
- /package/dist/{chunk-NI37CY4T.mjs.map → chunk-C3IPIF6O.mjs.map} +0 -0
- /package/dist/{chunk-DYFCACHD.js.map → chunk-EXHKSVTE.js.map} +0 -0
- /package/dist/{chunk-DDJ7T4MA.mjs.map → chunk-HGIBJYOU.mjs.map} +0 -0
- /package/dist/{chunk-NIFOTHBW.mjs.map → chunk-JKSOJRQA.mjs.map} +0 -0
- /package/dist/{chunk-CXAVBVKC.js.map → chunk-OTKKFP3Y.js.map} +0 -0
- /package/dist/{chunk-J6S43O7G.js.map → chunk-UZ2IY5VE.js.map} +0 -0
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
export type ComparisonOperator = "=" | ">" | ">=" | "<" | "<=" | "<>" | "!=";
|
|
2
|
+
export type Expand<T> = T extends any[]
|
|
3
|
+
? { [K in keyof T[0]]: T[0][K] }[] // 배열이면 첫 번째 요소를 Expand하고 배열로 감쌈
|
|
4
|
+
: T extends object ? { [K in keyof T]: T[K] } : T;
|
|
5
|
+
|
|
6
|
+
// EmptyRecord가 남아있으면 AvailableColumns 추론이 제대로 되지 않음 (EmptyRecord를 {}로 변경하면 정상 동작함)
|
|
7
|
+
export type MergeJoined<TExisting, TNew> =
|
|
8
|
+
TExisting extends EmptyRecord
|
|
9
|
+
? TNew // 첫 join: EmptyRecord 제거하고 대체
|
|
10
|
+
: TExisting & TNew; // 이후 join: 누적
|
|
11
|
+
|
|
12
|
+
type DeepEqual<T, U> = [T] extends [U] ? [U] extends [T] ? true : false : false;
|
|
13
|
+
type Extends<T, U> = DeepEqual<T, Record<string, never>> extends true ? false : (T extends U ? true : false);
|
|
14
|
+
type NullableToOptional<T> = {
|
|
15
|
+
[K in keyof T as T[K] extends null | undefined ? K : never]?: Exclude<T[K], null | undefined>
|
|
16
|
+
} & Partial<{
|
|
17
|
+
[K in keyof T as T[K] extends null | undefined ? never : K]: T[K]
|
|
18
|
+
}>;
|
|
19
|
+
|
|
20
|
+
// Join 등이 Empty 상태일 떄 {}가 아니라 EmptyRecord를 써서
|
|
21
|
+
export type EmptyRecord = Record<string, never>;
|
|
22
|
+
|
|
23
|
+
// Group By, Order By, Having 등에서 선택 가능한 컬럼
|
|
24
|
+
export type ResultAvailableColumns<
|
|
25
|
+
TSchema,
|
|
26
|
+
T extends keyof TSchema | string,
|
|
27
|
+
TOriginal = any,
|
|
28
|
+
TResult = any,
|
|
29
|
+
TJoined = EmptyRecord,
|
|
30
|
+
> = AvailableColumns<TSchema, T, TOriginal, TJoined> | `${keyof TResult & string}`;
|
|
31
|
+
|
|
32
|
+
// 사용 가능한 컬럼 경로 타입 (메인 테이블 + 조인된 테이블들)
|
|
33
|
+
export type AvailableColumns<
|
|
34
|
+
TSchema,
|
|
35
|
+
T extends keyof TSchema | string,
|
|
36
|
+
TOriginal = any,
|
|
37
|
+
TJoined = EmptyRecord,
|
|
38
|
+
> = T extends keyof TSchema
|
|
39
|
+
? // 기존 테이블 케이스
|
|
40
|
+
| (Extends<TJoined, Record<string, any>> extends false
|
|
41
|
+
// 이게 TSchema[T]에 존재하면
|
|
42
|
+
? keyof TSchema[T]
|
|
43
|
+
: {
|
|
44
|
+
[K in keyof TJoined]: TJoined[K] extends Record<string, any>
|
|
45
|
+
? `${string & K}.${keyof TJoined[K] & string}`
|
|
46
|
+
: never;
|
|
47
|
+
}[keyof TJoined])
|
|
48
|
+
| `${T & string}.${keyof TSchema[T] & string}`
|
|
49
|
+
: // 서브쿼리 케이스 (T는 alias string)
|
|
50
|
+
| keyof TOriginal
|
|
51
|
+
| `${T & string}.${keyof TOriginal & string}`
|
|
52
|
+
| (Extends<TJoined, Record<string, any>> extends true
|
|
53
|
+
? {
|
|
54
|
+
[K in keyof TJoined]: TJoined[K] extends Record<string, any>
|
|
55
|
+
? `${string & K}.${keyof TJoined[K] & string}`
|
|
56
|
+
: never;
|
|
57
|
+
}[keyof TJoined]
|
|
58
|
+
: never);
|
|
59
|
+
|
|
60
|
+
// 컬럼 경로에서 타입 추출
|
|
61
|
+
export type ExtractColumnType<
|
|
62
|
+
TSchema,
|
|
63
|
+
T extends keyof TSchema | string,
|
|
64
|
+
Path extends string,
|
|
65
|
+
TOriginal = any,
|
|
66
|
+
TJoined = EmptyRecord,
|
|
67
|
+
> = T extends keyof TSchema
|
|
68
|
+
? // 기존 테이블 케이스
|
|
69
|
+
Path extends keyof TSchema[T]
|
|
70
|
+
? TSchema[T][Path] // 메인 테이블 컬럼
|
|
71
|
+
: Path extends `${T & string}.${infer Column}`
|
|
72
|
+
? Column extends keyof TSchema[T]
|
|
73
|
+
? TSchema[T][Column]
|
|
74
|
+
: never
|
|
75
|
+
: Path extends `${infer Table}.${infer Column}`
|
|
76
|
+
? Table extends keyof TJoined
|
|
77
|
+
? TJoined[Table] extends Record<string, any>
|
|
78
|
+
? Column extends keyof TJoined[Table]
|
|
79
|
+
? TJoined[Table][Column]
|
|
80
|
+
: never
|
|
81
|
+
: never
|
|
82
|
+
: never
|
|
83
|
+
: never
|
|
84
|
+
: // 서브쿼리 케이스 (T는 alias)
|
|
85
|
+
Path extends `${T & string}.${infer Column}`
|
|
86
|
+
? Column extends keyof TOriginal
|
|
87
|
+
? TOriginal[Column] // 서브쿼리 alias.컬럼
|
|
88
|
+
: never
|
|
89
|
+
: Path extends `${infer Table}.${infer Column}`
|
|
90
|
+
? Table extends keyof TJoined
|
|
91
|
+
? TJoined[Table] extends Record<string, any>
|
|
92
|
+
? Column extends keyof TJoined[Table]
|
|
93
|
+
? TJoined[Table][Column]
|
|
94
|
+
: never
|
|
95
|
+
: never
|
|
96
|
+
: never
|
|
97
|
+
: Path extends keyof TOriginal
|
|
98
|
+
? TOriginal[Path] // 서브쿼리 컬럼 직접 접근 (가장 마지막에)
|
|
99
|
+
: never;
|
|
100
|
+
|
|
101
|
+
// SQL 함수 타입 정의
|
|
102
|
+
export type SqlFunction<T extends "string" | "number" | "boolean" | "date"> = {
|
|
103
|
+
_type: "sql_function";
|
|
104
|
+
_return: T;
|
|
105
|
+
_sql: string;
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
// SQL 함수 결과에서 타입 추출
|
|
109
|
+
type ExtractSqlType<T> =
|
|
110
|
+
T extends SqlFunction<infer R>
|
|
111
|
+
? R extends "string"
|
|
112
|
+
? string
|
|
113
|
+
: R extends "number"
|
|
114
|
+
? number
|
|
115
|
+
: R extends "boolean"
|
|
116
|
+
? boolean
|
|
117
|
+
: R extends "date"
|
|
118
|
+
? Date
|
|
119
|
+
: never
|
|
120
|
+
: never;
|
|
121
|
+
|
|
122
|
+
// Select 값 타입 확장
|
|
123
|
+
export type SelectValue<
|
|
124
|
+
TSchema,
|
|
125
|
+
T extends keyof TSchema | string,
|
|
126
|
+
TOriginal = any,
|
|
127
|
+
TJoined = EmptyRecord,
|
|
128
|
+
> =
|
|
129
|
+
| AvailableColumns<TSchema, T, TOriginal, TJoined> // 기존 컬럼
|
|
130
|
+
| SqlFunction<"string" | "number" | "boolean" | "date">; // SQL 함수
|
|
131
|
+
|
|
132
|
+
// Select 객체 타입 정의
|
|
133
|
+
export type SelectObject<
|
|
134
|
+
TSchema,
|
|
135
|
+
T extends keyof TSchema | string,
|
|
136
|
+
TOriginal = any,
|
|
137
|
+
TJoined = EmptyRecord,
|
|
138
|
+
> = Record<string, SelectValue<TSchema, T, TOriginal, TJoined>>;
|
|
139
|
+
|
|
140
|
+
// Select 결과 타입 추론
|
|
141
|
+
export type ParseSelectObject<
|
|
142
|
+
TSchema,
|
|
143
|
+
T extends keyof TSchema | string,
|
|
144
|
+
S extends SelectObject<TSchema, T, TOriginal, TJoined>,
|
|
145
|
+
TOriginal = any,
|
|
146
|
+
TJoined = EmptyRecord,
|
|
147
|
+
> = {
|
|
148
|
+
[K in keyof S]: S[K] extends SqlFunction<any>
|
|
149
|
+
? ExtractSqlType<S[K]> // SQL 함수면 타입 추출
|
|
150
|
+
: ExtractColumnType<TSchema, T, S[K] & string, TOriginal, TJoined>;
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
// Where 조건 타입 (조인된 테이블 컬럼도 포함)
|
|
154
|
+
export type WhereCondition<
|
|
155
|
+
TSchema,
|
|
156
|
+
T extends keyof TSchema | string,
|
|
157
|
+
TOriginal = any,
|
|
158
|
+
TJoined = EmptyRecord,
|
|
159
|
+
> =
|
|
160
|
+
// 메인 테이블/서브쿼리 조건들
|
|
161
|
+
(T extends keyof TSchema
|
|
162
|
+
? {
|
|
163
|
+
[K in keyof TSchema[T]]?: TSchema[T][K] | TSchema[T][K][];
|
|
164
|
+
}
|
|
165
|
+
: {
|
|
166
|
+
[K in keyof TOriginal]?: TOriginal[K] | TOriginal[K][];
|
|
167
|
+
}) &
|
|
168
|
+
// 조인된 테이블들의 조건들
|
|
169
|
+
(TJoined extends Record<string, any>
|
|
170
|
+
? {
|
|
171
|
+
[K in keyof TJoined as TJoined[K] extends Record<string, any>
|
|
172
|
+
? keyof TJoined[K] & string
|
|
173
|
+
: never]?: TJoined[K] extends Record<string, any>
|
|
174
|
+
?
|
|
175
|
+
| TJoined[K][K extends keyof TJoined[K] ? K : never]
|
|
176
|
+
| TJoined[K][K extends keyof TJoined[K] ? K : never][]
|
|
177
|
+
: never;
|
|
178
|
+
}
|
|
179
|
+
: Record<string, never>);
|
|
180
|
+
|
|
181
|
+
// Fulltext index 컬럼 추출 타입 (메인 테이블 + 조인된 테이블)
|
|
182
|
+
export type FulltextColumns<
|
|
183
|
+
TSchema,
|
|
184
|
+
T extends keyof TSchema | string,
|
|
185
|
+
TOriginal = any,
|
|
186
|
+
TJoined = EmptyRecord,
|
|
187
|
+
> = T extends keyof TSchema
|
|
188
|
+
? // 기존 테이블 케이스
|
|
189
|
+
| (TSchema[T] extends { __fulltext__: readonly (infer Col)[] }
|
|
190
|
+
? Col & string
|
|
191
|
+
: never)
|
|
192
|
+
| (TSchema[T] extends { __fulltext__: readonly (infer Col)[] }
|
|
193
|
+
? `${T & string}.${Col & string}`
|
|
194
|
+
: never)
|
|
195
|
+
| (TJoined extends Record<string, any>
|
|
196
|
+
? {
|
|
197
|
+
[K in keyof TJoined]: TJoined[K] extends {
|
|
198
|
+
__fulltext__: readonly (infer Col)[];
|
|
199
|
+
}
|
|
200
|
+
? (Col & string) | `${string & K}.${Col & string}`
|
|
201
|
+
: never;
|
|
202
|
+
}[keyof TJoined]
|
|
203
|
+
: never)
|
|
204
|
+
: // 서브쿼리 케이스 (T는 alias)
|
|
205
|
+
| (TOriginal extends { __fulltext__: readonly (infer Col)[] }
|
|
206
|
+
? Col & string
|
|
207
|
+
: never)
|
|
208
|
+
| (TOriginal extends { __fulltext__: readonly (infer Col)[] }
|
|
209
|
+
? `${T & string}.${Col & string}`
|
|
210
|
+
: never)
|
|
211
|
+
| (TJoined extends Record<string, any>
|
|
212
|
+
? {
|
|
213
|
+
[K in keyof TJoined]: TJoined[K] extends {
|
|
214
|
+
__fulltext__: readonly (infer Col)[];
|
|
215
|
+
}
|
|
216
|
+
? (Col & string) | `${string & K}.${Col & string}`
|
|
217
|
+
: never;
|
|
218
|
+
}[keyof TJoined]
|
|
219
|
+
: never);
|
|
220
|
+
|
|
221
|
+
// Insert 타입: id, created_at 제외
|
|
222
|
+
export type InsertData<T> = NullableToOptional<Omit<T, "id" | "created_at" | "__fulltext__">>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { PuriWrapper } from "./puri-wrapper";
|
|
2
|
+
import type { DBPreset } from "./db";
|
|
3
|
+
|
|
4
|
+
export class TransactionContext {
|
|
5
|
+
private transactions: Map<DBPreset, PuriWrapper> = new Map();
|
|
6
|
+
|
|
7
|
+
getTransaction(preset: DBPreset): PuriWrapper | undefined {
|
|
8
|
+
return this.transactions.get(preset);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
setTransaction(preset: DBPreset, trx: PuriWrapper): void {
|
|
12
|
+
this.transactions.set(preset, trx);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
deleteTransaction(preset: DBPreset): void {
|
|
16
|
+
this.transactions.delete(preset);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { randomUUID } from "crypto";
|
|
2
2
|
import _ from "lodash";
|
|
3
3
|
import { Knex } from "knex";
|
|
4
|
-
import { Kysely } from "kysely";
|
|
5
4
|
import { EntityManager } from "../entity/entity-manager";
|
|
6
5
|
import { nonNullable } from "../utils/utils";
|
|
7
6
|
import { RowWithId, batchUpdate } from "./_batch_update";
|
|
8
|
-
import { Database, DatabaseDriver, DriverSpec } from "./types";
|
|
9
|
-
import { DB } from "./db";
|
|
10
7
|
|
|
11
8
|
type TableData = {
|
|
12
9
|
references: Set<string>;
|
|
@@ -28,7 +25,7 @@ export function isRefField(field: any): field is UBRef {
|
|
|
28
25
|
);
|
|
29
26
|
}
|
|
30
27
|
|
|
31
|
-
export class UpsertBuilder
|
|
28
|
+
export class UpsertBuilder {
|
|
32
29
|
tables: Map<string, TableData>;
|
|
33
30
|
constructor() {
|
|
34
31
|
this.tables = new Map();
|
|
@@ -61,7 +58,7 @@ export class UpsertBuilder<D extends DatabaseDriver> {
|
|
|
61
58
|
}
|
|
62
59
|
|
|
63
60
|
register<T extends string>(
|
|
64
|
-
tableName:
|
|
61
|
+
tableName: string,
|
|
65
62
|
row: {
|
|
66
63
|
[key in T]?:
|
|
67
64
|
| UBRef
|
|
@@ -84,7 +81,7 @@ export class UpsertBuilder<D extends DatabaseDriver> {
|
|
|
84
81
|
if (isRefField(val)) {
|
|
85
82
|
return val.uuid;
|
|
86
83
|
} else {
|
|
87
|
-
return row[unqCol as keyof typeof row] ??
|
|
84
|
+
return row[unqCol as keyof typeof row] ?? randomUUID(); // nullable인 경우 uuid로 랜덤값 삽입
|
|
88
85
|
}
|
|
89
86
|
});
|
|
90
87
|
|
|
@@ -108,7 +105,7 @@ export class UpsertBuilder<D extends DatabaseDriver> {
|
|
|
108
105
|
}
|
|
109
106
|
|
|
110
107
|
// 찾을 수 없는 경우 생성
|
|
111
|
-
return
|
|
108
|
+
return randomUUID();
|
|
112
109
|
})();
|
|
113
110
|
|
|
114
111
|
// 모든 유니크키에 대해 유니크맵에 uuid 저장
|
|
@@ -127,7 +124,7 @@ export class UpsertBuilder<D extends DatabaseDriver> {
|
|
|
127
124
|
rowValue.use ??= "id";
|
|
128
125
|
table.references.add(rowValue.of + "." + rowValue.use);
|
|
129
126
|
r[rowKey] = rowValue;
|
|
130
|
-
} else if (typeof rowValue === "object") {
|
|
127
|
+
} else if (typeof rowValue === "object" && !(rowValue instanceof Date)) {
|
|
131
128
|
// object인 경우 JSON으로 변환
|
|
132
129
|
r[rowKey] = rowValue === null ? null : JSON.stringify(rowValue);
|
|
133
130
|
} else {
|
|
@@ -148,23 +145,23 @@ export class UpsertBuilder<D extends DatabaseDriver> {
|
|
|
148
145
|
}
|
|
149
146
|
|
|
150
147
|
async upsert(
|
|
151
|
-
wdb:
|
|
152
|
-
tableName:
|
|
148
|
+
wdb: Knex,
|
|
149
|
+
tableName: string,
|
|
153
150
|
chunkSize?: number
|
|
154
151
|
): Promise<number[]> {
|
|
155
152
|
return this.upsertOrInsert(wdb, tableName, "upsert", chunkSize);
|
|
156
153
|
}
|
|
157
154
|
async insertOnly(
|
|
158
|
-
wdb:
|
|
159
|
-
tableName:
|
|
155
|
+
wdb: Knex,
|
|
156
|
+
tableName: string,
|
|
160
157
|
chunkSize?: number
|
|
161
158
|
): Promise<number[]> {
|
|
162
159
|
return this.upsertOrInsert(wdb, tableName, "insert", chunkSize);
|
|
163
160
|
}
|
|
164
161
|
|
|
165
162
|
async upsertOrInsert(
|
|
166
|
-
|
|
167
|
-
tableName:
|
|
163
|
+
wdb: Knex,
|
|
164
|
+
tableName: string,
|
|
168
165
|
mode: "upsert" | "insert",
|
|
169
166
|
chunkSize?: number
|
|
170
167
|
): Promise<number[]> {
|
|
@@ -189,8 +186,6 @@ export class UpsertBuilder<D extends DatabaseDriver> {
|
|
|
189
186
|
throw new Error(`${tableName} 해결되지 않은 참조가 있습니다.`);
|
|
190
187
|
}
|
|
191
188
|
|
|
192
|
-
const wdb = DB.toClient(_wdb);
|
|
193
|
-
|
|
194
189
|
// 전체 테이블 순회하여 현재 테이블 참조하는 모든 테이블 추출
|
|
195
190
|
const { references, refTables } = Array.from(this.tables).reduce(
|
|
196
191
|
(r, [, table]) => {
|
|
@@ -226,20 +221,18 @@ export class UpsertBuilder<D extends DatabaseDriver> {
|
|
|
226
221
|
const uuidMap = new Map<string, any>();
|
|
227
222
|
|
|
228
223
|
for (const chunk of chunks) {
|
|
224
|
+
const q = wdb.insert(chunk).into(tableName);
|
|
229
225
|
if (mode === "insert") {
|
|
230
|
-
await
|
|
226
|
+
await q;
|
|
231
227
|
} else if (mode === "upsert") {
|
|
232
|
-
await
|
|
233
|
-
// await q.onDuplicateUpdate.apply(q, Object.keys(normalRows[0]));
|
|
228
|
+
await q.onDuplicateUpdate.apply(q, Object.keys(normalRows[0]));
|
|
234
229
|
}
|
|
235
230
|
|
|
236
231
|
// upsert된 row들을 다시 조회하여 uuidMap에 저장
|
|
237
232
|
const uuids = chunk.map((row) => row.uuid);
|
|
238
|
-
const upsertedRows = await wdb
|
|
239
|
-
.from(tableName)
|
|
233
|
+
const upsertedRows = await wdb(tableName)
|
|
240
234
|
.select(_.uniq(["uuid", "id", ...extractFields]))
|
|
241
|
-
.
|
|
242
|
-
.execute();
|
|
235
|
+
.whereIn("uuid", uuids);
|
|
243
236
|
upsertedRows.forEach((row: any) => {
|
|
244
237
|
uuidMap.set(row.uuid, row);
|
|
245
238
|
});
|
|
@@ -271,19 +264,24 @@ export class UpsertBuilder<D extends DatabaseDriver> {
|
|
|
271
264
|
if (selfRefRows.length > 0) {
|
|
272
265
|
// 처리된 데이터를 제외하고 다시 upsert
|
|
273
266
|
table.rows = selfRefRows;
|
|
274
|
-
const selfRefIds = await this.upsert(
|
|
267
|
+
const selfRefIds = await this.upsert(wdb, tableName, chunkSize);
|
|
275
268
|
allIds.push(...selfRefIds);
|
|
269
|
+
} else {
|
|
270
|
+
// 자기 참조가 없으면 해당 테이블의 데이터 초기화
|
|
271
|
+
table.rows = [];
|
|
272
|
+
table.references.clear();
|
|
273
|
+
table.uniquesMap.clear();
|
|
276
274
|
}
|
|
277
275
|
|
|
278
276
|
return allIds;
|
|
279
277
|
}
|
|
280
278
|
|
|
281
279
|
async updateBatch(
|
|
282
|
-
wdb: Knex
|
|
283
|
-
tableName:
|
|
280
|
+
wdb: Knex,
|
|
281
|
+
tableName: string,
|
|
284
282
|
options?: {
|
|
285
283
|
chunkSize?: number;
|
|
286
|
-
where?:
|
|
284
|
+
where?: string | string[];
|
|
287
285
|
}
|
|
288
286
|
): Promise<void> {
|
|
289
287
|
options = _.defaults(options, {
|
|
@@ -307,12 +305,11 @@ export class UpsertBuilder<D extends DatabaseDriver> {
|
|
|
307
305
|
return row as RowWithId<string>;
|
|
308
306
|
});
|
|
309
307
|
|
|
310
|
-
await batchUpdate(
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
);
|
|
308
|
+
await batchUpdate(wdb, tableName, whereColumns, rows, options.chunkSize);
|
|
309
|
+
|
|
310
|
+
// updateBatch 완료 후 처리된 데이터 제거
|
|
311
|
+
table.rows = [];
|
|
312
|
+
table.references.clear();
|
|
313
|
+
table.uniquesMap.clear();
|
|
317
314
|
}
|
|
318
315
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
|
-
import glob from "
|
|
2
|
+
import { glob } from "fs/promises";
|
|
3
3
|
import inflection from "inflection";
|
|
4
4
|
import _ from "lodash";
|
|
5
5
|
import path from "path";
|
|
6
6
|
import { Entity } from "./entity";
|
|
7
7
|
import { EntityJson } from "../types/types";
|
|
8
8
|
import { Sonamu } from "../api/sonamu";
|
|
9
|
-
import
|
|
9
|
+
import { readFile } from "fs/promises";
|
|
10
10
|
|
|
11
11
|
export type EntityNamesRecord = Record<
|
|
12
12
|
| "fs"
|
|
@@ -40,18 +40,10 @@ class EntityManagerClass {
|
|
|
40
40
|
);
|
|
41
41
|
!doSilent && console.log(chalk.yellow(`autoload ${pathPattern}`));
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
await this.register(JSON.parse(fs.readFileSync(file).toString()));
|
|
48
|
-
})
|
|
49
|
-
).then(() => {
|
|
50
|
-
resolve("ok");
|
|
51
|
-
this.isAutoloaded = true;
|
|
52
|
-
});
|
|
53
|
-
});
|
|
54
|
-
});
|
|
43
|
+
for await (const file of glob(path.resolve(pathPattern!))) {
|
|
44
|
+
await this.register(JSON.parse((await readFile(file)).toString()));
|
|
45
|
+
}
|
|
46
|
+
this.isAutoloaded = true;
|
|
55
47
|
}
|
|
56
48
|
|
|
57
49
|
async reload(doSilent: boolean = false) {
|
|
@@ -63,7 +55,7 @@ class EntityManagerClass {
|
|
|
63
55
|
|
|
64
56
|
const sonamuPath = path.join(
|
|
65
57
|
Sonamu.apiRootPath,
|
|
66
|
-
`dist/application/sonamu.generated.js
|
|
58
|
+
`dist/application/sonamu.generated.js`
|
|
67
59
|
);
|
|
68
60
|
// CJS
|
|
69
61
|
if (require?.cache && require.cache[sonamuPath]) {
|
package/src/entity/entity.ts
CHANGED
|
@@ -19,11 +19,12 @@ import {
|
|
|
19
19
|
} from "../types/types";
|
|
20
20
|
import inflection from "inflection";
|
|
21
21
|
import path from "path";
|
|
22
|
-
import
|
|
22
|
+
import { writeFile } from "fs/promises";
|
|
23
23
|
import { z } from "zod";
|
|
24
24
|
import { Sonamu } from "../api/sonamu";
|
|
25
25
|
import prettier from "prettier";
|
|
26
26
|
import { nonNullable } from "../utils/utils";
|
|
27
|
+
import { exists } from "../utils/fs-utils";
|
|
27
28
|
|
|
28
29
|
export class Entity {
|
|
29
30
|
id: string;
|
|
@@ -329,37 +330,14 @@ export class Entity {
|
|
|
329
330
|
toCol: relation.joinColumn,
|
|
330
331
|
};
|
|
331
332
|
} else if (isManyToManyRelationProp(relation)) {
|
|
332
|
-
const [table1, table2] = relation.joinTable.split("__");
|
|
333
|
-
const throughTables = (() => {
|
|
334
|
-
// 동일 테이블 릴레이션인 경우
|
|
335
|
-
if (this.table === relEntity.table) {
|
|
336
|
-
if (table1 === this.table) {
|
|
337
|
-
return {
|
|
338
|
-
fromCol: `${inflection.singularize(table1)}_id`,
|
|
339
|
-
toCol: `${inflection.singularize(table2)}_id`,
|
|
340
|
-
};
|
|
341
|
-
} else {
|
|
342
|
-
return {
|
|
343
|
-
fromCol: `${inflection.singularize(table2)}_id`,
|
|
344
|
-
toCol: `${inflection.singularize(table1)}_id`,
|
|
345
|
-
};
|
|
346
|
-
}
|
|
347
|
-
} else {
|
|
348
|
-
// 서로 다른 테이블인 경우 릴레이션 테이블 유지
|
|
349
|
-
return {
|
|
350
|
-
fromCol: `${inflection.singularize(this.table)}_id`,
|
|
351
|
-
toCol: `${inflection.singularize(relEntity.table)}_id`,
|
|
352
|
-
};
|
|
353
|
-
}
|
|
354
|
-
})();
|
|
355
|
-
|
|
356
333
|
manyJoin = {
|
|
357
334
|
fromTable: this.table,
|
|
358
335
|
fromCol: "id",
|
|
359
336
|
idField: prefix === "" ? `id` : `${prefix}__id`,
|
|
360
337
|
through: {
|
|
361
338
|
table: relation.joinTable,
|
|
362
|
-
|
|
339
|
+
fromCol: `${inflection.singularize(this.table)}_id`,
|
|
340
|
+
toCol: `${inflection.singularize(relEntity.table)}_id`,
|
|
363
341
|
},
|
|
364
342
|
toTable: relEntity.table,
|
|
365
343
|
toCol: "id",
|
|
@@ -523,7 +501,7 @@ export class Entity {
|
|
|
523
501
|
.filter((f) => f !== null) as string[];
|
|
524
502
|
}
|
|
525
503
|
|
|
526
|
-
getTableColumns(): string[] {
|
|
504
|
+
getTableColumns(): { name: string; type: string }[] {
|
|
527
505
|
return this.props
|
|
528
506
|
.map((prop) => {
|
|
529
507
|
if (prop.type === "relation") {
|
|
@@ -531,12 +509,12 @@ export class Entity {
|
|
|
531
509
|
prop.relationType === "BelongsToOne" ||
|
|
532
510
|
(prop.relationType === "OneToOne" && prop.hasJoinColumn === true)
|
|
533
511
|
) {
|
|
534
|
-
return `${prop.name}_id
|
|
512
|
+
return { name: `${prop.name}_id`, type: "int_unsigned" };
|
|
535
513
|
} else {
|
|
536
514
|
return null;
|
|
537
515
|
}
|
|
538
516
|
}
|
|
539
|
-
return prop.name;
|
|
517
|
+
return { name: prop.name, type: prop.type };
|
|
540
518
|
})
|
|
541
519
|
.filter(nonNullable);
|
|
542
520
|
}
|
|
@@ -574,7 +552,7 @@ export class Entity {
|
|
|
574
552
|
`dist/application/${typesModulePath}.js`
|
|
575
553
|
);
|
|
576
554
|
|
|
577
|
-
if (
|
|
555
|
+
if (await exists(typesFileDistPath)) {
|
|
578
556
|
const importPath = path.relative(__dirname, typesFileDistPath);
|
|
579
557
|
const t = await import(importPath);
|
|
580
558
|
this.types = Object.keys(t).reduce((result, key) => {
|
|
@@ -627,7 +605,7 @@ export class Entity {
|
|
|
627
605
|
`src/application/${this.names.parentFs}/${this.names.fs}.entity.json`
|
|
628
606
|
);
|
|
629
607
|
const json = this.toJson();
|
|
630
|
-
|
|
608
|
+
await writeFile(
|
|
631
609
|
jsonPath,
|
|
632
610
|
await prettier.format(JSON.stringify(json), {
|
|
633
611
|
parser: "json",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[여기](../migration/migrator.ts)로 이사갔어요.
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DeleteObjectCommand,
|
|
3
|
+
GetObjectCommand,
|
|
4
|
+
PutObjectCommand,
|
|
5
|
+
S3Client,
|
|
6
|
+
S3ClientConfig,
|
|
7
|
+
} from "@aws-sdk/client-s3";
|
|
8
|
+
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
|
|
9
|
+
import fs from "fs/promises";
|
|
10
|
+
import path from "path";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* 파일 저장소의 공통 인터페이스
|
|
14
|
+
*/
|
|
15
|
+
export interface Driver {
|
|
16
|
+
put(
|
|
17
|
+
key: string,
|
|
18
|
+
contents: Buffer,
|
|
19
|
+
options?: { contentType?: string; visibility?: "public" | "private" }
|
|
20
|
+
): Promise<void>;
|
|
21
|
+
|
|
22
|
+
del(key: string): Promise<void>;
|
|
23
|
+
|
|
24
|
+
getUrl(key: string): string;
|
|
25
|
+
|
|
26
|
+
getSignedUrl(key: string, expiresIn?: number): Promise<string>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export type FSDriverConfig = {
|
|
30
|
+
location: string;
|
|
31
|
+
urlPrefix: string;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* 로컬 파일시스템
|
|
36
|
+
*/
|
|
37
|
+
export class FSDriver implements Driver {
|
|
38
|
+
constructor(private config: FSDriverConfig) {}
|
|
39
|
+
|
|
40
|
+
async put(key: string, contents: Buffer): Promise<void> {
|
|
41
|
+
const filePath = path.join(this.config.location, key);
|
|
42
|
+
const dir = path.dirname(filePath);
|
|
43
|
+
|
|
44
|
+
await fs.mkdir(dir, { recursive: true });
|
|
45
|
+
|
|
46
|
+
await fs.writeFile(filePath, contents);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async del(key: string) {
|
|
50
|
+
await fs.rm(path.join(this.config.location, key));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
getUrl(key: string): string {
|
|
54
|
+
return `${this.config.urlPrefix}/${key}`;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// 로컬 파일시스템은 signed URL을 지원하지 않으므로 일반 URL 반환
|
|
58
|
+
async getSignedUrl(key: string, _expiresIn?: number): Promise<string> {
|
|
59
|
+
return this.getUrl(key);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export type S3DriverConfig = S3ClientConfig & {
|
|
64
|
+
bucket: string;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export class S3Driver implements Driver {
|
|
68
|
+
s3: S3Client;
|
|
69
|
+
|
|
70
|
+
constructor(private config: S3DriverConfig) {
|
|
71
|
+
this.s3 = new S3Client(config);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async put(
|
|
75
|
+
key: string,
|
|
76
|
+
contents: Buffer,
|
|
77
|
+
options?: { contentType?: string; visibility?: "public" | "private" }
|
|
78
|
+
): Promise<void> {
|
|
79
|
+
await this.s3.send(
|
|
80
|
+
new PutObjectCommand({
|
|
81
|
+
Bucket: this.config.bucket,
|
|
82
|
+
Key: key,
|
|
83
|
+
Body: contents,
|
|
84
|
+
ContentType: options?.contentType,
|
|
85
|
+
ACL: this.getAcl(options?.visibility),
|
|
86
|
+
})
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async del(key: string): Promise<void> {
|
|
91
|
+
await this.s3.send(
|
|
92
|
+
new DeleteObjectCommand({
|
|
93
|
+
Bucket: this.config.bucket,
|
|
94
|
+
Key: key,
|
|
95
|
+
})
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
getUrl(key: string): string {
|
|
100
|
+
return `https://${this.config.bucket}.s3.${this.config.region}.amazonaws.com/${key}`;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async getSignedUrl(key: string, expiresIn?: number): Promise<string> {
|
|
104
|
+
const command = new GetObjectCommand({
|
|
105
|
+
Bucket: this.config.bucket,
|
|
106
|
+
Key: key,
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
return getSignedUrl(this.s3, command, {
|
|
110
|
+
expiresIn: expiresIn ?? 60 * 60 * 24 * 7,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
private getAcl(visibility?: "public" | "private") {
|
|
115
|
+
if (visibility === "public") {
|
|
116
|
+
return "public-read";
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return visibility;
|
|
120
|
+
}
|
|
121
|
+
}
|