sonamu 0.4.14 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (385) hide show
  1. package/.swcrc +15 -0
  2. package/dist/api/base-frame.d.ts +8 -0
  3. package/dist/api/base-frame.d.ts.map +1 -0
  4. package/dist/api/base-frame.js +2 -0
  5. package/dist/api/base-frame.js.map +1 -0
  6. package/dist/api/caster.d.ts +5 -0
  7. package/dist/api/caster.d.ts.map +1 -0
  8. package/dist/api/caster.js +2 -0
  9. package/dist/api/caster.js.map +1 -0
  10. package/dist/api/code-converters.d.ts +23 -0
  11. package/dist/api/code-converters.d.ts.map +1 -0
  12. package/dist/api/code-converters.js +2 -0
  13. package/dist/api/code-converters.js.map +1 -0
  14. package/dist/api/context.d.ts +19 -0
  15. package/dist/api/context.d.ts.map +1 -0
  16. package/dist/api/context.js +2 -0
  17. package/dist/api/context.js.map +1 -0
  18. package/dist/api/decorators.d.ts +50 -0
  19. package/dist/api/decorators.d.ts.map +1 -0
  20. package/dist/api/decorators.js +2 -0
  21. package/dist/api/decorators.js.map +1 -0
  22. package/dist/api/index.d.ts +8 -0
  23. package/dist/api/index.d.ts.map +1 -0
  24. package/dist/api/index.js +2 -0
  25. package/dist/api/index.js.map +1 -0
  26. package/dist/api/sonamu.d.ts +84 -0
  27. package/dist/api/sonamu.d.ts.map +1 -0
  28. package/dist/api/sonamu.js +2 -0
  29. package/dist/api/sonamu.js.map +1 -0
  30. package/dist/bin/build-config.d.ts +9 -0
  31. package/dist/bin/build-config.d.ts.map +1 -0
  32. package/dist/bin/build-config.js +2 -0
  33. package/dist/bin/build-config.js.map +1 -0
  34. package/dist/bin/cli-wrapper.d.ts +2 -0
  35. package/dist/bin/cli-wrapper.d.ts.map +1 -0
  36. package/dist/bin/cli-wrapper.js +1 -38
  37. package/dist/bin/cli-wrapper.js.map +1 -1
  38. package/dist/bin/cli.d.ts +2 -2
  39. package/dist/bin/cli.d.ts.map +1 -0
  40. package/dist/bin/cli.js +1 -903
  41. package/dist/bin/cli.js.map +1 -1
  42. package/dist/database/_batch_update.d.ts +15 -0
  43. package/dist/database/_batch_update.d.ts.map +1 -0
  44. package/dist/database/_batch_update.js +2 -0
  45. package/dist/database/_batch_update.js.map +1 -0
  46. package/dist/database/base-model.d.ts +48 -0
  47. package/dist/database/base-model.d.ts.map +1 -0
  48. package/dist/database/base-model.js +2 -0
  49. package/dist/database/base-model.js.map +1 -0
  50. package/dist/database/code-generator.d.ts +13 -0
  51. package/dist/database/code-generator.d.ts.map +1 -0
  52. package/dist/database/code-generator.js +2 -0
  53. package/dist/database/code-generator.js.map +1 -0
  54. package/dist/database/db.d.ts +40 -0
  55. package/dist/database/db.d.ts.map +1 -0
  56. package/dist/database/db.js +2 -0
  57. package/dist/database/db.js.map +1 -0
  58. package/dist/database/knex-plugins/knex-on-duplicate-update.d.ts +2 -0
  59. package/dist/database/knex-plugins/knex-on-duplicate-update.d.ts.map +1 -0
  60. package/dist/database/knex-plugins/knex-on-duplicate-update.js +2 -0
  61. package/dist/database/knex-plugins/knex-on-duplicate-update.js.map +1 -0
  62. package/dist/database/puri-wrapper.d.ts +34 -0
  63. package/dist/database/puri-wrapper.d.ts.map +1 -0
  64. package/dist/database/puri-wrapper.js +2 -0
  65. package/dist/database/puri-wrapper.js.map +1 -0
  66. package/dist/database/puri.d.ts +83 -0
  67. package/dist/database/puri.d.ts.map +1 -0
  68. package/dist/database/puri.js +2 -0
  69. package/dist/database/puri.js.map +1 -0
  70. package/dist/database/puri.types.d.ts +60 -0
  71. package/dist/database/puri.types.d.ts.map +1 -0
  72. package/dist/database/puri.types.js +2 -0
  73. package/dist/database/puri.types.js.map +1 -0
  74. package/dist/database/transaction-context.d.ts +9 -0
  75. package/dist/database/transaction-context.d.ts.map +1 -0
  76. package/dist/database/transaction-context.js +2 -0
  77. package/dist/database/transaction-context.js.map +1 -0
  78. package/dist/database/upsert-builder.d.ts +34 -0
  79. package/dist/database/upsert-builder.d.ts.map +1 -0
  80. package/dist/database/upsert-builder.js +2 -0
  81. package/dist/database/upsert-builder.js.map +1 -0
  82. package/dist/entity/entity-manager.d.ts +32 -0
  83. package/dist/entity/entity-manager.d.ts.map +1 -0
  84. package/dist/entity/entity-manager.js +2 -0
  85. package/dist/entity/entity-manager.js.map +1 -0
  86. package/dist/entity/entity-utils.d.ts +61 -0
  87. package/dist/entity/entity-utils.d.ts.map +1 -0
  88. package/dist/entity/entity-utils.js +2 -0
  89. package/dist/entity/entity-utils.js.map +1 -0
  90. package/dist/entity/entity.d.ts +62 -0
  91. package/dist/entity/entity.d.ts.map +1 -0
  92. package/dist/entity/entity.js +2 -0
  93. package/dist/entity/entity.js.map +1 -0
  94. package/dist/entity/migrator.d.ts +135 -0
  95. package/dist/entity/migrator.d.ts.map +1 -0
  96. package/dist/entity/migrator.js +2 -0
  97. package/dist/entity/migrator.js.map +1 -0
  98. package/dist/exceptions/error-handler.d.ts +3 -0
  99. package/dist/exceptions/error-handler.d.ts.map +1 -0
  100. package/dist/exceptions/error-handler.js +2 -0
  101. package/dist/exceptions/error-handler.js.map +1 -0
  102. package/dist/exceptions/so-exceptions.d.ts +48 -0
  103. package/dist/exceptions/so-exceptions.d.ts.map +1 -0
  104. package/dist/exceptions/so-exceptions.js +2 -0
  105. package/dist/exceptions/so-exceptions.js.map +1 -0
  106. package/dist/file-storage/driver.d.ts +48 -0
  107. package/dist/file-storage/driver.d.ts.map +1 -0
  108. package/dist/file-storage/driver.js +2 -0
  109. package/dist/file-storage/driver.js.map +1 -0
  110. package/dist/file-storage/file-storage.d.ts +50 -0
  111. package/dist/file-storage/file-storage.d.ts.map +1 -0
  112. package/dist/file-storage/file-storage.js +2 -0
  113. package/dist/file-storage/file-storage.js.map +1 -0
  114. package/dist/index.d.ts +23 -813
  115. package/dist/index.d.ts.map +1 -0
  116. package/dist/index.js +1 -433
  117. package/dist/index.js.map +1 -1
  118. package/dist/migration/code-generation.d.ts +15 -0
  119. package/dist/migration/code-generation.d.ts.map +1 -0
  120. package/dist/migration/code-generation.js +2 -0
  121. package/dist/migration/code-generation.js.map +1 -0
  122. package/dist/migration/migration-set.d.ts +17 -0
  123. package/dist/migration/migration-set.d.ts.map +1 -0
  124. package/dist/migration/migration-set.js +2 -0
  125. package/dist/migration/migration-set.js.map +1 -0
  126. package/dist/migration/migrator.d.ts +130 -0
  127. package/dist/migration/migrator.d.ts.map +1 -0
  128. package/dist/migration/migrator.js +2 -0
  129. package/dist/migration/migrator.js.map +1 -0
  130. package/dist/migration/types.d.ts +52 -0
  131. package/dist/migration/types.d.ts.map +1 -0
  132. package/dist/migration/types.js +2 -0
  133. package/dist/migration/types.js.map +1 -0
  134. package/dist/stream/index.d.ts +2 -0
  135. package/dist/stream/index.d.ts.map +1 -0
  136. package/dist/stream/index.js +2 -0
  137. package/dist/stream/index.js.map +1 -0
  138. package/dist/stream/sse.d.ts +13 -0
  139. package/dist/stream/sse.d.ts.map +1 -0
  140. package/dist/stream/sse.js +2 -0
  141. package/dist/stream/sse.js.map +1 -0
  142. package/dist/syncer/index.d.ts +2 -0
  143. package/dist/syncer/index.d.ts.map +1 -0
  144. package/dist/syncer/index.js +2 -0
  145. package/dist/syncer/index.js.map +1 -0
  146. package/dist/syncer/syncer.d.ts +127 -0
  147. package/dist/syncer/syncer.d.ts.map +1 -0
  148. package/dist/syncer/syncer.js +2 -0
  149. package/dist/syncer/syncer.js.map +1 -0
  150. package/dist/templates/base-template.d.ts +13 -0
  151. package/dist/templates/base-template.d.ts.map +1 -0
  152. package/dist/templates/base-template.js +2 -0
  153. package/dist/templates/base-template.js.map +1 -0
  154. package/dist/templates/entity.template.d.ts +17 -0
  155. package/dist/templates/entity.template.d.ts.map +1 -0
  156. package/dist/templates/entity.template.js +2 -0
  157. package/dist/templates/entity.template.js.map +1 -0
  158. package/dist/templates/generated.template.d.ts +27 -0
  159. package/dist/templates/generated.template.d.ts.map +1 -0
  160. package/dist/templates/generated.template.js +2 -0
  161. package/dist/templates/generated.template.js.map +1 -0
  162. package/dist/templates/generated_http.template.d.ts +24 -0
  163. package/dist/templates/generated_http.template.d.ts.map +1 -0
  164. package/dist/templates/generated_http.template.js +2 -0
  165. package/dist/templates/generated_http.template.js.map +1 -0
  166. package/dist/templates/generated_sso.template.d.ts +20 -0
  167. package/dist/templates/generated_sso.template.d.ts.map +1 -0
  168. package/dist/templates/generated_sso.template.js +2 -0
  169. package/dist/templates/generated_sso.template.js.map +1 -0
  170. package/dist/templates/index.d.ts +2 -0
  171. package/dist/templates/index.d.ts.map +1 -0
  172. package/dist/templates/index.js +2 -0
  173. package/dist/templates/index.js.map +1 -0
  174. package/dist/templates/init_types.template.d.ts +17 -0
  175. package/dist/templates/init_types.template.d.ts.map +1 -0
  176. package/dist/templates/init_types.template.js +2 -0
  177. package/dist/templates/init_types.template.js.map +1 -0
  178. package/dist/templates/model.template.d.ts +17 -0
  179. package/dist/templates/model.template.d.ts.map +1 -0
  180. package/dist/templates/model.template.js +2 -0
  181. package/dist/templates/model.template.js.map +1 -0
  182. package/dist/templates/model_test.template.d.ts +17 -0
  183. package/dist/templates/model_test.template.d.ts.map +1 -0
  184. package/dist/templates/model_test.template.js +2 -0
  185. package/dist/templates/model_test.template.js.map +1 -0
  186. package/dist/templates/service.template.d.ts +29 -0
  187. package/dist/templates/service.template.d.ts.map +1 -0
  188. package/dist/templates/service.template.js +2 -0
  189. package/dist/templates/service.template.js.map +1 -0
  190. package/dist/templates/view_enums_buttonset.template.d.ts +17 -0
  191. package/dist/templates/view_enums_buttonset.template.d.ts.map +1 -0
  192. package/dist/templates/view_enums_buttonset.template.js +2 -0
  193. package/dist/templates/view_enums_buttonset.template.js.map +1 -0
  194. package/dist/templates/view_enums_dropdown.template.d.ts +18 -0
  195. package/dist/templates/view_enums_dropdown.template.d.ts.map +1 -0
  196. package/dist/templates/view_enums_dropdown.template.js +2 -0
  197. package/dist/templates/view_enums_dropdown.template.js.map +1 -0
  198. package/dist/templates/view_enums_select.template.d.ts +17 -0
  199. package/dist/templates/view_enums_select.template.d.ts.map +1 -0
  200. package/dist/templates/view_enums_select.template.js +2 -0
  201. package/dist/templates/view_enums_select.template.js.map +1 -0
  202. package/dist/templates/view_form.template.d.ts +26 -0
  203. package/dist/templates/view_form.template.d.ts.map +1 -0
  204. package/dist/templates/view_form.template.js +2 -0
  205. package/dist/templates/view_form.template.js.map +1 -0
  206. package/dist/templates/view_id_all_select.template.d.ts +17 -0
  207. package/dist/templates/view_id_all_select.template.d.ts.map +1 -0
  208. package/dist/templates/view_id_all_select.template.js +2 -0
  209. package/dist/templates/view_id_all_select.template.js.map +1 -0
  210. package/dist/templates/view_id_async_select.template.d.ts +17 -0
  211. package/dist/templates/view_id_async_select.template.d.ts.map +1 -0
  212. package/dist/templates/view_id_async_select.template.js +2 -0
  213. package/dist/templates/view_id_async_select.template.js.map +1 -0
  214. package/dist/templates/view_list.template.d.ts +38 -0
  215. package/dist/templates/view_list.template.d.ts.map +1 -0
  216. package/dist/templates/view_list.template.js +2 -0
  217. package/dist/templates/view_list.template.js.map +1 -0
  218. package/dist/templates/view_list_columns.template.d.ts +17 -0
  219. package/dist/templates/view_list_columns.template.d.ts.map +1 -0
  220. package/dist/templates/view_list_columns.template.js +2 -0
  221. package/dist/templates/view_list_columns.template.js.map +1 -0
  222. package/dist/templates/view_search_input.template.d.ts +17 -0
  223. package/dist/templates/view_search_input.template.d.ts.map +1 -0
  224. package/dist/templates/view_search_input.template.js +2 -0
  225. package/dist/templates/view_search_input.template.js.map +1 -0
  226. package/dist/testing/_relation-graph.d.ts +7 -0
  227. package/dist/testing/_relation-graph.d.ts.map +1 -0
  228. package/dist/testing/_relation-graph.js +2 -0
  229. package/dist/testing/_relation-graph.js.map +1 -0
  230. package/dist/testing/fixture-manager.d.ts +35 -0
  231. package/dist/testing/fixture-manager.d.ts.map +1 -0
  232. package/dist/testing/fixture-manager.js +2 -0
  233. package/dist/testing/fixture-manager.js.map +1 -0
  234. package/dist/types/types.d.ts +611 -0
  235. package/dist/types/types.d.ts.map +1 -0
  236. package/dist/types/types.js +2 -0
  237. package/dist/types/types.js.map +1 -0
  238. package/dist/typings/knex.d.js +2 -0
  239. package/dist/typings/knex.d.js.map +1 -0
  240. package/dist/utils/async-utils.d.ts +25 -0
  241. package/dist/utils/async-utils.d.ts.map +1 -0
  242. package/dist/utils/async-utils.js +2 -0
  243. package/dist/utils/async-utils.js.map +1 -0
  244. package/dist/utils/controller.d.ts +9 -0
  245. package/dist/utils/controller.d.ts.map +1 -0
  246. package/dist/utils/controller.js +2 -0
  247. package/dist/utils/controller.js.map +1 -0
  248. package/dist/utils/fs-utils.d.ts +9 -0
  249. package/dist/utils/fs-utils.d.ts.map +1 -0
  250. package/dist/utils/fs-utils.js +2 -0
  251. package/dist/utils/fs-utils.js.map +1 -0
  252. package/dist/utils/lodash-able.d.ts +2 -0
  253. package/dist/utils/lodash-able.d.ts.map +1 -0
  254. package/dist/utils/lodash-able.js +2 -0
  255. package/dist/utils/lodash-able.js.map +1 -0
  256. package/dist/utils/model.d.ts +17 -0
  257. package/dist/utils/model.d.ts.map +1 -0
  258. package/dist/utils/model.js +2 -0
  259. package/dist/utils/model.js.map +1 -0
  260. package/dist/utils/sql-parser.d.ts +4 -0
  261. package/dist/utils/sql-parser.d.ts.map +1 -0
  262. package/dist/utils/sql-parser.js +2 -0
  263. package/dist/utils/sql-parser.js.map +1 -0
  264. package/dist/utils/utils.d.ts +9 -0
  265. package/dist/utils/utils.d.ts.map +1 -0
  266. package/dist/utils/utils.js +2 -0
  267. package/dist/utils/utils.js.map +1 -0
  268. package/dist/utils/zod-error.d.ts +8 -0
  269. package/dist/utils/zod-error.d.ts.map +1 -0
  270. package/dist/utils/zod-error.js +2 -0
  271. package/dist/utils/zod-error.js.map +1 -0
  272. package/nodemon.json +6 -0
  273. package/package.json +32 -45
  274. package/src/api/base-frame.ts +3 -4
  275. package/src/api/caster.ts +22 -23
  276. package/src/api/code-converters.ts +170 -134
  277. package/src/api/context.ts +15 -3
  278. package/src/api/decorators.ts +144 -20
  279. package/src/api/index.ts +2 -0
  280. package/src/api/sonamu.ts +408 -165
  281. package/src/bin/build-config.ts +10 -0
  282. package/src/bin/cli-wrapper.ts +35 -32
  283. package/src/bin/cli.ts +141 -204
  284. package/src/database/_batch_update.ts +10 -15
  285. package/src/database/base-model.ts +326 -216
  286. package/src/database/db.ts +191 -21
  287. package/src/database/{drivers/knex/plugins → knex-plugins}/knex-on-duplicate-update.ts +1 -1
  288. package/src/database/puri-wrapper.ts +129 -0
  289. package/src/database/puri.ts +808 -0
  290. package/src/database/puri.types.ts +222 -0
  291. package/src/database/transaction-context.ts +18 -0
  292. package/src/database/upsert-builder.ts +32 -35
  293. package/src/entity/entity-manager.ts +7 -15
  294. package/src/entity/entity.ts +9 -31
  295. package/src/entity/migrator-/354/235/264/354/202/254/352/260/224/354/226/264/354/232/224.md +1 -0
  296. package/src/file-storage/driver.ts +131 -0
  297. package/src/file-storage/file-storage.ts +100 -0
  298. package/src/index.ts +15 -11
  299. package/src/migration/code-generation.ts +777 -0
  300. package/src/migration/migration-set.ts +453 -0
  301. package/src/migration/migrator.ts +823 -0
  302. package/src/migration/types.ts +53 -0
  303. package/src/shared/web.shared.ts.txt +33 -2
  304. package/src/stream/index.ts +1 -0
  305. package/src/stream/sse.ts +49 -0
  306. package/src/syncer/syncer.ts +294 -127
  307. package/src/templates/generated.template.ts +13 -1
  308. package/src/templates/generated_http.template.ts +15 -12
  309. package/src/templates/generated_sso.template.ts +50 -2
  310. package/src/templates/model.template.ts +138 -2
  311. package/src/templates/service.template.ts +0 -1
  312. package/src/templates/view_form.template.ts +11 -7
  313. package/src/templates/view_list.template.ts +12 -4
  314. package/src/testing/fixture-manager.ts +229 -174
  315. package/src/types/types.ts +108 -14
  316. package/src/utils/async-utils.ts +64 -0
  317. package/src/utils/fs-utils.ts +17 -0
  318. package/src/utils/model.ts +0 -2
  319. package/src/utils/utils.ts +14 -58
  320. package/src/utils/zod-error.ts +12 -176
  321. package/tsconfig.json +6 -0
  322. package/tsup.config.js +4 -2
  323. package/.pnp.cjs +0 -14363
  324. package/.pnp.loader.mjs +0 -2047
  325. package/.vscode/extensions.json +0 -6
  326. package/.vscode/settings.json +0 -9
  327. package/.yarnrc.yml +0 -5
  328. package/dist/base-model-CEB0H0aO.d.mts +0 -43
  329. package/dist/base-model-CrqDMYhI.d.ts +0 -43
  330. package/dist/bin/cli-wrapper.d.mts +0 -1
  331. package/dist/bin/cli-wrapper.mjs +0 -43
  332. package/dist/bin/cli-wrapper.mjs.map +0 -1
  333. package/dist/bin/cli.d.mts +0 -2
  334. package/dist/bin/cli.mjs +0 -907
  335. package/dist/bin/cli.mjs.map +0 -1
  336. package/dist/chunk-2WAC2GER.js +0 -7625
  337. package/dist/chunk-2WAC2GER.js.map +0 -1
  338. package/dist/chunk-C3IPIF6O.mjs +0 -1581
  339. package/dist/chunk-C3IPIF6O.mjs.map +0 -1
  340. package/dist/chunk-EXHKSVTE.js +0 -280
  341. package/dist/chunk-EXHKSVTE.js.map +0 -1
  342. package/dist/chunk-FCERKIIF.mjs +0 -7623
  343. package/dist/chunk-FCERKIIF.mjs.map +0 -1
  344. package/dist/chunk-HGIBJYOU.mjs +0 -231
  345. package/dist/chunk-HGIBJYOU.mjs.map +0 -1
  346. package/dist/chunk-JKSOJRQA.mjs +0 -280
  347. package/dist/chunk-JKSOJRQA.mjs.map +0 -1
  348. package/dist/chunk-OTKKFP3Y.js +0 -1581
  349. package/dist/chunk-OTKKFP3Y.js.map +0 -1
  350. package/dist/chunk-PTFDTOJU.mjs +0 -19
  351. package/dist/chunk-PTFDTOJU.mjs.map +0 -1
  352. package/dist/chunk-UZ2IY5VE.js +0 -231
  353. package/dist/chunk-UZ2IY5VE.js.map +0 -1
  354. package/dist/database/drivers/knex/base-model.d.mts +0 -16
  355. package/dist/database/drivers/knex/base-model.d.ts +0 -16
  356. package/dist/database/drivers/knex/base-model.js +0 -55
  357. package/dist/database/drivers/knex/base-model.js.map +0 -1
  358. package/dist/database/drivers/knex/base-model.mjs +0 -56
  359. package/dist/database/drivers/knex/base-model.mjs.map +0 -1
  360. package/dist/database/drivers/kysely/base-model.d.mts +0 -22
  361. package/dist/database/drivers/kysely/base-model.d.ts +0 -22
  362. package/dist/database/drivers/kysely/base-model.js +0 -64
  363. package/dist/database/drivers/kysely/base-model.js.map +0 -1
  364. package/dist/database/drivers/kysely/base-model.mjs +0 -65
  365. package/dist/database/drivers/kysely/base-model.mjs.map +0 -1
  366. package/dist/index.d.mts +0 -813
  367. package/dist/index.mjs +0 -435
  368. package/dist/index.mjs.map +0 -1
  369. package/dist/model-aFgomcdc.d.mts +0 -1112
  370. package/dist/model-aFgomcdc.d.ts +0 -1112
  371. package/src/database/base-model.abstract.ts +0 -97
  372. package/src/database/db.abstract.ts +0 -75
  373. package/src/database/drivers/knex/base-model.ts +0 -55
  374. package/src/database/drivers/knex/client.ts +0 -209
  375. package/src/database/drivers/knex/db.ts +0 -232
  376. package/src/database/drivers/knex/generator.ts +0 -659
  377. package/src/database/drivers/kysely/base-model.ts +0 -89
  378. package/src/database/drivers/kysely/client.ts +0 -309
  379. package/src/database/drivers/kysely/db.ts +0 -238
  380. package/src/database/drivers/kysely/generator.ts +0 -714
  381. package/src/database/types.ts +0 -118
  382. package/src/entity/migrator.ts +0 -1400
  383. package/src/smd/smd-manager.ts +0 -139
  384. package/src/smd/smd.ts +0 -571
  385. package/src/templates/kysely_types.template.ts +0 -205
@@ -1,28 +1,216 @@
1
- // base-model.ts
2
1
  import { DateTime } from "luxon";
3
- import _ from "lodash";
4
- import SqlParser from "node-sql-parser";
5
- import chalk from "chalk";
2
+ import { Knex } from "knex";
3
+ import { chunk, groupBy, isObject, omit, set, uniq } from "lodash";
4
+ import { DBPreset, DB } from "./db";
5
+ import { isCustomJoinClause, type SubsetQuery } from "../types/types";
6
+ import type { BaseListParams } from "../utils/model";
6
7
  import inflection from "inflection";
7
- import { BaseListParams } from "../utils/model";
8
- import { DBPreset, DriverSpec, DatabaseDriver } from "./types";
9
- import { SubsetQuery } from "../types/types";
8
+ import chalk from "chalk";
9
+ import { UpsertBuilder } from "./upsert-builder";
10
+ import SqlParser from "node-sql-parser";
10
11
  import { getTableName, getTableNamesFromWhere } from "../utils/sql-parser";
11
- import { DB } from "./db";
12
+ import { PuriWrapper } from "./puri-wrapper";
12
13
 
13
- export abstract class BaseModelClassAbstract<D extends DatabaseDriver> {
14
+ export class BaseModelClass {
14
15
  public modelName: string = "Unknown";
15
16
 
16
- protected abstract applyJoins(
17
- qb: DriverSpec[D]["adapter"],
18
- joins: SubsetQuery["joins"]
19
- ): DriverSpec[D]["adapter"];
20
- protected abstract executeCountQuery(
21
- qb: DriverSpec[D]["queryBuilder"]
22
- ): Promise<number>;
17
+ /* DB 인스턴스 get, destroy */
18
+ getDB(which: DBPreset): Knex {
19
+ return DB.getDB(which);
20
+ }
21
+
22
+ getPuri(which: DBPreset): PuriWrapper {
23
+ // 트랜잭션 컨텍스트에서 트랜잭션 획득
24
+ const trx = DB.getTransactionContext().getTransaction(which);
25
+ if (trx) {
26
+ return trx;
27
+ }
28
+
29
+ // 트랜잭션이 없으면 새로운 PuriWrapper 반환
30
+ const db = this.getDB(which);
31
+ return new PuriWrapper(db, this.getUpsertBuilder());
32
+ }
33
+
34
+ async destroy() {
35
+ return DB.destroy();
36
+ }
37
+
38
+ myNow(timestamp?: number): string {
39
+ const dt: DateTime =
40
+ timestamp === undefined
41
+ ? DateTime.local()
42
+ : DateTime.fromSeconds(timestamp);
43
+ return dt.toFormat("yyyy-MM-dd HH:mm:ss");
44
+ }
45
+
46
+ async getInsertedIds(
47
+ wdb: Knex,
48
+ rows: any[],
49
+ tableName: string,
50
+ unqKeyFields: string[],
51
+ chunkSize: number = 500
52
+ ) {
53
+ if (!wdb) {
54
+ wdb = this.getDB("w");
55
+ }
56
+
57
+ let unqKeys: string[];
58
+ let whereInField: any, selectField: string;
59
+ if (unqKeyFields.length > 1) {
60
+ whereInField = wdb.raw(`CONCAT_WS('_', '${unqKeyFields.join(",")}')`);
61
+ selectField = `${whereInField} as tmpUid`;
62
+ unqKeys = rows.map((row) =>
63
+ unqKeyFields.map((field) => row[field]).join("_")
64
+ );
65
+ } else {
66
+ whereInField = unqKeyFields[0];
67
+ selectField = unqKeyFields[0];
68
+ unqKeys = rows.map((row) => row[unqKeyFields[0]]);
69
+ }
70
+ const chunks = chunk(unqKeys, chunkSize);
71
+
72
+ let resultIds: number[] = [];
73
+ for (let chunk of chunks) {
74
+ const dbRows = await wdb(tableName)
75
+ .select("id", wdb.raw(selectField))
76
+ .whereIn(whereInField, chunk);
77
+ resultIds = resultIds.concat(
78
+ dbRows.map((dbRow: any) => parseInt(dbRow.id))
79
+ );
80
+ }
81
+
82
+ return resultIds;
83
+ }
84
+
85
+ async useLoaders(db: Knex, rows: any[], loaders: SubsetQuery["loaders"]) {
86
+ if (loaders.length === 0) {
87
+ return rows;
88
+ }
89
+
90
+ for (let loader of loaders) {
91
+ let subQ: any;
92
+ let subRows: any[];
93
+ let toCol: string;
94
+
95
+ const fromIds = rows.map((row) => row[loader.manyJoin.idField]);
96
+
97
+ if (loader.manyJoin.through === undefined) {
98
+ // HasMany
99
+ const idColumn = `${loader.manyJoin.toTable}.${loader.manyJoin.toCol}`;
100
+ subQ = db(loader.manyJoin.toTable)
101
+ .whereIn(idColumn, fromIds)
102
+ .select([...loader.select, idColumn]);
103
+
104
+ // HasMany에서 OneJoin이 있는 경우
105
+ loader.oneJoins.map((join) => {
106
+ if (join.join == "inner") {
107
+ subQ.innerJoin(
108
+ `${join.table} as ${join.as}`,
109
+ this.getJoinClause(db, join)
110
+ );
111
+ } else if (join.join == "outer") {
112
+ subQ.leftOuterJoin(
113
+ `${join.table} as ${join.as}`,
114
+ this.getJoinClause(db, join)
115
+ );
116
+ }
117
+ });
118
+ toCol = loader.manyJoin.toCol;
119
+ } else {
120
+ // ManyToMany
121
+ const idColumn = `${loader.manyJoin.through.table}.${loader.manyJoin.through.fromCol}`;
122
+ subQ = db(loader.manyJoin.through.table)
123
+ .join(
124
+ loader.manyJoin.toTable,
125
+ `${loader.manyJoin.through.table}.${loader.manyJoin.through.toCol}`,
126
+ `${loader.manyJoin.toTable}.${loader.manyJoin.toCol}`
127
+ )
128
+ .whereIn(idColumn, fromIds)
129
+ .select(uniq([...loader.select, idColumn]));
130
+
131
+ // ManyToMany에서 OneJoin이 있는 경우
132
+ loader.oneJoins.map((join) => {
133
+ if (join.join == "inner") {
134
+ subQ.innerJoin(
135
+ `${join.table} as ${join.as}`,
136
+ this.getJoinClause(db, join)
137
+ );
138
+ } else if (join.join == "outer") {
139
+ subQ.leftOuterJoin(
140
+ `${join.table} as ${join.as}`,
141
+ this.getJoinClause(db, join)
142
+ );
143
+ }
144
+ });
145
+ toCol = loader.manyJoin.through.fromCol;
146
+ }
147
+ subRows = await subQ;
148
+
149
+ if (loader.loaders) {
150
+ // 추가 -Many 케이스가 있는 경우 recursion 처리
151
+ subRows = await this.useLoaders(db, subRows, loader.loaders);
152
+ }
153
+
154
+ // 불러온 row들을 참조ID 기준으로 분류 배치
155
+ const subRowGroups = groupBy(subRows, toCol);
156
+ rows = rows.map((row) => {
157
+ row[loader.as] = (subRowGroups[row[loader.manyJoin.idField]] ?? []).map(
158
+ (r) => omit(r, toCol)
159
+ );
160
+ return row;
161
+ });
162
+ }
163
+ return rows;
164
+ }
23
165
 
24
- abstract getDB(which: DBPreset): DriverSpec[D]["core"];
25
- abstract destroy(): Promise<void>;
166
+ hydrate<T>(rows: T[]): T[] {
167
+ return rows.map((row: any) => {
168
+ // nullable relation인 경우 관련된 필드가 전부 null로 생성되는 것 방지하는 코드
169
+ const nestedKeys = Object.keys(row).filter((key) => key.includes("__"));
170
+ const groups = groupBy(nestedKeys, (key) => key.split("__")[0]);
171
+ const nullKeys = Object.keys(groups).filter(
172
+ (key) =>
173
+ groups[key].length > 1 &&
174
+ groups[key].every(
175
+ (field) =>
176
+ row[field] === null ||
177
+ (Array.isArray(row[field]) && row[field].length === 0)
178
+ )
179
+ );
180
+
181
+ const hydrated = Object.keys(row).reduce((r, field) => {
182
+ if (!field.includes("__")) {
183
+ if (Array.isArray(row[field]) && isObject(row[field][0])) {
184
+ r[field] = this.hydrate(row[field]);
185
+ return r;
186
+ } else {
187
+ r[field] = row[field];
188
+ return r;
189
+ }
190
+ }
191
+
192
+ const parts = field.split("__");
193
+ const objPath =
194
+ parts[0] +
195
+ parts
196
+ .slice(1)
197
+ .map((part) => `[${part}]`)
198
+ .join("");
199
+ set(
200
+ r,
201
+ objPath,
202
+ row[field] && Array.isArray(row[field]) && isObject(row[field][0])
203
+ ? this.hydrate(row[field])
204
+ : row[field]
205
+ );
206
+
207
+ return r;
208
+ }, {} as any);
209
+ nullKeys.map((nullKey) => (hydrated[nullKey] = null));
210
+
211
+ return hydrated;
212
+ });
213
+ }
26
214
 
27
215
  async runSubsetQuery<T extends BaseListParams, U extends string>({
28
216
  params,
@@ -30,6 +218,7 @@ export abstract class BaseModelClassAbstract<D extends DatabaseDriver> {
30
218
  subset,
31
219
  subsetQuery,
32
220
  build,
221
+ afterBuild,
33
222
  debug,
34
223
  db: _db,
35
224
  optimizeCountQuery,
@@ -38,265 +227,186 @@ export abstract class BaseModelClassAbstract<D extends DatabaseDriver> {
38
227
  params: T;
39
228
  subsetQuery: SubsetQuery;
40
229
  build: (buildParams: {
41
- qb: DriverSpec[D]["queryBuilder"];
42
- db: DriverSpec[D]["core"];
43
- select: SubsetQuery["select"];
230
+ qb: Knex.QueryBuilder;
231
+ db: Knex;
232
+ select: (string | Knex.Raw)[];
44
233
  joins: SubsetQuery["joins"];
45
234
  virtual: string[];
46
- }) => DriverSpec[D]["queryBuilder"];
47
- baseTable?: DriverSpec[D]["table"];
235
+ }) => Knex.QueryBuilder;
236
+ afterBuild?: (buildParams: {
237
+ qb: Knex.QueryBuilder;
238
+ db: Knex;
239
+ select: (string | Knex.Raw)[];
240
+ joins: SubsetQuery["joins"];
241
+ virtual: string[];
242
+ }) => Knex.QueryBuilder;
243
+ baseTable?: string;
48
244
  debug?: boolean | "list" | "count";
49
- db?: DriverSpec[D]["core"];
245
+ db?: Knex;
50
246
  optimizeCountQuery?: boolean;
51
247
  }): Promise<{
52
248
  rows: any[];
53
- total?: number;
249
+ total?: number | undefined;
54
250
  subsetQuery: SubsetQuery;
55
- qb: DriverSpec[D]["queryBuilder"];
251
+ qb: Knex.QueryBuilder;
56
252
  }> {
57
- const db = _db ?? DB.getDB(subset.startsWith("A") ? "w" : "r");
58
- const dbClient = DB.toClient(db);
253
+ const db = _db ?? this.getDB(subset.startsWith("A") ? "w" : "r");
59
254
  baseTable =
60
255
  baseTable ?? inflection.pluralize(inflection.underscore(this.modelName));
61
256
  const queryMode =
62
257
  params.queryMode ?? (params.id !== undefined ? "list" : "both");
63
258
 
64
259
  const { select, virtual, joins, loaders } = subsetQuery;
65
- const _qb = build({
66
- qb: dbClient.from(baseTable).qb,
260
+ const qb = build({
261
+ qb: db.from(baseTable),
67
262
  db,
68
263
  select,
69
264
  joins,
70
265
  virtual,
71
266
  });
72
- dbClient.qb = _qb;
73
- const qb = dbClient;
74
267
 
268
+ const applyJoinClause = (
269
+ qb: Knex.QueryBuilder,
270
+ joins: SubsetQuery["joins"]
271
+ ) => {
272
+ joins.map((join) => {
273
+ if (join.join == "inner") {
274
+ qb.innerJoin(
275
+ `${join.table} as ${join.as}`,
276
+ this.getJoinClause(db, join)
277
+ );
278
+ } else if (join.join == "outer") {
279
+ qb.leftOuterJoin(
280
+ `${join.table} as ${join.as}`,
281
+ this.getJoinClause(db, join)
282
+ );
283
+ }
284
+ });
285
+ };
286
+
287
+ // countQuery
75
288
  const total = await (async () => {
76
- if (queryMode === "list") return undefined;
289
+ if (queryMode === "list") {
290
+ return undefined;
291
+ }
77
292
 
78
- const clonedQb = qb
79
- .clone()
80
- .clearQueryParts(["order", "offset", "limit"])
81
- .clearSelect()
82
- .select(`${baseTable}.id`);
293
+ const clonedQb = qb.clone().clear("order").clear("offset").clear("limit");
83
294
  const parser = new SqlParser.Parser();
84
295
 
296
+ // optmizeCountQuery가 true인 경우 다른 clause에 영향을 주지 않는 모든 join을 제외함
85
297
  if (optimizeCountQuery) {
86
- const parsedQuery = parser.astify(clonedQb.sql);
298
+ const parsedQuery = parser.astify(clonedQb.toQuery());
87
299
  const tables = getTableNamesFromWhere(parsedQuery);
88
- const needToJoin = _.uniq(
300
+ // where절에 사용되는 테이블의 조인을 위해 사용되는 테이블
301
+ const needToJoin = uniq(
89
302
  tables.flatMap((table) =>
90
303
  table.split("__").map((t) => inflection.pluralize(t))
91
304
  )
92
305
  );
93
-
94
- this.applyJoins(
306
+ applyJoinClause(
95
307
  clonedQb,
96
308
  joins.filter((j) => needToJoin.includes(j.table))
97
309
  );
98
310
  } else {
99
- this.applyJoins(clonedQb, joins);
311
+ applyJoinClause(clonedQb, joins);
100
312
  }
101
313
 
102
- const parsedQuery = parser.astify(clonedQb.sql);
103
- const q = Array.isArray(parsedQuery) ? parsedQuery[0] : parsedQuery;
314
+ const processedQb =
315
+ afterBuild?.({
316
+ qb: clonedQb,
317
+ db,
318
+ select,
319
+ joins,
320
+ virtual,
321
+ }) ?? clonedQb;
104
322
 
323
+ const parsedQuery = parser.astify(processedQb.toQuery());
324
+ const q = Array.isArray(parsedQuery) ? parsedQuery[0] : parsedQuery;
105
325
  if (q.type !== "select") {
106
326
  throw new Error("Invalid query");
107
327
  }
108
328
 
109
- const countColumn = `${getTableName(q.columns[0].expr)}.${q.columns[0].expr.column}`;
110
- clonedQb.clearSelect().count(countColumn, "total").first();
111
- if (q.distinct) {
112
- clonedQb.distinct(countColumn);
113
- }
114
-
329
+ const countQuery =
330
+ q.distinct !== null
331
+ ? clonedQb
332
+ .clear("select")
333
+ .select(
334
+ db.raw(
335
+ `COUNT(DISTINCT \`${getTableName(q.columns[0].expr)}\`.\`${q.columns[0].expr.column}\`) as total`
336
+ )
337
+ )
338
+ .first()
339
+ : clonedQb.clear("select").count("*", { as: "total" }).first();
340
+ const countRow: { total?: number } = await countQuery;
341
+
342
+ // debug: countQuery
115
343
  if (debug === true || debug === "count") {
116
- console.debug("DEBUG: count query", chalk.blue(clonedQb.sql));
344
+ console.debug(
345
+ "DEBUG: count query",
346
+ chalk.blue(countQuery.toQuery().toString())
347
+ );
117
348
  }
118
349
 
119
- const [{ total }] = await clonedQb.execute();
120
- return total;
350
+ return countRow?.total ?? 0;
121
351
  })();
122
352
 
353
+ // listQuery
123
354
  const rows = await (async () => {
124
- if (queryMode === "count") return [];
125
-
126
- let listQb = qb;
127
- if (params.num !== 0) {
128
- listQb = listQb
129
- .limit(params.num!)
130
- .offset(params.num! * (params.page! - 1));
355
+ if (queryMode === "count") {
356
+ return [];
131
357
  }
132
358
 
133
- listQb.select(select);
134
- listQb = this.applyJoins(listQb, joins);
135
-
136
- if (debug === true || debug === "list") {
137
- console.debug("DEBUG: list query", chalk.blue(listQb.sql));
359
+ // limit, offset
360
+ if (params.num !== 0) {
361
+ qb.limit(params.num!);
362
+ qb.offset(params.num! * (params.page! - 1));
138
363
  }
139
364
 
140
- let rows = await listQb.execute();
141
- rows = await this.useLoaders(dbClient, rows, loaders);
142
- return this.hydrate(rows);
143
- })();
144
-
145
- return {
146
- rows,
147
- total,
148
- subsetQuery,
149
- qb: dbClient.qb,
150
- };
151
- }
152
-
153
- async useLoaders(
154
- db: DriverSpec[D]["adapter"],
155
- rows: any[],
156
- loaders: SubsetQuery["loaders"]
157
- ): Promise<any[]> {
158
- if (loaders.length === 0) return rows;
159
-
160
- for (const loader of loaders) {
161
- const fromIds = rows.map((row) => row[loader.manyJoin.idField]);
365
+ // select, rows
366
+ const clonedQb = qb.clone().select(select);
162
367
 
163
- if (!fromIds.length) continue;
368
+ // join
369
+ applyJoinClause(clonedQb, joins);
164
370
 
165
- let subRows: any[];
166
- let toCol: string;
167
-
168
- if (loader.manyJoin.through === undefined) {
169
- // HasMany
170
- const { subQ, col } = await this.buildHasManyQuery(db, loader, fromIds);
171
- subRows = await subQ.execute();
172
- toCol = col;
173
- } else {
174
- // ManyToMany
175
- const { subQ, col } = await this.buildManyToManyQuery(
371
+ const listQuery =
372
+ afterBuild?.({
373
+ qb: clonedQb,
176
374
  db,
177
- loader,
178
- fromIds
179
- );
180
- subRows = await subQ.execute();
181
- toCol = col;
182
- }
183
-
184
- if (loader.loaders) {
185
- subRows = await this.useLoaders(db, subRows, loader.loaders);
186
- }
375
+ select,
376
+ joins,
377
+ virtual,
378
+ }) ?? clonedQb;
187
379
 
188
- // Group and assign loaded rows
189
- const subRowGroups = _.groupBy(subRows, toCol);
190
- rows = rows.map((row) => {
191
- row[loader.as] = (subRowGroups[row[loader.manyJoin.idField]] ?? []).map(
192
- (r) => _.omit(r, toCol)
380
+ let rows = await listQuery;
381
+ // debug: listQuery
382
+ if (debug === true || debug === "list") {
383
+ console.debug(
384
+ "DEBUG: list query",
385
+ chalk.blue(listQuery.toQuery().toString())
193
386
  );
194
- return row;
195
- });
196
- }
197
-
198
- return rows;
199
- }
200
-
201
- protected async buildHasManyQuery(
202
- db: DriverSpec[D]["adapter"],
203
- loader: SubsetQuery["loaders"][number],
204
- fromIds: any[]
205
- ) {
206
- const idColumn = `${loader.manyJoin.toTable}.${loader.manyJoin.toCol}`;
207
- let qb = db.from(loader.manyJoin.toTable);
208
-
209
- db.where([idColumn, "in", fromIds]).select([...loader.select, idColumn]);
210
- qb = this.applyJoins(qb, loader.oneJoins);
387
+ }
211
388
 
212
- return {
213
- subQ: qb,
214
- col: loader.manyJoin.toCol,
215
- };
216
- }
389
+ rows = await this.useLoaders(db, rows, loaders);
390
+ rows = this.hydrate(rows);
391
+ return rows;
392
+ })();
217
393
 
218
- protected async buildManyToManyQuery(
219
- db: DriverSpec[D]["adapter"],
220
- loader: SubsetQuery["loaders"][number],
221
- fromIds: any[]
222
- ) {
223
- if (!loader.manyJoin.through)
224
- throw new Error("Through table info missing for many-to-many relation");
225
-
226
- const idColumn = `${loader.manyJoin.through.table}.${loader.manyJoin.through.fromCol}`;
227
- let qb = db.from(loader.manyJoin.through.table);
228
-
229
- const throughTable = loader.manyJoin.through.table;
230
- const targetTable = loader.manyJoin.toTable;
231
-
232
- qb = this.applyJoins(qb, [
233
- {
234
- join: "inner",
235
- table: targetTable,
236
- as: targetTable,
237
- from: `${throughTable}.${loader.manyJoin.through.toCol}`,
238
- to: `${targetTable}.${loader.manyJoin.toCol}`,
239
- },
240
- ]);
241
-
242
- qb.where([idColumn, "in", fromIds]).select([...loader.select, idColumn]);
243
- qb = this.applyJoins(qb, loader.oneJoins);
244
-
245
- return {
246
- subQ: qb,
247
- col: loader.manyJoin.through.fromCol,
248
- };
394
+ return { rows, total, subsetQuery, qb };
249
395
  }
250
396
 
251
- myNow(timestamp?: number): string {
252
- const dt: DateTime =
253
- timestamp === undefined
254
- ? DateTime.local()
255
- : DateTime.fromSeconds(timestamp);
256
- return dt.toFormat("yyyy-MM-dd HH:mm:ss");
397
+ getJoinClause(
398
+ db: Knex<any, unknown>,
399
+ join: SubsetQuery["joins"][number]
400
+ ): Knex.Raw<any> {
401
+ if (!isCustomJoinClause(join)) {
402
+ return db.raw(`${join.from} = ${join.to}`);
403
+ } else {
404
+ return db.raw(join.custom);
405
+ }
257
406
  }
258
407
 
259
- hydrate<T>(rows: T[]): T[] {
260
- return rows.map((row: any) => {
261
- const nestedKeys = Object.keys(row).filter((key) => key.includes("__"));
262
- const groups = _.groupBy(nestedKeys, (key) => key.split("__")[0]);
263
- const nullKeys = Object.keys(groups).filter(
264
- (key) =>
265
- groups[key].length > 1 &&
266
- groups[key].every((field) => row[field] === null)
267
- );
268
-
269
- const hydrated = Object.keys(row).reduce((r, field) => {
270
- if (!field.includes("__")) {
271
- if (Array.isArray(row[field]) && _.isObject(row[field][0])) {
272
- r[field] = this.hydrate(row[field]);
273
- } else {
274
- r[field] = row[field];
275
- }
276
- return r;
277
- }
278
-
279
- const parts = field.split("__");
280
- const objPath =
281
- parts[0] +
282
- parts
283
- .slice(1)
284
- .map((part) => `[${part}]`)
285
- .join("");
286
-
287
- _.set(
288
- r,
289
- objPath,
290
- row[field] && Array.isArray(row[field]) && _.isObject(row[field][0])
291
- ? this.hydrate(row[field])
292
- : row[field]
293
- );
294
-
295
- return r;
296
- }, {} as any);
297
-
298
- nullKeys.forEach((nullKey) => (hydrated[nullKey] = null));
299
- return hydrated;
300
- });
408
+ getUpsertBuilder(): UpsertBuilder {
409
+ return new UpsertBuilder();
301
410
  }
302
411
  }
412
+ export const BaseModel = new BaseModelClass();