d1s 0.2.11 → 0.2.12

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 (312) hide show
  1. package/dist/.next/.next/BUILD_ID +1 -1
  2. package/dist/.next/.next/app-build-manifest.json +28 -28
  3. package/dist/.next/.next/app-path-routes-manifest.json +1 -1
  4. package/dist/.next/.next/build-manifest.json +3 -3
  5. package/dist/.next/.next/cache/.rscinfo +1 -1
  6. package/dist/.next/.next/cache/.tsbuildinfo +1 -1
  7. package/dist/.next/.next/cache/webpack/client-production/0.pack +0 -0
  8. package/dist/.next/.next/cache/webpack/client-production/1.pack +0 -0
  9. package/dist/.next/.next/cache/webpack/client-production/10.pack +0 -0
  10. package/dist/.next/.next/cache/webpack/client-production/11.pack +0 -0
  11. package/dist/.next/.next/cache/webpack/client-production/12.pack +0 -0
  12. package/dist/.next/.next/cache/webpack/client-production/2.pack +0 -0
  13. package/dist/.next/.next/cache/webpack/client-production/3.pack +0 -0
  14. package/dist/.next/.next/cache/webpack/client-production/4.pack +0 -0
  15. package/dist/.next/.next/cache/webpack/client-production/5.pack +0 -0
  16. package/dist/.next/.next/cache/webpack/client-production/6.pack +0 -0
  17. package/dist/.next/.next/cache/webpack/client-production/7.pack +0 -0
  18. package/dist/.next/.next/cache/webpack/client-production/8.pack +0 -0
  19. package/dist/.next/.next/cache/webpack/client-production/9.pack +0 -0
  20. package/dist/.next/.next/cache/webpack/client-production/index.pack +0 -0
  21. package/dist/.next/.next/cache/webpack/client-production/index.pack.old +0 -0
  22. package/dist/.next/.next/cache/webpack/edge-server-production/index.pack +0 -0
  23. package/dist/.next/.next/cache/webpack/server-production/0.pack +0 -0
  24. package/dist/.next/.next/cache/webpack/server-production/1.pack +0 -0
  25. package/dist/.next/.next/cache/webpack/server-production/index.pack +0 -0
  26. package/dist/.next/.next/cache/webpack/server-production/index.pack.old +0 -0
  27. package/dist/.next/.next/next-minimal-server.js.nft.json +1 -1
  28. package/dist/.next/.next/next-server.js.nft.json +1 -1
  29. package/dist/.next/.next/prerender-manifest.json +1 -1
  30. package/dist/.next/.next/required-server-files.json +1 -1
  31. package/dist/.next/.next/server/app/_not-found/page.js +1 -1
  32. package/dist/.next/.next/server/app/_not-found/page.js.nft.json +1 -1
  33. package/dist/.next/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  34. package/dist/.next/.next/server/app/_not-found.html +1 -1
  35. package/dist/.next/.next/server/app/_not-found.rsc +4 -4
  36. package/dist/.next/.next/server/app/api/cloudflare/route.js +1 -1
  37. package/dist/.next/.next/server/app/api/cloudflare/route_client-reference-manifest.js +1 -1
  38. package/dist/.next/.next/server/app/api/databases/route.js +1 -1
  39. package/dist/.next/.next/server/app/api/databases/route_client-reference-manifest.js +1 -1
  40. package/dist/.next/.next/server/app/api/migrations/sync/route.js +5 -5
  41. package/dist/.next/.next/server/app/api/migrations/sync/route_client-reference-manifest.js +1 -1
  42. package/dist/.next/.next/server/app/api/migrations/sync-files/route.js +3 -3
  43. package/dist/.next/.next/server/app/api/migrations/sync-files/route_client-reference-manifest.js +1 -1
  44. package/dist/.next/.next/server/app/api/pull-data/confirm/route.js +1 -1
  45. package/dist/.next/.next/server/app/api/pull-data/confirm/route_client-reference-manifest.js +1 -1
  46. package/dist/.next/.next/server/app/api/pull-remote/confirm/route.js +2 -2
  47. package/dist/.next/.next/server/app/api/pull-remote/confirm/route_client-reference-manifest.js +1 -1
  48. package/dist/.next/.next/server/app/api/pull-remote/preview/route.js +4 -4
  49. package/dist/.next/.next/server/app/api/pull-remote/preview/route_client-reference-manifest.js +1 -1
  50. package/dist/.next/.next/server/app/api/push-remote/confirm/route.js +5 -5
  51. package/dist/.next/.next/server/app/api/push-remote/confirm/route_client-reference-manifest.js +1 -1
  52. package/dist/.next/.next/server/app/api/push-remote/preview/route.js +4 -4
  53. package/dist/.next/.next/server/app/api/push-remote/preview/route_client-reference-manifest.js +1 -1
  54. package/dist/.next/.next/server/app/api/query/route.js +3 -3
  55. package/dist/.next/.next/server/app/api/query/route_client-reference-manifest.js +1 -1
  56. package/dist/.next/.next/server/app/api/tables/[name]/route.js +5 -5
  57. package/dist/.next/.next/server/app/api/tables/[name]/route_client-reference-manifest.js +1 -1
  58. package/dist/.next/.next/server/app/api/tables/route.js +2 -2
  59. package/dist/.next/.next/server/app/api/tables/route_client-reference-manifest.js +1 -1
  60. package/dist/.next/.next/server/app/api/update/route.js +1 -1
  61. package/dist/.next/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  62. package/dist/.next/.next/server/app/index.html +2 -2
  63. package/dist/.next/.next/server/app/index.rsc +5 -5
  64. package/dist/.next/.next/server/app/page.js +7 -7
  65. package/dist/.next/.next/server/app/page.js.nft.json +1 -1
  66. package/dist/.next/.next/server/app/page_client-reference-manifest.js +1 -1
  67. package/dist/.next/.next/server/app-paths-manifest.json +1 -1
  68. package/dist/.next/.next/server/chunks/226.js +12 -12
  69. package/dist/.next/.next/server/chunks/391.js +1 -1
  70. package/dist/.next/.next/server/chunks/572.js +1 -0
  71. package/dist/.next/.next/server/chunks/992.js +3 -3
  72. package/dist/.next/.next/server/middleware-build-manifest.js +1 -1
  73. package/dist/.next/.next/server/next-font-manifest.js +1 -1
  74. package/dist/.next/.next/server/next-font-manifest.json +1 -1
  75. package/dist/.next/.next/server/pages/404.html +1 -1
  76. package/dist/.next/.next/server/pages/500.html +1 -1
  77. package/dist/.next/.next/server/server-reference-manifest.json +1 -1
  78. package/dist/.next/.next/static/chunks/{576-c4daf274bb6469a1.js → 576-18a2209e1ed26aad.js} +1 -1
  79. package/dist/.next/.next/static/chunks/{92-c4466e0f1ca8a3a8.js → 92-5f7522943fcb72a8.js} +1 -1
  80. package/dist/.next/.next/static/chunks/app/{layout-be6ee67cf0c92654.js → layout-40ec07d04681ba81.js} +1 -1
  81. package/dist/.next/.next/static/chunks/app/page-f05cd0fc436bf9bc.js +1 -0
  82. package/dist/.next/.next/static/chunks/{main-app-fa35024de9bd9284.js → main-app-4506e88db72db4b7.js} +1 -1
  83. package/dist/.next/.next/static/css/{9f6c25c5400f83d3.css → 7c16f57d325d0d7d.css} +1 -1
  84. package/dist/.next/.next/static/gABGrAoO8IPArDo_Ns_7g/_buildManifest.js +1 -0
  85. package/dist/.next/.next/static/gABGrAoO8IPArDo_Ns_7g/_ssgManifest.js +1 -0
  86. package/dist/.next/.next/static/gh-QfIUVo4FTTduYCVKT6/_buildManifest.js +1 -0
  87. package/dist/.next/.next/static/gh-QfIUVo4FTTduYCVKT6/_ssgManifest.js +1 -0
  88. package/dist/.next/.next/static/media/8d697b304b401681-s.woff2 +0 -0
  89. package/dist/.next/.next/static/media/9610d9e46709d722-s.woff2 +0 -0
  90. package/dist/.next/.next/static/ybCx6L6gHqtODbKmlhU-d/_buildManifest.js +1 -0
  91. package/dist/.next/.next/static/ybCx6L6gHqtODbKmlhU-d/_ssgManifest.js +1 -0
  92. package/dist/.next/.next/trace +3 -3
  93. package/dist/.next/.next/types/app/api/cloudflare/route.ts +1 -1
  94. package/dist/.next/.next/types/app/api/databases/route.ts +1 -1
  95. package/dist/.next/.next/types/app/api/migrations/sync/route.ts +1 -1
  96. package/dist/.next/.next/types/app/api/migrations/sync-files/route.ts +1 -1
  97. package/dist/.next/.next/types/app/api/pull-data/confirm/route.ts +1 -1
  98. package/dist/.next/.next/types/app/api/pull-remote/confirm/route.ts +1 -1
  99. package/dist/.next/.next/types/app/api/pull-remote/preview/route.ts +1 -1
  100. package/dist/.next/.next/types/app/api/push-remote/confirm/route.ts +1 -1
  101. package/dist/.next/.next/types/app/api/push-remote/preview/route.ts +1 -1
  102. package/dist/.next/.next/types/app/api/query/route.ts +1 -1
  103. package/dist/.next/.next/types/app/api/tables/[name]/route.ts +1 -1
  104. package/dist/.next/.next/types/app/api/tables/route.ts +1 -1
  105. package/dist/.next/.next/types/app/api/update/route.ts +1 -1
  106. package/dist/.next/.next/types/app/page.ts +1 -1
  107. package/dist/.next/BUILD_ID +1 -1
  108. package/dist/.next/app-build-manifest.json +28 -28
  109. package/dist/.next/app-path-routes-manifest.json +1 -1
  110. package/dist/.next/build-manifest.json +3 -3
  111. package/dist/.next/cache/.rscinfo +1 -1
  112. package/dist/.next/cache/.tsbuildinfo +1 -1
  113. package/dist/.next/cache/webpack/client-production/0.pack +0 -0
  114. package/dist/.next/cache/webpack/client-production/1.pack +0 -0
  115. package/dist/.next/cache/webpack/client-production/2.pack +0 -0
  116. package/dist/.next/cache/webpack/client-production/index.pack +0 -0
  117. package/dist/.next/cache/webpack/client-production/index.pack.old +0 -0
  118. package/dist/.next/cache/webpack/edge-server-production/index.pack +0 -0
  119. package/dist/.next/cache/webpack/server-production/0.pack +0 -0
  120. package/dist/.next/cache/webpack/server-production/index.pack +0 -0
  121. package/dist/.next/next-minimal-server.js.nft.json +1 -1
  122. package/dist/.next/next-server.js.nft.json +1 -1
  123. package/dist/.next/prerender-manifest.json +1 -1
  124. package/dist/.next/required-server-files.json +1 -1
  125. package/dist/.next/server/app/_not-found/page.js +1 -1
  126. package/dist/.next/server/app/_not-found/page.js.nft.json +1 -1
  127. package/dist/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  128. package/dist/.next/server/app/_not-found.html +1 -1
  129. package/dist/.next/server/app/_not-found.rsc +4 -4
  130. package/dist/.next/server/app/api/cloudflare/route.js +1 -1
  131. package/dist/.next/server/app/api/cloudflare/route_client-reference-manifest.js +1 -1
  132. package/dist/.next/server/app/api/databases/route.js +1 -1
  133. package/dist/.next/server/app/api/databases/route_client-reference-manifest.js +1 -1
  134. package/dist/.next/server/app/api/migrations/sync/route.js +5 -5
  135. package/dist/.next/server/app/api/migrations/sync/route_client-reference-manifest.js +1 -1
  136. package/dist/.next/server/app/api/migrations/sync-files/route.js +3 -3
  137. package/dist/.next/server/app/api/migrations/sync-files/route_client-reference-manifest.js +1 -1
  138. package/dist/.next/server/app/api/pull-data/confirm/route.js +1 -1
  139. package/dist/.next/server/app/api/pull-data/confirm/route_client-reference-manifest.js +1 -1
  140. package/dist/.next/server/app/api/pull-remote/confirm/route.js +2 -2
  141. package/dist/.next/server/app/api/pull-remote/confirm/route_client-reference-manifest.js +1 -1
  142. package/dist/.next/server/app/api/pull-remote/preview/route.js +4 -4
  143. package/dist/.next/server/app/api/pull-remote/preview/route_client-reference-manifest.js +1 -1
  144. package/dist/.next/server/app/api/push-remote/confirm/route.js +5 -5
  145. package/dist/.next/server/app/api/push-remote/confirm/route_client-reference-manifest.js +1 -1
  146. package/dist/.next/server/app/api/push-remote/preview/route.js +4 -4
  147. package/dist/.next/server/app/api/push-remote/preview/route_client-reference-manifest.js +1 -1
  148. package/dist/.next/server/app/api/query/route.js +3 -3
  149. package/dist/.next/server/app/api/query/route_client-reference-manifest.js +1 -1
  150. package/dist/.next/server/app/api/tables/[name]/route.js +5 -5
  151. package/dist/.next/server/app/api/tables/[name]/route_client-reference-manifest.js +1 -1
  152. package/dist/.next/server/app/api/tables/route.js +2 -2
  153. package/dist/.next/server/app/api/tables/route_client-reference-manifest.js +1 -1
  154. package/dist/.next/server/app/api/update/route.js +1 -1
  155. package/dist/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  156. package/dist/.next/server/app/index.html +2 -2
  157. package/dist/.next/server/app/index.rsc +5 -5
  158. package/dist/.next/server/app/page.js +7 -7
  159. package/dist/.next/server/app/page.js.nft.json +1 -1
  160. package/dist/.next/server/app/page_client-reference-manifest.js +1 -1
  161. package/dist/.next/server/app-paths-manifest.json +1 -1
  162. package/dist/.next/server/chunks/226.js +12 -12
  163. package/dist/.next/server/chunks/391.js +1 -1
  164. package/dist/.next/server/chunks/572.js +1 -0
  165. package/dist/.next/server/chunks/992.js +3 -3
  166. package/dist/.next/server/middleware-build-manifest.js +1 -1
  167. package/dist/.next/server/next-font-manifest.js +1 -1
  168. package/dist/.next/server/next-font-manifest.json +1 -1
  169. package/dist/.next/server/pages/404.html +1 -1
  170. package/dist/.next/server/pages/500.html +1 -1
  171. package/dist/.next/server/server-reference-manifest.json +1 -1
  172. package/dist/.next/static/IX-QLbm7scYnyqWeeimal/_buildManifest.js +1 -0
  173. package/dist/.next/static/IX-QLbm7scYnyqWeeimal/_ssgManifest.js +1 -0
  174. package/dist/.next/static/chunks/{576-c4daf274bb6469a1.js → 576-18a2209e1ed26aad.js} +1 -1
  175. package/dist/.next/static/chunks/{92-c4466e0f1ca8a3a8.js → 92-5f7522943fcb72a8.js} +1 -1
  176. package/dist/.next/static/chunks/app/{layout-be6ee67cf0c92654.js → layout-40ec07d04681ba81.js} +1 -1
  177. package/dist/.next/static/chunks/app/page-f05cd0fc436bf9bc.js +1 -0
  178. package/dist/.next/static/chunks/{main-app-fa35024de9bd9284.js → main-app-4506e88db72db4b7.js} +1 -1
  179. package/dist/.next/static/css/{9f6c25c5400f83d3.css → 7c16f57d325d0d7d.css} +1 -1
  180. package/dist/.next/static/media/8d697b304b401681-s.woff2 +0 -0
  181. package/dist/.next/static/media/9610d9e46709d722-s.woff2 +0 -0
  182. package/dist/.next/trace +3 -14
  183. package/dist/.next/types/app/api/cloudflare/route.ts +1 -1
  184. package/dist/.next/types/app/api/databases/route.ts +1 -1
  185. package/dist/.next/types/app/api/migrations/sync/route.ts +1 -1
  186. package/dist/.next/types/app/api/migrations/sync-files/route.ts +1 -1
  187. package/dist/.next/types/app/api/pull-data/confirm/route.ts +1 -1
  188. package/dist/.next/types/app/api/pull-remote/confirm/route.ts +1 -1
  189. package/dist/.next/types/app/api/pull-remote/preview/route.ts +1 -1
  190. package/dist/.next/types/app/api/push-remote/confirm/route.ts +1 -1
  191. package/dist/.next/types/app/api/push-remote/preview/route.ts +1 -1
  192. package/dist/.next/types/app/api/query/route.ts +1 -1
  193. package/dist/.next/types/app/api/tables/[name]/route.ts +1 -1
  194. package/dist/.next/types/app/api/tables/route.ts +1 -1
  195. package/dist/.next/types/app/api/update/route.ts +1 -1
  196. package/dist/.next/types/app/page.ts +1 -1
  197. package/dist/app/api/tables/[name]/route.js +22 -10
  198. package/dist/app/globals.css +39 -0
  199. package/dist/d1-studio.js +2 -2
  200. package/dist/lib/data-type-handlers.js +426 -0
  201. package/dist/lib/sql-operations.js +32 -8
  202. package/dist/lib/sql-sanitizer.js +233 -0
  203. package/package.json +3 -9
  204. package/dist/.next/.next/cache/webpack/server-production/2.pack +0 -0
  205. package/dist/.next/.next/server/chunks/90.js +0 -1
  206. package/dist/.next/.next/static/chunks/app/page-36ed30b2266617f3.js +0 -1
  207. package/dist/.next/server/chunks/90.js +0 -1
  208. package/dist/.next/static/chunks/app/page-36ed30b2266617f3.js +0 -1
  209. package/dist/app/app/api/cloudflare/route.js +0 -150
  210. package/dist/app/app/api/databases/route.js +0 -71
  211. package/dist/app/app/api/migrations/sync/route.js +0 -174
  212. package/dist/app/app/api/migrations/sync-files/route.js +0 -172
  213. package/dist/app/app/api/pull-data/confirm/route.js +0 -230
  214. package/dist/app/app/api/pull-remote/confirm/route.js +0 -278
  215. package/dist/app/app/api/pull-remote/preview/route.js +0 -144
  216. package/dist/app/app/api/push-remote/confirm/route.js +0 -196
  217. package/dist/app/app/api/push-remote/preview/route.js +0 -179
  218. package/dist/app/app/api/query/route.js +0 -168
  219. package/dist/app/app/api/tables/[name]/route.js +0 -174
  220. package/dist/app/app/api/tables/route.js +0 -178
  221. package/dist/app/app/api/update/route.js +0 -45
  222. package/dist/app/app/globals.css +0 -93
  223. package/dist/app/app/layout.jsx +0 -35
  224. package/dist/app/app/page.jsx +0 -34
  225. package/next.config.mjs +0 -18
  226. package/postcss.config.mjs +0 -8
  227. package/scripts/studio.js +0 -199
  228. package/scripts/test.js +0 -366
  229. package/src/app/api/cloudflare/route.js +0 -150
  230. package/src/app/api/databases/route.js +0 -71
  231. package/src/app/api/migrations/sync/route.js +0 -174
  232. package/src/app/api/migrations/sync-files/route.js +0 -172
  233. package/src/app/api/pull-data/confirm/route.js +0 -230
  234. package/src/app/api/pull-remote/confirm/route.js +0 -278
  235. package/src/app/api/pull-remote/preview/route.js +0 -144
  236. package/src/app/api/push-remote/confirm/route.js +0 -196
  237. package/src/app/api/push-remote/preview/route.js +0 -179
  238. package/src/app/api/query/route.js +0 -168
  239. package/src/app/api/tables/[name]/route.js +0 -174
  240. package/src/app/api/tables/route.js +0 -178
  241. package/src/app/api/update/route.js +0 -45
  242. package/src/app/globals.css +0 -93
  243. package/src/app/layout.jsx +0 -35
  244. package/src/app/page.jsx +0 -34
  245. package/src/components/cloudflare-credentials-modal.jsx +0 -94
  246. package/src/components/column-selector.jsx +0 -133
  247. package/src/components/column-sorting.jsx +0 -65
  248. package/src/components/delete-records-dialog.jsx +0 -64
  249. package/src/components/download-button.jsx +0 -205
  250. package/src/components/edit-error-alert.jsx +0 -30
  251. package/src/components/editable-cell.jsx +0 -163
  252. package/src/components/editable-row.jsx +0 -169
  253. package/src/components/environment-handler.jsx +0 -332
  254. package/src/components/environment-select.jsx +0 -62
  255. package/src/components/pull-preview-toast.jsx +0 -215
  256. package/src/components/push-error-alert.jsx +0 -72
  257. package/src/components/push-preview-toast.jsx +0 -183
  258. package/src/components/query-results.jsx +0 -112
  259. package/src/components/refresh-button.jsx +0 -61
  260. package/src/components/resize-columns.jsx +0 -101
  261. package/src/components/sidebar.jsx +0 -254
  262. package/src/components/sql-editor.jsx +0 -411
  263. package/src/components/sql-error-display.jsx +0 -167
  264. package/src/components/sync-migrations-button.jsx +0 -87
  265. package/src/components/table-error-dialog.jsx +0 -65
  266. package/src/components/table-toolbar.jsx +0 -285
  267. package/src/components/table-view.jsx +0 -843
  268. package/src/components/ui/alert.jsx +0 -47
  269. package/src/components/ui/button.jsx +0 -48
  270. package/src/components/ui/card.jsx +0 -50
  271. package/src/components/ui/checkbox.jsx +0 -24
  272. package/src/components/ui/collapsible.jsx +0 -11
  273. package/src/components/ui/dialog.jsx +0 -96
  274. package/src/components/ui/dropdown-menu.jsx +0 -158
  275. package/src/components/ui/input.jsx +0 -19
  276. package/src/components/ui/scroll-area.jsx +0 -40
  277. package/src/components/ui/select.jsx +0 -121
  278. package/src/components/ui/separator.jsx +0 -25
  279. package/src/components/ui/sheet.jsx +0 -109
  280. package/src/components/ui/sidebar.jsx +0 -620
  281. package/src/components/ui/skeleton.jsx +0 -14
  282. package/src/components/ui/table.jsx +0 -86
  283. package/src/components/ui/tabs.jsx +0 -43
  284. package/src/components/ui/toast.jsx +0 -86
  285. package/src/components/ui/toaster.jsx +0 -35
  286. package/src/components/ui/tooltip.jsx +0 -28
  287. package/src/components/update-banner.jsx +0 -93
  288. package/src/context/database-context.js +0 -510
  289. package/src/hooks/use-mobile.jsx +0 -19
  290. package/src/hooks/use-sql-error.ts +0 -23
  291. package/src/hooks/use-toast.js +0 -155
  292. package/src/lib/database-queue.js +0 -37
  293. package/src/lib/error.js +0 -20
  294. package/src/lib/find-wrangler-config.js +0 -74
  295. package/src/lib/license.js +0 -99
  296. package/src/lib/logger.js +0 -58
  297. package/src/lib/migrations.js +0 -415
  298. package/src/lib/parse-sql-error.js +0 -200
  299. package/src/lib/request-deduplication.js +0 -24
  300. package/src/lib/schema-operations.js +0 -106
  301. package/src/lib/sql-error-types.js +0 -14
  302. package/src/lib/sql-operations.js +0 -647
  303. package/src/lib/utils.js +0 -6
  304. package/src/lib/version-utils.js +0 -34
  305. /package/dist/.next/.next/static/{OUHnbB-64afrrZQL0Srn5 → Y9mYu4WBghepP5oT_3OdR}/_buildManifest.js +0 -0
  306. /package/dist/.next/.next/static/{OUHnbB-64afrrZQL0Srn5 → Y9mYu4WBghepP5oT_3OdR}/_ssgManifest.js +0 -0
  307. /package/dist/.next/.next/static/{ZBTCAyp1kO5FdEHMU-Dw2 → ae3gNmoSGm-R5LJC4UagI}/_buildManifest.js +0 -0
  308. /package/dist/.next/.next/static/{ZBTCAyp1kO5FdEHMU-Dw2 → ae3gNmoSGm-R5LJC4UagI}/_ssgManifest.js +0 -0
  309. /package/dist/.next/.next/static/{bHYW7fgIBDF8-Q33_WPoE → bKfUJeuvAQlBmR3TjrfkH}/_buildManifest.js +0 -0
  310. /package/dist/.next/.next/static/{bHYW7fgIBDF8-Q33_WPoE → bKfUJeuvAQlBmR3TjrfkH}/_ssgManifest.js +0 -0
  311. /package/dist/.next/{static/ZBTCAyp1kO5FdEHMU-Dw2 → .next/static/ejYPqJ2kVicVp5EFWOZIC}/_buildManifest.js +0 -0
  312. /package/dist/.next/{static/ZBTCAyp1kO5FdEHMU-Dw2 → .next/static/ejYPqJ2kVicVp5EFWOZIC}/_ssgManifest.js +0 -0
@@ -1,4 +1,4 @@
1
- // File: /Users/kona/Desktop/d1studio/src/app/api/cloudflare/route.js
1
+ // File: /Volumes/ProjectSpace/_wip/d1studio/src/app/api/cloudflare/route.js
2
2
  import * as entry from '../../../../../src/app/api/cloudflare/route.js'
3
3
  import type { NextRequest } from 'next/server.js'
4
4
 
@@ -1,4 +1,4 @@
1
- // File: /Users/kona/Desktop/d1studio/src/app/api/databases/route.js
1
+ // File: /Volumes/ProjectSpace/_wip/d1studio/src/app/api/databases/route.js
2
2
  import * as entry from '../../../../../src/app/api/databases/route.js'
3
3
  import type { NextRequest } from 'next/server.js'
4
4
 
@@ -1,4 +1,4 @@
1
- // File: /Users/kona/Desktop/d1studio/src/app/api/migrations/sync/route.js
1
+ // File: /Volumes/ProjectSpace/_wip/d1studio/src/app/api/migrations/sync/route.js
2
2
  import * as entry from '../../../../../../src/app/api/migrations/sync/route.js'
3
3
  import type { NextRequest } from 'next/server.js'
4
4
 
@@ -1,4 +1,4 @@
1
- // File: /Users/kona/Desktop/d1studio/src/app/api/migrations/sync-files/route.js
1
+ // File: /Volumes/ProjectSpace/_wip/d1studio/src/app/api/migrations/sync-files/route.js
2
2
  import * as entry from '../../../../../../src/app/api/migrations/sync-files/route.js'
3
3
  import type { NextRequest } from 'next/server.js'
4
4
 
@@ -1,4 +1,4 @@
1
- // File: /Users/kona/Desktop/d1studio/src/app/api/pull-data/confirm/route.js
1
+ // File: /Volumes/ProjectSpace/_wip/d1studio/src/app/api/pull-data/confirm/route.js
2
2
  import * as entry from '../../../../../../src/app/api/pull-data/confirm/route.js'
3
3
  import type { NextRequest } from 'next/server.js'
4
4
 
@@ -1,4 +1,4 @@
1
- // File: /Users/kona/Desktop/d1studio/src/app/api/pull-remote/confirm/route.js
1
+ // File: /Volumes/ProjectSpace/_wip/d1studio/src/app/api/pull-remote/confirm/route.js
2
2
  import * as entry from '../../../../../../src/app/api/pull-remote/confirm/route.js'
3
3
  import type { NextRequest } from 'next/server.js'
4
4
 
@@ -1,4 +1,4 @@
1
- // File: /Users/kona/Desktop/d1studio/src/app/api/pull-remote/preview/route.js
1
+ // File: /Volumes/ProjectSpace/_wip/d1studio/src/app/api/pull-remote/preview/route.js
2
2
  import * as entry from '../../../../../../src/app/api/pull-remote/preview/route.js'
3
3
  import type { NextRequest } from 'next/server.js'
4
4
 
@@ -1,4 +1,4 @@
1
- // File: /Users/kona/Desktop/d1studio/src/app/api/push-remote/confirm/route.js
1
+ // File: /Volumes/ProjectSpace/_wip/d1studio/src/app/api/push-remote/confirm/route.js
2
2
  import * as entry from '../../../../../../src/app/api/push-remote/confirm/route.js'
3
3
  import type { NextRequest } from 'next/server.js'
4
4
 
@@ -1,4 +1,4 @@
1
- // File: /Users/kona/Desktop/d1studio/src/app/api/push-remote/preview/route.js
1
+ // File: /Volumes/ProjectSpace/_wip/d1studio/src/app/api/push-remote/preview/route.js
2
2
  import * as entry from '../../../../../../src/app/api/push-remote/preview/route.js'
3
3
  import type { NextRequest } from 'next/server.js'
4
4
 
@@ -1,4 +1,4 @@
1
- // File: /Users/kona/Desktop/d1studio/src/app/api/query/route.js
1
+ // File: /Volumes/ProjectSpace/_wip/d1studio/src/app/api/query/route.js
2
2
  import * as entry from '../../../../../src/app/api/query/route.js'
3
3
  import type { NextRequest } from 'next/server.js'
4
4
 
@@ -1,4 +1,4 @@
1
- // File: /Users/kona/Desktop/d1studio/src/app/api/tables/[name]/route.js
1
+ // File: /Volumes/ProjectSpace/_wip/d1studio/src/app/api/tables/[name]/route.js
2
2
  import * as entry from '../../../../../../src/app/api/tables/[name]/route.js'
3
3
  import type { NextRequest } from 'next/server.js'
4
4
 
@@ -1,4 +1,4 @@
1
- // File: /Users/kona/Desktop/d1studio/src/app/api/tables/route.js
1
+ // File: /Volumes/ProjectSpace/_wip/d1studio/src/app/api/tables/route.js
2
2
  import * as entry from '../../../../../src/app/api/tables/route.js'
3
3
  import type { NextRequest } from 'next/server.js'
4
4
 
@@ -1,4 +1,4 @@
1
- // File: /Users/kona/Desktop/d1studio/src/app/api/update/route.js
1
+ // File: /Volumes/ProjectSpace/_wip/d1studio/src/app/api/update/route.js
2
2
  import * as entry from '../../../../../src/app/api/update/route.js'
3
3
  import type { NextRequest } from 'next/server.js'
4
4
 
@@ -1,4 +1,4 @@
1
- // File: /Users/kona/Desktop/d1studio/src/app/page.jsx
1
+ // File: /Volumes/ProjectSpace/_wip/d1studio/src/app/page.jsx
2
2
  import * as entry from '../../../src/app/page.js'
3
3
  import type { ResolvingMetadata, ResolvingViewport } from 'next/dist/lib/metadata/types/metadata-interface.js'
4
4
 
@@ -6,6 +6,7 @@ import { exec } from 'child_process';
6
6
  import { findWranglerConfig } from '@/lib/find-wrangler-config.js';
7
7
  import { dbQueue } from '@/lib/database-queue';
8
8
  import logger from '@/lib/logger';
9
+ import { sanitizeTableName, sanitizeColumnName } from '@/lib/sql-sanitizer.js';
9
10
 
10
11
  const execAsync = promisify(exec);
11
12
 
@@ -98,13 +99,18 @@ export async function GET(request, context) {
98
99
  // Get the first D1 database name from the configuration
99
100
  const databaseName = config.d1_databases[0].database_name;
100
101
 
101
- // Get table schema using PRAGMA query
102
- const schemaQuery = `PRAGMA table_info(${name});`;
102
+ // Validate and sanitize table name to prevent SQL injection
103
+ const sanitizedTableName = sanitizeTableName(name);
104
+
105
+ // Get table schema using PRAGMA query (PRAGMA is safe from injection when table name is sanitized)
106
+ const schemaQuery = `PRAGMA table_info(${sanitizedTableName});`;
103
107
  const schema = await executeD1Query(schemaQuery, projectDir, databaseName);
104
108
 
105
- // Get the CREATE TABLE statement from sqlite_master
106
- const createTableQuery = `SELECT sql FROM sqlite_master WHERE type='table' AND name='${name}';`;
107
- const tableDefinition = await executeD1Query(createTableQuery, projectDir, databaseName);
109
+ // Get the CREATE TABLE statement from sqlite_master using parameterized query approach
110
+ const createTableQuery = `SELECT sql FROM sqlite_master WHERE type='table' AND name = ?;`;
111
+ // Note: executeD1Query would need to support parameters, for now we sanitize the table name
112
+ const createTableQuerySafe = `SELECT sql FROM sqlite_master WHERE type='table' AND name='${name.replace(/'/g, "''")}';`;
113
+ const tableDefinition = await executeD1Query(createTableQuerySafe, projectDir, databaseName);
108
114
  const createTableSQL = tableDefinition[0]?.sql || '';
109
115
 
110
116
  // Extract CHECK constraints from the CREATE TABLE statement
@@ -116,17 +122,23 @@ export async function GET(request, context) {
116
122
  check: checkConstraints[column.name] || null
117
123
  }));
118
124
 
119
- // Get total row count for the table
120
- const countQuery = `SELECT COUNT(*) as total FROM ${name};`;
125
+ // Get total row count for the table (using sanitized table name)
126
+ const countQuery = `SELECT COUNT(*) as total FROM ${sanitizedTableName};`;
121
127
  const countResult = await executeD1Query(countQuery, projectDir, databaseName);
122
128
  const totalRows = countResult[0]?.total || 0;
123
129
 
124
130
  // Fetch paginated data using the primary key column for ordering
125
131
  const primaryKeyColumn = schema.find(col => col.pk === 1)?.name || schema[0]?.name;
132
+ const sanitizedPrimaryKey = primaryKeyColumn ? sanitizeColumnName(primaryKeyColumn) : '*';
133
+
134
+ // Validate limit and offset to prevent injection through URL params
135
+ const safeLimitNum = Math.max(1, Math.min(parseInt(limit) || 50, 1000)); // Cap at 1000 rows
136
+ const safeOffsetNum = Math.max(0, parseInt(offset) || 0);
137
+
126
138
  const dataQuery = `
127
- SELECT * FROM ${name}
128
- ORDER BY ${primaryKeyColumn} DESC
129
- LIMIT ${limit} OFFSET ${offset};
139
+ SELECT * FROM ${sanitizedTableName}
140
+ ORDER BY ${sanitizedPrimaryKey} DESC
141
+ LIMIT ${safeLimitNum} OFFSET ${safeOffsetNum};
130
142
  `;
131
143
  const data = await executeD1Query(dataQuery, projectDir, databaseName);
132
144
 
@@ -91,3 +91,42 @@ body {
91
91
  table-layout: fixed;
92
92
  width: 100%;
93
93
  }
94
+
95
+ /* Custom gray utility classes */
96
+ @layer utilities {
97
+ .bg-gray-custom-50 { background-color: var(--gray-50); }
98
+ .bg-gray-custom-100 { background-color: var(--gray-100); }
99
+ .bg-gray-custom-200 { background-color: var(--gray-200); }
100
+ .bg-gray-custom-300 { background-color: var(--gray-300); }
101
+ .bg-gray-custom-400 { background-color: var(--gray-400); }
102
+ .bg-gray-custom-500 { background-color: var(--gray-500); }
103
+ .bg-gray-custom-600 { background-color: var(--gray-600); }
104
+ .bg-gray-custom-700 { background-color: var(--gray-700); }
105
+ .bg-gray-custom-800 { background-color: var(--gray-800); }
106
+ .bg-gray-custom-900 { background-color: var(--gray-900); }
107
+ .bg-gray-custom-950 { background-color: var(--gray-950); }
108
+
109
+ .text-gray-custom-50 { color: var(--gray-50); }
110
+ .text-gray-custom-100 { color: var(--gray-100); }
111
+ .text-gray-custom-200 { color: var(--gray-200); }
112
+ .text-gray-custom-300 { color: var(--gray-300); }
113
+ .text-gray-custom-400 { color: var(--gray-400); }
114
+ .text-gray-custom-500 { color: var(--gray-500); }
115
+ .text-gray-custom-600 { color: var(--gray-600); }
116
+ .text-gray-custom-700 { color: var(--gray-700); }
117
+ .text-gray-custom-800 { color: var(--gray-800); }
118
+ .text-gray-custom-900 { color: var(--gray-900); }
119
+ .text-gray-custom-950 { color: var(--gray-950); }
120
+
121
+ .border-gray-custom-50 { border-color: var(--gray-50); }
122
+ .border-gray-custom-100 { border-color: var(--gray-100); }
123
+ .border-gray-custom-200 { border-color: var(--gray-200); }
124
+ .border-gray-custom-300 { border-color: var(--gray-300); }
125
+ .border-gray-custom-400 { border-color: var(--gray-400); }
126
+ .border-gray-custom-500 { border-color: var(--gray-500); }
127
+ .border-gray-custom-600 { border-color: var(--gray-600); }
128
+ .border-gray-custom-700 { border-color: var(--gray-700); }
129
+ .border-gray-custom-800 { border-color: var(--gray-800); }
130
+ .border-gray-custom-900 { border-color: var(--gray-900); }
131
+ .border-gray-custom-950 { border-color: var(--gray-950); }
132
+ }
package/dist/d1-studio.js CHANGED
@@ -6,8 +6,8 @@ import { dirname, join } from 'path';
6
6
  import express from 'express';
7
7
  import { createServer } from 'http';
8
8
  import next from 'next';
9
- import { findWranglerConfig } from '../src/lib/find-wrangler-config.js';
10
- import logger from '../src/lib/logger.js';
9
+ import { findWranglerConfig } from './lib/find-wrangler-config.js';
10
+ import logger from './lib/logger.js';
11
11
  import updateNotifier from 'update-notifier';
12
12
  import pkg from '../package.json' with { type: 'json' };
13
13
 
@@ -0,0 +1,426 @@
1
+ /**
2
+ * Data Type Handlers for Enhanced Database Operations
3
+ * Provides validation, formatting, and display logic for various data types
4
+ */
5
+
6
+ /**
7
+ * UUID validation regex - supports all UUID versions (1-5)
8
+ */
9
+ const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
10
+
11
+ /**
12
+ * Data type handlers with validation, formatting, and display logic
13
+ */
14
+ export const DataTypeHandlers = {
15
+ uuid: {
16
+ validate: (value) => {
17
+ if (!value || typeof value !== 'string') return false;
18
+ return UUID_REGEX.test(value);
19
+ },
20
+ format: (value) => {
21
+ if (!value) return null;
22
+ return value.toLowerCase().trim();
23
+ },
24
+ display: (value) => {
25
+ if (!value) return '';
26
+ if (value.length <= 16) return value;
27
+ return value.substring(0, 8) + '...' + value.substring(value.length - 8);
28
+ },
29
+ editComponent: 'input',
30
+ editProps: {
31
+ type: 'text',
32
+ placeholder: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
33
+ pattern: UUID_REGEX.source,
34
+ title: 'Enter a valid UUID (e.g., 123e4567-e89b-12d3-a456-426614174000)'
35
+ }
36
+ },
37
+
38
+ text: {
39
+ validate: (value) => {
40
+ return typeof value === 'string' || value === null || value === undefined;
41
+ },
42
+ format: (value) => {
43
+ if (value === null || value === undefined) return null;
44
+ return String(value);
45
+ },
46
+ display: (value) => {
47
+ if (!value) return '';
48
+ if (value.length <= 50) return value;
49
+ return value.substring(0, 50) + '...';
50
+ },
51
+ editComponent: 'input',
52
+ editProps: { type: 'text' }
53
+ },
54
+
55
+ longText: {
56
+ validate: (value) => {
57
+ return typeof value === 'string' || value === null || value === undefined;
58
+ },
59
+ format: (value) => {
60
+ if (value === null || value === undefined) return null;
61
+ return String(value);
62
+ },
63
+ display: (value) => {
64
+ if (!value) return '';
65
+ if (value.length <= 100) return value;
66
+ return value.substring(0, 100) + '...';
67
+ },
68
+ editComponent: 'textarea',
69
+ editProps: {
70
+ rows: 4,
71
+ placeholder: 'Enter long text content...'
72
+ }
73
+ },
74
+
75
+ json: {
76
+ validate: (value) => {
77
+ if (value === null || value === undefined) return true;
78
+ if (typeof value === 'string') {
79
+ try {
80
+ JSON.parse(value);
81
+ return true;
82
+ } catch {
83
+ return false;
84
+ }
85
+ }
86
+ return typeof value === 'object';
87
+ },
88
+ format: (value) => {
89
+ if (value === null || value === undefined) return null;
90
+ if (typeof value === 'string') {
91
+ try {
92
+ // Validate JSON by parsing, then return original string
93
+ JSON.parse(value);
94
+ return value;
95
+ } catch {
96
+ throw new Error('Invalid JSON format');
97
+ }
98
+ }
99
+ return JSON.stringify(value);
100
+ },
101
+ display: (value) => {
102
+ if (!value) return '';
103
+ const formatted = typeof value === 'string' ? value : JSON.stringify(value);
104
+ if (formatted.length <= 50) return formatted;
105
+ return formatted.substring(0, 50) + '...';
106
+ },
107
+ editComponent: 'textarea',
108
+ editProps: {
109
+ rows: 6,
110
+ placeholder: 'Enter valid JSON...',
111
+ className: 'font-mono'
112
+ }
113
+ },
114
+
115
+ integer: {
116
+ validate: (value) => {
117
+ if (value === null || value === undefined) return true;
118
+ return Number.isInteger(Number(value));
119
+ },
120
+ format: (value) => {
121
+ if (value === null || value === undefined) return null;
122
+ const num = Number(value);
123
+ if (!Number.isInteger(num)) {
124
+ throw new Error('Value must be an integer');
125
+ }
126
+ return num;
127
+ },
128
+ display: (value) => {
129
+ if (value === null || value === undefined) return '';
130
+ return String(value);
131
+ },
132
+ editComponent: 'input',
133
+ editProps: {
134
+ type: 'number',
135
+ step: '1',
136
+ pattern: '[0-9-]+'
137
+ }
138
+ },
139
+
140
+ real: {
141
+ validate: (value) => {
142
+ if (value === null || value === undefined) return true;
143
+ return !isNaN(Number(value)) && isFinite(Number(value));
144
+ },
145
+ format: (value) => {
146
+ if (value === null || value === undefined) return null;
147
+ const num = Number(value);
148
+ if (isNaN(num) || !isFinite(num)) {
149
+ throw new Error('Value must be a valid number');
150
+ }
151
+ return num;
152
+ },
153
+ display: (value) => {
154
+ if (value === null || value === undefined) return '';
155
+ return String(value);
156
+ },
157
+ editComponent: 'input',
158
+ editProps: {
159
+ type: 'number',
160
+ step: 'any'
161
+ }
162
+ },
163
+
164
+ boolean: {
165
+ validate: (value) => {
166
+ if (value === null || value === undefined) return true;
167
+ return typeof value === 'boolean' || value === 'true' || value === 'false' || value === 1 || value === 0;
168
+ },
169
+ format: (value) => {
170
+ if (value === null || value === undefined) return null;
171
+ if (typeof value === 'boolean') return value;
172
+ if (value === 'true' || value === 1) return true;
173
+ if (value === 'false' || value === 0) return false;
174
+ throw new Error('Value must be a boolean');
175
+ },
176
+ display: (value) => {
177
+ if (value === null || value === undefined) return '';
178
+ return value ? 'true' : 'false';
179
+ },
180
+ editComponent: 'select',
181
+ editProps: {
182
+ options: [
183
+ { value: '', label: 'NULL' },
184
+ { value: 'true', label: 'True' },
185
+ { value: 'false', label: 'False' }
186
+ ]
187
+ }
188
+ },
189
+
190
+ date: {
191
+ validate: (value) => {
192
+ if (value === null || value === undefined) return true;
193
+ return !isNaN(Date.parse(value));
194
+ },
195
+ format: (value) => {
196
+ if (value === null || value === undefined) return null;
197
+ const date = new Date(value);
198
+ if (isNaN(date.getTime())) {
199
+ throw new Error('Value must be a valid date');
200
+ }
201
+ return date.toISOString().split('T')[0];
202
+ },
203
+ display: (value) => {
204
+ if (!value) return '';
205
+ return value;
206
+ },
207
+ editComponent: 'input',
208
+ editProps: { type: 'date' }
209
+ },
210
+
211
+ datetime: {
212
+ validate: (value) => {
213
+ if (value === null || value === undefined) return true;
214
+ return !isNaN(Date.parse(value));
215
+ },
216
+ format: (value) => {
217
+ if (value === null || value === undefined) return null;
218
+ const date = new Date(value);
219
+ if (isNaN(date.getTime())) {
220
+ throw new Error('Value must be a valid datetime');
221
+ }
222
+ return date.toISOString();
223
+ },
224
+ display: (value) => {
225
+ if (!value) return '';
226
+ return new Date(value).toLocaleString();
227
+ },
228
+ editComponent: 'input',
229
+ editProps: { type: 'datetime-local' }
230
+ },
231
+
232
+ blob: {
233
+ validate: (value) => {
234
+ // For blob data, we typically handle as base64 strings or Buffer objects
235
+ if (value === null || value === undefined) return true;
236
+ return typeof value === 'string' || Buffer.isBuffer(value);
237
+ },
238
+ format: (value) => {
239
+ if (value === null || value === undefined) return null;
240
+ return value; // Keep as-is for blob data
241
+ },
242
+ display: (value) => {
243
+ if (!value) return '';
244
+ if (typeof value === 'string') {
245
+ return `<BLOB: ${value.length} chars>`;
246
+ }
247
+ if (Buffer.isBuffer(value)) {
248
+ return `<BLOB: ${value.length} bytes>`;
249
+ }
250
+ return '<BLOB>';
251
+ },
252
+ editComponent: 'input',
253
+ editProps: {
254
+ type: 'file',
255
+ accept: '*/*'
256
+ }
257
+ }
258
+ };
259
+
260
+ /**
261
+ * Detects the data type of a value based on its content
262
+ * @param {any} value - The value to analyze
263
+ * @returns {string} - The detected data type
264
+ */
265
+ export function detectDataType(value) {
266
+ if (value === null || value === undefined) return 'text';
267
+
268
+ if (typeof value === 'string') {
269
+ // Check for UUID pattern
270
+ if (UUID_REGEX.test(value)) return 'uuid';
271
+
272
+ // Check for JSON
273
+ try {
274
+ JSON.parse(value);
275
+ return 'json';
276
+ } catch {
277
+ // Not JSON, continue checking
278
+ }
279
+
280
+ // Check for date/datetime
281
+ if (!isNaN(Date.parse(value))) {
282
+ // Simple heuristic: if it looks like a full datetime, classify as datetime
283
+ if (value.includes('T') || value.includes(' ')) return 'datetime';
284
+ return 'date';
285
+ }
286
+
287
+ // Check for boolean
288
+ if (value === 'true' || value === 'false') return 'boolean';
289
+
290
+ // Check for number
291
+ if (!isNaN(Number(value)) && isFinite(Number(value))) {
292
+ return Number.isInteger(Number(value)) ? 'integer' : 'real';
293
+ }
294
+
295
+ // Long text heuristic
296
+ if (value.length > 255) return 'longText';
297
+
298
+ return 'text';
299
+ }
300
+
301
+ if (typeof value === 'number') {
302
+ return Number.isInteger(value) ? 'integer' : 'real';
303
+ }
304
+
305
+ if (typeof value === 'boolean') return 'boolean';
306
+
307
+ if (typeof value === 'object') return 'json';
308
+
309
+ if (Buffer.isBuffer(value)) return 'blob';
310
+
311
+ return 'text';
312
+ }
313
+
314
+ /**
315
+ * Gets the appropriate data type handler for a value
316
+ * @param {any} value - The value to get a handler for
317
+ * @returns {Object} - The data type handler
318
+ */
319
+ export function getDataTypeHandler(value) {
320
+ const type = detectDataType(value);
321
+ return DataTypeHandlers[type] || DataTypeHandlers.text;
322
+ }
323
+
324
+ /**
325
+ * Validates a value against its detected or specified data type
326
+ * @param {any} value - The value to validate
327
+ * @param {string} dataType - Optional explicit data type
328
+ * @returns {boolean} - True if valid
329
+ */
330
+ export function validateValue(value, dataType = null) {
331
+ const type = dataType || detectDataType(value);
332
+ const handler = DataTypeHandlers[type];
333
+
334
+ if (!handler) {
335
+ throw new Error(`Unknown data type: ${type}`);
336
+ }
337
+
338
+ return handler.validate(value);
339
+ }
340
+
341
+ /**
342
+ * Formats a value according to its data type
343
+ * @param {any} value - The value to format
344
+ * @param {string} dataType - Optional explicit data type
345
+ * @returns {any} - The formatted value
346
+ */
347
+ export function formatValue(value, dataType = null) {
348
+ const type = dataType || detectDataType(value);
349
+ const handler = DataTypeHandlers[type];
350
+
351
+ if (!handler) {
352
+ throw new Error(`Unknown data type: ${type}`);
353
+ }
354
+
355
+ return handler.format(value);
356
+ }
357
+
358
+ /**
359
+ * Gets display representation of a value
360
+ * @param {any} value - The value to display
361
+ * @param {string} dataType - Optional explicit data type
362
+ * @returns {string} - The display string
363
+ */
364
+ export function getDisplayValue(value, dataType = null) {
365
+ const type = dataType || detectDataType(value);
366
+ const handler = DataTypeHandlers[type];
367
+
368
+ if (!handler) {
369
+ return String(value || '');
370
+ }
371
+
372
+ return handler.display(value);
373
+ }
374
+
375
+ /**
376
+ * Enhanced WHERE clause builder with UUID support
377
+ * @param {Object} conditions - Conditions object
378
+ * @param {Object} options - Options for comparison operators
379
+ * @returns {Object} - WHERE clause and parameters
380
+ */
381
+ export function buildEnhancedWhereClause(conditions, options = {}) {
382
+ if (!conditions || typeof conditions !== 'object') {
383
+ throw new Error('Conditions must be an object');
384
+ }
385
+
386
+ const entries = Object.entries(conditions);
387
+ if (entries.length === 0) {
388
+ return { whereClause: '', params: [] };
389
+ }
390
+
391
+ const clauses = [];
392
+ const params = [];
393
+
394
+ for (const [column, value] of entries) {
395
+ const operator = options.operators?.[column] || '=';
396
+ const dataType = options.dataTypes?.[column] || detectDataType(value);
397
+
398
+ // Handle different operators
399
+ if (operator === 'LIKE') {
400
+ clauses.push(`${column} LIKE ?`);
401
+ params.push(`%${value}%`);
402
+ } else if (operator === 'IN') {
403
+ if (!Array.isArray(value)) {
404
+ throw new Error(`IN operator requires an array value for column ${column}`);
405
+ }
406
+ const placeholders = value.map(() => '?').join(', ');
407
+ clauses.push(`${column} IN (${placeholders})`);
408
+ params.push(...value);
409
+ } else if (operator === 'BETWEEN') {
410
+ if (!Array.isArray(value) || value.length !== 2) {
411
+ throw new Error(`BETWEEN operator requires an array of 2 values for column ${column}`);
412
+ }
413
+ clauses.push(`${column} BETWEEN ? AND ?`);
414
+ params.push(value[0], value[1]);
415
+ } else {
416
+ // Standard operators: =, !=, <, >, <=, >=
417
+ clauses.push(`${column} ${operator} ?`);
418
+ params.push(formatValue(value, dataType));
419
+ }
420
+ }
421
+
422
+ return {
423
+ whereClause: clauses.join(' AND '),
424
+ params: params
425
+ };
426
+ }