sonamu 0.5.6 → 0.6.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.
Files changed (365) hide show
  1. package/dist/api/base-frame.js +12 -2
  2. package/dist/api/caster.js +66 -2
  3. package/dist/api/code-converters.js +489 -2
  4. package/dist/api/config.d.ts +76 -0
  5. package/dist/api/config.d.ts.map +1 -0
  6. package/dist/api/config.js +32 -0
  7. package/dist/api/context.d.ts +1 -0
  8. package/dist/api/context.d.ts.map +1 -1
  9. package/dist/api/context.js +3 -2
  10. package/dist/api/decorators.d.ts +1 -0
  11. package/dist/api/decorators.d.ts.map +1 -1
  12. package/dist/api/decorators.js +142 -2
  13. package/dist/api/index.js +9 -2
  14. package/dist/api/sonamu.d.ts +8 -22
  15. package/dist/api/sonamu.d.ts.map +1 -1
  16. package/dist/api/sonamu.js +482 -2
  17. package/dist/bin/build-config.d.ts +2 -1
  18. package/dist/bin/build-config.d.ts.map +1 -1
  19. package/dist/bin/build-config.js +12 -2
  20. package/dist/bin/cli-wrapper.js +71 -2
  21. package/dist/bin/cli.js +418 -2
  22. package/dist/bin/hot-hook-register.d.ts +11 -0
  23. package/dist/bin/hot-hook-register.d.ts.map +1 -0
  24. package/dist/bin/hot-hook-register.js +21 -0
  25. package/dist/database/_batch_update.js +78 -2
  26. package/dist/database/base-model.js +247 -2
  27. package/dist/database/code-generator.js +53 -2
  28. package/dist/database/db.d.ts +5 -16
  29. package/dist/database/db.d.ts.map +1 -1
  30. package/dist/database/db.js +132 -2
  31. package/dist/database/knex-plugins/knex-on-duplicate-update.js +39 -2
  32. package/dist/database/puri-wrapper.d.ts +22 -10
  33. package/dist/database/puri-wrapper.d.ts.map +1 -1
  34. package/dist/database/puri-wrapper.js +109 -2
  35. package/dist/database/puri.d.ts +105 -73
  36. package/dist/database/puri.d.ts.map +1 -1
  37. package/dist/database/puri.js +539 -2
  38. package/dist/database/puri.types.d.ts +33 -42
  39. package/dist/database/puri.types.d.ts.map +1 -1
  40. package/dist/database/puri.types.js +3 -2
  41. package/dist/database/transaction-context.d.ts +3 -3
  42. package/dist/database/transaction-context.d.ts.map +1 -1
  43. package/dist/database/transaction-context.js +14 -2
  44. package/dist/database/upsert-builder.js +215 -2
  45. package/dist/entity/entity-manager.d.ts +3 -1
  46. package/dist/entity/entity-manager.d.ts.map +1 -1
  47. package/dist/entity/entity-manager.js +114 -2
  48. package/dist/entity/entity-utils.js +210 -2
  49. package/dist/entity/entity.d.ts.map +1 -1
  50. package/dist/entity/entity.js +651 -2
  51. package/dist/exceptions/error-handler.js +29 -2
  52. package/dist/exceptions/so-exceptions.js +85 -2
  53. package/dist/file-storage/driver.js +79 -2
  54. package/dist/file-storage/file-storage.js +75 -2
  55. package/dist/index.d.ts +2 -0
  56. package/dist/index.d.ts.map +1 -1
  57. package/dist/index.js +28 -2
  58. package/dist/migration/code-generation.js +558 -2
  59. package/dist/migration/migration-set.js +364 -2
  60. package/dist/migration/migrator.d.ts +0 -9
  61. package/dist/migration/migrator.d.ts.map +1 -1
  62. package/dist/migration/migrator.js +510 -2
  63. package/dist/migration/types.js +3 -2
  64. package/dist/naite/naite.d.ts +12 -0
  65. package/dist/naite/naite.d.ts.map +1 -0
  66. package/dist/naite/naite.js +72 -0
  67. package/dist/stream/index.js +3 -2
  68. package/dist/stream/sse.js +38 -2
  69. package/dist/syncer/api-parser.d.ts +20 -0
  70. package/dist/syncer/api-parser.d.ts.map +1 -0
  71. package/dist/syncer/api-parser.js +229 -0
  72. package/dist/syncer/checksum.d.ts +21 -0
  73. package/dist/syncer/checksum.d.ts.map +1 -0
  74. package/dist/syncer/checksum.js +98 -0
  75. package/dist/syncer/code-generator.d.ts +20 -0
  76. package/dist/syncer/code-generator.d.ts.map +1 -0
  77. package/dist/syncer/code-generator.js +141 -0
  78. package/dist/syncer/entity-operations.d.ts +17 -0
  79. package/dist/syncer/entity-operations.d.ts.map +1 -0
  80. package/dist/syncer/entity-operations.js +58 -0
  81. package/dist/syncer/file-patterns.d.ts +29 -0
  82. package/dist/syncer/file-patterns.d.ts.map +1 -0
  83. package/dist/syncer/file-patterns.js +38 -0
  84. package/dist/syncer/index.d.ts +6 -0
  85. package/dist/syncer/index.d.ts.map +1 -1
  86. package/dist/syncer/index.js +9 -2
  87. package/dist/syncer/module-loader.d.ts +35 -0
  88. package/dist/syncer/module-loader.d.ts.map +1 -0
  89. package/dist/syncer/module-loader.js +82 -0
  90. package/dist/syncer/syncer.d.ts +93 -108
  91. package/dist/syncer/syncer.d.ts.map +1 -1
  92. package/dist/syncer/syncer.js +375 -2
  93. package/dist/template/entity-converter.d.ts +14 -0
  94. package/dist/template/entity-converter.d.ts.map +1 -0
  95. package/dist/template/entity-converter.js +101 -0
  96. package/dist/template/helpers.d.ts +23 -0
  97. package/dist/template/helpers.d.ts.map +1 -0
  98. package/dist/template/helpers.js +64 -0
  99. package/dist/{templates → template/implementations}/entity.template.d.ts +3 -3
  100. package/dist/template/implementations/entity.template.d.ts.map +1 -0
  101. package/dist/template/implementations/entity.template.js +87 -0
  102. package/dist/{templates → template/implementations}/generated.template.d.ts +3 -3
  103. package/dist/template/implementations/generated.template.d.ts.map +1 -0
  104. package/dist/template/implementations/generated.template.js +232 -0
  105. package/dist/{templates → template/implementations}/generated_http.template.d.ts +3 -3
  106. package/dist/template/implementations/generated_http.template.d.ts.map +1 -0
  107. package/dist/template/implementations/generated_http.template.js +131 -0
  108. package/dist/{templates → template/implementations}/generated_sso.template.d.ts +3 -3
  109. package/dist/template/implementations/generated_sso.template.d.ts.map +1 -0
  110. package/dist/template/implementations/generated_sso.template.js +105 -0
  111. package/dist/{templates → template/implementations}/init_types.template.d.ts +3 -3
  112. package/dist/template/implementations/init_types.template.d.ts.map +1 -0
  113. package/dist/template/implementations/init_types.template.js +38 -0
  114. package/dist/template/implementations/model.template.d.ts +17 -0
  115. package/dist/template/implementations/model.template.d.ts.map +1 -0
  116. package/dist/template/implementations/model.template.js +171 -0
  117. package/dist/{templates → template/implementations}/model_test.template.d.ts +3 -3
  118. package/dist/template/implementations/model_test.template.d.ts.map +1 -0
  119. package/dist/template/implementations/model_test.template.js +35 -0
  120. package/dist/{templates → template/implementations}/service.template.d.ts +6 -6
  121. package/dist/template/implementations/service.template.d.ts.map +1 -0
  122. package/dist/template/implementations/service.template.js +193 -0
  123. package/dist/{templates → template/implementations}/view_enums_buttonset.template.d.ts +3 -3
  124. package/dist/template/implementations/view_enums_buttonset.template.d.ts.map +1 -0
  125. package/dist/template/implementations/view_enums_buttonset.template.js +31 -0
  126. package/dist/{templates → template/implementations}/view_enums_dropdown.template.d.ts +3 -4
  127. package/dist/template/implementations/view_enums_dropdown.template.d.ts.map +1 -0
  128. package/dist/template/implementations/view_enums_dropdown.template.js +50 -0
  129. package/dist/{templates → template/implementations}/view_enums_select.template.d.ts +3 -3
  130. package/dist/template/implementations/view_enums_select.template.d.ts.map +1 -0
  131. package/dist/template/implementations/view_enums_select.template.js +55 -0
  132. package/dist/{templates → template/implementations}/view_form.template.d.ts +5 -5
  133. package/dist/template/implementations/view_form.template.d.ts.map +1 -0
  134. package/dist/template/implementations/view_form.template.js +337 -0
  135. package/dist/{templates → template/implementations}/view_id_all_select.template.d.ts +3 -3
  136. package/dist/template/implementations/view_id_all_select.template.d.ts.map +1 -0
  137. package/dist/template/implementations/view_id_all_select.template.js +31 -0
  138. package/dist/{templates → template/implementations}/view_id_async_select.template.d.ts +3 -3
  139. package/dist/template/implementations/view_id_async_select.template.d.ts.map +1 -0
  140. package/dist/template/implementations/view_id_async_select.template.js +105 -0
  141. package/dist/{templates → template/implementations}/view_list.template.d.ts +5 -13
  142. package/dist/template/implementations/view_list.template.d.ts.map +1 -0
  143. package/dist/template/implementations/view_list.template.js +465 -0
  144. package/dist/{templates → template/implementations}/view_list_columns.template.d.ts +3 -3
  145. package/dist/template/implementations/view_list_columns.template.d.ts.map +1 -0
  146. package/dist/template/implementations/view_list_columns.template.js +49 -0
  147. package/dist/{templates → template/implementations}/view_search_input.template.d.ts +3 -3
  148. package/dist/template/implementations/view_search_input.template.d.ts.map +1 -0
  149. package/dist/template/implementations/view_search_input.template.js +64 -0
  150. package/dist/template/index.d.ts +5 -0
  151. package/dist/template/index.d.ts.map +1 -0
  152. package/dist/template/index.js +6 -0
  153. package/dist/template/template.d.ts +39 -0
  154. package/dist/template/template.d.ts.map +1 -0
  155. package/dist/template/template.js +47 -0
  156. package/dist/template/zod-converter.d.ts +18 -0
  157. package/dist/template/zod-converter.d.ts.map +1 -0
  158. package/dist/template/zod-converter.js +166 -0
  159. package/dist/testing/_relation-graph.js +80 -2
  160. package/dist/testing/fixture-manager.d.ts.map +1 -1
  161. package/dist/testing/fixture-manager.js +521 -2
  162. package/dist/types/types.d.ts +39 -40
  163. package/dist/types/types.d.ts.map +1 -1
  164. package/dist/types/types.js +289 -2
  165. package/dist/typings/knex.d.js +3 -2
  166. package/dist/utils/async-utils.d.ts +7 -0
  167. package/dist/utils/async-utils.d.ts.map +1 -1
  168. package/dist/utils/async-utils.js +57 -2
  169. package/dist/utils/console-util.d.ts +2 -0
  170. package/dist/utils/console-util.d.ts.map +1 -0
  171. package/dist/utils/console-util.js +6 -0
  172. package/dist/utils/controller.js +26 -2
  173. package/dist/utils/esm-utils.d.ts +45 -0
  174. package/dist/utils/esm-utils.d.ts.map +1 -0
  175. package/dist/utils/esm-utils.js +56 -0
  176. package/dist/utils/fs-utils.js +17 -2
  177. package/dist/utils/lodash-able.js +6 -2
  178. package/dist/utils/model.js +22 -2
  179. package/dist/utils/path-utils.d.ts +89 -0
  180. package/dist/utils/path-utils.d.ts.map +1 -0
  181. package/dist/utils/path-utils.js +60 -0
  182. package/dist/utils/process-utils.d.ts +13 -0
  183. package/dist/utils/process-utils.d.ts.map +1 -0
  184. package/dist/utils/process-utils.js +36 -0
  185. package/dist/utils/sql-parser.js +35 -2
  186. package/dist/utils/utils.d.ts +4 -7
  187. package/dist/utils/utils.d.ts.map +1 -1
  188. package/dist/utils/utils.js +33 -2
  189. package/dist/utils/zod-error.d.ts.map +1 -1
  190. package/dist/utils/zod-error.js +19 -2
  191. package/package.json +21 -9
  192. package/src/api/code-converters.ts +2 -2
  193. package/src/api/config.ts +142 -0
  194. package/src/api/context.ts +1 -0
  195. package/src/api/decorators.ts +15 -5
  196. package/src/api/sonamu.ts +102 -87
  197. package/src/bin/build-config.ts +2 -1
  198. package/src/bin/cli-wrapper.ts +10 -3
  199. package/src/bin/cli.ts +108 -56
  200. package/src/bin/hot-hook-register.ts +22 -0
  201. package/src/database/base-model.ts +1 -1
  202. package/src/database/code-generator.ts +1 -1
  203. package/src/database/db.ts +53 -60
  204. package/src/database/puri-wrapper.ts +104 -26
  205. package/src/database/puri.ts +477 -580
  206. package/src/database/puri.types.ts +111 -201
  207. package/src/database/transaction-context.ts +4 -4
  208. package/src/database/upsert-builder.ts +1 -1
  209. package/src/entity/entity-manager.ts +19 -15
  210. package/src/entity/entity.ts +4 -3
  211. package/src/index.ts +2 -0
  212. package/src/migration/code-generation.ts +1 -1
  213. package/src/migration/migration-set.ts +1 -1
  214. package/src/migration/migrator.ts +23 -152
  215. package/src/naite/naite.ts +70 -0
  216. package/src/syncer/api-parser.ts +299 -0
  217. package/src/syncer/checksum.ts +152 -0
  218. package/src/syncer/code-generator.ts +202 -0
  219. package/src/syncer/entity-operations.ts +68 -0
  220. package/src/syncer/file-patterns.ts +56 -0
  221. package/src/syncer/index.ts +6 -0
  222. package/src/syncer/module-loader.ts +125 -0
  223. package/src/syncer/syncer.ts +363 -1420
  224. package/src/template/entity-converter.ts +123 -0
  225. package/src/template/helpers.ts +84 -0
  226. package/src/{templates → template/implementations}/entity.template.ts +4 -4
  227. package/src/{templates → template/implementations}/generated.template.ts +9 -9
  228. package/src/{templates → template/implementations}/generated_http.template.ts +9 -6
  229. package/src/{templates → template/implementations}/generated_sso.template.ts +7 -7
  230. package/src/{templates → template/implementations}/init_types.template.ts +4 -4
  231. package/src/{templates → template/implementations}/model.template.ts +9 -9
  232. package/src/{templates → template/implementations}/model_test.template.ts +5 -5
  233. package/src/{templates → template/implementations}/service.template.ts +29 -12
  234. package/src/{templates → template/implementations}/view_enums_buttonset.template.ts +3 -3
  235. package/src/{templates → template/implementations}/view_enums_dropdown.template.ts +5 -21
  236. package/src/{templates → template/implementations}/view_enums_select.template.ts +4 -4
  237. package/src/{templates → template/implementations}/view_form.template.ts +11 -13
  238. package/src/{templates → template/implementations}/view_id_all_select.template.ts +3 -3
  239. package/src/{templates → template/implementations}/view_id_async_select.template.ts +3 -3
  240. package/src/{templates → template/implementations}/view_list.template.ts +13 -64
  241. package/src/{templates → template/implementations}/view_list_columns.template.ts +3 -3
  242. package/src/{templates → template/implementations}/view_search_input.template.ts +3 -3
  243. package/src/template/index.ts +4 -0
  244. package/src/template/template.ts +86 -0
  245. package/src/template/zod-converter.ts +219 -0
  246. package/src/testing/fixture-manager.ts +8 -1
  247. package/src/types/types.ts +39 -62
  248. package/src/utils/async-utils.ts +17 -0
  249. package/src/utils/console-util.ts +4 -0
  250. package/src/utils/esm-utils.ts +69 -0
  251. package/src/utils/path-utils.ts +102 -0
  252. package/src/utils/process-utils.ts +46 -0
  253. package/src/utils/sql-parser.ts +1 -1
  254. package/src/utils/utils.ts +14 -40
  255. package/src/utils/zod-error.ts +0 -1
  256. package/dist/api/base-frame.js.map +0 -1
  257. package/dist/api/caster.js.map +0 -1
  258. package/dist/api/code-converters.js.map +0 -1
  259. package/dist/api/context.js.map +0 -1
  260. package/dist/api/decorators.js.map +0 -1
  261. package/dist/api/index.js.map +0 -1
  262. package/dist/api/sonamu.js.map +0 -1
  263. package/dist/bin/build-config.js.map +0 -1
  264. package/dist/bin/cli-wrapper.js.map +0 -1
  265. package/dist/bin/cli.js.map +0 -1
  266. package/dist/database/_batch_update.js.map +0 -1
  267. package/dist/database/base-model.js.map +0 -1
  268. package/dist/database/code-generator.js.map +0 -1
  269. package/dist/database/db.js.map +0 -1
  270. package/dist/database/knex-plugins/knex-on-duplicate-update.js.map +0 -1
  271. package/dist/database/puri-wrapper.js.map +0 -1
  272. package/dist/database/puri.js.map +0 -1
  273. package/dist/database/puri.types.js.map +0 -1
  274. package/dist/database/transaction-context.js.map +0 -1
  275. package/dist/database/upsert-builder.js.map +0 -1
  276. package/dist/entity/entity-manager.js.map +0 -1
  277. package/dist/entity/entity-utils.js.map +0 -1
  278. package/dist/entity/entity.js.map +0 -1
  279. package/dist/exceptions/error-handler.js.map +0 -1
  280. package/dist/exceptions/so-exceptions.js.map +0 -1
  281. package/dist/file-storage/driver.js.map +0 -1
  282. package/dist/file-storage/file-storage.js.map +0 -1
  283. package/dist/index.js.map +0 -1
  284. package/dist/migration/code-generation.js.map +0 -1
  285. package/dist/migration/migration-set.js.map +0 -1
  286. package/dist/migration/migrator.js.map +0 -1
  287. package/dist/migration/types.js.map +0 -1
  288. package/dist/stream/index.js.map +0 -1
  289. package/dist/stream/sse.js.map +0 -1
  290. package/dist/syncer/index.js.map +0 -1
  291. package/dist/syncer/syncer.js.map +0 -1
  292. package/dist/templates/base-template.d.ts +0 -13
  293. package/dist/templates/base-template.d.ts.map +0 -1
  294. package/dist/templates/base-template.js +0 -2
  295. package/dist/templates/base-template.js.map +0 -1
  296. package/dist/templates/entity.template.d.ts.map +0 -1
  297. package/dist/templates/entity.template.js +0 -2
  298. package/dist/templates/entity.template.js.map +0 -1
  299. package/dist/templates/generated.template.d.ts.map +0 -1
  300. package/dist/templates/generated.template.js +0 -2
  301. package/dist/templates/generated.template.js.map +0 -1
  302. package/dist/templates/generated_http.template.d.ts.map +0 -1
  303. package/dist/templates/generated_http.template.js +0 -2
  304. package/dist/templates/generated_http.template.js.map +0 -1
  305. package/dist/templates/generated_sso.template.d.ts.map +0 -1
  306. package/dist/templates/generated_sso.template.js +0 -2
  307. package/dist/templates/generated_sso.template.js.map +0 -1
  308. package/dist/templates/index.d.ts +0 -2
  309. package/dist/templates/index.d.ts.map +0 -1
  310. package/dist/templates/index.js +0 -2
  311. package/dist/templates/index.js.map +0 -1
  312. package/dist/templates/init_types.template.d.ts.map +0 -1
  313. package/dist/templates/init_types.template.js +0 -2
  314. package/dist/templates/init_types.template.js.map +0 -1
  315. package/dist/templates/model.template.d.ts +0 -17
  316. package/dist/templates/model.template.d.ts.map +0 -1
  317. package/dist/templates/model.template.js +0 -2
  318. package/dist/templates/model.template.js.map +0 -1
  319. package/dist/templates/model_test.template.d.ts.map +0 -1
  320. package/dist/templates/model_test.template.js +0 -2
  321. package/dist/templates/model_test.template.js.map +0 -1
  322. package/dist/templates/service.template.d.ts.map +0 -1
  323. package/dist/templates/service.template.js +0 -2
  324. package/dist/templates/service.template.js.map +0 -1
  325. package/dist/templates/view_enums_buttonset.template.d.ts.map +0 -1
  326. package/dist/templates/view_enums_buttonset.template.js +0 -2
  327. package/dist/templates/view_enums_buttonset.template.js.map +0 -1
  328. package/dist/templates/view_enums_dropdown.template.d.ts.map +0 -1
  329. package/dist/templates/view_enums_dropdown.template.js +0 -2
  330. package/dist/templates/view_enums_dropdown.template.js.map +0 -1
  331. package/dist/templates/view_enums_select.template.d.ts.map +0 -1
  332. package/dist/templates/view_enums_select.template.js +0 -2
  333. package/dist/templates/view_enums_select.template.js.map +0 -1
  334. package/dist/templates/view_form.template.d.ts.map +0 -1
  335. package/dist/templates/view_form.template.js +0 -2
  336. package/dist/templates/view_form.template.js.map +0 -1
  337. package/dist/templates/view_id_all_select.template.d.ts.map +0 -1
  338. package/dist/templates/view_id_all_select.template.js +0 -2
  339. package/dist/templates/view_id_all_select.template.js.map +0 -1
  340. package/dist/templates/view_id_async_select.template.d.ts.map +0 -1
  341. package/dist/templates/view_id_async_select.template.js +0 -2
  342. package/dist/templates/view_id_async_select.template.js.map +0 -1
  343. package/dist/templates/view_list.template.d.ts.map +0 -1
  344. package/dist/templates/view_list.template.js +0 -2
  345. package/dist/templates/view_list.template.js.map +0 -1
  346. package/dist/templates/view_list_columns.template.d.ts.map +0 -1
  347. package/dist/templates/view_list_columns.template.js +0 -2
  348. package/dist/templates/view_list_columns.template.js.map +0 -1
  349. package/dist/templates/view_search_input.template.d.ts.map +0 -1
  350. package/dist/templates/view_search_input.template.js +0 -2
  351. package/dist/templates/view_search_input.template.js.map +0 -1
  352. package/dist/testing/_relation-graph.js.map +0 -1
  353. package/dist/testing/fixture-manager.js.map +0 -1
  354. package/dist/types/types.js.map +0 -1
  355. package/dist/typings/knex.d.js.map +0 -1
  356. package/dist/utils/async-utils.js.map +0 -1
  357. package/dist/utils/controller.js.map +0 -1
  358. package/dist/utils/fs-utils.js.map +0 -1
  359. package/dist/utils/lodash-able.js.map +0 -1
  360. package/dist/utils/model.js.map +0 -1
  361. package/dist/utils/sql-parser.js.map +0 -1
  362. package/dist/utils/utils.js.map +0 -1
  363. package/dist/utils/zod-error.js.map +0 -1
  364. package/src/templates/base-template.ts +0 -19
  365. package/src/templates/index.ts +0 -1
@@ -1,137 +1,140 @@
1
1
  import type { Knex } from "knex";
2
2
  import type {
3
3
  AvailableColumns,
4
+ SelectObject,
5
+ ParseSelectObject,
6
+ WhereCondition,
4
7
  ComparisonOperator,
5
- EmptyRecord,
6
- Expand,
7
8
  ExtractColumnType,
9
+ SqlExpression,
10
+ Expand,
8
11
  FulltextColumns,
9
- InsertData,
10
- MergeJoined,
11
- ParseSelectObject,
12
12
  ResultAvailableColumns,
13
- SelectObject,
14
- SqlFunction,
15
- WhereCondition,
13
+ InsertData,
14
+ SingleTableValue,
16
15
  } from "./puri.types";
17
16
  import chalk from "chalk";
17
+ import assert from "assert";
18
+ import { Naite } from "../naite/naite";
18
19
 
19
- // 메인 Puri 클래스
20
- export class Puri<
21
- TSchema,
22
- TTable extends keyof TSchema | string,
23
- TOriginal = TTable extends keyof TSchema ? TSchema[TTable] : unknown,
24
- TResult = TTable extends keyof TSchema ? TSchema[TTable] : unknown,
25
- TJoined = EmptyRecord,
26
- > {
20
+ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
27
21
  private knexQuery: Knex.QueryBuilder;
28
22
 
29
23
  // 생성자 시그니처들
24
+ constructor(knex: Knex, tableName: string);
30
25
  constructor(
31
26
  knex: Knex,
32
- tableName: TTable extends keyof TSchema ? TTable : unknown
33
- );
34
- constructor(
35
- knex: Knex,
36
- subquery: Puri<TSchema, any, any, TOriginal, any>,
37
- alias: TTable extends string ? TTable : never
27
+ tableSpec: Record<string, string | Puri<TSchema, any, any>>
38
28
  );
39
29
  constructor(
40
- private knex: Knex,
41
- tableNameOrSubquery: any,
42
- alias?: TTable extends string ? TTable : never
30
+ public knex: Knex,
31
+ tableNameOrSpec: any
43
32
  ) {
44
- if (typeof tableNameOrSubquery === "string") {
45
- // 일반 테이블로 시작
46
- this.knexQuery = knex(tableNameOrSubquery).from(tableNameOrSubquery);
33
+ if (typeof tableNameOrSpec === "string") {
34
+ // Case: new Puri(knex, "users")
35
+ this.knexQuery = this.knex(tableNameOrSpec).from(tableNameOrSpec);
36
+ } else if (typeof tableNameOrSpec === "object") {
37
+ const entries = Object.entries(tableNameOrSpec);
38
+ if (entries.length !== 1) {
39
+ throw new Error("Table spec must have exactly one entry");
40
+ }
41
+ assert(entries[0]);
42
+ const [alias, spec] = entries[0];
43
+ if (typeof spec === "string") {
44
+ this.knexQuery = this.knex(spec).from({ [alias]: spec });
45
+ } else if (spec instanceof Puri) {
46
+ const subqueryBuilder = spec.raw();
47
+ this.knexQuery = this.knex.from(subqueryBuilder.as(alias));
48
+ } else {
49
+ throw new Error("Invalid table specification");
50
+ }
47
51
  } else {
48
- // 서브쿼리로 시작
49
- this.knexQuery = knex.from(tableNameOrSubquery.raw().as(alias));
52
+ throw new Error("Invalid table specification");
50
53
  }
51
54
  }
52
55
 
53
- // Static SQL helper functions
54
- static count(column: string = "*"): SqlFunction<"number"> {
56
+ // Static SQL helper functions for SELECT
57
+ static count(column: string = "*"): SqlExpression<"number"> {
55
58
  return {
56
- _type: "sql_function",
59
+ _type: "sql_expression",
57
60
  _return: "number",
58
61
  _sql: `COUNT(${column})`,
59
62
  };
60
63
  }
61
-
62
- static sum(column: string): SqlFunction<"number"> {
63
- return { _type: "sql_function", _return: "number", _sql: `SUM(${column})` };
64
+ static sum(column: string): SqlExpression<"number"> {
65
+ return {
66
+ _type: "sql_expression",
67
+ _return: "number",
68
+ _sql: `SUM(${column})`,
69
+ };
64
70
  }
65
-
66
- static avg(column: string): SqlFunction<"number"> {
67
- return { _type: "sql_function", _return: "number", _sql: `AVG(${column})` };
71
+ static avg(column: string): SqlExpression<"number"> {
72
+ return {
73
+ _type: "sql_expression",
74
+ _return: "number",
75
+ _sql: `AVG(${column})`,
76
+ };
68
77
  }
69
-
70
- static max(column: string): SqlFunction<"number"> {
71
- return { _type: "sql_function", _return: "number", _sql: `MAX(${column})` };
78
+ static max(column: string): SqlExpression<"number"> {
79
+ return {
80
+ _type: "sql_expression",
81
+ _return: "number",
82
+ _sql: `MAX(${column})`,
83
+ };
72
84
  }
73
-
74
- static min(column: string): SqlFunction<"number"> {
75
- return { _type: "sql_function", _return: "number", _sql: `MIN(${column})` };
85
+ static min(column: string): SqlExpression<"number"> {
86
+ return {
87
+ _type: "sql_expression",
88
+ _return: "number",
89
+ _sql: `MIN(${column})`,
90
+ };
76
91
  }
77
-
78
- static concat(...args: string[]): SqlFunction<"string"> {
92
+ static concat(...args: string[]): SqlExpression<"string"> {
79
93
  return {
80
- _type: "sql_function",
94
+ _type: "sql_expression",
81
95
  _return: "string",
82
96
  _sql: `CONCAT(${args.join(", ")})`,
83
97
  };
84
98
  }
85
-
86
- static upper(column: string): SqlFunction<"string"> {
99
+ static upper(column: string): SqlExpression<"string"> {
87
100
  return {
88
- _type: "sql_function",
101
+ _type: "sql_expression",
89
102
  _return: "string",
90
103
  _sql: `UPPER(${column})`,
91
104
  };
92
105
  }
93
-
94
- static lower(column: string): SqlFunction<"string"> {
106
+ static lower(column: string): SqlExpression<"string"> {
95
107
  return {
96
- _type: "sql_function",
108
+ _type: "sql_expression",
97
109
  _return: "string",
98
110
  _sql: `LOWER(${column})`,
99
111
  };
100
112
  }
101
113
 
102
- // Raw functions
103
- static rawString(sql: string): SqlFunction<"string"> {
104
- return { _type: "sql_function", _return: "string", _sql: sql };
114
+ // Raw functions for SELECT
115
+ static rawString(sql: string): SqlExpression<"string"> {
116
+ return { _type: "sql_expression", _return: "string", _sql: sql };
105
117
  }
106
-
107
- static rawNumber(sql: string): SqlFunction<"number"> {
108
- return { _type: "sql_function", _return: "number", _sql: sql };
118
+ static rawNumber(sql: string): SqlExpression<"number"> {
119
+ return { _type: "sql_expression", _return: "number", _sql: sql };
109
120
  }
110
-
111
- static rawBoolean(sql: string): SqlFunction<"boolean"> {
112
- return { _type: "sql_function", _return: "boolean", _sql: sql };
121
+ static rawBoolean(sql: string): SqlExpression<"boolean"> {
122
+ return { _type: "sql_expression", _return: "boolean", _sql: sql };
113
123
  }
114
-
115
- static rawDate(sql: string): SqlFunction<"date"> {
116
- return { _type: "sql_function", _return: "date", _sql: sql };
124
+ static rawDate(sql: string): SqlExpression<"date"> {
125
+ return { _type: "sql_expression", _return: "date", _sql: sql };
117
126
  }
118
127
 
119
- // Alias 기반 Select
120
- select<TSelect extends SelectObject<TSchema, TTable, TOriginal, TJoined>>(
128
+ // SELECT (overwrite)
129
+ select<TSelect extends SelectObject<TTables>>(
121
130
  selectObj: TSelect
122
- ): Puri<
123
- TSchema,
124
- TTable,
125
- TOriginal,
126
- ParseSelectObject<TSchema, TTable, TSelect, TOriginal, TJoined>,
127
- TJoined
128
- > {
131
+ ): Puri<TSchema, TTables, ParseSelectObject<TTables, TSelect>> {
129
132
  const selectClauses: (string | Knex.Raw)[] = [];
130
133
 
131
134
  for (const [alias, columnOrFunction] of Object.entries(selectObj)) {
132
135
  if (
133
136
  typeof columnOrFunction === "object" &&
134
- columnOrFunction._type === "sql_function"
137
+ columnOrFunction._type === "sql_expression"
135
138
  ) {
136
139
  // SQL 함수인 경우
137
140
  selectClauses.push(
@@ -154,50 +157,211 @@ export class Puri<
154
157
  return this as any;
155
158
  }
156
159
 
157
- // 전체 선택 (편의 메서드)
158
- selectAll(): Puri<
159
- TSchema,
160
- TTable,
161
- TOriginal,
162
- TTable extends keyof TSchema
163
- ? TSchema[TTable] & TJoined
164
- : TResult & TJoined,
165
- TJoined
166
- > {
160
+ // SELECT (select는 overwrite, appendSelect는 append)
161
+ appendSelect<TSelect extends SelectObject<TTables>>(
162
+ selectObj: TSelect
163
+ ): Puri<TSchema, TTables, TResult & ParseSelectObject<TTables, TSelect>> {
164
+ return this.select(selectObj) as any;
165
+ }
166
+
167
+ // SELECT *
168
+ selectAll(): this {
167
169
  this.knexQuery.select("*");
168
170
  return this as any;
169
171
  }
170
172
 
171
- // Where 조건 (조인된 테이블 컬럼도 지원)
172
- where(
173
- conditions: WhereCondition<TSchema, TTable, TOriginal, TJoined>
174
- ): Puri<TSchema, TTable, TOriginal, TResult, TJoined>;
175
- where<TColumn extends AvailableColumns<TSchema, TTable, TOriginal, TJoined>>(
173
+ // JOIN: 서브쿼리 + Alias
174
+ join<TJoinAlias extends string, TSubResult>(
175
+ tableSpec: { [K in TJoinAlias]: Puri<TSchema, any, TSubResult> },
176
+ left: AvailableColumns<TTables>,
177
+ right: `${TJoinAlias}.${keyof TSubResult & string}`
178
+ ): Puri<
179
+ TSchema,
180
+ TTables & Record<TJoinAlias, TSubResult>, // 서브쿼리의 TResult
181
+ TResult
182
+ >;
183
+ // JOIN: 테이블 + Alias
184
+ join<TJoinTable extends keyof TSchema, TJoinAlias extends string>(
185
+ tableSpec: { [K in TJoinAlias]: TJoinTable },
186
+ left: AvailableColumns<TTables>,
187
+ right: `${TJoinAlias}.${keyof TSchema[TJoinTable] & string}`
188
+ ): Puri<
189
+ TSchema,
190
+ TTables & Record<TJoinAlias, TSchema[TJoinTable]>, // TTables 확장!
191
+ TResult
192
+ >;
193
+ // JOIN: 테이블명
194
+ join<TJoinTable extends keyof TSchema>(
195
+ tableName: TJoinTable,
196
+ left: AvailableColumns<TTables>,
197
+ right: `${TJoinTable & string}.${keyof TSchema[TJoinTable] & string}`
198
+ ): Puri<
199
+ TSchema,
200
+ TTables & Record<TJoinTable, TSchema[TJoinTable]>, // 테이블명이 키
201
+ TResult
202
+ >;
203
+ // JOIN: 서브쿼리 + Alias + 콜백
204
+ join<TJoinAlias extends string, TSubResult>(
205
+ tableSpec: { [K in TJoinAlias]: Puri<TSchema, any, TSubResult> },
206
+ callback: (
207
+ j: JoinClauseGroup<TTables, Record<TJoinAlias, TSubResult>>
208
+ ) => void
209
+ ): Puri<TSchema, TTables & Record<TJoinAlias, TSubResult>, TResult>;
210
+ // JOIN: 테이블 + Alias + 콜백
211
+ join<TJoinTable extends keyof TSchema, TJoinAlias extends string>(
212
+ tableSpec: { [K in TJoinAlias]: TJoinTable },
213
+ callback: (
214
+ j: JoinClauseGroup<TTables, Record<TJoinAlias, TSchema[TJoinTable]>>
215
+ ) => void
216
+ ): Puri<TSchema, TTables & Record<TJoinAlias, TSchema[TJoinTable]>, TResult>;
217
+ // JOIN: 테이블명 + 콜백
218
+ join<TJoinTable extends keyof TSchema>(
219
+ tableName: TJoinTable,
220
+ callback: (
221
+ j: JoinClauseGroup<TTables, Record<TJoinTable, TSchema[TJoinTable]>>
222
+ ) => void
223
+ ): Puri<TSchema, TTables & Record<TJoinTable, TSchema[TJoinTable]>, TResult>;
224
+ // JOIN 실제 구현
225
+ join(tableNameOrSpec: any, ...args: any[]): any {
226
+ return this.__commonJoin("join", tableNameOrSpec, ...args);
227
+ }
228
+
229
+ // LEFT JOIN: 서브쿼리 + Alias
230
+ leftJoin<TJoinAlias extends string, TSubResult>(
231
+ tableSpec: { [K in TJoinAlias]: Puri<TSchema, any, TSubResult> },
232
+ left: AvailableColumns<TTables>,
233
+ right: `${TJoinAlias}.${keyof TSubResult & string}`
234
+ ): Puri<
235
+ TSchema,
236
+ TTables & Record<TJoinAlias, TSubResult>, // 서브쿼리의 TResult
237
+ TResult
238
+ >;
239
+ // LEFT JOIN: 테이블 + Alias
240
+ leftJoin<TJoinTable extends keyof TSchema, TJoinAlias extends string>(
241
+ tableSpec: { [K in TJoinAlias]: TJoinTable },
242
+ left: AvailableColumns<TTables>,
243
+ right: `${TJoinAlias}.${keyof TSchema[TJoinTable] & string}`
244
+ ): Puri<
245
+ TSchema,
246
+ TTables & Record<TJoinAlias, TSchema[TJoinTable]>, // TTables 확장!
247
+ TResult
248
+ >;
249
+ // LEFT JOIN: 테이블명
250
+ leftJoin<TJoinTable extends keyof TSchema>(
251
+ tableName: TJoinTable,
252
+ left: AvailableColumns<TTables>,
253
+ right: `${TJoinTable & string}.${keyof TSchema[TJoinTable] & string}`
254
+ ): Puri<
255
+ TSchema,
256
+ TTables & Record<TJoinTable, TSchema[TJoinTable]>, // 테이블명이 키
257
+ TResult
258
+ >;
259
+ // LEFT JOIN: 서브쿼리 + Alias + 콜백
260
+ leftJoin<TJoinAlias extends string, TSubResult>(
261
+ tableSpec: { [K in TJoinAlias]: Puri<TSchema, any, TSubResult> },
262
+ callback: (
263
+ j: JoinClauseGroup<TTables, Record<TJoinAlias, TSubResult>>
264
+ ) => void
265
+ ): Puri<TSchema, TTables & Record<TJoinAlias, TSubResult>, TResult>;
266
+ // LEFT JOIN: 테이블 + Alias + 콜백
267
+ leftJoin<TJoinTable extends keyof TSchema, TJoinAlias extends string>(
268
+ tableSpec: { [K in TJoinAlias]: TJoinTable },
269
+ callback: (
270
+ j: JoinClauseGroup<TTables, Record<TJoinAlias, TSchema[TJoinTable]>>
271
+ ) => void
272
+ ): Puri<TSchema, TTables & Record<TJoinAlias, TSchema[TJoinTable]>, TResult>;
273
+ // LEFT JOIN: 테이블명 + 콜백
274
+ leftJoin<TJoinTable extends keyof TSchema>(
275
+ tableName: TJoinTable,
276
+ callback: (
277
+ j: JoinClauseGroup<TTables, Record<TJoinTable, TSchema[TJoinTable]>>
278
+ ) => void
279
+ ): Puri<TSchema, TTables & Record<TJoinTable, TSchema[TJoinTable]>, TResult>;
280
+ // LEFT JOIN 실제 구현
281
+ leftJoin(tableNameOrSpec: any, ...args: any[]): any {
282
+ return this.__commonJoin("leftJoin", tableNameOrSpec, ...args);
283
+ }
284
+
285
+ __commonJoin(
286
+ joinType: "join" | "leftJoin",
287
+ tableNameOrSpec: any,
288
+ ...args: any[]
289
+ ): this {
290
+ if (typeof tableNameOrSpec === "string") {
291
+ // Case 1: join("posts", ...)
292
+ const tableName = tableNameOrSpec;
293
+
294
+ if (args.length === 1 && typeof args[0] === "function") {
295
+ // join("posts", callback)
296
+ const callback = args[0];
297
+ this.knexQuery[joinType](tableName, (joinClause) => {
298
+ callback(new JoinClauseGroup(joinClause));
299
+ });
300
+ } else {
301
+ // join("posts", left, right)
302
+ const [left, right] = args;
303
+ this.knexQuery[joinType](tableName, left, right);
304
+ }
305
+ } else if (typeof tableNameOrSpec === "object") {
306
+ // Case 2: join({ alias: "table" }, ...) or join({ alias: subquery }, ...)
307
+ const entries = Object.entries(tableNameOrSpec);
308
+ if (entries.length !== 1) {
309
+ throw new Error("Table spec must have exactly one entry");
310
+ }
311
+ assert(entries[0]);
312
+ const [[alias, spec]] = entries;
313
+
314
+ if (typeof spec === "string") {
315
+ // 테이블: join({ p: "posts" }, ...)
316
+ if (args.length === 1 && typeof args[0] === "function") {
317
+ // Callback
318
+ const callback = args[0];
319
+ this.knexQuery[joinType]({ [alias]: spec }, (joinClause) => {
320
+ callback(new JoinClauseGroup(joinClause));
321
+ });
322
+ } else {
323
+ // Simple
324
+ const [left, right] = args;
325
+ this.knexQuery[joinType]({ [alias]: spec }, left, right);
326
+ }
327
+ } else if (spec instanceof Puri) {
328
+ // 서브쿼리: join({ sq: subquery }, ...)
329
+ if (args.length === 1 && typeof args[0] === "function") {
330
+ // Callback
331
+ const callback = args[0];
332
+ this.knexQuery[joinType](spec.raw().as(alias), (joinClause) => {
333
+ callback(new JoinClauseGroup(joinClause));
334
+ });
335
+ } else {
336
+ // Simple
337
+ const [left, right] = args;
338
+ this.knexQuery[joinType](spec.raw().as(alias), left, right);
339
+ }
340
+ } else {
341
+ throw new Error("Invalid table specification");
342
+ }
343
+ } else {
344
+ throw new Error("Invalid arguments");
345
+ }
346
+
347
+ return this;
348
+ }
349
+
350
+ // WHERE: 객체 - 사용: .where({ "u.id": 1, "u.status": "active" })
351
+ where(conditions: WhereCondition<TTables>): this;
352
+ // WHERE: 컬럼 - 사용: .where("u.id", 1)
353
+ where<TColumn extends AvailableColumns<TTables>>(
176
354
  column: TColumn,
177
- value: ExtractColumnType<
178
- TSchema,
179
- TTable,
180
- TColumn & string,
181
- TOriginal,
182
- TJoined
183
- >
184
- ): Puri<TSchema, TTable, TOriginal, TResult, TJoined>;
185
- where<TColumn extends AvailableColumns<TSchema, TTable, TOriginal, TJoined>>(
355
+ value: ExtractColumnType<TTables, TColumn & string>
356
+ ): this;
357
+ // WHERE: 컬럼 - 사용: .where("u.id", ">", 10)
358
+ where<TColumn extends AvailableColumns<TTables>>(
186
359
  column: TColumn,
187
- operator: ComparisonOperator | "like",
188
- value: ExtractColumnType<
189
- TSchema,
190
- TTable,
191
- TColumn & string,
192
- TOriginal,
193
- TJoined
194
- >
195
- ): Puri<TSchema, TTable, TOriginal, TResult, TJoined>;
196
- where(
197
- columnOrConditions: any,
198
- operatorOrValue?: any,
199
- value?: any
200
- ): Puri<TSchema, TTable, TOriginal, TResult, TJoined> {
360
+ operator: ComparisonOperator | "like" | "not like",
361
+ value: ExtractColumnType<TTables, TColumn & string>
362
+ ): this;
363
+ // WHERE: 컬럼 - 사용: .where("u.id", "like", "%test%")
364
+ where(columnOrConditions: any, operatorOrValue?: any, value?: any): this {
201
365
  if (typeof columnOrConditions === "object") {
202
366
  this.knexQuery.where(columnOrConditions);
203
367
  } else if (arguments.length === 2) {
@@ -223,386 +387,192 @@ export class Puri<
223
387
  return this;
224
388
  }
225
389
 
226
- // WhereIn (조인된 테이블 컬럼도 지원)
227
- whereIn<
228
- TColumn extends AvailableColumns<TSchema, TTable, TOriginal, TJoined>,
229
- >(
390
+ // WHERE IN
391
+ whereIn<TColumn extends AvailableColumns<TTables>>(
230
392
  column: TColumn,
231
- values: ExtractColumnType<
232
- TSchema,
233
- TTable,
234
- TColumn & string,
235
- TOriginal,
236
- TJoined
237
- >[]
238
- ): Puri<TSchema, TTable, TOriginal, TResult, TJoined>;
239
- whereIn(
240
- column: string,
241
- values: any[]
242
- ): Puri<TSchema, TTable, TOriginal, TResult, TJoined> {
393
+ values: ExtractColumnType<TTables, TColumn & string>[]
394
+ ): Puri<TSchema, TTables, TResult> {
243
395
  this.knexQuery.whereIn(column, values);
244
- return this;
396
+ return this as any;
245
397
  }
246
398
 
247
- whereNotIn<
248
- TColumn extends AvailableColumns<TSchema, TTable, TOriginal, TJoined>,
249
- >(
399
+ // WHERE NOT IN
400
+ whereNotIn<TColumn extends AvailableColumns<TTables>>(
250
401
  column: TColumn,
251
- values: ExtractColumnType<
252
- TSchema,
253
- TTable,
254
- TColumn & string,
255
- TOriginal,
256
- TJoined
257
- >[]
258
- ): Puri<TSchema, TTable, TOriginal, TResult, TJoined>;
259
- whereNotIn(
260
- column: string,
261
- values: any[]
262
- ): Puri<TSchema, TTable, TOriginal, TResult, TJoined> {
263
- this.knexQuery.whereNotIn(column, values);
264
- return this;
402
+ values: ExtractColumnType<TTables, TColumn & string>[]
403
+ ): Puri<TSchema, TTables, TResult> {
404
+ this.knexQuery.whereIn(column, values);
405
+ return this as any;
265
406
  }
266
407
 
267
- whereMatch<
268
- TColumn extends FulltextColumns<TSchema, TTable, TOriginal, TJoined>,
269
- >(
408
+ // WHERE MATCH
409
+ whereMatch<TColumn extends FulltextColumns<TTables>>(
270
410
  column: TColumn,
271
411
  value: string
272
- ): Puri<TSchema, TTable, TOriginal, TResult, TJoined> {
412
+ ): this {
273
413
  this.knexQuery.whereRaw(`MATCH (${String(column)}) AGAINST (?)`, [value]);
274
414
  return this;
275
415
  }
276
416
 
277
- // WhereGroup (괄호 그룹핑 지원)
278
- whereGroup(
279
- callback: (
280
- group: WhereGroup<TSchema, TTable, TOriginal, TJoined>
281
- ) => WhereGroup<TSchema, TTable, TOriginal, TJoined>
282
- ): Puri<TSchema, TTable, TOriginal, TResult, TJoined> {
417
+ // WHERE 괄호 그룹핑
418
+ whereGroup(callback: (g: WhereGroup<TTables>) => void): this {
283
419
  this.knexQuery.where((builder) => {
284
- const group = new WhereGroup<TSchema, TTable, TOriginal, TJoined>(
285
- builder
286
- );
420
+ const group = new WhereGroup<TTables>(builder);
287
421
  callback(group);
288
422
  });
289
423
  return this;
290
424
  }
291
-
292
- orWhereGroup(
293
- callback: (
294
- group: WhereGroup<TSchema, TTable, TOriginal, TJoined>
295
- ) => WhereGroup<TSchema, TTable, TOriginal, TJoined>
296
- ): Puri<TSchema, TTable, TOriginal, TResult, TJoined> {
425
+ orWhereGroup(callback: (g: WhereGroup<TTables>) => void): this {
297
426
  this.knexQuery.orWhere((builder) => {
298
- const group = new WhereGroup<TSchema, TTable, TOriginal, TJoined>(
299
- builder
300
- );
427
+ const group = new WhereGroup<TTables>(builder);
301
428
  callback(group);
302
429
  });
303
430
  return this;
304
431
  }
305
432
 
306
- // Join
307
- join<
308
- TJoinTable extends keyof TSchema,
309
- TLColumn extends AvailableColumns<
310
- TSchema,
311
- TTable,
312
- TOriginal,
313
- TJoined & Record<TJoinTable, TSchema[TJoinTable]>
314
- >,
315
- TRColumn extends AvailableColumns<
316
- TSchema,
317
- TTable,
318
- TOriginal,
319
- TJoined & Record<TJoinTable, TSchema[TJoinTable]>
320
- >,
321
- >(
322
- table: TJoinTable,
323
- left: TLColumn,
324
- right: TRColumn
325
- ): Puri<
326
- TSchema,
327
- TTable,
328
- TOriginal,
329
- TResult,
330
- MergeJoined<TJoined, Record<TJoinTable, TSchema[TJoinTable]>>
331
- >;
332
- join<TJoinTable extends keyof TSchema>(
333
- table: TJoinTable,
334
- joinCallback: (
335
- joinClause: JoinClauseGroup<TSchema, TTable, TOriginal, TJoined>
336
- ) => void
337
- ): Puri<
338
- TSchema,
339
- TTable,
340
- TOriginal,
341
- TResult,
342
- MergeJoined<TJoined, Record<TJoinTable, TSchema[TJoinTable]>>
343
- >;
344
- join<TSubResult, TAlias extends string>(
345
- subquery: Puri<TSchema, any, any, TSubResult, any>,
346
- alias: TAlias,
347
- left: string,
348
- right: string
349
- ): Puri<
350
- TSchema,
351
- TTable,
352
- TOriginal,
353
- TResult,
354
- TJoined & Record<TAlias, TSubResult>
355
- >;
356
- join(
357
- table: string,
358
- left: string,
359
- right: string
360
- ): Puri<TSchema, TTable, TOriginal, TResult, TJoined>;
361
- join(
362
- tableOrSubquery: string | keyof TSchema | Puri<TSchema, any, any, any, any>,
363
- ...args: any[]
364
- ): Puri<TSchema, TTable, TOriginal, TResult, any> {
365
- if (tableOrSubquery instanceof Puri) {
366
- // 서브쿼리 조인: join(subquery, alias, left, right)
367
- const [alias, left, right] = args;
368
- this.knexQuery.join(tableOrSubquery.raw().as(alias), left, right);
369
- } else if (
370
- args.length === 2 &&
371
- typeof args[0] === "string" &&
372
- typeof args[1] === "string"
373
- ) {
374
- const [left, right] = args;
375
- this.knexQuery.join(tableOrSubquery as string, left, right);
376
- } else if (args.length === 1 && typeof args[0] === "function") {
377
- const joinCallback = args[0];
378
- this.knexQuery.join(tableOrSubquery as string, (joinClause) => {
379
- joinCallback(new JoinClauseGroup(joinClause));
380
- });
381
- } else {
382
- throw new Error("Invalid arguments");
383
- }
384
- return this as any;
385
- }
386
-
387
- leftJoin<
388
- TJoinTable extends keyof TSchema,
389
- TLColumn extends AvailableColumns<
390
- TSchema,
391
- TTable,
392
- TOriginal,
393
- TJoined & Record<TJoinTable, TSchema[TJoinTable]>
394
- >,
395
- TRColumn extends AvailableColumns<
396
- TSchema,
397
- TTable,
398
- TOriginal,
399
- TJoined & Record<TJoinTable, TSchema[TJoinTable]>
400
- >,
401
- >(
402
- table: TJoinTable,
403
- left: TLColumn,
404
- right: TRColumn
405
- ): Puri<
406
- TSchema,
407
- TTable,
408
- TOriginal,
409
- TResult,
410
- TJoined & Record<TJoinTable, Partial<TSchema[TJoinTable]>>
411
- >;
412
- leftJoin<TSubResult, TAlias extends string>(
413
- subquery: Puri<TSchema, any, any, TSubResult, any>,
414
- alias: TAlias,
415
- left: string,
416
- right: string
417
- ): Puri<
418
- TSchema,
419
- TTable,
420
- TOriginal,
421
- TResult,
422
- TJoined & Record<TAlias, Partial<TSubResult>>
423
- >;
424
- leftJoin(
425
- table: string,
426
- left: string,
427
- right: string
428
- ): Puri<TSchema, TTable, TOriginal, TResult, TJoined>;
429
- leftJoin(
430
- tableOrSubquery: string | keyof TSchema | Puri<TSchema, any, any, any, any>,
431
- ...args: any[]
432
- ): Puri<TSchema, TTable, TOriginal, TResult, any> {
433
- if (tableOrSubquery instanceof Puri) {
434
- // 서브쿼리 조인: leftJoin(subquery, alias, left, right)
435
- const [alias, left, right] = args;
436
- this.knexQuery.leftJoin(tableOrSubquery.raw().as(alias), left, right);
437
- } else {
438
- const [left, right] = args;
439
- this.knexQuery.leftJoin(tableOrSubquery as string, left, right);
440
- }
441
- return this as any;
442
- }
443
-
444
- // OrderBy
445
- orderBy<
446
- TColumn extends ResultAvailableColumns<
447
- TSchema,
448
- TTable,
449
- TOriginal,
450
- TResult,
451
- TJoined
452
- >,
453
- >(
433
+ // ORDER BY
434
+ orderBy<TColumn extends ResultAvailableColumns<TTables, TResult>>(
454
435
  column: TColumn,
455
436
  direction: "asc" | "desc"
456
- ): Puri<TSchema, TTable, TOriginal, TResult, TJoined>;
457
- orderBy(
458
- column: string,
459
- direction: "asc" | "desc" = "asc"
460
- ): Puri<TSchema, TTable, TOriginal, TResult, TJoined> {
437
+ ): this;
438
+ orderBy(column: string, direction: "asc" | "desc" = "asc"): this {
461
439
  this.knexQuery.orderBy(column, direction);
462
440
  return this;
463
441
  }
464
442
 
465
443
  // 기본 쿼리 메서드들
466
- limit(count: number): Puri<TSchema, TTable, TOriginal, TResult, TJoined> {
444
+ limit(count: number): this {
467
445
  this.knexQuery.limit(count);
468
446
  return this;
469
447
  }
470
448
 
471
- offset(count: number): Puri<TSchema, TTable, TOriginal, TResult, TJoined> {
449
+ offset(count: number): this {
472
450
  this.knexQuery.offset(count);
473
451
  return this;
474
452
  }
475
453
 
476
- // Group by (조인된 테이블 컬럼도 지원)
477
- groupBy<
478
- TColumns extends ResultAvailableColumns<
479
- TSchema,
480
- TTable,
481
- TOriginal,
482
- TResult,
483
- TJoined
484
- >,
485
- >(...columns: TColumns[]): Puri<TSchema, TTable, TOriginal, TResult, TJoined>;
486
- groupBy(
487
- ...columns: string[]
488
- ): Puri<TSchema, TTable, TOriginal, TResult, TJoined> {
454
+ // GROUP BY
455
+ groupBy<TColumns extends ResultAvailableColumns<TTables, TResult>>(
456
+ ...columns: TColumns[]
457
+ ): this;
458
+ groupBy(...columns: string[]): this {
489
459
  this.knexQuery.groupBy(...(columns as string[]));
490
460
  return this;
491
461
  }
492
462
 
493
- having(condition: string): Puri<TSchema, TTable, TOriginal, TResult, TJoined>;
494
- having<
495
- TColumn extends ResultAvailableColumns<
496
- TSchema,
497
- TTable,
498
- TOriginal,
499
- TResult,
500
- TJoined
501
- >,
502
- >(
503
- condition: TColumn,
463
+ // HAVING
464
+ having(condition: string): this;
465
+ having<TColumn extends ResultAvailableColumns<TTables, TResult>>(
466
+ column: TColumn,
504
467
  operator: ComparisonOperator,
505
468
  value: any
506
- ): Puri<TSchema, TTable, TOriginal, TResult, TJoined>;
507
- having(
508
- ...conditions: string[]
509
- ): Puri<TSchema, TTable, TOriginal, TResult, TJoined> {
510
- this.knexQuery.having(...(conditions as [string, string, string]));
469
+ ): this;
470
+ // HAVING 구현
471
+ having(...conditions: any[]): this {
472
+ if (conditions.length === 1) {
473
+ // having("COUNT(*) > 10")
474
+ this.knexQuery.having(conditions[0]);
475
+ } else if (conditions.length === 3) {
476
+ // having("count", ">", 10)
477
+ this.knexQuery.having(conditions[0], conditions[1], conditions[2]);
478
+ } else {
479
+ throw new Error("Invalid having arguments");
480
+ }
511
481
  return this;
512
482
  }
483
+
513
484
  // 실행 메서드들 - thenable 구현
514
- then<TResult1, TResult2 = never>(
485
+ then<TResult1 = Expand<TResult>[], TResult2 = never>(
515
486
  onfulfilled?:
516
- | ((
517
- value: Expand<TResult>[]
518
- ) => Expand<TResult1> | PromiseLike<Expand<TResult1>>)
487
+ | ((value: Expand<TResult>[]) => TResult1 | PromiseLike<TResult1>)
519
488
  | null,
520
489
  onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null
521
- ): Promise<Expand<TResult1> | TResult2> {
490
+ ): Promise<TResult1 | TResult2> {
491
+ Naite.t("puri-query", this.toQuery());
522
492
  return this.knexQuery.then(onfulfilled as any, onrejected);
523
493
  }
524
-
525
494
  catch<TResult2 = never>(
526
495
  onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null
527
- ): Promise<Expand<TResult> | TResult2> {
496
+ ): Promise<TResult | TResult2> {
528
497
  return this.knexQuery.catch(onrejected);
529
498
  }
530
-
531
- finally(onfinally?: (() => void) | null): Promise<Expand<TResult>> {
499
+ finally(onfinally?: (() => void) | null): Promise<TResult> {
532
500
  return this.knexQuery.finally(onfinally);
533
501
  }
534
502
 
535
- // 안전한 실행 메서드들
536
- async first(): Promise<Expand<TResult> | undefined> {
537
- return this.knexQuery.first() as Promise<Expand<TResult> | undefined>;
503
+ // 하나만 쿼리
504
+ first(): ResolvedPuri<Expand<TResult>, never> {
505
+ this.knexQuery.first();
506
+ return new ResolvedPuri(this.knexQuery);
538
507
  }
539
508
 
540
- async firstOrFail(): Promise<TResult> {
541
- const result = await this.knexQuery.first();
542
- if (!result) {
543
- throw new Error("No results found");
544
- }
545
- return result as TResult;
546
- }
547
-
548
- async at(index: number): Promise<Expand<TResult> | undefined> {
549
- const results = await this;
550
- return results[index] as Expand<TResult> | undefined;
551
- }
552
-
553
- async assertAt(index: number): Promise<Expand<TResult>> {
554
- const results = await this;
555
- const result = results[index];
556
- if (result === undefined) {
557
- throw new Error(`No result found at index ${index}`);
558
- }
559
- return result;
560
- }
561
-
562
- // Pluck
563
- async pluck<
564
- TColumn extends ResultAvailableColumns<
565
- TSchema,
566
- TTable,
567
- TOriginal,
568
- TResult,
569
- TJoined
570
- >,
509
+ // 쿼리한 레코드에서 특정 컬럼만 추출한 배열 리턴
510
+ pluck<
511
+ TColumn extends keyof TResult | ResultAvailableColumns<TTables, TResult>,
571
512
  >(
572
513
  column: TColumn
573
- ): Promise<
574
- ExtractColumnType<TSchema, TTable, TColumn & string, TOriginal, TJoined>[]
514
+ ): ResolvedPuri<
515
+ TColumn extends keyof TResult
516
+ ? TResult[TColumn][]
517
+ : ExtractColumnType<TTables, TColumn & string>[],
518
+ never
575
519
  > {
576
- return this.knexQuery.pluck(column) as Promise<
577
- ExtractColumnType<TSchema, TTable, TColumn & string, TOriginal, TJoined>[]
578
- >;
520
+ this.knexQuery.pluck(column as string);
521
+ return new ResolvedPuri(this.knexQuery);
522
+ }
523
+
524
+ // INSERT
525
+ insert(
526
+ data: InsertData<SingleTableValue<TTables>>
527
+ ): ResolvedPuri<[number], never> {
528
+ this.knexQuery.insert(data);
529
+ return new ResolvedPuri(this.knexQuery);
579
530
  }
580
531
 
581
- // Insert/Update/Delete
582
- // TODO(Haze, 251030): InsertData<T>에서 nullable type을 제대로 처리하지 못하는 것 같음.
583
- async insert(
584
- data: TTable extends keyof TSchema ? InsertData<TSchema[TTable]> : unknown
585
- ): Promise<number[]> {
586
- return this.knexQuery.insert(data);
532
+ // UPDATE
533
+ update(data: WhereCondition<TTables>): ResolvedPuri<TResult, number> {
534
+ this.knexQuery.update(data);
535
+ return new ResolvedPuri(this.knexQuery);
587
536
  }
588
537
 
589
- async update(
590
- data: Partial<TTable extends keyof TSchema ? TSchema[TTable] : unknown>
591
- ): Promise<number> {
592
- return this.knexQuery.update(data);
538
+ // Increment
539
+ increment<TColumn extends AvailableColumns<TTables>>(
540
+ column: TColumn,
541
+ value: number
542
+ ): ResolvedPuri<number, never> {
543
+ if (value <= 0) {
544
+ throw new Error("Increment value must be greater than 0");
545
+ }
546
+ this.knexQuery.increment(column, value);
547
+ return new ResolvedPuri(this.knexQuery);
548
+ }
549
+ // Decrement
550
+ decrement<TColumn extends AvailableColumns<TTables>>(
551
+ column: TColumn,
552
+ value: number
553
+ ): ResolvedPuri<number, never> {
554
+ if (value <= 0) {
555
+ throw new Error("Decrement value must be greater than 0");
556
+ }
557
+ this.knexQuery.decrement(column, value);
558
+ return new ResolvedPuri(this.knexQuery);
593
559
  }
594
560
 
595
- async delete(): Promise<number> {
596
- return this.knexQuery.delete();
561
+ // DELETE
562
+ delete(): ResolvedPuri<number, never> {
563
+ this.knexQuery.delete();
564
+ return new ResolvedPuri(this.knexQuery);
597
565
  }
598
566
 
567
+ // 확인 쿼리 리턴
599
568
  toQuery(): string {
600
569
  return this.knexQuery.toQuery();
601
570
  }
602
571
 
603
- debug(): Puri<TSchema, TTable, TOriginal, TResult, TJoined> {
572
+ // 쿼리 디버깅 로그 출력
573
+ debug(): this {
604
574
  console.log(
605
- `${chalk.cyan("[Puri Debug]")} ${chalk.yellow(this.formatSQL(this.toQuery()))}`
575
+ `${chalk.cyan("[Puri Debug]")} ${chalk.yellow(this.toQuery())}`
606
576
  );
607
577
  return this;
608
578
  }
@@ -718,174 +688,62 @@ export class Puri<
718
688
  return indentedLines.join("\n").trim();
719
689
  }
720
690
 
691
+ // Knex 쿼리 빌더 직접 접근
721
692
  raw(): Knex.QueryBuilder {
722
693
  return this.knexQuery;
723
694
  }
724
-
725
- increment<
726
- TColumn extends AvailableColumns<TSchema, TTable, TOriginal, TJoined>,
727
- >(
728
- column: TColumn,
729
- value: number
730
- ): Puri<TSchema, TTable, TOriginal, TResult, TJoined> {
731
- if (value <= 0) {
732
- throw new Error("Increment value must be greater than 0");
733
- }
734
- this.knexQuery.increment(column, value);
735
- return this;
736
- }
737
-
738
- decrement<
739
- TColumn extends AvailableColumns<TSchema, TTable, TOriginal, TJoined>,
740
- >(
741
- column: TColumn,
742
- value: number
743
- ): Puri<TSchema, TTable, TOriginal, TResult, TJoined> {
744
- if (value <= 0) {
745
- throw new Error("Decrement value must be greater than 0");
746
- }
747
- this.knexQuery.decrement(column, value);
748
- return this;
749
- }
750
695
  }
751
696
 
752
- // 11. Database 클래스
753
- class WhereGroup<
754
- TSchema,
755
- TTable extends keyof TSchema | string,
756
- TOriginal = any,
757
- TJoined = EmptyRecord,
758
- > {
697
+ export class WhereGroup<TTables extends Record<string, any>> {
759
698
  constructor(private builder: Knex.QueryBuilder) {}
760
699
 
761
- where(
762
- conditions: WhereCondition<TSchema, TTable, TOriginal, TJoined>
763
- ): WhereGroup<TSchema, TTable, TOriginal, TJoined>;
764
- where<TColumn extends AvailableColumns<TSchema, TTable, TOriginal, TJoined>>(
700
+ // where 메서드들
701
+ where(conditions: WhereCondition<TTables>): this;
702
+ where<TColumn extends AvailableColumns<TTables>>(
765
703
  column: TColumn,
766
- value: ExtractColumnType<
767
- TSchema,
768
- TTable,
769
- TColumn & string,
770
- TOriginal,
771
- TJoined
772
- >
773
- ): WhereGroup<TSchema, TTable, TOriginal, TJoined>;
774
- where<TColumn extends AvailableColumns<TSchema, TTable, TOriginal, TJoined>>(
704
+ value: ExtractColumnType<TTables, TColumn & string>
705
+ ): this;
706
+ where<TColumn extends AvailableColumns<TTables>>(
775
707
  column: TColumn,
776
- operator: ComparisonOperator | "like",
777
- value: ExtractColumnType<
778
- TSchema,
779
- TTable,
780
- TColumn & string,
781
- TOriginal,
782
- TJoined
783
- >
784
- ): WhereGroup<TSchema, TTable, TOriginal, TJoined>;
785
- where(raw: string): WhereGroup<TSchema, TTable, TOriginal, TJoined>;
786
- where(...args: any[]): WhereGroup<TSchema, TTable, TOriginal, TJoined> {
708
+ operator: ComparisonOperator,
709
+ value: ExtractColumnType<TTables, TColumn & string>
710
+ ): this;
711
+ where(...args: any[]): WhereGroup<TTables> {
787
712
  this.builder.where(args[0], ...args.slice(1));
788
713
  return this;
789
714
  }
790
715
 
791
- orWhere(
792
- conditions: WhereCondition<TSchema, TTable, TOriginal, TJoined>
793
- ): WhereGroup<TSchema, TTable, TOriginal, TJoined>;
794
- orWhere<
795
- TColumn extends AvailableColumns<TSchema, TTable, TOriginal, TJoined>,
796
- >(
716
+ // orWhere 메서드들
717
+ orWhere(conditions: WhereCondition<TTables>): this;
718
+ orWhere<TColumn extends AvailableColumns<TTables>>(
797
719
  column: TColumn,
798
- value: ExtractColumnType<
799
- TSchema,
800
- TTable,
801
- TColumn & string,
802
- TOriginal,
803
- TJoined
804
- >
805
- ): WhereGroup<TSchema, TTable, TOriginal, TJoined>;
806
- orWhere<
807
- TColumn extends AvailableColumns<TSchema, TTable, TOriginal, TJoined>,
808
- >(
720
+ value: ExtractColumnType<TTables, TColumn & string>
721
+ ): this;
722
+ orWhere<TColumn extends AvailableColumns<TTables>>(
809
723
  column: TColumn,
810
- operator: ComparisonOperator | "like",
811
- value: ExtractColumnType<
812
- TSchema,
813
- TTable,
814
- TColumn & string,
815
- TOriginal,
816
- TJoined
817
- >
818
- ): WhereGroup<TSchema, TTable, TOriginal, TJoined>;
819
- orWhere(raw: string): WhereGroup<TSchema, TTable, TOriginal, TJoined>;
820
- orWhere(...args: any[]): WhereGroup<TSchema, TTable, TOriginal, TJoined> {
724
+ operator: ComparisonOperator,
725
+ value: ExtractColumnType<TTables, TColumn & string>
726
+ ): this;
727
+ orWhere(...args: any[]): WhereGroup<TTables> {
821
728
  this.builder.orWhere(args[0], ...args.slice(1));
822
729
  return this;
823
730
  }
824
731
 
825
- whereIn<
826
- TColumn extends AvailableColumns<TSchema, TTable, TOriginal, TJoined>,
827
- >(
828
- column: TColumn,
829
- values: ExtractColumnType<
830
- TSchema,
831
- TTable,
832
- TColumn & string,
833
- TOriginal,
834
- TJoined
835
- >[]
836
- ): WhereGroup<TSchema, TTable, TOriginal, TJoined>;
837
- whereIn(
838
- column: string,
839
- values: any[]
840
- ): WhereGroup<TSchema, TTable, TOriginal, TJoined> {
841
- this.builder.whereIn(column, values);
842
- return this;
843
- }
844
-
845
- orWhereIn<
846
- TColumn extends AvailableColumns<TSchema, TTable, TOriginal, TJoined>,
847
- >(
848
- column: TColumn,
849
- values: ExtractColumnType<
850
- TSchema,
851
- TTable,
852
- TColumn & string,
853
- TOriginal,
854
- TJoined
855
- >[]
856
- ): WhereGroup<TSchema, TTable, TOriginal, TJoined>;
857
- orWhereIn(
858
- column: string,
859
- values: any[]
860
- ): WhereGroup<TSchema, TTable, TOriginal, TJoined> {
861
- this.builder.orWhereIn(column, values);
862
- return this;
863
- }
864
-
865
- // 중첩 그룹 지원
866
- whereGroup(
867
- callback: (
868
- group: WhereGroup<TSchema, TTable, TOriginal, TJoined>
869
- ) => WhereGroup<TSchema, TTable, TOriginal, TJoined>
870
- ): WhereGroup<TSchema, TTable, TOriginal, TJoined> {
732
+ // 중첩 그룹
733
+ whereGroup(callback: (g: WhereGroup<TTables>) => void): this;
734
+ whereGroup(callback: (g: WhereGroup<TTables>) => void): WhereGroup<TTables> {
871
735
  this.builder.where((subBuilder) => {
872
- const subGroup = new WhereGroup<TSchema, TTable, TOriginal, TJoined>(
873
- subBuilder
874
- );
736
+ const subGroup = new WhereGroup<TTables>(subBuilder);
875
737
  callback(subGroup);
876
738
  });
877
739
  return this;
878
740
  }
879
-
741
+ orWhereGroup(callback: (g: WhereGroup<TTables>) => void): this;
880
742
  orWhereGroup(
881
- callback: (
882
- group: WhereGroup<TSchema, TTable, TOriginal, TJoined>
883
- ) => WhereGroup<TSchema, TTable, TOriginal, TJoined>
884
- ): WhereGroup<TSchema, TTable, TOriginal, TJoined> {
743
+ callback: (g: WhereGroup<TTables>) => void
744
+ ): WhereGroup<TTables> {
885
745
  this.builder.orWhere((subBuilder) => {
886
- const subGroup = new WhereGroup<TSchema, TTable, TOriginal, TJoined>(
887
- subBuilder
888
- );
746
+ const subGroup = new WhereGroup<TTables>(subBuilder);
889
747
  callback(subGroup);
890
748
  });
891
749
  return this;
@@ -893,38 +751,77 @@ class WhereGroup<
893
751
  }
894
752
 
895
753
  export class JoinClauseGroup<
896
- TSchema,
897
- TTable extends keyof TSchema | string,
898
- TOriginal = any,
899
- TJoined = EmptyRecord,
754
+ TLeft extends Record<string, any>,
755
+ TRight extends Record<string, any>,
900
756
  > {
901
757
  constructor(private callback: Knex.JoinClause) {}
902
758
 
759
+ // ON(AND): 컬럼 = 컬럼
760
+ on(left: AvailableColumns<TLeft>, right: AvailableColumns<TRight>): this;
761
+ // ON(AND): 컬럼 (연산자) 컬럼
903
762
  on(
904
- callback: (
905
- joinClause: JoinClauseGroup<TSchema, TTable, TOriginal, TJoined>
906
- ) => void
907
- ): JoinClauseGroup<TSchema, TTable, TOriginal, TJoined>;
908
- on(
909
- column: string,
910
- value: any
911
- ): JoinClauseGroup<TSchema, TTable, TOriginal, TJoined>;
912
- on(...args: any[]): JoinClauseGroup<TSchema, TTable, TOriginal, TJoined> {
763
+ left: AvailableColumns<TLeft>,
764
+ operator: ComparisonOperator,
765
+ right: AvailableColumns<TRight>
766
+ ): this;
767
+ // ON(AND): 콜백
768
+ on(callback: (nested: JoinClauseGroup<TLeft, TRight>) => void): this;
769
+ // ON(AND) 구현
770
+ on(...args: any[]): this {
913
771
  this.callback.on(...(args as [string, string]));
914
772
  return this;
915
773
  }
916
774
 
775
+ // ON(OR): 컬럼 = 컬럼
776
+ orOn(left: AvailableColumns<TLeft>, right: AvailableColumns<TRight>): this;
777
+ // ON(OR): 컬럼 (연산자) 컬럼
917
778
  orOn(
918
- callback: (
919
- joinClause: JoinClauseGroup<TSchema, TTable, TOriginal, TJoined>
920
- ) => void
921
- ): JoinClauseGroup<TSchema, TTable, TOriginal, TJoined>;
922
- orOn(
923
- column: string,
924
- value: any
925
- ): JoinClauseGroup<TSchema, TTable, TOriginal, TJoined>;
926
- orOn(...args: any[]): JoinClauseGroup<TSchema, TTable, TOriginal, TJoined> {
779
+ left: AvailableColumns<TLeft>,
780
+ operator: ComparisonOperator,
781
+ right: AvailableColumns<TRight>
782
+ ): this;
783
+ // ON(OR): 콜백
784
+ orOn(callback: (nested: JoinClauseGroup<TLeft, TRight>) => void): this;
785
+ // ON(OR) 구현
786
+ orOn(...args: any[]): this {
927
787
  this.callback.orOn(...(args as [string, string]));
928
788
  return this;
929
789
  }
930
790
  }
791
+
792
+ /*
793
+ TResolved: 쿼리 실행 후 반환될 결과 타입
794
+ _TReturning: 추후 RETURNING 절에 사용될 타입
795
+ */
796
+ export class ResolvedPuri<TResolved, _TReturning> {
797
+ constructor(public knexQuery: Knex.QueryBuilder) {}
798
+
799
+ toQuery(): string {
800
+ return this.knexQuery.toQuery();
801
+ }
802
+
803
+ debug(): this {
804
+ console.log(
805
+ `${chalk.cyan("[Puri Debug]")} ${chalk.yellow(this.toQuery())}`
806
+ );
807
+ return this;
808
+ }
809
+
810
+ then<TResult1 = TResolved, TResult2 = never>(
811
+ onfulfilled?:
812
+ | ((value: TResolved) => TResult1 | PromiseLike<TResult1>)
813
+ | null,
814
+ onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null
815
+ ): Promise<TResult1 | TResult2> {
816
+ Naite.t("puri-query", this.toQuery());
817
+ return this.knexQuery.then(onfulfilled as any, onrejected);
818
+ }
819
+ catch<TResult2 = never>(
820
+ onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null
821
+ ): Promise<TResolved | TResult2> {
822
+ return this.knexQuery.catch(onrejected);
823
+ }
824
+ finally(onfinally?: (() => void) | null): Promise<TResolved> {
825
+ return this.knexQuery.finally(onfinally);
826
+ }
827
+ }