db-studio 1.2.7 → 1.2.8
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/index.js +5 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var Nt=Object.defineProperty;var f=(t,e)=>()=>(t&&(e=t(t=0)),e);var
|
|
2
|
+
var Nt=Object.defineProperty;var f=(t,e)=>()=>(t&&(e=t(t=0)),e);var vt=(t,e)=>{for(var r in e)Nt(t,r,{get:e[r],enumerable:!0})};var N,I=f(()=>{"use strict";N={PORT:3333,ENV:".env",VAR_NAME:"DATABASE_URL",PROXY_URL:process.env.NODE_ENV==="development"?"http://localhost:8787":"https://db-studio-proxy.husamql3.workers.dev"}});import{Pool as Ft}from"pg";var U,Kt,C,Y=f(()=>{"use strict";U=null,Kt=()=>{if(!U){if(!process.env.DATABASE_URL)throw new Error("DATABASE_URL is not set. Please provide a database connection string.");try{U=new Ft({connectionString:process.env.DATABASE_URL}),U.on("error",t=>{})}catch(t){throw t}}return U},C=new Proxy({},{get(t,e){try{return Kt()[e]}catch(r){throw r}}})});import{Pool as Te}from"pg";var G,Vt,b,T=f(()=>{"use strict";G=class{pools=new Map;baseConfig=null;constructor(){this.initializeBaseConfig()}initializeBaseConfig(){let e=process.env.DATABASE_URL;if(!e)throw new Error("DATABASE_URL is not set. Please provide a database connection string.");try{let r=new URL(e);this.baseConfig={url:e,host:r.hostname,port:Number.parseInt(r.port,10)||5432,user:r.username,password:r.password}}catch(r){throw new Error(`Failed to parse DATABASE_URL: ${r}`)}}buildConnectionString(e){if(!this.baseConfig)throw new Error("Base configuration not initialized");if(!e){let r=this.baseConfig.url;r&&(e=new URL(r).pathname.slice(1))}try{let r=new URL(this.baseConfig.url);return r.pathname=`/${e}`,r.toString()}catch(r){throw new Error(`Failed to build connection string for database "${e}": ${r instanceof Error?r.message:String(r)}`)}}getPool(e){let r=this.buildConnectionString(e);if(!this.pools.has(r)){let o={connectionString:r,max:10,idleTimeoutMillis:3e4,connectionTimeoutMillis:2e3},a=new Te(o);a.on("error",n=>{}),this.pools.set(r,a)}return this.pools.get(r)??new Te({connectionString:r})}async closePool(e){let r=this.pools.get(e);r&&(await r.end(),this.pools.delete(e))}async closePoolByDatabase(e){let r=this.buildConnectionString(e);await this.closePool(r)}async closeAll(){let e=Array.from(this.pools.entries()).map(async([r,o])=>{await o.end()});await Promise.all(e),this.pools.clear()}getActivePools(){return Array.from(this.pools.keys())}},Vt=new G,b=t=>Vt.getPool(t)});function Se(t){let e=t.toLowerCase().trim();return e.includes("[]")||e==="date"||e==="time"||e==="time without time zone"||e.startsWith("time(")||e==="timestamp"||e==="timestamp without time zone"||e.startsWith("timestamp(")||e==="timestamp with time zone"||e==="timestamptz"||e.startsWith("timestamp with time zone(")?D.date:e==="integer"||e==="int"||e==="int4"||e==="bigint"||e==="int8"||e==="smallint"||e==="int2"||e==="decimal"||e.startsWith("decimal(")||e==="numeric"||e.startsWith("numeric(")||e==="real"||e==="float4"||e==="double precision"||e==="float8"||e==="float"||e==="serial"||e==="serial4"||e==="bigserial"||e==="serial8"||e==="money"?D.number:e==="boolean"||e==="bool"?D.boolean:e==="json"||e==="jsonb"?D.json:(e.startsWith("user-defined")||e==="enum"||e==="text"||e==="xml"||e==="character varying"||e.startsWith("varchar")||e.startsWith("character varying(")||e==="character"||e.startsWith("char")||e.startsWith("character(")||e==="bpchar"||e==="uuid"||e==="interval"||e.startsWith("interval")||e==="bytea"||e==="point"||e==="line"||e==="polygon"||e==="inet"||e==="cidr"||e==="macaddr"||e==="macaddr8",D.text)}function Ne(t){let e=t.toLowerCase().trim();return e==="integer"||e==="int"||e==="int4"||e==="serial"||e==="serial4"?p.int:e==="bigint"||e==="int8"||e==="bigserial"||e==="serial8"?p.bigint:e==="smallint"||e==="int2"?p.smallint:e==="decimal"||e.startsWith("decimal(")||e==="numeric"||e.startsWith("numeric(")?p.numeric:e==="real"||e==="float4"?p.float:e==="double precision"||e==="float8"||e==="float"?p.double:e==="money"?p.money:e==="boolean"||e==="bool"?p.boolean:e==="text"?p.text:e==="character varying"||e.startsWith("varchar")||e.startsWith("character varying(")?p.varchar:e==="character"||e.startsWith("char")||e.startsWith("character(")||e==="bpchar"?p.char:e==="json"?p.json:e==="jsonb"?p.jsonb:e==="xml"?p.xml:e==="uuid"?p.uuid:e==="date"?p.date:e==="time"||e==="time without time zone"||e.startsWith("time(")?p.time:e==="timestamp"||e==="timestamp without time zone"||e.startsWith("timestamp(")?p.timestamp:e==="timestamp with time zone"||e==="timestamptz"||e.startsWith("timestamp with time zone(")?p.timestamptz:e==="interval"||e.startsWith("interval")?p.interval:e==="bytea"?p.bytea:e==="inet"?p.inet:e==="cidr"?p.cidr:e==="macaddr"?p.macaddr:e==="macaddr8"?p.macaddr8:e==="point"?p.point:e==="line"?p.line:e==="polygon"?p.polygon:e.startsWith("array")||e.includes("[]")?p.text:e.startsWith("user-defined")||e==="enum"?p.enum:p.text}var D,p,ve=f(()=>{"use strict";D={text:"text",boolean:"boolean",number:"number",enum:"enum",json:"json",date:"date",array:"array"};p={int:"int",bigint:"bigint",smallint:"smallint",numeric:"numeric",float:"float",double:"double",money:"money",boolean:"boolean",text:"text",varchar:"varchar",char:"char",json:"json",jsonb:"jsonb",xml:"xml",uuid:"uuid",date:"date",time:"time",timestamp:"timestamp",timestamptz:"timestamptz",interval:"interval",bytea:"bytea",inet:"inet",cidr:"cidr",macaddr:"macaddr",macaddr8:"macaddr8",point:"point",line:"line",polygon:"polygon",array:"array",enum:"enum"}});var F,J=f(()=>{"use strict";T();ve();F=async(t,e)=>{let o=await b(e).connect();try{return(await o.query(`
|
|
3
3
|
SELECT
|
|
4
4
|
c.column_name as "columnName",
|
|
5
5
|
c.data_type as "dataType",
|
|
@@ -59,7 +59,7 @@ var Nt=Object.defineProperty;var f=(t,e)=>()=>(t&&(e=t(t=0)),e);var Dt=(t,e)=>{f
|
|
|
59
59
|
FROM pg_class
|
|
60
60
|
WHERE relname = $1
|
|
61
61
|
AND relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'public');
|
|
62
|
-
`,[t])).rows[0]?.description||void 0}finally{e.release()}}async function Bt(t){let e=await C.connect();try{return(await e.query(`SELECT * FROM "${t}" LIMIT 3`)).rows}catch{return[]}finally{e.release()}}function Ht(t){let e={name:t.columnName,type:t.dataTypeLabel,nullable:t.isNullable};return t.isPrimaryKey&&(e.isPrimaryKey=!0),t.isForeignKey&&t.referencedTable&&t.referencedColumn&&(e.foreignKey=`${t.referencedTable}.${t.referencedColumn}`),t.enumValues&&t.enumValues.length>0&&(e.enumValues=t.enumValues,e.description=`Enum values: ${t.enumValues.join(", ")}`),e}function Qt(t){let e=[];for(let r of t)for(let o of r.columns)if(o.foreignKey){let[a,n]=o.foreignKey.split(".");e.push({fromTable:r.name,fromColumn:o.name,toTable:a,toColumn:n})}return e}async function zt(t={}){let{includeSampleData:e=!1,includeDescriptions:r=!0}=t;try{let a=(await Wt()).map(async i=>{let[m,u,d]=await Promise.all([F(i),r?Mt(i):Promise.resolve(void 0),e?Bt(i):Promise.resolve([])]),l={name:i,columns:m.map(Ht)};return u&&(l.description=u),d.length>0&&(l.sampleData=d),l}),n=await Promise.all(a),s=Qt(n);return{dbType:"PostgreSQL",tables:n,relationships:s}}catch(o){throw new Error(`Failed to fetch database schema: ${o instanceof Error?o.message:"Unknown error"}`)}}async function
|
|
62
|
+
`,[t])).rows[0]?.description||void 0}finally{e.release()}}async function Bt(t){let e=await C.connect();try{return(await e.query(`SELECT * FROM "${t}" LIMIT 3`)).rows}catch{return[]}finally{e.release()}}function Ht(t){let e={name:t.columnName,type:t.dataTypeLabel,nullable:t.isNullable};return t.isPrimaryKey&&(e.isPrimaryKey=!0),t.isForeignKey&&t.referencedTable&&t.referencedColumn&&(e.foreignKey=`${t.referencedTable}.${t.referencedColumn}`),t.enumValues&&t.enumValues.length>0&&(e.enumValues=t.enumValues,e.description=`Enum values: ${t.enumValues.join(", ")}`),e}function Qt(t){let e=[];for(let r of t)for(let o of r.columns)if(o.foreignKey){let[a,n]=o.foreignKey.split(".");e.push({fromTable:r.name,fromColumn:o.name,toTable:a,toColumn:n})}return e}async function zt(t={}){let{includeSampleData:e=!1,includeDescriptions:r=!0}=t;try{let a=(await Wt()).map(async i=>{let[m,u,d]=await Promise.all([F(i),r?Mt(i):Promise.resolve(void 0),e?Bt(i):Promise.resolve([])]),l={name:i,columns:m.map(Ht)};return u&&(l.description=u),d.length>0&&(l.sampleData=d),l}),n=await Promise.all(a),s=Qt(n);return{dbType:"PostgreSQL",tables:n,relationships:s}}catch(o){throw new Error(`Failed to fetch database schema: ${o instanceof Error?o.message:"Unknown error"}`)}}async function De(){return zt({includeSampleData:!0,includeDescriptions:!0})}var Re=f(()=>{"use strict";Y();J()});function Ce(t){return`You are a database assistant for db-studio. Your responses must be CONCISE and FOCUSED.
|
|
63
63
|
|
|
64
64
|
**Your Role:**
|
|
65
65
|
1. Keep responses SHORT - 2-3 sentences maximum unless generating SQL
|
|
@@ -126,7 +126,7 @@ This will return the 5 customers with the highest total order value. You might a
|
|
|
126
126
|
`)}if(t.relationships&&t.relationships.length>0){e+=`
|
|
127
127
|
**Relationships:**
|
|
128
128
|
`;for(let r of t.relationships)e+=` - ${r.fromTable}.${r.fromColumn} -> ${r.toTable}.${r.toColumn}
|
|
129
|
-
`}return e}var _e=f(()=>{"use strict"});import{Hono as Gt}from"hono";var X,$e=f(()=>{"use strict";Re();I();_e();X=new Gt;X.post("/",async t=>{try{let{messages:e,conversationId:r}=await t.req.json(),o=await
|
|
129
|
+
`}return e}var _e=f(()=>{"use strict"});import{Hono as Gt}from"hono";var X,$e=f(()=>{"use strict";Re();I();_e();X=new Gt;X.post("/",async t=>{try{let{messages:e,conversationId:r}=await t.req.json(),o=await De(),a=Ce(o),n={messages:e,conversationId:r,systemPrompt:a},s=await fetch(`${N.PROXY_URL}/chat`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(n)});if(!s.ok){let u=await s.json();return t.json({error:u.error||"Proxy request failed"},s.status)}let{readable:i,writable:m}=new TransformStream;return s.body?.pipeTo(m),new Response(i,{headers:{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"}})}catch(e){let r=e instanceof Error?e.message:"An error occurred";return t.json({error:r},500)}})});import{z as c}from"zod";var Jt,xe,Xt,Zt,Pe,K,Ae,Le,Oe,Z,qe,L,_=f(()=>{"use strict";Jt=["CASCADE","SET NULL","SET DEFAULT","RESTRICT","NO ACTION"],xe=c.enum(Jt),Xt=c.object({columnName:c.string().min(1),columnType:c.string().min(1),defaultValue:c.string(),isPrimaryKey:c.boolean(),isNullable:c.boolean(),isUnique:c.boolean(),isIdentity:c.boolean(),isArray:c.boolean()}),Zt=c.object({columnName:c.string().min(1),referencedTable:c.string().min(1),referencedColumn:c.string().min(1),onUpdate:xe,onDelete:xe}),Pe=c.object({tableName:c.string().min(1,"Table name is required"),fields:c.array(Xt).min(1,"At least one field is required"),foreignKeys:c.array(Zt).optional()}),K=c.object({tableName:c.string().min(1,"Table name is required")}),Ae=c.object({page:c.string().optional().default("1").transform(Number),pageSize:c.string().optional().default("50").transform(Number),sort:c.string().optional().default(""),order:c.enum(["asc","desc"]).optional(),filters:c.string().optional().transform(t=>{if(!t)return[];try{return JSON.parse(t)}catch{return[]}})}),Le=c.object({tableName:c.string().min(1,"Table name is required"),data:c.record(c.string(),c.any())}),Oe=c.object({tableName:c.string().min(1,"Table name is required"),updates:c.array(c.object({rowData:c.any(),columnName:c.string().min(1),value:c.any()})).min(1,"At least one update is required"),primaryKey:c.string().optional()}),Z=c.object({tableName:c.string().min(1,"Table name is required"),primaryKeys:c.array(c.object({columnName:c.string().min(1),value:c.any()})).min(1,"At least one primary key is required")}),qe=c.object({query:c.string().min(1,"Query is required")}),L=c.object({database:c.string().optional()})});var $,V=f(()=>{"use strict";$=(t,e,r)=>{let o=e instanceof Error?e.message:r,a=!1;return e&&typeof e=="object"&&"code"in e?a=e.code==="ECONNREFUSED":e&&typeof e=="object"&&"errors"in e&&Array.isArray(e.errors)&&(a=e.errors?.some(s=>s.code==="ECONNREFUSED")??!1),a?t.json({success:!1,message:"Cannot connect to database. Please check your DATABASE_URL and ensure the database server is running.",error:o},503):t.json({success:!1,message:o},500)}});import{zValidator as ke}from"@hono/zod-validator";import{Hono as er}from"hono";var ee,Ie=f(()=>{"use strict";J();_();V();ee=new er;ee.get("/",ke("param",K),ke("query",L),async t=>{try{let{tableName:e}=t.req.valid("param"),{database:r}=t.req.valid("query"),o=await F(e,r);return t.json(o)}catch(e){return $(t,e,"Failed to fetch columns")}})});var tr,rr,je,Ue=f(()=>{"use strict";T();tr=t=>{if(t.length===0)return{clause:"",values:[]};let e=[],r=[];for(let o of t){let a=r.length+1,n=`"${o.columnName}"`;switch(o.operator){case"=":case"!=":case">":case">=":case"<":case"<=":e.push(`${n} ${o.operator} $${a}`),r.push(o.value);break;case"is":o.value.toLowerCase()==="null"?e.push(`${n} IS NULL`):(e.push(`${n} = $${a}`),r.push(o.value));break;case"is not":o.value.toLowerCase()==="null"?e.push(`${n} IS NOT NULL`):(e.push(`${n} != $${a}`),r.push(o.value));break;case"like":e.push(`${n}::text LIKE $${a}`),r.push(o.value);break;case"not like":e.push(`${n}::text NOT LIKE $${a}`),r.push(o.value);break;case"ilike":e.push(`${n}::text ILIKE $${a}`),r.push(o.value);break;case"not ilike":e.push(`${n}::text NOT ILIKE $${a}`),r.push(o.value);break;default:break}}return e.length===0?{clause:"",values:[]}:{clause:`WHERE ${e.join(" AND ")}`,values:r}},rr=(t,e)=>Array.isArray(t)?t.length===0?"":`ORDER BY ${t.map(o=>`"${o.columnName}" ${o.direction.toUpperCase()}`).join(", ")}`:t&&typeof t=="string"?`ORDER BY "${t}" ${e?.toUpperCase()||"ASC"}`:"",je=async(t,e=1,r=50,o="",a="asc",n=[],s)=>{let i=rr((Array.isArray(o),o),a),{clause:m,values:u}=tr(n),l=await b(s).connect();try{let g=(e-1)*r,w=await l.query(`SELECT COUNT(*) as total FROM "${t}" ${m}`,u),y=Number(w.rows[0].total),E=Math.ceil(y/r),S=u.length+1,h=u.length+2;return{data:(await l.query(`SELECT * FROM "${t}" ${m} ${i} LIMIT $${S} OFFSET $${h}`,[...u,r,g])).rows,meta:{page:e,limit:r,total:y,totalPages:E,hasNextPage:e<E,hasPreviousPage:e>1}}}finally{l.release()}}});import{zValidator as Fe}from"@hono/zod-validator";import{Hono as or}from"hono";var te,Ke=f(()=>{"use strict";Ue();_();V();te=new or;te.get("/",Fe("param",K),Fe("query",Ae),async t=>{try{let{tableName:e}=t.req.valid("param"),{page:r,pageSize:o,sort:a,order:n,filters:s}=t.req.valid("query"),i="";if(a)try{let d=JSON.parse(a);Array.isArray(d)?i=d:i=a}catch{i=a}let m=t.req.query("database"),u=await je(e,r,o,i,n,s,m);return t.json(u)}catch(e){return $(t,e,"Failed to fetch table data")}})});async function Ve(){return(await b().query(`
|
|
130
130
|
SELECT
|
|
131
131
|
d.datname as name,
|
|
132
132
|
pg_size_pretty(pg_database_size(d.datname)) as size,
|
|
@@ -187,7 +187,7 @@ This will return the 5 customers with the highest total order value. You might a
|
|
|
187
187
|
SET ${g.join(", ")}
|
|
188
188
|
WHERE "${o}" = $${w.length}
|
|
189
189
|
RETURNING *
|
|
190
|
-
`,E=await s.query(y,w);if(E.rowCount===0)throw new Error(`Record with ${o} = ${d} not found in table "${e}"`);m.push(E.rows[0]),u+=E.rowCount||0}return await s.query("COMMIT"),{success:!0,message:`Successfully updated ${u} ${u===1?"row":"rows"} in "${e}"`,data:m,updatedCount:u}}catch(i){throw await s.query("ROLLBACK"),i}finally{s.release()}}});import{zValidator as
|
|
190
|
+
`,E=await s.query(y,w);if(E.rowCount===0)throw new Error(`Record with ${o} = ${d} not found in table "${e}"`);m.push(E.rows[0]),u+=E.rowCount||0}return await s.query("COMMIT"),{success:!0,message:`Successfully updated ${u} ${u===1?"row":"rows"} in "${e}"`,data:m,updatedCount:u}}catch(i){throw await s.query("ROLLBACK"),i}finally{s.release()}}});import{zValidator as v}from"@hono/zod-validator";import{Hono as cr}from"hono";import{z as ot}from"zod";var W,x,nt=f(()=>{"use strict";Xe();et();rt();_();W=ot.object({database:ot.string()}),x=new cr;x.post("/",v("json",Le),v("query",W),async t=>{try{let e=t.req.valid("json"),{tableName:r,data:o}=e,{database:a}=t.req.valid("query"),n=await Ze({tableName:r,data:o,database:a});return t.json(n)}catch(e){let r=e&&typeof e=="object"&&"detail"in e?e.detail:void 0;return t.json({success:!1,message:e instanceof Error?e.message:"Failed to create record",detail:r},500)}});x.patch("/",v("json",Oe),v("query",W),async t=>{try{let e=t.req.valid("json"),{tableName:r,updates:o,primaryKey:a}=e,{database:n}=t.req.valid("query"),s=await tt({tableName:r,updates:o,primaryKey:a,database:n});return t.json(s)}catch(e){let r=e&&typeof e=="object"&&"detail"in e?e.detail:void 0;return t.json({success:!1,message:e instanceof Error?e.message:"Failed to update records",detail:r},500)}});x.delete("/",v("json",Z),v("query",W),async t=>{try{let e=t.req.valid("json"),{tableName:r,primaryKeys:o}=e,{database:a}=t.req.valid("query"),n=await Ge({tableName:r,primaryKeys:o,database:a});return n.fkViolation?t.json(n,409):t.json(n)}catch(e){let r=e&&typeof e=="object"&&"detail"in e?e.detail:void 0;return t.json({success:!1,message:e instanceof Error?e.message:"Failed to delete records",detail:r},500)}});x.delete("/force",v("json",Z),v("query",W),async t=>{try{let e=t.req.valid("json"),{tableName:r,primaryKeys:o}=e,{database:a}=t.req.valid("query"),n=await Je({tableName:r,primaryKeys:o,database:a});return t.json(n)}catch(e){let r=e&&typeof e=="object"&&"detail"in e?e.detail:void 0;return t.json({success:!1,message:e instanceof Error?e.message:"Failed to force delete records",detail:r},500)}})});var at,st=f(()=>{"use strict";T();at=async(t,e)=>{let{tableName:r,fields:o,foreignKeys:a}=t,s=await b(e).connect();try{let i=o.map(l=>{let g=`"${l.columnName}" ${l.columnType}`;return l.isArray&&(g+="[]"),l.isPrimaryKey&&(g+=" PRIMARY KEY"),l.isUnique&&!l.isPrimaryKey&&(g+=" UNIQUE"),l.isNullable||(g+=" NOT NULL"),l.isIdentity&&(g+=" GENERATED ALWAYS AS IDENTITY"),l.defaultValue&&!l.isIdentity&&(g+=` DEFAULT ${l.defaultValue}`),g}),m=a?.map(l=>`CONSTRAINT "${`fk_${r}_${l.columnName}_${l.referencedTable}_${l.referencedColumn}`}" FOREIGN KEY ("${l.columnName}") REFERENCES "${l.referencedTable}" ("${l.referencedColumn}") ON UPDATE ${l.onUpdate} ON DELETE ${l.onDelete}`)||[],u=[...i,...m],d=`
|
|
191
191
|
CREATE TABLE "${r}" (
|
|
192
192
|
${u.join(`,
|
|
193
193
|
`)}
|
|
@@ -201,5 +201,5 @@ This will return the 5 customers with the highest total order value. You might a
|
|
|
201
201
|
WHERE t.table_schema = 'public'
|
|
202
202
|
AND t.table_type = 'BASE TABLE'
|
|
203
203
|
ORDER BY t.table_name;
|
|
204
|
-
`)).rows.map(a=>({tableName:a.tableName,rowCount:Number(a.rowCount)}))}finally{r.release()}}});import{zValidator as ne}from"@hono/zod-validator";import{Hono as lr}from"hono";var M,lt=f(()=>{"use strict";st();ct();_();V();M=new lr;M.get("/",ne("query",L),async t=>{try{let{database:e}=t.req.valid("query"),r=await it(e);return t.json(r)}catch(e){return $(t,e,"Failed to fetch tables")}});M.post("/",ne("json",Pe),ne("query",L),async t=>{try{let e=t.req.valid("json"),{database:r}=t.req.valid("query"),o=await at(e,r);return t.json(o)}catch(e){let r=e&&typeof e=="object"&&"detail"in e?e.detail:void 0;return t.json({success:!1,message:e instanceof Error?e.message:"Failed to create table",detail:r},500)}})});import{Hono as ur}from"hono";var ut,mr,dr,mt,dt=f(()=>{"use strict";Y();ut=async()=>{let t=await C.connect();try{return await t.query("SELECT 1"),{success:!0}}catch(e){return{success:!1,error:e instanceof Error?e.message:"Unknown error"}}finally{t.release()}},mr=5e3,dr=1e4,mt=t=>{let e=new ur;return e.get("/",t(()=>{let r;return{onOpen:async(o,a)=>{try{let n=await ut();a.send(JSON.stringify({...n,status:n.success?"connected":"failed",timestamp:new Date().toISOString()}))}catch{a.send(JSON.stringify({success:!1,status:"failed",error:"Initial check failed",timestamp:new Date().toISOString()}))}r=setInterval(async()=>{try{let n=await Promise.race([ut(),new Promise((s,i)=>setTimeout(()=>i({success:!1,error:"Database check timeout"}),dr))]);a.send(JSON.stringify({...n,status:n.success?"connected":"failed",timestamp:new Date().toISOString()}))}catch(n){a.send(JSON.stringify({success:!1,status:"failed",error:n instanceof Error?n.message:"Check failed",timestamp:new Date().toISOString()}))}},mr)},onMessage(o,a){},onClose:()=>{r&&clearInterval(r)},onError:o=>{r&&clearInterval(r)}}})),e}});var gt={};
|
|
204
|
+
`)).rows.map(a=>({tableName:a.tableName,rowCount:Number(a.rowCount)}))}finally{r.release()}}});import{zValidator as ne}from"@hono/zod-validator";import{Hono as lr}from"hono";var M,lt=f(()=>{"use strict";st();ct();_();V();M=new lr;M.get("/",ne("query",L),async t=>{try{let{database:e}=t.req.valid("query"),r=await it(e);return t.json(r)}catch(e){return $(t,e,"Failed to fetch tables")}});M.post("/",ne("json",Pe),ne("query",L),async t=>{try{let e=t.req.valid("json"),{database:r}=t.req.valid("query"),o=await at(e,r);return t.json(o)}catch(e){let r=e&&typeof e=="object"&&"detail"in e?e.detail:void 0;return t.json({success:!1,message:e instanceof Error?e.message:"Failed to create table",detail:r},500)}})});import{Hono as ur}from"hono";var ut,mr,dr,mt,dt=f(()=>{"use strict";Y();ut=async()=>{let t=await C.connect();try{return await t.query("SELECT 1"),{success:!0}}catch(e){return{success:!1,error:e instanceof Error?e.message:"Unknown error"}}finally{t.release()}},mr=5e3,dr=1e4,mt=t=>{let e=new ur;return e.get("/",t(()=>{let r;return{onOpen:async(o,a)=>{try{let n=await ut();a.send(JSON.stringify({...n,status:n.success?"connected":"failed",timestamp:new Date().toISOString()}))}catch{a.send(JSON.stringify({success:!1,status:"failed",error:"Initial check failed",timestamp:new Date().toISOString()}))}r=setInterval(async()=>{try{let n=await Promise.race([ut(),new Promise((s,i)=>setTimeout(()=>i({success:!1,error:"Database check timeout"}),dr))]);a.send(JSON.stringify({...n,status:n.success?"connected":"failed",timestamp:new Date().toISOString()}))}catch(n){a.send(JSON.stringify({success:!1,status:"failed",error:n instanceof Error?n.message:"Check failed",timestamp:new Date().toISOString()}))}},mr)},onMessage(o,a){},onClose:()=>{r&&clearInterval(r)},onError:o=>{r&&clearInterval(r)}}})),e}});var gt={};vt(gt,{createServer:()=>hr});import B from"path";import{fileURLToPath as pr}from"url";import{serveStatic as pt}from"@hono/node-server/serve-static";import{createNodeWebSocket as fr}from"@hono/node-ws";import{Hono as gr}from"hono";import{cors as br}from"hono/cors";import{logger as yr}from"hono/logger";var ft,hr,bt=f(()=>{"use strict";$e();Ie();Ke();He();Ye();nt();lt();dt();ft=()=>{if(process.env.NODE_ENV==="development")return B.resolve(process.cwd(),"../core/dist");let t=B.dirname(pr(import.meta.url));return B.resolve(t,"./core-dist")},hr=()=>{let t=new gr({strict:!1}),{upgradeWebSocket:e,injectWebSocket:r}=fr({app:t});return t.use("/*",br()),process.env.NODE_ENV==="development"&&t.use(yr()),t.use("/favicon.ico",pt({path:B.resolve(ft(),"favicon.ico")})),t.use("*",async(o,a)=>{o.header("Access-Control-Allow-Origin","*"),o.header("Access-Control-Allow-Methods","GET, POST, PUT, DELETE, OPTIONS"),o.header("Access-Control-Allow-Headers","Content-Type"),await a()}),t.route("/ws",mt(e)),t.route("/databases",O),t.route("/tables",M),t.route("/tables/:tableName/columns",ee),t.route("/tables/:tableName/data",te),t.route("/records",x),t.route("/query",re),t.route("/chat",X),t.use("/*",pt({root:ft()})),{app:t,injectWebSocket:r}}});import{intro as Er,outro as wr}from"@clack/prompts";import{serve as Tr}from"@hono/node-server";import Sr from"open";import ae from"picocolors";import{program as ce}from"commander";var le=()=>(ce.name("db-studio").option("-e, --env <path>","Path to custom .env file").option("-p, --port <port>","Port to run the server on").option("-d, --database-url <url>","Database URL to use").option("-n, --var-name <name>","Custom environment variable name (default: DATABASE_URL)").option("-s, --status","Show status of the server").option("-h, --help","Show help").option("-v, --version","Show version").parse(process.argv),ce.opts());import{readFile as Dt}from"fs/promises";import{resolve as Rt}from"path";import{cancel as k,isCancel as Q,note as ue,select as Ct,spinner as _t,text as me}from"@clack/prompts";import{parse as $t}from"dotenv";import z from"picocolors";var de=async(t,e)=>{let r=e||"DATABASE_URL";if(t?.[r])return t[r];let o=_t();o.start("Looking for database connection..."),t?ue(z.red(`${r} not found in .env`)):ue(z.red("No .env file found in current directory"));let a=await Ct({message:`How do you want to provide ${r}?`,options:[{value:"manual",label:"Enter connection string manually"},{value:"other-env",label:"Use different .env file"},{value:"cancel",label:"Cancel / Exit"}],initialValue:"manual"});if((Q(a)||a==="cancel")&&(k("No database connection provided. Exiting..."),process.exit(0)),a==="other-env"){o.start("Waiting for path...");let s=await me({message:"Enter path to .env file",placeholder:"~/projects/myapp/.env.local or ./special.env",validate(m){if(!m.trim())return"Path is required"}});Q(s)&&(k("Cancelled."),process.exit(0)),o.stop("Trying custom .env...");let i=Rt(s);try{let m=await Dt(i,"utf-8"),u=$t(m);if(u[r])return u[r];throw new Error(`${r} still missing in custom file`)}catch(m){let u=m;k(`Cannot read or parse file: ${z.dim(u.message)}`),process.exit(1)}}o.stop("Manual input...");let n=await me({message:`Paste your ${r}`,placeholder:"postgresql://user:password@localhost:5432/mydb",validate(s){if(!s.trim())return"Connection string is required!";try{new URL(s);return}catch{return"Must be a valid URL format"}}});return Q(n)&&(k("Cancelled."),process.exit(0)),n.trim()};import{access as xt,readFile as Pt}from"fs/promises";import{resolve as pe}from"path";import{parse as At}from"dotenv";var R=async t=>{let e=t?pe(t):pe(process.cwd(),".env");try{await xt(e);let r=await Pt(e,"utf-8");return At(r)}catch(r){if(r instanceof Error&&r.message.includes("ENOENT"))return null;throw r}};import{intro as Lt,outro as Ot}from"@clack/prompts";import fe from"picocolors";var ge=()=>{Lt(fe.inverse(" db-studio ")),Ot(fe.green("For more information, visit: https://dbstudio.sh/docs"))};import{intro as qt,note as kt,outro as be}from"@clack/prompts";import j from"picocolors";I();var ye=async(t,e,r)=>{qt(j.inverse(" db-studio "));let o=r||N.VAR_NAME,a=null;if(e)a=e;else{let n=t?await R(t):await R(N.ENV);n?.[o]&&(a=n[o])}a?be(j.green(`\u2713 Database connection configured (using ${o})`)):(kt(j.red(`\u2717 ${o} not found`),"Status"),be(j.yellow("\u26A0 No database connection configured")))};import{intro as jt,outro as Ut}from"@clack/prompts";import Ee from"picocolors";var he={name:"db-studio",type:"module",version:"1.2.8",description:"Modern database client for PostgreSQL with spreadsheet-like grid, AI-powered SQL assistance, ER diagrams, fast data browsing and editing. CLI tool, upcoming desktop & web versions.",keywords:["database","database client","postgres","postgresql","database gui","sql client","database studio","postgres gui","ai sql","sql editor","er diagram","database management","data browser","spreadsheet database","postgres admin","mysql client","sqlite client","database tool","developer tools"],author:"H\xFCsam \u{1F951} <devhsmq@gmail.com>",homepage:"https://dbstudio.sh",repository:{type:"git",url:"git+https://github.com/husamql3/db-studio.git"},bugs:{url:"https://github.com/husamql3/db-studio/issues"},license:"MIT",bin:{"db-studio":"./dist/index.js"},files:["dist"],scripts:{dev:"NODE_ENV=development tsx watch src/index.ts",build:"tsup","build:release":"tsup --minify --sourcemap",start:"node dist/index.js",check:"biome check --write --unsafe --verbose"},dependencies:{"@clack/prompts":"^0.11.0","@hono/node-server":"^1.19.7","@hono/node-ws":"^1.2.0","@hono/zod-validator":"^0.7.6","@tanstack/ai-openai":"^0.2.1","@upstash/redis":"^1.36.1",commander:"^12.1.0",dotenv:"^16.4.7",hono:"^4.10.4",open:"^10.0.2",pg:"^8.13.1",picocolors:"^1.1.1",zod:"^4.2.1"},devDependencies:{"@biomejs/biome":"^2.2.6","@biomejs/cli-linux-x64":"^2.2.6","@types/node":"^20.11.17","@types/pg":"^8.16.0",tsup:"^8.5.1",tsx:"^4.7.1",typescript:"^5.8.3",wrangler:"^4.4.0"}};var we=()=>{jt(Ee.inverse(" db-studio ")),Ut(Ee.green(`\u{1F680} db-studio v${he.version}`))};I();var Nr=async()=>{let{env:t,port:e,databaseUrl:r,varName:o,status:a,help:n,version:s}=le();n&&(ge(),process.exit(0)),s&&(we(),process.exit(0)),a&&(await ye(t,r,o),process.exit(0)),Er(ae.inverse(" db-studio "));let i=e?parseInt(e,10):N.PORT,m=o||N.VAR_NAME,u=t?await R(t):await R(N.ENV),d=r||await de(u,m);process.env.DATABASE_URL=d;let{createServer:l}=await Promise.resolve().then(()=>(bt(),gt)),{app:g,injectWebSocket:w}=l(),y=Tr({fetch:g.fetch,port:i});w(y),wr(ae.green(`Server running at ${ae.cyan(`http://localhost:${i}`)}`)),process.env.NODE_ENV&&process.env.NODE_ENV!=="development"&&await Sr(`http://localhost:${i}`)};Nr().catch(t=>{process.exit(1)});export{Nr as main};
|
|
205
205
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/defaults.ts","../src/db.ts","../src/db-manager.ts","../src/types/column.types.ts","../src/dao/table-columns.dao.ts","../src/dao/table-details-schema.ts","../src/utils/system-prompt-generator.ts","../src/routes/chat.routes.ts","../src/types/create-table.type.ts","../src/utils/error-handler.ts","../src/routes/columns.routes.ts","../src/dao/tables-data.dao.ts","../src/routes/data.routes.ts","../src/dao/database-list.dao.ts","../src/routes/databases.routes.ts","../src/dao/query.dao.ts","../src/routes/query.routes.ts","../src/dao/delete-records.dao.ts","../src/dao/insert-record.dao.ts","../src/dao/update-records.dao.ts","../src/routes/records.routes.ts","../src/dao/create-table.dao.ts","../src/dao/table-list.dao.ts","../src/routes/tables.routes.ts","../src/routes/websocket.routes.ts","../src/utils/create-server.ts","../src/index.ts","../src/cmd/args.ts","../src/cmd/get-db-url.ts","../src/cmd/load-env.ts","../src/cmd/show-help.ts","../src/cmd/show-status.ts","../src/cmd/show-version.ts","../package.json"],"sourcesContent":["export const DEFAULTS = {\n\tPORT: 3333,\n\tENV: \".env\",\n\tVAR_NAME: \"DATABASE_URL\",\n\tPROXY_URL:\n\t\tprocess.env.NODE_ENV === \"development\"\n\t\t\t? \"http://localhost:8787\"\n\t\t\t: \"https://db-studio-proxy.husamql3.workers.dev\",\n};\n","import { Pool } from \"pg\";\n\nlet dbInstance: Pool | null = null;\n\nconst getPool = (): Pool => {\n\tif (!dbInstance) {\n\t\tif (!process.env.DATABASE_URL) {\n\t\t\tthrow new Error(\n\t\t\t\t\"DATABASE_URL is not set. Please provide a database connection string.\",\n\t\t\t);\n\t\t}\n\t\ttry {\n\t\t\tdbInstance = new Pool({\n\t\t\t\tconnectionString: process.env.DATABASE_URL,\n\t\t\t});\n\n\t\t\t// Handle pool errors to prevent server crashes\n\t\t\t// This catches connection errors, idle client errors, etc.\n\t\t\tdbInstance.on(\"error\", (err) => {\n\t\t\t\tconsole.error(\"Unexpected database pool error:\", err.message);\n\t\t\t\t// Don't throw - just log the error to prevent server crash\n\t\t\t\t// The pool will automatically retry connections\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tconsole.error(\"Failed to create database pool:\", error);\n\t\t\t// Re-throw initialization errors as they indicate a configuration problem\n\t\t\tthrow error;\n\t\t}\n\t}\n\treturn dbInstance;\n};\n\n// Export db as a Proxy that lazily initializes the pool\n// This allows process.env.DATABASE_URL to be set after module import\nexport const db = new Proxy({} as Pool, {\n\tget(_target, prop) {\n\t\ttry {\n\t\t\treturn getPool()[prop as keyof Pool];\n\t\t} catch (error) {\n\t\t\t// If pool initialization fails, log and re-throw\n\t\t\tconsole.error(\"Database pool access error:\", error);\n\t\t\tthrow error;\n\t\t}\n\t},\n});\n","import type { PoolConfig } from \"pg\";\nimport { Pool } from \"pg\";\n\n/**\n * DatabaseManager - Manages multiple database connection pools\n * Allows switching between different databases on the same PostgreSQL server\n */\nclass DatabaseManager {\n\tprivate pools: Map<string, Pool> = new Map();\n\tprivate baseConfig: {\n\t\turl: string;\n\t\thost: string;\n\t\tport: number;\n\t\tuser: string;\n\t\tpassword: string;\n\t} | null = null;\n\n\tconstructor() {\n\t\tthis.initializeBaseConfig();\n\t}\n\n\t/**\n\t * Parse DATABASE_URL and extract connection details\n\t */\n\tprivate initializeBaseConfig() {\n\t\tconst databaseUrl = process.env.DATABASE_URL;\n\t\tif (!databaseUrl) {\n\t\t\tthrow new Error(\n\t\t\t\t\"DATABASE_URL is not set. Please provide a database connection string.\",\n\t\t\t);\n\t\t}\n\n\t\ttry {\n\t\t\tconst url = new URL(databaseUrl);\n\t\t\tthis.baseConfig = {\n\t\t\t\turl: databaseUrl,\n\t\t\t\thost: url.hostname,\n\t\t\t\tport: Number.parseInt(url.port, 10) || 5432,\n\t\t\t\tuser: url.username,\n\t\t\t\tpassword: url.password,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tthrow new Error(`Failed to parse DATABASE_URL: ${error}`);\n\t\t}\n\t}\n\n\t/**\n\t * Build a connection string for the specified database\n\t * @param database - The database name (optional, defaults to database from DATABASE_URL)\n\t * @returns The connection string for the specified database\n\t * @throws Error if database is invalid or unknown\n\t */\n\tbuildConnectionString(database?: string): string {\n\t\tif (!this.baseConfig) {\n\t\t\tthrow new Error(\"Base configuration not initialized\");\n\t\t}\n\n\t\t// If no database specified, extract from original DATABASE_URL\n\t\tif (!database) {\n\t\t\tconst databaseUrl = this.baseConfig.url;\n\t\t\tif (databaseUrl) {\n\t\t\t\tconst url = new URL(databaseUrl);\n\t\t\t\tdatabase = url.pathname.slice(1); // Remove leading slash\n\t\t\t}\n\t\t}\n\n\t\t// if (!database || database.trim() === \"\") {\n\t\t// \tthrow new Error(\"Database name is required and cannot be empty\");\n\t\t// }\n\n\t\t// Validate database name format (PostgreSQL identifiers)\n\t\t// Database names cannot contain special characters that would break URL parsing\n\t\t// if (!/^[a-zA-Z_][a-zA-Z0-9_$]*$/.test(database)) {\n\t\t// \tthrow new Error(\n\t\t// \t\t`Invalid database name: \"${database}\". Database names must start with a letter or underscore and contain only alphanumeric characters, underscores, or dollar signs.`,\n\t\t// \t);\n\t\t// }\n\n\t\ttry {\n\t\t\tconst url = new URL(this.baseConfig.url);\n\t\t\turl.pathname = `/${database}`;\n\t\t\treturn url.toString();\n\t\t} catch (error) {\n\t\t\tthrow new Error(\n\t\t\t\t`Failed to build connection string for database \"${database}\": ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Get or create a connection pool for the specified database\n\t * Pools are cached by connection string to ensure distinct connections per database\n\t */\n\tgetPool(database?: string): Pool {\n\t\t// Build connection string first to validate the database\n\t\tconst connectionString = this.buildConnectionString(database);\n\n\t\t// Use connection string as the cache key\n\t\tif (!this.pools.has(connectionString)) {\n\t\t\tconst poolConfig: PoolConfig = {\n\t\t\t\tconnectionString,\n\t\t\t\tmax: 10, // Maximum number of clients in the pool\n\t\t\t\tidleTimeoutMillis: 30000, // Close idle clients after 30 seconds\n\t\t\t\tconnectionTimeoutMillis: 2000, // Return an error after 2 seconds if connection cannot be established\n\t\t\t};\n\n\t\t\tconst pool = new Pool(poolConfig);\n\n\t\t\t// Handle pool errors\n\t\t\tpool.on(\"error\", (err) => {\n\t\t\t\tconsole.error(\n\t\t\t\t\t`Unexpected error on database pool for \"${connectionString}\":`,\n\t\t\t\t\terr.message,\n\t\t\t\t);\n\t\t\t});\n\n\t\t\tthis.pools.set(connectionString, pool);\n\t\t\tconsole.log(`Created connection pool for: ${connectionString}`);\n\t\t}\n\n\t\treturn this.pools.get(connectionString) ?? new Pool({ connectionString });\n\t}\n\n\t/**\n\t * Close a specific database pool by connection string\n\t */\n\tasync closePool(connectionString: string): Promise<void> {\n\t\tconst pool = this.pools.get(connectionString);\n\t\tif (pool) {\n\t\t\tawait pool.end();\n\t\t\tthis.pools.delete(connectionString);\n\t\t\tconsole.log(`Closed connection pool for: ${connectionString}`);\n\t\t}\n\t}\n\n\t/**\n\t * Close a specific database pool by database name\n\t */\n\tasync closePoolByDatabase(database: string): Promise<void> {\n\t\tconst connectionString = this.buildConnectionString(database);\n\t\tawait this.closePool(connectionString);\n\t}\n\n\t/**\n\t * Close all database pools\n\t */\n\tasync closeAll(): Promise<void> {\n\t\tconst closePromises = Array.from(this.pools.entries()).map(\n\t\t\tasync ([connectionString, pool]) => {\n\t\t\t\tawait pool.end();\n\t\t\t\tconsole.log(`Closed connection pool for: ${connectionString}`);\n\t\t\t},\n\t\t);\n\t\tawait Promise.all(closePromises);\n\t\tthis.pools.clear();\n\t}\n\n\t/**\n\t * Get all active pool connection strings\n\t */\n\tgetActivePools(): string[] {\n\t\treturn Array.from(this.pools.keys());\n\t}\n}\n\n// Singleton instance\nconst databaseManager = new DatabaseManager();\n\n/**\n * Get a database pool for the specified database\n * If no database is specified, returns the default database pool\n */\nexport const getDbPool = (database?: string): Pool => {\n\treturn databaseManager.getPool(database);\n};\n\n/**\n * Build a connection string for the specified database\n */\nexport const buildDbConnectionString = (database?: string): string => {\n\treturn databaseManager.buildConnectionString(database);\n};\n\n/**\n * Close a specific database pool by database name\n */\nexport const closeDbPool = async (database: string): Promise<void> => {\n\treturn databaseManager.closePoolByDatabase(database);\n};\n\n/**\n * Close a specific database pool by connection string\n */\nexport const closeDbPoolByConnectionString = async (\n\tconnectionString: string,\n): Promise<void> => {\n\treturn databaseManager.closePool(connectionString);\n};\n\n/**\n * Close all database pools\n */\nexport const closeAllDbPools = async (): Promise<void> => {\n\treturn databaseManager.closeAll();\n};\n\n/**\n * Get list of active pool connection strings\n */\nexport const getActivePools = (): string[] => {\n\treturn databaseManager.getActivePools();\n};\n\nexport default databaseManager;\n","export const DataTypes = {\n\ttext: \"text\",\n\tboolean: \"boolean\",\n\tnumber: \"number\",\n\tenum: \"enum\",\n\tjson: \"json\",\n\tdate: \"date\",\n\tarray: \"array\",\n} as const;\n\nexport type DataTypes = (typeof DataTypes)[keyof typeof DataTypes];\n\n/**\n * Maps PostgreSQL data types to generic DataType enum\n */\nexport function mapPostgresToDataType(pgType: string): DataTypes {\n\tconst normalized = pgType.toLowerCase().trim();\n\n\t// Handle array types and date/time types\n\tif (\n\t\tnormalized.includes(\"[]\") ||\n\t\tnormalized === \"date\" ||\n\t\tnormalized === \"time\" ||\n\t\tnormalized === \"time without time zone\" ||\n\t\tnormalized.startsWith(\"time(\") ||\n\t\tnormalized === \"timestamp\" ||\n\t\tnormalized === \"timestamp without time zone\" ||\n\t\tnormalized.startsWith(\"timestamp(\") ||\n\t\tnormalized === \"timestamp with time zone\" ||\n\t\tnormalized === \"timestamptz\" ||\n\t\tnormalized.startsWith(\"timestamp with time zone(\")\n\t) {\n\t\treturn DataTypes.date;\n\t}\n\n\t// Numeric types\n\tif (\n\t\tnormalized === \"integer\" ||\n\t\tnormalized === \"int\" ||\n\t\tnormalized === \"int4\" ||\n\t\tnormalized === \"bigint\" ||\n\t\tnormalized === \"int8\" ||\n\t\tnormalized === \"smallint\" ||\n\t\tnormalized === \"int2\" ||\n\t\tnormalized === \"decimal\" ||\n\t\tnormalized.startsWith(\"decimal(\") ||\n\t\tnormalized === \"numeric\" ||\n\t\tnormalized.startsWith(\"numeric(\") ||\n\t\tnormalized === \"real\" ||\n\t\tnormalized === \"float4\" ||\n\t\tnormalized === \"double precision\" ||\n\t\tnormalized === \"float8\" ||\n\t\tnormalized === \"float\" ||\n\t\tnormalized === \"serial\" ||\n\t\tnormalized === \"serial4\" ||\n\t\tnormalized === \"bigserial\" ||\n\t\tnormalized === \"serial8\" ||\n\t\tnormalized === \"money\"\n\t) {\n\t\treturn DataTypes.number;\n\t}\n\n\t// Boolean\n\tif (normalized === \"boolean\" || normalized === \"bool\") {\n\t\treturn DataTypes.boolean;\n\t}\n\n\t// JSON types\n\tif (normalized === \"json\" || normalized === \"jsonb\") {\n\t\treturn DataTypes.json;\n\t}\n\n\t// Enum types and long text types\n\tif (\n\t\tnormalized.startsWith(\"user-defined\") ||\n\t\tnormalized === \"enum\" ||\n\t\tnormalized === \"text\" ||\n\t\tnormalized === \"xml\"\n\t) {\n\t\treturn DataTypes.text;\n\t}\n\n\t// Short string types (varchar, char, uuid, etc.)\n\tif (\n\t\tnormalized === \"character varying\" ||\n\t\tnormalized.startsWith(\"varchar\") ||\n\t\tnormalized.startsWith(\"character varying(\") ||\n\t\tnormalized === \"character\" ||\n\t\tnormalized.startsWith(\"char\") ||\n\t\tnormalized.startsWith(\"character(\") ||\n\t\tnormalized === \"bpchar\" ||\n\t\tnormalized === \"uuid\" ||\n\t\tnormalized === \"interval\" ||\n\t\tnormalized.startsWith(\"interval\") ||\n\t\tnormalized === \"bytea\" ||\n\t\tnormalized === \"point\" ||\n\t\tnormalized === \"line\" ||\n\t\tnormalized === \"polygon\" ||\n\t\tnormalized === \"inet\" ||\n\t\tnormalized === \"cidr\" ||\n\t\tnormalized === \"macaddr\" ||\n\t\tnormalized === \"macaddr8\"\n\t) {\n\t\treturn DataTypes.text;\n\t}\n\n\t// Default to short for unrecognized types\n\treturn DataTypes.text;\n}\n\n/**\n * Standardized data type labels\n */\nexport const StandardizedDataType = {\n\t// Numeric types\n\tint: \"int\",\n\tbigint: \"bigint\",\n\tsmallint: \"smallint\",\n\tnumeric: \"numeric\",\n\tfloat: \"float\",\n\tdouble: \"double\",\n\tmoney: \"money\",\n\t// Boolean\n\tboolean: \"boolean\",\n\t// Text types\n\ttext: \"text\",\n\tvarchar: \"varchar\",\n\tchar: \"char\",\n\t// JSON types\n\tjson: \"json\",\n\tjsonb: \"jsonb\",\n\txml: \"xml\",\n\t// UUID\n\tuuid: \"uuid\",\n\t// Date/Time types\n\tdate: \"date\",\n\ttime: \"time\",\n\ttimestamp: \"timestamp\",\n\ttimestamptz: \"timestamptz\",\n\tinterval: \"interval\",\n\t// Binary\n\tbytea: \"bytea\",\n\t// Network types\n\tinet: \"inet\",\n\tcidr: \"cidr\",\n\tmacaddr: \"macaddr\",\n\tmacaddr8: \"macaddr8\",\n\t// Geometric types\n\tpoint: \"point\",\n\tline: \"line\",\n\tpolygon: \"polygon\",\n\t// Complex types\n\tarray: \"array\",\n\tenum: \"enum\",\n} as const;\n\nexport type StandardizedDataType =\n\t(typeof StandardizedDataType)[keyof typeof StandardizedDataType];\n\n/**\n * Maps PostgreSQL data types to standardized display labels\n */\nexport function standardizeDataTypeLabel(pgType: string): StandardizedDataType {\n\tconst normalized = pgType.toLowerCase().trim();\n\n\t// Numeric types\n\tif (\n\t\tnormalized === \"integer\" ||\n\t\tnormalized === \"int\" ||\n\t\tnormalized === \"int4\" ||\n\t\tnormalized === \"serial\" ||\n\t\tnormalized === \"serial4\"\n\t) {\n\t\treturn StandardizedDataType.int;\n\t}\n\n\tif (\n\t\tnormalized === \"bigint\" ||\n\t\tnormalized === \"int8\" ||\n\t\tnormalized === \"bigserial\" ||\n\t\tnormalized === \"serial8\"\n\t) {\n\t\treturn StandardizedDataType.bigint;\n\t}\n\n\tif (normalized === \"smallint\" || normalized === \"int2\") {\n\t\treturn StandardizedDataType.smallint;\n\t}\n\n\tif (\n\t\tnormalized === \"decimal\" ||\n\t\tnormalized.startsWith(\"decimal(\") ||\n\t\tnormalized === \"numeric\" ||\n\t\tnormalized.startsWith(\"numeric(\")\n\t) {\n\t\treturn StandardizedDataType.numeric;\n\t}\n\n\tif (normalized === \"real\" || normalized === \"float4\") {\n\t\treturn StandardizedDataType.float;\n\t}\n\n\tif (\n\t\tnormalized === \"double precision\" ||\n\t\tnormalized === \"float8\" ||\n\t\tnormalized === \"float\"\n\t) {\n\t\treturn StandardizedDataType.double;\n\t}\n\n\tif (normalized === \"money\") {\n\t\treturn StandardizedDataType.money;\n\t}\n\n\t// Boolean\n\tif (normalized === \"boolean\" || normalized === \"bool\") {\n\t\treturn StandardizedDataType.boolean;\n\t}\n\n\t// Text types\n\tif (normalized === \"text\") {\n\t\treturn StandardizedDataType.text;\n\t}\n\n\tif (\n\t\tnormalized === \"character varying\" ||\n\t\tnormalized.startsWith(\"varchar\") ||\n\t\tnormalized.startsWith(\"character varying(\")\n\t) {\n\t\treturn StandardizedDataType.varchar;\n\t}\n\n\tif (\n\t\tnormalized === \"character\" ||\n\t\tnormalized.startsWith(\"char\") ||\n\t\tnormalized.startsWith(\"character(\") ||\n\t\tnormalized === \"bpchar\"\n\t) {\n\t\treturn StandardizedDataType.char;\n\t}\n\n\t// JSON types\n\tif (normalized === \"json\") {\n\t\treturn StandardizedDataType.json;\n\t}\n\n\tif (normalized === \"jsonb\") {\n\t\treturn StandardizedDataType.jsonb;\n\t}\n\n\tif (normalized === \"xml\") {\n\t\treturn StandardizedDataType.xml;\n\t}\n\n\t// UUID\n\tif (normalized === \"uuid\") {\n\t\treturn StandardizedDataType.uuid;\n\t}\n\n\t// Date/Time types\n\tif (normalized === \"date\") {\n\t\treturn StandardizedDataType.date;\n\t}\n\n\tif (\n\t\tnormalized === \"time\" ||\n\t\tnormalized === \"time without time zone\" ||\n\t\tnormalized.startsWith(\"time(\")\n\t) {\n\t\treturn StandardizedDataType.time;\n\t}\n\n\tif (\n\t\tnormalized === \"timestamp\" ||\n\t\tnormalized === \"timestamp without time zone\" ||\n\t\tnormalized.startsWith(\"timestamp(\")\n\t) {\n\t\treturn StandardizedDataType.timestamp;\n\t}\n\n\tif (\n\t\tnormalized === \"timestamp with time zone\" ||\n\t\tnormalized === \"timestamptz\" ||\n\t\tnormalized.startsWith(\"timestamp with time zone(\")\n\t) {\n\t\treturn StandardizedDataType.timestamptz;\n\t}\n\n\tif (normalized === \"interval\" || normalized.startsWith(\"interval\")) {\n\t\treturn StandardizedDataType.interval;\n\t}\n\n\t// Binary\n\tif (normalized === \"bytea\") {\n\t\treturn StandardizedDataType.bytea;\n\t}\n\n\t// Network types\n\tif (normalized === \"inet\") {\n\t\treturn StandardizedDataType.inet;\n\t}\n\n\tif (normalized === \"cidr\") {\n\t\treturn StandardizedDataType.cidr;\n\t}\n\n\tif (normalized === \"macaddr\") {\n\t\treturn StandardizedDataType.macaddr;\n\t}\n\n\tif (normalized === \"macaddr8\") {\n\t\treturn StandardizedDataType.macaddr8;\n\t}\n\n\t// Geometric types\n\tif (normalized === \"point\") {\n\t\treturn StandardizedDataType.point;\n\t}\n\n\tif (normalized === \"line\") {\n\t\treturn StandardizedDataType.line;\n\t}\n\n\tif (normalized === \"polygon\") {\n\t\treturn StandardizedDataType.polygon;\n\t}\n\n\t// Array types\n\t// todo: handle array types\n\tif (normalized.startsWith(\"array\") || normalized.includes(\"[]\")) {\n\t\treturn StandardizedDataType.text;\n\t}\n\n\t// User-defined types (enums)\n\tif (normalized.startsWith(\"user-defined\") || normalized === \"enum\") {\n\t\treturn StandardizedDataType.enum;\n\t}\n\n\t// Default: return the original type\n\treturn StandardizedDataType.text;\n}\n","import { getDbPool } from \"@/db-manager.js\";\nimport {\n\ttype DataTypes,\n\tmapPostgresToDataType,\n\ttype StandardizedDataType,\n\tstandardizeDataTypeLabel,\n} from \"../types/column.types.js\";\n\nexport interface ColumnInfo {\n\tcolumnName: string; // The column name from the database\n\tdataType: DataTypes; // Generic type mapped to cell variant (text/boolean/number/enum/json/date)\n\tdataTypeLabel: StandardizedDataType; // Exact database type (int/varchar/timestamp/etc.)\n\tisNullable: boolean;\n\tcolumnDefault: string | null;\n\tisPrimaryKey: boolean;\n\tisForeignKey: boolean;\n\treferencedTable: string | null;\n\treferencedColumn: string | null;\n\tenumValues: string[] | null;\n}\n\nexport const getTableColumns = async (\n\ttableName: string,\n\tdatabase?: string,\n): Promise<ColumnInfo[]> => {\n\tconst pool = getDbPool(database);\n\tconst client = await pool.connect();\n\n\ttry {\n\t\tconst res = await client.query(\n\t\t\t`\n SELECT \n c.column_name as \"columnName\",\n c.data_type as \"dataType\",\n c.udt_name as \"udtName\",\n c.is_nullable = 'YES' as \"isNullable\",\n c.column_default as \"columnDefault\",\n CASE WHEN pk.column_name IS NOT NULL THEN true ELSE false END as \"isPrimaryKey\",\n CASE WHEN fk.column_name IS NOT NULL THEN true ELSE false END as \"isForeignKey\",\n fk.referenced_table as \"referencedTable\",\n fk.referenced_column as \"referencedColumn\",\n CASE \n WHEN c.data_type = 'USER-DEFINED' THEN \n (SELECT array_agg(e.enumlabel ORDER BY e.enumsortorder)\n FROM pg_type t\n JOIN pg_enum e ON t.oid = e.enumtypid\n WHERE t.typname = c.udt_name)\n ELSE NULL\n END as \"enumValues\"\n FROM information_schema.columns c\n LEFT JOIN (\n SELECT ku.column_name\n FROM information_schema.table_constraints tc\n JOIN information_schema.key_column_usage ku\n ON tc.constraint_name = ku.constraint_name\n AND tc.table_schema = ku.table_schema\n WHERE tc.constraint_type = 'PRIMARY KEY'\n AND tc.table_schema = 'public'\n AND tc.table_name = $1\n ) pk ON c.column_name = pk.column_name\n LEFT JOIN (\n SELECT \n kcu.column_name,\n ccu.table_name AS referenced_table,\n ccu.column_name AS referenced_column\n FROM information_schema.table_constraints tc\n JOIN information_schema.key_column_usage kcu\n ON tc.constraint_name = kcu.constraint_name\n AND tc.table_schema = kcu.table_schema\n JOIN information_schema.constraint_column_usage ccu\n ON tc.constraint_name = ccu.constraint_name\n AND tc.table_schema = ccu.table_schema\n WHERE tc.constraint_type = 'FOREIGN KEY'\n AND tc.table_schema = 'public'\n AND tc.table_name = $1\n ) fk ON c.column_name = fk.column_name\n WHERE c.table_schema = 'public'\n AND c.table_name = $1\n ORDER BY c.ordinal_position;\n `,\n\t\t\t[tableName],\n\t\t);\n\n\t\treturn res.rows.map((r: any) => {\n\t\t\t// Parse enumValues to always return string[] | null\n\t\t\tlet parsedEnumValues: string[] | null = null;\n\t\t\tif (r.enumValues) {\n\t\t\t\tif (Array.isArray(r.enumValues)) {\n\t\t\t\t\t// Already an array, use as-is\n\t\t\t\t\tparsedEnumValues = r.enumValues;\n\t\t\t\t} else if (typeof r.enumValues === \"string\") {\n\t\t\t\t\t// Parse PostgreSQL array format: \"{VALUE1,VALUE2,VALUE3}\"\n\t\t\t\t\tparsedEnumValues = r.enumValues.replace(/[{}]/g, \"\").split(\",\").filter(Boolean);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tcolumnName: r.columnName,\n\t\t\t\tdataType: mapPostgresToDataType(r.dataType),\n\t\t\t\tdataTypeLabel: standardizeDataTypeLabel(r.dataType),\n\t\t\t\tisNullable: r.isNullable,\n\t\t\t\tcolumnDefault: r.columnDefault,\n\t\t\t\tisPrimaryKey: r.isPrimaryKey,\n\t\t\t\tisForeignKey: r.isForeignKey,\n\t\t\t\treferencedTable: r.referencedTable,\n\t\t\t\treferencedColumn: r.referencedColumn,\n\t\t\t\tenumValues: parsedEnumValues,\n\t\t\t};\n\t\t});\n\t} finally {\n\t\tclient.release();\n\t}\n};\n","import { db } from \"@/db.js\";\nimport { type ColumnInfo, getTableColumns } from \"./table-columns.dao.js\";\n\nexport interface DatabaseSchema {\n\tdbType: string;\n\ttables: Table[];\n\trelationships: Relationship[];\n}\n\ninterface Table {\n\tname: string;\n\tdescription?: string;\n\tcolumns: Column[];\n\tsampleData?: Record<string, string>[];\n}\n\ninterface Column {\n\tname: string;\n\ttype: string;\n\tnullable: boolean;\n\tisPrimaryKey?: boolean;\n\tforeignKey?: string;\n\tdescription?: string;\n\tenumValues?: string[];\n}\n\ninterface Relationship {\n\tfromTable: string;\n\tfromColumn: string;\n\ttoTable: string;\n\ttoColumn: string;\n}\n\n/**\n * Get all table names from the database\n */\nasync function getTableNames(): Promise<string[]> {\n\tconst client = await db.connect();\n\ttry {\n\t\tconst res = await client.query(\n\t\t\t`\n SELECT table_name\n FROM information_schema.tables\n WHERE table_schema = 'public'\n AND table_type = 'BASE TABLE'\n ORDER BY table_name;\n `,\n\t\t);\n\t\treturn res.rows.map((r) => r.table_name);\n\t} finally {\n\t\tclient.release();\n\t}\n}\n\n/**\n * Get table comment/description if available\n */\nasync function getTableDescription(tableName: string): Promise<string | undefined> {\n\tconst client = await db.connect();\n\ttry {\n\t\tconst res = await client.query(\n\t\t\t`\n SELECT obj_description(oid) as description\n FROM pg_class\n WHERE relname = $1\n AND relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'public');\n `,\n\t\t\t[tableName],\n\t\t);\n\t\treturn res.rows[0]?.description || undefined;\n\t} finally {\n\t\tclient.release();\n\t}\n}\n\n/**\n * Get sample data from a table (first 3 rows)\n */\nasync function getSampleData(tableName: string): Promise<Record<string, any>[]> {\n\tconst client = await db.connect();\n\ttry {\n\t\t// Sanitize table name to prevent SQL injection\n\t\t// In production, validate tableName against known tables list\n\t\tconst res = await client.query(`SELECT * FROM \"${tableName}\" LIMIT 3`);\n\t\treturn res.rows;\n\t} catch (error) {\n\t\tconsole.warn(`Could not fetch sample data for table ${tableName}:`, error);\n\t\treturn [];\n\t} finally {\n\t\tclient.release();\n\t}\n}\n\n/**\n * Convert ColumnInfo to the schema Column format\n */\nfunction convertColumnInfo(col: ColumnInfo): Column {\n\tconst column: Column = {\n\t\tname: col.columnName,\n\t\ttype: col.dataTypeLabel,\n\t\tnullable: col.isNullable,\n\t};\n\n\tif (col.isPrimaryKey) {\n\t\tcolumn.isPrimaryKey = true;\n\t}\n\n\tif (col.isForeignKey && col.referencedTable && col.referencedColumn) {\n\t\tcolumn.foreignKey = `${col.referencedTable}.${col.referencedColumn}`;\n\t}\n\n\tif (col.enumValues && col.enumValues.length > 0) {\n\t\tcolumn.enumValues = col.enumValues;\n\t\tcolumn.description = `Enum values: ${col.enumValues.join(\", \")}`;\n\t}\n\n\treturn column;\n}\n\n/**\n * Extract all relationships from table columns\n */\nfunction extractRelationships(tables: Table[]): Relationship[] {\n\tconst relationships: Relationship[] = [];\n\n\tfor (const table of tables) {\n\t\tfor (const column of table.columns) {\n\t\t\tif (column.foreignKey) {\n\t\t\t\tconst [toTable, toColumn] = column.foreignKey.split(\".\");\n\t\t\t\trelationships.push({\n\t\t\t\t\tfromTable: table.name,\n\t\t\t\t\tfromColumn: column.name,\n\t\t\t\t\ttoTable,\n\t\t\t\t\ttoColumn,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\treturn relationships;\n}\n\n/**\n * Get complete database schema with all tables, columns, and relationships\n */\nexport async function getDatabaseSchema(\n\t// connectionId: string,\n\toptions: {\n\t\tincludeSampleData?: boolean;\n\t\tincludeDescriptions?: boolean;\n\t\tmaxTables?: number;\n\t} = {},\n): Promise<DatabaseSchema> {\n\tconst {\n\t\tincludeSampleData = false,\n\t\tincludeDescriptions = true,\n\t\t// maxTables = 50, // Prevent overwhelming the context\n\t} = options;\n\n\ttry {\n\t\t// Get all table names\n\t\tconst tableNames = await getTableNames();\n\n\t\t// Limit tables if needed to prevent token overflow\n\t\t// const limitedTableNames = tableNames.slice(0, maxTables);\n\n\t\t// if (tableNames.length > maxTables) {\n\t\t// console.warn(\n\t\t// `Database has ${tableNames.length} tables, only including first ${maxTables} in schema context`\n\t\t// );\n\t\t// }\n\n\t\t// Fetch schema info for each table in parallel\n\t\t// const tablePromises = limitedTableNames.map(async (tableName) => {\n\t\tconst tablePromises = tableNames.map(async (tableName) => {\n\t\t\tconst [columns, description, sampleData] = await Promise.all([\n\t\t\t\tgetTableColumns(tableName),\n\t\t\t\tincludeDescriptions ? getTableDescription(tableName) : Promise.resolve(undefined),\n\t\t\t\tincludeSampleData ? getSampleData(tableName) : Promise.resolve([]),\n\t\t\t]);\n\n\t\t\tconst table: Table = {\n\t\t\t\tname: tableName,\n\t\t\t\tcolumns: columns.map(convertColumnInfo),\n\t\t\t};\n\n\t\t\tif (description) {\n\t\t\t\ttable.description = description;\n\t\t\t}\n\n\t\t\tif (sampleData.length > 0) {\n\t\t\t\ttable.sampleData = sampleData;\n\t\t\t}\n\n\t\t\treturn table;\n\t\t});\n\n\t\tconst tables = await Promise.all(tablePromises);\n\n\t\t// Extract relationships from foreign keys\n\t\tconst relationships = extractRelationships(tables);\n\n\t\treturn {\n\t\t\tdbType: \"PostgreSQL\",\n\t\t\ttables,\n\t\t\trelationships,\n\t\t};\n\t} catch (error) {\n\t\tconsole.error(\"Error fetching database schema:\", error);\n\t\tthrow new Error(\n\t\t\t`Failed to fetch database schema: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n\t\t);\n\t}\n}\n\n/**\n * Get lightweight schema (no sample data, useful for token efficiency)\n */\nexport async function getLightweightSchema(): Promise<DatabaseSchema> {\n\treturn getDatabaseSchema({\n\t\tincludeSampleData: false,\n\t\tincludeDescriptions: false,\n\t});\n}\n\n/**\n * Get detailed schema with sample data (for initial conversation context)\n */\nexport async function getDetailedSchema(): Promise<DatabaseSchema> {\n\treturn getDatabaseSchema({\n\t\tincludeSampleData: true,\n\t\tincludeDescriptions: true,\n\t\t// maxTables: 30, // todo: DELETE THIS AFTER TESTING\n\t});\n}\n","import type { DatabaseSchema } from \"@/dao/table-details-schema.js\";\n\n/**\n * Generate system prompt with database context\n */\nexport function generateSystemPrompt(schema: DatabaseSchema): string {\n\treturn `You are a database assistant for db-studio. Your responses must be CONCISE and FOCUSED.\n\n**Your Role:**\n1. Keep responses SHORT - 2-3 sentences maximum unless generating SQL\n2. When generating SQL:\n - Provide 1 sentence explanation\n - The SQL query in a code block\n - 1 sentence about expected results\n - NO verbose explanations\n3. Use exact table/column names from the schema\n4. Generate valid ${schema.dbType} syntax\n5. If query is unclear, ask ONE specific clarifying question\n6. No preamble, no apologies, get straight to the answer\n\n**Database Context:**\n${formatSchemaForPrompt(schema)}\n\n**Guidelines:**\n1. Always generate syntactically correct SQL for the database type (${schema.dbType})\n2. Use proper table/column names exactly as defined in the schema\n3. When generating queries, wrap them in \\`\\`\\`sql code blocks\n4. Explain what the query does in plain language\n5. Suggest relevant follow-up questions or analyses\n6. If a request is ambiguous, ask clarifying questions\n7. For complex queries, break down the logic step-by-step\n8. Warn about potentially expensive operations (full table scans, etc.)\n9. Consider data privacy - remind users not to share sensitive data externally\n\n**Response Format:**\nWhen generating queries, use this structure:\n- Brief explanation of what you'll do\n- The SQL query in a code block\n- Expected results description\n- Optional: suggestions for related queries\n\n**Example:**\nUser: \"Show me the top 5 customers by revenue\"\n\nResponse: \"I'll query the orders and customers tables to find your highest-value customers.\n\n\\`\\`\\`sql\nSELECT \n c.customer_name,\n SUM(o.total_amount) as total_revenue\nFROM customers c\nJOIN orders o ON c.id = o.customer_id\nGROUP BY c.id, c.customer_name\nORDER BY total_revenue DESC\nLIMIT 5;\n\\`\\`\\`\n\nThis will return the 5 customers with the highest total order value. You might also want to see:\n- Revenue trends over time for these customers\n- Their most frequently ordered products\"`;\n}\n\n/**\n * Format schema information for the prompt\n */\nexport function formatSchemaForPrompt(schema: DatabaseSchema): string {\n\tlet output = `Database Type: ${schema.dbType}\\n\\n`;\n\n\toutput += \"**Tables and Columns:**\\n\";\n\tfor (const table of schema.tables) {\n\t\toutput += `\\n### ${table.name}\\n`;\n\t\tif (table.description) {\n\t\t\toutput += `Description: ${table.description}\\n`;\n\t\t}\n\t\toutput += \"Columns:\\n\";\n\n\t\tfor (const col of table.columns) {\n\t\t\tconst pkIndicator = col.isPrimaryKey ? \" [PRIMARY KEY]\" : \"\";\n\t\t\tconst fkIndicator = col.foreignKey ? ` [FK -> ${col.foreignKey}]` : \"\";\n\t\t\tconst nullable = col.nullable ? \"NULL\" : \"NOT NULL\";\n\n\t\t\toutput += ` - ${col.name}: ${col.type} ${nullable}${pkIndicator}${fkIndicator}\\n`;\n\t\t\tif (col.description) {\n\t\t\t\toutput += ` ${col.description}\\n`;\n\t\t\t}\n\t\t}\n\n\t\t// Add sample data if available\n\t\tif (table.sampleData && table.sampleData.length > 0) {\n\t\t\toutput += `Sample data (${table.sampleData.length} rows):\\n`;\n\t\t\toutput += `${JSON.stringify(table.sampleData.slice(0, 3), null, 2)}\\n`;\n\t\t}\n\t}\n\n\t// Add relationships\n\tif (schema.relationships && schema.relationships.length > 0) {\n\t\toutput += \"\\n**Relationships:**\\n\";\n\t\tfor (const rel of schema.relationships) {\n\t\t\toutput += ` - ${rel.fromTable}.${rel.fromColumn} -> ${rel.toTable}.${rel.toColumn}\\n`;\n\t\t}\n\t}\n\n\treturn output;\n}\n","import { Hono } from \"hono\";\nimport { getDetailedSchema } from \"@/dao/table-details-schema.js\";\nimport { DEFAULTS } from \"@/utils/defaults.js\";\nimport { generateSystemPrompt } from \"@/utils/system-prompt-generator.js\";\n\nexport const chatRoutes = new Hono();\n\n/**\n * POST /chat - Handle AI chat requests with streaming\n * Proxies to the Cloudflare Worker which has the Gemini API key\n */\nchatRoutes.post(\"/\", async (c) => {\n\ttry {\n\t\tconst { messages, conversationId } = await c.req.json();\n\t\tconsole.log(\"POST /chat messages\", messages);\n\n\t\t// Get the database schema and generate system prompt\n\t\tconst schema = await getDetailedSchema();\n\t\tconst systemPrompt = generateSystemPrompt(schema);\n\n\t\tconst payload = {\n\t\t\tmessages,\n\t\t\tconversationId,\n\t\t\tsystemPrompt,\n\t\t};\n\n\t\t// Forward request to the proxy with the system prompt\n\t\tconst proxyResponse = await fetch(`${DEFAULTS.PROXY_URL}/chat`, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t},\n\t\t\tbody: JSON.stringify(payload),\n\t\t});\n\n\t\tif (!proxyResponse.ok) {\n\t\t\tconst errorData = await proxyResponse.json();\n\t\t\treturn c.json(\n\t\t\t\t{ error: errorData.error || \"Proxy request failed\" },\n\t\t\t\tproxyResponse.status as 400 | 500,\n\t\t\t);\n\t\t}\n\n\t\t// Stream the SSE response back to the client\n\t\tconst { readable, writable } = new TransformStream();\n\t\tproxyResponse.body?.pipeTo(writable);\n\n\t\treturn new Response(readable, {\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"text/event-stream\",\n\t\t\t\t\"Cache-Control\": \"no-cache\",\n\t\t\t\tConnection: \"keep-alive\",\n\t\t\t},\n\t\t});\n\t} catch (error) {\n\t\tconsole.error(\"POST /chat error:\", error);\n\t\tconst errorMessage = error instanceof Error ? error.message : \"An error occurred\";\n\t\treturn c.json(\n\t\t\t{\n\t\t\t\terror: errorMessage,\n\t\t\t},\n\t\t\t500,\n\t\t);\n\t}\n});\n","import { z } from \"zod\";\n\nexport const FOREIGN_KEY_ACTIONS = [\n\t\"CASCADE\",\n\t\"SET NULL\",\n\t\"SET DEFAULT\",\n\t\"RESTRICT\",\n\t\"NO ACTION\",\n] as const;\nexport const foreignKeyActionSchema = z.enum(FOREIGN_KEY_ACTIONS);\nexport type ForeignKeyAction = z.infer<typeof foreignKeyActionSchema>;\n\nexport const fieldDataSchema = z.object({\n\tcolumnName: z.string().min(1),\n\tcolumnType: z.string().min(1),\n\tdefaultValue: z.string(),\n\tisPrimaryKey: z.boolean(),\n\tisNullable: z.boolean(),\n\tisUnique: z.boolean(),\n\tisIdentity: z.boolean(),\n\tisArray: z.boolean(),\n});\nexport type FieldDataType = z.infer<typeof fieldDataSchema>;\n\nexport const foreignKeyDataSchema = z.object({\n\tcolumnName: z.string().min(1),\n\treferencedTable: z.string().min(1),\n\treferencedColumn: z.string().min(1),\n\tonUpdate: foreignKeyActionSchema,\n\tonDelete: foreignKeyActionSchema,\n});\nexport type ForeignKeyDataType = z.infer<typeof foreignKeyDataSchema>;\n\nexport const createTableSchema = z.object({\n\ttableName: z.string().min(1, \"Table name is required\"),\n\tfields: z.array(fieldDataSchema).min(1, \"At least one field is required\"),\n\tforeignKeys: z.array(foreignKeyDataSchema).optional(),\n});\nexport type CreateTableFormData = z.infer<typeof createTableSchema>;\n\nexport const tableNameParamSchema = z.object({\n\ttableName: z.string().min(1, \"Table name is required\"),\n});\n\nexport const tableDataQuerySchema = z.object({\n\tpage: z.string().optional().default(\"1\").transform(Number),\n\tpageSize: z.string().optional().default(\"50\").transform(Number),\n\tsort: z.string().optional().default(\"\"),\n\torder: z.enum([\"asc\", \"desc\"]).optional(),\n\tfilters: z\n\t\t.string()\n\t\t.optional()\n\t\t.transform((val) => {\n\t\t\tif (!val) return [];\n\t\t\ttry {\n\t\t\t\treturn JSON.parse(val);\n\t\t\t} catch {\n\t\t\t\treturn [];\n\t\t\t}\n\t\t}),\n});\n\nexport const insertRecordSchema = z.object({\n\ttableName: z.string().min(1, \"Table name is required\"),\n\tdata: z.record(z.string(), z.any()),\n});\n\nexport const updateRecordsSchema = z.object({\n\ttableName: z.string().min(1, \"Table name is required\"),\n\tupdates: z\n\t\t.array(\n\t\t\tz.object({\n\t\t\t\trowData: z.any(),\n\t\t\t\tcolumnName: z.string().min(1),\n\t\t\t\tvalue: z.any(),\n\t\t\t}),\n\t\t)\n\t\t.min(1, \"At least one update is required\"),\n\tprimaryKey: z.string().optional(),\n});\n\nexport const deleteRecordsSchema = z.object({\n\ttableName: z.string().min(1, \"Table name is required\"),\n\tprimaryKeys: z\n\t\t.array(\n\t\t\tz.object({\n\t\t\t\tcolumnName: z.string().min(1),\n\t\t\t\tvalue: z.any(),\n\t\t\t}),\n\t\t)\n\t\t.min(1, \"At least one primary key is required\"),\n});\n\nexport const executeQuerySchema = z.object({\n\tquery: z.string().min(1, \"Query is required\"),\n});\n\nexport const databaseQuerySchema = z.object({\n\tdatabase: z.string().optional(),\n});\n","import type { Context } from \"hono\";\n\nexport const handleConnectionError = (\n\tc: Context,\n\terror: unknown,\n\tfallbackMessage: string,\n) => {\n\tconst errorMessage = error instanceof Error ? error.message : fallbackMessage;\n\n\tlet isConnectionError = false;\n\tif (error && typeof error === \"object\" && \"code\" in error) {\n\t\tisConnectionError = (error as { code?: string }).code === \"ECONNREFUSED\";\n\t} else if (\n\t\terror &&\n\t\ttypeof error === \"object\" &&\n\t\t\"errors\" in error &&\n\t\tArray.isArray((error as { errors?: unknown[] }).errors)\n\t) {\n\t\tconst aggregateError = error as { errors?: Array<{ code?: string }> };\n\t\tisConnectionError =\n\t\t\taggregateError.errors?.some((err) => err.code === \"ECONNREFUSED\") ?? false;\n\t}\n\n\tif (isConnectionError) {\n\t\treturn c.json(\n\t\t\t{\n\t\t\t\tsuccess: false,\n\t\t\t\tmessage:\n\t\t\t\t\t\"Cannot connect to database. Please check your DATABASE_URL and ensure the database server is running.\",\n\t\t\t\terror: errorMessage,\n\t\t\t},\n\t\t\t503,\n\t\t);\n\t}\n\n\treturn c.json(\n\t\t{\n\t\t\tsuccess: false,\n\t\t\tmessage: errorMessage,\n\t\t},\n\t\t500,\n\t);\n};\n","import { zValidator } from \"@hono/zod-validator\";\nimport { Hono } from \"hono\";\nimport { getTableColumns } from \"@/dao/table-columns.dao.js\";\nimport { databaseQuerySchema, tableNameParamSchema } from \"@/types/create-table.type.js\";\nimport { handleConnectionError } from \"@/utils/error-handler.js\";\n\nexport const columnsRoutes = new Hono();\n\n/**\n * GET /tables/:tableName/columns - Get all columns for a table\n */\ncolumnsRoutes.get(\n\t\"/\",\n\tzValidator(\"param\", tableNameParamSchema),\n\tzValidator(\"query\", databaseQuerySchema),\n\tasync (c) => {\n\t\ttry {\n\t\t\tconst { tableName } = c.req.valid(\"param\");\n\t\t\tconst { database } = c.req.valid(\"query\");\n\n\t\t\tconst columns = await getTableColumns(tableName, database);\n\t\t\tconsole.log(\"GET /tables/:tableName/columns\", columns);\n\t\t\treturn c.json(columns);\n\t\t} catch (error) {\n\t\t\tconsole.error(\"GET /tables/:tableName/columns error:\", error);\n\t\t\treturn handleConnectionError(c, error, \"Failed to fetch columns\");\n\t\t}\n\t},\n);\n","import { getDbPool } from \"@/db-manager.js\";\n\nexport interface Filter {\n\tcolumnName: string;\n\toperator: string;\n\tvalue: string;\n}\n\nexport type SortDirection = \"asc\" | \"desc\";\n\nexport type Sort = {\n\tcolumnName: string;\n\tdirection: SortDirection;\n};\n\nexport interface TableDataResult {\n\tdata: Record<string, unknown>[];\n\tmeta: {\n\t\tpage: number;\n\t\tlimit: number;\n\t\ttotal: number;\n\t\ttotalPages: number;\n\t\thasNextPage: boolean;\n\t\thasPreviousPage: boolean;\n\t};\n}\n\nconst buildWhereClause = (filters: Filter[]): { clause: string; values: unknown[] } => {\n\tif (filters.length === 0) {\n\t\treturn { clause: \"\", values: [] };\n\t}\n\n\tconst conditions: string[] = [];\n\tconst values: unknown[] = [];\n\n\tfor (const filter of filters) {\n\t\tconst paramIndex = values.length + 1;\n\t\tconst columnName = `\"${filter.columnName}\"`;\n\n\t\tswitch (filter.operator) {\n\t\t\tcase \"=\":\n\t\t\tcase \"!=\":\n\t\t\tcase \">\":\n\t\t\tcase \">=\":\n\t\t\tcase \"<\":\n\t\t\tcase \"<=\":\n\t\t\t\tconditions.push(`${columnName} ${filter.operator} $${paramIndex}`);\n\t\t\t\tvalues.push(filter.value);\n\t\t\t\tbreak;\n\t\t\tcase \"is\":\n\t\t\t\t// Handle NULL values\n\t\t\t\tif (filter.value.toLowerCase() === \"null\") {\n\t\t\t\t\tconditions.push(`${columnName} IS NULL`);\n\t\t\t\t} else {\n\t\t\t\t\tconditions.push(`${columnName} = $${paramIndex}`);\n\t\t\t\t\tvalues.push(filter.value);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase \"is not\":\n\t\t\t\tif (filter.value.toLowerCase() === \"null\") {\n\t\t\t\t\tconditions.push(`${columnName} IS NOT NULL`);\n\t\t\t\t} else {\n\t\t\t\t\tconditions.push(`${columnName} != $${paramIndex}`);\n\t\t\t\t\tvalues.push(filter.value);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase \"like\":\n\t\t\t\tconditions.push(`${columnName}::text LIKE $${paramIndex}`);\n\t\t\t\tvalues.push(filter.value);\n\t\t\t\tbreak;\n\t\t\tcase \"not like\":\n\t\t\t\tconditions.push(`${columnName}::text NOT LIKE $${paramIndex}`);\n\t\t\t\tvalues.push(filter.value);\n\t\t\t\tbreak;\n\t\t\tcase \"ilike\":\n\t\t\t\tconditions.push(`${columnName}::text ILIKE $${paramIndex}`);\n\t\t\t\tvalues.push(filter.value);\n\t\t\t\tbreak;\n\t\t\tcase \"not ilike\":\n\t\t\t\tconditions.push(`${columnName}::text NOT ILIKE $${paramIndex}`);\n\t\t\t\tvalues.push(filter.value);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\t// Unknown operator, skip\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (conditions.length === 0) {\n\t\treturn { clause: \"\", values: [] };\n\t}\n\n\treturn { clause: `WHERE ${conditions.join(\" AND \")}`, values };\n};\n\nconst buildSortClause = (sorts: Sort[] | string, order: SortDirection): string => {\n\t// Handle array of Sort objects (new format for referenced tables)\n\tif (Array.isArray(sorts)) {\n\t\tif (sorts.length === 0) {\n\t\t\treturn \"\";\n\t\t}\n\t\tconst sortParts = sorts.map(\n\t\t\t(sort) => `\"${sort.columnName}\" ${sort.direction.toUpperCase()}`,\n\t\t);\n\t\treturn `ORDER BY ${sortParts.join(\", \")}`;\n\t}\n\n\t// Handle legacy format (string column name + order)\n\tif (sorts && typeof sorts === \"string\") {\n\t\treturn `ORDER BY \"${sorts}\" ${order?.toUpperCase() || \"ASC\"}`;\n\t}\n\n\treturn \"\";\n};\n\nexport const getTableData = async (\n\ttableName: string,\n\tpage: number = 1,\n\tpageSize: number = 50,\n\tsort: string | Sort[] = \"\",\n\torder: SortDirection = \"asc\",\n\tfilters: Filter[] = [],\n\tdatabase?: string,\n): Promise<TableDataResult> => {\n\tconst sortClause = buildSortClause(\n\t\tArray.isArray(sort) ? sort : sort,\n\t\torder as SortDirection,\n\t);\n\tconst { clause: whereClause, values: filterValues } = buildWhereClause(filters);\n\n\tconst pool = getDbPool(database);\n\tconst client = await pool.connect();\n\ttry {\n\t\t// Calculate offset\n\t\tconst offset = (page - 1) * pageSize;\n\n\t\t// Get total count (with filters)\n\t\tconst countRes = await client.query(\n\t\t\t`SELECT COUNT(*) as total FROM \"${tableName}\" ${whereClause}`,\n\t\t\tfilterValues,\n\t\t);\n\t\tconst totalRows = Number(countRes.rows[0].total);\n\t\tconst totalPages = Math.ceil(totalRows / pageSize);\n\n\t\t// Get paginated data (with filters)\n\t\t// Parameter indices continue after filter values\n\t\tconst limitParamIndex = filterValues.length + 1;\n\t\tconst offsetParamIndex = filterValues.length + 2;\n\n\t\tconst dataRes = await client.query(\n\t\t\t`SELECT * FROM \"${tableName}\" ${whereClause} ${sortClause} LIMIT $${limitParamIndex} OFFSET $${offsetParamIndex}`,\n\t\t\t[...filterValues, pageSize, offset],\n\t\t);\n\n\t\treturn {\n\t\t\tdata: dataRes.rows,\n\t\t\tmeta: {\n\t\t\t\tpage,\n\t\t\t\tlimit: pageSize,\n\t\t\t\ttotal: totalRows,\n\t\t\t\ttotalPages,\n\t\t\t\thasNextPage: page < totalPages,\n\t\t\t\thasPreviousPage: page > 1,\n\t\t\t},\n\t\t};\n\t} finally {\n\t\tclient.release();\n\t}\n};\n","import { zValidator } from \"@hono/zod-validator\";\nimport { Hono } from \"hono\";\nimport { getTableData, type Sort } from \"@/dao/tables-data.dao.js\";\nimport { tableDataQuerySchema, tableNameParamSchema } from \"@/types/create-table.type.js\";\nimport { handleConnectionError } from \"@/utils/error-handler.js\";\n\nexport const dataRoutes = new Hono();\n\n/**\n * GET /data - Get paginated data for a table\n */\ndataRoutes.get(\n\t\"/\",\n\tzValidator(\"param\", tableNameParamSchema),\n\tzValidator(\"query\", tableDataQuerySchema),\n\tasync (c) => {\n\t\ttry {\n\t\t\tconst { tableName } = c.req.valid(\"param\");\n\t\t\tconst { page, pageSize, sort: sortParam, order, filters } = c.req.valid(\"query\");\n\n\t\t\t// Parse sort - can be either a string (legacy) or JSON array (new format)\n\t\t\tlet sort: Sort[] | string = \"\";\n\t\t\tif (sortParam) {\n\t\t\t\ttry {\n\t\t\t\t\t// Try to parse as JSON first (new format)\n\t\t\t\t\tconst parsed = JSON.parse(sortParam);\n\t\t\t\t\tif (Array.isArray(parsed)) {\n\t\t\t\t\t\tsort = parsed;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tsort = sortParam;\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// If JSON parse fails, use as string (legacy format)\n\t\t\t\t\tsort = sortParam;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst database = c.req.query(\"database\");\n\t\t\tconst data = await getTableData(\n\t\t\t\ttableName,\n\t\t\t\tpage,\n\t\t\t\tpageSize,\n\t\t\t\tsort,\n\t\t\t\torder,\n\t\t\t\tfilters,\n\t\t\t\tdatabase,\n\t\t\t);\n\t\t\treturn c.json(data);\n\t\t} catch (error) {\n\t\t\tconsole.error(\"GET /data error:\", error);\n\t\t\treturn handleConnectionError(c, error, \"Failed to fetch table data\");\n\t\t}\n\t},\n);\n","import { getDbPool } from \"@/db-manager.js\";\n\nexport interface DatabaseInfo {\n\tname: string;\n\tsize: string;\n\towner: string;\n\tencoding: string;\n}\n\nexport interface DatabaseConnectionInfo {\n\thost: string;\n\tport: number;\n\tuser: string;\n\tdatabase: string;\n\tversion: string;\n\tactiveConnections: number;\n\tmaxConnections: number;\n}\n\nexport interface CurrentDatabase {\n\tdatabase: string;\n}\n\n/**\n * Get list of all databases on the server\n */\nexport async function getDatabasesList(): Promise<DatabaseInfo[]> {\n\tconst pool = getDbPool();\n\tconst query = `\n\t\tSELECT \n\t\t\td.datname as name,\n\t\t\tpg_size_pretty(pg_database_size(d.datname)) as size,\n\t\t\tpg_catalog.pg_get_userbyid(d.datdba) as owner,\n\t\t\tpg_encoding_to_char(d.encoding) as encoding\n\t\tFROM pg_catalog.pg_database d\n\t\tWHERE d.datistemplate = false\n\t\tORDER BY d.datname;\n\t`;\n\n\tconst result = await pool.query(query);\n\treturn result.rows;\n}\n\n/**\n * Get current database name\n */\nexport async function getCurrentDatabase(): Promise<CurrentDatabase> {\n\tconst pool = getDbPool();\n\tconst query = \"SELECT current_database() as database;\";\n\tconst result = await pool.query(query);\n\treturn result.rows[0];\n}\n\n/**\n * Get detailed connection information for current database\n */\nexport async function getDatabaseConnectionInfo(): Promise<DatabaseConnectionInfo> {\n\tconst pool = getDbPool();\n\n\t// Get version and connection stats\n\tconst infoQuery = `\n\t\tSELECT \n\t\t\tversion() as version,\n\t\t\tcurrent_database() as database,\n\t\t\tcurrent_user as user,\n\t\t\tinet_server_addr() as host,\n\t\t\tinet_server_port() as port,\n\t\t\t(SELECT count(*) FROM pg_stat_activity WHERE datname = current_database()) as active_connections,\n\t\t\t(SELECT setting::int FROM pg_settings WHERE name = 'max_connections') as max_connections;\n\t`;\n\n\tconst result = await pool.query(infoQuery);\n\tconst row = result.rows[0];\n\n\t// Parse DATABASE_URL for host and port since inet_server_addr() might return null for local connections\n\tconst databaseUrl = process.env.DATABASE_URL;\n\tlet host = \"localhost\";\n\tlet port = 5432;\n\n\tif (databaseUrl) {\n\t\ttry {\n\t\t\tconst url = new URL(databaseUrl);\n\t\t\thost = url.hostname;\n\t\t\tport = Number.parseInt(url.port, 10) || 5432;\n\t\t} catch (error) {\n\t\t\tconsole.error(\"Failed to parse DATABASE_URL:\", error);\n\t\t}\n\t}\n\n\treturn {\n\t\thost: row.host || host,\n\t\tport: row.port || port,\n\t\tuser: row.user,\n\t\tdatabase: row.database,\n\t\tversion: row.version,\n\t\tactiveConnections: Number.parseInt(row.active_connections, 10),\n\t\tmaxConnections: Number.parseInt(row.max_connections, 10),\n\t};\n}\n","import { Hono } from \"hono\";\nimport {\n\tgetCurrentDatabase,\n\tgetDatabaseConnectionInfo,\n\tgetDatabasesList,\n} from \"@/dao/database-list.dao.js\";\n\nexport const databasesRoutes = new Hono();\n\n/**\n * GET /databases - Get list of all databases\n */\ndatabasesRoutes.get(\"/\", async (c) => {\n\ttry {\n\t\tconst databases = await getDatabasesList();\n\t\treturn c.json(databases);\n\t} catch (error) {\n\t\tconsole.error(\"Error fetching databases list:\", error);\n\t\treturn c.json({ error: \"Failed to fetch databases list\" }, 500);\n\t}\n});\n\n/**\n * GET /databases/current - Get current database name\n */\ndatabasesRoutes.get(\"/current\", async (c) => {\n\ttry {\n\t\tconst current = await getCurrentDatabase();\n\t\treturn c.json(current);\n\t} catch (error) {\n\t\tconsole.error(\"Error fetching current database:\", error);\n\t\treturn c.json({ error: \"Failed to fetch current database\" }, 500);\n\t}\n});\n\n/**\n * GET /databases/connection - Get database connection information\n */\ndatabasesRoutes.get(\"/connection\", async (c) => {\n\ttry {\n\t\tconst info = await getDatabaseConnectionInfo();\n\t\treturn c.json(info);\n\t} catch (error) {\n\t\tconsole.error(\"Error fetching database connection info:\", error);\n\t\treturn c.json({ error: \"Failed to fetch database connection info\" }, 500);\n\t}\n});\n","import { getDbPool } from \"@/db-manager.js\";\n\nexport type ExecuteQueryResponse = {\n\tcolumns: string[];\n\trows: Record<string, unknown>[];\n\trowCount: number;\n\tduration: number;\n\tmessage?: string;\n\terror?: string;\n};\n\nexport const executeQuery = async (params: {\n\tquery: string;\n\tdatabase?: string;\n}): Promise<ExecuteQueryResponse> => {\n\tconst { query, database } = params;\n\tconst pool = getDbPool(database);\n\tconst client = await pool.connect();\n\n\ttry {\n\t\tif (!query || !query.trim()) {\n\t\t\tthrow new Error(\"Query cannot be empty\");\n\t\t}\n\n\t\t// Clean the query - remove trailing semicolons and whitespace\n\t\tconst cleanedQuery = query.trim().replace(/;+$/, \"\");\n\n\t\tconsole.log(\"executeQuery query:\", cleanedQuery);\n\t\tconst startTime = performance.now();\n\t\tconst result = await client.query(cleanedQuery);\n\t\tconst duration = performance.now() - startTime;\n\n\t\tconst columns = result.fields.map((field) => field.name);\n\n\t\treturn {\n\t\t\tcolumns,\n\t\t\trows: result.rows,\n\t\t\trowCount: result.rows.length,\n\t\t\tduration,\n\t\t\tmessage: result.rows.length === 0 ? \"OK\" : undefined,\n\t\t};\n\t} catch (error) {\n\t\tconsole.error(\"Error executing query:\", error);\n\t\tconst errorMessage =\n\t\t\terror instanceof Error ? error.message : \"Unknown error occurred\";\n\t\tthrow new Error(errorMessage);\n\t} finally {\n\t\tclient.release();\n\t}\n};\n","import { zValidator } from \"@hono/zod-validator\";\nimport { Hono } from \"hono\";\nimport { executeQuery } from \"@/dao/query.dao.js\";\nimport { executeQuerySchema } from \"@/types/create-table.type.js\";\n\nexport const queryRoutes = new Hono();\n\n/**\n * POST /query - Execute a SQL query\n */\nqueryRoutes.post(\"/\", zValidator(\"json\", executeQuerySchema), async (c) => {\n\ttry {\n\t\tconst { query } = c.req.valid(\"json\");\n\t\tconst database = c.req.query(\"database\");\n\n\t\tconst data = await executeQuery({ query, database });\n\t\treturn c.json(data);\n\t} catch (error) {\n\t\tconsole.error(\"POST /query error:\", error);\n\t\tconst errorMessage = error instanceof Error ? error.message : \"Unknown error\";\n\t\treturn c.json(\n\t\t\t{\n\t\t\t\tstatus: \"error\",\n\t\t\t\terror: errorMessage,\n\t\t\t},\n\t\t\t500,\n\t\t);\n\t}\n});\n","import { getDbPool } from \"@/db-manager.js\";\n\nexport interface DeleteRecordParams {\n\ttableName: string;\n\tprimaryKeys: Array<{ columnName: string; value: unknown }>;\n\tdatabase?: string;\n}\n\nexport interface ForeignKeyConstraint {\n\tconstraintName: string;\n\treferencingTable: string;\n\treferencingColumn: string;\n\treferencedTable: string;\n\treferencedColumn: string;\n}\n\nexport interface ForeignKeyConstraintRow {\n\tconstraint_name: string;\n\treferencing_table: string;\n\treferencing_column: string;\n\treferenced_table: string;\n\treferenced_column: string;\n}\n\nexport interface RelatedRecord {\n\ttableName: string;\n\tcolumnName: string;\n\tconstraintName: string;\n\trecords: Array<Record<string, unknown>>;\n}\n\nexport interface DeleteResult {\n\tsuccess: boolean;\n\tmessage: string;\n\tdeletedCount?: number;\n\tfkViolation?: boolean;\n\trelatedRecords?: RelatedRecord[];\n}\n\n/**\n * Gets foreign key constraints that reference the given table\n */\nexport const getForeignKeyReferences = async (\n\ttableName: string,\n\tdatabase?: string,\n): Promise<ForeignKeyConstraint[]> => {\n\tconst query = `\n\t\tSELECT\n\t\t\ttc.constraint_name,\n\t\t\ttc.table_name as referencing_table,\n\t\t\tkcu.column_name as referencing_column,\n\t\t\tccu.table_name AS referenced_table,\n\t\t\tccu.column_name AS referenced_column\n\t\tFROM information_schema.table_constraints AS tc\n\t\tJOIN information_schema.key_column_usage AS kcu\n\t\t\tON tc.constraint_name = kcu.constraint_name\n\t\t\tAND tc.table_schema = kcu.table_schema\n\t\tJOIN information_schema.constraint_column_usage AS ccu\n\t\t\tON ccu.constraint_name = tc.constraint_name\n\t\t\tAND ccu.table_schema = tc.table_schema\n\t\tWHERE tc.constraint_type = 'FOREIGN KEY'\n\t\t\tAND ccu.table_name = $1\n\t`;\n\n\tconst pool = getDbPool(database);\n\tconst result = await pool.query(query, [tableName]);\n\n\treturn result.rows.map(({ row }: { row: ForeignKeyConstraintRow }) => ({\n\t\tconstraintName: row.constraint_name,\n\t\treferencingTable: row.referencing_table,\n\t\treferencingColumn: row.referencing_column,\n\t\treferencedTable: row.referenced_table,\n\t\treferencedColumn: row.referenced_column,\n\t}));\n};\n\n/**\n * Finds all records in other tables that reference the given primary key values\n */\nexport const getRelatedRecords = async (\n\ttableName: string,\n\tprimaryKeys: Array<{ columnName: string; value: unknown }>,\n\tdatabase?: string,\n): Promise<RelatedRecord[]> => {\n\tconst fkConstraints = await getForeignKeyReferences(tableName, database);\n\n\tif (fkConstraints.length === 0) {\n\t\treturn [];\n\t}\n\n\tconst relatedRecords: RelatedRecord[] = [];\n\tconst pool = getDbPool(database);\n\n\t// Group constraints by referencing table and column for efficiency\n\tconst constraintsByTable = new Map<string, ForeignKeyConstraint[]>();\n\tfor (const constraint of fkConstraints) {\n\t\tconst key = `${constraint.referencingTable}.${constraint.referencingColumn}`;\n\t\tif (!constraintsByTable.has(key)) {\n\t\t\tconstraintsByTable.set(key, []);\n\t\t}\n\t\tconstraintsByTable.get(key)?.push(constraint);\n\t}\n\n\t// Get the primary key values that we're looking for\n\tconst pkValues = primaryKeys.map((pk) => pk.value);\n\n\tfor (const [_tableColumn, constraints] of constraintsByTable) {\n\t\tconst constraint = constraints[0];\n\t\tif (!constraint) continue;\n\n\t\t// Find which primary key column matches this FK's referenced column\n\t\tconst matchingPk = primaryKeys.find(\n\t\t\t(pk) => pk.columnName === constraint.referencedColumn,\n\t\t);\n\t\tif (!matchingPk) continue;\n\n\t\t// Build query to find related records\n\t\tconst placeholders = pkValues.map((_, i) => `$${i + 1}`).join(\", \");\n\t\tconst query = `\n\t\t\tSELECT * FROM \"${constraint.referencingTable}\"\n\t\t\tWHERE \"${constraint.referencingColumn}\" IN (${placeholders})\n\t\t\tLIMIT 100\n\t\t`;\n\n\t\ttry {\n\t\t\tconst result = await pool.query(query, pkValues);\n\n\t\t\tif (result.rows.length > 0) {\n\t\t\t\trelatedRecords.push({\n\t\t\t\t\ttableName: constraint.referencingTable,\n\t\t\t\t\tcolumnName: constraint.referencingColumn,\n\t\t\t\t\tconstraintName: constraint.constraintName,\n\t\t\t\t\trecords: result.rows,\n\t\t\t\t});\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconsole.error(\n\t\t\t\t`Error fetching related records from ${constraint.referencingTable}:`,\n\t\t\t\terror,\n\t\t\t);\n\t\t}\n\t}\n\n\treturn relatedRecords;\n};\n\n/**\n * Attempts to delete records. If FK violation occurs, returns related records.\n */\nexport const deleteRecords = async (\n\tparams: DeleteRecordParams,\n): Promise<DeleteResult> => {\n\tconst { tableName, primaryKeys, database } = params;\n\tconst pool = getDbPool(database);\n\tconst client = await pool.connect();\n\n\ttry {\n\t\tawait client.query(\"BEGIN\");\n\n\t\t// Build the delete query\n\t\tconst pkColumn = primaryKeys[0]?.columnName;\n\t\tif (!pkColumn) {\n\t\t\tthrow new Error(\"Primary key column name is required\");\n\t\t}\n\n\t\tconst pkValues = primaryKeys.map((pk) => pk.value);\n\t\tconst placeholders = pkValues.map((_, i) => `$${i + 1}`).join(\", \");\n\n\t\tconst deleteSQL = `\n\t\t\tDELETE FROM \"${tableName}\"\n\t\t\tWHERE \"${pkColumn}\" IN (${placeholders})\n\t\t\tRETURNING *\n\t\t`;\n\n\t\tconsole.log(\"Deleting records with SQL:\", deleteSQL, \"Values:\", pkValues);\n\t\tconst result = await client.query(deleteSQL, pkValues);\n\n\t\tawait client.query(\"COMMIT\");\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tmessage: `Successfully deleted ${result.rowCount} ${result.rowCount === 1 ? \"record\" : \"records\"} from \"${tableName}\"`,\n\t\t\tdeletedCount: result.rowCount ?? 0,\n\t\t};\n\t} catch (error) {\n\t\tawait client.query(\"ROLLBACK\");\n\n\t\t// Check if this is a foreign key violation\n\t\tconst pgError = error as { code?: string; detail?: string; constraint?: string };\n\n\t\tif (pgError.code === \"23503\") {\n\t\t\t// Foreign key violation\n\t\t\tconsole.log(\"FK violation detected, fetching related records...\");\n\n\t\t\t// Fetch related records to show the user\n\t\t\tconst relatedRecords = await getRelatedRecords(tableName, primaryKeys);\n\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\tmessage: \"Cannot delete: Records are referenced by other tables\",\n\t\t\t\tfkViolation: true,\n\t\t\t\trelatedRecords,\n\t\t\t};\n\t\t}\n\n\t\tconsole.error(\"Error deleting records:\", error);\n\t\tthrow error;\n\t} finally {\n\t\tclient.release();\n\t}\n};\n\n/**\n * Force deletes records by first deleting all related records in referencing tables (cascade)\n */\nexport const forceDeleteRecords = async (\n\tparams: DeleteRecordParams,\n): Promise<DeleteResult> => {\n\tconst { tableName, primaryKeys, database } = params;\n\tconst pool = getDbPool(database);\n\tconst client = await pool.connect();\n\n\ttry {\n\t\tawait client.query(\"BEGIN\");\n\n\t\tconst pkColumn = primaryKeys[0]?.columnName;\n\t\tif (!pkColumn) {\n\t\t\tthrow new Error(\"Primary key column name is required\");\n\t\t}\n\n\t\tconst pkValues = primaryKeys.map((pk) => pk.value);\n\n\t\t// Get all FK constraints that reference this table\n\t\tconst fkConstraints = await getForeignKeyReferences(tableName, database);\n\n\t\tlet totalRelatedDeleted = 0;\n\n\t\t// Delete related records in reverse dependency order\n\t\t// We need to handle nested FKs recursively\n\t\tconst deletedTables = new Set<string>();\n\n\t\tconst deleteRelatedRecursively = async (\n\t\t\ttargetTable: string,\n\t\t\ttargetColumn: string,\n\t\t\tvalues: unknown[],\n\t\t) => {\n\t\t\t// First, find if there are tables referencing the target table\n\t\t\tconst nestedFks = await getForeignKeyReferences(targetTable, database);\n\n\t\t\tfor (const nestedFk of nestedFks) {\n\t\t\t\t// Get the values that will be deleted from the target table\n\t\t\t\tconst placeholders = values.map((_, i) => `$${i + 1}`).join(\", \");\n\t\t\t\tconst selectQuery = `\n\t\t\t\t\tSELECT \"${nestedFk.referencedColumn}\" FROM \"${targetTable}\"\n\t\t\t\t\tWHERE \"${targetColumn}\" IN (${placeholders})\n\t\t\t\t`;\n\n\t\t\t\tconst selectResult = await client.query(selectQuery, values);\n\t\t\t\tconst nestedValues = selectResult.rows.map(\n\t\t\t\t\t({ row }: { row: { [nestedFk.referencedColumn]: unknown } }) =>\n\t\t\t\t\t\trow[nestedFk.referencedColumn],\n\t\t\t\t);\n\n\t\t\t\tif (nestedValues.length > 0) {\n\t\t\t\t\tawait deleteRelatedRecursively(\n\t\t\t\t\t\tnestedFk.referencingTable,\n\t\t\t\t\t\tnestedFk.referencingColumn,\n\t\t\t\t\t\tnestedValues,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Now delete from the target table\n\t\t\tconst placeholders = values.map((_, i) => `$${i + 1}`).join(\", \");\n\t\t\tconst deleteQuery = `\n\t\t\t\tDELETE FROM \"${targetTable}\"\n\t\t\t\tWHERE \"${targetColumn}\" IN (${placeholders})\n\t\t\t`;\n\n\t\t\tconst deleteResult = await client.query(deleteQuery, values);\n\t\t\ttotalRelatedDeleted += deleteResult.rowCount ?? 0;\n\t\t\tdeletedTables.add(targetTable);\n\t\t};\n\n\t\t// Delete from all referencing tables first\n\t\tfor (const constraint of fkConstraints) {\n\t\t\tif (deletedTables.has(constraint.referencingTable)) continue;\n\n\t\t\tawait deleteRelatedRecursively(\n\t\t\t\tconstraint.referencingTable,\n\t\t\t\tconstraint.referencingColumn,\n\t\t\t\tpkValues,\n\t\t\t);\n\t\t}\n\n\t\t// Finally delete the main records\n\t\tconst placeholders = pkValues.map((_, i) => `$${i + 1}`).join(\", \");\n\t\tconst deleteSQL = `\n\t\t\tDELETE FROM \"${tableName}\"\n\t\t\tWHERE \"${pkColumn}\" IN (${placeholders})\n\t\t\tRETURNING *\n\t\t`;\n\n\t\tconsole.log(\"Force deleting records with SQL:\", deleteSQL, \"Values:\", pkValues);\n\t\tconst result = await client.query(deleteSQL, pkValues);\n\n\t\tawait client.query(\"COMMIT\");\n\n\t\tconst mainDeleted = result.rowCount ?? 0;\n\t\tconst message =\n\t\t\ttotalRelatedDeleted > 0\n\t\t\t\t? `Successfully deleted ${mainDeleted} ${mainDeleted === 1 ? \"record\" : \"records\"} from \"${tableName}\" and ${totalRelatedDeleted} related ${totalRelatedDeleted === 1 ? \"record\" : \"records\"} from other tables`\n\t\t\t\t: `Successfully deleted ${mainDeleted} ${mainDeleted === 1 ? \"record\" : \"records\"} from \"${tableName}\"`;\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tmessage,\n\t\t\tdeletedCount: mainDeleted + totalRelatedDeleted,\n\t\t};\n\t} catch (error) {\n\t\tawait client.query(\"ROLLBACK\");\n\t\tconsole.error(\"Error force deleting records:\", error);\n\t\tthrow error;\n\t} finally {\n\t\tclient.release();\n\t}\n};\n","import { getDbPool } from \"@/db-manager.js\";\n\nexport interface InsertRecordParams {\n\ttableName: string;\n\tdata: Record<string, unknown>;\n\tdatabase?: string;\n}\n\nexport const insertRecord = async (params: InsertRecordParams) => {\n\tconst { tableName, data, database } = params;\n\tconst pool = getDbPool(database);\n\tconst client = await pool.connect();\n\n\ttry {\n\t\t// Extract column names and values\n\t\tconst columns = Object.keys(data);\n\t\tconst values = Object.values(data);\n\n\t\t// Build the INSERT query\n\t\tconst placeholders = columns.map((_, index) => `$${index + 1}`).join(\", \");\n\t\tconst columnNames = columns.map((col) => `\"${col}\"`).join(\", \");\n\n\t\tconst insertSQL = `\n\t\t\tINSERT INTO \"${tableName}\" (${columnNames})\n\t\t\tVALUES (${placeholders})\n\t\t\tRETURNING *\n\t\t`;\n\n\t\tconsole.log(\"Inserting record with SQL:\", insertSQL, \"Values:\", values);\n\t\tconst result = await client.query(insertSQL, values);\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tmessage: `Record inserted into \"${tableName}\" successfully`,\n\t\t\tdata: result.rows[0],\n\t\t};\n\t} catch (error) {\n\t\tconsole.error(\"Error inserting record:\", error);\n\t\tthrow error;\n\t} finally {\n\t\tclient.release();\n\t}\n};\n","import { getDbPool } from \"@/db-manager.js\";\n\nexport interface UpdateRecordParams {\n\ttableName: string;\n\tupdates: Array<{\n\t\trowData: Record<string, unknown>; // Original row data to identify the record\n\t\tcolumnName: string;\n\t\tvalue: unknown;\n\t}>;\n\tprimaryKey?: string; // Optional: specify primary key column (defaults to 'id')\n\tdatabase?: string;\n}\n\n/**\n * Updates multiple cells in a table. Can update multiple rows or multiple cells in the same row.\n * Groups updates by row and executes them efficiently.\n */\nexport const updateRecords = async (params: UpdateRecordParams) => {\n\tconst { tableName, updates, primaryKey = \"id\", database } = params;\n\tconst pool = getDbPool(database);\n\tconst client = await pool.connect();\n\n\ttry {\n\t\tawait client.query(\"BEGIN\");\n\n\t\t// Group updates by row (using the primary key value)\n\t\tconst updatesByRow = new Map<\n\t\t\tunknown,\n\t\t\tArray<{ columnName: string; value: unknown; rowData: Record<string, unknown> }>\n\t\t>();\n\n\t\tfor (const update of updates) {\n\t\t\tconst pkValue = update.rowData[primaryKey];\n\t\t\tif (pkValue === undefined) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Primary key \"${primaryKey}\" not found in row data. Please ensure the row has a primary key.`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (!updatesByRow.has(pkValue)) {\n\t\t\t\tupdatesByRow.set(pkValue, []);\n\t\t\t}\n\t\t\tupdatesByRow.get(pkValue)?.push({\n\t\t\t\tcolumnName: update.columnName,\n\t\t\t\tvalue: update.value,\n\t\t\t\trowData: update.rowData,\n\t\t\t});\n\t\t}\n\n\t\tconst results = [];\n\t\tlet totalUpdated = 0;\n\n\t\t// Execute updates for each row\n\t\tfor (const [pkValue, rowUpdates] of updatesByRow.entries()) {\n\t\t\tconst setClauses = rowUpdates.map(\n\t\t\t\t(u, index) => `\"${u.columnName}\" = $${index + 1}`,\n\t\t\t);\n\t\t\tconst values = rowUpdates.map((u) => {\n\t\t\t\tconsole.log(`Value for ${u.columnName}:`, typeof u.value, u.value);\n\t\t\t\t// If the value is an object or array, stringify it for JSON/JSONB columns\n\t\t\t\tif (u.value !== null && typeof u.value === \"object\") {\n\t\t\t\t\treturn JSON.stringify(u.value);\n\t\t\t\t}\n\t\t\t\treturn u.value;\n\t\t\t});\n\n\t\t\t// Add the primary key value as the last parameter\n\t\t\tvalues.push(pkValue);\n\n\t\t\tconst updateSQL = `\n\t\t\t\tUPDATE \"${tableName}\"\n\t\t\t\tSET ${setClauses.join(\", \")}\n\t\t\t\tWHERE \"${primaryKey}\" = $${values.length}\n\t\t\t\tRETURNING *\n\t\t\t`;\n\n\t\t\tconsole.log(\"Updating record with SQL:\", updateSQL, \"Values:\", values);\n\t\t\tconst result = await client.query(updateSQL, values);\n\n\t\t\tif (result.rowCount === 0) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Record with ${primaryKey} = ${pkValue} not found in table \"${tableName}\"`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tresults.push(result.rows[0]);\n\t\t\ttotalUpdated += result.rowCount || 0;\n\t\t}\n\n\t\tawait client.query(\"COMMIT\");\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tmessage: `Successfully updated ${totalUpdated} ${totalUpdated === 1 ? \"row\" : \"rows\"} in \"${tableName}\"`,\n\t\t\tdata: results,\n\t\t\tupdatedCount: totalUpdated,\n\t\t};\n\t} catch (error) {\n\t\tawait client.query(\"ROLLBACK\");\n\t\tconsole.error(\"Error updating records:\", error);\n\t\tthrow error;\n\t} finally {\n\t\tclient.release();\n\t}\n};\n","import { zValidator } from \"@hono/zod-validator\";\nimport { Hono } from \"hono\";\nimport { z } from \"zod\";\nimport { deleteRecords, forceDeleteRecords } from \"@/dao/delete-records.dao.js\";\nimport { insertRecord } from \"@/dao/insert-record.dao.js\";\nimport { updateRecords } from \"@/dao/update-records.dao.js\";\nimport {\n\tdeleteRecordsSchema,\n\tinsertRecordSchema,\n\tupdateRecordsSchema,\n} from \"@/types/create-table.type.js\";\n\nconst databaseQuerySchema = z.object({\n\tdatabase: z.string(),\n});\n\nexport const recordsRoutes = new Hono();\n\n/**\n * POST /records - Insert a new record into a table\n */\nrecordsRoutes.post(\n\t\"/\",\n\tzValidator(\"json\", insertRecordSchema),\n\tzValidator(\"query\", databaseQuerySchema),\n\tasync (c) => {\n\t\ttry {\n\t\t\tconst body = c.req.valid(\"json\");\n\t\t\tconst { tableName, data } = body;\n\t\t\tconst { database } = c.req.valid(\"query\");\n\n\t\t\tconsole.log(\"POST /records body\", { tableName, data });\n\t\t\tconst result = await insertRecord({ tableName, data, database });\n\t\t\tconsole.log(\"POST /records\", result);\n\t\t\treturn c.json(result);\n\t\t} catch (error) {\n\t\t\tconsole.error(\"POST /records error:\", error);\n\t\t\tconst errorDetail =\n\t\t\t\terror && typeof error === \"object\" && \"detail\" in error\n\t\t\t\t\t? (error as { detail?: string }).detail\n\t\t\t\t\t: undefined;\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\tmessage: error instanceof Error ? error.message : \"Failed to create record\",\n\t\t\t\t\tdetail: errorDetail,\n\t\t\t\t},\n\t\t\t\t500,\n\t\t\t);\n\t\t}\n\t},\n);\n\n/**\n * PATCH /records - Update one or more cells in a table\n */\nrecordsRoutes.patch(\n\t\"/\",\n\tzValidator(\"json\", updateRecordsSchema),\n\tzValidator(\"query\", databaseQuerySchema),\n\tasync (c) => {\n\t\ttry {\n\t\t\tconst body = c.req.valid(\"json\");\n\t\t\tconst { tableName, updates, primaryKey } = body;\n\t\t\tconst { database } = c.req.valid(\"query\");\n\n\t\t\tconsole.log(\"PATCH /records body\", { tableName, updates, primaryKey });\n\t\t\tconst result = await updateRecords({ tableName, updates, primaryKey, database });\n\t\t\tconsole.log(\"PATCH /records\", result);\n\t\t\treturn c.json(result);\n\t\t} catch (error) {\n\t\t\tconsole.error(\"PATCH /records error:\", error);\n\t\t\tconst errorDetail =\n\t\t\t\terror && typeof error === \"object\" && \"detail\" in error\n\t\t\t\t\t? (error as { detail?: string }).detail\n\t\t\t\t\t: undefined;\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\tmessage: error instanceof Error ? error.message : \"Failed to update records\",\n\t\t\t\t\tdetail: errorDetail,\n\t\t\t\t},\n\t\t\t\t500,\n\t\t\t);\n\t\t}\n\t},\n);\n\n/**\n * DELETE /records - Delete records from a table\n */\nrecordsRoutes.delete(\n\t\"/\",\n\tzValidator(\"json\", deleteRecordsSchema),\n\tzValidator(\"query\", databaseQuerySchema),\n\tasync (c) => {\n\t\ttry {\n\t\t\tconst body = c.req.valid(\"json\");\n\t\t\tconst { tableName, primaryKeys } = body;\n\t\t\tconst { database } = c.req.valid(\"query\");\n\n\t\t\tconsole.log(\"DELETE /records body\", { tableName, primaryKeys });\n\t\t\tconst result = await deleteRecords({ tableName, primaryKeys, database });\n\t\t\tconsole.log(\"DELETE /records result\", result);\n\n\t\t\tif (result.fkViolation) {\n\t\t\t\treturn c.json(result, 409);\n\t\t\t}\n\n\t\t\treturn c.json(result);\n\t\t} catch (error) {\n\t\t\tconsole.error(\"DELETE /records error:\", error);\n\t\t\tconst errorDetail =\n\t\t\t\terror && typeof error === \"object\" && \"detail\" in error\n\t\t\t\t\t? (error as { detail?: string }).detail\n\t\t\t\t\t: undefined;\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\tmessage: error instanceof Error ? error.message : \"Failed to delete records\",\n\t\t\t\t\tdetail: errorDetail,\n\t\t\t\t},\n\t\t\t\t500,\n\t\t\t);\n\t\t}\n\t},\n);\n\n/**\n * DELETE /records/force - Force delete records and all related FK records\n */\nrecordsRoutes.delete(\n\t\"/force\",\n\tzValidator(\"json\", deleteRecordsSchema),\n\tzValidator(\"query\", databaseQuerySchema),\n\tasync (c) => {\n\t\ttry {\n\t\t\tconst body = c.req.valid(\"json\");\n\t\t\tconst { tableName, primaryKeys } = body;\n\t\t\tconst { database } = c.req.valid(\"query\");\n\n\t\t\tconsole.log(\"DELETE /records/force body\", { tableName, primaryKeys });\n\t\t\tconst result = await forceDeleteRecords({ tableName, primaryKeys, database });\n\t\t\tconsole.log(\"DELETE /records/force result\", result);\n\n\t\t\treturn c.json(result);\n\t\t} catch (error) {\n\t\t\tconsole.error(\"DELETE /records/force error:\", error);\n\t\t\tconst errorDetail =\n\t\t\t\terror && typeof error === \"object\" && \"detail\" in error\n\t\t\t\t\t? (error as { detail?: string }).detail\n\t\t\t\t\t: undefined;\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\tmessage:\n\t\t\t\t\t\terror instanceof Error ? error.message : \"Failed to force delete records\",\n\t\t\t\t\tdetail: errorDetail,\n\t\t\t\t},\n\t\t\t\t500,\n\t\t\t);\n\t\t}\n\t},\n);\n","import { getDbPool } from \"@/db-manager.js\";\nimport type { CreateTableFormData, FieldDataType } from \"@/types/create-table.type.js\";\n\nexport const createTable = async (tableData: CreateTableFormData, database?: string) => {\n\tconst { tableName, fields, foreignKeys } = tableData;\n\tconst pool = getDbPool(database);\n\tconst client = await pool.connect();\n\n\ttry {\n\t\t// Build column definitions\n\t\tconst columnDefinitions = fields.map((field: FieldDataType) => {\n\t\t\tlet columnDef = `\"${field.columnName}\" ${field.columnType}`;\n\n\t\t\t// Add array suffix if needed\n\t\t\tif (field.isArray) {\n\t\t\t\tcolumnDef += \"[]\";\n\t\t\t}\n\n\t\t\t// Add PRIMARY KEY constraint\n\t\t\tif (field.isPrimaryKey) {\n\t\t\t\tcolumnDef += \" PRIMARY KEY\";\n\t\t\t}\n\n\t\t\t// Add UNIQUE constraint\n\t\t\tif (field.isUnique && !field.isPrimaryKey) {\n\t\t\t\tcolumnDef += \" UNIQUE\";\n\t\t\t}\n\n\t\t\t// Add NOT NULL constraint (if not nullable)\n\t\t\tif (!field.isNullable) {\n\t\t\t\tcolumnDef += \" NOT NULL\";\n\t\t\t}\n\n\t\t\t// Add GENERATED ALWAYS AS IDENTITY for identity columns\n\t\t\tif (field.isIdentity) {\n\t\t\t\tcolumnDef += \" GENERATED ALWAYS AS IDENTITY\";\n\t\t\t}\n\n\t\t\t// Add default value\n\t\t\tif (field.defaultValue && !field.isIdentity) {\n\t\t\t\tcolumnDef += ` DEFAULT ${field.defaultValue}`;\n\t\t\t}\n\n\t\t\treturn columnDef;\n\t\t});\n\n\t\t// Build foreign key constraints\n\t\tconst foreignKeyConstraints =\n\t\t\tforeignKeys?.map((fk) => {\n\t\t\t\tconst constraintName = `fk_${tableName}_${fk.columnName}_${fk.referencedTable}_${fk.referencedColumn}`;\n\t\t\t\treturn `CONSTRAINT \"${constraintName}\" FOREIGN KEY (\"${fk.columnName}\") REFERENCES \"${fk.referencedTable}\" (\"${fk.referencedColumn}\") ON UPDATE ${fk.onUpdate} ON DELETE ${fk.onDelete}`;\n\t\t\t}) || [];\n\n\t\t// Combine column definitions and foreign key constraints\n\t\tconst allDefinitions = [...columnDefinitions, ...foreignKeyConstraints];\n\n\t\t// Create the table\n\t\tconst createTableSQL = `\n\t\t\tCREATE TABLE \"${tableName}\" (\n\t\t\t\t${allDefinitions.join(\",\\n\\t\\t\\t\\t\")}\n\t\t\t);\n\t\t`;\n\n\t\tconsole.log(\"Creating table with SQL:\", createTableSQL);\n\t\tawait client.query(createTableSQL);\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\ttableName,\n\t\t\tmessage: `Table \"${tableName}\" created successfully`,\n\t\t};\n\t} catch (error) {\n\t\tconsole.error(\"Error creating table:\", error);\n\t\tthrow error;\n\t} finally {\n\t\tclient.release();\n\t}\n};\n","import { getDbPool } from \"@/db-manager.js\";\n\nexport interface TableInfo {\n\ttableName: string;\n\trowCount: number;\n}\n\nexport const getTablesList = async (database?: string): Promise<TableInfo[]> => {\n\tconst pool = getDbPool(database);\n\tconst client = await pool.connect();\n\ttry {\n\t\tconst res = await client.query(`\n SELECT \n t.table_name as \"tableName\",\n COALESCE(s.n_live_tup, 0) as \"rowCount\" \n FROM information_schema.tables t\n LEFT JOIN pg_stat_user_tables s ON t.table_name = s.relname\n WHERE t.table_schema = 'public'\n AND t.table_type = 'BASE TABLE'\n ORDER BY t.table_name;\n `);\n\t\treturn res.rows.map((r: any) => ({\n\t\t\ttableName: r.tableName,\n\t\t\trowCount: Number(r.rowCount),\n\t\t}));\n\t} finally {\n\t\tclient.release();\n\t}\n};\n","import { zValidator } from \"@hono/zod-validator\";\nimport { Hono } from \"hono\";\nimport { createTable } from \"@/dao/create-table.dao.js\";\nimport { getTablesList } from \"@/dao/table-list.dao.js\";\nimport { createTableSchema, databaseQuerySchema } from \"@/types/create-table.type.js\";\nimport { handleConnectionError } from \"@/utils/error-handler.js\";\n\nexport const tablesRoutes = new Hono();\n\n/**\n * GET /tables - Get all tables\n */\ntablesRoutes.get(\"/\", zValidator(\"query\", databaseQuerySchema), async (c) => {\n\ttry {\n\t\tconst { database } = c.req.valid(\"query\");\n\t\tconst tablesList = await getTablesList(database);\n\t\tconsole.log(\"GET /tables\", tablesList);\n\t\treturn c.json(tablesList);\n\t} catch (error) {\n\t\tconsole.error(\"GET /tables error:\", error);\n\t\treturn handleConnectionError(c, error, \"Failed to fetch tables\");\n\t}\n});\n\n/**\n * POST /tables - Create a new table\n */\ntablesRoutes.post(\n\t\"/\",\n\tzValidator(\"json\", createTableSchema),\n\tzValidator(\"query\", databaseQuerySchema),\n\tasync (c) => {\n\t\ttry {\n\t\t\tconst body = c.req.valid(\"json\");\n\t\t\tconst { database } = c.req.valid(\"query\");\n\t\t\tconsole.log(\"POST /tables body\", body);\n\t\t\tconst data = await createTable(body, database);\n\t\t\tconsole.log(\"POST /tables\", data);\n\t\t\treturn c.json(data);\n\t\t} catch (error) {\n\t\t\tconsole.error(\"POST /tables error:\", error);\n\t\t\tconst errorDetail =\n\t\t\t\terror && typeof error === \"object\" && \"detail\" in error\n\t\t\t\t\t? (error as { detail?: string }).detail\n\t\t\t\t\t: undefined;\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\tmessage: error instanceof Error ? error.message : \"Failed to create table\",\n\t\t\t\t\tdetail: errorDetail,\n\t\t\t\t},\n\t\t\t\t500,\n\t\t\t);\n\t\t}\n\t},\n);\n","import type { NodeWebSocket } from \"@hono/node-ws\";\nimport { Hono } from \"hono\";\nimport { db } from \"@/db.js\";\n\nconst checkDatabaseConnection = async (): Promise<{\n\tsuccess: boolean;\n\terror?: string;\n}> => {\n\tconst client = await db.connect();\n\ttry {\n\t\tawait client.query(\"SELECT 1\");\n\t\treturn { success: true };\n\t} catch (error) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: error instanceof Error ? error.message : \"Unknown error\",\n\t\t};\n\t} finally {\n\t\tclient.release();\n\t}\n};\n\nconst DB_CHECK_INTERVAL = 5000;\nconst DB_CHECK_TIMEOUT = 10000;\n\nexport const websocketRoutes = (upgradeWebSocket: NodeWebSocket[\"upgradeWebSocket\"]) => {\n\tconst app = new Hono();\n\n\tapp.get(\n\t\t\"/\",\n\t\tupgradeWebSocket(() => {\n\t\t\tlet interval: NodeJS.Timeout;\n\n\t\t\treturn {\n\t\t\t\tonOpen: async (_event, ws) => {\n\t\t\t\t\tconsole.log(\"WebSocket client connected\");\n\n\t\t\t\t\t// Send initial status\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst status = await checkDatabaseConnection();\n\t\t\t\t\t\tws.send(\n\t\t\t\t\t\t\tJSON.stringify({\n\t\t\t\t\t\t\t\t...status,\n\t\t\t\t\t\t\t\tstatus: status.success ? \"connected\" : \"failed\",\n\t\t\t\t\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tconsole.error(\"Error checking DB on open:\", err);\n\t\t\t\t\t\tws.send(\n\t\t\t\t\t\t\tJSON.stringify({\n\t\t\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\t\t\tstatus: \"failed\",\n\t\t\t\t\t\t\t\terror: \"Initial check failed\",\n\t\t\t\t\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Check DB status every 5 seconds\n\t\t\t\t\tinterval = setInterval(async () => {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst status = await Promise.race([\n\t\t\t\t\t\t\t\tcheckDatabaseConnection(),\n\t\t\t\t\t\t\t\tnew Promise<{ success: boolean; error: string }>((_, reject) =>\n\t\t\t\t\t\t\t\t\tsetTimeout(\n\t\t\t\t\t\t\t\t\t\t() => reject({ success: false, error: \"Database check timeout\" }),\n\t\t\t\t\t\t\t\t\t\tDB_CHECK_TIMEOUT,\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t]);\n\t\t\t\t\t\t\tws.send(\n\t\t\t\t\t\t\t\tJSON.stringify({\n\t\t\t\t\t\t\t\t\t...status,\n\t\t\t\t\t\t\t\t\tstatus: status.success ? \"connected\" : \"failed\",\n\t\t\t\t\t\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\tconsole.error(\"Error in DB check interval:\", err);\n\t\t\t\t\t\t\tws.send(\n\t\t\t\t\t\t\t\tJSON.stringify({\n\t\t\t\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\t\t\t\tstatus: \"failed\",\n\t\t\t\t\t\t\t\t\terror: err instanceof Error ? err.message : \"Check failed\",\n\t\t\t\t\t\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}, DB_CHECK_INTERVAL);\n\t\t\t\t},\n\t\t\t\tonMessage(event, _ws) {\n\t\t\t\t\tconsole.log(`Message from client: ${event.data}`);\n\t\t\t\t},\n\t\t\t\tonClose: () => {\n\t\t\t\t\tconsole.log(\"WebSocket connection closed\");\n\t\t\t\t\tif (interval) {\n\t\t\t\t\t\tclearInterval(interval);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tonError: (err) => {\n\t\t\t\t\tconsole.error(\"WebSocket error:\", err);\n\t\t\t\t\tif (interval) {\n\t\t\t\t\t\tclearInterval(interval);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t};\n\t\t}),\n\t);\n\n\treturn app;\n};\n","import path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { serveStatic } from \"@hono/node-server/serve-static\";\nimport { createNodeWebSocket } from \"@hono/node-ws\";\nimport { Hono } from \"hono\";\nimport { cors } from \"hono/cors\";\nimport { logger } from \"hono/logger\";\nimport { chatRoutes } from \"@/routes/chat.routes.js\";\nimport { columnsRoutes } from \"@/routes/columns.routes.js\";\nimport { dataRoutes } from \"@/routes/data.routes.js\";\nimport { databasesRoutes } from \"@/routes/databases.routes.js\";\nimport { queryRoutes } from \"@/routes/query.routes.js\";\nimport { recordsRoutes } from \"@/routes/records.routes.js\";\nimport { tablesRoutes } from \"@/routes/tables.routes.js\";\nimport { websocketRoutes } from \"@/routes/websocket.routes.js\";\n\nconst getCoreDistPath = () => {\n\tif (process.env.NODE_ENV === \"development\") {\n\t\treturn path.resolve(process.cwd(), \"../core/dist\");\n\t}\n\n\tconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\treturn path.resolve(__dirname, \"./core-dist\");\n};\n\nexport const createServer = () => {\n\tconst app = new Hono({ strict: false });\n\tconst { upgradeWebSocket, injectWebSocket } = createNodeWebSocket({ app: app as any });\n\n\tapp.use(\"/*\", cors());\n\tapp.use(logger());\n\n\tapp.use(\n\t\t\"/favicon.ico\",\n\t\tserveStatic({ path: path.resolve(getCoreDistPath(), \"favicon.ico\") }),\n\t);\n\n\tapp.use(\"*\", async (c, next) => {\n\t\tc.header(\"Access-Control-Allow-Origin\", \"*\");\n\t\tc.header(\"Access-Control-Allow-Methods\", \"GET, POST, PUT, DELETE, OPTIONS\");\n\t\tc.header(\"Access-Control-Allow-Headers\", \"Content-Type\");\n\t\tawait next();\n\t});\n\n\tapp.route(\"/ws\", websocketRoutes(upgradeWebSocket));\n\tapp.route(\"/databases\", databasesRoutes);\n\tapp.route(\"/tables\", tablesRoutes);\n\tapp.route(\"/tables/:tableName/columns\", columnsRoutes);\n\tapp.route(\"/tables/:tableName/data\", dataRoutes);\n\tapp.route(\"/records\", recordsRoutes);\n\tapp.route(\"/query\", queryRoutes);\n\tapp.route(\"/chat\", chatRoutes);\n\n\tapp.use(\"/*\", serveStatic({ root: getCoreDistPath() }));\n\n\treturn { app, injectWebSocket };\n};\n","import { intro, outro } from \"@clack/prompts\";\nimport { serve } from \"@hono/node-server\";\nimport open from \"open\";\nimport color from \"picocolors\";\n\nimport { args } from \"@/cmd/args.js\";\nimport { getDatabaseUrl } from \"@/cmd/get-db-url.js\";\nimport { loadEnv } from \"@/cmd/load-env.js\";\nimport { showHelp } from \"@/cmd/show-help.js\";\nimport { showStatus } from \"@/cmd/show-status.js\";\nimport { showVersion } from \"@/cmd/show-version.js\";\nimport { DEFAULTS } from \"@/utils/defaults.js\";\n\nexport const main = async () => {\n\tconst { env, port, databaseUrl, varName, status, help, version } = args();\n\n\t// Handle help flag\n\tif (help) {\n\t\tshowHelp();\n\t\tprocess.exit(0);\n\t}\n\n\t// Handle version flag\n\tif (version) {\n\t\tshowVersion();\n\t\tprocess.exit(0);\n\t}\n\n\t// Handle status flag\n\tif (status) {\n\t\tawait showStatus(env, databaseUrl, varName);\n\t\tprocess.exit(0);\n\t}\n\n\tintro(color.inverse(\" db-studio \"));\n\n\tconst PORT = port ? parseInt(port, 10) : DEFAULTS.PORT;\n\tconst VAR_NAME = varName || DEFAULTS.VAR_NAME;\n\tconst ENV = env ? await loadEnv(env) : await loadEnv(DEFAULTS.ENV);\n\tconst DATABASE_URL = databaseUrl ? databaseUrl : await getDatabaseUrl(ENV, VAR_NAME);\n\n\t// Set DATABASE_URL in process.env before importing createServer\n\t// This ensures the db pool is initialized with the correct connection string\n\tprocess.env.DATABASE_URL = DATABASE_URL;\n\n\t// Import createServer dynamically after setting DATABASE_URL\n\tconst { createServer } = await import(\"./utils/create-server.js\");\n\tconst { app, injectWebSocket } = createServer();\n\tconst server = serve({\n\t\tfetch: app.fetch,\n\t\tport: PORT,\n\t});\n\tinjectWebSocket(server);\n\n\toutro(color.green(`Server running at ${color.cyan(`http://localhost:${PORT}`)}`));\n\n\tif (process.env.NODE_ENV && process.env.NODE_ENV !== \"development\") {\n\t\tawait open(`http://localhost:${PORT}`);\n\t}\n};\n\nmain().catch((err) => {\n\tconsole.error(color.red(`❌ Unexpected error: ${err.message}`));\n\tprocess.exit(1);\n});\n","import { program } from \"commander\";\n\ntype Args = {\n\tenv?: string;\n\tport?: string;\n\tdatabaseUrl?: string;\n\tvarName?: string;\n\tstatus?: boolean;\n\thelp?: boolean;\n\tversion?: boolean;\n};\n\n/**\n * Get the arguments from the command line\n */\nexport const args = () => {\n\tprogram\n\t\t.name(\"db-studio\")\n\t\t.option(\"-e, --env <path>\", \"Path to custom .env file\")\n\t\t.option(\"-p, --port <port>\", \"Port to run the server on\")\n\t\t.option(\"-d, --database-url <url>\", \"Database URL to use\")\n\t\t.option(\n\t\t\t\"-n, --var-name <name>\",\n\t\t\t\"Custom environment variable name (default: DATABASE_URL)\",\n\t\t)\n\t\t.option(\"-s, --status\", \"Show status of the server\")\n\t\t.option(\"-h, --help\", \"Show help\")\n\t\t.option(\"-v, --version\", \"Show version\")\n\t\t.parse(process.argv);\n\n\treturn program.opts<Args>();\n};\n","import { readFile } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport { cancel, isCancel, note, select, spinner, text } from \"@clack/prompts\";\nimport { type DotenvParseOutput, parse as parseDotenv } from \"dotenv\";\nimport color from \"picocolors\";\n\n/**\n * Get the database URL from the environment variables\n */\nexport const getDatabaseUrl = async (\n\tenv?: DotenvParseOutput | null,\n\tvarName?: string,\n) => {\n\tconst envVarName = varName || \"DATABASE_URL\";\n\n\tif (env?.[envVarName]) {\n\t\treturn env[envVarName];\n\t}\n\n\tconst s = spinner();\n\ts.start(\"Looking for database connection...\");\n\n\tif (!env) {\n\t\tnote(color.red(\"No .env file found in current directory\"));\n\t} else {\n\t\tnote(color.red(`${envVarName} not found in .env`));\n\t}\n\n\tconst choice = await select({\n\t\tmessage: `How do you want to provide ${envVarName}?`,\n\t\toptions: [\n\t\t\t{ value: \"manual\", label: \"Enter connection string manually\" },\n\t\t\t{ value: \"other-env\", label: \"Use different .env file\" },\n\t\t\t// todo: add multiple db connections support\n\t\t\t{ value: \"cancel\", label: \"Cancel / Exit\" },\n\t\t],\n\t\tinitialValue: \"manual\",\n\t});\n\tif (isCancel(choice) || choice === \"cancel\") {\n\t\tcancel(\"No database connection provided. Exiting...\");\n\t\tprocess.exit(0);\n\t}\n\n\tif (choice === \"other-env\") {\n\t\ts.start(\"Waiting for path...\");\n\t\tconst customPath = await text({\n\t\t\tmessage: \"Enter path to .env file\",\n\t\t\tplaceholder: \"~/projects/myapp/.env.local or ./special.env\",\n\t\t\tvalidate(value: string) {\n\t\t\t\tif (!value.trim()) return \"Path is required\";\n\t\t\t},\n\t\t});\n\n\t\tif (isCancel(customPath)) {\n\t\t\tcancel(\"Cancelled.\");\n\t\t\tprocess.exit(0);\n\t\t}\n\n\t\ts.stop(\"Trying custom .env...\");\n\n\t\tconst customEnvPath = resolve(customPath);\n\t\ttry {\n\t\t\tconst content = await readFile(customEnvPath, \"utf-8\");\n\t\t\tconst parsed = parseDotenv(content);\n\t\t\tif (parsed[envVarName]) {\n\t\t\t\treturn parsed[envVarName];\n\t\t\t}\n\t\t\tthrow new Error(`${envVarName} still missing in custom file`);\n\t\t} catch (e: unknown) {\n\t\t\tconst error = e as Error;\n\t\t\tcancel(`Cannot read or parse file: ${color.dim(error.message)}`);\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\n\t// 3. Manual input\n\ts.stop(\"Manual input...\");\n\n\tconst dbUrl = await text({\n\t\tmessage: `Paste your ${envVarName}`,\n\t\tplaceholder: \"postgresql://user:password@localhost:5432/mydb\",\n\t\tvalidate(value: string) {\n\t\t\tif (!value.trim()) return \"Connection string is required!\";\n\t\t\ttry {\n\t\t\t\tnew URL(value); // very basic check\n\t\t\t\treturn undefined;\n\t\t\t} catch {\n\t\t\t\treturn \"Must be a valid URL format\";\n\t\t\t}\n\t\t},\n\t});\n\n\tif (isCancel(dbUrl)) {\n\t\tcancel(\"Cancelled.\");\n\t\tprocess.exit(0);\n\t}\n\n\treturn dbUrl.trim();\n};\n","import { access, readFile } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport { parse as parseDotenv } from \"dotenv\";\n\n/**\n * Load the environment variables from the file\n */\nexport const loadEnv = async (env?: string) => {\n\tconst envPath = env ? resolve(env) : resolve(process.cwd(), \".env\");\n\n\ttry {\n\t\tawait access(envPath);\n\t\tconst content = await readFile(envPath, \"utf-8\");\n\t\treturn parseDotenv(content);\n\t} catch (err) {\n\t\tif (err instanceof Error && err.message.includes(\"ENOENT\")) {\n\t\t\treturn null; // we'll handle missing file later\n\t\t}\n\t\tthrow err;\n\t}\n};\n","import { intro, outro } from \"@clack/prompts\";\nimport color from \"picocolors\";\n\n/**\n * Display help information\n */\nexport const showHelp = () => {\n\tintro(color.inverse(\" db-studio \"));\n\n\tconsole.log(color.bold(\"\\nUsage:\"));\n\tconsole.log(\" db-studio [options]\\n\");\n\n\tconsole.log(color.bold(\"Options:\"));\n\tconsole.log(\" -e, --env <path> Path to custom .env file\");\n\tconsole.log(\" -p, --port <port> Port to run the server on (default: 3333)\");\n\tconsole.log(\" -d, --database-url <url> Database URL to use\");\n\tconsole.log(\n\t\t\" -n, --var-name <name> Custom environment variable name (default: DATABASE_URL)\",\n\t);\n\tconsole.log(\" -s, --status Show status of the database connection\");\n\tconsole.log(\" -h, --help Show this help message\");\n\tconsole.log(\" -v, --version Show version number\\n\");\n\n\tconsole.log(color.bold(\"Examples:\"));\n\tconsole.log(\" db-studio\");\n\tconsole.log(\" db-studio -e .env.local\");\n\tconsole.log(\" db-studio -p 4000\");\n\tconsole.log(\" db-studio -d postgresql://user:pass@localhost:5432/mydb\");\n\tconsole.log(\" db-studio -n MY_DATABASE_URL\");\n\tconsole.log(\" db-studio -e .env.production -n PROD_DB_URL\");\n\tconsole.log(\" db-studio --status\\n\");\n\n\toutro(color.green(\"For more information, visit: https://dbstudio.sh/docs\"));\n};\n","import { intro, note, outro } from \"@clack/prompts\";\nimport color from \"picocolors\";\nimport { loadEnv } from \"@/cmd/load-env.js\";\nimport { DEFAULTS } from \"@/utils/defaults.js\";\n\n/**\n * Show connection status\n */\nexport const showStatus = async (\n\tenv?: string,\n\tdatabaseUrl?: string,\n\tvarName?: string,\n) => {\n\tintro(color.inverse(\" db-studio \"));\n\n\tconst envVarName = varName || DEFAULTS.VAR_NAME;\n\tlet foundUrl: string | null = null;\n\n\t// Check if DATABASE_URL is provided via CLI\n\tif (databaseUrl) {\n\t\tfoundUrl = databaseUrl;\n\t} else {\n\t\t// Try to load from .env file\n\t\tconst ENV = env ? await loadEnv(env) : await loadEnv(DEFAULTS.ENV);\n\t\tif (ENV?.[envVarName]) {\n\t\t\tfoundUrl = ENV[envVarName];\n\t\t}\n\t}\n\n\tif (foundUrl) {\n\t\toutro(color.green(`✓ Database connection configured (using ${envVarName})`));\n\t} else {\n\t\tnote(color.red(`✗ ${envVarName} not found`), \"Status\");\n\t\tconsole.log(color.yellow(\"\\n To configure database connection:\"));\n\t\tconsole.log(color.dim(` • Add ${envVarName} to your .env file`));\n\t\tconsole.log(color.dim(\" • Use -d flag: db-studio -d <url>\"));\n\t\tconsole.log(color.dim(\" • Use -e flag: db-studio -e <path-to-env>\"));\n\t\tconsole.log(color.dim(\" • Use -n flag: db-studio -n <var-name>\\n\"));\n\n\t\toutro(color.yellow(\"⚠ No database connection configured\"));\n\t}\n};\n","import { intro, outro } from \"@clack/prompts\";\nimport color from \"picocolors\";\nimport packageJson from \"../../package.json\" with { type: \"json\" };\n\n/**\n * Display version information\n */\nexport const showVersion = () => {\n\tintro(color.inverse(\" db-studio \"));\n\toutro(color.green(`🚀 db-studio v${packageJson.version}`));\n};\n","{\n \"name\": \"db-studio\",\n \"type\": \"module\",\n \"version\": \"1.2.7\",\n \"description\": \"Modern database client for PostgreSQL with spreadsheet-like grid, AI-powered SQL assistance, ER diagrams, fast data browsing and editing. CLI tool, upcoming desktop & web versions.\",\n \"keywords\": [\n \"database\",\n \"database client\",\n \"postgres\",\n \"postgresql\",\n \"database gui\",\n \"sql client\",\n \"database studio\",\n \"postgres gui\",\n \"ai sql\",\n \"sql editor\",\n \"er diagram\",\n \"database management\",\n \"data browser\",\n \"spreadsheet database\",\n \"postgres admin\",\n \"mysql client\",\n \"sqlite client\",\n \"database tool\",\n \"developer tools\"\n ],\n \"author\": \"Hüsam 🥑 <devhsmq@gmail.com>\",\n \"homepage\": \"https://dbstudio.sh\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/husamql3/db-studio.git\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/husamql3/db-studio/issues\"\n },\n \"license\": \"MIT\",\n \"bin\": {\n \"db-studio\": \"./dist/index.js\"\n },\n \"files\": [\n \"dist\"\n ],\n \"scripts\": {\n \"dev\": \"NODE_ENV=development tsx watch src/index.ts\",\n \"build\": \"tsup\",\n \"build:release\": \"tsup --minify --sourcemap\",\n \"start\": \"node dist/index.js\",\n \"check\": \"biome check --write --unsafe --verbose\"\n },\n \"dependencies\": {\n \"@clack/prompts\": \"^0.11.0\",\n \"@hono/node-server\": \"^1.19.7\",\n \"@hono/node-ws\": \"^1.2.0\",\n \"@hono/zod-validator\": \"^0.7.6\",\n \"@tanstack/ai-openai\": \"^0.2.1\",\n \"@upstash/redis\": \"^1.36.1\",\n \"commander\": \"^12.1.0\",\n \"dotenv\": \"^16.4.7\",\n \"hono\": \"^4.10.4\",\n \"open\": \"^10.0.2\",\n \"pg\": \"^8.13.1\",\n \"picocolors\": \"^1.1.1\",\n \"zod\": \"^4.2.1\"\n },\n \"devDependencies\": {\n \"@biomejs/biome\": \"^2.2.6\",\n \"@biomejs/cli-linux-x64\": \"^2.2.6\",\n \"@types/node\": \"^20.11.17\",\n \"@types/pg\": \"^8.16.0\",\n \"tsup\": \"^8.5.1\",\n \"tsx\": \"^4.7.1\",\n \"typescript\": \"^5.8.3\",\n \"wrangler\": \"^4.4.0\"\n }\n}"],"mappings":"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","names":["DEFAULTS","init_defaults","__esmMin","Pool","dbInstance","getPool","db","init_db","__esmMin","err","error","_target","prop","Pool","DatabaseManager","databaseManager","getDbPool","init_db_manager","__esmMin","databaseUrl","url","error","database","connectionString","poolConfig","pool","err","closePromises","mapPostgresToDataType","pgType","normalized","DataTypes","standardizeDataTypeLabel","StandardizedDataType","init_column_types","__esmMin","getTableColumns","init_table_columns_dao","__esmMin","init_db_manager","init_column_types","tableName","database","client","getDbPool","r","parsedEnumValues","mapPostgresToDataType","standardizeDataTypeLabel","getTableNames","client","db","getTableDescription","tableName","getSampleData","convertColumnInfo","col","column","extractRelationships","tables","relationships","table","toTable","toColumn","getDatabaseSchema","options","includeSampleData","includeDescriptions","tablePromises","columns","description","sampleData","getTableColumns","error","getDetailedSchema","init_table_details_schema","__esmMin","init_db","init_table_columns_dao","generateSystemPrompt","schema","formatSchemaForPrompt","output","table","col","pkIndicator","fkIndicator","nullable","rel","init_system_prompt_generator","__esmMin","Hono","chatRoutes","init_chat_routes","__esmMin","init_table_details_schema","init_defaults","init_system_prompt_generator","c","messages","conversationId","schema","getDetailedSchema","systemPrompt","generateSystemPrompt","payload","proxyResponse","DEFAULTS","errorData","readable","writable","error","errorMessage","z","FOREIGN_KEY_ACTIONS","foreignKeyActionSchema","fieldDataSchema","foreignKeyDataSchema","createTableSchema","tableNameParamSchema","tableDataQuerySchema","insertRecordSchema","updateRecordsSchema","deleteRecordsSchema","executeQuerySchema","databaseQuerySchema","init_create_table_type","__esmMin","val","handleConnectionError","init_error_handler","__esmMin","c","error","fallbackMessage","errorMessage","isConnectionError","err","zValidator","Hono","columnsRoutes","init_columns_routes","__esmMin","init_table_columns_dao","init_create_table_type","init_error_handler","tableNameParamSchema","databaseQuerySchema","c","tableName","database","columns","getTableColumns","error","handleConnectionError","buildWhereClause","buildSortClause","getTableData","init_tables_data_dao","__esmMin","init_db_manager","filters","conditions","values","filter","paramIndex","columnName","sorts","order","sort","tableName","page","pageSize","database","sortClause","whereClause","filterValues","client","getDbPool","offset","countRes","totalRows","totalPages","limitParamIndex","offsetParamIndex","zValidator","Hono","dataRoutes","init_data_routes","__esmMin","init_tables_data_dao","init_create_table_type","init_error_handler","tableNameParamSchema","tableDataQuerySchema","c","tableName","page","pageSize","sortParam","order","filters","sort","parsed","database","data","getTableData","error","handleConnectionError","getDatabasesList","getDbPool","getCurrentDatabase","getDatabaseConnectionInfo","row","databaseUrl","host","port","url","init_database_list_dao","__esmMin","init_db_manager","Hono","databasesRoutes","init_databases_routes","__esmMin","init_database_list_dao","c","databases","getDatabasesList","current","getCurrentDatabase","info","getDatabaseConnectionInfo","executeQuery","init_query_dao","__esmMin","init_db_manager","params","query","database","client","getDbPool","cleanedQuery","startTime","result","duration","field","error","errorMessage","zValidator","Hono","queryRoutes","init_query_routes","__esmMin","init_query_dao","init_create_table_type","executeQuerySchema","c","query","database","data","executeQuery","error","errorMessage","getForeignKeyReferences","getRelatedRecords","deleteRecords","forceDeleteRecords","init_delete_records_dao","__esmMin","init_db_manager","tableName","database","getDbPool","row","primaryKeys","fkConstraints","relatedRecords","pool","constraintsByTable","constraint","key","pkValues","pk","_tableColumn","constraints","placeholders","_","i","query","result","params","client","pkColumn","deleteSQL","error","totalRelatedDeleted","deletedTables","deleteRelatedRecursively","targetTable","targetColumn","values","nestedFks","nestedFk","selectQuery","nestedValues","deleteQuery","deleteResult","mainDeleted","insertRecord","init_insert_record_dao","__esmMin","init_db_manager","params","tableName","data","database","client","getDbPool","columns","values","placeholders","_","index","columnNames","col","insertSQL","result","error","updateRecords","init_update_records_dao","__esmMin","init_db_manager","params","tableName","updates","primaryKey","database","client","getDbPool","updatesByRow","update","pkValue","results","totalUpdated","rowUpdates","setClauses","u","index","values","updateSQL","result","error","zValidator","Hono","z","databaseQuerySchema","recordsRoutes","init_records_routes","__esmMin","init_delete_records_dao","init_insert_record_dao","init_update_records_dao","init_create_table_type","insertRecordSchema","c","body","tableName","data","database","result","insertRecord","error","errorDetail","updateRecordsSchema","updates","primaryKey","updateRecords","deleteRecordsSchema","primaryKeys","deleteRecords","forceDeleteRecords","createTable","init_create_table_dao","__esmMin","init_db_manager","tableData","database","tableName","fields","foreignKeys","client","getDbPool","columnDefinitions","field","columnDef","foreignKeyConstraints","fk","allDefinitions","createTableSQL","error","getTablesList","init_table_list_dao","__esmMin","init_db_manager","database","client","getDbPool","r","zValidator","Hono","tablesRoutes","init_tables_routes","__esmMin","init_create_table_dao","init_table_list_dao","init_create_table_type","init_error_handler","databaseQuerySchema","c","database","tablesList","getTablesList","error","handleConnectionError","createTableSchema","body","data","createTable","errorDetail","Hono","checkDatabaseConnection","DB_CHECK_INTERVAL","DB_CHECK_TIMEOUT","websocketRoutes","init_websocket_routes","__esmMin","init_db","client","db","error","upgradeWebSocket","app","interval","_event","ws","status","_","reject","err","event","_ws","create_server_exports","__export","createServer","path","fileURLToPath","serveStatic","createNodeWebSocket","Hono","cors","logger","getCoreDistPath","init_create_server","__esmMin","init_chat_routes","init_columns_routes","init_data_routes","init_databases_routes","init_query_routes","init_records_routes","init_tables_routes","init_websocket_routes","__dirname","app","upgradeWebSocket","injectWebSocket","c","next","websocketRoutes","databasesRoutes","tablesRoutes","columnsRoutes","dataRoutes","recordsRoutes","queryRoutes","chatRoutes","intro","outro","serve","open","color","program","args","readFile","resolve","cancel","isCancel","note","select","spinner","text","parseDotenv","color","getDatabaseUrl","env","varName","envVarName","s","choice","customPath","value","customEnvPath","content","parsed","e","error","dbUrl","access","readFile","resolve","parseDotenv","loadEnv","env","envPath","content","err","intro","outro","color","showHelp","intro","note","outro","color","init_defaults","showStatus","env","databaseUrl","varName","intro","color","envVarName","DEFAULTS","foundUrl","ENV","loadEnv","outro","note","intro","outro","color","package_default","showVersion","intro","color","outro","package_default","init_defaults","main","env","port","databaseUrl","varName","status","help","version","args","showHelp","showVersion","showStatus","intro","color","PORT","DEFAULTS","VAR_NAME","ENV","loadEnv","DATABASE_URL","getDatabaseUrl","createServer","app","injectWebSocket","server","serve","outro","open","err"]}
|
|
1
|
+
{"version":3,"sources":["../src/utils/defaults.ts","../src/db.ts","../src/db-manager.ts","../src/types/column.types.ts","../src/dao/table-columns.dao.ts","../src/dao/table-details-schema.ts","../src/utils/system-prompt-generator.ts","../src/routes/chat.routes.ts","../src/types/create-table.type.ts","../src/utils/error-handler.ts","../src/routes/columns.routes.ts","../src/dao/tables-data.dao.ts","../src/routes/data.routes.ts","../src/dao/database-list.dao.ts","../src/routes/databases.routes.ts","../src/dao/query.dao.ts","../src/routes/query.routes.ts","../src/dao/delete-records.dao.ts","../src/dao/insert-record.dao.ts","../src/dao/update-records.dao.ts","../src/routes/records.routes.ts","../src/dao/create-table.dao.ts","../src/dao/table-list.dao.ts","../src/routes/tables.routes.ts","../src/routes/websocket.routes.ts","../src/utils/create-server.ts","../src/index.ts","../src/cmd/args.ts","../src/cmd/get-db-url.ts","../src/cmd/load-env.ts","../src/cmd/show-help.ts","../src/cmd/show-status.ts","../src/cmd/show-version.ts","../package.json"],"sourcesContent":["export const DEFAULTS = {\n\tPORT: 3333,\n\tENV: \".env\",\n\tVAR_NAME: \"DATABASE_URL\",\n\tPROXY_URL:\n\t\tprocess.env.NODE_ENV === \"development\"\n\t\t\t? \"http://localhost:8787\"\n\t\t\t: \"https://db-studio-proxy.husamql3.workers.dev\",\n};\n","import { Pool } from \"pg\";\n\nlet dbInstance: Pool | null = null;\n\nconst getPool = (): Pool => {\n\tif (!dbInstance) {\n\t\tif (!process.env.DATABASE_URL) {\n\t\t\tthrow new Error(\n\t\t\t\t\"DATABASE_URL is not set. Please provide a database connection string.\",\n\t\t\t);\n\t\t}\n\t\ttry {\n\t\t\tdbInstance = new Pool({\n\t\t\t\tconnectionString: process.env.DATABASE_URL,\n\t\t\t});\n\n\t\t\t// Handle pool errors to prevent server crashes\n\t\t\t// This catches connection errors, idle client errors, etc.\n\t\t\tdbInstance.on(\"error\", (err) => {\n\t\t\t\tconsole.error(\"Unexpected database pool error:\", err.message);\n\t\t\t\t// Don't throw - just log the error to prevent server crash\n\t\t\t\t// The pool will automatically retry connections\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tconsole.error(\"Failed to create database pool:\", error);\n\t\t\t// Re-throw initialization errors as they indicate a configuration problem\n\t\t\tthrow error;\n\t\t}\n\t}\n\treturn dbInstance;\n};\n\n// Export db as a Proxy that lazily initializes the pool\n// This allows process.env.DATABASE_URL to be set after module import\nexport const db = new Proxy({} as Pool, {\n\tget(_target, prop) {\n\t\ttry {\n\t\t\treturn getPool()[prop as keyof Pool];\n\t\t} catch (error) {\n\t\t\t// If pool initialization fails, log and re-throw\n\t\t\tconsole.error(\"Database pool access error:\", error);\n\t\t\tthrow error;\n\t\t}\n\t},\n});\n","import type { PoolConfig } from \"pg\";\nimport { Pool } from \"pg\";\n\n/**\n * DatabaseManager - Manages multiple database connection pools\n * Allows switching between different databases on the same PostgreSQL server\n */\nclass DatabaseManager {\n\tprivate pools: Map<string, Pool> = new Map();\n\tprivate baseConfig: {\n\t\turl: string;\n\t\thost: string;\n\t\tport: number;\n\t\tuser: string;\n\t\tpassword: string;\n\t} | null = null;\n\n\tconstructor() {\n\t\tthis.initializeBaseConfig();\n\t}\n\n\t/**\n\t * Parse DATABASE_URL and extract connection details\n\t */\n\tprivate initializeBaseConfig() {\n\t\tconst databaseUrl = process.env.DATABASE_URL;\n\t\tif (!databaseUrl) {\n\t\t\tthrow new Error(\n\t\t\t\t\"DATABASE_URL is not set. Please provide a database connection string.\",\n\t\t\t);\n\t\t}\n\n\t\ttry {\n\t\t\tconst url = new URL(databaseUrl);\n\t\t\tthis.baseConfig = {\n\t\t\t\turl: databaseUrl,\n\t\t\t\thost: url.hostname,\n\t\t\t\tport: Number.parseInt(url.port, 10) || 5432,\n\t\t\t\tuser: url.username,\n\t\t\t\tpassword: url.password,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tthrow new Error(`Failed to parse DATABASE_URL: ${error}`);\n\t\t}\n\t}\n\n\t/**\n\t * Build a connection string for the specified database\n\t * @param database - The database name (optional, defaults to database from DATABASE_URL)\n\t * @returns The connection string for the specified database\n\t * @throws Error if database is invalid or unknown\n\t */\n\tbuildConnectionString(database?: string): string {\n\t\tif (!this.baseConfig) {\n\t\t\tthrow new Error(\"Base configuration not initialized\");\n\t\t}\n\n\t\t// If no database specified, extract from original DATABASE_URL\n\t\tif (!database) {\n\t\t\tconst databaseUrl = this.baseConfig.url;\n\t\t\tif (databaseUrl) {\n\t\t\t\tconst url = new URL(databaseUrl);\n\t\t\t\tdatabase = url.pathname.slice(1); // Remove leading slash\n\t\t\t}\n\t\t}\n\n\t\t// if (!database || database.trim() === \"\") {\n\t\t// \tthrow new Error(\"Database name is required and cannot be empty\");\n\t\t// }\n\n\t\t// Validate database name format (PostgreSQL identifiers)\n\t\t// Database names cannot contain special characters that would break URL parsing\n\t\t// if (!/^[a-zA-Z_][a-zA-Z0-9_$]*$/.test(database)) {\n\t\t// \tthrow new Error(\n\t\t// \t\t`Invalid database name: \"${database}\". Database names must start with a letter or underscore and contain only alphanumeric characters, underscores, or dollar signs.`,\n\t\t// \t);\n\t\t// }\n\n\t\ttry {\n\t\t\tconst url = new URL(this.baseConfig.url);\n\t\t\turl.pathname = `/${database}`;\n\t\t\treturn url.toString();\n\t\t} catch (error) {\n\t\t\tthrow new Error(\n\t\t\t\t`Failed to build connection string for database \"${database}\": ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Get or create a connection pool for the specified database\n\t * Pools are cached by connection string to ensure distinct connections per database\n\t */\n\tgetPool(database?: string): Pool {\n\t\t// Build connection string first to validate the database\n\t\tconst connectionString = this.buildConnectionString(database);\n\n\t\t// Use connection string as the cache key\n\t\tif (!this.pools.has(connectionString)) {\n\t\t\tconst poolConfig: PoolConfig = {\n\t\t\t\tconnectionString,\n\t\t\t\tmax: 10, // Maximum number of clients in the pool\n\t\t\t\tidleTimeoutMillis: 30000, // Close idle clients after 30 seconds\n\t\t\t\tconnectionTimeoutMillis: 2000, // Return an error after 2 seconds if connection cannot be established\n\t\t\t};\n\n\t\t\tconst pool = new Pool(poolConfig);\n\n\t\t\t// Handle pool errors\n\t\t\tpool.on(\"error\", (err) => {\n\t\t\t\tconsole.error(\n\t\t\t\t\t`Unexpected error on database pool for \"${connectionString}\":`,\n\t\t\t\t\terr.message,\n\t\t\t\t);\n\t\t\t});\n\n\t\t\tthis.pools.set(connectionString, pool);\n\t\t\tconsole.log(`Created connection pool for: ${connectionString}`);\n\t\t}\n\n\t\treturn this.pools.get(connectionString) ?? new Pool({ connectionString });\n\t}\n\n\t/**\n\t * Close a specific database pool by connection string\n\t */\n\tasync closePool(connectionString: string): Promise<void> {\n\t\tconst pool = this.pools.get(connectionString);\n\t\tif (pool) {\n\t\t\tawait pool.end();\n\t\t\tthis.pools.delete(connectionString);\n\t\t\tconsole.log(`Closed connection pool for: ${connectionString}`);\n\t\t}\n\t}\n\n\t/**\n\t * Close a specific database pool by database name\n\t */\n\tasync closePoolByDatabase(database: string): Promise<void> {\n\t\tconst connectionString = this.buildConnectionString(database);\n\t\tawait this.closePool(connectionString);\n\t}\n\n\t/**\n\t * Close all database pools\n\t */\n\tasync closeAll(): Promise<void> {\n\t\tconst closePromises = Array.from(this.pools.entries()).map(\n\t\t\tasync ([connectionString, pool]) => {\n\t\t\t\tawait pool.end();\n\t\t\t\tconsole.log(`Closed connection pool for: ${connectionString}`);\n\t\t\t},\n\t\t);\n\t\tawait Promise.all(closePromises);\n\t\tthis.pools.clear();\n\t}\n\n\t/**\n\t * Get all active pool connection strings\n\t */\n\tgetActivePools(): string[] {\n\t\treturn Array.from(this.pools.keys());\n\t}\n}\n\n// Singleton instance\nconst databaseManager = new DatabaseManager();\n\n/**\n * Get a database pool for the specified database\n * If no database is specified, returns the default database pool\n */\nexport const getDbPool = (database?: string): Pool => {\n\treturn databaseManager.getPool(database);\n};\n\n/**\n * Build a connection string for the specified database\n */\nexport const buildDbConnectionString = (database?: string): string => {\n\treturn databaseManager.buildConnectionString(database);\n};\n\n/**\n * Close a specific database pool by database name\n */\nexport const closeDbPool = async (database: string): Promise<void> => {\n\treturn databaseManager.closePoolByDatabase(database);\n};\n\n/**\n * Close a specific database pool by connection string\n */\nexport const closeDbPoolByConnectionString = async (\n\tconnectionString: string,\n): Promise<void> => {\n\treturn databaseManager.closePool(connectionString);\n};\n\n/**\n * Close all database pools\n */\nexport const closeAllDbPools = async (): Promise<void> => {\n\treturn databaseManager.closeAll();\n};\n\n/**\n * Get list of active pool connection strings\n */\nexport const getActivePools = (): string[] => {\n\treturn databaseManager.getActivePools();\n};\n\nexport default databaseManager;\n","export const DataTypes = {\n\ttext: \"text\",\n\tboolean: \"boolean\",\n\tnumber: \"number\",\n\tenum: \"enum\",\n\tjson: \"json\",\n\tdate: \"date\",\n\tarray: \"array\",\n} as const;\n\nexport type DataTypes = (typeof DataTypes)[keyof typeof DataTypes];\n\n/**\n * Maps PostgreSQL data types to generic DataType enum\n */\nexport function mapPostgresToDataType(pgType: string): DataTypes {\n\tconst normalized = pgType.toLowerCase().trim();\n\n\t// Handle array types and date/time types\n\tif (\n\t\tnormalized.includes(\"[]\") ||\n\t\tnormalized === \"date\" ||\n\t\tnormalized === \"time\" ||\n\t\tnormalized === \"time without time zone\" ||\n\t\tnormalized.startsWith(\"time(\") ||\n\t\tnormalized === \"timestamp\" ||\n\t\tnormalized === \"timestamp without time zone\" ||\n\t\tnormalized.startsWith(\"timestamp(\") ||\n\t\tnormalized === \"timestamp with time zone\" ||\n\t\tnormalized === \"timestamptz\" ||\n\t\tnormalized.startsWith(\"timestamp with time zone(\")\n\t) {\n\t\treturn DataTypes.date;\n\t}\n\n\t// Numeric types\n\tif (\n\t\tnormalized === \"integer\" ||\n\t\tnormalized === \"int\" ||\n\t\tnormalized === \"int4\" ||\n\t\tnormalized === \"bigint\" ||\n\t\tnormalized === \"int8\" ||\n\t\tnormalized === \"smallint\" ||\n\t\tnormalized === \"int2\" ||\n\t\tnormalized === \"decimal\" ||\n\t\tnormalized.startsWith(\"decimal(\") ||\n\t\tnormalized === \"numeric\" ||\n\t\tnormalized.startsWith(\"numeric(\") ||\n\t\tnormalized === \"real\" ||\n\t\tnormalized === \"float4\" ||\n\t\tnormalized === \"double precision\" ||\n\t\tnormalized === \"float8\" ||\n\t\tnormalized === \"float\" ||\n\t\tnormalized === \"serial\" ||\n\t\tnormalized === \"serial4\" ||\n\t\tnormalized === \"bigserial\" ||\n\t\tnormalized === \"serial8\" ||\n\t\tnormalized === \"money\"\n\t) {\n\t\treturn DataTypes.number;\n\t}\n\n\t// Boolean\n\tif (normalized === \"boolean\" || normalized === \"bool\") {\n\t\treturn DataTypes.boolean;\n\t}\n\n\t// JSON types\n\tif (normalized === \"json\" || normalized === \"jsonb\") {\n\t\treturn DataTypes.json;\n\t}\n\n\t// Enum types and long text types\n\tif (\n\t\tnormalized.startsWith(\"user-defined\") ||\n\t\tnormalized === \"enum\" ||\n\t\tnormalized === \"text\" ||\n\t\tnormalized === \"xml\"\n\t) {\n\t\treturn DataTypes.text;\n\t}\n\n\t// Short string types (varchar, char, uuid, etc.)\n\tif (\n\t\tnormalized === \"character varying\" ||\n\t\tnormalized.startsWith(\"varchar\") ||\n\t\tnormalized.startsWith(\"character varying(\") ||\n\t\tnormalized === \"character\" ||\n\t\tnormalized.startsWith(\"char\") ||\n\t\tnormalized.startsWith(\"character(\") ||\n\t\tnormalized === \"bpchar\" ||\n\t\tnormalized === \"uuid\" ||\n\t\tnormalized === \"interval\" ||\n\t\tnormalized.startsWith(\"interval\") ||\n\t\tnormalized === \"bytea\" ||\n\t\tnormalized === \"point\" ||\n\t\tnormalized === \"line\" ||\n\t\tnormalized === \"polygon\" ||\n\t\tnormalized === \"inet\" ||\n\t\tnormalized === \"cidr\" ||\n\t\tnormalized === \"macaddr\" ||\n\t\tnormalized === \"macaddr8\"\n\t) {\n\t\treturn DataTypes.text;\n\t}\n\n\t// Default to short for unrecognized types\n\treturn DataTypes.text;\n}\n\n/**\n * Standardized data type labels\n */\nexport const StandardizedDataType = {\n\t// Numeric types\n\tint: \"int\",\n\tbigint: \"bigint\",\n\tsmallint: \"smallint\",\n\tnumeric: \"numeric\",\n\tfloat: \"float\",\n\tdouble: \"double\",\n\tmoney: \"money\",\n\t// Boolean\n\tboolean: \"boolean\",\n\t// Text types\n\ttext: \"text\",\n\tvarchar: \"varchar\",\n\tchar: \"char\",\n\t// JSON types\n\tjson: \"json\",\n\tjsonb: \"jsonb\",\n\txml: \"xml\",\n\t// UUID\n\tuuid: \"uuid\",\n\t// Date/Time types\n\tdate: \"date\",\n\ttime: \"time\",\n\ttimestamp: \"timestamp\",\n\ttimestamptz: \"timestamptz\",\n\tinterval: \"interval\",\n\t// Binary\n\tbytea: \"bytea\",\n\t// Network types\n\tinet: \"inet\",\n\tcidr: \"cidr\",\n\tmacaddr: \"macaddr\",\n\tmacaddr8: \"macaddr8\",\n\t// Geometric types\n\tpoint: \"point\",\n\tline: \"line\",\n\tpolygon: \"polygon\",\n\t// Complex types\n\tarray: \"array\",\n\tenum: \"enum\",\n} as const;\n\nexport type StandardizedDataType =\n\t(typeof StandardizedDataType)[keyof typeof StandardizedDataType];\n\n/**\n * Maps PostgreSQL data types to standardized display labels\n */\nexport function standardizeDataTypeLabel(pgType: string): StandardizedDataType {\n\tconst normalized = pgType.toLowerCase().trim();\n\n\t// Numeric types\n\tif (\n\t\tnormalized === \"integer\" ||\n\t\tnormalized === \"int\" ||\n\t\tnormalized === \"int4\" ||\n\t\tnormalized === \"serial\" ||\n\t\tnormalized === \"serial4\"\n\t) {\n\t\treturn StandardizedDataType.int;\n\t}\n\n\tif (\n\t\tnormalized === \"bigint\" ||\n\t\tnormalized === \"int8\" ||\n\t\tnormalized === \"bigserial\" ||\n\t\tnormalized === \"serial8\"\n\t) {\n\t\treturn StandardizedDataType.bigint;\n\t}\n\n\tif (normalized === \"smallint\" || normalized === \"int2\") {\n\t\treturn StandardizedDataType.smallint;\n\t}\n\n\tif (\n\t\tnormalized === \"decimal\" ||\n\t\tnormalized.startsWith(\"decimal(\") ||\n\t\tnormalized === \"numeric\" ||\n\t\tnormalized.startsWith(\"numeric(\")\n\t) {\n\t\treturn StandardizedDataType.numeric;\n\t}\n\n\tif (normalized === \"real\" || normalized === \"float4\") {\n\t\treturn StandardizedDataType.float;\n\t}\n\n\tif (\n\t\tnormalized === \"double precision\" ||\n\t\tnormalized === \"float8\" ||\n\t\tnormalized === \"float\"\n\t) {\n\t\treturn StandardizedDataType.double;\n\t}\n\n\tif (normalized === \"money\") {\n\t\treturn StandardizedDataType.money;\n\t}\n\n\t// Boolean\n\tif (normalized === \"boolean\" || normalized === \"bool\") {\n\t\treturn StandardizedDataType.boolean;\n\t}\n\n\t// Text types\n\tif (normalized === \"text\") {\n\t\treturn StandardizedDataType.text;\n\t}\n\n\tif (\n\t\tnormalized === \"character varying\" ||\n\t\tnormalized.startsWith(\"varchar\") ||\n\t\tnormalized.startsWith(\"character varying(\")\n\t) {\n\t\treturn StandardizedDataType.varchar;\n\t}\n\n\tif (\n\t\tnormalized === \"character\" ||\n\t\tnormalized.startsWith(\"char\") ||\n\t\tnormalized.startsWith(\"character(\") ||\n\t\tnormalized === \"bpchar\"\n\t) {\n\t\treturn StandardizedDataType.char;\n\t}\n\n\t// JSON types\n\tif (normalized === \"json\") {\n\t\treturn StandardizedDataType.json;\n\t}\n\n\tif (normalized === \"jsonb\") {\n\t\treturn StandardizedDataType.jsonb;\n\t}\n\n\tif (normalized === \"xml\") {\n\t\treturn StandardizedDataType.xml;\n\t}\n\n\t// UUID\n\tif (normalized === \"uuid\") {\n\t\treturn StandardizedDataType.uuid;\n\t}\n\n\t// Date/Time types\n\tif (normalized === \"date\") {\n\t\treturn StandardizedDataType.date;\n\t}\n\n\tif (\n\t\tnormalized === \"time\" ||\n\t\tnormalized === \"time without time zone\" ||\n\t\tnormalized.startsWith(\"time(\")\n\t) {\n\t\treturn StandardizedDataType.time;\n\t}\n\n\tif (\n\t\tnormalized === \"timestamp\" ||\n\t\tnormalized === \"timestamp without time zone\" ||\n\t\tnormalized.startsWith(\"timestamp(\")\n\t) {\n\t\treturn StandardizedDataType.timestamp;\n\t}\n\n\tif (\n\t\tnormalized === \"timestamp with time zone\" ||\n\t\tnormalized === \"timestamptz\" ||\n\t\tnormalized.startsWith(\"timestamp with time zone(\")\n\t) {\n\t\treturn StandardizedDataType.timestamptz;\n\t}\n\n\tif (normalized === \"interval\" || normalized.startsWith(\"interval\")) {\n\t\treturn StandardizedDataType.interval;\n\t}\n\n\t// Binary\n\tif (normalized === \"bytea\") {\n\t\treturn StandardizedDataType.bytea;\n\t}\n\n\t// Network types\n\tif (normalized === \"inet\") {\n\t\treturn StandardizedDataType.inet;\n\t}\n\n\tif (normalized === \"cidr\") {\n\t\treturn StandardizedDataType.cidr;\n\t}\n\n\tif (normalized === \"macaddr\") {\n\t\treturn StandardizedDataType.macaddr;\n\t}\n\n\tif (normalized === \"macaddr8\") {\n\t\treturn StandardizedDataType.macaddr8;\n\t}\n\n\t// Geometric types\n\tif (normalized === \"point\") {\n\t\treturn StandardizedDataType.point;\n\t}\n\n\tif (normalized === \"line\") {\n\t\treturn StandardizedDataType.line;\n\t}\n\n\tif (normalized === \"polygon\") {\n\t\treturn StandardizedDataType.polygon;\n\t}\n\n\t// Array types\n\t// todo: handle array types\n\tif (normalized.startsWith(\"array\") || normalized.includes(\"[]\")) {\n\t\treturn StandardizedDataType.text;\n\t}\n\n\t// User-defined types (enums)\n\tif (normalized.startsWith(\"user-defined\") || normalized === \"enum\") {\n\t\treturn StandardizedDataType.enum;\n\t}\n\n\t// Default: return the original type\n\treturn StandardizedDataType.text;\n}\n","import { getDbPool } from \"@/db-manager.js\";\nimport {\n\ttype DataTypes,\n\tmapPostgresToDataType,\n\ttype StandardizedDataType,\n\tstandardizeDataTypeLabel,\n} from \"../types/column.types.js\";\n\nexport interface ColumnInfo {\n\tcolumnName: string; // The column name from the database\n\tdataType: DataTypes; // Generic type mapped to cell variant (text/boolean/number/enum/json/date)\n\tdataTypeLabel: StandardizedDataType; // Exact database type (int/varchar/timestamp/etc.)\n\tisNullable: boolean;\n\tcolumnDefault: string | null;\n\tisPrimaryKey: boolean;\n\tisForeignKey: boolean;\n\treferencedTable: string | null;\n\treferencedColumn: string | null;\n\tenumValues: string[] | null;\n}\n\nexport const getTableColumns = async (\n\ttableName: string,\n\tdatabase?: string,\n): Promise<ColumnInfo[]> => {\n\tconst pool = getDbPool(database);\n\tconst client = await pool.connect();\n\n\ttry {\n\t\tconst res = await client.query(\n\t\t\t`\n SELECT \n c.column_name as \"columnName\",\n c.data_type as \"dataType\",\n c.udt_name as \"udtName\",\n c.is_nullable = 'YES' as \"isNullable\",\n c.column_default as \"columnDefault\",\n CASE WHEN pk.column_name IS NOT NULL THEN true ELSE false END as \"isPrimaryKey\",\n CASE WHEN fk.column_name IS NOT NULL THEN true ELSE false END as \"isForeignKey\",\n fk.referenced_table as \"referencedTable\",\n fk.referenced_column as \"referencedColumn\",\n CASE \n WHEN c.data_type = 'USER-DEFINED' THEN \n (SELECT array_agg(e.enumlabel ORDER BY e.enumsortorder)\n FROM pg_type t\n JOIN pg_enum e ON t.oid = e.enumtypid\n WHERE t.typname = c.udt_name)\n ELSE NULL\n END as \"enumValues\"\n FROM information_schema.columns c\n LEFT JOIN (\n SELECT ku.column_name\n FROM information_schema.table_constraints tc\n JOIN information_schema.key_column_usage ku\n ON tc.constraint_name = ku.constraint_name\n AND tc.table_schema = ku.table_schema\n WHERE tc.constraint_type = 'PRIMARY KEY'\n AND tc.table_schema = 'public'\n AND tc.table_name = $1\n ) pk ON c.column_name = pk.column_name\n LEFT JOIN (\n SELECT \n kcu.column_name,\n ccu.table_name AS referenced_table,\n ccu.column_name AS referenced_column\n FROM information_schema.table_constraints tc\n JOIN information_schema.key_column_usage kcu\n ON tc.constraint_name = kcu.constraint_name\n AND tc.table_schema = kcu.table_schema\n JOIN information_schema.constraint_column_usage ccu\n ON tc.constraint_name = ccu.constraint_name\n AND tc.table_schema = ccu.table_schema\n WHERE tc.constraint_type = 'FOREIGN KEY'\n AND tc.table_schema = 'public'\n AND tc.table_name = $1\n ) fk ON c.column_name = fk.column_name\n WHERE c.table_schema = 'public'\n AND c.table_name = $1\n ORDER BY c.ordinal_position;\n `,\n\t\t\t[tableName],\n\t\t);\n\n\t\treturn res.rows.map((r: any) => {\n\t\t\t// Parse enumValues to always return string[] | null\n\t\t\tlet parsedEnumValues: string[] | null = null;\n\t\t\tif (r.enumValues) {\n\t\t\t\tif (Array.isArray(r.enumValues)) {\n\t\t\t\t\t// Already an array, use as-is\n\t\t\t\t\tparsedEnumValues = r.enumValues;\n\t\t\t\t} else if (typeof r.enumValues === \"string\") {\n\t\t\t\t\t// Parse PostgreSQL array format: \"{VALUE1,VALUE2,VALUE3}\"\n\t\t\t\t\tparsedEnumValues = r.enumValues.replace(/[{}]/g, \"\").split(\",\").filter(Boolean);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tcolumnName: r.columnName,\n\t\t\t\tdataType: mapPostgresToDataType(r.dataType),\n\t\t\t\tdataTypeLabel: standardizeDataTypeLabel(r.dataType),\n\t\t\t\tisNullable: r.isNullable,\n\t\t\t\tcolumnDefault: r.columnDefault,\n\t\t\t\tisPrimaryKey: r.isPrimaryKey,\n\t\t\t\tisForeignKey: r.isForeignKey,\n\t\t\t\treferencedTable: r.referencedTable,\n\t\t\t\treferencedColumn: r.referencedColumn,\n\t\t\t\tenumValues: parsedEnumValues,\n\t\t\t};\n\t\t});\n\t} finally {\n\t\tclient.release();\n\t}\n};\n","import { db } from \"@/db.js\";\nimport { type ColumnInfo, getTableColumns } from \"./table-columns.dao.js\";\n\nexport interface DatabaseSchema {\n\tdbType: string;\n\ttables: Table[];\n\trelationships: Relationship[];\n}\n\ninterface Table {\n\tname: string;\n\tdescription?: string;\n\tcolumns: Column[];\n\tsampleData?: Record<string, string>[];\n}\n\ninterface Column {\n\tname: string;\n\ttype: string;\n\tnullable: boolean;\n\tisPrimaryKey?: boolean;\n\tforeignKey?: string;\n\tdescription?: string;\n\tenumValues?: string[];\n}\n\ninterface Relationship {\n\tfromTable: string;\n\tfromColumn: string;\n\ttoTable: string;\n\ttoColumn: string;\n}\n\n/**\n * Get all table names from the database\n */\nasync function getTableNames(): Promise<string[]> {\n\tconst client = await db.connect();\n\ttry {\n\t\tconst res = await client.query(\n\t\t\t`\n SELECT table_name\n FROM information_schema.tables\n WHERE table_schema = 'public'\n AND table_type = 'BASE TABLE'\n ORDER BY table_name;\n `,\n\t\t);\n\t\treturn res.rows.map((r) => r.table_name);\n\t} finally {\n\t\tclient.release();\n\t}\n}\n\n/**\n * Get table comment/description if available\n */\nasync function getTableDescription(tableName: string): Promise<string | undefined> {\n\tconst client = await db.connect();\n\ttry {\n\t\tconst res = await client.query(\n\t\t\t`\n SELECT obj_description(oid) as description\n FROM pg_class\n WHERE relname = $1\n AND relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'public');\n `,\n\t\t\t[tableName],\n\t\t);\n\t\treturn res.rows[0]?.description || undefined;\n\t} finally {\n\t\tclient.release();\n\t}\n}\n\n/**\n * Get sample data from a table (first 3 rows)\n */\nasync function getSampleData(tableName: string): Promise<Record<string, any>[]> {\n\tconst client = await db.connect();\n\ttry {\n\t\t// Sanitize table name to prevent SQL injection\n\t\t// In production, validate tableName against known tables list\n\t\tconst res = await client.query(`SELECT * FROM \"${tableName}\" LIMIT 3`);\n\t\treturn res.rows;\n\t} catch (error) {\n\t\tconsole.warn(`Could not fetch sample data for table ${tableName}:`, error);\n\t\treturn [];\n\t} finally {\n\t\tclient.release();\n\t}\n}\n\n/**\n * Convert ColumnInfo to the schema Column format\n */\nfunction convertColumnInfo(col: ColumnInfo): Column {\n\tconst column: Column = {\n\t\tname: col.columnName,\n\t\ttype: col.dataTypeLabel,\n\t\tnullable: col.isNullable,\n\t};\n\n\tif (col.isPrimaryKey) {\n\t\tcolumn.isPrimaryKey = true;\n\t}\n\n\tif (col.isForeignKey && col.referencedTable && col.referencedColumn) {\n\t\tcolumn.foreignKey = `${col.referencedTable}.${col.referencedColumn}`;\n\t}\n\n\tif (col.enumValues && col.enumValues.length > 0) {\n\t\tcolumn.enumValues = col.enumValues;\n\t\tcolumn.description = `Enum values: ${col.enumValues.join(\", \")}`;\n\t}\n\n\treturn column;\n}\n\n/**\n * Extract all relationships from table columns\n */\nfunction extractRelationships(tables: Table[]): Relationship[] {\n\tconst relationships: Relationship[] = [];\n\n\tfor (const table of tables) {\n\t\tfor (const column of table.columns) {\n\t\t\tif (column.foreignKey) {\n\t\t\t\tconst [toTable, toColumn] = column.foreignKey.split(\".\");\n\t\t\t\trelationships.push({\n\t\t\t\t\tfromTable: table.name,\n\t\t\t\t\tfromColumn: column.name,\n\t\t\t\t\ttoTable,\n\t\t\t\t\ttoColumn,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\treturn relationships;\n}\n\n/**\n * Get complete database schema with all tables, columns, and relationships\n */\nexport async function getDatabaseSchema(\n\t// connectionId: string,\n\toptions: {\n\t\tincludeSampleData?: boolean;\n\t\tincludeDescriptions?: boolean;\n\t\tmaxTables?: number;\n\t} = {},\n): Promise<DatabaseSchema> {\n\tconst {\n\t\tincludeSampleData = false,\n\t\tincludeDescriptions = true,\n\t\t// maxTables = 50, // Prevent overwhelming the context\n\t} = options;\n\n\ttry {\n\t\t// Get all table names\n\t\tconst tableNames = await getTableNames();\n\n\t\t// Limit tables if needed to prevent token overflow\n\t\t// const limitedTableNames = tableNames.slice(0, maxTables);\n\n\t\t// if (tableNames.length > maxTables) {\n\t\t// console.warn(\n\t\t// `Database has ${tableNames.length} tables, only including first ${maxTables} in schema context`\n\t\t// );\n\t\t// }\n\n\t\t// Fetch schema info for each table in parallel\n\t\t// const tablePromises = limitedTableNames.map(async (tableName) => {\n\t\tconst tablePromises = tableNames.map(async (tableName) => {\n\t\t\tconst [columns, description, sampleData] = await Promise.all([\n\t\t\t\tgetTableColumns(tableName),\n\t\t\t\tincludeDescriptions ? getTableDescription(tableName) : Promise.resolve(undefined),\n\t\t\t\tincludeSampleData ? getSampleData(tableName) : Promise.resolve([]),\n\t\t\t]);\n\n\t\t\tconst table: Table = {\n\t\t\t\tname: tableName,\n\t\t\t\tcolumns: columns.map(convertColumnInfo),\n\t\t\t};\n\n\t\t\tif (description) {\n\t\t\t\ttable.description = description;\n\t\t\t}\n\n\t\t\tif (sampleData.length > 0) {\n\t\t\t\ttable.sampleData = sampleData;\n\t\t\t}\n\n\t\t\treturn table;\n\t\t});\n\n\t\tconst tables = await Promise.all(tablePromises);\n\n\t\t// Extract relationships from foreign keys\n\t\tconst relationships = extractRelationships(tables);\n\n\t\treturn {\n\t\t\tdbType: \"PostgreSQL\",\n\t\t\ttables,\n\t\t\trelationships,\n\t\t};\n\t} catch (error) {\n\t\tconsole.error(\"Error fetching database schema:\", error);\n\t\tthrow new Error(\n\t\t\t`Failed to fetch database schema: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n\t\t);\n\t}\n}\n\n/**\n * Get lightweight schema (no sample data, useful for token efficiency)\n */\nexport async function getLightweightSchema(): Promise<DatabaseSchema> {\n\treturn getDatabaseSchema({\n\t\tincludeSampleData: false,\n\t\tincludeDescriptions: false,\n\t});\n}\n\n/**\n * Get detailed schema with sample data (for initial conversation context)\n */\nexport async function getDetailedSchema(): Promise<DatabaseSchema> {\n\treturn getDatabaseSchema({\n\t\tincludeSampleData: true,\n\t\tincludeDescriptions: true,\n\t\t// maxTables: 30, // todo: DELETE THIS AFTER TESTING\n\t});\n}\n","import type { DatabaseSchema } from \"@/dao/table-details-schema.js\";\n\n/**\n * Generate system prompt with database context\n */\nexport function generateSystemPrompt(schema: DatabaseSchema): string {\n\treturn `You are a database assistant for db-studio. Your responses must be CONCISE and FOCUSED.\n\n**Your Role:**\n1. Keep responses SHORT - 2-3 sentences maximum unless generating SQL\n2. When generating SQL:\n - Provide 1 sentence explanation\n - The SQL query in a code block\n - 1 sentence about expected results\n - NO verbose explanations\n3. Use exact table/column names from the schema\n4. Generate valid ${schema.dbType} syntax\n5. If query is unclear, ask ONE specific clarifying question\n6. No preamble, no apologies, get straight to the answer\n\n**Database Context:**\n${formatSchemaForPrompt(schema)}\n\n**Guidelines:**\n1. Always generate syntactically correct SQL for the database type (${schema.dbType})\n2. Use proper table/column names exactly as defined in the schema\n3. When generating queries, wrap them in \\`\\`\\`sql code blocks\n4. Explain what the query does in plain language\n5. Suggest relevant follow-up questions or analyses\n6. If a request is ambiguous, ask clarifying questions\n7. For complex queries, break down the logic step-by-step\n8. Warn about potentially expensive operations (full table scans, etc.)\n9. Consider data privacy - remind users not to share sensitive data externally\n\n**Response Format:**\nWhen generating queries, use this structure:\n- Brief explanation of what you'll do\n- The SQL query in a code block\n- Expected results description\n- Optional: suggestions for related queries\n\n**Example:**\nUser: \"Show me the top 5 customers by revenue\"\n\nResponse: \"I'll query the orders and customers tables to find your highest-value customers.\n\n\\`\\`\\`sql\nSELECT \n c.customer_name,\n SUM(o.total_amount) as total_revenue\nFROM customers c\nJOIN orders o ON c.id = o.customer_id\nGROUP BY c.id, c.customer_name\nORDER BY total_revenue DESC\nLIMIT 5;\n\\`\\`\\`\n\nThis will return the 5 customers with the highest total order value. You might also want to see:\n- Revenue trends over time for these customers\n- Their most frequently ordered products\"`;\n}\n\n/**\n * Format schema information for the prompt\n */\nexport function formatSchemaForPrompt(schema: DatabaseSchema): string {\n\tlet output = `Database Type: ${schema.dbType}\\n\\n`;\n\n\toutput += \"**Tables and Columns:**\\n\";\n\tfor (const table of schema.tables) {\n\t\toutput += `\\n### ${table.name}\\n`;\n\t\tif (table.description) {\n\t\t\toutput += `Description: ${table.description}\\n`;\n\t\t}\n\t\toutput += \"Columns:\\n\";\n\n\t\tfor (const col of table.columns) {\n\t\t\tconst pkIndicator = col.isPrimaryKey ? \" [PRIMARY KEY]\" : \"\";\n\t\t\tconst fkIndicator = col.foreignKey ? ` [FK -> ${col.foreignKey}]` : \"\";\n\t\t\tconst nullable = col.nullable ? \"NULL\" : \"NOT NULL\";\n\n\t\t\toutput += ` - ${col.name}: ${col.type} ${nullable}${pkIndicator}${fkIndicator}\\n`;\n\t\t\tif (col.description) {\n\t\t\t\toutput += ` ${col.description}\\n`;\n\t\t\t}\n\t\t}\n\n\t\t// Add sample data if available\n\t\tif (table.sampleData && table.sampleData.length > 0) {\n\t\t\toutput += `Sample data (${table.sampleData.length} rows):\\n`;\n\t\t\toutput += `${JSON.stringify(table.sampleData.slice(0, 3), null, 2)}\\n`;\n\t\t}\n\t}\n\n\t// Add relationships\n\tif (schema.relationships && schema.relationships.length > 0) {\n\t\toutput += \"\\n**Relationships:**\\n\";\n\t\tfor (const rel of schema.relationships) {\n\t\t\toutput += ` - ${rel.fromTable}.${rel.fromColumn} -> ${rel.toTable}.${rel.toColumn}\\n`;\n\t\t}\n\t}\n\n\treturn output;\n}\n","import { Hono } from \"hono\";\nimport { getDetailedSchema } from \"@/dao/table-details-schema.js\";\nimport { DEFAULTS } from \"@/utils/defaults.js\";\nimport { generateSystemPrompt } from \"@/utils/system-prompt-generator.js\";\n\nexport const chatRoutes = new Hono();\n\n/**\n * POST /chat - Handle AI chat requests with streaming\n * Proxies to the Cloudflare Worker which has the Gemini API key\n */\nchatRoutes.post(\"/\", async (c) => {\n\ttry {\n\t\tconst { messages, conversationId } = await c.req.json();\n\t\tconsole.log(\"POST /chat messages\", messages);\n\n\t\t// Get the database schema and generate system prompt\n\t\tconst schema = await getDetailedSchema();\n\t\tconst systemPrompt = generateSystemPrompt(schema);\n\n\t\tconst payload = {\n\t\t\tmessages,\n\t\t\tconversationId,\n\t\t\tsystemPrompt,\n\t\t};\n\n\t\t// Forward request to the proxy with the system prompt\n\t\tconst proxyResponse = await fetch(`${DEFAULTS.PROXY_URL}/chat`, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t},\n\t\t\tbody: JSON.stringify(payload),\n\t\t});\n\n\t\tif (!proxyResponse.ok) {\n\t\t\tconst errorData = await proxyResponse.json();\n\t\t\treturn c.json(\n\t\t\t\t{ error: errorData.error || \"Proxy request failed\" },\n\t\t\t\tproxyResponse.status as 400 | 500,\n\t\t\t);\n\t\t}\n\n\t\t// Stream the SSE response back to the client\n\t\tconst { readable, writable } = new TransformStream();\n\t\tproxyResponse.body?.pipeTo(writable);\n\n\t\treturn new Response(readable, {\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"text/event-stream\",\n\t\t\t\t\"Cache-Control\": \"no-cache\",\n\t\t\t\tConnection: \"keep-alive\",\n\t\t\t},\n\t\t});\n\t} catch (error) {\n\t\tconsole.error(\"POST /chat error:\", error);\n\t\tconst errorMessage = error instanceof Error ? error.message : \"An error occurred\";\n\t\treturn c.json(\n\t\t\t{\n\t\t\t\terror: errorMessage,\n\t\t\t},\n\t\t\t500,\n\t\t);\n\t}\n});\n","import { z } from \"zod\";\n\nexport const FOREIGN_KEY_ACTIONS = [\n\t\"CASCADE\",\n\t\"SET NULL\",\n\t\"SET DEFAULT\",\n\t\"RESTRICT\",\n\t\"NO ACTION\",\n] as const;\nexport const foreignKeyActionSchema = z.enum(FOREIGN_KEY_ACTIONS);\nexport type ForeignKeyAction = z.infer<typeof foreignKeyActionSchema>;\n\nexport const fieldDataSchema = z.object({\n\tcolumnName: z.string().min(1),\n\tcolumnType: z.string().min(1),\n\tdefaultValue: z.string(),\n\tisPrimaryKey: z.boolean(),\n\tisNullable: z.boolean(),\n\tisUnique: z.boolean(),\n\tisIdentity: z.boolean(),\n\tisArray: z.boolean(),\n});\nexport type FieldDataType = z.infer<typeof fieldDataSchema>;\n\nexport const foreignKeyDataSchema = z.object({\n\tcolumnName: z.string().min(1),\n\treferencedTable: z.string().min(1),\n\treferencedColumn: z.string().min(1),\n\tonUpdate: foreignKeyActionSchema,\n\tonDelete: foreignKeyActionSchema,\n});\nexport type ForeignKeyDataType = z.infer<typeof foreignKeyDataSchema>;\n\nexport const createTableSchema = z.object({\n\ttableName: z.string().min(1, \"Table name is required\"),\n\tfields: z.array(fieldDataSchema).min(1, \"At least one field is required\"),\n\tforeignKeys: z.array(foreignKeyDataSchema).optional(),\n});\nexport type CreateTableFormData = z.infer<typeof createTableSchema>;\n\nexport const tableNameParamSchema = z.object({\n\ttableName: z.string().min(1, \"Table name is required\"),\n});\n\nexport const tableDataQuerySchema = z.object({\n\tpage: z.string().optional().default(\"1\").transform(Number),\n\tpageSize: z.string().optional().default(\"50\").transform(Number),\n\tsort: z.string().optional().default(\"\"),\n\torder: z.enum([\"asc\", \"desc\"]).optional(),\n\tfilters: z\n\t\t.string()\n\t\t.optional()\n\t\t.transform((val) => {\n\t\t\tif (!val) return [];\n\t\t\ttry {\n\t\t\t\treturn JSON.parse(val);\n\t\t\t} catch {\n\t\t\t\treturn [];\n\t\t\t}\n\t\t}),\n});\n\nexport const insertRecordSchema = z.object({\n\ttableName: z.string().min(1, \"Table name is required\"),\n\tdata: z.record(z.string(), z.any()),\n});\n\nexport const updateRecordsSchema = z.object({\n\ttableName: z.string().min(1, \"Table name is required\"),\n\tupdates: z\n\t\t.array(\n\t\t\tz.object({\n\t\t\t\trowData: z.any(),\n\t\t\t\tcolumnName: z.string().min(1),\n\t\t\t\tvalue: z.any(),\n\t\t\t}),\n\t\t)\n\t\t.min(1, \"At least one update is required\"),\n\tprimaryKey: z.string().optional(),\n});\n\nexport const deleteRecordsSchema = z.object({\n\ttableName: z.string().min(1, \"Table name is required\"),\n\tprimaryKeys: z\n\t\t.array(\n\t\t\tz.object({\n\t\t\t\tcolumnName: z.string().min(1),\n\t\t\t\tvalue: z.any(),\n\t\t\t}),\n\t\t)\n\t\t.min(1, \"At least one primary key is required\"),\n});\n\nexport const executeQuerySchema = z.object({\n\tquery: z.string().min(1, \"Query is required\"),\n});\n\nexport const databaseQuerySchema = z.object({\n\tdatabase: z.string().optional(),\n});\n","import type { Context } from \"hono\";\n\nexport const handleConnectionError = (\n\tc: Context,\n\terror: unknown,\n\tfallbackMessage: string,\n) => {\n\tconst errorMessage = error instanceof Error ? error.message : fallbackMessage;\n\n\tlet isConnectionError = false;\n\tif (error && typeof error === \"object\" && \"code\" in error) {\n\t\tisConnectionError = (error as { code?: string }).code === \"ECONNREFUSED\";\n\t} else if (\n\t\terror &&\n\t\ttypeof error === \"object\" &&\n\t\t\"errors\" in error &&\n\t\tArray.isArray((error as { errors?: unknown[] }).errors)\n\t) {\n\t\tconst aggregateError = error as { errors?: Array<{ code?: string }> };\n\t\tisConnectionError =\n\t\t\taggregateError.errors?.some((err) => err.code === \"ECONNREFUSED\") ?? false;\n\t}\n\n\tif (isConnectionError) {\n\t\treturn c.json(\n\t\t\t{\n\t\t\t\tsuccess: false,\n\t\t\t\tmessage:\n\t\t\t\t\t\"Cannot connect to database. Please check your DATABASE_URL and ensure the database server is running.\",\n\t\t\t\terror: errorMessage,\n\t\t\t},\n\t\t\t503,\n\t\t);\n\t}\n\n\treturn c.json(\n\t\t{\n\t\t\tsuccess: false,\n\t\t\tmessage: errorMessage,\n\t\t},\n\t\t500,\n\t);\n};\n","import { zValidator } from \"@hono/zod-validator\";\nimport { Hono } from \"hono\";\nimport { getTableColumns } from \"@/dao/table-columns.dao.js\";\nimport { databaseQuerySchema, tableNameParamSchema } from \"@/types/create-table.type.js\";\nimport { handleConnectionError } from \"@/utils/error-handler.js\";\n\nexport const columnsRoutes = new Hono();\n\n/**\n * GET /tables/:tableName/columns - Get all columns for a table\n */\ncolumnsRoutes.get(\n\t\"/\",\n\tzValidator(\"param\", tableNameParamSchema),\n\tzValidator(\"query\", databaseQuerySchema),\n\tasync (c) => {\n\t\ttry {\n\t\t\tconst { tableName } = c.req.valid(\"param\");\n\t\t\tconst { database } = c.req.valid(\"query\");\n\n\t\t\tconst columns = await getTableColumns(tableName, database);\n\t\t\tconsole.log(\"GET /tables/:tableName/columns\", columns);\n\t\t\treturn c.json(columns);\n\t\t} catch (error) {\n\t\t\tconsole.error(\"GET /tables/:tableName/columns error:\", error);\n\t\t\treturn handleConnectionError(c, error, \"Failed to fetch columns\");\n\t\t}\n\t},\n);\n","import { getDbPool } from \"@/db-manager.js\";\n\nexport interface Filter {\n\tcolumnName: string;\n\toperator: string;\n\tvalue: string;\n}\n\nexport type SortDirection = \"asc\" | \"desc\";\n\nexport type Sort = {\n\tcolumnName: string;\n\tdirection: SortDirection;\n};\n\nexport interface TableDataResult {\n\tdata: Record<string, unknown>[];\n\tmeta: {\n\t\tpage: number;\n\t\tlimit: number;\n\t\ttotal: number;\n\t\ttotalPages: number;\n\t\thasNextPage: boolean;\n\t\thasPreviousPage: boolean;\n\t};\n}\n\nconst buildWhereClause = (filters: Filter[]): { clause: string; values: unknown[] } => {\n\tif (filters.length === 0) {\n\t\treturn { clause: \"\", values: [] };\n\t}\n\n\tconst conditions: string[] = [];\n\tconst values: unknown[] = [];\n\n\tfor (const filter of filters) {\n\t\tconst paramIndex = values.length + 1;\n\t\tconst columnName = `\"${filter.columnName}\"`;\n\n\t\tswitch (filter.operator) {\n\t\t\tcase \"=\":\n\t\t\tcase \"!=\":\n\t\t\tcase \">\":\n\t\t\tcase \">=\":\n\t\t\tcase \"<\":\n\t\t\tcase \"<=\":\n\t\t\t\tconditions.push(`${columnName} ${filter.operator} $${paramIndex}`);\n\t\t\t\tvalues.push(filter.value);\n\t\t\t\tbreak;\n\t\t\tcase \"is\":\n\t\t\t\t// Handle NULL values\n\t\t\t\tif (filter.value.toLowerCase() === \"null\") {\n\t\t\t\t\tconditions.push(`${columnName} IS NULL`);\n\t\t\t\t} else {\n\t\t\t\t\tconditions.push(`${columnName} = $${paramIndex}`);\n\t\t\t\t\tvalues.push(filter.value);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase \"is not\":\n\t\t\t\tif (filter.value.toLowerCase() === \"null\") {\n\t\t\t\t\tconditions.push(`${columnName} IS NOT NULL`);\n\t\t\t\t} else {\n\t\t\t\t\tconditions.push(`${columnName} != $${paramIndex}`);\n\t\t\t\t\tvalues.push(filter.value);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase \"like\":\n\t\t\t\tconditions.push(`${columnName}::text LIKE $${paramIndex}`);\n\t\t\t\tvalues.push(filter.value);\n\t\t\t\tbreak;\n\t\t\tcase \"not like\":\n\t\t\t\tconditions.push(`${columnName}::text NOT LIKE $${paramIndex}`);\n\t\t\t\tvalues.push(filter.value);\n\t\t\t\tbreak;\n\t\t\tcase \"ilike\":\n\t\t\t\tconditions.push(`${columnName}::text ILIKE $${paramIndex}`);\n\t\t\t\tvalues.push(filter.value);\n\t\t\t\tbreak;\n\t\t\tcase \"not ilike\":\n\t\t\t\tconditions.push(`${columnName}::text NOT ILIKE $${paramIndex}`);\n\t\t\t\tvalues.push(filter.value);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\t// Unknown operator, skip\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (conditions.length === 0) {\n\t\treturn { clause: \"\", values: [] };\n\t}\n\n\treturn { clause: `WHERE ${conditions.join(\" AND \")}`, values };\n};\n\nconst buildSortClause = (sorts: Sort[] | string, order: SortDirection): string => {\n\t// Handle array of Sort objects (new format for referenced tables)\n\tif (Array.isArray(sorts)) {\n\t\tif (sorts.length === 0) {\n\t\t\treturn \"\";\n\t\t}\n\t\tconst sortParts = sorts.map(\n\t\t\t(sort) => `\"${sort.columnName}\" ${sort.direction.toUpperCase()}`,\n\t\t);\n\t\treturn `ORDER BY ${sortParts.join(\", \")}`;\n\t}\n\n\t// Handle legacy format (string column name + order)\n\tif (sorts && typeof sorts === \"string\") {\n\t\treturn `ORDER BY \"${sorts}\" ${order?.toUpperCase() || \"ASC\"}`;\n\t}\n\n\treturn \"\";\n};\n\nexport const getTableData = async (\n\ttableName: string,\n\tpage: number = 1,\n\tpageSize: number = 50,\n\tsort: string | Sort[] = \"\",\n\torder: SortDirection = \"asc\",\n\tfilters: Filter[] = [],\n\tdatabase?: string,\n): Promise<TableDataResult> => {\n\tconst sortClause = buildSortClause(\n\t\tArray.isArray(sort) ? sort : sort,\n\t\torder as SortDirection,\n\t);\n\tconst { clause: whereClause, values: filterValues } = buildWhereClause(filters);\n\n\tconst pool = getDbPool(database);\n\tconst client = await pool.connect();\n\ttry {\n\t\t// Calculate offset\n\t\tconst offset = (page - 1) * pageSize;\n\n\t\t// Get total count (with filters)\n\t\tconst countRes = await client.query(\n\t\t\t`SELECT COUNT(*) as total FROM \"${tableName}\" ${whereClause}`,\n\t\t\tfilterValues,\n\t\t);\n\t\tconst totalRows = Number(countRes.rows[0].total);\n\t\tconst totalPages = Math.ceil(totalRows / pageSize);\n\n\t\t// Get paginated data (with filters)\n\t\t// Parameter indices continue after filter values\n\t\tconst limitParamIndex = filterValues.length + 1;\n\t\tconst offsetParamIndex = filterValues.length + 2;\n\n\t\tconst dataRes = await client.query(\n\t\t\t`SELECT * FROM \"${tableName}\" ${whereClause} ${sortClause} LIMIT $${limitParamIndex} OFFSET $${offsetParamIndex}`,\n\t\t\t[...filterValues, pageSize, offset],\n\t\t);\n\n\t\treturn {\n\t\t\tdata: dataRes.rows,\n\t\t\tmeta: {\n\t\t\t\tpage,\n\t\t\t\tlimit: pageSize,\n\t\t\t\ttotal: totalRows,\n\t\t\t\ttotalPages,\n\t\t\t\thasNextPage: page < totalPages,\n\t\t\t\thasPreviousPage: page > 1,\n\t\t\t},\n\t\t};\n\t} finally {\n\t\tclient.release();\n\t}\n};\n","import { zValidator } from \"@hono/zod-validator\";\nimport { Hono } from \"hono\";\nimport { getTableData, type Sort } from \"@/dao/tables-data.dao.js\";\nimport { tableDataQuerySchema, tableNameParamSchema } from \"@/types/create-table.type.js\";\nimport { handleConnectionError } from \"@/utils/error-handler.js\";\n\nexport const dataRoutes = new Hono();\n\n/**\n * GET /data - Get paginated data for a table\n */\ndataRoutes.get(\n\t\"/\",\n\tzValidator(\"param\", tableNameParamSchema),\n\tzValidator(\"query\", tableDataQuerySchema),\n\tasync (c) => {\n\t\ttry {\n\t\t\tconst { tableName } = c.req.valid(\"param\");\n\t\t\tconst { page, pageSize, sort: sortParam, order, filters } = c.req.valid(\"query\");\n\n\t\t\t// Parse sort - can be either a string (legacy) or JSON array (new format)\n\t\t\tlet sort: Sort[] | string = \"\";\n\t\t\tif (sortParam) {\n\t\t\t\ttry {\n\t\t\t\t\t// Try to parse as JSON first (new format)\n\t\t\t\t\tconst parsed = JSON.parse(sortParam);\n\t\t\t\t\tif (Array.isArray(parsed)) {\n\t\t\t\t\t\tsort = parsed;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tsort = sortParam;\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// If JSON parse fails, use as string (legacy format)\n\t\t\t\t\tsort = sortParam;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst database = c.req.query(\"database\");\n\t\t\tconst data = await getTableData(\n\t\t\t\ttableName,\n\t\t\t\tpage,\n\t\t\t\tpageSize,\n\t\t\t\tsort,\n\t\t\t\torder,\n\t\t\t\tfilters,\n\t\t\t\tdatabase,\n\t\t\t);\n\t\t\treturn c.json(data);\n\t\t} catch (error) {\n\t\t\tconsole.error(\"GET /data error:\", error);\n\t\t\treturn handleConnectionError(c, error, \"Failed to fetch table data\");\n\t\t}\n\t},\n);\n","import { getDbPool } from \"@/db-manager.js\";\n\nexport interface DatabaseInfo {\n\tname: string;\n\tsize: string;\n\towner: string;\n\tencoding: string;\n}\n\nexport interface DatabaseConnectionInfo {\n\thost: string;\n\tport: number;\n\tuser: string;\n\tdatabase: string;\n\tversion: string;\n\tactiveConnections: number;\n\tmaxConnections: number;\n}\n\nexport interface CurrentDatabase {\n\tdatabase: string;\n}\n\n/**\n * Get list of all databases on the server\n */\nexport async function getDatabasesList(): Promise<DatabaseInfo[]> {\n\tconst pool = getDbPool();\n\tconst query = `\n\t\tSELECT \n\t\t\td.datname as name,\n\t\t\tpg_size_pretty(pg_database_size(d.datname)) as size,\n\t\t\tpg_catalog.pg_get_userbyid(d.datdba) as owner,\n\t\t\tpg_encoding_to_char(d.encoding) as encoding\n\t\tFROM pg_catalog.pg_database d\n\t\tWHERE d.datistemplate = false\n\t\tORDER BY d.datname;\n\t`;\n\n\tconst result = await pool.query(query);\n\treturn result.rows;\n}\n\n/**\n * Get current database name\n */\nexport async function getCurrentDatabase(): Promise<CurrentDatabase> {\n\tconst pool = getDbPool();\n\tconst query = \"SELECT current_database() as database;\";\n\tconst result = await pool.query(query);\n\treturn result.rows[0];\n}\n\n/**\n * Get detailed connection information for current database\n */\nexport async function getDatabaseConnectionInfo(): Promise<DatabaseConnectionInfo> {\n\tconst pool = getDbPool();\n\n\t// Get version and connection stats\n\tconst infoQuery = `\n\t\tSELECT \n\t\t\tversion() as version,\n\t\t\tcurrent_database() as database,\n\t\t\tcurrent_user as user,\n\t\t\tinet_server_addr() as host,\n\t\t\tinet_server_port() as port,\n\t\t\t(SELECT count(*) FROM pg_stat_activity WHERE datname = current_database()) as active_connections,\n\t\t\t(SELECT setting::int FROM pg_settings WHERE name = 'max_connections') as max_connections;\n\t`;\n\n\tconst result = await pool.query(infoQuery);\n\tconst row = result.rows[0];\n\n\t// Parse DATABASE_URL for host and port since inet_server_addr() might return null for local connections\n\tconst databaseUrl = process.env.DATABASE_URL;\n\tlet host = \"localhost\";\n\tlet port = 5432;\n\n\tif (databaseUrl) {\n\t\ttry {\n\t\t\tconst url = new URL(databaseUrl);\n\t\t\thost = url.hostname;\n\t\t\tport = Number.parseInt(url.port, 10) || 5432;\n\t\t} catch (error) {\n\t\t\tconsole.error(\"Failed to parse DATABASE_URL:\", error);\n\t\t}\n\t}\n\n\treturn {\n\t\thost: row.host || host,\n\t\tport: row.port || port,\n\t\tuser: row.user,\n\t\tdatabase: row.database,\n\t\tversion: row.version,\n\t\tactiveConnections: Number.parseInt(row.active_connections, 10),\n\t\tmaxConnections: Number.parseInt(row.max_connections, 10),\n\t};\n}\n","import { Hono } from \"hono\";\nimport {\n\tgetCurrentDatabase,\n\tgetDatabaseConnectionInfo,\n\tgetDatabasesList,\n} from \"@/dao/database-list.dao.js\";\n\nexport const databasesRoutes = new Hono();\n\n/**\n * GET /databases - Get list of all databases\n */\ndatabasesRoutes.get(\"/\", async (c) => {\n\ttry {\n\t\tconst databases = await getDatabasesList();\n\t\treturn c.json(databases);\n\t} catch (error) {\n\t\tconsole.error(\"Error fetching databases list:\", error);\n\t\treturn c.json({ error: \"Failed to fetch databases list\" }, 500);\n\t}\n});\n\n/**\n * GET /databases/current - Get current database name\n */\ndatabasesRoutes.get(\"/current\", async (c) => {\n\ttry {\n\t\tconst current = await getCurrentDatabase();\n\t\treturn c.json(current);\n\t} catch (error) {\n\t\tconsole.error(\"Error fetching current database:\", error);\n\t\treturn c.json({ error: \"Failed to fetch current database\" }, 500);\n\t}\n});\n\n/**\n * GET /databases/connection - Get database connection information\n */\ndatabasesRoutes.get(\"/connection\", async (c) => {\n\ttry {\n\t\tconst info = await getDatabaseConnectionInfo();\n\t\treturn c.json(info);\n\t} catch (error) {\n\t\tconsole.error(\"Error fetching database connection info:\", error);\n\t\treturn c.json({ error: \"Failed to fetch database connection info\" }, 500);\n\t}\n});\n","import { getDbPool } from \"@/db-manager.js\";\n\nexport type ExecuteQueryResponse = {\n\tcolumns: string[];\n\trows: Record<string, unknown>[];\n\trowCount: number;\n\tduration: number;\n\tmessage?: string;\n\terror?: string;\n};\n\nexport const executeQuery = async (params: {\n\tquery: string;\n\tdatabase?: string;\n}): Promise<ExecuteQueryResponse> => {\n\tconst { query, database } = params;\n\tconst pool = getDbPool(database);\n\tconst client = await pool.connect();\n\n\ttry {\n\t\tif (!query || !query.trim()) {\n\t\t\tthrow new Error(\"Query cannot be empty\");\n\t\t}\n\n\t\t// Clean the query - remove trailing semicolons and whitespace\n\t\tconst cleanedQuery = query.trim().replace(/;+$/, \"\");\n\n\t\tconsole.log(\"executeQuery query:\", cleanedQuery);\n\t\tconst startTime = performance.now();\n\t\tconst result = await client.query(cleanedQuery);\n\t\tconst duration = performance.now() - startTime;\n\n\t\tconst columns = result.fields.map((field) => field.name);\n\n\t\treturn {\n\t\t\tcolumns,\n\t\t\trows: result.rows,\n\t\t\trowCount: result.rows.length,\n\t\t\tduration,\n\t\t\tmessage: result.rows.length === 0 ? \"OK\" : undefined,\n\t\t};\n\t} catch (error) {\n\t\tconsole.error(\"Error executing query:\", error);\n\t\tconst errorMessage =\n\t\t\terror instanceof Error ? error.message : \"Unknown error occurred\";\n\t\tthrow new Error(errorMessage);\n\t} finally {\n\t\tclient.release();\n\t}\n};\n","import { zValidator } from \"@hono/zod-validator\";\nimport { Hono } from \"hono\";\nimport { executeQuery } from \"@/dao/query.dao.js\";\nimport { executeQuerySchema } from \"@/types/create-table.type.js\";\n\nexport const queryRoutes = new Hono();\n\n/**\n * POST /query - Execute a SQL query\n */\nqueryRoutes.post(\"/\", zValidator(\"json\", executeQuerySchema), async (c) => {\n\ttry {\n\t\tconst { query } = c.req.valid(\"json\");\n\t\tconst database = c.req.query(\"database\");\n\n\t\tconst data = await executeQuery({ query, database });\n\t\treturn c.json(data);\n\t} catch (error) {\n\t\tconsole.error(\"POST /query error:\", error);\n\t\tconst errorMessage = error instanceof Error ? error.message : \"Unknown error\";\n\t\treturn c.json(\n\t\t\t{\n\t\t\t\tstatus: \"error\",\n\t\t\t\terror: errorMessage,\n\t\t\t},\n\t\t\t500,\n\t\t);\n\t}\n});\n","import { getDbPool } from \"@/db-manager.js\";\n\nexport interface DeleteRecordParams {\n\ttableName: string;\n\tprimaryKeys: Array<{ columnName: string; value: unknown }>;\n\tdatabase?: string;\n}\n\nexport interface ForeignKeyConstraint {\n\tconstraintName: string;\n\treferencingTable: string;\n\treferencingColumn: string;\n\treferencedTable: string;\n\treferencedColumn: string;\n}\n\nexport interface ForeignKeyConstraintRow {\n\tconstraint_name: string;\n\treferencing_table: string;\n\treferencing_column: string;\n\treferenced_table: string;\n\treferenced_column: string;\n}\n\nexport interface RelatedRecord {\n\ttableName: string;\n\tcolumnName: string;\n\tconstraintName: string;\n\trecords: Array<Record<string, unknown>>;\n}\n\nexport interface DeleteResult {\n\tsuccess: boolean;\n\tmessage: string;\n\tdeletedCount?: number;\n\tfkViolation?: boolean;\n\trelatedRecords?: RelatedRecord[];\n}\n\n/**\n * Gets foreign key constraints that reference the given table\n */\nexport const getForeignKeyReferences = async (\n\ttableName: string,\n\tdatabase?: string,\n): Promise<ForeignKeyConstraint[]> => {\n\tconst query = `\n\t\tSELECT\n\t\t\ttc.constraint_name,\n\t\t\ttc.table_name as referencing_table,\n\t\t\tkcu.column_name as referencing_column,\n\t\t\tccu.table_name AS referenced_table,\n\t\t\tccu.column_name AS referenced_column\n\t\tFROM information_schema.table_constraints AS tc\n\t\tJOIN information_schema.key_column_usage AS kcu\n\t\t\tON tc.constraint_name = kcu.constraint_name\n\t\t\tAND tc.table_schema = kcu.table_schema\n\t\tJOIN information_schema.constraint_column_usage AS ccu\n\t\t\tON ccu.constraint_name = tc.constraint_name\n\t\t\tAND ccu.table_schema = tc.table_schema\n\t\tWHERE tc.constraint_type = 'FOREIGN KEY'\n\t\t\tAND ccu.table_name = $1\n\t`;\n\n\tconst pool = getDbPool(database);\n\tconst result = await pool.query(query, [tableName]);\n\n\treturn result.rows.map(({ row }: { row: ForeignKeyConstraintRow }) => ({\n\t\tconstraintName: row.constraint_name,\n\t\treferencingTable: row.referencing_table,\n\t\treferencingColumn: row.referencing_column,\n\t\treferencedTable: row.referenced_table,\n\t\treferencedColumn: row.referenced_column,\n\t}));\n};\n\n/**\n * Finds all records in other tables that reference the given primary key values\n */\nexport const getRelatedRecords = async (\n\ttableName: string,\n\tprimaryKeys: Array<{ columnName: string; value: unknown }>,\n\tdatabase?: string,\n): Promise<RelatedRecord[]> => {\n\tconst fkConstraints = await getForeignKeyReferences(tableName, database);\n\n\tif (fkConstraints.length === 0) {\n\t\treturn [];\n\t}\n\n\tconst relatedRecords: RelatedRecord[] = [];\n\tconst pool = getDbPool(database);\n\n\t// Group constraints by referencing table and column for efficiency\n\tconst constraintsByTable = new Map<string, ForeignKeyConstraint[]>();\n\tfor (const constraint of fkConstraints) {\n\t\tconst key = `${constraint.referencingTable}.${constraint.referencingColumn}`;\n\t\tif (!constraintsByTable.has(key)) {\n\t\t\tconstraintsByTable.set(key, []);\n\t\t}\n\t\tconstraintsByTable.get(key)?.push(constraint);\n\t}\n\n\t// Get the primary key values that we're looking for\n\tconst pkValues = primaryKeys.map((pk) => pk.value);\n\n\tfor (const [_tableColumn, constraints] of constraintsByTable) {\n\t\tconst constraint = constraints[0];\n\t\tif (!constraint) continue;\n\n\t\t// Find which primary key column matches this FK's referenced column\n\t\tconst matchingPk = primaryKeys.find(\n\t\t\t(pk) => pk.columnName === constraint.referencedColumn,\n\t\t);\n\t\tif (!matchingPk) continue;\n\n\t\t// Build query to find related records\n\t\tconst placeholders = pkValues.map((_, i) => `$${i + 1}`).join(\", \");\n\t\tconst query = `\n\t\t\tSELECT * FROM \"${constraint.referencingTable}\"\n\t\t\tWHERE \"${constraint.referencingColumn}\" IN (${placeholders})\n\t\t\tLIMIT 100\n\t\t`;\n\n\t\ttry {\n\t\t\tconst result = await pool.query(query, pkValues);\n\n\t\t\tif (result.rows.length > 0) {\n\t\t\t\trelatedRecords.push({\n\t\t\t\t\ttableName: constraint.referencingTable,\n\t\t\t\t\tcolumnName: constraint.referencingColumn,\n\t\t\t\t\tconstraintName: constraint.constraintName,\n\t\t\t\t\trecords: result.rows,\n\t\t\t\t});\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconsole.error(\n\t\t\t\t`Error fetching related records from ${constraint.referencingTable}:`,\n\t\t\t\terror,\n\t\t\t);\n\t\t}\n\t}\n\n\treturn relatedRecords;\n};\n\n/**\n * Attempts to delete records. If FK violation occurs, returns related records.\n */\nexport const deleteRecords = async (\n\tparams: DeleteRecordParams,\n): Promise<DeleteResult> => {\n\tconst { tableName, primaryKeys, database } = params;\n\tconst pool = getDbPool(database);\n\tconst client = await pool.connect();\n\n\ttry {\n\t\tawait client.query(\"BEGIN\");\n\n\t\t// Build the delete query\n\t\tconst pkColumn = primaryKeys[0]?.columnName;\n\t\tif (!pkColumn) {\n\t\t\tthrow new Error(\"Primary key column name is required\");\n\t\t}\n\n\t\tconst pkValues = primaryKeys.map((pk) => pk.value);\n\t\tconst placeholders = pkValues.map((_, i) => `$${i + 1}`).join(\", \");\n\n\t\tconst deleteSQL = `\n\t\t\tDELETE FROM \"${tableName}\"\n\t\t\tWHERE \"${pkColumn}\" IN (${placeholders})\n\t\t\tRETURNING *\n\t\t`;\n\n\t\tconsole.log(\"Deleting records with SQL:\", deleteSQL, \"Values:\", pkValues);\n\t\tconst result = await client.query(deleteSQL, pkValues);\n\n\t\tawait client.query(\"COMMIT\");\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tmessage: `Successfully deleted ${result.rowCount} ${result.rowCount === 1 ? \"record\" : \"records\"} from \"${tableName}\"`,\n\t\t\tdeletedCount: result.rowCount ?? 0,\n\t\t};\n\t} catch (error) {\n\t\tawait client.query(\"ROLLBACK\");\n\n\t\t// Check if this is a foreign key violation\n\t\tconst pgError = error as { code?: string; detail?: string; constraint?: string };\n\n\t\tif (pgError.code === \"23503\") {\n\t\t\t// Foreign key violation\n\t\t\tconsole.log(\"FK violation detected, fetching related records...\");\n\n\t\t\t// Fetch related records to show the user\n\t\t\tconst relatedRecords = await getRelatedRecords(tableName, primaryKeys);\n\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\tmessage: \"Cannot delete: Records are referenced by other tables\",\n\t\t\t\tfkViolation: true,\n\t\t\t\trelatedRecords,\n\t\t\t};\n\t\t}\n\n\t\tconsole.error(\"Error deleting records:\", error);\n\t\tthrow error;\n\t} finally {\n\t\tclient.release();\n\t}\n};\n\n/**\n * Force deletes records by first deleting all related records in referencing tables (cascade)\n */\nexport const forceDeleteRecords = async (\n\tparams: DeleteRecordParams,\n): Promise<DeleteResult> => {\n\tconst { tableName, primaryKeys, database } = params;\n\tconst pool = getDbPool(database);\n\tconst client = await pool.connect();\n\n\ttry {\n\t\tawait client.query(\"BEGIN\");\n\n\t\tconst pkColumn = primaryKeys[0]?.columnName;\n\t\tif (!pkColumn) {\n\t\t\tthrow new Error(\"Primary key column name is required\");\n\t\t}\n\n\t\tconst pkValues = primaryKeys.map((pk) => pk.value);\n\n\t\t// Get all FK constraints that reference this table\n\t\tconst fkConstraints = await getForeignKeyReferences(tableName, database);\n\n\t\tlet totalRelatedDeleted = 0;\n\n\t\t// Delete related records in reverse dependency order\n\t\t// We need to handle nested FKs recursively\n\t\tconst deletedTables = new Set<string>();\n\n\t\tconst deleteRelatedRecursively = async (\n\t\t\ttargetTable: string,\n\t\t\ttargetColumn: string,\n\t\t\tvalues: unknown[],\n\t\t) => {\n\t\t\t// First, find if there are tables referencing the target table\n\t\t\tconst nestedFks = await getForeignKeyReferences(targetTable, database);\n\n\t\t\tfor (const nestedFk of nestedFks) {\n\t\t\t\t// Get the values that will be deleted from the target table\n\t\t\t\tconst placeholders = values.map((_, i) => `$${i + 1}`).join(\", \");\n\t\t\t\tconst selectQuery = `\n\t\t\t\t\tSELECT \"${nestedFk.referencedColumn}\" FROM \"${targetTable}\"\n\t\t\t\t\tWHERE \"${targetColumn}\" IN (${placeholders})\n\t\t\t\t`;\n\n\t\t\t\tconst selectResult = await client.query(selectQuery, values);\n\t\t\t\tconst nestedValues = selectResult.rows.map(\n\t\t\t\t\t({ row }: { row: { [nestedFk.referencedColumn]: unknown } }) =>\n\t\t\t\t\t\trow[nestedFk.referencedColumn],\n\t\t\t\t);\n\n\t\t\t\tif (nestedValues.length > 0) {\n\t\t\t\t\tawait deleteRelatedRecursively(\n\t\t\t\t\t\tnestedFk.referencingTable,\n\t\t\t\t\t\tnestedFk.referencingColumn,\n\t\t\t\t\t\tnestedValues,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Now delete from the target table\n\t\t\tconst placeholders = values.map((_, i) => `$${i + 1}`).join(\", \");\n\t\t\tconst deleteQuery = `\n\t\t\t\tDELETE FROM \"${targetTable}\"\n\t\t\t\tWHERE \"${targetColumn}\" IN (${placeholders})\n\t\t\t`;\n\n\t\t\tconst deleteResult = await client.query(deleteQuery, values);\n\t\t\ttotalRelatedDeleted += deleteResult.rowCount ?? 0;\n\t\t\tdeletedTables.add(targetTable);\n\t\t};\n\n\t\t// Delete from all referencing tables first\n\t\tfor (const constraint of fkConstraints) {\n\t\t\tif (deletedTables.has(constraint.referencingTable)) continue;\n\n\t\t\tawait deleteRelatedRecursively(\n\t\t\t\tconstraint.referencingTable,\n\t\t\t\tconstraint.referencingColumn,\n\t\t\t\tpkValues,\n\t\t\t);\n\t\t}\n\n\t\t// Finally delete the main records\n\t\tconst placeholders = pkValues.map((_, i) => `$${i + 1}`).join(\", \");\n\t\tconst deleteSQL = `\n\t\t\tDELETE FROM \"${tableName}\"\n\t\t\tWHERE \"${pkColumn}\" IN (${placeholders})\n\t\t\tRETURNING *\n\t\t`;\n\n\t\tconsole.log(\"Force deleting records with SQL:\", deleteSQL, \"Values:\", pkValues);\n\t\tconst result = await client.query(deleteSQL, pkValues);\n\n\t\tawait client.query(\"COMMIT\");\n\n\t\tconst mainDeleted = result.rowCount ?? 0;\n\t\tconst message =\n\t\t\ttotalRelatedDeleted > 0\n\t\t\t\t? `Successfully deleted ${mainDeleted} ${mainDeleted === 1 ? \"record\" : \"records\"} from \"${tableName}\" and ${totalRelatedDeleted} related ${totalRelatedDeleted === 1 ? \"record\" : \"records\"} from other tables`\n\t\t\t\t: `Successfully deleted ${mainDeleted} ${mainDeleted === 1 ? \"record\" : \"records\"} from \"${tableName}\"`;\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tmessage,\n\t\t\tdeletedCount: mainDeleted + totalRelatedDeleted,\n\t\t};\n\t} catch (error) {\n\t\tawait client.query(\"ROLLBACK\");\n\t\tconsole.error(\"Error force deleting records:\", error);\n\t\tthrow error;\n\t} finally {\n\t\tclient.release();\n\t}\n};\n","import { getDbPool } from \"@/db-manager.js\";\n\nexport interface InsertRecordParams {\n\ttableName: string;\n\tdata: Record<string, unknown>;\n\tdatabase?: string;\n}\n\nexport const insertRecord = async (params: InsertRecordParams) => {\n\tconst { tableName, data, database } = params;\n\tconst pool = getDbPool(database);\n\tconst client = await pool.connect();\n\n\ttry {\n\t\t// Extract column names and values\n\t\tconst columns = Object.keys(data);\n\t\tconst values = Object.values(data);\n\n\t\t// Build the INSERT query\n\t\tconst placeholders = columns.map((_, index) => `$${index + 1}`).join(\", \");\n\t\tconst columnNames = columns.map((col) => `\"${col}\"`).join(\", \");\n\n\t\tconst insertSQL = `\n\t\t\tINSERT INTO \"${tableName}\" (${columnNames})\n\t\t\tVALUES (${placeholders})\n\t\t\tRETURNING *\n\t\t`;\n\n\t\tconsole.log(\"Inserting record with SQL:\", insertSQL, \"Values:\", values);\n\t\tconst result = await client.query(insertSQL, values);\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tmessage: `Record inserted into \"${tableName}\" successfully`,\n\t\t\tdata: result.rows[0],\n\t\t};\n\t} catch (error) {\n\t\tconsole.error(\"Error inserting record:\", error);\n\t\tthrow error;\n\t} finally {\n\t\tclient.release();\n\t}\n};\n","import { getDbPool } from \"@/db-manager.js\";\n\nexport interface UpdateRecordParams {\n\ttableName: string;\n\tupdates: Array<{\n\t\trowData: Record<string, unknown>; // Original row data to identify the record\n\t\tcolumnName: string;\n\t\tvalue: unknown;\n\t}>;\n\tprimaryKey?: string; // Optional: specify primary key column (defaults to 'id')\n\tdatabase?: string;\n}\n\n/**\n * Updates multiple cells in a table. Can update multiple rows or multiple cells in the same row.\n * Groups updates by row and executes them efficiently.\n */\nexport const updateRecords = async (params: UpdateRecordParams) => {\n\tconst { tableName, updates, primaryKey = \"id\", database } = params;\n\tconst pool = getDbPool(database);\n\tconst client = await pool.connect();\n\n\ttry {\n\t\tawait client.query(\"BEGIN\");\n\n\t\t// Group updates by row (using the primary key value)\n\t\tconst updatesByRow = new Map<\n\t\t\tunknown,\n\t\t\tArray<{ columnName: string; value: unknown; rowData: Record<string, unknown> }>\n\t\t>();\n\n\t\tfor (const update of updates) {\n\t\t\tconst pkValue = update.rowData[primaryKey];\n\t\t\tif (pkValue === undefined) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Primary key \"${primaryKey}\" not found in row data. Please ensure the row has a primary key.`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (!updatesByRow.has(pkValue)) {\n\t\t\t\tupdatesByRow.set(pkValue, []);\n\t\t\t}\n\t\t\tupdatesByRow.get(pkValue)?.push({\n\t\t\t\tcolumnName: update.columnName,\n\t\t\t\tvalue: update.value,\n\t\t\t\trowData: update.rowData,\n\t\t\t});\n\t\t}\n\n\t\tconst results = [];\n\t\tlet totalUpdated = 0;\n\n\t\t// Execute updates for each row\n\t\tfor (const [pkValue, rowUpdates] of updatesByRow.entries()) {\n\t\t\tconst setClauses = rowUpdates.map(\n\t\t\t\t(u, index) => `\"${u.columnName}\" = $${index + 1}`,\n\t\t\t);\n\t\t\tconst values = rowUpdates.map((u) => {\n\t\t\t\tconsole.log(`Value for ${u.columnName}:`, typeof u.value, u.value);\n\t\t\t\t// If the value is an object or array, stringify it for JSON/JSONB columns\n\t\t\t\tif (u.value !== null && typeof u.value === \"object\") {\n\t\t\t\t\treturn JSON.stringify(u.value);\n\t\t\t\t}\n\t\t\t\treturn u.value;\n\t\t\t});\n\n\t\t\t// Add the primary key value as the last parameter\n\t\t\tvalues.push(pkValue);\n\n\t\t\tconst updateSQL = `\n\t\t\t\tUPDATE \"${tableName}\"\n\t\t\t\tSET ${setClauses.join(\", \")}\n\t\t\t\tWHERE \"${primaryKey}\" = $${values.length}\n\t\t\t\tRETURNING *\n\t\t\t`;\n\n\t\t\tconsole.log(\"Updating record with SQL:\", updateSQL, \"Values:\", values);\n\t\t\tconst result = await client.query(updateSQL, values);\n\n\t\t\tif (result.rowCount === 0) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Record with ${primaryKey} = ${pkValue} not found in table \"${tableName}\"`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tresults.push(result.rows[0]);\n\t\t\ttotalUpdated += result.rowCount || 0;\n\t\t}\n\n\t\tawait client.query(\"COMMIT\");\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tmessage: `Successfully updated ${totalUpdated} ${totalUpdated === 1 ? \"row\" : \"rows\"} in \"${tableName}\"`,\n\t\t\tdata: results,\n\t\t\tupdatedCount: totalUpdated,\n\t\t};\n\t} catch (error) {\n\t\tawait client.query(\"ROLLBACK\");\n\t\tconsole.error(\"Error updating records:\", error);\n\t\tthrow error;\n\t} finally {\n\t\tclient.release();\n\t}\n};\n","import { zValidator } from \"@hono/zod-validator\";\nimport { Hono } from \"hono\";\nimport { z } from \"zod\";\nimport { deleteRecords, forceDeleteRecords } from \"@/dao/delete-records.dao.js\";\nimport { insertRecord } from \"@/dao/insert-record.dao.js\";\nimport { updateRecords } from \"@/dao/update-records.dao.js\";\nimport {\n\tdeleteRecordsSchema,\n\tinsertRecordSchema,\n\tupdateRecordsSchema,\n} from \"@/types/create-table.type.js\";\n\nconst databaseQuerySchema = z.object({\n\tdatabase: z.string(),\n});\n\nexport const recordsRoutes = new Hono();\n\n/**\n * POST /records - Insert a new record into a table\n */\nrecordsRoutes.post(\n\t\"/\",\n\tzValidator(\"json\", insertRecordSchema),\n\tzValidator(\"query\", databaseQuerySchema),\n\tasync (c) => {\n\t\ttry {\n\t\t\tconst body = c.req.valid(\"json\");\n\t\t\tconst { tableName, data } = body;\n\t\t\tconst { database } = c.req.valid(\"query\");\n\n\t\t\tconsole.log(\"POST /records body\", { tableName, data });\n\t\t\tconst result = await insertRecord({ tableName, data, database });\n\t\t\tconsole.log(\"POST /records\", result);\n\t\t\treturn c.json(result);\n\t\t} catch (error) {\n\t\t\tconsole.error(\"POST /records error:\", error);\n\t\t\tconst errorDetail =\n\t\t\t\terror && typeof error === \"object\" && \"detail\" in error\n\t\t\t\t\t? (error as { detail?: string }).detail\n\t\t\t\t\t: undefined;\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\tmessage: error instanceof Error ? error.message : \"Failed to create record\",\n\t\t\t\t\tdetail: errorDetail,\n\t\t\t\t},\n\t\t\t\t500,\n\t\t\t);\n\t\t}\n\t},\n);\n\n/**\n * PATCH /records - Update one or more cells in a table\n */\nrecordsRoutes.patch(\n\t\"/\",\n\tzValidator(\"json\", updateRecordsSchema),\n\tzValidator(\"query\", databaseQuerySchema),\n\tasync (c) => {\n\t\ttry {\n\t\t\tconst body = c.req.valid(\"json\");\n\t\t\tconst { tableName, updates, primaryKey } = body;\n\t\t\tconst { database } = c.req.valid(\"query\");\n\n\t\t\tconsole.log(\"PATCH /records body\", { tableName, updates, primaryKey });\n\t\t\tconst result = await updateRecords({ tableName, updates, primaryKey, database });\n\t\t\tconsole.log(\"PATCH /records\", result);\n\t\t\treturn c.json(result);\n\t\t} catch (error) {\n\t\t\tconsole.error(\"PATCH /records error:\", error);\n\t\t\tconst errorDetail =\n\t\t\t\terror && typeof error === \"object\" && \"detail\" in error\n\t\t\t\t\t? (error as { detail?: string }).detail\n\t\t\t\t\t: undefined;\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\tmessage: error instanceof Error ? error.message : \"Failed to update records\",\n\t\t\t\t\tdetail: errorDetail,\n\t\t\t\t},\n\t\t\t\t500,\n\t\t\t);\n\t\t}\n\t},\n);\n\n/**\n * DELETE /records - Delete records from a table\n */\nrecordsRoutes.delete(\n\t\"/\",\n\tzValidator(\"json\", deleteRecordsSchema),\n\tzValidator(\"query\", databaseQuerySchema),\n\tasync (c) => {\n\t\ttry {\n\t\t\tconst body = c.req.valid(\"json\");\n\t\t\tconst { tableName, primaryKeys } = body;\n\t\t\tconst { database } = c.req.valid(\"query\");\n\n\t\t\tconsole.log(\"DELETE /records body\", { tableName, primaryKeys });\n\t\t\tconst result = await deleteRecords({ tableName, primaryKeys, database });\n\t\t\tconsole.log(\"DELETE /records result\", result);\n\n\t\t\tif (result.fkViolation) {\n\t\t\t\treturn c.json(result, 409);\n\t\t\t}\n\n\t\t\treturn c.json(result);\n\t\t} catch (error) {\n\t\t\tconsole.error(\"DELETE /records error:\", error);\n\t\t\tconst errorDetail =\n\t\t\t\terror && typeof error === \"object\" && \"detail\" in error\n\t\t\t\t\t? (error as { detail?: string }).detail\n\t\t\t\t\t: undefined;\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\tmessage: error instanceof Error ? error.message : \"Failed to delete records\",\n\t\t\t\t\tdetail: errorDetail,\n\t\t\t\t},\n\t\t\t\t500,\n\t\t\t);\n\t\t}\n\t},\n);\n\n/**\n * DELETE /records/force - Force delete records and all related FK records\n */\nrecordsRoutes.delete(\n\t\"/force\",\n\tzValidator(\"json\", deleteRecordsSchema),\n\tzValidator(\"query\", databaseQuerySchema),\n\tasync (c) => {\n\t\ttry {\n\t\t\tconst body = c.req.valid(\"json\");\n\t\t\tconst { tableName, primaryKeys } = body;\n\t\t\tconst { database } = c.req.valid(\"query\");\n\n\t\t\tconsole.log(\"DELETE /records/force body\", { tableName, primaryKeys });\n\t\t\tconst result = await forceDeleteRecords({ tableName, primaryKeys, database });\n\t\t\tconsole.log(\"DELETE /records/force result\", result);\n\n\t\t\treturn c.json(result);\n\t\t} catch (error) {\n\t\t\tconsole.error(\"DELETE /records/force error:\", error);\n\t\t\tconst errorDetail =\n\t\t\t\terror && typeof error === \"object\" && \"detail\" in error\n\t\t\t\t\t? (error as { detail?: string }).detail\n\t\t\t\t\t: undefined;\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\tmessage:\n\t\t\t\t\t\terror instanceof Error ? error.message : \"Failed to force delete records\",\n\t\t\t\t\tdetail: errorDetail,\n\t\t\t\t},\n\t\t\t\t500,\n\t\t\t);\n\t\t}\n\t},\n);\n","import { getDbPool } from \"@/db-manager.js\";\nimport type { CreateTableFormData, FieldDataType } from \"@/types/create-table.type.js\";\n\nexport const createTable = async (tableData: CreateTableFormData, database?: string) => {\n\tconst { tableName, fields, foreignKeys } = tableData;\n\tconst pool = getDbPool(database);\n\tconst client = await pool.connect();\n\n\ttry {\n\t\t// Build column definitions\n\t\tconst columnDefinitions = fields.map((field: FieldDataType) => {\n\t\t\tlet columnDef = `\"${field.columnName}\" ${field.columnType}`;\n\n\t\t\t// Add array suffix if needed\n\t\t\tif (field.isArray) {\n\t\t\t\tcolumnDef += \"[]\";\n\t\t\t}\n\n\t\t\t// Add PRIMARY KEY constraint\n\t\t\tif (field.isPrimaryKey) {\n\t\t\t\tcolumnDef += \" PRIMARY KEY\";\n\t\t\t}\n\n\t\t\t// Add UNIQUE constraint\n\t\t\tif (field.isUnique && !field.isPrimaryKey) {\n\t\t\t\tcolumnDef += \" UNIQUE\";\n\t\t\t}\n\n\t\t\t// Add NOT NULL constraint (if not nullable)\n\t\t\tif (!field.isNullable) {\n\t\t\t\tcolumnDef += \" NOT NULL\";\n\t\t\t}\n\n\t\t\t// Add GENERATED ALWAYS AS IDENTITY for identity columns\n\t\t\tif (field.isIdentity) {\n\t\t\t\tcolumnDef += \" GENERATED ALWAYS AS IDENTITY\";\n\t\t\t}\n\n\t\t\t// Add default value\n\t\t\tif (field.defaultValue && !field.isIdentity) {\n\t\t\t\tcolumnDef += ` DEFAULT ${field.defaultValue}`;\n\t\t\t}\n\n\t\t\treturn columnDef;\n\t\t});\n\n\t\t// Build foreign key constraints\n\t\tconst foreignKeyConstraints =\n\t\t\tforeignKeys?.map((fk) => {\n\t\t\t\tconst constraintName = `fk_${tableName}_${fk.columnName}_${fk.referencedTable}_${fk.referencedColumn}`;\n\t\t\t\treturn `CONSTRAINT \"${constraintName}\" FOREIGN KEY (\"${fk.columnName}\") REFERENCES \"${fk.referencedTable}\" (\"${fk.referencedColumn}\") ON UPDATE ${fk.onUpdate} ON DELETE ${fk.onDelete}`;\n\t\t\t}) || [];\n\n\t\t// Combine column definitions and foreign key constraints\n\t\tconst allDefinitions = [...columnDefinitions, ...foreignKeyConstraints];\n\n\t\t// Create the table\n\t\tconst createTableSQL = `\n\t\t\tCREATE TABLE \"${tableName}\" (\n\t\t\t\t${allDefinitions.join(\",\\n\\t\\t\\t\\t\")}\n\t\t\t);\n\t\t`;\n\n\t\tconsole.log(\"Creating table with SQL:\", createTableSQL);\n\t\tawait client.query(createTableSQL);\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\ttableName,\n\t\t\tmessage: `Table \"${tableName}\" created successfully`,\n\t\t};\n\t} catch (error) {\n\t\tconsole.error(\"Error creating table:\", error);\n\t\tthrow error;\n\t} finally {\n\t\tclient.release();\n\t}\n};\n","import { getDbPool } from \"@/db-manager.js\";\n\nexport interface TableInfo {\n\ttableName: string;\n\trowCount: number;\n}\n\nexport const getTablesList = async (database?: string): Promise<TableInfo[]> => {\n\tconst pool = getDbPool(database);\n\tconst client = await pool.connect();\n\ttry {\n\t\tconst res = await client.query(`\n SELECT \n t.table_name as \"tableName\",\n COALESCE(s.n_live_tup, 0) as \"rowCount\" \n FROM information_schema.tables t\n LEFT JOIN pg_stat_user_tables s ON t.table_name = s.relname\n WHERE t.table_schema = 'public'\n AND t.table_type = 'BASE TABLE'\n ORDER BY t.table_name;\n `);\n\t\treturn res.rows.map((r: any) => ({\n\t\t\ttableName: r.tableName,\n\t\t\trowCount: Number(r.rowCount),\n\t\t}));\n\t} finally {\n\t\tclient.release();\n\t}\n};\n","import { zValidator } from \"@hono/zod-validator\";\nimport { Hono } from \"hono\";\nimport { createTable } from \"@/dao/create-table.dao.js\";\nimport { getTablesList } from \"@/dao/table-list.dao.js\";\nimport { createTableSchema, databaseQuerySchema } from \"@/types/create-table.type.js\";\nimport { handleConnectionError } from \"@/utils/error-handler.js\";\n\nexport const tablesRoutes = new Hono();\n\n/**\n * GET /tables - Get all tables\n */\ntablesRoutes.get(\"/\", zValidator(\"query\", databaseQuerySchema), async (c) => {\n\ttry {\n\t\tconst { database } = c.req.valid(\"query\");\n\t\tconst tablesList = await getTablesList(database);\n\t\tconsole.log(\"GET /tables\", tablesList);\n\t\treturn c.json(tablesList);\n\t} catch (error) {\n\t\tconsole.error(\"GET /tables error:\", error);\n\t\treturn handleConnectionError(c, error, \"Failed to fetch tables\");\n\t}\n});\n\n/**\n * POST /tables - Create a new table\n */\ntablesRoutes.post(\n\t\"/\",\n\tzValidator(\"json\", createTableSchema),\n\tzValidator(\"query\", databaseQuerySchema),\n\tasync (c) => {\n\t\ttry {\n\t\t\tconst body = c.req.valid(\"json\");\n\t\t\tconst { database } = c.req.valid(\"query\");\n\t\t\tconsole.log(\"POST /tables body\", body);\n\t\t\tconst data = await createTable(body, database);\n\t\t\tconsole.log(\"POST /tables\", data);\n\t\t\treturn c.json(data);\n\t\t} catch (error) {\n\t\t\tconsole.error(\"POST /tables error:\", error);\n\t\t\tconst errorDetail =\n\t\t\t\terror && typeof error === \"object\" && \"detail\" in error\n\t\t\t\t\t? (error as { detail?: string }).detail\n\t\t\t\t\t: undefined;\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\tmessage: error instanceof Error ? error.message : \"Failed to create table\",\n\t\t\t\t\tdetail: errorDetail,\n\t\t\t\t},\n\t\t\t\t500,\n\t\t\t);\n\t\t}\n\t},\n);\n","import type { NodeWebSocket } from \"@hono/node-ws\";\nimport { Hono } from \"hono\";\nimport { db } from \"@/db.js\";\n\nconst checkDatabaseConnection = async (): Promise<{\n\tsuccess: boolean;\n\terror?: string;\n}> => {\n\tconst client = await db.connect();\n\ttry {\n\t\tawait client.query(\"SELECT 1\");\n\t\treturn { success: true };\n\t} catch (error) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: error instanceof Error ? error.message : \"Unknown error\",\n\t\t};\n\t} finally {\n\t\tclient.release();\n\t}\n};\n\nconst DB_CHECK_INTERVAL = 5000;\nconst DB_CHECK_TIMEOUT = 10000;\n\nexport const websocketRoutes = (upgradeWebSocket: NodeWebSocket[\"upgradeWebSocket\"]) => {\n\tconst app = new Hono();\n\n\tapp.get(\n\t\t\"/\",\n\t\tupgradeWebSocket(() => {\n\t\t\tlet interval: NodeJS.Timeout;\n\n\t\t\treturn {\n\t\t\t\tonOpen: async (_event, ws) => {\n\t\t\t\t\tconsole.log(\"WebSocket client connected\");\n\n\t\t\t\t\t// Send initial status\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst status = await checkDatabaseConnection();\n\t\t\t\t\t\tws.send(\n\t\t\t\t\t\t\tJSON.stringify({\n\t\t\t\t\t\t\t\t...status,\n\t\t\t\t\t\t\t\tstatus: status.success ? \"connected\" : \"failed\",\n\t\t\t\t\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tconsole.error(\"Error checking DB on open:\", err);\n\t\t\t\t\t\tws.send(\n\t\t\t\t\t\t\tJSON.stringify({\n\t\t\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\t\t\tstatus: \"failed\",\n\t\t\t\t\t\t\t\terror: \"Initial check failed\",\n\t\t\t\t\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Check DB status every 5 seconds\n\t\t\t\t\tinterval = setInterval(async () => {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst status = await Promise.race([\n\t\t\t\t\t\t\t\tcheckDatabaseConnection(),\n\t\t\t\t\t\t\t\tnew Promise<{ success: boolean; error: string }>((_, reject) =>\n\t\t\t\t\t\t\t\t\tsetTimeout(\n\t\t\t\t\t\t\t\t\t\t() => reject({ success: false, error: \"Database check timeout\" }),\n\t\t\t\t\t\t\t\t\t\tDB_CHECK_TIMEOUT,\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t]);\n\t\t\t\t\t\t\tws.send(\n\t\t\t\t\t\t\t\tJSON.stringify({\n\t\t\t\t\t\t\t\t\t...status,\n\t\t\t\t\t\t\t\t\tstatus: status.success ? \"connected\" : \"failed\",\n\t\t\t\t\t\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\tconsole.error(\"Error in DB check interval:\", err);\n\t\t\t\t\t\t\tws.send(\n\t\t\t\t\t\t\t\tJSON.stringify({\n\t\t\t\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\t\t\t\tstatus: \"failed\",\n\t\t\t\t\t\t\t\t\terror: err instanceof Error ? err.message : \"Check failed\",\n\t\t\t\t\t\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}, DB_CHECK_INTERVAL);\n\t\t\t\t},\n\t\t\t\tonMessage(event, _ws) {\n\t\t\t\t\tconsole.log(`Message from client: ${event.data}`);\n\t\t\t\t},\n\t\t\t\tonClose: () => {\n\t\t\t\t\tconsole.log(\"WebSocket connection closed\");\n\t\t\t\t\tif (interval) {\n\t\t\t\t\t\tclearInterval(interval);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tonError: (err) => {\n\t\t\t\t\tconsole.error(\"WebSocket error:\", err);\n\t\t\t\t\tif (interval) {\n\t\t\t\t\t\tclearInterval(interval);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t};\n\t\t}),\n\t);\n\n\treturn app;\n};\n","import path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { serveStatic } from \"@hono/node-server/serve-static\";\nimport { createNodeWebSocket } from \"@hono/node-ws\";\nimport { Hono } from \"hono\";\nimport { cors } from \"hono/cors\";\nimport { logger } from \"hono/logger\";\n\nimport { chatRoutes } from \"@/routes/chat.routes.js\";\nimport { columnsRoutes } from \"@/routes/columns.routes.js\";\nimport { dataRoutes } from \"@/routes/data.routes.js\";\nimport { databasesRoutes } from \"@/routes/databases.routes.js\";\nimport { queryRoutes } from \"@/routes/query.routes.js\";\nimport { recordsRoutes } from \"@/routes/records.routes.js\";\nimport { tablesRoutes } from \"@/routes/tables.routes.js\";\nimport { websocketRoutes } from \"@/routes/websocket.routes.js\";\n\nconst getCoreDistPath = () => {\n\tif (process.env.NODE_ENV === \"development\") {\n\t\treturn path.resolve(process.cwd(), \"../core/dist\");\n\t}\n\n\tconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\treturn path.resolve(__dirname, \"./core-dist\");\n};\n\nexport const createServer = () => {\n\tconst app = new Hono({ strict: false });\n\tconst { upgradeWebSocket, injectWebSocket } = createNodeWebSocket({ app: app as any });\n\n\tapp.use(\"/*\", cors());\n\n\tif (process.env.NODE_ENV === \"development\") {\n\t\tapp.use(logger());\n\t}\n\n\tapp.use(\n\t\t\"/favicon.ico\",\n\t\tserveStatic({ path: path.resolve(getCoreDistPath(), \"favicon.ico\") }),\n\t);\n\n\tapp.use(\"*\", async (c, next) => {\n\t\tc.header(\"Access-Control-Allow-Origin\", \"*\");\n\t\tc.header(\"Access-Control-Allow-Methods\", \"GET, POST, PUT, DELETE, OPTIONS\");\n\t\tc.header(\"Access-Control-Allow-Headers\", \"Content-Type\");\n\t\tawait next();\n\t});\n\n\tapp.route(\"/ws\", websocketRoutes(upgradeWebSocket));\n\tapp.route(\"/databases\", databasesRoutes);\n\tapp.route(\"/tables\", tablesRoutes);\n\tapp.route(\"/tables/:tableName/columns\", columnsRoutes);\n\tapp.route(\"/tables/:tableName/data\", dataRoutes);\n\tapp.route(\"/records\", recordsRoutes);\n\tapp.route(\"/query\", queryRoutes);\n\tapp.route(\"/chat\", chatRoutes);\n\n\tapp.use(\"/*\", serveStatic({ root: getCoreDistPath() }));\n\n\treturn { app, injectWebSocket };\n};\n","import { intro, outro } from \"@clack/prompts\";\nimport { serve } from \"@hono/node-server\";\nimport open from \"open\";\nimport color from \"picocolors\";\n\nimport { args } from \"@/cmd/args.js\";\nimport { getDatabaseUrl } from \"@/cmd/get-db-url.js\";\nimport { loadEnv } from \"@/cmd/load-env.js\";\nimport { showHelp } from \"@/cmd/show-help.js\";\nimport { showStatus } from \"@/cmd/show-status.js\";\nimport { showVersion } from \"@/cmd/show-version.js\";\nimport { DEFAULTS } from \"@/utils/defaults.js\";\n\nexport const main = async () => {\n\tconst { env, port, databaseUrl, varName, status, help, version } = args();\n\n\t// Handle help flag\n\tif (help) {\n\t\tshowHelp();\n\t\tprocess.exit(0);\n\t}\n\n\t// Handle version flag\n\tif (version) {\n\t\tshowVersion();\n\t\tprocess.exit(0);\n\t}\n\n\t// Handle status flag\n\tif (status) {\n\t\tawait showStatus(env, databaseUrl, varName);\n\t\tprocess.exit(0);\n\t}\n\n\tintro(color.inverse(\" db-studio \"));\n\n\tconst PORT = port ? parseInt(port, 10) : DEFAULTS.PORT;\n\tconst VAR_NAME = varName || DEFAULTS.VAR_NAME;\n\tconst ENV = env ? await loadEnv(env) : await loadEnv(DEFAULTS.ENV);\n\tconst DATABASE_URL = databaseUrl ? databaseUrl : await getDatabaseUrl(ENV, VAR_NAME);\n\n\t// Set DATABASE_URL in process.env before importing createServer\n\t// This ensures the db pool is initialized with the correct connection string\n\tprocess.env.DATABASE_URL = DATABASE_URL;\n\n\t// Import createServer dynamically after setting DATABASE_URL\n\tconst { createServer } = await import(\"./utils/create-server.js\");\n\tconst { app, injectWebSocket } = createServer();\n\tconst server = serve({\n\t\tfetch: app.fetch,\n\t\tport: PORT,\n\t});\n\tinjectWebSocket(server);\n\n\toutro(color.green(`Server running at ${color.cyan(`http://localhost:${PORT}`)}`));\n\n\tif (process.env.NODE_ENV && process.env.NODE_ENV !== \"development\") {\n\t\tawait open(`http://localhost:${PORT}`);\n\t}\n};\n\nmain().catch((err) => {\n\tconsole.error(color.red(`❌ Unexpected error: ${err.message}`));\n\tprocess.exit(1);\n});\n","import { program } from \"commander\";\n\ntype Args = {\n\tenv?: string;\n\tport?: string;\n\tdatabaseUrl?: string;\n\tvarName?: string;\n\tstatus?: boolean;\n\thelp?: boolean;\n\tversion?: boolean;\n};\n\n/**\n * Get the arguments from the command line\n */\nexport const args = () => {\n\tprogram\n\t\t.name(\"db-studio\")\n\t\t.option(\"-e, --env <path>\", \"Path to custom .env file\")\n\t\t.option(\"-p, --port <port>\", \"Port to run the server on\")\n\t\t.option(\"-d, --database-url <url>\", \"Database URL to use\")\n\t\t.option(\n\t\t\t\"-n, --var-name <name>\",\n\t\t\t\"Custom environment variable name (default: DATABASE_URL)\",\n\t\t)\n\t\t.option(\"-s, --status\", \"Show status of the server\")\n\t\t.option(\"-h, --help\", \"Show help\")\n\t\t.option(\"-v, --version\", \"Show version\")\n\t\t.parse(process.argv);\n\n\treturn program.opts<Args>();\n};\n","import { readFile } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport { cancel, isCancel, note, select, spinner, text } from \"@clack/prompts\";\nimport { type DotenvParseOutput, parse as parseDotenv } from \"dotenv\";\nimport color from \"picocolors\";\n\n/**\n * Get the database URL from the environment variables\n */\nexport const getDatabaseUrl = async (\n\tenv?: DotenvParseOutput | null,\n\tvarName?: string,\n) => {\n\tconst envVarName = varName || \"DATABASE_URL\";\n\n\tif (env?.[envVarName]) {\n\t\treturn env[envVarName];\n\t}\n\n\tconst s = spinner();\n\ts.start(\"Looking for database connection...\");\n\n\tif (!env) {\n\t\tnote(color.red(\"No .env file found in current directory\"));\n\t} else {\n\t\tnote(color.red(`${envVarName} not found in .env`));\n\t}\n\n\tconst choice = await select({\n\t\tmessage: `How do you want to provide ${envVarName}?`,\n\t\toptions: [\n\t\t\t{ value: \"manual\", label: \"Enter connection string manually\" },\n\t\t\t{ value: \"other-env\", label: \"Use different .env file\" },\n\t\t\t// todo: add multiple db connections support\n\t\t\t{ value: \"cancel\", label: \"Cancel / Exit\" },\n\t\t],\n\t\tinitialValue: \"manual\",\n\t});\n\tif (isCancel(choice) || choice === \"cancel\") {\n\t\tcancel(\"No database connection provided. Exiting...\");\n\t\tprocess.exit(0);\n\t}\n\n\tif (choice === \"other-env\") {\n\t\ts.start(\"Waiting for path...\");\n\t\tconst customPath = await text({\n\t\t\tmessage: \"Enter path to .env file\",\n\t\t\tplaceholder: \"~/projects/myapp/.env.local or ./special.env\",\n\t\t\tvalidate(value: string) {\n\t\t\t\tif (!value.trim()) return \"Path is required\";\n\t\t\t},\n\t\t});\n\n\t\tif (isCancel(customPath)) {\n\t\t\tcancel(\"Cancelled.\");\n\t\t\tprocess.exit(0);\n\t\t}\n\n\t\ts.stop(\"Trying custom .env...\");\n\n\t\tconst customEnvPath = resolve(customPath);\n\t\ttry {\n\t\t\tconst content = await readFile(customEnvPath, \"utf-8\");\n\t\t\tconst parsed = parseDotenv(content);\n\t\t\tif (parsed[envVarName]) {\n\t\t\t\treturn parsed[envVarName];\n\t\t\t}\n\t\t\tthrow new Error(`${envVarName} still missing in custom file`);\n\t\t} catch (e: unknown) {\n\t\t\tconst error = e as Error;\n\t\t\tcancel(`Cannot read or parse file: ${color.dim(error.message)}`);\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\n\t// 3. Manual input\n\ts.stop(\"Manual input...\");\n\n\tconst dbUrl = await text({\n\t\tmessage: `Paste your ${envVarName}`,\n\t\tplaceholder: \"postgresql://user:password@localhost:5432/mydb\",\n\t\tvalidate(value: string) {\n\t\t\tif (!value.trim()) return \"Connection string is required!\";\n\t\t\ttry {\n\t\t\t\tnew URL(value); // very basic check\n\t\t\t\treturn undefined;\n\t\t\t} catch {\n\t\t\t\treturn \"Must be a valid URL format\";\n\t\t\t}\n\t\t},\n\t});\n\n\tif (isCancel(dbUrl)) {\n\t\tcancel(\"Cancelled.\");\n\t\tprocess.exit(0);\n\t}\n\n\treturn dbUrl.trim();\n};\n","import { access, readFile } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport { parse as parseDotenv } from \"dotenv\";\n\n/**\n * Load the environment variables from the file\n */\nexport const loadEnv = async (env?: string) => {\n\tconst envPath = env ? resolve(env) : resolve(process.cwd(), \".env\");\n\n\ttry {\n\t\tawait access(envPath);\n\t\tconst content = await readFile(envPath, \"utf-8\");\n\t\treturn parseDotenv(content);\n\t} catch (err) {\n\t\tif (err instanceof Error && err.message.includes(\"ENOENT\")) {\n\t\t\treturn null; // we'll handle missing file later\n\t\t}\n\t\tthrow err;\n\t}\n};\n","import { intro, outro } from \"@clack/prompts\";\nimport color from \"picocolors\";\n\n/**\n * Display help information\n */\nexport const showHelp = () => {\n\tintro(color.inverse(\" db-studio \"));\n\n\tconsole.log(color.bold(\"\\nUsage:\"));\n\tconsole.log(\" db-studio [options]\\n\");\n\n\tconsole.log(color.bold(\"Options:\"));\n\tconsole.log(\" -e, --env <path> Path to custom .env file\");\n\tconsole.log(\" -p, --port <port> Port to run the server on (default: 3333)\");\n\tconsole.log(\" -d, --database-url <url> Database URL to use\");\n\tconsole.log(\n\t\t\" -n, --var-name <name> Custom environment variable name (default: DATABASE_URL)\",\n\t);\n\tconsole.log(\" -s, --status Show status of the database connection\");\n\tconsole.log(\" -h, --help Show this help message\");\n\tconsole.log(\" -v, --version Show version number\\n\");\n\n\tconsole.log(color.bold(\"Examples:\"));\n\tconsole.log(\" db-studio\");\n\tconsole.log(\" db-studio -e .env.local\");\n\tconsole.log(\" db-studio -p 4000\");\n\tconsole.log(\" db-studio -d postgresql://user:pass@localhost:5432/mydb\");\n\tconsole.log(\" db-studio -n MY_DATABASE_URL\");\n\tconsole.log(\" db-studio -e .env.production -n PROD_DB_URL\");\n\tconsole.log(\" db-studio --status\\n\");\n\n\toutro(color.green(\"For more information, visit: https://dbstudio.sh/docs\"));\n};\n","import { intro, note, outro } from \"@clack/prompts\";\nimport color from \"picocolors\";\nimport { loadEnv } from \"@/cmd/load-env.js\";\nimport { DEFAULTS } from \"@/utils/defaults.js\";\n\n/**\n * Show connection status\n */\nexport const showStatus = async (\n\tenv?: string,\n\tdatabaseUrl?: string,\n\tvarName?: string,\n) => {\n\tintro(color.inverse(\" db-studio \"));\n\n\tconst envVarName = varName || DEFAULTS.VAR_NAME;\n\tlet foundUrl: string | null = null;\n\n\t// Check if DATABASE_URL is provided via CLI\n\tif (databaseUrl) {\n\t\tfoundUrl = databaseUrl;\n\t} else {\n\t\t// Try to load from .env file\n\t\tconst ENV = env ? await loadEnv(env) : await loadEnv(DEFAULTS.ENV);\n\t\tif (ENV?.[envVarName]) {\n\t\t\tfoundUrl = ENV[envVarName];\n\t\t}\n\t}\n\n\tif (foundUrl) {\n\t\toutro(color.green(`✓ Database connection configured (using ${envVarName})`));\n\t} else {\n\t\tnote(color.red(`✗ ${envVarName} not found`), \"Status\");\n\t\tconsole.log(color.yellow(\"\\n To configure database connection:\"));\n\t\tconsole.log(color.dim(` • Add ${envVarName} to your .env file`));\n\t\tconsole.log(color.dim(\" • Use -d flag: db-studio -d <url>\"));\n\t\tconsole.log(color.dim(\" • Use -e flag: db-studio -e <path-to-env>\"));\n\t\tconsole.log(color.dim(\" • Use -n flag: db-studio -n <var-name>\\n\"));\n\n\t\toutro(color.yellow(\"⚠ No database connection configured\"));\n\t}\n};\n","import { intro, outro } from \"@clack/prompts\";\nimport color from \"picocolors\";\nimport packageJson from \"../../package.json\" with { type: \"json\" };\n\n/**\n * Display version information\n */\nexport const showVersion = () => {\n\tintro(color.inverse(\" db-studio \"));\n\toutro(color.green(`🚀 db-studio v${packageJson.version}`));\n};\n","{\n \"name\": \"db-studio\",\n \"type\": \"module\",\n \"version\": \"1.2.8\",\n \"description\": \"Modern database client for PostgreSQL with spreadsheet-like grid, AI-powered SQL assistance, ER diagrams, fast data browsing and editing. CLI tool, upcoming desktop & web versions.\",\n \"keywords\": [\n \"database\",\n \"database client\",\n \"postgres\",\n \"postgresql\",\n \"database gui\",\n \"sql client\",\n \"database studio\",\n \"postgres gui\",\n \"ai sql\",\n \"sql editor\",\n \"er diagram\",\n \"database management\",\n \"data browser\",\n \"spreadsheet database\",\n \"postgres admin\",\n \"mysql client\",\n \"sqlite client\",\n \"database tool\",\n \"developer tools\"\n ],\n \"author\": \"Hüsam 🥑 <devhsmq@gmail.com>\",\n \"homepage\": \"https://dbstudio.sh\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/husamql3/db-studio.git\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/husamql3/db-studio/issues\"\n },\n \"license\": \"MIT\",\n \"bin\": {\n \"db-studio\": \"./dist/index.js\"\n },\n \"files\": [\n \"dist\"\n ],\n \"scripts\": {\n \"dev\": \"NODE_ENV=development tsx watch src/index.ts\",\n \"build\": \"tsup\",\n \"build:release\": \"tsup --minify --sourcemap\",\n \"start\": \"node dist/index.js\",\n \"check\": \"biome check --write --unsafe --verbose\"\n },\n \"dependencies\": {\n \"@clack/prompts\": \"^0.11.0\",\n \"@hono/node-server\": \"^1.19.7\",\n \"@hono/node-ws\": \"^1.2.0\",\n \"@hono/zod-validator\": \"^0.7.6\",\n \"@tanstack/ai-openai\": \"^0.2.1\",\n \"@upstash/redis\": \"^1.36.1\",\n \"commander\": \"^12.1.0\",\n \"dotenv\": \"^16.4.7\",\n \"hono\": \"^4.10.4\",\n \"open\": \"^10.0.2\",\n \"pg\": \"^8.13.1\",\n \"picocolors\": \"^1.1.1\",\n \"zod\": \"^4.2.1\"\n },\n \"devDependencies\": {\n \"@biomejs/biome\": \"^2.2.6\",\n \"@biomejs/cli-linux-x64\": \"^2.2.6\",\n \"@types/node\": \"^20.11.17\",\n \"@types/pg\": \"^8.16.0\",\n \"tsup\": \"^8.5.1\",\n \"tsx\": \"^4.7.1\",\n \"typescript\": \"^5.8.3\",\n \"wrangler\": \"^4.4.0\"\n }\n}"],"mappings":"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","names":["DEFAULTS","init_defaults","__esmMin","Pool","dbInstance","getPool","db","init_db","__esmMin","err","error","_target","prop","Pool","DatabaseManager","databaseManager","getDbPool","init_db_manager","__esmMin","databaseUrl","url","error","database","connectionString","poolConfig","pool","err","closePromises","mapPostgresToDataType","pgType","normalized","DataTypes","standardizeDataTypeLabel","StandardizedDataType","init_column_types","__esmMin","getTableColumns","init_table_columns_dao","__esmMin","init_db_manager","init_column_types","tableName","database","client","getDbPool","r","parsedEnumValues","mapPostgresToDataType","standardizeDataTypeLabel","getTableNames","client","db","getTableDescription","tableName","getSampleData","convertColumnInfo","col","column","extractRelationships","tables","relationships","table","toTable","toColumn","getDatabaseSchema","options","includeSampleData","includeDescriptions","tablePromises","columns","description","sampleData","getTableColumns","error","getDetailedSchema","init_table_details_schema","__esmMin","init_db","init_table_columns_dao","generateSystemPrompt","schema","formatSchemaForPrompt","output","table","col","pkIndicator","fkIndicator","nullable","rel","init_system_prompt_generator","__esmMin","Hono","chatRoutes","init_chat_routes","__esmMin","init_table_details_schema","init_defaults","init_system_prompt_generator","c","messages","conversationId","schema","getDetailedSchema","systemPrompt","generateSystemPrompt","payload","proxyResponse","DEFAULTS","errorData","readable","writable","error","errorMessage","z","FOREIGN_KEY_ACTIONS","foreignKeyActionSchema","fieldDataSchema","foreignKeyDataSchema","createTableSchema","tableNameParamSchema","tableDataQuerySchema","insertRecordSchema","updateRecordsSchema","deleteRecordsSchema","executeQuerySchema","databaseQuerySchema","init_create_table_type","__esmMin","val","handleConnectionError","init_error_handler","__esmMin","c","error","fallbackMessage","errorMessage","isConnectionError","err","zValidator","Hono","columnsRoutes","init_columns_routes","__esmMin","init_table_columns_dao","init_create_table_type","init_error_handler","tableNameParamSchema","databaseQuerySchema","c","tableName","database","columns","getTableColumns","error","handleConnectionError","buildWhereClause","buildSortClause","getTableData","init_tables_data_dao","__esmMin","init_db_manager","filters","conditions","values","filter","paramIndex","columnName","sorts","order","sort","tableName","page","pageSize","database","sortClause","whereClause","filterValues","client","getDbPool","offset","countRes","totalRows","totalPages","limitParamIndex","offsetParamIndex","zValidator","Hono","dataRoutes","init_data_routes","__esmMin","init_tables_data_dao","init_create_table_type","init_error_handler","tableNameParamSchema","tableDataQuerySchema","c","tableName","page","pageSize","sortParam","order","filters","sort","parsed","database","data","getTableData","error","handleConnectionError","getDatabasesList","getDbPool","getCurrentDatabase","getDatabaseConnectionInfo","row","databaseUrl","host","port","url","init_database_list_dao","__esmMin","init_db_manager","Hono","databasesRoutes","init_databases_routes","__esmMin","init_database_list_dao","c","databases","getDatabasesList","current","getCurrentDatabase","info","getDatabaseConnectionInfo","executeQuery","init_query_dao","__esmMin","init_db_manager","params","query","database","client","getDbPool","cleanedQuery","startTime","result","duration","field","error","errorMessage","zValidator","Hono","queryRoutes","init_query_routes","__esmMin","init_query_dao","init_create_table_type","executeQuerySchema","c","query","database","data","executeQuery","error","errorMessage","getForeignKeyReferences","getRelatedRecords","deleteRecords","forceDeleteRecords","init_delete_records_dao","__esmMin","init_db_manager","tableName","database","getDbPool","row","primaryKeys","fkConstraints","relatedRecords","pool","constraintsByTable","constraint","key","pkValues","pk","_tableColumn","constraints","placeholders","_","i","query","result","params","client","pkColumn","deleteSQL","error","totalRelatedDeleted","deletedTables","deleteRelatedRecursively","targetTable","targetColumn","values","nestedFks","nestedFk","selectQuery","nestedValues","deleteQuery","deleteResult","mainDeleted","insertRecord","init_insert_record_dao","__esmMin","init_db_manager","params","tableName","data","database","client","getDbPool","columns","values","placeholders","_","index","columnNames","col","insertSQL","result","error","updateRecords","init_update_records_dao","__esmMin","init_db_manager","params","tableName","updates","primaryKey","database","client","getDbPool","updatesByRow","update","pkValue","results","totalUpdated","rowUpdates","setClauses","u","index","values","updateSQL","result","error","zValidator","Hono","z","databaseQuerySchema","recordsRoutes","init_records_routes","__esmMin","init_delete_records_dao","init_insert_record_dao","init_update_records_dao","init_create_table_type","insertRecordSchema","c","body","tableName","data","database","result","insertRecord","error","errorDetail","updateRecordsSchema","updates","primaryKey","updateRecords","deleteRecordsSchema","primaryKeys","deleteRecords","forceDeleteRecords","createTable","init_create_table_dao","__esmMin","init_db_manager","tableData","database","tableName","fields","foreignKeys","client","getDbPool","columnDefinitions","field","columnDef","foreignKeyConstraints","fk","allDefinitions","createTableSQL","error","getTablesList","init_table_list_dao","__esmMin","init_db_manager","database","client","getDbPool","r","zValidator","Hono","tablesRoutes","init_tables_routes","__esmMin","init_create_table_dao","init_table_list_dao","init_create_table_type","init_error_handler","databaseQuerySchema","c","database","tablesList","getTablesList","error","handleConnectionError","createTableSchema","body","data","createTable","errorDetail","Hono","checkDatabaseConnection","DB_CHECK_INTERVAL","DB_CHECK_TIMEOUT","websocketRoutes","init_websocket_routes","__esmMin","init_db","client","db","error","upgradeWebSocket","app","interval","_event","ws","status","_","reject","err","event","_ws","create_server_exports","__export","createServer","path","fileURLToPath","serveStatic","createNodeWebSocket","Hono","cors","logger","getCoreDistPath","init_create_server","__esmMin","init_chat_routes","init_columns_routes","init_data_routes","init_databases_routes","init_query_routes","init_records_routes","init_tables_routes","init_websocket_routes","__dirname","app","upgradeWebSocket","injectWebSocket","c","next","websocketRoutes","databasesRoutes","tablesRoutes","columnsRoutes","dataRoutes","recordsRoutes","queryRoutes","chatRoutes","intro","outro","serve","open","color","program","args","readFile","resolve","cancel","isCancel","note","select","spinner","text","parseDotenv","color","getDatabaseUrl","env","varName","envVarName","s","choice","customPath","value","customEnvPath","content","parsed","e","error","dbUrl","access","readFile","resolve","parseDotenv","loadEnv","env","envPath","content","err","intro","outro","color","showHelp","intro","note","outro","color","init_defaults","showStatus","env","databaseUrl","varName","intro","color","envVarName","DEFAULTS","foundUrl","ENV","loadEnv","outro","note","intro","outro","color","package_default","showVersion","intro","color","outro","package_default","init_defaults","main","env","port","databaseUrl","varName","status","help","version","args","showHelp","showVersion","showStatus","intro","color","PORT","DEFAULTS","VAR_NAME","ENV","loadEnv","DATABASE_URL","getDatabaseUrl","createServer","app","injectWebSocket","server","serve","outro","open","err"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "db-studio",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.2.
|
|
4
|
+
"version": "1.2.8",
|
|
5
5
|
"description": "Modern database client for PostgreSQL with spreadsheet-like grid, AI-powered SQL assistance, ER diagrams, fast data browsing and editing. CLI tool, upcoming desktop & web versions.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"database",
|