d1s 0.2.11 → 0.2.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.next/.next/BUILD_ID +1 -1
- package/dist/.next/.next/app-build-manifest.json +28 -28
- package/dist/.next/.next/app-path-routes-manifest.json +1 -1
- package/dist/.next/.next/build-manifest.json +3 -3
- package/dist/.next/.next/cache/.rscinfo +1 -1
- package/dist/.next/.next/cache/.tsbuildinfo +1 -1
- package/dist/.next/.next/cache/webpack/client-production/0.pack +0 -0
- package/dist/.next/.next/cache/webpack/client-production/1.pack +0 -0
- package/dist/.next/.next/cache/webpack/client-production/10.pack +0 -0
- package/dist/.next/.next/cache/webpack/client-production/11.pack +0 -0
- package/dist/.next/.next/cache/webpack/client-production/12.pack +0 -0
- package/dist/.next/.next/cache/webpack/client-production/2.pack +0 -0
- package/dist/.next/.next/cache/webpack/client-production/3.pack +0 -0
- package/dist/.next/.next/cache/webpack/client-production/4.pack +0 -0
- package/dist/.next/.next/cache/webpack/client-production/5.pack +0 -0
- package/dist/.next/.next/cache/webpack/client-production/6.pack +0 -0
- package/dist/.next/.next/cache/webpack/client-production/7.pack +0 -0
- package/dist/.next/.next/cache/webpack/client-production/8.pack +0 -0
- package/dist/.next/.next/cache/webpack/client-production/9.pack +0 -0
- package/dist/.next/.next/cache/webpack/client-production/index.pack +0 -0
- package/dist/.next/.next/cache/webpack/client-production/index.pack.old +0 -0
- package/dist/.next/.next/cache/webpack/edge-server-production/index.pack +0 -0
- package/dist/.next/.next/cache/webpack/server-production/0.pack +0 -0
- package/dist/.next/.next/cache/webpack/server-production/1.pack +0 -0
- package/dist/.next/.next/cache/webpack/server-production/2.pack +0 -0
- package/dist/.next/.next/cache/webpack/server-production/3.pack +0 -0
- package/dist/.next/.next/cache/webpack/server-production/index.pack +0 -0
- package/dist/.next/.next/cache/webpack/server-production/index.pack.old +0 -0
- package/dist/.next/.next/next-minimal-server.js.nft.json +1 -1
- package/dist/.next/.next/next-server.js.nft.json +1 -1
- package/dist/.next/.next/prerender-manifest.json +1 -1
- package/dist/.next/.next/required-server-files.json +1 -1
- package/dist/.next/.next/server/app/_not-found/page.js +1 -1
- package/dist/.next/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/dist/.next/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/.next/.next/server/app/_not-found.html +1 -1
- package/dist/.next/.next/server/app/_not-found.rsc +4 -4
- package/dist/.next/.next/server/app/api/cloudflare/route.js +1 -1
- package/dist/.next/.next/server/app/api/cloudflare/route_client-reference-manifest.js +1 -1
- package/dist/.next/.next/server/app/api/databases/route.js +1 -1
- package/dist/.next/.next/server/app/api/databases/route_client-reference-manifest.js +1 -1
- package/dist/.next/.next/server/app/api/migrations/sync/route.js +5 -5
- package/dist/.next/.next/server/app/api/migrations/sync/route_client-reference-manifest.js +1 -1
- package/dist/.next/.next/server/app/api/migrations/sync-files/route.js +3 -3
- package/dist/.next/.next/server/app/api/migrations/sync-files/route_client-reference-manifest.js +1 -1
- package/dist/.next/.next/server/app/api/pull-data/confirm/route.js +1 -1
- package/dist/.next/.next/server/app/api/pull-data/confirm/route_client-reference-manifest.js +1 -1
- package/dist/.next/.next/server/app/api/pull-remote/confirm/route.js +2 -2
- package/dist/.next/.next/server/app/api/pull-remote/confirm/route_client-reference-manifest.js +1 -1
- package/dist/.next/.next/server/app/api/pull-remote/preview/route.js +4 -4
- package/dist/.next/.next/server/app/api/pull-remote/preview/route_client-reference-manifest.js +1 -1
- package/dist/.next/.next/server/app/api/push-remote/confirm/route.js +5 -5
- package/dist/.next/.next/server/app/api/push-remote/confirm/route_client-reference-manifest.js +1 -1
- package/dist/.next/.next/server/app/api/push-remote/preview/route.js +4 -4
- package/dist/.next/.next/server/app/api/push-remote/preview/route_client-reference-manifest.js +1 -1
- package/dist/.next/.next/server/app/api/query/route.js +3 -3
- package/dist/.next/.next/server/app/api/query/route_client-reference-manifest.js +1 -1
- package/dist/.next/.next/server/app/api/tables/[name]/route.js +5 -5
- package/dist/.next/.next/server/app/api/tables/[name]/route_client-reference-manifest.js +1 -1
- package/dist/.next/.next/server/app/api/tables/route.js +2 -2
- package/dist/.next/.next/server/app/api/tables/route_client-reference-manifest.js +1 -1
- package/dist/.next/.next/server/app/api/update/route.js +1 -1
- package/dist/.next/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
- package/dist/.next/.next/server/app/index.html +2 -2
- package/dist/.next/.next/server/app/index.rsc +5 -5
- package/dist/.next/.next/server/app/page.js +7 -7
- package/dist/.next/.next/server/app/page.js.nft.json +1 -1
- package/dist/.next/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/.next/.next/server/app-paths-manifest.json +1 -1
- package/dist/.next/.next/server/chunks/226.js +12 -12
- package/dist/.next/.next/server/chunks/391.js +1 -1
- package/dist/.next/.next/server/chunks/572.js +1 -0
- package/dist/.next/.next/server/chunks/992.js +3 -3
- package/dist/.next/.next/server/middleware-build-manifest.js +1 -1
- package/dist/.next/.next/server/next-font-manifest.js +1 -1
- package/dist/.next/.next/server/next-font-manifest.json +1 -1
- package/dist/.next/.next/server/pages/404.html +1 -1
- package/dist/.next/.next/server/pages/500.html +1 -1
- package/dist/.next/.next/server/server-reference-manifest.json +1 -1
- package/dist/.next/.next/static/chunks/{576-c4daf274bb6469a1.js → 576-18a2209e1ed26aad.js} +1 -1
- package/dist/.next/.next/static/chunks/{92-c4466e0f1ca8a3a8.js → 92-5f7522943fcb72a8.js} +1 -1
- package/dist/.next/.next/static/chunks/app/{layout-be6ee67cf0c92654.js → layout-40ec07d04681ba81.js} +1 -1
- package/dist/.next/.next/static/chunks/app/page-f05cd0fc436bf9bc.js +1 -0
- package/dist/.next/.next/static/chunks/app/page-f2bc307c0d8acdaa.js +1 -0
- package/dist/.next/.next/static/chunks/{main-app-fa35024de9bd9284.js → main-app-4506e88db72db4b7.js} +1 -1
- package/dist/.next/.next/static/css/{9f6c25c5400f83d3.css → 7c16f57d325d0d7d.css} +1 -1
- package/dist/.next/.next/static/ejYPqJ2kVicVp5EFWOZIC/_buildManifest.js +1 -0
- package/dist/.next/.next/static/ejYPqJ2kVicVp5EFWOZIC/_ssgManifest.js +1 -0
- package/dist/.next/.next/static/gABGrAoO8IPArDo_Ns_7g/_buildManifest.js +1 -0
- package/dist/.next/.next/static/gABGrAoO8IPArDo_Ns_7g/_ssgManifest.js +1 -0
- package/dist/.next/.next/static/gh-QfIUVo4FTTduYCVKT6/_buildManifest.js +1 -0
- package/dist/.next/.next/static/gh-QfIUVo4FTTduYCVKT6/_ssgManifest.js +1 -0
- package/dist/.next/.next/static/media/8d697b304b401681-s.woff2 +0 -0
- package/dist/.next/.next/static/media/9610d9e46709d722-s.woff2 +0 -0
- package/dist/.next/.next/static/thaCy2qVeNqYYhdayr13C/_buildManifest.js +1 -0
- package/dist/.next/.next/static/thaCy2qVeNqYYhdayr13C/_ssgManifest.js +1 -0
- package/dist/.next/.next/static/ybCx6L6gHqtODbKmlhU-d/_buildManifest.js +1 -0
- package/dist/.next/.next/static/ybCx6L6gHqtODbKmlhU-d/_ssgManifest.js +1 -0
- package/dist/.next/.next/trace +3 -3
- package/dist/.next/.next/types/app/api/cloudflare/route.ts +1 -1
- package/dist/.next/.next/types/app/api/databases/route.ts +1 -1
- package/dist/.next/.next/types/app/api/migrations/sync/route.ts +1 -1
- package/dist/.next/.next/types/app/api/migrations/sync-files/route.ts +1 -1
- package/dist/.next/.next/types/app/api/pull-data/confirm/route.ts +1 -1
- package/dist/.next/.next/types/app/api/pull-remote/confirm/route.ts +1 -1
- package/dist/.next/.next/types/app/api/pull-remote/preview/route.ts +1 -1
- package/dist/.next/.next/types/app/api/push-remote/confirm/route.ts +1 -1
- package/dist/.next/.next/types/app/api/push-remote/preview/route.ts +1 -1
- package/dist/.next/.next/types/app/api/query/route.ts +1 -1
- package/dist/.next/.next/types/app/api/tables/[name]/route.ts +1 -1
- package/dist/.next/.next/types/app/api/tables/route.ts +1 -1
- package/dist/.next/.next/types/app/api/update/route.ts +1 -1
- package/dist/.next/.next/types/app/page.ts +1 -1
- package/dist/.next/BUILD_ID +1 -1
- package/dist/.next/app-build-manifest.json +28 -28
- package/dist/.next/app-path-routes-manifest.json +1 -1
- package/dist/.next/build-manifest.json +3 -3
- package/dist/.next/cache/.rscinfo +1 -1
- package/dist/.next/cache/.tsbuildinfo +1 -1
- package/dist/.next/cache/webpack/client-production/0.pack +0 -0
- package/dist/.next/cache/webpack/client-production/1.pack +0 -0
- package/dist/.next/cache/webpack/client-production/2.pack +0 -0
- package/dist/.next/cache/webpack/client-production/index.pack +0 -0
- package/dist/.next/cache/webpack/client-production/index.pack.old +0 -0
- package/dist/.next/cache/webpack/edge-server-production/index.pack +0 -0
- package/dist/.next/cache/webpack/server-production/0.pack +0 -0
- package/dist/.next/cache/webpack/server-production/index.pack +0 -0
- package/dist/.next/next-minimal-server.js.nft.json +1 -1
- package/dist/.next/next-server.js.nft.json +1 -1
- package/dist/.next/prerender-manifest.json +1 -1
- package/dist/.next/required-server-files.json +1 -1
- package/dist/.next/server/app/_not-found/page.js +1 -1
- package/dist/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/dist/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/_not-found.html +1 -1
- package/dist/.next/server/app/_not-found.rsc +4 -4
- package/dist/.next/server/app/api/cloudflare/route.js +1 -1
- package/dist/.next/server/app/api/cloudflare/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/databases/route.js +1 -1
- package/dist/.next/server/app/api/databases/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/migrations/sync/route.js +5 -5
- package/dist/.next/server/app/api/migrations/sync/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/migrations/sync-files/route.js +3 -3
- package/dist/.next/server/app/api/migrations/sync-files/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/pull-data/confirm/route.js +1 -1
- package/dist/.next/server/app/api/pull-data/confirm/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/pull-remote/confirm/route.js +2 -2
- package/dist/.next/server/app/api/pull-remote/confirm/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/pull-remote/preview/route.js +4 -4
- package/dist/.next/server/app/api/pull-remote/preview/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/push-remote/confirm/route.js +5 -5
- package/dist/.next/server/app/api/push-remote/confirm/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/push-remote/preview/route.js +4 -4
- package/dist/.next/server/app/api/push-remote/preview/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/query/route.js +3 -3
- package/dist/.next/server/app/api/query/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/tables/[name]/route.js +5 -5
- package/dist/.next/server/app/api/tables/[name]/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/tables/route.js +2 -2
- package/dist/.next/server/app/api/tables/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/update/route.js +1 -1
- package/dist/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/index.html +2 -2
- package/dist/.next/server/app/index.rsc +5 -5
- package/dist/.next/server/app/page.js +7 -7
- package/dist/.next/server/app/page.js.nft.json +1 -1
- package/dist/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/.next/server/app-paths-manifest.json +1 -1
- package/dist/.next/server/chunks/226.js +12 -12
- package/dist/.next/server/chunks/391.js +1 -1
- package/dist/.next/server/chunks/572.js +1 -0
- package/dist/.next/server/chunks/992.js +3 -3
- package/dist/.next/server/middleware-build-manifest.js +1 -1
- package/dist/.next/server/next-font-manifest.js +1 -1
- package/dist/.next/server/next-font-manifest.json +1 -1
- package/dist/.next/server/pages/404.html +1 -1
- package/dist/.next/server/pages/500.html +1 -1
- package/dist/.next/server/server-reference-manifest.json +1 -1
- package/dist/.next/static/IX-QLbm7scYnyqWeeimal/_buildManifest.js +1 -0
- package/dist/.next/static/IX-QLbm7scYnyqWeeimal/_ssgManifest.js +1 -0
- package/dist/.next/static/chunks/{576-c4daf274bb6469a1.js → 576-18a2209e1ed26aad.js} +1 -1
- package/dist/.next/static/chunks/{92-c4466e0f1ca8a3a8.js → 92-5f7522943fcb72a8.js} +1 -1
- package/dist/.next/static/chunks/app/{layout-be6ee67cf0c92654.js → layout-40ec07d04681ba81.js} +1 -1
- package/dist/.next/static/chunks/app/page-f05cd0fc436bf9bc.js +1 -0
- package/dist/.next/static/chunks/{main-app-fa35024de9bd9284.js → main-app-4506e88db72db4b7.js} +1 -1
- package/dist/.next/static/css/{9f6c25c5400f83d3.css → 7c16f57d325d0d7d.css} +1 -1
- package/dist/.next/static/media/8d697b304b401681-s.woff2 +0 -0
- package/dist/.next/static/media/9610d9e46709d722-s.woff2 +0 -0
- package/dist/.next/trace +3 -14
- package/dist/.next/types/app/api/cloudflare/route.ts +1 -1
- package/dist/.next/types/app/api/databases/route.ts +1 -1
- package/dist/.next/types/app/api/migrations/sync/route.ts +1 -1
- package/dist/.next/types/app/api/migrations/sync-files/route.ts +1 -1
- package/dist/.next/types/app/api/pull-data/confirm/route.ts +1 -1
- package/dist/.next/types/app/api/pull-remote/confirm/route.ts +1 -1
- package/dist/.next/types/app/api/pull-remote/preview/route.ts +1 -1
- package/dist/.next/types/app/api/push-remote/confirm/route.ts +1 -1
- package/dist/.next/types/app/api/push-remote/preview/route.ts +1 -1
- package/dist/.next/types/app/api/query/route.ts +1 -1
- package/dist/.next/types/app/api/tables/[name]/route.ts +1 -1
- package/dist/.next/types/app/api/tables/route.ts +1 -1
- package/dist/.next/types/app/api/update/route.ts +1 -1
- package/dist/.next/types/app/page.ts +1 -1
- package/dist/app/api/tables/[name]/route.js +22 -10
- package/dist/app/globals.css +39 -0
- package/dist/d1-studio.js +2 -2
- package/dist/lib/data-type-handlers.js +426 -0
- package/dist/lib/sql-operations.js +32 -8
- package/dist/lib/sql-sanitizer.js +233 -0
- package/package.json +3 -9
- package/dist/.next/.next/server/chunks/90.js +0 -1
- package/dist/.next/.next/static/chunks/app/page-36ed30b2266617f3.js +0 -1
- package/dist/.next/server/chunks/90.js +0 -1
- package/dist/.next/static/chunks/app/page-36ed30b2266617f3.js +0 -1
- package/dist/app/app/api/cloudflare/route.js +0 -150
- package/dist/app/app/api/databases/route.js +0 -71
- package/dist/app/app/api/migrations/sync/route.js +0 -174
- package/dist/app/app/api/migrations/sync-files/route.js +0 -172
- package/dist/app/app/api/pull-data/confirm/route.js +0 -230
- package/dist/app/app/api/pull-remote/confirm/route.js +0 -278
- package/dist/app/app/api/pull-remote/preview/route.js +0 -144
- package/dist/app/app/api/push-remote/confirm/route.js +0 -196
- package/dist/app/app/api/push-remote/preview/route.js +0 -179
- package/dist/app/app/api/query/route.js +0 -168
- package/dist/app/app/api/tables/[name]/route.js +0 -174
- package/dist/app/app/api/tables/route.js +0 -178
- package/dist/app/app/api/update/route.js +0 -45
- package/dist/app/app/globals.css +0 -93
- package/dist/app/app/layout.jsx +0 -35
- package/dist/app/app/page.jsx +0 -34
- package/next.config.mjs +0 -18
- package/postcss.config.mjs +0 -8
- package/scripts/studio.js +0 -199
- package/scripts/test.js +0 -366
- package/src/app/api/cloudflare/route.js +0 -150
- package/src/app/api/databases/route.js +0 -71
- package/src/app/api/migrations/sync/route.js +0 -174
- package/src/app/api/migrations/sync-files/route.js +0 -172
- package/src/app/api/pull-data/confirm/route.js +0 -230
- package/src/app/api/pull-remote/confirm/route.js +0 -278
- package/src/app/api/pull-remote/preview/route.js +0 -144
- package/src/app/api/push-remote/confirm/route.js +0 -196
- package/src/app/api/push-remote/preview/route.js +0 -179
- package/src/app/api/query/route.js +0 -168
- package/src/app/api/tables/[name]/route.js +0 -174
- package/src/app/api/tables/route.js +0 -178
- package/src/app/api/update/route.js +0 -45
- package/src/app/globals.css +0 -93
- package/src/app/layout.jsx +0 -35
- package/src/app/page.jsx +0 -34
- package/src/components/cloudflare-credentials-modal.jsx +0 -94
- package/src/components/column-selector.jsx +0 -133
- package/src/components/column-sorting.jsx +0 -65
- package/src/components/delete-records-dialog.jsx +0 -64
- package/src/components/download-button.jsx +0 -205
- package/src/components/edit-error-alert.jsx +0 -30
- package/src/components/editable-cell.jsx +0 -163
- package/src/components/editable-row.jsx +0 -169
- package/src/components/environment-handler.jsx +0 -332
- package/src/components/environment-select.jsx +0 -62
- package/src/components/pull-preview-toast.jsx +0 -215
- package/src/components/push-error-alert.jsx +0 -72
- package/src/components/push-preview-toast.jsx +0 -183
- package/src/components/query-results.jsx +0 -112
- package/src/components/refresh-button.jsx +0 -61
- package/src/components/resize-columns.jsx +0 -101
- package/src/components/sidebar.jsx +0 -254
- package/src/components/sql-editor.jsx +0 -411
- package/src/components/sql-error-display.jsx +0 -167
- package/src/components/sync-migrations-button.jsx +0 -87
- package/src/components/table-error-dialog.jsx +0 -65
- package/src/components/table-toolbar.jsx +0 -285
- package/src/components/table-view.jsx +0 -843
- package/src/components/ui/alert.jsx +0 -47
- package/src/components/ui/button.jsx +0 -48
- package/src/components/ui/card.jsx +0 -50
- package/src/components/ui/checkbox.jsx +0 -24
- package/src/components/ui/collapsible.jsx +0 -11
- package/src/components/ui/dialog.jsx +0 -96
- package/src/components/ui/dropdown-menu.jsx +0 -158
- package/src/components/ui/input.jsx +0 -19
- package/src/components/ui/scroll-area.jsx +0 -40
- package/src/components/ui/select.jsx +0 -121
- package/src/components/ui/separator.jsx +0 -25
- package/src/components/ui/sheet.jsx +0 -109
- package/src/components/ui/sidebar.jsx +0 -620
- package/src/components/ui/skeleton.jsx +0 -14
- package/src/components/ui/table.jsx +0 -86
- package/src/components/ui/tabs.jsx +0 -43
- package/src/components/ui/toast.jsx +0 -86
- package/src/components/ui/toaster.jsx +0 -35
- package/src/components/ui/tooltip.jsx +0 -28
- package/src/components/update-banner.jsx +0 -93
- package/src/context/database-context.js +0 -510
- package/src/hooks/use-mobile.jsx +0 -19
- package/src/hooks/use-sql-error.ts +0 -23
- package/src/hooks/use-toast.js +0 -155
- package/src/lib/database-queue.js +0 -37
- package/src/lib/error.js +0 -20
- package/src/lib/find-wrangler-config.js +0 -74
- package/src/lib/license.js +0 -99
- package/src/lib/logger.js +0 -58
- package/src/lib/migrations.js +0 -415
- package/src/lib/parse-sql-error.js +0 -200
- package/src/lib/request-deduplication.js +0 -24
- package/src/lib/schema-operations.js +0 -106
- package/src/lib/sql-error-types.js +0 -14
- package/src/lib/sql-operations.js +0 -647
- package/src/lib/utils.js +0 -6
- package/src/lib/version-utils.js +0 -34
- /package/dist/.next/.next/static/{OUHnbB-64afrrZQL0Srn5 → FEsQ9jwPUQv5A3fwg6Opl}/_buildManifest.js +0 -0
- /package/dist/.next/.next/static/{OUHnbB-64afrrZQL0Srn5 → FEsQ9jwPUQv5A3fwg6Opl}/_ssgManifest.js +0 -0
- /package/dist/.next/.next/static/{ZBTCAyp1kO5FdEHMU-Dw2 → Y9mYu4WBghepP5oT_3OdR}/_buildManifest.js +0 -0
- /package/dist/.next/.next/static/{ZBTCAyp1kO5FdEHMU-Dw2 → Y9mYu4WBghepP5oT_3OdR}/_ssgManifest.js +0 -0
- /package/dist/.next/.next/static/{bHYW7fgIBDF8-Q33_WPoE → ae3gNmoSGm-R5LJC4UagI}/_buildManifest.js +0 -0
- /package/dist/.next/.next/static/{bHYW7fgIBDF8-Q33_WPoE → ae3gNmoSGm-R5LJC4UagI}/_ssgManifest.js +0 -0
- /package/dist/.next/{static/ZBTCAyp1kO5FdEHMU-Dw2 → .next/static/bKfUJeuvAQlBmR3TjrfkH}/_buildManifest.js +0 -0
- /package/dist/.next/{static/ZBTCAyp1kO5FdEHMU-Dw2 → .next/static/bKfUJeuvAQlBmR3TjrfkH}/_ssgManifest.js +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// File: /
|
|
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: /
|
|
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: /
|
|
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: /
|
|
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: /
|
|
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: /
|
|
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: /
|
|
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: /
|
|
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: /
|
|
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: /
|
|
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: /
|
|
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
|
-
//
|
|
102
|
-
const
|
|
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=
|
|
107
|
-
|
|
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 ${
|
|
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 ${
|
|
128
|
-
ORDER BY ${
|
|
129
|
-
LIMIT ${
|
|
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
|
|
package/dist/app/globals.css
CHANGED
|
@@ -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 '
|
|
10
|
-
import logger from '
|
|
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
|
+
}
|