datapeek 0.1.12 → 0.1.14
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/README.md +38 -9
- package/dist/cli/dev.js +225 -52
- package/dist/cli/index.js +225 -52
- package/dist/client/assets/index-CVuQr9d7.js +385 -0
- package/dist/client/assets/index-Ys_niuVH.css +1 -0
- package/dist/client/index.html +2 -2
- package/dist/client/screenshots/dark1.png +0 -0
- package/dist/client/screenshots/dark2.png +0 -0
- package/dist/client/screenshots/light1.png +0 -0
- package/dist/client/screenshots/light2.png +0 -0
- package/dist/server/dev.js +225 -52
- package/dist/server/index.js +225 -52
- package/package.json +1 -1
- package/dist/client/assets/index-BXssAVuE.css +0 -1
- package/dist/client/assets/index-DgwSpfvt.js +0 -378
|
@@ -0,0 +1 @@
|
|
|
1
|
+
*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}:root{--background: 0 0% 100%;--foreground: 222.2 84% 4.9%;--card: 0 0% 100%;--card-foreground: 222.2 84% 4.9%;--popover: 0 0% 100%;--popover-foreground: 222.2 84% 4.9%;--primary: 222.2 47.4% 11.2%;--primary-foreground: 210 40% 98%;--secondary: 210 40% 96.1%;--secondary-foreground: 222.2 47.4% 11.2%;--muted: 210 40% 96.1%;--muted-foreground: 215.4 16.3% 46.9%;--accent: 210 40% 96.1%;--accent-foreground: 222.2 47.4% 11.2%;--destructive: 0 84.2% 60.2%;--destructive-foreground: 210 40% 98%;--border: 214.3 31.8% 91.4%;--input: 214.3 31.8% 91.4%;--ring: 222.2 84% 4.9%;--radius: .5rem;--chart-1: 12 76% 61%;--chart-2: 173 58% 39%;--chart-3: 197 37% 24%;--chart-4: 43 74% 66%;--chart-5: 27 87% 67%;--header-bg: 0 0% 100%;--sidebar-bg: 0 0% 100%;--content-bg: 0 0% 100%;--tabs-bg: 0 0% 100%;--grid-bg: 0 0% 100%}.dark{--background: 222.2 84% 4.9%;--foreground: 210 40% 98%;--card: 222.2 84% 4.9%;--card-foreground: 210 40% 98%;--popover: 222.2 84% 4.9%;--popover-foreground: 210 40% 98%;--primary: 210 40% 98%;--primary-foreground: 222.2 47.4% 11.2%;--secondary: 217.2 32.6% 17.5%;--secondary-foreground: 210 40% 98%;--muted: 217.2 32.6% 17.5%;--muted-foreground: 215 20.2% 65.1%;--accent: 217.2 32.6% 17.5%;--accent-foreground: 210 40% 98%;--destructive: 0 70% 55%;--destructive-foreground: 210 40% 98%;--border: 217.2 32.6% 17.5%;--input: 217.2 32.6% 17.5%;--ring: 212.7 26.8% 83.9%;--chart-1: 220 70% 50%;--chart-2: 160 60% 45%;--chart-3: 30 80% 55%;--chart-4: 280 65% 60%;--chart-5: 340 75% 55%;--header-bg: 222.2 84% 6.5%;--sidebar-bg: 222.2 84% 5.5%;--content-bg: 222.2 84% 4.9%;--tabs-bg: 222.2 84% 5.2%;--grid-bg: 222.2 84% 5%}*{border-color:hsl(var(--border))}body{background-color:hsl(var(--background));color:hsl(var(--foreground));font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif}code,pre{font-family:JetBrains Mono,Menlo,Monaco,Courier New,monospace}.container{width:100%}@media(min-width:640px){.container{max-width:640px}}@media(min-width:768px){.container{max-width:768px}}@media(min-width:1024px){.container{max-width:1024px}}@media(min-width:1280px){.container{max-width:1280px}}@media(min-width:1536px){.container{max-width:1536px}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{top:0;right:0;bottom:0;left:0}.bottom-0{bottom:0}.left-0{left:0}.left-2{left:.5rem}.right-0{right:0}.right-2{right:.5rem}.right-3{right:.75rem}.right-4{right:1rem}.top-0{top:0}.top-1\/2{top:50%}.top-4{top:1rem}.top-full{top:100%}.z-10{z-index:10}.z-20{z-index:20}.z-50{z-index:50}.z-\[100\]{z-index:100}.m-2{margin:.5rem}.mx-1{margin-left:.25rem;margin-right:.25rem}.mx-auto{margin-left:auto;margin-right:auto}.my-1{margin-top:.25rem;margin-bottom:.25rem}.-mb-px{margin-bottom:-1px}.mb-2{margin-bottom:.5rem}.mb-4{margin-bottom:1rem}.ml-2{margin-left:.5rem}.ml-4{margin-left:1rem}.ml-auto{margin-left:auto}.mr-1{margin-right:.25rem}.mr-1\.5{margin-right:.375rem}.mr-2{margin-right:.5rem}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-1\.5{margin-top:.375rem}.mt-2{margin-top:.5rem}.block{display:block}.flex{display:flex}.inline-flex{display:inline-flex}.\!table{display:table!important}.table{display:table}.grid{display:grid}.hidden{display:none}.h-1{height:.25rem}.h-10{height:2.5rem}.h-12{height:3rem}.h-2{height:.5rem}.h-3{height:.75rem}.h-3\.5{height:.875rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-64{height:16rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-9{height:2.25rem}.h-auto{height:auto}.h-full{height:100%}.h-px{height:1px}.h-screen{height:100vh}.max-h-48{max-height:12rem}.max-h-64{max-height:16rem}.max-h-96{max-height:24rem}.max-h-\[400px\]{max-height:400px}.max-h-\[95vh\]{max-height:95vh}.max-h-\[calc\(100vh-16px\)\]{max-height:calc(100vh - 16px)}.min-h-\[240px\]{min-height:240px}.w-12{width:3rem}.w-2{width:.5rem}.w-3{width:.75rem}.w-3\.5{width:.875rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-64{width:16rem}.w-7{width:1.75rem}.w-72{width:18rem}.w-8{width:2rem}.w-9{width:2.25rem}.w-auto{width:auto}.w-full{width:100%}.w-px{width:1px}.min-w-0{min-width:0px}.min-w-\[200px\]{min-width:200px}.min-w-\[280px\]{min-width:280px}.min-w-\[600px\]{min-width:600px}.min-w-\[8rem\]{min-width:8rem}.max-w-\[220px\]{max-width:220px}.max-w-\[300px\]{max-width:300px}.max-w-\[3800px\]{max-width:3800px}.max-w-\[400px\]{max-width:400px}.max-w-md{max-width:28rem}.flex-1{flex:1 1 0%}.flex-shrink-0,.shrink-0{flex-shrink:0}.border-collapse{border-collapse:collapse}.-translate-y-1\/2{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-cell{cursor:cell}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.cursor-row-resize{cursor:row-resize}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.resize-none{resize:none}.resize{resize:both}.list-inside{list-style-position:inside}.list-disc{list-style-type:disc}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-\[1fr_150px\]{grid-template-columns:1fr 150px}.grid-cols-\[1fr_200px\]{grid-template-columns:1fr 200px}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0\.5{gap:.125rem}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.5rem * var(--tw-space-x-reverse));margin-left:calc(.5rem * calc(1 - var(--tw-space-x-reverse)))}.space-y-0\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.125rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.125rem * var(--tw-space-y-reverse))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-1\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.375rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.break-words{overflow-wrap:break-word}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:var(--radius)}.rounded-md{border-radius:calc(var(--radius) - 2px)}.rounded-sm{border-radius:calc(var(--radius) - 4px)}.border{border-width:1px}.border-b{border-bottom-width:1px}.border-b-2{border-bottom-width:2px}.border-l{border-left-width:1px}.border-l-2{border-left-width:2px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-border{border-color:hsl(var(--border))}.border-border\/40{border-color:hsl(var(--border) / .4)}.border-border\/50{border-color:hsl(var(--border) / .5)}.border-gray-300{--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity, 1))}.border-input{border-color:hsl(var(--input))}.border-primary{border-color:hsl(var(--primary))}.bg-accent{background-color:hsl(var(--accent))}.bg-background{background-color:hsl(var(--background))}.bg-background\/80{background-color:hsl(var(--background) / .8)}.bg-black\/50{background-color:#00000080}.bg-border{background-color:hsl(var(--border))}.bg-card{background-color:hsl(var(--card))}.bg-content-bg{background-color:hsl(var(--content-bg))}.bg-destructive{background-color:hsl(var(--destructive))}.bg-destructive\/10{background-color:hsl(var(--destructive) / .1)}.bg-destructive\/90{background-color:hsl(var(--destructive) / .9)}.bg-green-500{--tw-bg-opacity: 1;background-color:rgb(34 197 94 / var(--tw-bg-opacity, 1))}.bg-green-500\/10{background-color:#22c55e1a}.bg-grid-bg{background-color:hsl(var(--grid-bg))}.bg-header-bg{background-color:hsl(var(--header-bg))}.bg-muted{background-color:hsl(var(--muted))}.bg-muted\/30{background-color:hsl(var(--muted) / .3)}.bg-muted\/50{background-color:hsl(var(--muted) / .5)}.bg-popover{background-color:hsl(var(--popover))}.bg-primary{background-color:hsl(var(--primary))}.bg-primary\/20{background-color:hsl(var(--primary) / .2)}.bg-primary\/90{background-color:hsl(var(--primary) / .9)}.bg-secondary{background-color:hsl(var(--secondary))}.bg-secondary\/80{background-color:hsl(var(--secondary) / .8)}.bg-sidebar-bg{background-color:hsl(var(--sidebar-bg))}.bg-tabs-bg{background-color:hsl(var(--tabs-bg))}.bg-transparent{background-color:transparent}.fill-yellow-500{fill:#eab308}.p-0{padding:0}.p-0\.5{padding:.125rem}.p-1{padding:.25rem}.p-1\.5{padding:.375rem}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-8{padding-left:2rem;padding-right:2rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-8{padding-top:2rem;padding-bottom:2rem}.pb-3{padding-bottom:.75rem}.pl-4{padding-left:1rem}.pl-7{padding-left:1.75rem}.pl-8{padding-left:2rem}.pr-8{padding-right:2rem}.pt-0{padding-top:0}.pt-1{padding-top:.25rem}.pt-1\.5{padding-top:.375rem}.pt-2{padding-top:.5rem}.pt-3{padding-top:.75rem}.text-left{text-align:left}.text-center{text-align:center}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-\[10px\]{font-size:10px}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.lowercase{text-transform:lowercase}.italic{font-style:italic}.leading-none{line-height:1}.tracking-tight{letter-spacing:-.025em}.text-accent-foreground{color:hsl(var(--accent-foreground))}.text-blue-600{--tw-text-opacity: 1;color:rgb(37 99 235 / var(--tw-text-opacity, 1))}.text-card-foreground{color:hsl(var(--card-foreground))}.text-destructive{color:hsl(var(--destructive))}.text-destructive-foreground{color:hsl(var(--destructive-foreground))}.text-foreground{color:hsl(var(--foreground))}.text-green-600{--tw-text-opacity: 1;color:rgb(22 163 74 / var(--tw-text-opacity, 1))}.text-muted-foreground{color:hsl(var(--muted-foreground))}.text-popover-foreground{color:hsl(var(--popover-foreground))}.text-primary{color:hsl(var(--primary))}.text-primary-foreground{color:hsl(var(--primary-foreground))}.text-secondary-foreground{color:hsl(var(--secondary-foreground))}.text-yellow-500{--tw-text-opacity: 1;color:rgb(234 179 8 / var(--tw-text-opacity, 1))}.underline{text-decoration-line:underline}.underline-offset-4{text-underline-offset:4px}.opacity-0{opacity:0}.opacity-30{opacity:.3}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.opacity-70{opacity:.7}.shadow{--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1);--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.outline-none{outline:2px solid transparent;outline-offset:2px}.outline{outline-style:solid}.ring-offset-background{--tw-ring-offset-color: hsl(var(--background))}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.backdrop-blur-sm{--tw-backdrop-blur: blur(4px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}@keyframes enter{0%{opacity:var(--tw-enter-opacity, 1);transform:translate3d(var(--tw-enter-translate-x, 0),var(--tw-enter-translate-y, 0),0) scale3d(var(--tw-enter-scale, 1),var(--tw-enter-scale, 1),var(--tw-enter-scale, 1)) rotate(var(--tw-enter-rotate, 0))}}@keyframes exit{to{opacity:var(--tw-exit-opacity, 1);transform:translate3d(var(--tw-exit-translate-x, 0),var(--tw-exit-translate-y, 0),0) scale3d(var(--tw-exit-scale, 1),var(--tw-exit-scale, 1),var(--tw-exit-scale, 1)) rotate(var(--tw-exit-rotate, 0))}}.file\:border-0::file-selector-button{border-width:0px}.file\:bg-transparent::file-selector-button{background-color:transparent}.file\:text-sm::file-selector-button{font-size:.875rem;line-height:1.25rem}.file\:font-medium::file-selector-button{font-weight:500}.placeholder\:text-muted-foreground::-moz-placeholder{color:hsl(var(--muted-foreground))}.placeholder\:text-muted-foreground::placeholder{color:hsl(var(--muted-foreground))}.last\:border-b-0:last-child{border-bottom-width:0px}.last\:border-r-0:last-child{border-right-width:0px}.hover\:bg-accent:hover{background-color:hsl(var(--accent))}.hover\:bg-accent\/80:hover{background-color:hsl(var(--accent) / .8)}.hover\:bg-destructive\/10:hover{background-color:hsl(var(--destructive) / .1)}.hover\:bg-destructive\/90:hover{background-color:hsl(var(--destructive) / .9)}.hover\:bg-green-500\/20:hover{background-color:#22c55e33}.hover\:bg-muted\/30:hover{background-color:hsl(var(--muted) / .3)}.hover\:bg-muted\/70:hover{background-color:hsl(var(--muted) / .7)}.hover\:bg-primary\/50:hover{background-color:hsl(var(--primary) / .5)}.hover\:bg-primary\/90:hover{background-color:hsl(var(--primary) / .9)}.hover\:bg-secondary\/80:hover{background-color:hsl(var(--secondary) / .8)}.hover\:bg-transparent:hover{background-color:transparent}.hover\:text-accent-foreground:hover{color:hsl(var(--accent-foreground))}.hover\:text-destructive:hover{color:hsl(var(--destructive))}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-100:hover{opacity:1}.focus\:bg-accent:focus{background-color:hsl(var(--accent))}.focus\:bg-destructive\/10:focus{background-color:hsl(var(--destructive) / .1)}.focus\:text-accent-foreground:focus{color:hsl(var(--accent-foreground))}.focus\:text-destructive:focus{color:hsl(var(--destructive))}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-2:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-ring:focus{--tw-ring-color: hsl(var(--ring))}.focus\:ring-offset-2:focus{--tw-ring-offset-width: 2px}.focus-visible\:outline-none:focus-visible{outline:2px solid transparent;outline-offset:2px}.focus-visible\:ring-1:focus-visible{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus-visible\:ring-ring:focus-visible{--tw-ring-color: hsl(var(--ring))}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}.group:hover .group-hover\:ml-0{margin-left:0}.group:hover .group-hover\:opacity-100{opacity:1}.peer:disabled~.peer-disabled\:cursor-not-allowed{cursor:not-allowed}.peer:disabled~.peer-disabled\:opacity-70{opacity:.7}.data-\[disabled\]\:pointer-events-none[data-disabled]{pointer-events:none}.data-\[disabled\]\:opacity-50[data-disabled]{opacity:.5}.dark\:bg-content-bg:is(.dark *){background-color:hsl(var(--content-bg))}.dark\:bg-grid-bg:is(.dark *){background-color:hsl(var(--grid-bg))}.dark\:bg-header-bg:is(.dark *){background-color:hsl(var(--header-bg))}.dark\:bg-muted\/40:is(.dark *){background-color:hsl(var(--muted) / .4)}.dark\:bg-sidebar-bg:is(.dark *){background-color:hsl(var(--sidebar-bg))}.dark\:bg-tabs-bg:is(.dark *){background-color:hsl(var(--tabs-bg))}.dark\:text-blue-400:is(.dark *){--tw-text-opacity: 1;color:rgb(96 165 250 / var(--tw-text-opacity, 1))}.dark\:text-green-400:is(.dark *){--tw-text-opacity: 1;color:rgb(74 222 128 / var(--tw-text-opacity, 1))}@media(min-width:640px){.sm\:rounded-lg{border-radius:var(--radius)}.sm\:text-left{text-align:left}}
|
package/dist/client/index.html
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
<link rel="icon" type="image/png" href="/favicon.png" />
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
7
|
<title>Datapeek - SQL Database Browser</title>
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-
|
|
9
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-CVuQr9d7.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="/assets/index-Ys_niuVH.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
12
12
|
<div id="root"></div>
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/dist/server/dev.js
CHANGED
|
@@ -54,8 +54,15 @@ connectionRoutes.post("/test", async (req, res) => {
|
|
|
54
54
|
}
|
|
55
55
|
});
|
|
56
56
|
connectionRoutes.get("/provided", (req, res) => {
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
try {
|
|
58
|
+
const connString = getProvidedConnectionString();
|
|
59
|
+
res.json({ connectionString: connString || null });
|
|
60
|
+
} catch (error) {
|
|
61
|
+
res.status(500).json({
|
|
62
|
+
connectionString: null,
|
|
63
|
+
error: error.message || "Failed to get connection string"
|
|
64
|
+
});
|
|
65
|
+
}
|
|
59
66
|
});
|
|
60
67
|
connectionRoutes.post("/", async (req, res) => {
|
|
61
68
|
const timeout = setTimeout(() => {
|
|
@@ -158,12 +165,17 @@ tableRoutes.get("/", async (req, res) => {
|
|
|
158
165
|
const result = await executeQuery(query);
|
|
159
166
|
res.json(result);
|
|
160
167
|
} catch (error) {
|
|
168
|
+
console.error("Error fetching tables:", error);
|
|
161
169
|
const errorMessage = error.message || "";
|
|
162
170
|
if (errorMessage.includes("Login failed") || errorMessage.includes("authentication") || errorMessage.includes("password authentication")) {
|
|
163
171
|
const { disconnect: disconnect2 } = await import("./db-CJPCGHL3.js");
|
|
164
172
|
await disconnect2();
|
|
165
173
|
}
|
|
166
|
-
|
|
174
|
+
const errorDetails = error.originalError?.message || error.originalError?.info?.message || error.message || "Failed to fetch tables";
|
|
175
|
+
res.status(500).json({
|
|
176
|
+
error: error.message || "Failed to fetch tables",
|
|
177
|
+
details: errorDetails
|
|
178
|
+
});
|
|
167
179
|
}
|
|
168
180
|
});
|
|
169
181
|
tableRoutes.get("/:schema/:table", async (req, res) => {
|
|
@@ -220,13 +232,13 @@ tableRoutes.get("/:schema/:table", async (req, res) => {
|
|
|
220
232
|
) fk ON c.table_schema = fk.table_schema
|
|
221
233
|
AND c.table_name = fk.table_name
|
|
222
234
|
AND c.column_name = fk.column_name
|
|
223
|
-
WHERE c.table_schema =
|
|
224
|
-
AND c.table_name =
|
|
235
|
+
WHERE c.table_schema = ${dialect.param(1)}
|
|
236
|
+
AND c.table_name = ${dialect.param(2)}
|
|
225
237
|
ORDER BY c.ordinal_position
|
|
226
238
|
`;
|
|
227
239
|
const result = await executeQuery(query, [
|
|
228
|
-
{ name: "
|
|
229
|
-
{ name: "
|
|
240
|
+
{ name: "p1", value: schema },
|
|
241
|
+
{ name: "p2", value: table }
|
|
230
242
|
]);
|
|
231
243
|
res.json(result);
|
|
232
244
|
} catch (error) {
|
|
@@ -314,9 +326,9 @@ tableRoutes.get("/:schema/:table/data", async (req, res) => {
|
|
|
314
326
|
WHERE table_schema = ${dialect.param(1)} AND table_name = ${dialect.param(2)} AND column_name IN (${placeholders})
|
|
315
327
|
`;
|
|
316
328
|
const validateParams = [
|
|
317
|
-
{ name: "
|
|
318
|
-
{ name: "
|
|
319
|
-
...columnNames.map((col) => ({ name:
|
|
329
|
+
{ name: "p1", value: schema },
|
|
330
|
+
{ name: "p2", value: table },
|
|
331
|
+
...columnNames.map((col, idx) => ({ name: `p${idx + 3}`, value: col }))
|
|
320
332
|
];
|
|
321
333
|
const validateResult = await executeQuery(validateQuery, validateParams);
|
|
322
334
|
validateResult.forEach((r) => {
|
|
@@ -356,75 +368,111 @@ tableRoutes.get("/:schema/:table/data", async (req, res) => {
|
|
|
356
368
|
switch (operator) {
|
|
357
369
|
// Text operators
|
|
358
370
|
case "contains":
|
|
359
|
-
filterParams.push({ name: `
|
|
371
|
+
filterParams.push({ name: `p${paramIndex}`, value: `%${String(value)}%` });
|
|
360
372
|
condition = `${quotedColumn} LIKE ${dialect.param(paramIndex)}`;
|
|
361
373
|
break;
|
|
362
374
|
case "equals":
|
|
363
|
-
filterParams.push({ name: `
|
|
375
|
+
filterParams.push({ name: `p${paramIndex}`, value: String(value) });
|
|
364
376
|
condition = `${quotedColumn} = ${dialect.param(paramIndex)}`;
|
|
365
377
|
break;
|
|
366
378
|
case "startsWith":
|
|
367
|
-
filterParams.push({ name: `
|
|
379
|
+
filterParams.push({ name: `p${paramIndex}`, value: `${String(value)}%` });
|
|
368
380
|
condition = `${quotedColumn} LIKE ${dialect.param(paramIndex)}`;
|
|
369
381
|
break;
|
|
370
382
|
case "endsWith":
|
|
371
|
-
filterParams.push({ name: `
|
|
383
|
+
filterParams.push({ name: `p${paramIndex}`, value: `%${String(value)}` });
|
|
372
384
|
condition = `${quotedColumn} LIKE ${dialect.param(paramIndex)}`;
|
|
373
385
|
break;
|
|
374
386
|
case "notContains":
|
|
375
|
-
filterParams.push({ name: `
|
|
387
|
+
filterParams.push({ name: `p${paramIndex}`, value: `%${String(value)}%` });
|
|
376
388
|
condition = `${quotedColumn} NOT LIKE ${dialect.param(paramIndex)}`;
|
|
377
389
|
break;
|
|
378
390
|
// Number operators
|
|
379
391
|
case "eq":
|
|
380
|
-
|
|
392
|
+
const isNumericType = dataType && ["int", "bigint", "decimal", "numeric", "float", "double", "real", "smallint", "tinyint", "money", "smallmoney"].some((t) => dataType.toLowerCase().includes(t));
|
|
393
|
+
if (isNumericType) {
|
|
394
|
+
const numValue = Number(value);
|
|
395
|
+
if (isNaN(numValue)) {
|
|
396
|
+
console.warn(`Cannot convert filter value to number for ${columnName}, skipping`);
|
|
397
|
+
break;
|
|
398
|
+
}
|
|
399
|
+
filterParams.push({ name: `p${paramIndex}`, value: numValue });
|
|
400
|
+
} else {
|
|
401
|
+
filterParams.push({ name: `p${paramIndex}`, value: String(value) });
|
|
402
|
+
}
|
|
381
403
|
condition = `${quotedColumn} = ${dialect.param(paramIndex)}`;
|
|
382
404
|
break;
|
|
383
405
|
case "gt":
|
|
384
|
-
|
|
406
|
+
const gtValue = Number(value);
|
|
407
|
+
if (isNaN(gtValue)) {
|
|
408
|
+
console.warn(`Cannot convert filter value to number for ${columnName} (gt), skipping`);
|
|
409
|
+
break;
|
|
410
|
+
}
|
|
411
|
+
filterParams.push({ name: `p${paramIndex}`, value: gtValue });
|
|
385
412
|
condition = `${quotedColumn} > ${dialect.param(paramIndex)}`;
|
|
386
413
|
break;
|
|
387
414
|
case "gte":
|
|
388
|
-
|
|
415
|
+
const gteValue = Number(value);
|
|
416
|
+
if (isNaN(gteValue)) {
|
|
417
|
+
console.warn(`Cannot convert filter value to number for ${columnName} (gte), skipping`);
|
|
418
|
+
break;
|
|
419
|
+
}
|
|
420
|
+
filterParams.push({ name: `p${paramIndex}`, value: gteValue });
|
|
389
421
|
condition = `${quotedColumn} >= ${dialect.param(paramIndex)}`;
|
|
390
422
|
break;
|
|
391
423
|
case "lt":
|
|
392
|
-
|
|
424
|
+
const ltValue = Number(value);
|
|
425
|
+
if (isNaN(ltValue)) {
|
|
426
|
+
console.warn(`Cannot convert filter value to number for ${columnName} (lt), skipping`);
|
|
427
|
+
break;
|
|
428
|
+
}
|
|
429
|
+
filterParams.push({ name: `p${paramIndex}`, value: ltValue });
|
|
393
430
|
condition = `${quotedColumn} < ${dialect.param(paramIndex)}`;
|
|
394
431
|
break;
|
|
395
432
|
case "lte":
|
|
396
|
-
|
|
433
|
+
const lteValue = Number(value);
|
|
434
|
+
if (isNaN(lteValue)) {
|
|
435
|
+
console.warn(`Cannot convert filter value to number for ${columnName} (lte), skipping`);
|
|
436
|
+
break;
|
|
437
|
+
}
|
|
438
|
+
filterParams.push({ name: `p${paramIndex}`, value: lteValue });
|
|
397
439
|
condition = `${quotedColumn} <= ${dialect.param(paramIndex)}`;
|
|
398
440
|
break;
|
|
399
441
|
case "between":
|
|
400
442
|
if (typeof value === "object" && "from" in value && "to" in value) {
|
|
401
443
|
const fromParamIndex = paramIndex;
|
|
402
444
|
const toParamIndex = paramIndex + 1;
|
|
403
|
-
|
|
404
|
-
|
|
445
|
+
const fromValue = Number(value.from);
|
|
446
|
+
const toValue = Number(value.to);
|
|
447
|
+
if (isNaN(fromValue) || isNaN(toValue)) {
|
|
448
|
+
console.warn(`Cannot convert filter values to numbers for ${columnName} (between), skipping`);
|
|
449
|
+
break;
|
|
450
|
+
}
|
|
451
|
+
filterParams.push({ name: `p${fromParamIndex}`, value: fromValue });
|
|
452
|
+
filterParams.push({ name: `p${toParamIndex}`, value: toValue });
|
|
405
453
|
condition = `${quotedColumn} BETWEEN ${dialect.param(fromParamIndex)} AND ${dialect.param(toParamIndex)}`;
|
|
406
454
|
paramIndex++;
|
|
407
455
|
}
|
|
408
456
|
break;
|
|
409
457
|
// Date operators
|
|
410
458
|
case "dateEq":
|
|
411
|
-
filterParams.push({ name: `
|
|
459
|
+
filterParams.push({ name: `p${paramIndex}`, value: String(value) });
|
|
412
460
|
condition = `${dialect.castToDate(quotedColumn)} = ${dialect.castToDate(dialect.param(paramIndex))}`;
|
|
413
461
|
break;
|
|
414
462
|
case "dateAfter":
|
|
415
|
-
filterParams.push({ name: `
|
|
463
|
+
filterParams.push({ name: `p${paramIndex}`, value: String(value) });
|
|
416
464
|
condition = `${dialect.castToDate(quotedColumn)} > ${dialect.castToDate(dialect.param(paramIndex))}`;
|
|
417
465
|
break;
|
|
418
466
|
case "dateBefore":
|
|
419
|
-
filterParams.push({ name: `
|
|
467
|
+
filterParams.push({ name: `p${paramIndex}`, value: String(value) });
|
|
420
468
|
condition = `${dialect.castToDate(quotedColumn)} < ${dialect.castToDate(dialect.param(paramIndex))}`;
|
|
421
469
|
break;
|
|
422
470
|
case "dateBetween":
|
|
423
471
|
if (typeof value === "object" && "from" in value && "to" in value) {
|
|
424
472
|
const fromParamIndex = paramIndex;
|
|
425
473
|
const toParamIndex = paramIndex + 1;
|
|
426
|
-
filterParams.push({ name: `
|
|
427
|
-
filterParams.push({ name: `
|
|
474
|
+
filterParams.push({ name: `p${fromParamIndex}`, value: String(value.from) });
|
|
475
|
+
filterParams.push({ name: `p${toParamIndex}`, value: String(value.to) });
|
|
428
476
|
condition = `${dialect.castToDate(quotedColumn)} BETWEEN ${dialect.castToDate(dialect.param(fromParamIndex))} AND ${dialect.castToDate(dialect.param(toParamIndex))}`;
|
|
429
477
|
paramIndex++;
|
|
430
478
|
}
|
|
@@ -436,7 +484,7 @@ tableRoutes.get("/:schema/:table/data", async (req, res) => {
|
|
|
436
484
|
const placeholders = [];
|
|
437
485
|
value.forEach((val, i) => {
|
|
438
486
|
const currentIndex = paramIndex + i;
|
|
439
|
-
filterParams.push({ name: `
|
|
487
|
+
filterParams.push({ name: `p${currentIndex}`, value: val });
|
|
440
488
|
placeholders.push(dialect.param(currentIndex));
|
|
441
489
|
});
|
|
442
490
|
const inOperator = operator === "in" ? "IN" : "NOT IN";
|
|
@@ -446,7 +494,7 @@ tableRoutes.get("/:schema/:table/data", async (req, res) => {
|
|
|
446
494
|
break;
|
|
447
495
|
default:
|
|
448
496
|
console.warn(`Unknown filter operator: ${operator}, falling back to contains`);
|
|
449
|
-
filterParams.push({ name: `
|
|
497
|
+
filterParams.push({ name: `p${paramIndex}`, value: `%${String(value)}%` });
|
|
450
498
|
condition = `${quotedColumn} LIKE ${dialect.param(paramIndex)}`;
|
|
451
499
|
}
|
|
452
500
|
if (condition) {
|
|
@@ -483,9 +531,9 @@ tableRoutes.get("/:schema/:table/data", async (req, res) => {
|
|
|
483
531
|
WHERE table_schema = ${dialect.param(1)} AND table_name = ${dialect.param(2)} AND column_name = ${dialect.param(3)}
|
|
484
532
|
`;
|
|
485
533
|
const validateResult = await executeQuery(validateQuery, [
|
|
486
|
-
{ name: "
|
|
487
|
-
{ name: "
|
|
488
|
-
{ name: "
|
|
534
|
+
{ name: "p1", value: schema },
|
|
535
|
+
{ name: "p2", value: table },
|
|
536
|
+
{ name: "p3", value: orderByColumn }
|
|
489
537
|
]);
|
|
490
538
|
if (validateResult.length === 0) {
|
|
491
539
|
orderByColumn = "";
|
|
@@ -507,8 +555,8 @@ tableRoutes.get("/:schema/:table/data", async (req, res) => {
|
|
|
507
555
|
${!topClause ? dialect.limitOffset(0, 1) : ""}
|
|
508
556
|
`;
|
|
509
557
|
const structureResult = await executeQuery(structureQuery, [
|
|
510
|
-
{ name: "
|
|
511
|
-
{ name: "
|
|
558
|
+
{ name: "p1", value: schema },
|
|
559
|
+
{ name: "p2", value: table }
|
|
512
560
|
]);
|
|
513
561
|
if (structureResult.length > 0) {
|
|
514
562
|
orderByColumn = structureResult[0].column_name || structureResult[0].COLUMN_NAME;
|
|
@@ -540,8 +588,8 @@ tableRoutes.get("/:schema/:table/data", async (req, res) => {
|
|
|
540
588
|
`;
|
|
541
589
|
console.log("Fetching foreign keys with query:", fkQuery);
|
|
542
590
|
const foreignKeys = await executeQuery(fkQuery, [
|
|
543
|
-
{ name: "
|
|
544
|
-
{ name: "
|
|
591
|
+
{ name: "p1", value: schema },
|
|
592
|
+
{ name: "p2", value: table }
|
|
545
593
|
]);
|
|
546
594
|
console.log(`Found ${foreignKeys.length} foreign key(s)`);
|
|
547
595
|
if (foreignKeys.length > 0) {
|
|
@@ -558,11 +606,11 @@ tableRoutes.get("/:schema/:table/data", async (req, res) => {
|
|
|
558
606
|
WHERE ${tableConditions}
|
|
559
607
|
ORDER BY table_schema, table_name, ordinal_position
|
|
560
608
|
`;
|
|
561
|
-
const batchParams = uniqueRefTables.flatMap((tableRef) => {
|
|
609
|
+
const batchParams = uniqueRefTables.flatMap((tableRef, idx) => {
|
|
562
610
|
const [refSchema, refTable] = tableRef.split(".");
|
|
563
611
|
return [
|
|
564
|
-
{ name:
|
|
565
|
-
{ name:
|
|
612
|
+
{ name: `p${idx * 2 + 1}`, value: refSchema },
|
|
613
|
+
{ name: `p${idx * 2 + 2}`, value: refTable }
|
|
566
614
|
];
|
|
567
615
|
});
|
|
568
616
|
console.log("Fetching referenced table columns with query:", batchColumnsQuery);
|
|
@@ -795,8 +843,8 @@ tableRoutes.post("/:schema/:table/related-data", async (req, res) => {
|
|
|
795
843
|
ORDER BY ordinal_position
|
|
796
844
|
`;
|
|
797
845
|
const columns = await executeQuery(columnsQuery, [
|
|
798
|
-
{ name: "
|
|
799
|
-
{ name: "
|
|
846
|
+
{ name: "p1", value: referencedSchema },
|
|
847
|
+
{ name: "p2", value: referencedTable }
|
|
800
848
|
]);
|
|
801
849
|
const referencedColInfo = columns.find((col) => {
|
|
802
850
|
const colName = col.column_name || col.COLUMN_NAME;
|
|
@@ -838,8 +886,8 @@ tableRoutes.post("/:schema/:table/related-data", async (req, res) => {
|
|
|
838
886
|
FROM ${quotedRefSchema}.${quotedRefTable}
|
|
839
887
|
WHERE ${quotedRefColumn} IN (${placeholders})
|
|
840
888
|
`;
|
|
841
|
-
const params = ids.map((id) => ({
|
|
842
|
-
name:
|
|
889
|
+
const params = ids.map((id, idx) => ({
|
|
890
|
+
name: `p${idx + 1}`,
|
|
843
891
|
value: id
|
|
844
892
|
}));
|
|
845
893
|
const result = await executeQuery(dataQuery, params);
|
|
@@ -905,9 +953,9 @@ tableRoutes.get("/:schema/:table/distinct-values/:column", async (req, res) => {
|
|
|
905
953
|
WHERE c.table_schema = ${dialect.param(1)} AND c.table_name = ${dialect.param(2)} AND c.column_name = ${dialect.param(3)}
|
|
906
954
|
`;
|
|
907
955
|
const columnResult = await executeQuery(columnQuery, [
|
|
908
|
-
{ name: "
|
|
909
|
-
{ name: "
|
|
910
|
-
{ name: "
|
|
956
|
+
{ name: "p1", value: schema },
|
|
957
|
+
{ name: "p2", value: table },
|
|
958
|
+
{ name: "p3", value: column }
|
|
911
959
|
]);
|
|
912
960
|
if (columnResult.length === 0) {
|
|
913
961
|
return res.status(400).json({ error: "Column not found" });
|
|
@@ -934,7 +982,7 @@ tableRoutes.get("/:schema/:table/distinct-values/:column", async (req, res) => {
|
|
|
934
982
|
if (searchQuery && searchQuery.trim()) {
|
|
935
983
|
const searchCols = columnsToSelect.map((col) => `${dialect.quoteId(col)} LIKE ${dialect.param(1)}`).join(" OR ");
|
|
936
984
|
query += ` WHERE (${searchCols}) AND ${quotedRefColumn} IS NOT NULL`;
|
|
937
|
-
params.push({ name: "
|
|
985
|
+
params.push({ name: "p1", value: `%${searchQuery.trim()}%` });
|
|
938
986
|
} else {
|
|
939
987
|
query += ` WHERE ${quotedRefColumn} IS NOT NULL`;
|
|
940
988
|
}
|
|
@@ -948,8 +996,8 @@ tableRoutes.get("/:schema/:table/distinct-values/:column", async (req, res) => {
|
|
|
948
996
|
ORDER BY ordinal_position
|
|
949
997
|
`;
|
|
950
998
|
const refColumns = await executeQuery(refColumnsQuery, [
|
|
951
|
-
{ name: "
|
|
952
|
-
{ name: "
|
|
999
|
+
{ name: "p1", value: refSchema },
|
|
1000
|
+
{ name: "p2", value: refTable }
|
|
953
1001
|
]);
|
|
954
1002
|
const preferredNames = ["name", "title", "description", "code"];
|
|
955
1003
|
for (const preferredName of preferredNames) {
|
|
@@ -982,7 +1030,7 @@ tableRoutes.get("/:schema/:table/distinct-values/:column", async (req, res) => {
|
|
|
982
1030
|
} else {
|
|
983
1031
|
query += ` WHERE ${quotedRefColumn} LIKE ${dialect.param(1)}`;
|
|
984
1032
|
}
|
|
985
|
-
params.push({ name: "
|
|
1033
|
+
params.push({ name: "p1", value: `%${searchQuery.trim()}%` });
|
|
986
1034
|
query += ` AND ${quotedRefColumn} IS NOT NULL`;
|
|
987
1035
|
} else {
|
|
988
1036
|
query += ` WHERE ${quotedRefColumn} IS NOT NULL`;
|
|
@@ -1003,7 +1051,7 @@ tableRoutes.get("/:schema/:table/distinct-values/:column", async (req, res) => {
|
|
|
1003
1051
|
if (searchQuery && searchQuery.trim()) {
|
|
1004
1052
|
const searchCols = quotedColumns.map((col) => `${dialect.tryCastToNVarChar(col)} LIKE ${dialect.param(1)}`).join(" OR ");
|
|
1005
1053
|
query += ` WHERE (${searchCols}) AND ${keyColumn} IS NOT NULL`;
|
|
1006
|
-
params.push({ name: "
|
|
1054
|
+
params.push({ name: "p1", value: `%${searchQuery.trim()}%` });
|
|
1007
1055
|
} else {
|
|
1008
1056
|
query += ` WHERE ${keyColumn} IS NOT NULL`;
|
|
1009
1057
|
}
|
|
@@ -1013,7 +1061,7 @@ tableRoutes.get("/:schema/:table/distinct-values/:column", async (req, res) => {
|
|
|
1013
1061
|
if (searchQuery && searchQuery.trim()) {
|
|
1014
1062
|
if (["varchar", "nvarchar", "char", "nchar", "text", "ntext"].some((t) => dataType.includes(t))) {
|
|
1015
1063
|
query += ` WHERE ${quotedColumn} LIKE ${dialect.param(1)}`;
|
|
1016
|
-
params.push({ name: "
|
|
1064
|
+
params.push({ name: "p1", value: `%${searchQuery.trim()}%` });
|
|
1017
1065
|
query += ` AND ${quotedColumn} IS NOT NULL`;
|
|
1018
1066
|
} else {
|
|
1019
1067
|
query += ` WHERE ${quotedColumn} IS NOT NULL`;
|
|
@@ -1036,6 +1084,131 @@ tableRoutes.get("/:schema/:table/distinct-values/:column", async (req, res) => {
|
|
|
1036
1084
|
res.status(500).json({ error: error.message || "Failed to fetch distinct values" });
|
|
1037
1085
|
}
|
|
1038
1086
|
});
|
|
1087
|
+
tableRoutes.get("/:schema/:table/reverse-foreign-keys", async (req, res) => {
|
|
1088
|
+
try {
|
|
1089
|
+
const { schema, table } = req.params;
|
|
1090
|
+
const pool = getConnection();
|
|
1091
|
+
if (!pool) {
|
|
1092
|
+
return res.status(400).json({ error: "Not connected to database" });
|
|
1093
|
+
}
|
|
1094
|
+
const isConnected = "connected" in pool ? pool.connected === true : !pool.ended;
|
|
1095
|
+
if (!isConnected) {
|
|
1096
|
+
return res.status(400).json({ error: "Not connected to database" });
|
|
1097
|
+
}
|
|
1098
|
+
const dialect = getDialect();
|
|
1099
|
+
const query = `
|
|
1100
|
+
SELECT
|
|
1101
|
+
kcu1.table_schema as "referencingSchema",
|
|
1102
|
+
kcu1.table_name as "referencingTable",
|
|
1103
|
+
kcu1.column_name as "fkColumnName",
|
|
1104
|
+
kcu2.column_name as "referencedColumn"
|
|
1105
|
+
FROM information_schema.referential_constraints rc
|
|
1106
|
+
INNER JOIN information_schema.key_column_usage kcu1
|
|
1107
|
+
ON rc.constraint_catalog = kcu1.constraint_catalog
|
|
1108
|
+
AND rc.constraint_schema = kcu1.constraint_schema
|
|
1109
|
+
AND rc.constraint_name = kcu1.constraint_name
|
|
1110
|
+
INNER JOIN information_schema.key_column_usage kcu2
|
|
1111
|
+
ON rc.unique_constraint_catalog = kcu2.constraint_catalog
|
|
1112
|
+
AND rc.unique_constraint_schema = kcu2.constraint_schema
|
|
1113
|
+
AND rc.unique_constraint_name = kcu2.constraint_name
|
|
1114
|
+
AND kcu1.ordinal_position = kcu2.ordinal_position
|
|
1115
|
+
WHERE kcu2.table_schema = ${dialect.param(1)}
|
|
1116
|
+
AND kcu2.table_name = ${dialect.param(2)}
|
|
1117
|
+
ORDER BY kcu1.table_schema, kcu1.table_name, kcu1.ordinal_position
|
|
1118
|
+
`;
|
|
1119
|
+
const result = await executeQuery(query, [
|
|
1120
|
+
{ name: "p1", value: schema },
|
|
1121
|
+
{ name: "p2", value: table }
|
|
1122
|
+
]);
|
|
1123
|
+
const grouped = {};
|
|
1124
|
+
result.forEach((row) => {
|
|
1125
|
+
const referencingSchema = row.referencingSchema || row.referencing_schema;
|
|
1126
|
+
const referencingTable = row.referencingTable || row.referencing_table;
|
|
1127
|
+
const fkColumnName = row.fkColumnName || row.fk_column_name;
|
|
1128
|
+
const referencedColumn = row.referencedColumn || row.referenced_column;
|
|
1129
|
+
const key = `${referencingSchema}.${referencingTable}`;
|
|
1130
|
+
if (!grouped[key]) {
|
|
1131
|
+
grouped[key] = {
|
|
1132
|
+
referencingSchema,
|
|
1133
|
+
referencingTable,
|
|
1134
|
+
fkColumns: [],
|
|
1135
|
+
referencedColumns: []
|
|
1136
|
+
};
|
|
1137
|
+
}
|
|
1138
|
+
grouped[key].fkColumns.push(fkColumnName);
|
|
1139
|
+
grouped[key].referencedColumns.push(referencedColumn);
|
|
1140
|
+
});
|
|
1141
|
+
const reverseFks = Object.values(grouped);
|
|
1142
|
+
res.json(reverseFks);
|
|
1143
|
+
} catch (error) {
|
|
1144
|
+
console.error("Error fetching reverse foreign keys:", error);
|
|
1145
|
+
const errorMessage = error.message || "";
|
|
1146
|
+
if (errorMessage.includes("Login failed") || errorMessage.includes("authentication") || errorMessage.includes("password authentication")) {
|
|
1147
|
+
const { disconnect: disconnect2 } = await import("./db-CJPCGHL3.js");
|
|
1148
|
+
await disconnect2();
|
|
1149
|
+
}
|
|
1150
|
+
res.status(500).json({ error: error.message || "Failed to fetch reverse foreign keys" });
|
|
1151
|
+
}
|
|
1152
|
+
});
|
|
1153
|
+
tableRoutes.post("/:schema/:table/count-related", async (req, res) => {
|
|
1154
|
+
try {
|
|
1155
|
+
const { schema, table } = req.params;
|
|
1156
|
+
const { referencingSchema, referencingTable, fkColumns, referencedColumns, primaryKeyValues } = req.body;
|
|
1157
|
+
if (!referencingSchema || !referencingTable || !fkColumns || !Array.isArray(fkColumns) || !referencedColumns || !Array.isArray(referencedColumns) || !primaryKeyValues || !Array.isArray(primaryKeyValues)) {
|
|
1158
|
+
return res.status(400).json({ error: "Missing required parameters" });
|
|
1159
|
+
}
|
|
1160
|
+
if (fkColumns.length !== referencedColumns.length || fkColumns.length !== primaryKeyValues.length) {
|
|
1161
|
+
return res.status(400).json({ error: "FK columns, referenced columns, and primary key values arrays must have the same length" });
|
|
1162
|
+
}
|
|
1163
|
+
const pool = getConnection();
|
|
1164
|
+
if (!pool) {
|
|
1165
|
+
return res.status(400).json({ error: "Not connected to database" });
|
|
1166
|
+
}
|
|
1167
|
+
const isConnected = "connected" in pool ? pool.connected === true : !pool.ended;
|
|
1168
|
+
if (!isConnected) {
|
|
1169
|
+
return res.status(400).json({ error: "Not connected to database" });
|
|
1170
|
+
}
|
|
1171
|
+
const dialect = getDialect();
|
|
1172
|
+
const quotedSchema = dialect.quoteId(referencingSchema);
|
|
1173
|
+
const quotedTable = dialect.quoteId(referencingTable);
|
|
1174
|
+
const whereConditions = [];
|
|
1175
|
+
let paramIndex = 1;
|
|
1176
|
+
const params = [];
|
|
1177
|
+
fkColumns.forEach((fkCol, idx) => {
|
|
1178
|
+
const quotedCol = dialect.quoteId(fkCol);
|
|
1179
|
+
let pkValue = primaryKeyValues[idx];
|
|
1180
|
+
if (typeof pkValue === "number" && isNaN(pkValue)) {
|
|
1181
|
+
pkValue = null;
|
|
1182
|
+
}
|
|
1183
|
+
if (pkValue === "NaN" || pkValue === "nan") {
|
|
1184
|
+
pkValue = null;
|
|
1185
|
+
}
|
|
1186
|
+
if (pkValue === null || pkValue === void 0) {
|
|
1187
|
+
whereConditions.push(`${quotedCol} IS NULL`);
|
|
1188
|
+
} else {
|
|
1189
|
+
whereConditions.push(`${quotedCol} = ${dialect.param(paramIndex)}`);
|
|
1190
|
+
params.push({ name: `p${paramIndex}`, value: pkValue });
|
|
1191
|
+
paramIndex++;
|
|
1192
|
+
}
|
|
1193
|
+
});
|
|
1194
|
+
const query = `
|
|
1195
|
+
SELECT COUNT(*) as "count"
|
|
1196
|
+
FROM ${quotedSchema}.${quotedTable}
|
|
1197
|
+
WHERE ${whereConditions.join(" AND ")}
|
|
1198
|
+
`;
|
|
1199
|
+
const result = await executeQuery(query, params);
|
|
1200
|
+
const count = result[0]?.count || result[0]?.COUNT || 0;
|
|
1201
|
+
res.json({ count: Number(count) });
|
|
1202
|
+
} catch (error) {
|
|
1203
|
+
console.error("Error counting related rows:", error);
|
|
1204
|
+
const errorMessage = error.message || "";
|
|
1205
|
+
if (errorMessage.includes("Login failed") || errorMessage.includes("authentication") || errorMessage.includes("password authentication")) {
|
|
1206
|
+
const { disconnect: disconnect2 } = await import("./db-CJPCGHL3.js");
|
|
1207
|
+
await disconnect2();
|
|
1208
|
+
}
|
|
1209
|
+
res.status(500).json({ error: error.message || "Failed to count related rows" });
|
|
1210
|
+
}
|
|
1211
|
+
});
|
|
1039
1212
|
|
|
1040
1213
|
// src/server/routes/query.ts
|
|
1041
1214
|
import { Router as Router3 } from "express";
|