db-studio 1.2.25 → 1.3.25
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 +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -225,5 +225,5 @@ ORDER BY t.table_name;
|
|
|
225
225
|
FROM pg_index i
|
|
226
226
|
JOIN pg_attribute a ON a.attrelid = i.indrelid AND a.attnum = ANY(i.indkey)
|
|
227
227
|
WHERE i.indrelid = $1::regclass AND i.indisprimary
|
|
228
|
-
ORDER BY array_position(i.indkey, a.attnum)`,[o])).rows.map(a=>a.column_name)},Do=async({tableName:t,cursor:e="",limit:o=50,direction:r="asc",sort:a=[],order:n="asc",filters:i=[],db:c})=>{let s=y(c),u=await Ir(s,t),l=[],p=n;Array.isArray(a)&&a.length>0?(l=a.map(R=>R.columnName),p=a[0].direction):typeof a=="string"&&a&&(l=[a]);let b=[...l,...u.filter(R=>!l.includes(R))];b.length===0&&b.push("ctid");let{clause:E,values:d}=To(i),h="",x=[];if(e){let R=qr(e);if(R){let P=Eo(R,r,p,d.length+1);h=P.clause,x=P.values}}let U="";E&&h?U=`WHERE ${E.replace(/^WHERE\s+/i,"")} AND ${h}`:E?U=E:h&&(U=`WHERE ${h}`);let F=So((Array.isArray(a),a),n),H=F;r==="desc"?F?H=F.replace(/\bASC\b/gi,"TEMP_DESC").replace(/\bDESC\b/gi,"ASC").replace(/TEMP_DESC/g,"DESC"):H=`ORDER BY ${b.map(P=>`"${P}" ${p==="asc"?"DESC":"ASC"}`).join(", ")}`:!F&&b.length>0&&(H=`ORDER BY ${b.map(P=>`"${P}" ${p.toUpperCase()}`).join(", ")}`);let ye=await s.query(`SELECT COUNT(*) as total FROM "${t}" ${E}`,d),O=Number(ye.rows[0].total),Y=d.length+x.length+1,M=await s.query(`SELECT * FROM "${t}" ${U} ${H} LIMIT $${Y}`,[...d,...x,o+1]),C=M.fields&&M.fields.length>0?M.rows.filter(R=>Object.keys(R).length>0):M.rows,q=C.length>o;q&&(C=C.slice(0,o)),r==="desc"&&(C=C.reverse());let G=null,be=null;if(C.length>0){let R=C[0],P=C[C.length-1],Z=Po=>({values:Object.fromEntries(b.map($e=>[$e,Po[$e]])),sortColumns:b});r==="asc"?(q&&(G=ue(Z(P))),e&&(be=ue(Z(R)))):(e&&(G=ue(Z(P))),q&&(be=ue(Z(R))))}return{data:C,meta:{limit:o,total:O,hasNextPage:r==="asc"?q:!!e,hasPreviousPage:r==="asc"?!!e:q,nextCursor:G,prevCursor:be}}}});import{utils as X,write as Lr}from"xlsx";function Co({cols:t,rows:e,format:o,tableName:r}){switch(o){case"json":{let a=JSON.stringify(e??[],null,2);return new Uint8Array(Buffer.from(a,"utf-8"))}case"csv":{let a=[t,...e?.map(c=>t?.map(s=>c[s]))??[]],n=X.aoa_to_sheet(a),i=X.sheet_to_csv(n);return new Uint8Array(Buffer.from(i,"utf-8"))}case"xlsx":{let a=[t,...e?.map(s=>t?.map(u=>s[u]))??[]],n=X.aoa_to_sheet(a),i=X.book_new();X.book_append_sheet(i,n,r.slice(0,31));let c=Lr(i,{bookType:"xlsx",type:"buffer"});return new Uint8Array(c)}}}var xo=m(()=>{"use strict"});import{zValidator as _}from"@hono/zod-validator";import{Hono as Or}from"hono";var No,vo=m(()=>{"use strict";L();mo();fo();bo();Ne();go();Ro();xo();No=new Or().basePath("/tables").get("/",_("query",T),async t=>{let{db:e}=t.req.valid("query"),o=await ho(e);return t.json({data:o},200)}).post("/",_("query",T),_("json",ct),async t=>{let{db:e}=t.req.valid("query"),o=t.req.valid("json");return await lo({tableData:o,db:e}),t.json({data:`Table ${o.tableName} created successfully`},200)}).delete("/:tableName/columns/:columnName",_("query",dt),_("param",ne),async t=>{let{db:e,cascade:o}=t.req.valid("query"),{tableName:r,columnName:a}=t.req.valid("param"),{deletedCount:n}=await po({tableName:r,columnName:a,cascade:o,db:e});return t.json({data:`Column "${a}" deleted successfully from table "${r}" with ${n} rows deleted`},200)}).get("/:tableName/columns",_("query",T),_("param",ae),async t=>{let{db:e}=t.req.valid("query"),{tableName:o}=t.req.valid("param"),r=await ce({tableName:o,db:e});return t.json({data:r},200)}).get("/:tableName/data",_("param",ae),_("query",wt),async t=>{let{tableName:e}=t.req.valid("param"),{cursor:o,limit:r,direction:a,sort:n,order:i,filters:c,db:s}=t.req.valid("query"),u=await Do({tableName:e,cursor:o,limit:r,direction:a,sort:n,order:i,filters:c,db:s});return t.json({data:u},200)}).get("/:tableName/export",_("param",ae),_("query",Tt),async t=>{let{tableName:e}=t.req.valid("param"),{db:o,format:r}=t.req.valid("query"),{cols:a,rows:n}=await yo({tableName:e,db:o}),i=Co({cols:a,rows:n,format:r,tableName:e}),c;switch(r){case"csv":c="text/csv";break;case"xlsx":c="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";break;case"json":c="application/json";break}return new Response(i,{headers:{"Content-Type":c??"","Content-Disposition":`attachment; filename="${e}_export.${r}"`}})})});var _o={};Io(_o,{createServer:()=>zr});import fe from"path";import{fileURLToPath as kr}from"url";import{serveStatic as pe}from"@hono/node-server/serve-static";import{zValidator as jr}from"@hono/zod-validator";import{Hono as Ur}from"hono";import{cors as Fr}from"hono/cors";import{logger as Hr}from"hono/logger";import{prettyJSON as Mr}from"hono/pretty-json";var de,zr,Ao=m(()=>{"use strict";L();_t();jt();Kt();Jt();co();vo();de=()=>{if(process.env.NODE_ENV==="development")return fe.resolve(process.cwd(),"../core/dist");let t=fe.dirname(kr(import.meta.url));return fe.resolve(t,"./core-dist")},zr=()=>({app:new Ur({strict:!1}).use("/*",Fr()).use(Mr({space:2})).use(process.env.NODE_ENV==="development"?Hr():(e,o)=>o()).use("/favicon.ico",pe({path:fe.resolve(de(),"favicon.ico")})).use("*",async(e,o)=>{e.header("Access-Control-Allow-Origin","*"),e.header("Access-Control-Allow-Methods","GET, POST, PUT, DELETE, OPTIONS"),e.header("Access-Control-Allow-Headers","Content-Type"),await o()}).onError(Nt).route("/",Wt).use("/assets/*",pe({root:de()})).use("/image.png",pe({root:de()})).use("/:dbType/*",jr("param",et,vt)).use("/:dbType/*",async(e,o)=>{let r=e.req.param("dbType");e.set("dbType",r),await o()}).route("/:dbType",No).route("/:dbType",io).route("/:dbType",Gt).route("/:dbType",kt).use("/*",pe({root:de()}))})});ee();import{intro as Br,outro as Wr}from"@clack/prompts";import{serve as Kr}from"@hono/node-server";import Vr from"open";import Ae from"picocolors";import{program as ke}from"commander";var je=()=>(ke.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),ke.opts());import{readFile as Lo}from"fs/promises";import{resolve as Oo}from"path";import{cancel as te,isCancel as ge,note as Ue,select as ko,spinner as jo,text as Fe}from"@clack/prompts";import{parse as Uo}from"dotenv";import Te from"picocolors";var He=async(t,e)=>{let o=e||"DATABASE_URL";if(t?.[o])return t[o];if(process.env[o])return process.env[o];let r=jo();r.start("Looking for database connection..."),t?Ue(Te.red(`${o} not found in .env or process.env`)):Ue(Te.red(`No .env file found and ${o} not set in process.env`));let a=await ko({message:`How do you want to provide ${o}?`,options:[{value:"manual",label:"Enter connection string manually"},{value:"other-env",label:"Use different .env file"},{value:"cancel",label:"Cancel / Exit"}],initialValue:"manual"});if((ge(a)||a==="cancel")&&(te("No database connection provided. Exiting..."),process.exit(0)),a==="other-env"){r.start("Waiting for path...");let i=await Fe({message:"Enter path to .env file",placeholder:"~/projects/myapp/.env.local or ./special.env",validate(s){if(!s.trim())return"Path is required"}});ge(i)&&(te("Cancelled."),process.exit(0)),r.stop("Trying custom .env...");let c=Oo(i);try{let s=await Lo(c,"utf-8"),u=Uo(s);if(u[o])return u[o];throw new Error(`${o} still missing in custom file`)}catch(s){let u=s;te(`Cannot read or parse file: ${Te.dim(u.message)}`),process.exit(1)}}r.stop("Manual input...");let n=await Fe({message:`Paste your ${o}`,placeholder:"postgresql://user:password@localhost:5432/mydb",validate(i){if(!i.trim())return"Connection string is required!";try{new URL(i);return}catch{return"Must be a valid URL format"}}});return ge(n)&&(te("Cancelled."),process.exit(0)),n.trim()};import{access as Fo,readFile as Ho}from"fs/promises";import{dirname as Mo,resolve as Se}from"path";import{parse as zo}from"dotenv";var Bo=async t=>{let e=Se(t);for(;;){let o=Se(e,".env");try{return await Fo(o),o}catch{}let r=Mo(e);if(r===e)return null;e=r}},z=async t=>{let e;if(t?e=Se(t):e=await Bo(process.cwd()),!e)return null;try{let o=await Ho(e,"utf-8");return zo(o)}catch(o){if(o instanceof Error&&o.message.includes("ENOENT"))return null;throw o}};he();import{intro as Wo,outro as Ko}from"@clack/prompts";import Me from"picocolors";var ze=()=>{Wo(Me.inverse(" db-studio ")),Ko(Me.green(`For more information, visit: ${Le.SITE_DOCS_LINK}`))};ee();import{intro as Vo,note as Qo,outro as Be}from"@clack/prompts";import oe from"picocolors";var We=async(t,e,o)=>{Vo(oe.inverse(" db-studio "));let r=o||k.VAR_NAME,a=null;if(e)a=e;else{let n=t?await z(t):await z();n?.[r]?a=n[r]:process.env[r]&&(a=process.env[r]??null)}a?Be(oe.green(`\u2713 Database connection configured (using ${r})`)):(Qo(oe.red(`\u2717 ${r} not found`),"Status"),Be(oe.yellow("\u26A0 No database connection configured")))};import{intro as Go,outro as Jo}from"@clack/prompts";import Ve from"picocolors";var Ke={name:"db-studio",type:"module",version:"1.2.25",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 --minify --sourcemap",prepack:"cd ../core && bun run build && cd ../server && bun run build",start:"node dist/index.js",check:"biome check --write --unsafe",test:"vitest run","test:watch":"vitest","test:coverage":"vitest run --coverage"},dependencies:{"@clack/prompts":"^0.11.0","@hono/node-server":"^1.19.7","@hono/zod-validator":"^0.7.6",commander:"^12.1.0",dotenv:"^16.4.7",hono:"^4.10.4",open:"^10.0.2",pg:"^8.13.1",picocolors:"^1.1.1",xlsx:"^0.18.5",zod:"^4.2.1"},devDependencies:{"@biomejs/biome":"^2.2.6","@types/node":"^20.11.17","@types/pg":"^8.16.0","@vitest/coverage-v8":"^4.0.17",shared:"workspace:*",tsup:"^8.5.1",tsx:"^4.7.1",typescript:"^5.8.3",vitest:"^4.0.17"}};var Qe=()=>{Go(Ve.inverse(" db-studio ")),Jo(Ve.green(`\u{1F680} db-studio v${Ke.version}`))};var Qr=async()=>{let{env:t,port:e,databaseUrl:o,varName:r,status:a,help:n,version:i}=je();n&&(ze(),process.exit(0)),i&&(Qe(),process.exit(0)),a&&(await We(t,o,r),process.exit(0)),Br(Ae.inverse(" db-studio "));let c=e?parseInt(e,10):k.PORT,s=r||k.VAR_NAME,u=t?await z(t):await z(),l=o||await He(u,s);process.env.DATABASE_URL=l;let{createServer:p}=await Promise.resolve().then(()=>(Ao(),_o)),{app:b}=p();Kr({fetch:b.fetch,port:c}),Wr(Ae.green(`Server running at ${Ae.cyan(`http://localhost:${c}`)}`)),process.env.NODE_ENV&&process.env.NODE_ENV!=="development"&&await Vr(`http://localhost:${c}`)};Qr().catch(t=>{process.exit(1)});export{Qr as main};
|
|
228
|
+
ORDER BY array_position(i.indkey, a.attnum)`,[o])).rows.map(a=>a.column_name)},Do=async({tableName:t,cursor:e="",limit:o=50,direction:r="asc",sort:a=[],order:n="asc",filters:i=[],db:c})=>{let s=y(c),u=await Ir(s,t),l=[],p=n;Array.isArray(a)&&a.length>0?(l=a.map(R=>R.columnName),p=a[0].direction):typeof a=="string"&&a&&(l=[a]);let b=[...l,...u.filter(R=>!l.includes(R))];b.length===0&&b.push("ctid");let{clause:E,values:d}=To(i),h="",x=[];if(e){let R=qr(e);if(R){let P=Eo(R,r,p,d.length+1);h=P.clause,x=P.values}}let U="";E&&h?U=`WHERE ${E.replace(/^WHERE\s+/i,"")} AND ${h}`:E?U=E:h&&(U=`WHERE ${h}`);let F=So((Array.isArray(a),a),n),H=F;r==="desc"?F?H=F.replace(/\bASC\b/gi,"TEMP_DESC").replace(/\bDESC\b/gi,"ASC").replace(/TEMP_DESC/g,"DESC"):H=`ORDER BY ${b.map(P=>`"${P}" ${p==="asc"?"DESC":"ASC"}`).join(", ")}`:!F&&b.length>0&&(H=`ORDER BY ${b.map(P=>`"${P}" ${p.toUpperCase()}`).join(", ")}`);let ye=await s.query(`SELECT COUNT(*) as total FROM "${t}" ${E}`,d),O=Number(ye.rows[0].total),Y=d.length+x.length+1,M=await s.query(`SELECT * FROM "${t}" ${U} ${H} LIMIT $${Y}`,[...d,...x,o+1]),C=M.fields&&M.fields.length>0?M.rows.filter(R=>Object.keys(R).length>0):M.rows,q=C.length>o;q&&(C=C.slice(0,o)),r==="desc"&&(C=C.reverse());let G=null,be=null;if(C.length>0){let R=C[0],P=C[C.length-1],Z=Po=>({values:Object.fromEntries(b.map($e=>[$e,Po[$e]])),sortColumns:b});r==="asc"?(q&&(G=ue(Z(P))),e&&(be=ue(Z(R)))):(e&&(G=ue(Z(P))),q&&(be=ue(Z(R))))}return{data:C,meta:{limit:o,total:O,hasNextPage:r==="asc"?q:!!e,hasPreviousPage:r==="asc"?!!e:q,nextCursor:G,prevCursor:be}}}});import{utils as X,write as Lr}from"xlsx";function Co({cols:t,rows:e,format:o,tableName:r}){switch(o){case"json":{let a=JSON.stringify(e??[],null,2);return new Uint8Array(Buffer.from(a,"utf-8"))}case"csv":{let a=[t,...e?.map(c=>t?.map(s=>c[s]))??[]],n=X.aoa_to_sheet(a),i=X.sheet_to_csv(n);return new Uint8Array(Buffer.from(i,"utf-8"))}case"xlsx":{let a=[t,...e?.map(s=>t?.map(u=>s[u]))??[]],n=X.aoa_to_sheet(a),i=X.book_new();X.book_append_sheet(i,n,r.slice(0,31));let c=Lr(i,{bookType:"xlsx",type:"buffer"});return new Uint8Array(c)}}}var xo=m(()=>{"use strict"});import{zValidator as _}from"@hono/zod-validator";import{Hono as Or}from"hono";var No,vo=m(()=>{"use strict";L();mo();fo();bo();Ne();go();Ro();xo();No=new Or().basePath("/tables").get("/",_("query",T),async t=>{let{db:e}=t.req.valid("query"),o=await ho(e);return t.json({data:o},200)}).post("/",_("query",T),_("json",ct),async t=>{let{db:e}=t.req.valid("query"),o=t.req.valid("json");return await lo({tableData:o,db:e}),t.json({data:`Table ${o.tableName} created successfully`},200)}).delete("/:tableName/columns/:columnName",_("query",dt),_("param",ne),async t=>{let{db:e,cascade:o}=t.req.valid("query"),{tableName:r,columnName:a}=t.req.valid("param"),{deletedCount:n}=await po({tableName:r,columnName:a,cascade:o,db:e});return t.json({data:`Column "${a}" deleted successfully from table "${r}" with ${n} rows deleted`},200)}).get("/:tableName/columns",_("query",T),_("param",ae),async t=>{let{db:e}=t.req.valid("query"),{tableName:o}=t.req.valid("param"),r=await ce({tableName:o,db:e});return t.json({data:r},200)}).get("/:tableName/data",_("param",ae),_("query",wt),async t=>{let{tableName:e}=t.req.valid("param"),{cursor:o,limit:r,direction:a,sort:n,order:i,filters:c,db:s}=t.req.valid("query"),u=await Do({tableName:e,cursor:o,limit:r,direction:a,sort:n,order:i,filters:c,db:s});return t.json({data:u},200)}).get("/:tableName/export",_("param",ae),_("query",Tt),async t=>{let{tableName:e}=t.req.valid("param"),{db:o,format:r}=t.req.valid("query"),{cols:a,rows:n}=await yo({tableName:e,db:o}),i=Co({cols:a,rows:n,format:r,tableName:e}),c;switch(r){case"csv":c="text/csv";break;case"xlsx":c="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";break;case"json":c="application/json";break}return new Response(i,{headers:{"Content-Type":c??"","Content-Disposition":`attachment; filename="${e}_export.${r}"`}})})});var _o={};Io(_o,{createServer:()=>zr});import fe from"path";import{fileURLToPath as kr}from"url";import{serveStatic as pe}from"@hono/node-server/serve-static";import{zValidator as jr}from"@hono/zod-validator";import{Hono as Ur}from"hono";import{cors as Fr}from"hono/cors";import{logger as Hr}from"hono/logger";import{prettyJSON as Mr}from"hono/pretty-json";var de,zr,Ao=m(()=>{"use strict";L();_t();jt();Kt();Jt();co();vo();de=()=>{if(process.env.NODE_ENV==="development")return fe.resolve(process.cwd(),"../core/dist");let t=fe.dirname(kr(import.meta.url));return fe.resolve(t,"./core-dist")},zr=()=>({app:new Ur({strict:!1}).use("/*",Fr()).use(Mr({space:2})).use(process.env.NODE_ENV==="development"?Hr():(e,o)=>o()).use("/favicon.ico",pe({path:fe.resolve(de(),"favicon.ico")})).use("*",async(e,o)=>{e.header("Access-Control-Allow-Origin","*"),e.header("Access-Control-Allow-Methods","GET, POST, PUT, DELETE, OPTIONS"),e.header("Access-Control-Allow-Headers","Content-Type"),await o()}).onError(Nt).route("/",Wt).use("/assets/*",pe({root:de()})).use("/image.png",pe({root:de()})).use("/:dbType/*",jr("param",et,vt)).use("/:dbType/*",async(e,o)=>{let r=e.req.param("dbType");e.set("dbType",r),await o()}).route("/:dbType",No).route("/:dbType",io).route("/:dbType",Gt).route("/:dbType",kt).use("/*",pe({root:de()}))})});ee();import{intro as Br,outro as Wr}from"@clack/prompts";import{serve as Kr}from"@hono/node-server";import Vr from"open";import Ae from"picocolors";import{program as ke}from"commander";var je=()=>(ke.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),ke.opts());import{readFile as Lo}from"fs/promises";import{resolve as Oo}from"path";import{cancel as te,isCancel as ge,note as Ue,select as ko,spinner as jo,text as Fe}from"@clack/prompts";import{parse as Uo}from"dotenv";import Te from"picocolors";var He=async(t,e)=>{let o=e||"DATABASE_URL";if(t?.[o])return t[o];if(process.env[o])return process.env[o];let r=jo();r.start("Looking for database connection..."),t?Ue(Te.red(`${o} not found in .env or process.env`)):Ue(Te.red(`No .env file found and ${o} not set in process.env`));let a=await ko({message:`How do you want to provide ${o}?`,options:[{value:"manual",label:"Enter connection string manually"},{value:"other-env",label:"Use different .env file"},{value:"cancel",label:"Cancel / Exit"}],initialValue:"manual"});if((ge(a)||a==="cancel")&&(te("No database connection provided. Exiting..."),process.exit(0)),a==="other-env"){r.start("Waiting for path...");let i=await Fe({message:"Enter path to .env file",placeholder:"~/projects/myapp/.env.local or ./special.env",validate(s){if(!s.trim())return"Path is required"}});ge(i)&&(te("Cancelled."),process.exit(0)),r.stop("Trying custom .env...");let c=Oo(i);try{let s=await Lo(c,"utf-8"),u=Uo(s);if(u[o])return u[o];throw new Error(`${o} still missing in custom file`)}catch(s){let u=s;te(`Cannot read or parse file: ${Te.dim(u.message)}`),process.exit(1)}}r.stop("Manual input...");let n=await Fe({message:`Paste your ${o}`,placeholder:"postgresql://user:password@localhost:5432/mydb",validate(i){if(!i.trim())return"Connection string is required!";try{new URL(i);return}catch{return"Must be a valid URL format"}}});return ge(n)&&(te("Cancelled."),process.exit(0)),n.trim()};import{access as Fo,readFile as Ho}from"fs/promises";import{dirname as Mo,resolve as Se}from"path";import{parse as zo}from"dotenv";var Bo=async t=>{let e=Se(t);for(;;){let o=Se(e,".env");try{return await Fo(o),o}catch{}let r=Mo(e);if(r===e)return null;e=r}},z=async t=>{let e;if(t?e=Se(t):e=await Bo(process.cwd()),!e)return null;try{let o=await Ho(e,"utf-8");return zo(o)}catch(o){if(o instanceof Error&&o.message.includes("ENOENT"))return null;throw o}};he();import{intro as Wo,outro as Ko}from"@clack/prompts";import Me from"picocolors";var ze=()=>{Wo(Me.inverse(" db-studio ")),Ko(Me.green(`For more information, visit: ${Le.SITE_DOCS_LINK}`))};ee();import{intro as Vo,note as Qo,outro as Be}from"@clack/prompts";import oe from"picocolors";var We=async(t,e,o)=>{Vo(oe.inverse(" db-studio "));let r=o||k.VAR_NAME,a=null;if(e)a=e;else{let n=t?await z(t):await z();n?.[r]?a=n[r]:process.env[r]&&(a=process.env[r]??null)}a?Be(oe.green(`\u2713 Database connection configured (using ${r})`)):(Qo(oe.red(`\u2717 ${r} not found`),"Status"),Be(oe.yellow("\u26A0 No database connection configured")))};import{intro as Go,outro as Jo}from"@clack/prompts";import Ve from"picocolors";var Ke={name:"db-studio",type:"module",version:"1.3.25",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 --minify --sourcemap",prepack:"cd ../core && bun run build && cd ../server && bun run build",start:"node dist/index.js",check:"biome check --write --unsafe",test:"vitest run","test:watch":"vitest","test:coverage":"vitest run --coverage"},dependencies:{"@clack/prompts":"^0.11.0","@hono/node-server":"^1.19.7","@hono/zod-validator":"^0.7.6",commander:"^12.1.0",dotenv:"^16.4.7",hono:"^4.10.4",open:"^10.0.2",pg:"^8.13.1",picocolors:"^1.1.1",xlsx:"^0.18.5",zod:"^4.2.1"},devDependencies:{"@biomejs/biome":"^2.2.6","@types/node":"^20.11.17","@types/pg":"^8.16.0","@vitest/coverage-v8":"^4.0.17",shared:"workspace:*",tsup:"^8.5.1",tsx:"^4.7.1",typescript:"^5.8.3",vitest:"^4.0.17"}};var Qe=()=>{Go(Ve.inverse(" db-studio ")),Jo(Ve.green(`\u{1F680} db-studio v${Ke.version}`))};var Qr=async()=>{let{env:t,port:e,databaseUrl:o,varName:r,status:a,help:n,version:i}=je();n&&(ze(),process.exit(0)),i&&(Qe(),process.exit(0)),a&&(await We(t,o,r),process.exit(0)),Br(Ae.inverse(" db-studio "));let c=e?parseInt(e,10):k.PORT,s=r||k.VAR_NAME,u=t?await z(t):await z(),l=o||await He(u,s);process.env.DATABASE_URL=l;let{createServer:p}=await Promise.resolve().then(()=>(Ao(),_o)),{app:b}=p();Kr({fetch:b.fetch,port:c}),Wr(Ae.green(`Server running at ${Ae.cyan(`http://localhost:${c}`)}`)),process.env.NODE_ENV&&process.env.NODE_ENV!=="development"&&await Vr(`http://localhost:${c}`)};Qr().catch(t=>{process.exit(1)});export{Qr as main};
|
|
229
229
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../shared/src/constants/chat.ts","../../shared/src/constants/defaults.ts","../../shared/src/constants/links.ts","../../shared/src/constants/meta.ts","../../shared/src/constants/proxy-limits.ts","../../shared/src/constants/index.ts","../../shared/src/types/add-record.types.ts","../../shared/src/types/api-response.types.ts","../../shared/src/types/bulk-insert-records.type.ts","../../shared/src/types/database.types.ts","../../shared/src/types/chat.types.ts","../../shared/src/types/cmd-args.types.ts","../../shared/src/types/column-info.types.ts","../../shared/src/types/column.type.ts","../../shared/src/types/create-table.types.ts","../../shared/src/types/database-list.types.ts","../../shared/src/types/database-schema.type.ts","../../shared/src/types/delete-column.types.ts","../../shared/src/types/delete-record.types.ts","../../shared/src/types/execute-query.types.ts","../../shared/src/types/export-table.types.ts","../../shared/src/types/rate-limit-response.type.ts","../../shared/src/types/table-data.types.ts","../../shared/src/types/table-info.type.ts","../../shared/src/types/update-recors.types.ts","../../shared/src/types/index.ts","../src/middlewares/error-handler.ts","../src/db.ts","../src/db-manager.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/utils/parse-database-url.ts","../src/dao/database-list.dao.ts","../src/routes/databases.routes.ts","../src/dao/query.dao.ts","../src/routes/query.routes.ts","../src/dao/add-record.dao.ts","../src/dao/bulk-insert-records.dao.ts","../src/dao/delete-records.dao.ts","../src/dao/update-records.dao.ts","../src/routes/records.routes.ts","../src/dao/create-table.dao.ts","../src/dao/delete-column.dao.ts","../src/dao/export-table.dao.ts","../src/dao/table-list.dao.ts","../src/utils/build-clauses.ts","../src/dao/tables-data.dao.ts","../src/utils/get-export-file.ts","../src/routes/tables.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 CHAT_SUGGESTIONS = [\n\t\"Show me all tables in my database\",\n\t\"What columns are in the users table?\",\n\t\"Write a query to find all active users\",\n\t\"How many orders were placed last month?\",\n\t\"Find top 5 customers by total spend\",\n\t\"Write a JOIN between users and orders\",\n\t\"Users who haven't made any purchase yet\",\n\t\"Generate monthly revenue summary query\",\n\t\"Suggest useful indexes for better performance\",\n\t\"Show schema of the products / inventory table\",\n\t\"Latest 20 orders with customer names\",\n\t\"Help me write a safe UPDATE query\",\n];\n\n// const MODEL_LIST = [\n// \t{\n// \t\tid: \"gpt-4o\",\n// \t\tname: \"GPT-4o\",\n// \t\tchef: \"OpenAI\",\n// \t\tchefSlug: \"openai\",\n// \t},\n// \t{\n// \t\tid: \"gpt-4o-mini\",\n// \t\tname: \"GPT-4o Mini\",\n// \t\tchef: \"OpenAI\",\n// \t\tchefSlug: \"openai\",\n// \t},\n// \t{\n// \t\tid: \"claude-opus-4-20250514\",\n// \t\tname: \"Claude 4 Opus\",\n// \t\tchef: \"Anthropic\",\n// \t\tchefSlug: \"anthropic\",\n// \t},\n// \t{\n// \t\tid: \"claude-sonnet-4-20250514\",\n// \t\tname: \"Claude 4 Sonnet\",\n// \t\tchef: \"Anthropic\",\n// \t\tchefSlug: \"anthropic\",\n// \t},\n// \t{\n// \t\tid: \"gemini-2.0-flash-exp\",\n// \t\tname: \"Gemini 2.0 Flash\",\n// \t\tchef: \"Google\",\n// \t\tchefSlug: \"google\",\n// \t},\n// ];\n","export const DEFAULTS = {\n\tPORT: 3333,\n\tENV: \".env\",\n\tVAR_NAME: \"DATABASE_URL\",\n\tBASE_URL: \"http://localhost:3333\",\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","export const HEADER_LINKS = [\n\t{ label: \"Home\", href: \"/\" },\n\t{ label: \"Roadmap\", href: \"/roadmap\" },\n\t{ label: \"Docs\", href: \"/docs/$\" },\n\t{ label: \"Changelog\", href: \"/changelog\" },\n];\n","export const META = {\n\t//* author\n\tAUTHOR: \"Hüsam 🥑 <devhsmq@gmail.com>\",\n\tAUTHOR_NAME: \"Hüsam\",\n\tAUTHOR_AVATAR: \"/avocado.png\",\n\tAUTHOR_USERNAME: \"husamql3\",\n\tAUTHOR_GITHUB_LINK: \"https://github.com/husamql3\",\n\t//* site\n\tSITE_DESCRIPTION: \"The modern pgAdmin alternative that works with every database.\",\n\tSITE_KEYWORDS: [\"database\", \"management\", \"studio\", \"spreadsheet\", \"ai\", \"sql\"],\n\tSITE_TITLE: \"DB Studio\",\n\tSITE_NAME: \"dbstudio.sh\",\n\tSITE_URL: \"https://dbstudio.sh\",\n\tSITE_X_LINK: \"https://x.com/dbstudio_sh\",\n\tSITE_GITHUB_LINK: \"https://github.com/husamql3/db-studio\",\n\tSITE_DOCS_LINK: \"https://dbstudio.sh/docs\",\n\tSITE_CHANGELOG_LINK: \"https://dbstudio.sh/changelog\",\n\tSITE_ROADMAP_LINK: \"https://dbstudio.sh/roadmap\",\n\tSITE_IMAGE: \"/og-image.png\",\n\tSITE_IMAGE_WIDTH: \"1200\",\n\tSITE_IMAGE_HEIGHT: \"630\",\n\tSITE_IMAGE_ALT: \"dbstudio.sh – Modern database management studio\",\n\tSITE_COLOR: \"#1447e6\",\n};\n","export const ONE_DAY = 24 * 60 * 60 * 1000;\nexport const LIMIT = 3;\n","export * from \"./chat.js\";\nexport * from \"./defaults.js\";\nexport * from \"./links.js\";\nexport * from \"./meta.js\";\nexport * from \"./proxy-limits.js\";\n","import { z } from \"zod\";\n\nexport const addRecordSchema = z.object({\n\ttableName: z.string(\"Table name is required\"),\n\tdata: z.record(z.string(\"Column name is required\"), z.any()),\n});\n\nexport type AddRecordSchemaType = z.infer<typeof addRecordSchema>;\n","/**\n * Standard API success response wrapper type\n * Used by both server and client\n */\nexport type BaseResponse<T> = {\n\tdata: T;\n\tmessage?: string;\n};\n\n/**\n * Standard API error response type\n */\nexport type ApiError = {\n\terror: string;\n\tdetails?: string;\n};\n","import { z } from \"zod\";\nimport type { DatabaseSchemaType } from \"./database.types\";\n\nexport type BulkInsertRecordsParams = {\n\ttableName: string;\n\trecords: Record<string, unknown>[];\n\tdb: DatabaseSchemaType[\"db\"];\n};\n\nexport type BulkInsertResult = {\n\tsuccess: boolean;\n\tmessage: string;\n\tsuccessCount: number;\n\tfailureCount: number;\n\terrors?: Array<{ recordIndex: number; error: string }>;\n};\n\nexport const bulkInsertRecordsSchema = z.object({\n\ttableName: z.string().min(1, \"Table name is required\"),\n\trecords: z.array(z.record(z.string(), z.any())).min(1, \"At least one record is required\"),\n});\n","import { z } from \"zod\";\n\nexport const databaseSchema = z.object({\n\tdb: z.string(\"Database name is required\"),\n});\n\nexport type DatabaseSchemaType = z.infer<typeof databaseSchema>;\n\nexport const DATABASE_TYPES = [\"pg\"] as const;\n\nexport const databaseTypeSchema = z.enum(DATABASE_TYPES, {\n\tmessage: \"Invalid database type\",\n});\nexport type DatabaseTypeSchema = z.infer<typeof databaseTypeSchema>;\n\nexport const currentDatabaseSchema = databaseSchema.extend({\n\tdbType: databaseTypeSchema,\n});\nexport type CurrentDatabaseSchemaType = z.infer<typeof currentDatabaseSchema>;\n\nexport const databaseTypeParamSchema = z.object({\n\tdbType: databaseTypeSchema,\n});\n\nexport const tableNameSchema = z.object({\n\ttableName: z.string(\"Table name is required\"),\n});\n\nexport type TableNameSchemaType = z.infer<typeof tableNameSchema>;\n","import { z } from \"zod\";\nimport { databaseSchema } from \"./database.types.js\";\n\nexport const chatSchema = z.object({\n\tmessages: z.array(\n\t\tz.object({\n\t\t\trole: z.enum([\"user\", \"assistant\"]),\n\t\t\tcontent: z.string(\"Content is required\"),\n\t\t}),\n\t),\n\tconversationId: z.string().optional(),\n\tdb: databaseSchema.shape.db,\n});\n","export type Args = {\n\tenv?: string;\n\tport?: string;\n\tdatabaseUrl?: string;\n\tvarName?: string;\n\tstatus?: boolean;\n\thelp?: boolean;\n\tversion?: boolean;\n};\n","import { z } from \"zod\";\n\nconst dataTypes = [\"text\", \"boolean\", \"number\", \"enum\", \"json\", \"date\", \"array\"] as const;\n\nexport const dataTypesSchema = z.enum(dataTypes);\nexport type DataTypes = z.infer<typeof dataTypesSchema>;\n\nexport 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 satisfies Record<DataTypes, string>;\n\nconst standardizedDataTypes = [\n\t\"int\",\n\t\"bigint\",\n\t\"smallint\",\n\t\"numeric\",\n\t\"float\",\n\t\"double\",\n\t\"money\",\n\t\"boolean\",\n\t\"text\",\n\t\"varchar\",\n\t\"char\",\n\t\"json\",\n\t\"jsonb\",\n\t\"xml\",\n\t\"uuid\",\n\t\"date\",\n\t\"time\",\n\t\"timestamp\",\n\t\"timestamptz\",\n\t\"interval\",\n\t\"bytea\",\n\t\"inet\",\n\t\"cidr\",\n\t\"macaddr\",\n\t\"macaddr8\",\n\t\"point\",\n\t\"line\",\n\t\"polygon\",\n\t\"array\",\n\t\"enum\",\n] as const;\n\nexport const standardizedDataTypeSchema = z.enum(standardizedDataTypes);\n\nexport const columnInfoSchema = z.object({\n\tcolumnName: z.string(),\n\tdataType: dataTypesSchema,\n\tdataTypeLabel: standardizedDataTypeSchema,\n\tisNullable: z.boolean(),\n\tcolumnDefault: z.string().nullable(),\n\tisPrimaryKey: z.boolean(),\n\tisForeignKey: z.boolean(),\n\treferencedTable: z.string().nullable(),\n\treferencedColumn: z.string().nullable(),\n\tenumValues: z.array(z.string()).nullable(),\n});\n\nexport type ColumnInfoSchemaType = z.infer<typeof columnInfoSchema>;\n","import { DataTypes } from \"./column-info.types.js\";\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(\n\tpgType: string | null | undefined,\n): StandardizedDataType {\n\tif (!pgType) {\n\t\treturn StandardizedDataType.text; // Default fallback\n\t}\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 (normalized === \"double precision\" || normalized === \"float8\" || normalized === \"float\") {\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 { 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);\n\nexport const fieldDataSchema = z.object({\n\tcolumnName: z.string(\"Column name is required\"),\n\tcolumnType: z.string(\"Column type is required\"),\n\tdefaultValue: z.string().optional(),\n\tisPrimaryKey: z.boolean().default(false),\n\tisNullable: z.boolean().default(false),\n\tisUnique: z.boolean().default(false),\n\tisIdentity: z.boolean().default(false),\n\tisArray: z.boolean().default(false),\n});\nexport type FieldDataType = z.infer<typeof fieldDataSchema>;\n\nexport const foreignKeyDataSchema = z.object({\n\tcolumnName: z.string(\"Column name is required\"),\n\treferencedTable: z.string(\"Referenced table is required\"),\n\treferencedColumn: z.string(\"Referenced column is required\"),\n\tonUpdate: foreignKeyActionSchema.default(\"NO ACTION\"),\n\tonDelete: foreignKeyActionSchema.default(\"NO ACTION\"),\n});\nexport type ForeignKeyDataType = z.infer<typeof foreignKeyDataSchema>;\n\nexport const createTableSchema = z.object({\n\ttableName: z.string(\"Table name is required\"),\n\tfields: z.array(fieldDataSchema).min(1, \"At least one field is required\"),\n\tforeignKeys: z.array(foreignKeyDataSchema).optional(),\n});\n\nexport type CreateTableSchemaType = z.infer<typeof createTableSchema>;\n","import { z } from \"zod\";\nimport { databaseTypeSchema } from \"./database.types.js\";\n\nexport const databaseInfoSchema = z.object({\n\tname: z.string(\"Name is required\"),\n\tsize: z.string(\"Size is required\"),\n\towner: z.string(\"Owner is required\"),\n\tencoding: z.string(\"Encoding is required\"),\n});\n\nexport type DatabaseInfoSchemaType = z.infer<typeof databaseInfoSchema>;\n\nexport const databaseListSchema = z.object({\n\tdatabases: z.array(databaseInfoSchema),\n\tdbType: databaseTypeSchema,\n});\n\nexport type DatabaseListSchemaType = z.infer<typeof databaseListSchema>;\n\nexport const connectionInfoSchema = z.object({\n\tversion: z.string(\"Version is required\"),\n\tdatabase: z.string(\"Database is required\"),\n\tuser: z.string(\"User is required\"),\n\thost: z.string(\"Host is required\").nullable(),\n\tport: z.number(\"Port is required\").nullable(),\n\tactive_connections: z.coerce.number(\"Active connections is required\"),\n\tmax_connections: z.coerce.number(\"Max connections is required\"),\n});\n\nexport type ConnectionInfoSchemaType = z.infer<typeof connectionInfoSchema>;\n","import type { DatabaseTypeSchema } from \"./database.types\";\n\nexport type DatabaseSchema = {\n\tdbType: DatabaseTypeSchema;\n\ttables: Table[];\n\trelationships: Relationship[];\n};\n\nexport type Table = {\n\tname: string;\n\tdescription?: string;\n\tcolumns: Column[];\n\tsampleData?: Record<string, string>[];\n};\n\nexport type Column = {\n\tname: string;\n\ttype: string;\n\tnullable: boolean;\n\tisPrimaryKey?: boolean;\n\tforeignKey?: string;\n\tdescription?: string;\n\tenumValues?: string[];\n};\n\nexport type Relationship = {\n\tfromTable: string;\n\tfromColumn: string;\n\ttoTable: string;\n\ttoColumn: string;\n};\n","import { z } from \"zod\";\nimport { databaseSchema } from \"./database.types\";\n\nexport const deleteColumnQuerySchema = databaseSchema.extend({\n\tcascade: z\n\t\t.string()\n\t\t.optional()\n\t\t.transform((val) => val === \"true\"),\n});\n\nexport type DeleteColumnQuerySchemaType = z.infer<typeof deleteColumnQuerySchema>;\n\nexport const deleteColumnParamSchema = z.object({\n\ttableName: z.string(\"Table name is required\"),\n\tcolumnName: z.string(\"Column name is required\"),\n});\n\nexport const deleteColumnParamsSchema = z.object({\n\tdb: databaseSchema.shape.db,\n\ttableName: deleteColumnParamSchema.shape.tableName,\n\tcolumnName: deleteColumnParamSchema.shape.columnName,\n\tcascade: z.boolean().optional(),\n});\n\nexport type DeleteColumnParamsSchemaType = z.infer<typeof deleteColumnParamsSchema>;\n\nexport const deleteColumnSuccessResponseSchema = z.object({\n\tmessage: z.string(\"Message is required\"),\n\ttableName: z.string(\"Table name is required\"),\n\tcolumnName: z.string(\"Column name is required\"),\n\tdeletedCount: z.number(\"Deleted count is required\").default(0),\n});\n\nexport type DeleteColumnResponseType = z.infer<typeof deleteColumnSuccessResponseSchema>;\n","import { z } from \"zod\";\nimport type { DatabaseSchemaType } from \"./database.types\";\n\nexport const deleteRecordSchema = z.object({\n\ttableName: z.string(\"Table name is required\"),\n\tprimaryKeys: z\n\t\t.array(\n\t\t\tz.object({\n\t\t\t\tcolumnName: z.string(\"Column name is required\"),\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 type DeleteRecordSchemaType = z.infer<typeof deleteRecordSchema>;\n\nexport type DeleteRecordParams = DeleteRecordSchemaType & {\n\tdb: DatabaseSchemaType[\"db\"];\n};\n\nexport type DeleteRecordResult = {\n\tdeletedCount: number;\n\tfkViolation: boolean;\n\trelatedRecords: RelatedRecord[];\n};\n\nexport type ForeignKeyConstraint = {\n\tconstraintName: string;\n\treferencingTable: string;\n\treferencingColumn: string;\n\treferencedTable: string;\n\treferencedColumn: string;\n};\n\nexport type ForeignKeyConstraintRow = {\n\tconstraint_name: string;\n\treferencing_table: string;\n\treferencing_column: string;\n\treferenced_table: string;\n\treferenced_column: string;\n};\n\nexport type RelatedRecord = {\n\ttableName: string;\n\tcolumnName: string;\n\tconstraintName: string;\n\trecords: Array<Record<string, unknown>>;\n};\n","import { z } from \"zod\";\n\nexport const executeQuerySchema = z.object({\n\tquery: z.string(\"Query is required\"),\n});\n\nexport type ExecuteQueryParams = z.infer<typeof executeQuerySchema>;\n\nexport type ExecuteQueryResult = {\n\tcolumns: string[];\n\trows: Record<string, unknown>[];\n\trowCount: number;\n\tduration: number;\n\tmessage?: string;\n\terror?: string;\n};\n","import { z } from \"zod\";\nimport { databaseSchema } from \"./database.types.js\";\n\nexport const FORMAT_TYPES = [\"csv\", \"xlsx\", \"json\"] as const;\nexport type FormatType = (typeof FORMAT_TYPES)[number];\n\nexport const exportTableSchema = databaseSchema.extend({\n\tformat: z.enum(FORMAT_TYPES, {\n\t\tmessage: \"Invalid format. Supported formats: csv, xlsx, json\",\n\t}),\n});\nexport type ExportTableSchemaType = z.infer<typeof exportTableSchema>;\n\nexport type CellValue = string | number | boolean | Date | null | undefined;\n","export type RateLimitResponse = {\n\tlimit: number;\n\tused: number;\n\tremaining: number;\n};\n","import { z } from \"zod\";\nimport { databaseSchema } from \"./database.types.js\";\n\nexport const filterSchema = z.object({\n\tcolumnName: z.string(),\n\toperator: z.string(),\n\tvalue: z.string(),\n});\n\nexport type FilterType = z.infer<typeof filterSchema>;\n\nexport const sortDirections = [\"asc\", \"desc\"] as const;\nexport type SortDirection = (typeof sortDirections)[number];\n\nexport const sortSchema = z.object({\n\tcolumnName: z.string(),\n\tdirection: z.enum(sortDirections),\n});\n\nexport type SortType = z.infer<typeof sortSchema>;\n\nexport const tableDataMetaSchema = z.object({\n\tlimit: z.number(),\n\ttotal: z.number(),\n\thasNextPage: z.boolean(),\n\thasPreviousPage: z.boolean(),\n\tnextCursor: z.string().nullable(),\n\tprevCursor: z.string().nullable(),\n});\n\nexport const tableDataResultSchema = z.object({\n\tdata: z.array(z.record(z.string(), z.unknown())),\n\tmeta: tableDataMetaSchema,\n});\n\nexport type TableDataResultSchemaType = z.infer<typeof tableDataResultSchema>;\n\nexport const tableDataQuerySchema = z.object({\n\tdb: databaseSchema.shape.db,\n\tcursor: z.string().optional(), // Base64 encoded cursor for pagination\n\tlimit: z.string().optional().default(\"50\").transform(Number),\n\tdirection: z.enum(sortDirections).optional().default(sortDirections[0]), // Pagination direction\n\tsort: z\n\t\t.string()\n\t\t.optional()\n\t\t.transform((val) => {\n\t\t\tif (!val) return \"\";\n\n\t\t\ttry {\n\t\t\t\tconst parsed = JSON.parse(val);\n\t\t\t\tif (Array.isArray(parsed)) {\n\t\t\t\t\treturn parsed;\n\t\t\t\t}\n\t\t\t\treturn val;\n\t\t\t} catch {\n\t\t\t\treturn val;\n\t\t\t}\n\t\t}),\n\torder: z.enum(sortDirections).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 type TableDataQuerySchemaType = z.infer<typeof tableDataQuerySchema>;\n\nexport interface CursorData {\n\tvalues: Record<string, unknown>;\n\tsortColumns: string[];\n}\n","import { z } from \"zod\";\n\nexport const tableInfoSchema = z.object({\n\ttableName: z.string(\"Table name is required\"),\n\trowCount: z.coerce.number(\"Row count is required\"),\n});\n\nexport type TableInfoSchemaType = z.infer<typeof tableInfoSchema>;\n","import { z } from \"zod\";\n\nexport const updateRecordsSchema = z.object({\n\ttableName: z.string(\"Table name is required\"),\n\tprimaryKey: z.string(\"Primary key is required\").default(\"id\"),\n\tupdates: z\n\t\t.array(\n\t\t\tz.object(\n\t\t\t\t{\n\t\t\t\t\trowData: z.record(z.string(\"Column name is required\"), z.any()),\n\t\t\t\t\tcolumnName: z.string(\"Column name is required\"),\n\t\t\t\t\tvalue: z.any(),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tmessage: \"Each update must have a row data, column name, and value.\",\n\t\t\t\t},\n\t\t\t),\n\t\t)\n\t\t.min(1, \"At least one update is required\"),\n});\n\nexport type UpdateRecordsSchemaType = z.infer<typeof updateRecordsSchema>;\n","export * from \"./add-record.types.js\"; // done\nexport * from \"./api-response.types.js\";\nexport * from \"./bulk-insert-records.type.js\";\nexport * from \"./chat.types.js\"; // done\nexport * from \"./cmd-args.types.js\"; // done\nexport * from \"./column.type.js\";\nexport * from \"./column-info.types.js\";\nexport * from \"./create-table.types.js\"; // done\nexport * from \"./database.types.js\"; // done\nexport * from \"./database-list.types.js\"; // done\nexport * from \"./database-schema.type.js\"; // done\nexport * from \"./delete-column.types.js\"; // done\nexport * from \"./delete-record.types.js\"; // done\nexport * from \"./execute-query.types.js\"; // done\nexport * from \"./export-table.types.js\";\nexport * from \"./rate-limit-response.type.js\";\nexport * from \"./table-data.types.js\"; // done\nexport * from \"./table-info.type.js\"; // done\nexport * from \"./update-recors.types.js\"; // done\n","import type { Context } from \"hono\";\nimport { HTTPException } from \"hono/http-exception\";\nimport { DatabaseError } from \"pg\";\nimport type { ApiError } from \"shared/types/api-response.types.js\";\nimport { ZodError } from \"zod\";\n\n/**\n * Centralized error handler for the application\n */\nexport function handleError(e: Error | unknown, c: Context) {\n\tconsole.error(\"handleError:\", e);\n\n\tif (e instanceof HTTPException) {\n\t\treturn c.json<ApiError>(\n\t\t\t{\n\t\t\t\terror: e.message ?? \"Internal server error\",\n\t\t\t},\n\t\t\te.status,\n\t\t);\n\t}\n\n\tif (e instanceof ZodError) {\n\t\tconst issue = e.issues[0];\n\t\treturn c.json<ApiError>(\n\t\t\t{\n\t\t\t\terror: \"Validation error\",\n\t\t\t\tdetails: issue.message,\n\t\t\t},\n\t\t\t400,\n\t\t);\n\t}\n\n\tif (e instanceof Error) {\n\t\tconst isConnectionError =\n\t\t\te.message.includes(\"ECONNREFUSED\") ||\n\t\t\te.message.includes(\"connection refused\") ||\n\t\t\te.message.includes(\"timeout expired\") ||\n\t\t\te.message.includes(\"Connection terminated\") ||\n\t\t\t(e instanceof DatabaseError && e.code?.startsWith(\"08\")); // Connection exception class\n\n\t\tif (isConnectionError) {\n\t\t\treturn c.json<ApiError>(\n\t\t\t\t{ error: \"Database connection failed\", details: e.message },\n\t\t\t\t503,\n\t\t\t);\n\t\t}\n\t}\n\n\treturn c.json<ApiError>(\n\t\t{\n\t\t\terror: e instanceof Error ? e.message : \"Internal server error\",\n\t\t},\n\t\t500,\n\t);\n}\n\nexport const validationHook = (\n\tresult: {\n\t\tsuccess: boolean;\n\t\tdata?: unknown;\n\t\terror?: { issues: { message: string }[] };\n\t},\n\tc: Context,\n): Response | undefined => {\n\tif (!result.success) {\n\t\tconst issue = result.error?.issues[0];\n\t\treturn c.json<ApiError>(\n\t\t\t{\n\t\t\t\terror: \"Validation error\",\n\t\t\t\tdetails: issue?.message ?? \"Unknown validation error\",\n\t\t\t},\n\t\t\t400,\n\t\t);\n\t}\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(\"DATABASE_URL is not set. Please provide a database connection string.\");\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 { Pool, type PoolConfig } from \"pg\";\nimport type { DatabaseTypeSchema } from \"shared/types\";\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\tdbType: DatabaseTypeSchema;\n\t} | null = null;\n\n\tconstructor() {\n\t\tthis.initializeBaseConfig();\n\t}\n\n\t/**\n\t * Detect database type from URL protocol\n\t */\n\tprivate detectDbType(url: URL): DatabaseTypeSchema {\n\t\tconst protocol = url.protocol.replace(\":\", \"\");\n\t\t// postgres:// or postgresql:// -> pg\n\t\tif (protocol === \"postgres\" || protocol === \"postgresql\") {\n\t\t\treturn \"pg\";\n\t\t}\n\t\t// Default to pg for now, can be extended for mysql, sqlite, etc.\n\t\treturn \"pg\";\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(\"DATABASE_URL is not set. Please provide a database connection string.\");\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\tdbType: this.detectDbType(url),\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 * Get the detected database type\n\t */\n\tgetDbType(): DatabaseTypeSchema {\n\t\tif (!this.baseConfig) {\n\t\t\tthrow new Error(\"Base configuration not initialized\");\n\t\t}\n\t\treturn this.baseConfig.dbType;\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\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 * Get the detected database type from DATABASE_URL\n */\nexport const getDbType = (): DatabaseTypeSchema => {\n\treturn databaseManager.getDbType();\n};\n\n/**\n * Build a connection string for the specified database\n */\nconst _buildDbConnectionString = (database?: string): string => {\n\treturn databaseManager.buildConnectionString(database);\n};\n\n/**\n * Close a specific database pool by database name\n */\nconst _closeDbPool = async (database: string): Promise<void> => {\n\treturn databaseManager.closePoolByDatabase(database);\n};\n\n/**\n * Close a specific database pool by connection string\n */\nconst _closeDbPoolByConnectionString = async (connectionString: string): Promise<void> => {\n\treturn databaseManager.closePool(connectionString);\n};\n\n/**\n * Close all database pools\n */\nconst _closeAllDbPools = async (): Promise<void> => {\n\treturn databaseManager.closeAll();\n};\n\n/**\n * Get list of active pool connection strings\n */\nconst _getActivePools = (): string[] => {\n\treturn databaseManager.getActivePools();\n};\n","import { HTTPException } from \"hono/http-exception\";\nimport {\n\ttype ColumnInfoSchemaType,\n\ttype DatabaseSchemaType,\n\tmapPostgresToDataType,\n\tstandardizeDataTypeLabel,\n\ttype TableNameSchemaType,\n} from \"shared/types\";\nimport { getDbPool } from \"@/db-manager.js\";\n\nexport async function getTableColumns({\n\ttableName,\n\tdb,\n}: {\n\ttableName: TableNameSchemaType[\"tableName\"];\n\tdb: DatabaseSchemaType[\"db\"];\n}): Promise<ColumnInfoSchemaType[]> {\n\tconst pool = getDbPool(db);\n\tconst query = `\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\n\tconst { rows } = await pool.query(query, [tableName]);\n\tif (!rows || rows.length === 0) {\n\t\tthrow new HTTPException(404, {\n\t\t\tmessage: `Table \"${tableName}\" does not exist`,\n\t\t});\n\t}\n\n\treturn rows.map((r) => {\n\t\t// Parse enumValues to always return string[] | null\n\t\tlet parsedEnumValues: string[] | null = null;\n\t\tif (r.enumValues) {\n\t\t\tif (Array.isArray(r.enumValues)) {\n\t\t\t\t// Already an array, use as-is\n\t\t\t\tparsedEnumValues = r.enumValues;\n\t\t\t} else if (typeof r.enumValues === \"string\") {\n\t\t\t\t// Parse PostgreSQL array format: \"{VALUE1,VALUE2,VALUE3}\"\n\t\t\t\tparsedEnumValues = r.enumValues.replace(/[{}]/g, \"\").split(\",\").filter(Boolean);\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tcolumnName: r.columnName,\n\t\t\tdataType: mapPostgresToDataType(r.dataType),\n\t\t\tdataTypeLabel: standardizeDataTypeLabel(r.dataType),\n\t\t\tisNullable: r.isNullable,\n\t\t\tcolumnDefault: r.columnDefault,\n\t\t\tisPrimaryKey: r.isPrimaryKey,\n\t\t\tisForeignKey: r.isForeignKey,\n\t\t\treferencedTable: r.referencedTable,\n\t\t\treferencedColumn: r.referencedColumn,\n\t\t\tenumValues: parsedEnumValues,\n\t\t};\n\t});\n}\n","import type {\n\tColumn,\n\tColumnInfoSchemaType,\n\tDatabaseSchema,\n\tDatabaseSchemaType,\n\tRelationship,\n\tTable,\n} from \"shared/types\";\nimport { db } from \"@/db.js\";\nimport { getDbPool } from \"@/db-manager.js\";\nimport { getTableColumns } from \"./table-columns.dao.js\";\n\n/**\n * Get all table names from the database\n */\nasync function getTableNames(db: DatabaseSchemaType[\"db\"]): Promise<string[]> {\n\tconst pool = getDbPool(db);\n\tconst query = `\n\t\tSELECT table_name\n\t\tFROM information_schema.tables\n\t\tWHERE table_schema = 'public'\n\t\t\tAND table_type = 'BASE TABLE'\n\t\tORDER BY table_name;\n\t`;\n\tconst { rows } = await pool.query(query);\n\treturn rows.map((r) => r.table_name);\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, unknown>[]> {\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: ColumnInfoSchemaType): 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 */\nasync function getDatabaseSchema(\n\tdb: DatabaseSchemaType[\"db\"],\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\tconst tableNames = await getTableNames(db);\n\n\t\t// Fetch schema info for each table in parallel\n\t\tconst tablePromises = tableNames.map(async (tableName) => {\n\t\t\tconst [columns, description, sampleData] = await Promise.all([\n\t\t\t\tgetTableColumns({ tableName, db }),\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.map((row) =>\n\t\t\t\t\tObject.fromEntries(Object.entries(row).map(([key, value]) => [key, String(value)])),\n\t\t\t\t);\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 detailed schema with sample data (for initial conversation context)\n */\nexport async function getDetailedSchema(\n\tdb: DatabaseSchemaType[\"db\"],\n): Promise<DatabaseSchema> {\n\treturn getDatabaseSchema(db, {\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 \"shared/types\";\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 */\nfunction 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 { zValidator } from \"@hono/zod-validator\";\nimport { Hono } from \"hono\";\nimport { DEFAULTS } from \"shared/constants\";\nimport { chatSchema } from \"shared/types\";\nimport { getDetailedSchema } from \"@/dao/table-details-schema.js\";\nimport { generateSystemPrompt } from \"@/utils/system-prompt-generator.js\";\n\nexport const chatRoutes = new Hono()\n\t/**\n\t * Base path for the endpoints, /:dbType/chat/...\n\t */\n\t.basePath(\"/chat\")\n\n\t/**\n\t * POST /chat - Handle AI chat requests with streaming\n\t * Proxies to the Cloudflare Worker which has the Gemini API key\n\t */\n\t.post(\"/\", zValidator(\"json\", chatSchema), async (c) => {\n\t\tconst { messages, conversationId, db } = c.req.valid(\"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(db);\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});\n\nexport type ChatRoutes = typeof chatRoutes;\n","/**\n * Parse DATABASE_URL to extract host and port\n */\nexport function parseDatabaseUrl(): { host: string; port: number } {\n\tconst databaseUrl = process.env.DATABASE_URL;\n\n\tif (!databaseUrl) {\n\t\treturn { host: \"localhost\", port: 5432 };\n\t}\n\n\ttry {\n\t\tconst url = new URL(databaseUrl);\n\t\treturn {\n\t\t\thost: url.hostname || \"localhost\",\n\t\t\tport: Number.parseInt(url.port, 10) || 5432,\n\t\t};\n\t} catch (error) {\n\t\tconsole.error(\"Failed to parse DATABASE_URL:\", error);\n\t\treturn { host: \"localhost\", port: 5432 };\n\t}\n}\n","import { HTTPException } from \"hono/http-exception\";\nimport {\n\ttype ConnectionInfoSchemaType,\n\tconnectionInfoSchema,\n\ttype DatabaseInfoSchemaType,\n\ttype DatabaseSchemaType,\n} from \"shared/types\";\nimport { getDbPool } from \"@/db-manager.js\";\nimport { parseDatabaseUrl } from \"@/utils/parse-database-url.js\";\n\n/**\n * Gets list of all normal databases on the PostgreSQL server.\n * Returns name, size (human readable), owner, and encoding.\n *\n * @returns List of database information objects\n * @throws Error if query fails or no databases are found\n */\nexport async function getDatabasesList(): Promise<DatabaseInfoSchemaType[]> {\n\tconst pool = getDbPool();\n\tconst query = `\n SELECT \n d.datname as name,\n pg_size_pretty(pg_database_size(d.datname)) as size,\n pg_catalog.pg_get_userbyid(d.datdba) as owner,\n pg_encoding_to_char(d.encoding) as encoding\n FROM pg_catalog.pg_database d\n WHERE d.datistemplate = false\n ORDER BY d.datname;\n `;\n\n\tconst { rows } = await pool.query(query);\n\tif (!rows[0]) {\n\t\tthrow new HTTPException(500, {\n\t\t\tmessage: \"No databases returned from database\",\n\t\t});\n\t}\n\n\treturn rows;\n}\n\n/**\n * Gets the name of the database we are currently using.\n *\n * @returns Object with current database name\n * @throws Error if query fails or no name is returned\n */\nexport async function getCurrentDatabase(): Promise<DatabaseSchemaType> {\n\tconst pool = getDbPool();\n\tconst query = \"SELECT current_database() as database;\";\n\n\tconst { rows } = await pool.query(query);\n\tif (!rows[0]) {\n\t\tthrow new HTTPException(500, {\n\t\t\tmessage: \"No current database returned from database\",\n\t\t});\n\t}\n\n\treturn rows[0];\n}\n\n/**\n * Gets useful information about the connection and PostgreSQL server.\n * Includes version, host, port, user, database name, active connections, etc.\n *\n * Uses fallback values from DATABASE_URL if some fields are missing.\n *\n * @returns Connection and server information object\n * @throws Error if query fails or result is invalid\n */\nexport async function getDatabaseConnectionInfo(): Promise<ConnectionInfoSchemaType> {\n\tconst pool = getDbPool();\n\tconst query = `\n SELECT \n version() as version,\n current_database() as database,\n current_user as user,\n inet_server_addr() as host,\n inet_server_port() as port,\n (SELECT count(*) FROM pg_stat_activity WHERE datname = current_database()) as active_connections,\n (SELECT setting::int FROM pg_settings WHERE name = 'max_connections') as max_connections;\n `;\n\n\tconst { rows } = await pool.query(query);\n\tif (!rows[0]) {\n\t\tthrow new HTTPException(500, {\n\t\t\tmessage: \"No connection information returned from database\",\n\t\t});\n\t}\n\n\t// Validate main result\n\tconst result = connectionInfoSchema.parse(rows[0]);\n\n\t// Use DATABASE_URL as backup for host/port if needed\n\tconst urlDefaults = parseDatabaseUrl();\n\n\treturn {\n\t\thost: result.host || urlDefaults.host,\n\t\tport: result.port || urlDefaults.port,\n\t\tuser: result.user,\n\t\tdatabase: result.database,\n\t\tversion: result.version.toString(),\n\t\tactive_connections: result.active_connections,\n\t\tmax_connections: result.max_connections,\n\t};\n}\n","import { Hono } from \"hono\";\nimport type {\n\tConnectionInfoSchemaType,\n\tCurrentDatabaseSchemaType,\n\tDatabaseListSchemaType,\n} from \"shared/types\";\nimport type { ApiHandler } from \"@/app.types.js\";\nimport {\n\tgetCurrentDatabase,\n\tgetDatabaseConnectionInfo,\n\tgetDatabasesList,\n} from \"@/dao/database-list.dao.js\";\nimport { getDbType } from \"@/db-manager.js\";\n\n/**\n * /databases routes (at root level, no dbType required)\n * GET /databases - Get list of all databases on the server (name, size, owner, encoding)\n * GET /databases/current - Get the name of the database we are currently connected to\n * GET /databases/connection - Get connection details and server information (PostgreSQL version, host, port, user, current database, connection counts)\n */\nexport const databasesRoutes = new Hono()\n\t/**\n\t * Base path for the endpoints, /databases/...\n\t */\n\t.basePath(\"/databases\")\n\n\t/**\n\t * GET /databases\n\t * Returns list of all databases on the server (name, size, owner, encoding) and the database type\n\t * @returns {Object} Object with databases array and dbType\n\t */\n\t.get(\"/\", async (c): ApiHandler<DatabaseListSchemaType> => {\n\t\tconst databases = await getDatabasesList();\n\t\tconst dbType = getDbType();\n\t\treturn c.json({ data: { databases, dbType } }, 200);\n\t})\n\n\t/**\n\t * GET /databases/current\n\t * Returns the name of the database we are currently connected to and the database type\n\t * @returns {Object} Object with current database name and type\n\t */\n\t.get(\"/current\", async (c): ApiHandler<CurrentDatabaseSchemaType> => {\n\t\tconst current = await getCurrentDatabase();\n\t\tconst dbType = getDbType();\n\t\treturn c.json({ data: { ...current, dbType } }, 200);\n\t})\n\n\t/**\n\t * GET /databases/connection\n\t * Returns connection details and server information\n\t * (PostgreSQL version, host, port, user, current database, connection counts)\n\t * @returns {Object} Connection and server info\n\t */\n\t.get(\"/connection\", async (c): ApiHandler<ConnectionInfoSchemaType> => {\n\t\tconst info = await getDatabaseConnectionInfo();\n\t\treturn c.json({ data: info }, 200);\n\t});\n\nexport type DatabasesRoutes = typeof databasesRoutes.routes;\n","import { HTTPException } from \"hono/http-exception\";\nimport type { DatabaseSchemaType, ExecuteQueryParams, ExecuteQueryResult } from \"shared/types\";\nimport { getDbPool } from \"@/db-manager.js\";\n\nexport const executeQuery = async ({\n\tquery,\n\tdb,\n}: {\n\tquery: ExecuteQueryParams[\"query\"];\n\tdb: DatabaseSchemaType[\"db\"];\n}): Promise<ExecuteQueryResult> => {\n\tconst pool = getDbPool(db);\n\tif (!query || !query.trim()) {\n\t\tthrow new HTTPException(400, {\n\t\t\tmessage: \"Query is required\",\n\t\t});\n\t}\n\n\t// Clean the query - remove trailing semicolons and whitespace\n\tconst cleanedQuery = query.trim().replace(/;+$/, \"\");\n\n\tconst startTime = performance.now();\n\tconst result = await pool.query(cleanedQuery);\n\tconst duration = performance.now() - startTime;\n\n\tconst columns = result.fields.map((field) => field.name);\n\n\treturn {\n\t\tcolumns,\n\t\trows: result.rows,\n\t\trowCount: result.rows.length,\n\t\tduration,\n\t\tmessage: result.rows.length === 0 ? \"OK\" : undefined,\n\t};\n};\n","import { zValidator } from \"@hono/zod-validator\";\nimport { Hono } from \"hono\";\nimport { databaseSchema, type ExecuteQueryResult, executeQuerySchema } from \"shared/types\";\nimport type { ApiHandler } from \"@/app.types.js\";\nimport { executeQuery } from \"@/dao/query.dao.js\";\n\nexport const queryRoutes = new Hono()\n\t/**\n\t * Base path for the endpoints, /:dbType/query/...\n\t */\n\t.basePath(\"/query\")\n\n\t/**\n\t * POST /query\n\t * Executes a SQL query on the currently connected database\n\t * @param {DatabaseSchemaType} query - The database to use\n\t * @param {ExecuteQuerySchemaType} json - The query to execute\n\t * @returns {ApiHandler<ExecuteQueryResult>} The result of the query\n\t */\n\t.post(\n\t\t\"/\",\n\t\tzValidator(\"query\", databaseSchema),\n\t\tzValidator(\"json\", executeQuerySchema),\n\t\tasync (c): ApiHandler<ExecuteQueryResult> => {\n\t\t\tconst { query } = c.req.valid(\"json\");\n\t\t\tconst { db } = c.req.valid(\"query\");\n\t\t\tconst data = await executeQuery({ query, db });\n\t\t\treturn c.json({ data }, 200);\n\t\t},\n\t);\n\nexport type QueryRoutes = typeof queryRoutes;\n","import { HTTPException } from \"hono/http-exception\";\nimport type { AddRecordSchemaType, DatabaseSchemaType } from \"shared/types\";\nimport { getDbPool } from \"@/db-manager.js\";\n\nexport async function addRecord({\n\tdb,\n\tparams,\n}: {\n\tdb: DatabaseSchemaType[\"db\"];\n\tparams: AddRecordSchemaType;\n}): Promise<{ insertedCount: number }> {\n\tconst { tableName, data } = params;\n\tconst pool = getDbPool(db);\n\n\t// Extract column names and values\n\tconst columns = Object.keys(data);\n\tconst values = Object.values(data);\n\n\t// Build the INSERT query\n\tconst placeholders = columns.map((_, index) => `$${index + 1}`).join(\", \");\n\tconst columnNames = columns.map((col) => `\"${col}\"`).join(\", \");\n\n\tconst query = `\n\t\t\tINSERT INTO \"${tableName}\" (${columnNames})\n\t\t\tVALUES (${placeholders})\n\t\t\tRETURNING *\n\t\t`;\n\n\tconst result = await pool.query(query, values);\n\tif (result.rowCount === 0) {\n\t\tthrow new HTTPException(500, {\n\t\t\tmessage: `Failed to insert record into \"${tableName}\"`,\n\t\t});\n\t}\n\n\treturn { insertedCount: result.rowCount ?? 0 };\n}\n","import { HTTPException } from \"hono/http-exception\";\nimport type { BulkInsertRecordsParams, BulkInsertResult } from \"shared/types\";\nimport { getDbPool } from \"@/db-manager.js\";\n\nexport const bulkInsertRecords = async ({\n\ttableName,\n\trecords,\n\tdb,\n}: BulkInsertRecordsParams): Promise<BulkInsertResult> => {\n\tif (!records || records.length === 0) {\n\t\tthrow new HTTPException(400, {\n\t\t\tmessage: \"At least one record is required\",\n\t\t});\n\t}\n\n\tconst pool = getDbPool(db);\n\tconst client = await pool.connect();\n\n\ttry {\n\t\t// Get column names from the first record\n\t\tconst columns = Object.keys(records[0]);\n\t\tconst columnNames = columns.map((col) => `\"${col}\"`).join(\", \");\n\n\t\tlet successCount = 0;\n\t\tconst failureCount = 0;\n\t\tconst errors: Array<{ recordIndex: number; error: string }> = [];\n\n\t\t// Execute inserts in a transaction\n\t\tawait client.query(\"BEGIN\");\n\n\t\tfor (let i = 0; i < records.length; i++) {\n\t\t\tconst record = records[i];\n\t\t\tconst values = columns.map((col) => record[col]);\n\n\t\t\tconst placeholders = columns.map((_, index) => `$${index + 1}`).join(\", \");\n\n\t\t\tconst insertSQL = `\n\t\t\t\tINSERT INTO \"${tableName}\" (${columnNames})\n\t\t\t\tVALUES (${placeholders})\n\t\t\t\tRETURNING *\n\t\t\t`;\n\n\t\t\ttry {\n\t\t\t\tawait client.query(insertSQL, values);\n\t\t\t\tsuccessCount++;\n\t\t\t} catch (error) {\n\t\t\t\tthrow new HTTPException(500, {\n\t\t\t\t\tmessage: `Failed: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tawait client.query(\"COMMIT\");\n\n\t\treturn {\n\t\t\tsuccess: failureCount === 0,\n\t\t\tmessage: `Bulk insert completed: ${successCount} records inserted${failureCount > 0 ? `, ${failureCount} failed` : \"\"}`,\n\t\t\tsuccessCount,\n\t\t\tfailureCount,\n\t\t\terrors: errors.length > 0 ? errors : undefined,\n\t\t};\n\t} catch (error) {\n\t\tawait client.query(\"ROLLBACK\");\n\t\tif (error instanceof HTTPException) {\n\t\t\tthrow error;\n\t\t}\n\t\tthrow new HTTPException(500, {\n\t\t\tmessage: `Failed to bulk insert records into \"${tableName}\"`,\n\t\t});\n\t} finally {\n\t\tclient.release();\n\t}\n};\n","import { HTTPException } from \"hono/http-exception\";\nimport type {\n\tDatabaseSchemaType,\n\tDeleteRecordParams,\n\tDeleteRecordResult,\n\tDeleteRecordSchemaType,\n\tForeignKeyConstraint,\n\tForeignKeyConstraintRow,\n\tRelatedRecord,\n} from \"shared/types\";\nimport { getDbPool } from \"@/db-manager.js\";\n\n/**\n * Gets foreign key constraints that reference the given table\n */\nasync function getForeignKeyReferences(\n\ttableName: string,\n\tdb: DatabaseSchemaType[\"db\"],\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(db);\n\tconst result = await pool.query(query, [tableName]);\n\n\treturn result.rows.map((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 */\nasync function getRelatedRecords(\n\ttableName: string,\n\tprimaryKeys: DeleteRecordSchemaType[\"primaryKeys\"],\n\tdb: DatabaseSchemaType[\"db\"],\n): Promise<RelatedRecord[]> {\n\tconst fkConstraints = await getForeignKeyReferences(tableName, db);\n\n\tif (fkConstraints.length === 0) {\n\t\treturn [];\n\t}\n\n\tconst relatedRecords: RelatedRecord[] = [];\n\tconst pool = getDbPool(db);\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((pk) => pk.columnName === constraint.referencedColumn);\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 relatedQuery = `\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\tconst relatedResult = await pool.query(relatedQuery, pkValues);\n\n\t\tif (relatedResult.rows.length > 0) {\n\t\t\trelatedRecords.push({\n\t\t\t\ttableName: constraint.referencingTable,\n\t\t\t\tcolumnName: constraint.referencingColumn,\n\t\t\t\tconstraintName: constraint.constraintName,\n\t\t\t\trecords: relatedResult.rows,\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 async function deleteRecords({\n\ttableName,\n\tprimaryKeys,\n\tdb,\n}: DeleteRecordParams): Promise<DeleteRecordResult> {\n\tconst pool = getDbPool(db);\n\n\tconst pkColumn = primaryKeys[0]?.columnName;\n\tif (!pkColumn) {\n\t\tthrow new HTTPException(400, {\n\t\t\tmessage: \"Primary key column name is required\",\n\t\t});\n\t}\n\n\tconst pkValues = primaryKeys.map((pk) => pk.value);\n\tconst placeholders = pkValues.map((_, i) => `$${i + 1}`).join(\", \");\n\n\tconst query = `\n\t\tDELETE FROM \"${tableName}\"\n\t\tWHERE \"${pkColumn}\" IN (${placeholders})\n\t\tRETURNING *\n\t`;\n\n\ttry {\n\t\tawait pool.query(\"BEGIN\");\n\t\tconst result = await pool.query(query, pkValues);\n\t\tawait pool.query(\"COMMIT\");\n\t\treturn { deletedCount: result.rowCount ?? 0, fkViolation: false, relatedRecords: [] };\n\t} catch (error) {\n\t\tawait pool.query(\"ROLLBACK\");\n\n\t\t// Check if this is a foreign key violation\n\t\tconst pgError = error as {\n\t\t\tcode?: string;\n\t\t\tdetail?: string;\n\t\t\tconstraint?: string;\n\t\t};\n\n\t\tif (pgError.code === \"23503\") {\n\t\t\t// Fetch related records to show the user\n\t\t\tconst relatedRecords = await getRelatedRecords(tableName, primaryKeys, db);\n\n\t\t\treturn {\n\t\t\t\tdeletedCount: 0,\n\t\t\t\tfkViolation: true,\n\t\t\t\trelatedRecords,\n\t\t\t};\n\t\t}\n\n\t\tif (error instanceof HTTPException) {\n\t\t\tthrow error;\n\t\t}\n\n\t\tthrow new HTTPException(500, {\n\t\t\tmessage: `Failed to delete records from \"${tableName}\"`,\n\t\t});\n\t}\n}\n\n/**\n * Force deletes records by first deleting all related records in referencing tables (cascade)\n */\nexport async function forceDeleteRecords({\n\ttableName,\n\tprimaryKeys,\n\tdb,\n}: DeleteRecordParams): Promise<{ deletedCount: number }> {\n\tconst pool = getDbPool(db);\n\n\tconst pkColumn = primaryKeys[0]?.columnName;\n\tif (!pkColumn) {\n\t\tthrow new HTTPException(400, {\n\t\t\tmessage: \"Primary key column name is required\",\n\t\t});\n\t}\n\n\tconst pkValues = primaryKeys.map((pk) => pk.value);\n\n\tawait pool.query(\"BEGIN\");\n\n\ttry {\n\t\t// Get all FK constraints that reference this table\n\t\tconst fkConstraints = await getForeignKeyReferences(tableName, db);\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, db);\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 nestedPlaceholders = 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 (${nestedPlaceholders})\n\t\t\t\t`;\n\n\t\t\t\tconst selectResult = await pool.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 deletePlaceholders = 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 (${deletePlaceholders})\n\t\t\t`;\n\n\t\t\tconst deleteResult = await pool.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 query = `\n\t\t\tDELETE FROM \"${tableName}\"\n\t\t\tWHERE \"${pkColumn}\" IN (${placeholders})\n\t\t\tRETURNING *\n\t\t`;\n\n\t\tconst result = await pool.query(query, pkValues);\n\n\t\tawait pool.query(\"COMMIT\");\n\n\t\tconst mainDeleted = result.rowCount ?? 0;\n\n\t\treturn { deletedCount: mainDeleted + totalRelatedDeleted };\n\t} catch (error) {\n\t\tawait pool.query(\"ROLLBACK\");\n\n\t\tif (error instanceof HTTPException) {\n\t\t\tthrow error;\n\t\t}\n\n\t\tthrow new HTTPException(500, {\n\t\t\tmessage: `Failed to force delete records from \"${tableName}\"`,\n\t\t});\n\t}\n}\n","import { HTTPException } from \"hono/http-exception\";\nimport type { DatabaseSchemaType, UpdateRecordsSchemaType } from \"shared/types\";\nimport { getDbPool } from \"@/db-manager.js\";\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 async function updateRecords({\n\tparams,\n\tdb,\n}: {\n\tparams: UpdateRecordsSchemaType;\n\tdb: DatabaseSchemaType[\"db\"];\n}): Promise<{ updatedCount: number }> {\n\tconst { tableName, updates, primaryKey } = params;\n\tconst pool = getDbPool(db);\n\n\t// Group updates by row (using the primary key value)\n\tconst updatesByRow = new Map<\n\t\tunknown,\n\t\tArray<{\n\t\t\tcolumnName: string;\n\t\t\tvalue: unknown;\n\t\t\trowData: Record<string, unknown>;\n\t\t}>\n\t>();\n\n\tfor (const update of updates) {\n\t\tconst pkValue = update.rowData[primaryKey];\n\t\tif (pkValue === undefined || pkValue === null) {\n\t\t\tthrow new HTTPException(400, {\n\t\t\t\tmessage: `Primary key \"${primaryKey}\" not found in row data. Please ensure the row has a \"${primaryKey}\" column.`,\n\t\t\t});\n\t\t}\n\n\t\tif (!updatesByRow.has(pkValue)) {\n\t\t\tupdatesByRow.set(pkValue, []);\n\t\t}\n\t\tupdatesByRow.get(pkValue)?.push({\n\t\t\tcolumnName: update.columnName,\n\t\t\tvalue: update.value,\n\t\t\trowData: update.rowData,\n\t\t});\n\t}\n\n\t// Use transaction for multiple updates\n\tawait pool.query(\"BEGIN\");\n\n\ttry {\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((u, index) => `\"${u.columnName}\" = $${index + 1}`);\n\t\t\tconst values = rowUpdates.map((u) => {\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 query = `\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\tconst result = await pool.query(query, values);\n\t\t\tif (result.rowCount === 0) {\n\t\t\t\tthrow new HTTPException(404, {\n\t\t\t\t\tmessage: `Record with ${primaryKey} = ${pkValue} not found in table \"${tableName}\"`,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\ttotalUpdated += result.rowCount ?? 0;\n\t\t}\n\n\t\tawait pool.query(\"COMMIT\");\n\n\t\treturn { updatedCount: totalUpdated };\n\t} catch (error) {\n\t\tawait pool.query(\"ROLLBACK\");\n\n\t\tif (error instanceof HTTPException) {\n\t\t\tthrow error;\n\t\t}\n\n\t\tthrow new HTTPException(500, {\n\t\t\tmessage: `Failed to update records in \"${tableName}\"`,\n\t\t});\n\t}\n}\n","import { zValidator } from \"@hono/zod-validator\";\nimport { Hono } from \"hono\";\nimport {\n\taddRecordSchema,\n\tbulkInsertRecordsSchema,\n\ttype DeleteRecordResult,\n\tdatabaseSchema,\n\tdeleteRecordSchema,\n\tupdateRecordsSchema,\n} from \"shared/types\";\nimport type { ApiHandler } from \"@/app.types.js\";\nimport { addRecord } from \"@/dao/add-record.dao.js\";\nimport { bulkInsertRecords } from \"@/dao/bulk-insert-records.dao.js\";\nimport { deleteRecords, forceDeleteRecords } from \"@/dao/delete-records.dao.js\";\nimport { updateRecords } from \"@/dao/update-records.dao.js\";\n\nexport const recordsRoutes = new Hono()\n\t/**\n\t * Base path for the endpoints, /:dbType/records/...\n\t */\n\t.basePath(\"/records\")\n\n\t/**\n\t * POST /records\n\t * Adds a new record into a table\n\t * @param {DatabaseSchemaType} query - The database to use\n\t * @param {AddRecordSchemaType} json - The data for the new record\n\t * @returns {BaseResponseType<string>} A success message\n\t */\n\t.post(\n\t\t\"/\",\n\t\tzValidator(\"query\", databaseSchema),\n\t\tzValidator(\"json\", addRecordSchema),\n\t\tasync (c): ApiHandler<string> => {\n\t\t\tconst { db } = c.req.valid(\"query\");\n\t\t\tconst { tableName, data } = c.req.valid(\"json\");\n\t\t\tconst { insertedCount } = await addRecord({\n\t\t\t\tdb,\n\t\t\t\tparams: {\n\t\t\t\t\ttableName,\n\t\t\t\t\tdata,\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\tdata: `Record inserted into \"${tableName}\" with ${insertedCount} rows inserted`,\n\t\t\t\t},\n\t\t\t\t200,\n\t\t\t);\n\t\t},\n\t)\n\n\t/**\n\t * PATCH /records\n\t * Updates one or more cells in a table\n\t * @param {DatabaseSchemaType} query - The database to use\n\t * @param {UpdateRecordsSchemaType} json - The data for the updates\n\t * @returns {ApiHandler<string>} A success message\n\t */\n\t.patch(\n\t\t\"/\",\n\t\tzValidator(\"query\", databaseSchema),\n\t\tzValidator(\"json\", updateRecordsSchema),\n\t\tasync (c): ApiHandler<string> => {\n\t\t\tconst { db } = c.req.valid(\"query\");\n\t\t\tconst { tableName, primaryKey, updates } = c.req.valid(\"json\");\n\t\t\tconst { updatedCount } = await updateRecords({\n\t\t\t\tparams: {\n\t\t\t\t\ttableName,\n\t\t\t\t\tprimaryKey,\n\t\t\t\t\tupdates,\n\t\t\t\t},\n\t\t\t\tdb,\n\t\t\t});\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\tdata: `Updated ${updatedCount} records in \"${tableName}\"`,\n\t\t\t\t},\n\t\t\t\t200,\n\t\t\t);\n\t\t},\n\t)\n\n\t/**\n\t * DELETE /records\n\t * Deletes records from a table\n\t * @param {DatabaseSchemaType} query - The database to use\n\t * @param {DeleteRecordSchemaType} json - The data for the deletes\n\t * @returns {ApiHandler<string, 409 | 200>} A success message\n\t */\n\t.delete(\n\t\t\"/\",\n\t\tzValidator(\"query\", databaseSchema),\n\t\tzValidator(\"json\", deleteRecordSchema),\n\t\tasync (c): ApiHandler<DeleteRecordResult, 409 | 200> => {\n\t\t\t// TODO: refactor this shit, the backend responses should be consistent\n\t\t\t// TODO: the frontend could be simplified too\n\t\t\tconst { db } = c.req.valid(\"query\");\n\t\t\tconst { tableName, primaryKeys } = c.req.valid(\"json\");\n\t\t\tconst { deletedCount, fkViolation, relatedRecords } = await deleteRecords({\n\t\t\t\ttableName,\n\t\t\t\tprimaryKeys,\n\t\t\t\tdb,\n\t\t\t});\n\t\t\tif (fkViolation) {\n\t\t\t\treturn c.json(\n\t\t\t\t\t{\n\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\tdeletedCount: 0,\n\t\t\t\t\t\t\tfkViolation: true,\n\t\t\t\t\t\t\trelatedRecords,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t409,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tdeletedCount,\n\t\t\t\t\t\tfkViolation: false,\n\t\t\t\t\t\trelatedRecords: [],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t200,\n\t\t\t);\n\t\t},\n\t)\n\n\t/**\n\t * DELETE /records/force\n\t * Force deletes records and all related FK records\n\t * @param {DatabaseSchemaType} query - The database to use\n\t * @param {DeleteRecordSchemaType} json - The data for the deletes\n\t * @returns {ApiHandler<string>} A success message\n\t */\n\t.delete(\n\t\t\"/force\",\n\t\tzValidator(\"query\", databaseSchema),\n\t\tzValidator(\"json\", deleteRecordSchema),\n\t\tasync (c): ApiHandler<{ deletedCount: number }> => {\n\t\t\tconst { db } = c.req.valid(\"query\");\n\t\t\tconst { tableName, primaryKeys } = c.req.valid(\"json\");\n\t\t\tconst deletedCount = await forceDeleteRecords({ tableName, primaryKeys, db });\n\t\t\treturn c.json({ data: deletedCount }, 200);\n\t\t},\n\t)\n\n\t/**\n\t * POST /records/bulk\n\t * Bulk inserts multiple records into a table\n\t * @param {DatabaseSchemaType} query - The database to use\n\t * @param {BulkInsertRecordsParamsType} json - The data for the bulk insert\n\t * @returns {BaseResponseType<BulkInsertResult>} Success and failure counts\n\t */\n\t.post(\n\t\t\"/bulk\",\n\t\tzValidator(\"query\", databaseSchema),\n\t\tzValidator(\"json\", bulkInsertRecordsSchema),\n\t\tasync (c): ApiHandler<object> => {\n\t\t\tconst { db } = c.req.valid(\"query\");\n\t\t\tconst { tableName, records } = c.req.valid(\"json\");\n\t\t\tconst result = await bulkInsertRecords({ tableName, records, db });\n\t\t\tconsole.log(\"result\", result);\n\t\t\treturn c.json({ data: result }, 200);\n\t\t},\n\t);\n\nexport type RecordsRoutes = typeof recordsRoutes;\n","import type {\n\tCreateTableSchemaType,\n\tDatabaseSchemaType,\n\tFieldDataType,\n\tForeignKeyDataType,\n} from \"shared/types\";\nimport { getDbPool } from \"@/db-manager.js\";\n\nexport async function createTable({\n\ttableData,\n\tdb,\n}: {\n\ttableData: CreateTableSchemaType;\n\tdb: DatabaseSchemaType[\"db\"];\n}) {\n\tconst { tableName, fields, foreignKeys } = tableData;\n\tconst pool = getDbPool(db);\n\n\t// Build column definitions\n\tconst columnDefinitions = fields.map((field: FieldDataType) => {\n\t\tlet columnDef = `\"${field.columnName}\" ${field.columnType}`;\n\n\t\t// Add array suffix if needed\n\t\tif (field.isArray) {\n\t\t\tcolumnDef += \"[]\";\n\t\t}\n\n\t\t// Add PRIMARY KEY constraint\n\t\tif (field.isPrimaryKey) {\n\t\t\tcolumnDef += \" PRIMARY KEY\";\n\t\t}\n\n\t\t// Add UNIQUE constraint\n\t\tif (field.isUnique && !field.isPrimaryKey) {\n\t\t\tcolumnDef += \" UNIQUE\";\n\t\t}\n\n\t\t// Add NOT NULL constraint (if not nullable)\n\t\tif (!field.isNullable) {\n\t\t\tcolumnDef += \" NOT NULL\";\n\t\t}\n\n\t\t// Add GENERATED ALWAYS AS IDENTITY for identity columns\n\t\tif (field.isIdentity) {\n\t\t\tcolumnDef += \" GENERATED ALWAYS AS IDENTITY\";\n\t\t}\n\n\t\t// Add default value\n\t\tif (field.defaultValue && !field.isIdentity) {\n\t\t\tcolumnDef += ` DEFAULT ${field.defaultValue}`;\n\t\t}\n\n\t\treturn columnDef;\n\t});\n\n\t// Build foreign key constraints\n\tconst foreignKeyConstraints =\n\t\tforeignKeys?.map((fk: ForeignKeyDataType) => {\n\t\t\tconst constraintName = `fk_${tableName}_${fk.columnName}_${fk.referencedTable}_${fk.referencedColumn}`;\n\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}) || [];\n\n\t// Combine column definitions and foreign key constraints\n\tconst allDefinitions = [...columnDefinitions, ...foreignKeyConstraints];\n\n\t// Create the table\n\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\tawait pool.query(createTableSQL);\n}\n","import { HTTPException } from \"hono/http-exception\";\nimport type { DeleteColumnParamsSchemaType } from \"shared/types\";\nimport { getDbPool } from \"@/db-manager.js\";\n\n/**\n * Deletes a column from a table using ALTER TABLE DROP COLUMN.\n * Uses CASCADE to drop dependent objects, or RESTRICT to fail if there are dependencies.\n *\n * @param params.tableName - Name of the table containing the column\n * @param params.columnName - Name of the column to delete\n * @param params.cascade - If true, uses CASCADE; if false, uses RESTRICT\n * @param params.db - Optional database name to connect to\n * @returns {Object} Object with deleted count\n * @throws HTTPException if table or column does not exist\n */\nexport async function deleteColumn(\n\tparams: DeleteColumnParamsSchemaType,\n): Promise<{ deletedCount: number }> {\n\tconst { tableName, columnName, cascade, db } = params;\n\tconst pool = getDbPool(db);\n\n\t// Check if table exists\n\tconst tableExistsQuery = `\n\t\tSELECT EXISTS (\n\t\t\tSELECT 1 FROM information_schema.tables \n\t\t\tWHERE table_name = $1 AND table_schema = 'public'\n\t\t) as exists;\n\t`;\n\tconst { rows: tableRows } = await pool.query(tableExistsQuery, [tableName]);\n\tif (!tableRows[0]?.exists) {\n\t\tthrow new HTTPException(404, {\n\t\t\tmessage: `Table \"${tableName}\" does not exist`,\n\t\t});\n\t}\n\n\t// Check if column exists\n\tconst columnExistsQuery = `\n\t\tSELECT EXISTS (\n\t\t\tSELECT 1 FROM information_schema.columns \n\t\t\tWHERE table_name = $1 AND column_name = $2 AND table_schema = 'public'\n\t\t) as exists;\n\t`;\n\tconst { rows: columnRows } = await pool.query(columnExistsQuery, [tableName, columnName]);\n\tif (!columnRows[0]?.exists) {\n\t\tthrow new HTTPException(404, {\n\t\t\tmessage: `Column \"${columnName}\" does not exist in table \"${tableName}\"`,\n\t\t});\n\t}\n\n\t// Use CASCADE to drop dependent objects, or RESTRICT to fail if there are dependencies\n\tconst dropMode = cascade ? \"CASCADE\" : \"RESTRICT\";\n\tconst dropColumnSQL = `ALTER TABLE \"${tableName}\" DROP COLUMN \"${columnName}\" ${dropMode}`;\n\n\tconst { rowCount } = await pool.query(dropColumnSQL);\n\n\treturn { deletedCount: rowCount ?? 0 };\n}\n","import { HTTPException } from \"hono/http-exception\";\nimport type { CellValue, DatabaseSchemaType, TableNameSchemaType } from \"shared/types\";\nimport { getDbPool } from \"@/db-manager.js\";\n\nexport async function exportTableData({\n\ttableName,\n\tdb,\n}: {\n\ttableName: TableNameSchemaType[\"tableName\"];\n\tdb: DatabaseSchemaType[\"db\"];\n}): Promise<{ cols: string[]; rows: Record<string, CellValue>[] }> {\n\tconst pool = getDbPool(db);\n\tconst { rows } = await pool.query(`SELECT * FROM \"${tableName}\"`);\n\n\tif (!rows || rows.length === 0) {\n\t\tthrow new HTTPException(404, {\n\t\t\tmessage: `Table \"${tableName}\" does not exist or has no data`,\n\t\t});\n\t}\n\n\tconst cols = Object.keys(rows[0]);\n\n\treturn { cols, rows };\n}\n","import { HTTPException } from \"hono/http-exception\";\nimport type { TableInfoSchemaType } from \"shared/types\";\nimport type { DatabaseSchemaType } from \"shared/types/database.types.js\";\nimport { getDbPool } from \"@/db-manager.js\";\n\nexport async function getTablesList(\n\tdb: DatabaseSchemaType[\"db\"],\n): Promise<TableInfoSchemaType[]> {\n\tconst pool = getDbPool(db);\n\tconst query = `\n\tSELECT \n t.table_name as \"tableName\",\n CASE \n WHEN s.n_live_tup IS NULL OR s.n_live_tup = 0 \n THEN (SELECT COUNT(*) FROM information_schema.tables \n WHERE table_schema = 'public' \n AND table_name = t.table_name)\n ELSE s.n_live_tup \n END::integer as \"rowCount\"\nFROM information_schema.tables t\nLEFT JOIN pg_stat_user_tables s ON t.table_name = s.relname\nWHERE t.table_schema = 'public'\n AND t.table_type = 'BASE TABLE'\nORDER BY t.table_name;\n\t`;\n\n\tconst { rows } = await pool.query(query);\n\tif (!rows[0]) {\n\t\tthrow new HTTPException(500, {\n\t\t\tmessage: \"No tables returned from database\",\n\t\t});\n\t}\n\n\treturn rows;\n}\n","import type { CursorData, FilterType, SortDirection, SortType } from \"shared/types\";\n\nexport function buildWhereClause(filters: FilterType[]): {\n\tclause: string;\n\tvalues: unknown[];\n} {\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\nexport function buildSortClause(sorts: SortType[] | 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 function buildCursorWhereClause(\n\tcursorData: CursorData,\n\tdirection: SortDirection,\n\tsortDirection: SortDirection,\n\tstartParamIndex: number,\n): { clause: string; values: unknown[] } {\n\tconst { values, sortColumns } = cursorData;\n\tconst conditions: string[] = [];\n\tconst queryValues: unknown[] = [];\n\n\t// Determine comparison operator based on direction and sort order\n\t// Forward + ASC = >, Forward + DESC = <\n\t// Backward + ASC = <, Backward + DESC = >\n\tconst isAscending = sortDirection === \"asc\";\n\tconst isForward = direction === \"asc\";\n\tconst useGreaterThan = isAscending === isForward;\n\n\t// Build row comparison for multi-column cursor\n\t// Uses tuple comparison: (col1, col2, ...) > (val1, val2, ...)\n\tif (sortColumns.length > 0) {\n\t\tconst columnList = sortColumns.map((col) => `\"${col}\"`).join(\", \");\n\t\tconst placeholders = sortColumns.map((_, i) => `$${startParamIndex + i}`).join(\", \");\n\t\tconst operator = useGreaterThan ? \">\" : \"<\";\n\n\t\tconditions.push(`(${columnList}) ${operator} (${placeholders})`);\n\t\tfor (const col of sortColumns) {\n\t\t\tqueryValues.push(values[col]);\n\t\t}\n\t}\n\n\treturn {\n\t\tclause: conditions.length > 0 ? `(${conditions.join(\" AND \")})` : \"\",\n\t\tvalues: queryValues,\n\t};\n}\n","import type {\n\tCursorData,\n\tDatabaseSchemaType,\n\tFilterType,\n\tSortDirection,\n\tSortType,\n\tTableDataResultSchemaType,\n} from \"shared/types\";\nimport { getDbPool } from \"@/db-manager.js\";\nimport {\n\tbuildCursorWhereClause,\n\tbuildSortClause,\n\tbuildWhereClause,\n} from \"@/utils/build-clauses.js\";\n\n// Encode cursor data to base64 string\nconst encodeCursor = (data: CursorData): string => {\n\treturn Buffer.from(JSON.stringify(data)).toString(\"base64url\");\n};\n\n// Decode base64 cursor string to cursor data\nconst decodeCursor = (cursor: string): CursorData | null => {\n\ttry {\n\t\treturn JSON.parse(Buffer.from(cursor, \"base64url\").toString(\"utf-8\"));\n\t} catch {\n\t\treturn null;\n\t}\n};\n\n// Get primary key column(s) for a table\nconst getPrimaryKeyColumns = async (\n\tpool: ReturnType<typeof getDbPool>,\n\ttableName: string,\n): Promise<string[]> => {\n\t// Quote the table name to preserve case sensitivity in PostgreSQL\n\tconst quotedTableName = `\"${tableName}\"`;\n\tconst result = await pool.query(\n\t\t`SELECT a.attname as column_name\n\t\t FROM pg_index i\n\t\t JOIN pg_attribute a ON a.attrelid = i.indrelid AND a.attnum = ANY(i.indkey)\n\t\t WHERE i.indrelid = $1::regclass AND i.indisprimary\n\t\t ORDER BY array_position(i.indkey, a.attnum)`,\n\t\t[quotedTableName],\n\t);\n\treturn result.rows.map((row) => row.column_name);\n};\n\nexport interface GetTableDataParams {\n\ttableName: string;\n\tcursor?: string;\n\tlimit?: number;\n\tdirection?: SortDirection;\n\tsort?: string | SortType[];\n\torder?: SortDirection;\n\tfilters?: FilterType[];\n\tdb: DatabaseSchemaType[\"db\"];\n}\n\nexport const getTableData = async ({\n\ttableName,\n\tcursor = \"\",\n\tlimit = 50,\n\tdirection = \"asc\",\n\tsort = [],\n\torder = \"asc\",\n\tfilters = [],\n\tdb,\n}: GetTableDataParams): Promise<TableDataResultSchemaType> => {\n\tconst pool = getDbPool(db);\n\n\t// Get primary key columns for stable cursor pagination\n\tconst primaryKeyColumns = await getPrimaryKeyColumns(pool, tableName);\n\n\t// Determine sort columns - use provided sort or fall back to primary key\n\tlet sortColumns: string[] = [];\n\tlet effectiveSortDirection: SortDirection = order;\n\n\tif (Array.isArray(sort) && sort.length > 0) {\n\t\tsortColumns = sort.map((s) => s.columnName);\n\t\teffectiveSortDirection = sort[0].direction;\n\t} else if (typeof sort === \"string\" && sort) {\n\t\tsortColumns = [sort];\n\t}\n\t// Always include primary key columns for stable pagination\n\tconst cursorColumns = [\n\t\t...sortColumns,\n\t\t...primaryKeyColumns.filter((pk) => !sortColumns.includes(pk)),\n\t];\n\n\t// If no sort columns and no primary key, fall back to ctid (PostgreSQL internal row id)\n\tif (cursorColumns.length === 0) {\n\t\tcursorColumns.push(\"ctid\");\n\t}\n\t// Build filter WHERE clause\n\tconst { clause: filterWhereClause, values: filterValues } = buildWhereClause(filters);\n\t// Build cursor WHERE clause if cursor is provided\n\tlet cursorWhereClause = \"\";\n\tlet cursorValues: unknown[] = [];\n\n\tif (cursor) {\n\t\tconst cursorData = decodeCursor(cursor);\n\t\tif (cursorData) {\n\t\t\tconst cursorResult = buildCursorWhereClause(\n\t\t\t\tcursorData,\n\t\t\t\tdirection,\n\t\t\t\teffectiveSortDirection,\n\t\t\t\tfilterValues.length + 1,\n\t\t\t);\n\t\t\tcursorWhereClause = cursorResult.clause;\n\t\t\tcursorValues = cursorResult.values;\n\t\t}\n\t}\n\t// Combine WHERE clauses\n\tlet combinedWhereClause = \"\";\n\tif (filterWhereClause && cursorWhereClause) {\n\t\t// Remove \"WHERE \" prefix from filterWhereClause and combine\n\t\tconst filterCondition = filterWhereClause.replace(/^WHERE\\s+/i, \"\");\n\t\tcombinedWhereClause = `WHERE ${filterCondition} AND ${cursorWhereClause}`;\n\t} else if (filterWhereClause) {\n\t\tcombinedWhereClause = filterWhereClause;\n\t} else if (cursorWhereClause) {\n\t\tcombinedWhereClause = `WHERE ${cursorWhereClause}`;\n\t}\n\n\t// Build sort clause\n\tconst sortClause = buildSortClause(Array.isArray(sort) ? sort : sort, order);\n\n\t// For backward pagination, reverse the sort order\n\tlet effectiveSortClause = sortClause;\n\tif (direction === \"desc\") {\n\t\tif (sortClause) {\n\t\t\teffectiveSortClause = sortClause\n\t\t\t\t.replace(/\\bASC\\b/gi, \"TEMP_DESC\")\n\t\t\t\t.replace(/\\bDESC\\b/gi, \"ASC\")\n\t\t\t\t.replace(/TEMP_DESC/g, \"DESC\");\n\t\t} else {\n\t\t\t// Default sort by cursor columns in reverse\n\t\t\tconst reverseSortParts = cursorColumns.map(\n\t\t\t\t(col) => `\"${col}\" ${effectiveSortDirection === \"asc\" ? \"DESC\" : \"ASC\"}`,\n\t\t\t);\n\t\t\teffectiveSortClause = `ORDER BY ${reverseSortParts.join(\", \")}`;\n\t\t}\n\t} else if (!sortClause && cursorColumns.length > 0) {\n\t\t// Default sort by cursor columns\n\t\tconst defaultSortParts = cursorColumns.map(\n\t\t\t(col) => `\"${col}\" ${effectiveSortDirection.toUpperCase()}`,\n\t\t);\n\t\teffectiveSortClause = `ORDER BY ${defaultSortParts.join(\", \")}`;\n\t}\n\n\t// Get total count (with filters only, not cursor)\n\tconst countRes = await pool.query(\n\t\t`SELECT COUNT(*) as total FROM \"${tableName}\" ${filterWhereClause}`,\n\t\tfilterValues,\n\t);\n\tconst totalRows = Number(countRes.rows[0].total);\n\t// Fetch one extra row to determine if there are more results\n\tconst limitParamIndex = filterValues.length + cursorValues.length + 1;\n\tconst dataRes = await pool.query(\n\t\t`SELECT * FROM \"${tableName}\" ${combinedWhereClause} ${effectiveSortClause} LIMIT $${limitParamIndex}`,\n\t\t[...filterValues, ...cursorValues, limit + 1],\n\t);\n\t// Check if table has columns\n\tconst hasColumns = dataRes.fields && dataRes.fields.length > 0;\n\t// Filter out empty objects\n\tlet rows = hasColumns\n\t\t? dataRes.rows.filter((row) => Object.keys(row).length > 0)\n\t\t: dataRes.rows;\n\t// Determine if there are more results\n\tconst hasMore = rows.length > limit;\n\tif (hasMore) {\n\t\trows = rows.slice(0, limit);\n\t}\n\t// For backward pagination, reverse the results to maintain correct order\n\tif (direction === \"desc\") {\n\t\trows = rows.reverse();\n\t}\n\t// Build cursors for next/previous pages\n\tlet nextCursor: string | null = null;\n\tlet prevCursor: string | null = null;\n\tif (rows.length > 0) {\n\t\tconst firstRow = rows[0];\n\t\tconst lastRow = rows[rows.length - 1];\n\t\t// Create cursor from row values\n\t\tconst createCursorFromRow = (row: Record<string, unknown>): CursorData => ({\n\t\t\tvalues: Object.fromEntries(cursorColumns.map((col) => [col, row[col]])),\n\t\t\tsortColumns: cursorColumns,\n\t\t});\n\t\t// For forward pagination\n\t\tif (direction === \"asc\") {\n\t\t\t// Next cursor: if there are more results, encode the last row\n\t\t\tif (hasMore) {\n\t\t\t\tnextCursor = encodeCursor(createCursorFromRow(lastRow));\n\t\t\t}\n\t\t\t// Previous cursor: if we used a cursor to get here, encode the first row\n\t\t\tif (cursor) {\n\t\t\t\tprevCursor = encodeCursor(createCursorFromRow(firstRow));\n\t\t\t}\n\t\t} else {\n\t\t\t// For backward pagination\n\t\t\t// Next cursor: if we used a cursor, encode the last row (to go forward again)\n\t\t\tif (cursor) {\n\t\t\t\tnextCursor = encodeCursor(createCursorFromRow(lastRow));\n\t\t\t}\n\t\t\t// Previous cursor: if there are more results going backward, encode the first row\n\t\t\tif (hasMore) {\n\t\t\t\tprevCursor = encodeCursor(createCursorFromRow(firstRow));\n\t\t\t}\n\t\t}\n\t}\n\treturn {\n\t\tdata: rows,\n\t\tmeta: {\n\t\t\tlimit,\n\t\t\ttotal: totalRows,\n\t\t\thasNextPage: direction === \"asc\" ? hasMore : !!cursor,\n\t\t\thasPreviousPage: direction === \"asc\" ? !!cursor : hasMore,\n\t\t\tnextCursor,\n\t\t\tprevCursor,\n\t\t},\n\t};\n};\n","import type { CellValue, FormatType } from \"shared/types\";\nimport { utils, write } from \"xlsx\";\n\ninterface ExportFileOptions {\n\tcols: string[];\n\trows: Record<string, CellValue>[];\n\tformat: FormatType;\n\ttableName: string;\n}\n\n/**\n * Converts table data to the specified export format (CSV, XLSX, or JSON)\n *\n * @param options - The export options\n * @param options.cols - Array of column names\n * @param options.rows - Array of row data objects\n * @param options.format - The export format ('csv', 'xlsx', or 'json')\n * @param options.tableName - The name of the table being exported\n * @returns The file content as a Uint8Array\n */\nexport function getExportFile({ cols, rows, format, tableName }: ExportFileOptions): BodyInit {\n\tswitch (format) {\n\t\tcase \"json\": {\n\t\t\tconst jsonContent = JSON.stringify(rows ?? [], null, 2);\n\t\t\treturn new Uint8Array(Buffer.from(jsonContent, \"utf-8\"));\n\t\t}\n\n\t\tcase \"csv\": {\n\t\t\tconst data: CellValue[][] = [\n\t\t\t\tcols,\n\t\t\t\t...(rows?.map((row) => cols?.map((col) => row[col])) ?? []),\n\t\t\t];\n\t\t\tconst worksheet = utils.aoa_to_sheet(data);\n\t\t\tconst csvContent = utils.sheet_to_csv(worksheet);\n\t\t\treturn new Uint8Array(Buffer.from(csvContent, \"utf-8\"));\n\t\t}\n\n\t\tcase \"xlsx\": {\n\t\t\tconst data: CellValue[][] = [\n\t\t\t\tcols,\n\t\t\t\t...(rows?.map((row) => cols?.map((col) => row[col])) ?? []),\n\t\t\t];\n\t\t\tconst worksheet = utils.aoa_to_sheet(data);\n\t\t\tconst workbook = utils.book_new();\n\t\t\tutils.book_append_sheet(workbook, worksheet, tableName.slice(0, 31));\n\t\t\tconst buffer = write(workbook, {\n\t\t\t\tbookType: \"xlsx\",\n\t\t\t\ttype: \"buffer\",\n\t\t\t}) as Buffer;\n\t\t\treturn new Uint8Array(buffer);\n\t\t}\n\t}\n}\n","import { zValidator } from \"@hono/zod-validator\";\nimport { Hono } from \"hono\";\nimport {\n\ttype ColumnInfoSchemaType,\n\tcreateTableSchema,\n\tdatabaseSchema,\n\tdeleteColumnParamSchema,\n\tdeleteColumnQuerySchema,\n\texportTableSchema,\n\ttype TableDataResultSchemaType,\n\ttype TableInfoSchemaType,\n\ttableDataQuerySchema,\n\ttableNameSchema,\n} from \"shared/types\";\nimport type { ApiHandler } from \"@/app.types.js\";\nimport { createTable } from \"@/dao/create-table.dao.js\";\nimport { deleteColumn } from \"@/dao/delete-column.dao.js\";\nimport { exportTableData } from \"@/dao/export-table.dao.js\";\nimport { getTableColumns } from \"@/dao/table-columns.dao.js\";\nimport { getTablesList } from \"@/dao/table-list.dao.js\";\nimport { getTableData } from \"@/dao/tables-data.dao.js\";\nimport { getExportFile } from \"@/utils/get-export-file.js\";\n\nexport const tablesRoutes = new Hono()\n\t/**\n\t * Base path for the endpoints, /:dbType/tables/...\n\t */\n\t.basePath(\"/tables\")\n\n\t/**\n\t * GET /tables\n\t * Returns list of all tables in the currently connected database\n\t * @returns {Array} List of table info objects\n\t */\n\t.get(\n\t\t\"/\",\n\t\tzValidator(\"query\", databaseSchema),\n\t\tasync (c): ApiHandler<TableInfoSchemaType[]> => {\n\t\t\tconst { db } = c.req.valid(\"query\");\n\t\t\tconst tablesList = await getTablesList(db);\n\t\t\treturn c.json({ data: tablesList }, 200);\n\t\t},\n\t)\n\n\t/**\n\t * POST /tables\n\t * Creates a new table in the currently connected database\n\t * @param {CreateTableSchemaType} body - The data for the new table\n\t * @returns {string} A success message\n\t */\n\t.post(\n\t\t\"/\",\n\t\tzValidator(\"query\", databaseSchema),\n\t\tzValidator(\"json\", createTableSchema),\n\t\tasync (c): ApiHandler<string> => {\n\t\t\tconst { db } = c.req.valid(\"query\");\n\t\t\tconst body = c.req.valid(\"json\");\n\t\t\tawait createTable({ tableData: body, db });\n\t\t\treturn c.json({ data: `Table ${body.tableName} created successfully` }, 200);\n\t\t},\n\t)\n\n\t/**\n\t * DELETE /tables/:tableName/columns/:columnName\n\t * Deletes a column from a table\n\t * @param {DatabaseSchemaType} query - The query parameters\n\t * @param {DeleteColumnParamSchemaType} param - The URL parameters\n\t * @returns {DeleteColumnResponseType} The response\n\t */\n\t.delete(\n\t\t\"/:tableName/columns/:columnName\",\n\t\tzValidator(\"query\", deleteColumnQuerySchema),\n\t\tzValidator(\"param\", deleteColumnParamSchema),\n\t\tasync (c): ApiHandler<string> => {\n\t\t\tconst { db, cascade } = c.req.valid(\"query\");\n\t\t\tconst { tableName, columnName } = c.req.valid(\"param\");\n\t\t\tconst { deletedCount } = await deleteColumn({\n\t\t\t\ttableName,\n\t\t\t\tcolumnName,\n\t\t\t\tcascade,\n\t\t\t\tdb,\n\t\t\t});\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\tdata: `Column \"${columnName}\" deleted successfully from table \"${tableName}\" with ${deletedCount} rows deleted`,\n\t\t\t\t},\n\t\t\t\t200,\n\t\t\t);\n\t\t},\n\t)\n\n\t/**\n\t * GET /tables/:tableName/columns\n\t * Returns list of all columns in a table\n\t * @param {DatabaseSchemaType} query - The query parameters\n\t * @param {TableNameSchemaType} param - The URL parameters\n\t * @returns {ColumnInfoSchemaType[]} The response\n\t */\n\t.get(\n\t\t\"/:tableName/columns\",\n\t\tzValidator(\"query\", databaseSchema),\n\t\tzValidator(\"param\", tableNameSchema),\n\t\tasync (c): ApiHandler<ColumnInfoSchemaType[]> => {\n\t\t\tconst { db } = c.req.valid(\"query\");\n\t\t\tconst { tableName } = c.req.valid(\"param\");\n\t\t\tconst columns = await getTableColumns({ tableName, db });\n\t\t\treturn c.json({ data: columns }, 200);\n\t\t},\n\t)\n\n\t/**\n\t * GET /tables/:tableName/data\n\t * Get cursor-paginated data for a table\n\t * @param {TableNameSchemaType} param - The URL parameters\n\t * @param {TableDataQuerySchemaType} query - The query parameters\n\t * @returns {TableDataResultSchemaType} The response\n\t * @throws {HTTPException} If the table does not exist or the query is invalid\n\t */\n\t.get(\n\t\t\"/:tableName/data\",\n\t\tzValidator(\"param\", tableNameSchema),\n\t\tzValidator(\"query\", tableDataQuerySchema),\n\t\tasync (c): ApiHandler<TableDataResultSchemaType> => {\n\t\t\tconst { tableName } = c.req.valid(\"param\");\n\t\t\tconst { cursor, limit, direction, sort, order, filters, db } = c.req.valid(\"query\");\n\t\t\tconst tableData = await getTableData({\n\t\t\t\ttableName,\n\t\t\t\tcursor,\n\t\t\t\tlimit,\n\t\t\t\tdirection,\n\t\t\t\tsort,\n\t\t\t\torder,\n\t\t\t\tfilters,\n\t\t\t\tdb,\n\t\t\t});\n\t\t\treturn c.json({ data: tableData }, 200);\n\t\t},\n\t)\n\n\t/**\n\t * GET /tables/:tableName/export\n\t * Export table data to CSV or XLSX format\n\t * @param {TableNameSchemaType} param - The URL parameters\n\t * @param {ExportTableSchemaType} query - The query parameters (db, format)\n\t * @returns {BodyInit} The file content as a binary response\n\t */\n\t.get(\n\t\t\"/:tableName/export\",\n\t\tzValidator(\"param\", tableNameSchema),\n\t\tzValidator(\"query\", exportTableSchema),\n\t\tasync (c) => {\n\t\t\tconst { tableName } = c.req.valid(\"param\");\n\t\t\tconst { db, format } = c.req.valid(\"query\");\n\n\t\t\tconst { cols, rows } = await exportTableData({ tableName, db });\n\t\t\tconst fileContent = getExportFile({ cols, rows, format, tableName });\n\t\t\tlet contentType: string | undefined;\n\n\t\t\tswitch (format) {\n\t\t\t\tcase \"csv\":\n\t\t\t\t\tcontentType = \"text/csv\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"xlsx\":\n\t\t\t\t\tcontentType = \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"json\":\n\t\t\t\t\tcontentType = \"application/json\";\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\treturn new Response(fileContent, {\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": contentType ?? \"\",\n\t\t\t\t\t\"Content-Disposition\": `attachment; filename=\"${tableName}_export.${format}\"`,\n\t\t\t\t},\n\t\t\t});\n\t\t},\n\t);\n\nexport type TablesRoutes = typeof tablesRoutes.routes;\n","import path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { serveStatic } from \"@hono/node-server/serve-static\";\nimport { zValidator } from \"@hono/zod-validator\";\nimport { Hono } from \"hono\";\nimport { cors } from \"hono/cors\";\nimport { logger } from \"hono/logger\";\nimport { prettyJSON } from \"hono/pretty-json\";\nimport { type DatabaseTypeSchema, databaseTypeParamSchema } from \"shared/types\";\nimport type { AppType } from \"@/app.types.js\";\nimport { handleError, validationHook } from \"@/middlewares/error-handler.js\";\nimport { chatRoutes } from \"@/routes/chat.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\";\n\n/**\n * Get the path to the core distribution directory.\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<AppType>({ strict: false })\n\t\t/**\n\t\t * Enable CORS\n\t\t */\n\t\t.use(\"/*\", cors())\n\n\t\t/**\n\t\t * Pretty print the JSON response\n\t\t */\n\t\t.use(prettyJSON({ space: 2 }))\n\n\t\t/**\n\t\t * Enable logger in development mode\n\t\t */\n\t\t.use(process.env.NODE_ENV === \"development\" ? logger() : (_, next) => next())\n\n\t\t/**\n\t\t * Serve the favicon.ico file\n\t\t */\n\t\t.use(\n\t\t\t\"/favicon.ico\",\n\t\t\tserveStatic({\n\t\t\t\tpath: path.resolve(getCoreDistPath(), \"favicon.ico\"),\n\t\t\t}),\n\t\t)\n\n\t\t/**\n\t\t * Handle CORS requests\n\t\t */\n\t\t.use(\"*\", async (c, next) => {\n\t\t\tc.header(\"Access-Control-Allow-Origin\", \"*\");\n\t\t\tc.header(\"Access-Control-Allow-Methods\", \"GET, POST, PUT, DELETE, OPTIONS\");\n\t\t\tc.header(\"Access-Control-Allow-Headers\", \"Content-Type\");\n\t\t\tawait next();\n\t\t})\n\n\t\t/**\n\t\t * Handle errors\n\t\t */\n\t\t.onError(handleError)\n\n\t\t/**\n\t\t * Database routes - available at root level (no dbType required)\n\t\t */\n\t\t.route(\"/\", databasesRoutes)\n\n\t\t/**\n\t\t * Serve static assets (before dbType validation to avoid conflicts)\n\t\t */\n\t\t.use(\"/assets/*\", serveStatic({ root: getCoreDistPath() }))\n\t\t.use(\"/image.png\", serveStatic({ root: getCoreDistPath() }))\n\n\t\t/**\n\t\t * Routes that require dbType validation - under /:dbType/...\n\t\t */\n\t\t.use(\"/:dbType/*\", zValidator(\"param\", databaseTypeParamSchema, validationHook))\n\t\t.use(\"/:dbType/*\", async (c, next) => {\n\t\t\tconst dbType = c.req.param(\"dbType\") as DatabaseTypeSchema;\n\t\t\tc.set(\"dbType\", dbType);\n\t\t\tawait next();\n\t\t})\n\t\t.route(\"/:dbType\", tablesRoutes)\n\t\t.route(\"/:dbType\", recordsRoutes)\n\t\t.route(\"/:dbType\", queryRoutes)\n\t\t.route(\"/:dbType\", chatRoutes)\n\n\t\t/**\n\t\t * Serve all other static files as fallback (for SPA)\n\t\t */\n\t\t.use(\"/*\", serveStatic({ root: getCoreDistPath() }));\n\n\treturn { app };\n};\n\nexport type { AppType };\n\n// Export the app type for hc client\nexport type AppRoutes = ReturnType<typeof createServer>[\"app\"];\n","import { intro, outro } from \"@clack/prompts\";\nimport { serve } from \"@hono/node-server\";\nimport open from \"open\";\nimport color from \"picocolors\";\nimport { DEFAULTS } from \"shared/constants\";\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\";\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();\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 } = createServer();\n\tserve({\n\t\tfetch: app.fetch,\n\t\tport: PORT,\n\t});\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\";\nimport type { Args } from \"shared/types\";\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\";\n\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 .env file, then process.env\n */\nexport const getDatabaseUrl = async (env?: DotenvParseOutput | null, varName?: string) => {\n\tconst envVarName = varName || \"DATABASE_URL\";\n\n\tif (env?.[envVarName]) {\n\t\treturn env[envVarName];\n\t}\n\n\t// Fall back to process.env (e.g. from shell or package.json script)\n\tif (process.env[envVarName]) {\n\t\treturn process.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 and ${envVarName} not set in process.env`));\n\t} else {\n\t\tnote(color.red(`${envVarName} not found in .env or process.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 { dirname, resolve } from \"node:path\";\n\nimport { parse as parseDotenv } from \"dotenv\";\n\n/**\n * Find .env path: try cwd, then walk up parent directories until root.\n */\nconst findEnvPath = async (startDir: string): Promise<string | null> => {\n\tlet dir = resolve(startDir);\n\tfor (;;) {\n\t\tconst envPath = resolve(dir, \".env\");\n\t\ttry {\n\t\t\tawait access(envPath);\n\t\t\treturn envPath;\n\t\t} catch {\n\t\t\t// ENOENT or other: try parent\n\t\t}\n\t\tconst parent = dirname(dir);\n\t\tif (parent === dir) return null;\n\t\tdir = parent;\n\t}\n};\n\n/**\n * Load the environment variables from the file.\n * When no path is given: tries current directory, then parent directories until a .env is found.\n * When --env path is given: uses that path only (no walk).\n */\nexport const loadEnv = async (env?: string) => {\n\tlet envPath: string | null;\n\n\tif (env) {\n\t\tenvPath = resolve(env);\n\t} else {\n\t\tenvPath = await findEnvPath(process.cwd());\n\t}\n\n\tif (!envPath) return null;\n\n\ttry {\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;\n\t\t}\n\t\tthrow err;\n\t}\n};\n","import { intro, outro } from \"@clack/prompts\";\nimport color from \"picocolors\";\nimport { META } from \"shared/constants/meta.js\";\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: ${META.SITE_DOCS_LINK}`));\n};\n","import { intro, note, outro } from \"@clack/prompts\";\nimport color from \"picocolors\";\nimport { DEFAULTS } from \"shared/constants\";\nimport { loadEnv } from \"@/cmd/load-env.js\";\n\n/**\n * Show connection status\n */\nexport const showStatus = async (env?: string, databaseUrl?: string, varName?: string) => {\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 .env file, then process.env\n\t\tconst ENV = env ? await loadEnv(env) : await loadEnv();\n\t\tif (ENV?.[envVarName]) {\n\t\t\tfoundUrl = ENV[envVarName];\n\t\t} else if (process.env[envVarName]) {\n\t\t\tfoundUrl = process.env[envVarName] ?? null;\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 or set it in process.env`));\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.25\",\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 --minify --sourcemap\",\n \"prepack\": \"cd ../core && bun run build && cd ../server && bun run build\",\n \"start\": \"node dist/index.js\",\n \"check\": \"biome check --write --unsafe\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"test:coverage\": \"vitest run --coverage\"\n },\n \"dependencies\": {\n \"@clack/prompts\": \"^0.11.0\",\n \"@hono/node-server\": \"^1.19.7\",\n \"@hono/zod-validator\": \"^0.7.6\",\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 \"xlsx\": \"^0.18.5\",\n \"zod\": \"^4.2.1\"\n },\n \"devDependencies\": {\n \"@biomejs/biome\": \"^2.2.6\",\n \"@types/node\": \"^20.11.17\",\n \"@types/pg\": \"^8.16.0\",\n \"@vitest/coverage-v8\": \"^4.0.17\",\n \"shared\": \"workspace:*\",\n \"tsup\": \"^8.5.1\",\n \"tsx\": \"^4.7.1\",\n \"typescript\": \"^5.8.3\",\n \"vitest\": \"^4.0.17\"\n }\n}"],"mappings":"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","names":["init_chat","__esmMin","DEFAULTS","init_defaults","__esmMin","init_links","__esmMin","META","init_meta","__esmMin","init_proxy_limits","__esmMin","init_constants","__esmMin","init_chat","init_defaults","init_links","init_meta","init_proxy_limits","z","addRecordSchema","init_add_record_types","__esmMin","init_api_response_types","__esmMin","z","bulkInsertRecordsSchema","init_bulk_insert_records_type","__esmMin","z","databaseSchema","DATABASE_TYPES","databaseTypeSchema","currentDatabaseSchema","databaseTypeParamSchema","tableNameSchema","init_database_types","__esmMin","z","chatSchema","init_chat_types","__esmMin","init_database_types","databaseSchema","init_cmd_args_types","__esmMin","z","dataTypes","dataTypesSchema","DataTypes","standardizedDataTypes","standardizedDataTypeSchema","columnInfoSchema","init_column_info_types","__esmMin","mapPostgresToDataType","pgType","normalized","DataTypes","standardizeDataTypeLabel","StandardizedDataType","init_column_type","__esmMin","init_column_info_types","z","FOREIGN_KEY_ACTIONS","foreignKeyActionSchema","fieldDataSchema","foreignKeyDataSchema","createTableSchema","init_create_table_types","__esmMin","z","databaseInfoSchema","databaseListSchema","connectionInfoSchema","init_database_list_types","__esmMin","init_database_types","databaseTypeSchema","init_database_schema_type","__esmMin","z","deleteColumnQuerySchema","deleteColumnParamSchema","deleteColumnParamsSchema","deleteColumnSuccessResponseSchema","init_delete_column_types","__esmMin","init_database_types","databaseSchema","val","z","deleteRecordSchema","init_delete_record_types","__esmMin","z","executeQuerySchema","init_execute_query_types","__esmMin","z","FORMAT_TYPES","exportTableSchema","init_export_table_types","__esmMin","init_database_types","databaseSchema","init_rate_limit_response_type","__esmMin","z","filterSchema","sortDirections","sortSchema","tableDataMetaSchema","tableDataResultSchema","tableDataQuerySchema","init_table_data_types","__esmMin","init_database_types","databaseSchema","val","parsed","z","tableInfoSchema","init_table_info_type","__esmMin","z","updateRecordsSchema","init_update_recors_types","__esmMin","init_types","__esmMin","init_add_record_types","init_api_response_types","init_bulk_insert_records_type","init_chat_types","init_cmd_args_types","init_column_type","init_column_info_types","init_create_table_types","init_database_types","init_database_list_types","init_database_schema_type","init_delete_column_types","init_delete_record_types","init_execute_query_types","init_export_table_types","init_rate_limit_response_type","init_table_data_types","init_table_info_type","init_update_recors_types","HTTPException","DatabaseError","ZodError","handleError","e","c","issue","validationHook","init_error_handler","__esmMin","result","Pool","dbInstance","getPool","db","init_db","__esmMin","err","error","_target","prop","Pool","DatabaseManager","databaseManager","getDbPool","getDbType","init_db_manager","__esmMin","url","protocol","databaseUrl","error","database","connectionString","poolConfig","pool","err","closePromises","HTTPException","getTableColumns","tableName","db","pool","getDbPool","query","rows","r","parsedEnumValues","mapPostgresToDataType","standardizeDataTypeLabel","init_table_columns_dao","__esmMin","init_types","init_db_manager","getTableNames","db","pool","getDbPool","query","rows","r","getTableDescription","tableName","client","getSampleData","convertColumnInfo","col","column","extractRelationships","tables","relationships","table","toTable","toColumn","getDatabaseSchema","options","includeSampleData","includeDescriptions","tablePromises","columns","description","sampleData","getTableColumns","row","key","value","error","getDetailedSchema","init_table_details_schema","__esmMin","init_db","init_db_manager","init_table_columns_dao","generateSystemPrompt","schema","formatSchemaForPrompt","output","table","col","pkIndicator","fkIndicator","nullable","rel","init_system_prompt_generator","__esmMin","zValidator","Hono","chatRoutes","init_chat_routes","__esmMin","init_constants","init_types","init_table_details_schema","init_system_prompt_generator","chatSchema","c","messages","conversationId","db","schema","getDetailedSchema","systemPrompt","generateSystemPrompt","payload","proxyResponse","DEFAULTS","errorData","readable","writable","parseDatabaseUrl","databaseUrl","url","init_parse_database_url","__esmMin","HTTPException","getDatabasesList","pool","getDbPool","query","rows","getCurrentDatabase","getDatabaseConnectionInfo","result","connectionInfoSchema","urlDefaults","parseDatabaseUrl","init_database_list_dao","__esmMin","init_types","init_db_manager","init_parse_database_url","Hono","databasesRoutes","init_databases_routes","__esmMin","init_database_list_dao","init_db_manager","c","databases","getDatabasesList","dbType","getDbType","current","getCurrentDatabase","info","getDatabaseConnectionInfo","HTTPException","executeQuery","init_query_dao","__esmMin","init_db_manager","query","db","pool","getDbPool","cleanedQuery","startTime","result","duration","field","zValidator","Hono","queryRoutes","init_query_routes","__esmMin","init_types","init_query_dao","databaseSchema","executeQuerySchema","c","query","db","data","executeQuery","HTTPException","addRecord","db","params","tableName","data","pool","getDbPool","columns","values","placeholders","_","index","columnNames","col","query","result","init_add_record_dao","__esmMin","init_db_manager","HTTPException","bulkInsertRecords","init_bulk_insert_records_dao","__esmMin","init_db_manager","tableName","records","db","client","getDbPool","columns","columnNames","col","successCount","failureCount","errors","i","record","values","placeholders","_","index","insertSQL","error","HTTPException","getForeignKeyReferences","tableName","db","getDbPool","row","getRelatedRecords","primaryKeys","fkConstraints","relatedRecords","pool","constraintsByTable","constraint","key","pkValues","pk","_tableColumn","constraints","placeholders","_","i","relatedQuery","relatedResult","deleteRecords","pkColumn","query","result","error","forceDeleteRecords","totalRelatedDeleted","deletedTables","deleteRelatedRecursively","targetTable","targetColumn","values","nestedFks","nestedFk","nestedPlaceholders","selectQuery","nestedValues","deletePlaceholders","deleteQuery","deleteResult","init_delete_records_dao","__esmMin","init_db_manager","HTTPException","updateRecords","params","db","tableName","updates","primaryKey","pool","getDbPool","updatesByRow","update","pkValue","totalUpdated","rowUpdates","setClauses","u","index","values","query","result","error","init_update_records_dao","__esmMin","init_db_manager","zValidator","Hono","recordsRoutes","init_records_routes","__esmMin","init_types","init_add_record_dao","init_bulk_insert_records_dao","init_delete_records_dao","init_update_records_dao","databaseSchema","addRecordSchema","c","db","tableName","data","insertedCount","addRecord","updateRecordsSchema","primaryKey","updates","updatedCount","updateRecords","deleteRecordSchema","primaryKeys","deletedCount","fkViolation","relatedRecords","deleteRecords","forceDeleteRecords","bulkInsertRecordsSchema","records","result","bulkInsertRecords","createTable","tableData","db","tableName","fields","foreignKeys","pool","getDbPool","columnDefinitions","field","columnDef","foreignKeyConstraints","fk","allDefinitions","createTableSQL","init_create_table_dao","__esmMin","init_db_manager","HTTPException","deleteColumn","params","tableName","columnName","cascade","db","pool","getDbPool","tableExistsQuery","tableRows","columnExistsQuery","columnRows","dropColumnSQL","rowCount","init_delete_column_dao","__esmMin","init_db_manager","HTTPException","exportTableData","tableName","db","pool","getDbPool","rows","init_export_table_dao","__esmMin","init_db_manager","HTTPException","getTablesList","db","pool","getDbPool","query","rows","init_table_list_dao","__esmMin","init_db_manager","buildWhereClause","filters","conditions","values","filter","paramIndex","columnName","buildSortClause","sorts","order","sort","buildCursorWhereClause","cursorData","direction","sortDirection","startParamIndex","sortColumns","queryValues","useGreaterThan","columnList","col","placeholders","_","i","operator","init_build_clauses","__esmMin","encodeCursor","decodeCursor","getPrimaryKeyColumns","getTableData","init_tables_data_dao","__esmMin","init_db_manager","init_build_clauses","data","cursor","pool","tableName","quotedTableName","row","limit","direction","sort","order","filters","db","getDbPool","primaryKeyColumns","sortColumns","effectiveSortDirection","s","cursorColumns","pk","filterWhereClause","filterValues","buildWhereClause","cursorWhereClause","cursorValues","cursorData","cursorResult","buildCursorWhereClause","combinedWhereClause","sortClause","buildSortClause","effectiveSortClause","col","countRes","totalRows","limitParamIndex","dataRes","rows","hasMore","nextCursor","prevCursor","firstRow","lastRow","createCursorFromRow","utils","write","getExportFile","cols","rows","format","tableName","jsonContent","data","row","col","worksheet","csvContent","workbook","buffer","init_get_export_file","__esmMin","zValidator","Hono","tablesRoutes","init_tables_routes","__esmMin","init_types","init_create_table_dao","init_delete_column_dao","init_export_table_dao","init_table_columns_dao","init_table_list_dao","init_tables_data_dao","init_get_export_file","databaseSchema","c","db","tablesList","getTablesList","createTableSchema","body","createTable","deleteColumnQuerySchema","deleteColumnParamSchema","cascade","tableName","columnName","deletedCount","deleteColumn","tableNameSchema","columns","getTableColumns","tableDataQuerySchema","cursor","limit","direction","sort","order","filters","tableData","getTableData","exportTableSchema","format","cols","rows","exportTableData","fileContent","getExportFile","contentType","create_server_exports","__export","createServer","path","fileURLToPath","serveStatic","zValidator","Hono","cors","logger","prettyJSON","getCoreDistPath","init_create_server","__esmMin","init_types","init_error_handler","init_chat_routes","init_databases_routes","init_query_routes","init_records_routes","init_tables_routes","__dirname","_","next","c","handleError","databasesRoutes","databaseTypeParamSchema","validationHook","dbType","tablesRoutes","recordsRoutes","queryRoutes","chatRoutes","init_constants","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","dirname","resolve","parseDotenv","findEnvPath","startDir","dir","envPath","parent","loadEnv","env","content","err","init_meta","intro","outro","color","showHelp","META","init_constants","intro","note","outro","color","showStatus","env","databaseUrl","varName","intro","color","envVarName","DEFAULTS","foundUrl","ENV","loadEnv","outro","note","intro","outro","color","package_default","showVersion","intro","color","outro","package_default","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","serve","outro","open","err"]}
|
|
1
|
+
{"version":3,"sources":["../../shared/src/constants/chat.ts","../../shared/src/constants/defaults.ts","../../shared/src/constants/links.ts","../../shared/src/constants/meta.ts","../../shared/src/constants/proxy-limits.ts","../../shared/src/constants/index.ts","../../shared/src/types/add-record.types.ts","../../shared/src/types/api-response.types.ts","../../shared/src/types/bulk-insert-records.type.ts","../../shared/src/types/database.types.ts","../../shared/src/types/chat.types.ts","../../shared/src/types/cmd-args.types.ts","../../shared/src/types/column-info.types.ts","../../shared/src/types/column.type.ts","../../shared/src/types/create-table.types.ts","../../shared/src/types/database-list.types.ts","../../shared/src/types/database-schema.type.ts","../../shared/src/types/delete-column.types.ts","../../shared/src/types/delete-record.types.ts","../../shared/src/types/execute-query.types.ts","../../shared/src/types/export-table.types.ts","../../shared/src/types/rate-limit-response.type.ts","../../shared/src/types/table-data.types.ts","../../shared/src/types/table-info.type.ts","../../shared/src/types/update-recors.types.ts","../../shared/src/types/index.ts","../src/middlewares/error-handler.ts","../src/db.ts","../src/db-manager.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/utils/parse-database-url.ts","../src/dao/database-list.dao.ts","../src/routes/databases.routes.ts","../src/dao/query.dao.ts","../src/routes/query.routes.ts","../src/dao/add-record.dao.ts","../src/dao/bulk-insert-records.dao.ts","../src/dao/delete-records.dao.ts","../src/dao/update-records.dao.ts","../src/routes/records.routes.ts","../src/dao/create-table.dao.ts","../src/dao/delete-column.dao.ts","../src/dao/export-table.dao.ts","../src/dao/table-list.dao.ts","../src/utils/build-clauses.ts","../src/dao/tables-data.dao.ts","../src/utils/get-export-file.ts","../src/routes/tables.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 CHAT_SUGGESTIONS = [\n\t\"Show me all tables in my database\",\n\t\"What columns are in the users table?\",\n\t\"Write a query to find all active users\",\n\t\"How many orders were placed last month?\",\n\t\"Find top 5 customers by total spend\",\n\t\"Write a JOIN between users and orders\",\n\t\"Users who haven't made any purchase yet\",\n\t\"Generate monthly revenue summary query\",\n\t\"Suggest useful indexes for better performance\",\n\t\"Show schema of the products / inventory table\",\n\t\"Latest 20 orders with customer names\",\n\t\"Help me write a safe UPDATE query\",\n];\n\n// const MODEL_LIST = [\n// \t{\n// \t\tid: \"gpt-4o\",\n// \t\tname: \"GPT-4o\",\n// \t\tchef: \"OpenAI\",\n// \t\tchefSlug: \"openai\",\n// \t},\n// \t{\n// \t\tid: \"gpt-4o-mini\",\n// \t\tname: \"GPT-4o Mini\",\n// \t\tchef: \"OpenAI\",\n// \t\tchefSlug: \"openai\",\n// \t},\n// \t{\n// \t\tid: \"claude-opus-4-20250514\",\n// \t\tname: \"Claude 4 Opus\",\n// \t\tchef: \"Anthropic\",\n// \t\tchefSlug: \"anthropic\",\n// \t},\n// \t{\n// \t\tid: \"claude-sonnet-4-20250514\",\n// \t\tname: \"Claude 4 Sonnet\",\n// \t\tchef: \"Anthropic\",\n// \t\tchefSlug: \"anthropic\",\n// \t},\n// \t{\n// \t\tid: \"gemini-2.0-flash-exp\",\n// \t\tname: \"Gemini 2.0 Flash\",\n// \t\tchef: \"Google\",\n// \t\tchefSlug: \"google\",\n// \t},\n// ];\n","export const DEFAULTS = {\n\tPORT: 3333,\n\tENV: \".env\",\n\tVAR_NAME: \"DATABASE_URL\",\n\tBASE_URL: \"http://localhost:3333\",\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","export const HEADER_LINKS = [\n\t{ label: \"Home\", href: \"/\" },\n\t{ label: \"Roadmap\", href: \"/roadmap\" },\n\t{ label: \"Docs\", href: \"/docs/$\" },\n\t{ label: \"Changelog\", href: \"/changelog\" },\n];\n","export const META = {\n\t//* author\n\tAUTHOR: \"Hüsam 🥑 <devhsmq@gmail.com>\",\n\tAUTHOR_NAME: \"Hüsam\",\n\tAUTHOR_AVATAR: \"/avocado.png\",\n\tAUTHOR_USERNAME: \"husamql3\",\n\tAUTHOR_GITHUB_LINK: \"https://github.com/husamql3\",\n\t//* site\n\tSITE_DESCRIPTION: \"The modern pgAdmin alternative that works with every database.\",\n\tSITE_KEYWORDS: [\"database\", \"management\", \"studio\", \"spreadsheet\", \"ai\", \"sql\"],\n\tSITE_TITLE: \"DB Studio\",\n\tSITE_NAME: \"dbstudio.sh\",\n\tSITE_URL: \"https://dbstudio.sh\",\n\tSITE_X_LINK: \"https://x.com/dbstudio_sh\",\n\tSITE_GITHUB_LINK: \"https://github.com/husamql3/db-studio\",\n\tSITE_DOCS_LINK: \"https://dbstudio.sh/docs\",\n\tSITE_CHANGELOG_LINK: \"https://dbstudio.sh/changelog\",\n\tSITE_ROADMAP_LINK: \"https://dbstudio.sh/roadmap\",\n\tSITE_IMAGE: \"/og-image.png\",\n\tSITE_IMAGE_WIDTH: \"1200\",\n\tSITE_IMAGE_HEIGHT: \"630\",\n\tSITE_IMAGE_ALT: \"dbstudio.sh – Modern database management studio\",\n\tSITE_COLOR: \"#1447e6\",\n};\n","export const ONE_DAY = 24 * 60 * 60 * 1000;\nexport const LIMIT = 3;\n","export * from \"./chat.js\";\nexport * from \"./defaults.js\";\nexport * from \"./links.js\";\nexport * from \"./meta.js\";\nexport * from \"./proxy-limits.js\";\n","import { z } from \"zod\";\n\nexport const addRecordSchema = z.object({\n\ttableName: z.string(\"Table name is required\"),\n\tdata: z.record(z.string(\"Column name is required\"), z.any()),\n});\n\nexport type AddRecordSchemaType = z.infer<typeof addRecordSchema>;\n","/**\n * Standard API success response wrapper type\n * Used by both server and client\n */\nexport type BaseResponse<T> = {\n\tdata: T;\n\tmessage?: string;\n};\n\n/**\n * Standard API error response type\n */\nexport type ApiError = {\n\terror: string;\n\tdetails?: string;\n};\n","import { z } from \"zod\";\nimport type { DatabaseSchemaType } from \"./database.types\";\n\nexport type BulkInsertRecordsParams = {\n\ttableName: string;\n\trecords: Record<string, unknown>[];\n\tdb: DatabaseSchemaType[\"db\"];\n};\n\nexport type BulkInsertResult = {\n\tsuccess: boolean;\n\tmessage: string;\n\tsuccessCount: number;\n\tfailureCount: number;\n\terrors?: Array<{ recordIndex: number; error: string }>;\n};\n\nexport const bulkInsertRecordsSchema = z.object({\n\ttableName: z.string().min(1, \"Table name is required\"),\n\trecords: z.array(z.record(z.string(), z.any())).min(1, \"At least one record is required\"),\n});\n","import { z } from \"zod\";\n\nexport const databaseSchema = z.object({\n\tdb: z.string(\"Database name is required\"),\n});\n\nexport type DatabaseSchemaType = z.infer<typeof databaseSchema>;\n\nexport const DATABASE_TYPES = [\"pg\"] as const;\n\nexport const databaseTypeSchema = z.enum(DATABASE_TYPES, {\n\tmessage: \"Invalid database type\",\n});\nexport type DatabaseTypeSchema = z.infer<typeof databaseTypeSchema>;\n\nexport const currentDatabaseSchema = databaseSchema.extend({\n\tdbType: databaseTypeSchema,\n});\nexport type CurrentDatabaseSchemaType = z.infer<typeof currentDatabaseSchema>;\n\nexport const databaseTypeParamSchema = z.object({\n\tdbType: databaseTypeSchema,\n});\n\nexport const tableNameSchema = z.object({\n\ttableName: z.string(\"Table name is required\"),\n});\n\nexport type TableNameSchemaType = z.infer<typeof tableNameSchema>;\n","import { z } from \"zod\";\nimport { databaseSchema } from \"./database.types.js\";\n\nexport const chatSchema = z.object({\n\tmessages: z.array(\n\t\tz.object({\n\t\t\trole: z.enum([\"user\", \"assistant\"]),\n\t\t\tcontent: z.string(\"Content is required\"),\n\t\t}),\n\t),\n\tconversationId: z.string().optional(),\n\tdb: databaseSchema.shape.db,\n});\n","export type Args = {\n\tenv?: string;\n\tport?: string;\n\tdatabaseUrl?: string;\n\tvarName?: string;\n\tstatus?: boolean;\n\thelp?: boolean;\n\tversion?: boolean;\n};\n","import { z } from \"zod\";\n\nconst dataTypes = [\"text\", \"boolean\", \"number\", \"enum\", \"json\", \"date\", \"array\"] as const;\n\nexport const dataTypesSchema = z.enum(dataTypes);\nexport type DataTypes = z.infer<typeof dataTypesSchema>;\n\nexport 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 satisfies Record<DataTypes, string>;\n\nconst standardizedDataTypes = [\n\t\"int\",\n\t\"bigint\",\n\t\"smallint\",\n\t\"numeric\",\n\t\"float\",\n\t\"double\",\n\t\"money\",\n\t\"boolean\",\n\t\"text\",\n\t\"varchar\",\n\t\"char\",\n\t\"json\",\n\t\"jsonb\",\n\t\"xml\",\n\t\"uuid\",\n\t\"date\",\n\t\"time\",\n\t\"timestamp\",\n\t\"timestamptz\",\n\t\"interval\",\n\t\"bytea\",\n\t\"inet\",\n\t\"cidr\",\n\t\"macaddr\",\n\t\"macaddr8\",\n\t\"point\",\n\t\"line\",\n\t\"polygon\",\n\t\"array\",\n\t\"enum\",\n] as const;\n\nexport const standardizedDataTypeSchema = z.enum(standardizedDataTypes);\n\nexport const columnInfoSchema = z.object({\n\tcolumnName: z.string(),\n\tdataType: dataTypesSchema,\n\tdataTypeLabel: standardizedDataTypeSchema,\n\tisNullable: z.boolean(),\n\tcolumnDefault: z.string().nullable(),\n\tisPrimaryKey: z.boolean(),\n\tisForeignKey: z.boolean(),\n\treferencedTable: z.string().nullable(),\n\treferencedColumn: z.string().nullable(),\n\tenumValues: z.array(z.string()).nullable(),\n});\n\nexport type ColumnInfoSchemaType = z.infer<typeof columnInfoSchema>;\n","import { DataTypes } from \"./column-info.types.js\";\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(\n\tpgType: string | null | undefined,\n): StandardizedDataType {\n\tif (!pgType) {\n\t\treturn StandardizedDataType.text; // Default fallback\n\t}\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 (normalized === \"double precision\" || normalized === \"float8\" || normalized === \"float\") {\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 { 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);\n\nexport const fieldDataSchema = z.object({\n\tcolumnName: z.string(\"Column name is required\"),\n\tcolumnType: z.string(\"Column type is required\"),\n\tdefaultValue: z.string().optional(),\n\tisPrimaryKey: z.boolean().default(false),\n\tisNullable: z.boolean().default(false),\n\tisUnique: z.boolean().default(false),\n\tisIdentity: z.boolean().default(false),\n\tisArray: z.boolean().default(false),\n});\nexport type FieldDataType = z.infer<typeof fieldDataSchema>;\n\nexport const foreignKeyDataSchema = z.object({\n\tcolumnName: z.string(\"Column name is required\"),\n\treferencedTable: z.string(\"Referenced table is required\"),\n\treferencedColumn: z.string(\"Referenced column is required\"),\n\tonUpdate: foreignKeyActionSchema.default(\"NO ACTION\"),\n\tonDelete: foreignKeyActionSchema.default(\"NO ACTION\"),\n});\nexport type ForeignKeyDataType = z.infer<typeof foreignKeyDataSchema>;\n\nexport const createTableSchema = z.object({\n\ttableName: z.string(\"Table name is required\"),\n\tfields: z.array(fieldDataSchema).min(1, \"At least one field is required\"),\n\tforeignKeys: z.array(foreignKeyDataSchema).optional(),\n});\n\nexport type CreateTableSchemaType = z.infer<typeof createTableSchema>;\n","import { z } from \"zod\";\nimport { databaseTypeSchema } from \"./database.types.js\";\n\nexport const databaseInfoSchema = z.object({\n\tname: z.string(\"Name is required\"),\n\tsize: z.string(\"Size is required\"),\n\towner: z.string(\"Owner is required\"),\n\tencoding: z.string(\"Encoding is required\"),\n});\n\nexport type DatabaseInfoSchemaType = z.infer<typeof databaseInfoSchema>;\n\nexport const databaseListSchema = z.object({\n\tdatabases: z.array(databaseInfoSchema),\n\tdbType: databaseTypeSchema,\n});\n\nexport type DatabaseListSchemaType = z.infer<typeof databaseListSchema>;\n\nexport const connectionInfoSchema = z.object({\n\tversion: z.string(\"Version is required\"),\n\tdatabase: z.string(\"Database is required\"),\n\tuser: z.string(\"User is required\"),\n\thost: z.string(\"Host is required\").nullable(),\n\tport: z.number(\"Port is required\").nullable(),\n\tactive_connections: z.coerce.number(\"Active connections is required\"),\n\tmax_connections: z.coerce.number(\"Max connections is required\"),\n});\n\nexport type ConnectionInfoSchemaType = z.infer<typeof connectionInfoSchema>;\n","import type { DatabaseTypeSchema } from \"./database.types\";\n\nexport type DatabaseSchema = {\n\tdbType: DatabaseTypeSchema;\n\ttables: Table[];\n\trelationships: Relationship[];\n};\n\nexport type Table = {\n\tname: string;\n\tdescription?: string;\n\tcolumns: Column[];\n\tsampleData?: Record<string, string>[];\n};\n\nexport type Column = {\n\tname: string;\n\ttype: string;\n\tnullable: boolean;\n\tisPrimaryKey?: boolean;\n\tforeignKey?: string;\n\tdescription?: string;\n\tenumValues?: string[];\n};\n\nexport type Relationship = {\n\tfromTable: string;\n\tfromColumn: string;\n\ttoTable: string;\n\ttoColumn: string;\n};\n","import { z } from \"zod\";\nimport { databaseSchema } from \"./database.types\";\n\nexport const deleteColumnQuerySchema = databaseSchema.extend({\n\tcascade: z\n\t\t.string()\n\t\t.optional()\n\t\t.transform((val) => val === \"true\"),\n});\n\nexport type DeleteColumnQuerySchemaType = z.infer<typeof deleteColumnQuerySchema>;\n\nexport const deleteColumnParamSchema = z.object({\n\ttableName: z.string(\"Table name is required\"),\n\tcolumnName: z.string(\"Column name is required\"),\n});\n\nexport const deleteColumnParamsSchema = z.object({\n\tdb: databaseSchema.shape.db,\n\ttableName: deleteColumnParamSchema.shape.tableName,\n\tcolumnName: deleteColumnParamSchema.shape.columnName,\n\tcascade: z.boolean().optional(),\n});\n\nexport type DeleteColumnParamsSchemaType = z.infer<typeof deleteColumnParamsSchema>;\n\nexport const deleteColumnSuccessResponseSchema = z.object({\n\tmessage: z.string(\"Message is required\"),\n\ttableName: z.string(\"Table name is required\"),\n\tcolumnName: z.string(\"Column name is required\"),\n\tdeletedCount: z.number(\"Deleted count is required\").default(0),\n});\n\nexport type DeleteColumnResponseType = z.infer<typeof deleteColumnSuccessResponseSchema>;\n","import { z } from \"zod\";\nimport type { DatabaseSchemaType } from \"./database.types\";\n\nexport const deleteRecordSchema = z.object({\n\ttableName: z.string(\"Table name is required\"),\n\tprimaryKeys: z\n\t\t.array(\n\t\t\tz.object({\n\t\t\t\tcolumnName: z.string(\"Column name is required\"),\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 type DeleteRecordSchemaType = z.infer<typeof deleteRecordSchema>;\n\nexport type DeleteRecordParams = DeleteRecordSchemaType & {\n\tdb: DatabaseSchemaType[\"db\"];\n};\n\nexport type DeleteRecordResult = {\n\tdeletedCount: number;\n\tfkViolation: boolean;\n\trelatedRecords: RelatedRecord[];\n};\n\nexport type ForeignKeyConstraint = {\n\tconstraintName: string;\n\treferencingTable: string;\n\treferencingColumn: string;\n\treferencedTable: string;\n\treferencedColumn: string;\n};\n\nexport type ForeignKeyConstraintRow = {\n\tconstraint_name: string;\n\treferencing_table: string;\n\treferencing_column: string;\n\treferenced_table: string;\n\treferenced_column: string;\n};\n\nexport type RelatedRecord = {\n\ttableName: string;\n\tcolumnName: string;\n\tconstraintName: string;\n\trecords: Array<Record<string, unknown>>;\n};\n","import { z } from \"zod\";\n\nexport const executeQuerySchema = z.object({\n\tquery: z.string(\"Query is required\"),\n});\n\nexport type ExecuteQueryParams = z.infer<typeof executeQuerySchema>;\n\nexport type ExecuteQueryResult = {\n\tcolumns: string[];\n\trows: Record<string, unknown>[];\n\trowCount: number;\n\tduration: number;\n\tmessage?: string;\n\terror?: string;\n};\n","import { z } from \"zod\";\nimport { databaseSchema } from \"./database.types.js\";\n\nexport const FORMAT_TYPES = [\"csv\", \"xlsx\", \"json\"] as const;\nexport type FormatType = (typeof FORMAT_TYPES)[number];\n\nexport const exportTableSchema = databaseSchema.extend({\n\tformat: z.enum(FORMAT_TYPES, {\n\t\tmessage: \"Invalid format. Supported formats: csv, xlsx, json\",\n\t}),\n});\nexport type ExportTableSchemaType = z.infer<typeof exportTableSchema>;\n\nexport type CellValue = string | number | boolean | Date | null | undefined;\n","export type RateLimitResponse = {\n\tlimit: number;\n\tused: number;\n\tremaining: number;\n};\n","import { z } from \"zod\";\nimport { databaseSchema } from \"./database.types.js\";\n\nexport const filterSchema = z.object({\n\tcolumnName: z.string(),\n\toperator: z.string(),\n\tvalue: z.string(),\n});\n\nexport type FilterType = z.infer<typeof filterSchema>;\n\nexport const sortDirections = [\"asc\", \"desc\"] as const;\nexport type SortDirection = (typeof sortDirections)[number];\n\nexport const sortSchema = z.object({\n\tcolumnName: z.string(),\n\tdirection: z.enum(sortDirections),\n});\n\nexport type SortType = z.infer<typeof sortSchema>;\n\nexport const tableDataMetaSchema = z.object({\n\tlimit: z.number(),\n\ttotal: z.number(),\n\thasNextPage: z.boolean(),\n\thasPreviousPage: z.boolean(),\n\tnextCursor: z.string().nullable(),\n\tprevCursor: z.string().nullable(),\n});\n\nexport const tableDataResultSchema = z.object({\n\tdata: z.array(z.record(z.string(), z.unknown())),\n\tmeta: tableDataMetaSchema,\n});\n\nexport type TableDataResultSchemaType = z.infer<typeof tableDataResultSchema>;\n\nexport const tableDataQuerySchema = z.object({\n\tdb: databaseSchema.shape.db,\n\tcursor: z.string().optional(), // Base64 encoded cursor for pagination\n\tlimit: z.string().optional().default(\"50\").transform(Number),\n\tdirection: z.enum(sortDirections).optional().default(sortDirections[0]), // Pagination direction\n\tsort: z\n\t\t.string()\n\t\t.optional()\n\t\t.transform((val) => {\n\t\t\tif (!val) return \"\";\n\n\t\t\ttry {\n\t\t\t\tconst parsed = JSON.parse(val);\n\t\t\t\tif (Array.isArray(parsed)) {\n\t\t\t\t\treturn parsed;\n\t\t\t\t}\n\t\t\t\treturn val;\n\t\t\t} catch {\n\t\t\t\treturn val;\n\t\t\t}\n\t\t}),\n\torder: z.enum(sortDirections).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 type TableDataQuerySchemaType = z.infer<typeof tableDataQuerySchema>;\n\nexport interface CursorData {\n\tvalues: Record<string, unknown>;\n\tsortColumns: string[];\n}\n","import { z } from \"zod\";\n\nexport const tableInfoSchema = z.object({\n\ttableName: z.string(\"Table name is required\"),\n\trowCount: z.coerce.number(\"Row count is required\"),\n});\n\nexport type TableInfoSchemaType = z.infer<typeof tableInfoSchema>;\n","import { z } from \"zod\";\n\nexport const updateRecordsSchema = z.object({\n\ttableName: z.string(\"Table name is required\"),\n\tprimaryKey: z.string(\"Primary key is required\").default(\"id\"),\n\tupdates: z\n\t\t.array(\n\t\t\tz.object(\n\t\t\t\t{\n\t\t\t\t\trowData: z.record(z.string(\"Column name is required\"), z.any()),\n\t\t\t\t\tcolumnName: z.string(\"Column name is required\"),\n\t\t\t\t\tvalue: z.any(),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tmessage: \"Each update must have a row data, column name, and value.\",\n\t\t\t\t},\n\t\t\t),\n\t\t)\n\t\t.min(1, \"At least one update is required\"),\n});\n\nexport type UpdateRecordsSchemaType = z.infer<typeof updateRecordsSchema>;\n","export * from \"./add-record.types.js\"; // done\nexport * from \"./api-response.types.js\";\nexport * from \"./bulk-insert-records.type.js\";\nexport * from \"./chat.types.js\"; // done\nexport * from \"./cmd-args.types.js\"; // done\nexport * from \"./column.type.js\";\nexport * from \"./column-info.types.js\";\nexport * from \"./create-table.types.js\"; // done\nexport * from \"./database.types.js\"; // done\nexport * from \"./database-list.types.js\"; // done\nexport * from \"./database-schema.type.js\"; // done\nexport * from \"./delete-column.types.js\"; // done\nexport * from \"./delete-record.types.js\"; // done\nexport * from \"./execute-query.types.js\"; // done\nexport * from \"./export-table.types.js\";\nexport * from \"./rate-limit-response.type.js\";\nexport * from \"./table-data.types.js\"; // done\nexport * from \"./table-info.type.js\"; // done\nexport * from \"./update-recors.types.js\"; // done\n","import type { Context } from \"hono\";\nimport { HTTPException } from \"hono/http-exception\";\nimport { DatabaseError } from \"pg\";\nimport type { ApiError } from \"shared/types/api-response.types.js\";\nimport { ZodError } from \"zod\";\n\n/**\n * Centralized error handler for the application\n */\nexport function handleError(e: Error | unknown, c: Context) {\n\tconsole.error(\"handleError:\", e);\n\n\tif (e instanceof HTTPException) {\n\t\treturn c.json<ApiError>(\n\t\t\t{\n\t\t\t\terror: e.message ?? \"Internal server error\",\n\t\t\t},\n\t\t\te.status,\n\t\t);\n\t}\n\n\tif (e instanceof ZodError) {\n\t\tconst issue = e.issues[0];\n\t\treturn c.json<ApiError>(\n\t\t\t{\n\t\t\t\terror: \"Validation error\",\n\t\t\t\tdetails: issue.message,\n\t\t\t},\n\t\t\t400,\n\t\t);\n\t}\n\n\tif (e instanceof Error) {\n\t\tconst isConnectionError =\n\t\t\te.message.includes(\"ECONNREFUSED\") ||\n\t\t\te.message.includes(\"connection refused\") ||\n\t\t\te.message.includes(\"timeout expired\") ||\n\t\t\te.message.includes(\"Connection terminated\") ||\n\t\t\t(e instanceof DatabaseError && e.code?.startsWith(\"08\")); // Connection exception class\n\n\t\tif (isConnectionError) {\n\t\t\treturn c.json<ApiError>(\n\t\t\t\t{ error: \"Database connection failed\", details: e.message },\n\t\t\t\t503,\n\t\t\t);\n\t\t}\n\t}\n\n\treturn c.json<ApiError>(\n\t\t{\n\t\t\terror: e instanceof Error ? e.message : \"Internal server error\",\n\t\t},\n\t\t500,\n\t);\n}\n\nexport const validationHook = (\n\tresult: {\n\t\tsuccess: boolean;\n\t\tdata?: unknown;\n\t\terror?: { issues: { message: string }[] };\n\t},\n\tc: Context,\n): Response | undefined => {\n\tif (!result.success) {\n\t\tconst issue = result.error?.issues[0];\n\t\treturn c.json<ApiError>(\n\t\t\t{\n\t\t\t\terror: \"Validation error\",\n\t\t\t\tdetails: issue?.message ?? \"Unknown validation error\",\n\t\t\t},\n\t\t\t400,\n\t\t);\n\t}\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(\"DATABASE_URL is not set. Please provide a database connection string.\");\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 { Pool, type PoolConfig } from \"pg\";\nimport type { DatabaseTypeSchema } from \"shared/types\";\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\tdbType: DatabaseTypeSchema;\n\t} | null = null;\n\n\tconstructor() {\n\t\tthis.initializeBaseConfig();\n\t}\n\n\t/**\n\t * Detect database type from URL protocol\n\t */\n\tprivate detectDbType(url: URL): DatabaseTypeSchema {\n\t\tconst protocol = url.protocol.replace(\":\", \"\");\n\t\t// postgres:// or postgresql:// -> pg\n\t\tif (protocol === \"postgres\" || protocol === \"postgresql\") {\n\t\t\treturn \"pg\";\n\t\t}\n\t\t// Default to pg for now, can be extended for mysql, sqlite, etc.\n\t\treturn \"pg\";\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(\"DATABASE_URL is not set. Please provide a database connection string.\");\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\tdbType: this.detectDbType(url),\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 * Get the detected database type\n\t */\n\tgetDbType(): DatabaseTypeSchema {\n\t\tif (!this.baseConfig) {\n\t\t\tthrow new Error(\"Base configuration not initialized\");\n\t\t}\n\t\treturn this.baseConfig.dbType;\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\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 * Get the detected database type from DATABASE_URL\n */\nexport const getDbType = (): DatabaseTypeSchema => {\n\treturn databaseManager.getDbType();\n};\n\n/**\n * Build a connection string for the specified database\n */\nconst _buildDbConnectionString = (database?: string): string => {\n\treturn databaseManager.buildConnectionString(database);\n};\n\n/**\n * Close a specific database pool by database name\n */\nconst _closeDbPool = async (database: string): Promise<void> => {\n\treturn databaseManager.closePoolByDatabase(database);\n};\n\n/**\n * Close a specific database pool by connection string\n */\nconst _closeDbPoolByConnectionString = async (connectionString: string): Promise<void> => {\n\treturn databaseManager.closePool(connectionString);\n};\n\n/**\n * Close all database pools\n */\nconst _closeAllDbPools = async (): Promise<void> => {\n\treturn databaseManager.closeAll();\n};\n\n/**\n * Get list of active pool connection strings\n */\nconst _getActivePools = (): string[] => {\n\treturn databaseManager.getActivePools();\n};\n","import { HTTPException } from \"hono/http-exception\";\nimport {\n\ttype ColumnInfoSchemaType,\n\ttype DatabaseSchemaType,\n\tmapPostgresToDataType,\n\tstandardizeDataTypeLabel,\n\ttype TableNameSchemaType,\n} from \"shared/types\";\nimport { getDbPool } from \"@/db-manager.js\";\n\nexport async function getTableColumns({\n\ttableName,\n\tdb,\n}: {\n\ttableName: TableNameSchemaType[\"tableName\"];\n\tdb: DatabaseSchemaType[\"db\"];\n}): Promise<ColumnInfoSchemaType[]> {\n\tconst pool = getDbPool(db);\n\tconst query = `\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\n\tconst { rows } = await pool.query(query, [tableName]);\n\tif (!rows || rows.length === 0) {\n\t\tthrow new HTTPException(404, {\n\t\t\tmessage: `Table \"${tableName}\" does not exist`,\n\t\t});\n\t}\n\n\treturn rows.map((r) => {\n\t\t// Parse enumValues to always return string[] | null\n\t\tlet parsedEnumValues: string[] | null = null;\n\t\tif (r.enumValues) {\n\t\t\tif (Array.isArray(r.enumValues)) {\n\t\t\t\t// Already an array, use as-is\n\t\t\t\tparsedEnumValues = r.enumValues;\n\t\t\t} else if (typeof r.enumValues === \"string\") {\n\t\t\t\t// Parse PostgreSQL array format: \"{VALUE1,VALUE2,VALUE3}\"\n\t\t\t\tparsedEnumValues = r.enumValues.replace(/[{}]/g, \"\").split(\",\").filter(Boolean);\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tcolumnName: r.columnName,\n\t\t\tdataType: mapPostgresToDataType(r.dataType),\n\t\t\tdataTypeLabel: standardizeDataTypeLabel(r.dataType),\n\t\t\tisNullable: r.isNullable,\n\t\t\tcolumnDefault: r.columnDefault,\n\t\t\tisPrimaryKey: r.isPrimaryKey,\n\t\t\tisForeignKey: r.isForeignKey,\n\t\t\treferencedTable: r.referencedTable,\n\t\t\treferencedColumn: r.referencedColumn,\n\t\t\tenumValues: parsedEnumValues,\n\t\t};\n\t});\n}\n","import type {\n\tColumn,\n\tColumnInfoSchemaType,\n\tDatabaseSchema,\n\tDatabaseSchemaType,\n\tRelationship,\n\tTable,\n} from \"shared/types\";\nimport { db } from \"@/db.js\";\nimport { getDbPool } from \"@/db-manager.js\";\nimport { getTableColumns } from \"./table-columns.dao.js\";\n\n/**\n * Get all table names from the database\n */\nasync function getTableNames(db: DatabaseSchemaType[\"db\"]): Promise<string[]> {\n\tconst pool = getDbPool(db);\n\tconst query = `\n\t\tSELECT table_name\n\t\tFROM information_schema.tables\n\t\tWHERE table_schema = 'public'\n\t\t\tAND table_type = 'BASE TABLE'\n\t\tORDER BY table_name;\n\t`;\n\tconst { rows } = await pool.query(query);\n\treturn rows.map((r) => r.table_name);\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, unknown>[]> {\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: ColumnInfoSchemaType): 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 */\nasync function getDatabaseSchema(\n\tdb: DatabaseSchemaType[\"db\"],\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\tconst tableNames = await getTableNames(db);\n\n\t\t// Fetch schema info for each table in parallel\n\t\tconst tablePromises = tableNames.map(async (tableName) => {\n\t\t\tconst [columns, description, sampleData] = await Promise.all([\n\t\t\t\tgetTableColumns({ tableName, db }),\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.map((row) =>\n\t\t\t\t\tObject.fromEntries(Object.entries(row).map(([key, value]) => [key, String(value)])),\n\t\t\t\t);\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 detailed schema with sample data (for initial conversation context)\n */\nexport async function getDetailedSchema(\n\tdb: DatabaseSchemaType[\"db\"],\n): Promise<DatabaseSchema> {\n\treturn getDatabaseSchema(db, {\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 \"shared/types\";\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 */\nfunction 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 { zValidator } from \"@hono/zod-validator\";\nimport { Hono } from \"hono\";\nimport { DEFAULTS } from \"shared/constants\";\nimport { chatSchema } from \"shared/types\";\nimport { getDetailedSchema } from \"@/dao/table-details-schema.js\";\nimport { generateSystemPrompt } from \"@/utils/system-prompt-generator.js\";\n\nexport const chatRoutes = new Hono()\n\t/**\n\t * Base path for the endpoints, /:dbType/chat/...\n\t */\n\t.basePath(\"/chat\")\n\n\t/**\n\t * POST /chat - Handle AI chat requests with streaming\n\t * Proxies to the Cloudflare Worker which has the Gemini API key\n\t */\n\t.post(\"/\", zValidator(\"json\", chatSchema), async (c) => {\n\t\tconst { messages, conversationId, db } = c.req.valid(\"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(db);\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});\n\nexport type ChatRoutes = typeof chatRoutes;\n","/**\n * Parse DATABASE_URL to extract host and port\n */\nexport function parseDatabaseUrl(): { host: string; port: number } {\n\tconst databaseUrl = process.env.DATABASE_URL;\n\n\tif (!databaseUrl) {\n\t\treturn { host: \"localhost\", port: 5432 };\n\t}\n\n\ttry {\n\t\tconst url = new URL(databaseUrl);\n\t\treturn {\n\t\t\thost: url.hostname || \"localhost\",\n\t\t\tport: Number.parseInt(url.port, 10) || 5432,\n\t\t};\n\t} catch (error) {\n\t\tconsole.error(\"Failed to parse DATABASE_URL:\", error);\n\t\treturn { host: \"localhost\", port: 5432 };\n\t}\n}\n","import { HTTPException } from \"hono/http-exception\";\nimport {\n\ttype ConnectionInfoSchemaType,\n\tconnectionInfoSchema,\n\ttype DatabaseInfoSchemaType,\n\ttype DatabaseSchemaType,\n} from \"shared/types\";\nimport { getDbPool } from \"@/db-manager.js\";\nimport { parseDatabaseUrl } from \"@/utils/parse-database-url.js\";\n\n/**\n * Gets list of all normal databases on the PostgreSQL server.\n * Returns name, size (human readable), owner, and encoding.\n *\n * @returns List of database information objects\n * @throws Error if query fails or no databases are found\n */\nexport async function getDatabasesList(): Promise<DatabaseInfoSchemaType[]> {\n\tconst pool = getDbPool();\n\tconst query = `\n SELECT \n d.datname as name,\n pg_size_pretty(pg_database_size(d.datname)) as size,\n pg_catalog.pg_get_userbyid(d.datdba) as owner,\n pg_encoding_to_char(d.encoding) as encoding\n FROM pg_catalog.pg_database d\n WHERE d.datistemplate = false\n ORDER BY d.datname;\n `;\n\n\tconst { rows } = await pool.query(query);\n\tif (!rows[0]) {\n\t\tthrow new HTTPException(500, {\n\t\t\tmessage: \"No databases returned from database\",\n\t\t});\n\t}\n\n\treturn rows;\n}\n\n/**\n * Gets the name of the database we are currently using.\n *\n * @returns Object with current database name\n * @throws Error if query fails or no name is returned\n */\nexport async function getCurrentDatabase(): Promise<DatabaseSchemaType> {\n\tconst pool = getDbPool();\n\tconst query = \"SELECT current_database() as database;\";\n\n\tconst { rows } = await pool.query(query);\n\tif (!rows[0]) {\n\t\tthrow new HTTPException(500, {\n\t\t\tmessage: \"No current database returned from database\",\n\t\t});\n\t}\n\n\treturn rows[0];\n}\n\n/**\n * Gets useful information about the connection and PostgreSQL server.\n * Includes version, host, port, user, database name, active connections, etc.\n *\n * Uses fallback values from DATABASE_URL if some fields are missing.\n *\n * @returns Connection and server information object\n * @throws Error if query fails or result is invalid\n */\nexport async function getDatabaseConnectionInfo(): Promise<ConnectionInfoSchemaType> {\n\tconst pool = getDbPool();\n\tconst query = `\n SELECT \n version() as version,\n current_database() as database,\n current_user as user,\n inet_server_addr() as host,\n inet_server_port() as port,\n (SELECT count(*) FROM pg_stat_activity WHERE datname = current_database()) as active_connections,\n (SELECT setting::int FROM pg_settings WHERE name = 'max_connections') as max_connections;\n `;\n\n\tconst { rows } = await pool.query(query);\n\tif (!rows[0]) {\n\t\tthrow new HTTPException(500, {\n\t\t\tmessage: \"No connection information returned from database\",\n\t\t});\n\t}\n\n\t// Validate main result\n\tconst result = connectionInfoSchema.parse(rows[0]);\n\n\t// Use DATABASE_URL as backup for host/port if needed\n\tconst urlDefaults = parseDatabaseUrl();\n\n\treturn {\n\t\thost: result.host || urlDefaults.host,\n\t\tport: result.port || urlDefaults.port,\n\t\tuser: result.user,\n\t\tdatabase: result.database,\n\t\tversion: result.version.toString(),\n\t\tactive_connections: result.active_connections,\n\t\tmax_connections: result.max_connections,\n\t};\n}\n","import { Hono } from \"hono\";\nimport type {\n\tConnectionInfoSchemaType,\n\tCurrentDatabaseSchemaType,\n\tDatabaseListSchemaType,\n} from \"shared/types\";\nimport type { ApiHandler } from \"@/app.types.js\";\nimport {\n\tgetCurrentDatabase,\n\tgetDatabaseConnectionInfo,\n\tgetDatabasesList,\n} from \"@/dao/database-list.dao.js\";\nimport { getDbType } from \"@/db-manager.js\";\n\n/**\n * /databases routes (at root level, no dbType required)\n * GET /databases - Get list of all databases on the server (name, size, owner, encoding)\n * GET /databases/current - Get the name of the database we are currently connected to\n * GET /databases/connection - Get connection details and server information (PostgreSQL version, host, port, user, current database, connection counts)\n */\nexport const databasesRoutes = new Hono()\n\t/**\n\t * Base path for the endpoints, /databases/...\n\t */\n\t.basePath(\"/databases\")\n\n\t/**\n\t * GET /databases\n\t * Returns list of all databases on the server (name, size, owner, encoding) and the database type\n\t * @returns {Object} Object with databases array and dbType\n\t */\n\t.get(\"/\", async (c): ApiHandler<DatabaseListSchemaType> => {\n\t\tconst databases = await getDatabasesList();\n\t\tconst dbType = getDbType();\n\t\treturn c.json({ data: { databases, dbType } }, 200);\n\t})\n\n\t/**\n\t * GET /databases/current\n\t * Returns the name of the database we are currently connected to and the database type\n\t * @returns {Object} Object with current database name and type\n\t */\n\t.get(\"/current\", async (c): ApiHandler<CurrentDatabaseSchemaType> => {\n\t\tconst current = await getCurrentDatabase();\n\t\tconst dbType = getDbType();\n\t\treturn c.json({ data: { ...current, dbType } }, 200);\n\t})\n\n\t/**\n\t * GET /databases/connection\n\t * Returns connection details and server information\n\t * (PostgreSQL version, host, port, user, current database, connection counts)\n\t * @returns {Object} Connection and server info\n\t */\n\t.get(\"/connection\", async (c): ApiHandler<ConnectionInfoSchemaType> => {\n\t\tconst info = await getDatabaseConnectionInfo();\n\t\treturn c.json({ data: info }, 200);\n\t});\n\nexport type DatabasesRoutes = typeof databasesRoutes.routes;\n","import { HTTPException } from \"hono/http-exception\";\nimport type { DatabaseSchemaType, ExecuteQueryParams, ExecuteQueryResult } from \"shared/types\";\nimport { getDbPool } from \"@/db-manager.js\";\n\nexport const executeQuery = async ({\n\tquery,\n\tdb,\n}: {\n\tquery: ExecuteQueryParams[\"query\"];\n\tdb: DatabaseSchemaType[\"db\"];\n}): Promise<ExecuteQueryResult> => {\n\tconst pool = getDbPool(db);\n\tif (!query || !query.trim()) {\n\t\tthrow new HTTPException(400, {\n\t\t\tmessage: \"Query is required\",\n\t\t});\n\t}\n\n\t// Clean the query - remove trailing semicolons and whitespace\n\tconst cleanedQuery = query.trim().replace(/;+$/, \"\");\n\n\tconst startTime = performance.now();\n\tconst result = await pool.query(cleanedQuery);\n\tconst duration = performance.now() - startTime;\n\n\tconst columns = result.fields.map((field) => field.name);\n\n\treturn {\n\t\tcolumns,\n\t\trows: result.rows,\n\t\trowCount: result.rows.length,\n\t\tduration,\n\t\tmessage: result.rows.length === 0 ? \"OK\" : undefined,\n\t};\n};\n","import { zValidator } from \"@hono/zod-validator\";\nimport { Hono } from \"hono\";\nimport { databaseSchema, type ExecuteQueryResult, executeQuerySchema } from \"shared/types\";\nimport type { ApiHandler } from \"@/app.types.js\";\nimport { executeQuery } from \"@/dao/query.dao.js\";\n\nexport const queryRoutes = new Hono()\n\t/**\n\t * Base path for the endpoints, /:dbType/query/...\n\t */\n\t.basePath(\"/query\")\n\n\t/**\n\t * POST /query\n\t * Executes a SQL query on the currently connected database\n\t * @param {DatabaseSchemaType} query - The database to use\n\t * @param {ExecuteQuerySchemaType} json - The query to execute\n\t * @returns {ApiHandler<ExecuteQueryResult>} The result of the query\n\t */\n\t.post(\n\t\t\"/\",\n\t\tzValidator(\"query\", databaseSchema),\n\t\tzValidator(\"json\", executeQuerySchema),\n\t\tasync (c): ApiHandler<ExecuteQueryResult> => {\n\t\t\tconst { query } = c.req.valid(\"json\");\n\t\t\tconst { db } = c.req.valid(\"query\");\n\t\t\tconst data = await executeQuery({ query, db });\n\t\t\treturn c.json({ data }, 200);\n\t\t},\n\t);\n\nexport type QueryRoutes = typeof queryRoutes;\n","import { HTTPException } from \"hono/http-exception\";\nimport type { AddRecordSchemaType, DatabaseSchemaType } from \"shared/types\";\nimport { getDbPool } from \"@/db-manager.js\";\n\nexport async function addRecord({\n\tdb,\n\tparams,\n}: {\n\tdb: DatabaseSchemaType[\"db\"];\n\tparams: AddRecordSchemaType;\n}): Promise<{ insertedCount: number }> {\n\tconst { tableName, data } = params;\n\tconst pool = getDbPool(db);\n\n\t// Extract column names and values\n\tconst columns = Object.keys(data);\n\tconst values = Object.values(data);\n\n\t// Build the INSERT query\n\tconst placeholders = columns.map((_, index) => `$${index + 1}`).join(\", \");\n\tconst columnNames = columns.map((col) => `\"${col}\"`).join(\", \");\n\n\tconst query = `\n\t\t\tINSERT INTO \"${tableName}\" (${columnNames})\n\t\t\tVALUES (${placeholders})\n\t\t\tRETURNING *\n\t\t`;\n\n\tconst result = await pool.query(query, values);\n\tif (result.rowCount === 0) {\n\t\tthrow new HTTPException(500, {\n\t\t\tmessage: `Failed to insert record into \"${tableName}\"`,\n\t\t});\n\t}\n\n\treturn { insertedCount: result.rowCount ?? 0 };\n}\n","import { HTTPException } from \"hono/http-exception\";\nimport type { BulkInsertRecordsParams, BulkInsertResult } from \"shared/types\";\nimport { getDbPool } from \"@/db-manager.js\";\n\nexport const bulkInsertRecords = async ({\n\ttableName,\n\trecords,\n\tdb,\n}: BulkInsertRecordsParams): Promise<BulkInsertResult> => {\n\tif (!records || records.length === 0) {\n\t\tthrow new HTTPException(400, {\n\t\t\tmessage: \"At least one record is required\",\n\t\t});\n\t}\n\n\tconst pool = getDbPool(db);\n\tconst client = await pool.connect();\n\n\ttry {\n\t\t// Get column names from the first record\n\t\tconst columns = Object.keys(records[0]);\n\t\tconst columnNames = columns.map((col) => `\"${col}\"`).join(\", \");\n\n\t\tlet successCount = 0;\n\t\tconst failureCount = 0;\n\t\tconst errors: Array<{ recordIndex: number; error: string }> = [];\n\n\t\t// Execute inserts in a transaction\n\t\tawait client.query(\"BEGIN\");\n\n\t\tfor (let i = 0; i < records.length; i++) {\n\t\t\tconst record = records[i];\n\t\t\tconst values = columns.map((col) => record[col]);\n\n\t\t\tconst placeholders = columns.map((_, index) => `$${index + 1}`).join(\", \");\n\n\t\t\tconst insertSQL = `\n\t\t\t\tINSERT INTO \"${tableName}\" (${columnNames})\n\t\t\t\tVALUES (${placeholders})\n\t\t\t\tRETURNING *\n\t\t\t`;\n\n\t\t\ttry {\n\t\t\t\tawait client.query(insertSQL, values);\n\t\t\t\tsuccessCount++;\n\t\t\t} catch (error) {\n\t\t\t\tthrow new HTTPException(500, {\n\t\t\t\t\tmessage: `Failed: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tawait client.query(\"COMMIT\");\n\n\t\treturn {\n\t\t\tsuccess: failureCount === 0,\n\t\t\tmessage: `Bulk insert completed: ${successCount} records inserted${failureCount > 0 ? `, ${failureCount} failed` : \"\"}`,\n\t\t\tsuccessCount,\n\t\t\tfailureCount,\n\t\t\terrors: errors.length > 0 ? errors : undefined,\n\t\t};\n\t} catch (error) {\n\t\tawait client.query(\"ROLLBACK\");\n\t\tif (error instanceof HTTPException) {\n\t\t\tthrow error;\n\t\t}\n\t\tthrow new HTTPException(500, {\n\t\t\tmessage: `Failed to bulk insert records into \"${tableName}\"`,\n\t\t});\n\t} finally {\n\t\tclient.release();\n\t}\n};\n","import { HTTPException } from \"hono/http-exception\";\nimport type {\n\tDatabaseSchemaType,\n\tDeleteRecordParams,\n\tDeleteRecordResult,\n\tDeleteRecordSchemaType,\n\tForeignKeyConstraint,\n\tForeignKeyConstraintRow,\n\tRelatedRecord,\n} from \"shared/types\";\nimport { getDbPool } from \"@/db-manager.js\";\n\n/**\n * Gets foreign key constraints that reference the given table\n */\nasync function getForeignKeyReferences(\n\ttableName: string,\n\tdb: DatabaseSchemaType[\"db\"],\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(db);\n\tconst result = await pool.query(query, [tableName]);\n\n\treturn result.rows.map((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 */\nasync function getRelatedRecords(\n\ttableName: string,\n\tprimaryKeys: DeleteRecordSchemaType[\"primaryKeys\"],\n\tdb: DatabaseSchemaType[\"db\"],\n): Promise<RelatedRecord[]> {\n\tconst fkConstraints = await getForeignKeyReferences(tableName, db);\n\n\tif (fkConstraints.length === 0) {\n\t\treturn [];\n\t}\n\n\tconst relatedRecords: RelatedRecord[] = [];\n\tconst pool = getDbPool(db);\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((pk) => pk.columnName === constraint.referencedColumn);\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 relatedQuery = `\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\tconst relatedResult = await pool.query(relatedQuery, pkValues);\n\n\t\tif (relatedResult.rows.length > 0) {\n\t\t\trelatedRecords.push({\n\t\t\t\ttableName: constraint.referencingTable,\n\t\t\t\tcolumnName: constraint.referencingColumn,\n\t\t\t\tconstraintName: constraint.constraintName,\n\t\t\t\trecords: relatedResult.rows,\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 async function deleteRecords({\n\ttableName,\n\tprimaryKeys,\n\tdb,\n}: DeleteRecordParams): Promise<DeleteRecordResult> {\n\tconst pool = getDbPool(db);\n\n\tconst pkColumn = primaryKeys[0]?.columnName;\n\tif (!pkColumn) {\n\t\tthrow new HTTPException(400, {\n\t\t\tmessage: \"Primary key column name is required\",\n\t\t});\n\t}\n\n\tconst pkValues = primaryKeys.map((pk) => pk.value);\n\tconst placeholders = pkValues.map((_, i) => `$${i + 1}`).join(\", \");\n\n\tconst query = `\n\t\tDELETE FROM \"${tableName}\"\n\t\tWHERE \"${pkColumn}\" IN (${placeholders})\n\t\tRETURNING *\n\t`;\n\n\ttry {\n\t\tawait pool.query(\"BEGIN\");\n\t\tconst result = await pool.query(query, pkValues);\n\t\tawait pool.query(\"COMMIT\");\n\t\treturn { deletedCount: result.rowCount ?? 0, fkViolation: false, relatedRecords: [] };\n\t} catch (error) {\n\t\tawait pool.query(\"ROLLBACK\");\n\n\t\t// Check if this is a foreign key violation\n\t\tconst pgError = error as {\n\t\t\tcode?: string;\n\t\t\tdetail?: string;\n\t\t\tconstraint?: string;\n\t\t};\n\n\t\tif (pgError.code === \"23503\") {\n\t\t\t// Fetch related records to show the user\n\t\t\tconst relatedRecords = await getRelatedRecords(tableName, primaryKeys, db);\n\n\t\t\treturn {\n\t\t\t\tdeletedCount: 0,\n\t\t\t\tfkViolation: true,\n\t\t\t\trelatedRecords,\n\t\t\t};\n\t\t}\n\n\t\tif (error instanceof HTTPException) {\n\t\t\tthrow error;\n\t\t}\n\n\t\tthrow new HTTPException(500, {\n\t\t\tmessage: `Failed to delete records from \"${tableName}\"`,\n\t\t});\n\t}\n}\n\n/**\n * Force deletes records by first deleting all related records in referencing tables (cascade)\n */\nexport async function forceDeleteRecords({\n\ttableName,\n\tprimaryKeys,\n\tdb,\n}: DeleteRecordParams): Promise<{ deletedCount: number }> {\n\tconst pool = getDbPool(db);\n\n\tconst pkColumn = primaryKeys[0]?.columnName;\n\tif (!pkColumn) {\n\t\tthrow new HTTPException(400, {\n\t\t\tmessage: \"Primary key column name is required\",\n\t\t});\n\t}\n\n\tconst pkValues = primaryKeys.map((pk) => pk.value);\n\n\tawait pool.query(\"BEGIN\");\n\n\ttry {\n\t\t// Get all FK constraints that reference this table\n\t\tconst fkConstraints = await getForeignKeyReferences(tableName, db);\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, db);\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 nestedPlaceholders = 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 (${nestedPlaceholders})\n\t\t\t\t`;\n\n\t\t\t\tconst selectResult = await pool.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 deletePlaceholders = 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 (${deletePlaceholders})\n\t\t\t`;\n\n\t\t\tconst deleteResult = await pool.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 query = `\n\t\t\tDELETE FROM \"${tableName}\"\n\t\t\tWHERE \"${pkColumn}\" IN (${placeholders})\n\t\t\tRETURNING *\n\t\t`;\n\n\t\tconst result = await pool.query(query, pkValues);\n\n\t\tawait pool.query(\"COMMIT\");\n\n\t\tconst mainDeleted = result.rowCount ?? 0;\n\n\t\treturn { deletedCount: mainDeleted + totalRelatedDeleted };\n\t} catch (error) {\n\t\tawait pool.query(\"ROLLBACK\");\n\n\t\tif (error instanceof HTTPException) {\n\t\t\tthrow error;\n\t\t}\n\n\t\tthrow new HTTPException(500, {\n\t\t\tmessage: `Failed to force delete records from \"${tableName}\"`,\n\t\t});\n\t}\n}\n","import { HTTPException } from \"hono/http-exception\";\nimport type { DatabaseSchemaType, UpdateRecordsSchemaType } from \"shared/types\";\nimport { getDbPool } from \"@/db-manager.js\";\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 async function updateRecords({\n\tparams,\n\tdb,\n}: {\n\tparams: UpdateRecordsSchemaType;\n\tdb: DatabaseSchemaType[\"db\"];\n}): Promise<{ updatedCount: number }> {\n\tconst { tableName, updates, primaryKey } = params;\n\tconst pool = getDbPool(db);\n\n\t// Group updates by row (using the primary key value)\n\tconst updatesByRow = new Map<\n\t\tunknown,\n\t\tArray<{\n\t\t\tcolumnName: string;\n\t\t\tvalue: unknown;\n\t\t\trowData: Record<string, unknown>;\n\t\t}>\n\t>();\n\n\tfor (const update of updates) {\n\t\tconst pkValue = update.rowData[primaryKey];\n\t\tif (pkValue === undefined || pkValue === null) {\n\t\t\tthrow new HTTPException(400, {\n\t\t\t\tmessage: `Primary key \"${primaryKey}\" not found in row data. Please ensure the row has a \"${primaryKey}\" column.`,\n\t\t\t});\n\t\t}\n\n\t\tif (!updatesByRow.has(pkValue)) {\n\t\t\tupdatesByRow.set(pkValue, []);\n\t\t}\n\t\tupdatesByRow.get(pkValue)?.push({\n\t\t\tcolumnName: update.columnName,\n\t\t\tvalue: update.value,\n\t\t\trowData: update.rowData,\n\t\t});\n\t}\n\n\t// Use transaction for multiple updates\n\tawait pool.query(\"BEGIN\");\n\n\ttry {\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((u, index) => `\"${u.columnName}\" = $${index + 1}`);\n\t\t\tconst values = rowUpdates.map((u) => {\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 query = `\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\tconst result = await pool.query(query, values);\n\t\t\tif (result.rowCount === 0) {\n\t\t\t\tthrow new HTTPException(404, {\n\t\t\t\t\tmessage: `Record with ${primaryKey} = ${pkValue} not found in table \"${tableName}\"`,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\ttotalUpdated += result.rowCount ?? 0;\n\t\t}\n\n\t\tawait pool.query(\"COMMIT\");\n\n\t\treturn { updatedCount: totalUpdated };\n\t} catch (error) {\n\t\tawait pool.query(\"ROLLBACK\");\n\n\t\tif (error instanceof HTTPException) {\n\t\t\tthrow error;\n\t\t}\n\n\t\tthrow new HTTPException(500, {\n\t\t\tmessage: `Failed to update records in \"${tableName}\"`,\n\t\t});\n\t}\n}\n","import { zValidator } from \"@hono/zod-validator\";\nimport { Hono } from \"hono\";\nimport {\n\taddRecordSchema,\n\tbulkInsertRecordsSchema,\n\ttype DeleteRecordResult,\n\tdatabaseSchema,\n\tdeleteRecordSchema,\n\tupdateRecordsSchema,\n} from \"shared/types\";\nimport type { ApiHandler } from \"@/app.types.js\";\nimport { addRecord } from \"@/dao/add-record.dao.js\";\nimport { bulkInsertRecords } from \"@/dao/bulk-insert-records.dao.js\";\nimport { deleteRecords, forceDeleteRecords } from \"@/dao/delete-records.dao.js\";\nimport { updateRecords } from \"@/dao/update-records.dao.js\";\n\nexport const recordsRoutes = new Hono()\n\t/**\n\t * Base path for the endpoints, /:dbType/records/...\n\t */\n\t.basePath(\"/records\")\n\n\t/**\n\t * POST /records\n\t * Adds a new record into a table\n\t * @param {DatabaseSchemaType} query - The database to use\n\t * @param {AddRecordSchemaType} json - The data for the new record\n\t * @returns {BaseResponseType<string>} A success message\n\t */\n\t.post(\n\t\t\"/\",\n\t\tzValidator(\"query\", databaseSchema),\n\t\tzValidator(\"json\", addRecordSchema),\n\t\tasync (c): ApiHandler<string> => {\n\t\t\tconst { db } = c.req.valid(\"query\");\n\t\t\tconst { tableName, data } = c.req.valid(\"json\");\n\t\t\tconst { insertedCount } = await addRecord({\n\t\t\t\tdb,\n\t\t\t\tparams: {\n\t\t\t\t\ttableName,\n\t\t\t\t\tdata,\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\tdata: `Record inserted into \"${tableName}\" with ${insertedCount} rows inserted`,\n\t\t\t\t},\n\t\t\t\t200,\n\t\t\t);\n\t\t},\n\t)\n\n\t/**\n\t * PATCH /records\n\t * Updates one or more cells in a table\n\t * @param {DatabaseSchemaType} query - The database to use\n\t * @param {UpdateRecordsSchemaType} json - The data for the updates\n\t * @returns {ApiHandler<string>} A success message\n\t */\n\t.patch(\n\t\t\"/\",\n\t\tzValidator(\"query\", databaseSchema),\n\t\tzValidator(\"json\", updateRecordsSchema),\n\t\tasync (c): ApiHandler<string> => {\n\t\t\tconst { db } = c.req.valid(\"query\");\n\t\t\tconst { tableName, primaryKey, updates } = c.req.valid(\"json\");\n\t\t\tconst { updatedCount } = await updateRecords({\n\t\t\t\tparams: {\n\t\t\t\t\ttableName,\n\t\t\t\t\tprimaryKey,\n\t\t\t\t\tupdates,\n\t\t\t\t},\n\t\t\t\tdb,\n\t\t\t});\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\tdata: `Updated ${updatedCount} records in \"${tableName}\"`,\n\t\t\t\t},\n\t\t\t\t200,\n\t\t\t);\n\t\t},\n\t)\n\n\t/**\n\t * DELETE /records\n\t * Deletes records from a table\n\t * @param {DatabaseSchemaType} query - The database to use\n\t * @param {DeleteRecordSchemaType} json - The data for the deletes\n\t * @returns {ApiHandler<string, 409 | 200>} A success message\n\t */\n\t.delete(\n\t\t\"/\",\n\t\tzValidator(\"query\", databaseSchema),\n\t\tzValidator(\"json\", deleteRecordSchema),\n\t\tasync (c): ApiHandler<DeleteRecordResult, 409 | 200> => {\n\t\t\t// TODO: refactor this shit, the backend responses should be consistent\n\t\t\t// TODO: the frontend could be simplified too\n\t\t\tconst { db } = c.req.valid(\"query\");\n\t\t\tconst { tableName, primaryKeys } = c.req.valid(\"json\");\n\t\t\tconst { deletedCount, fkViolation, relatedRecords } = await deleteRecords({\n\t\t\t\ttableName,\n\t\t\t\tprimaryKeys,\n\t\t\t\tdb,\n\t\t\t});\n\t\t\tif (fkViolation) {\n\t\t\t\treturn c.json(\n\t\t\t\t\t{\n\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\tdeletedCount: 0,\n\t\t\t\t\t\t\tfkViolation: true,\n\t\t\t\t\t\t\trelatedRecords,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t409,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tdeletedCount,\n\t\t\t\t\t\tfkViolation: false,\n\t\t\t\t\t\trelatedRecords: [],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t200,\n\t\t\t);\n\t\t},\n\t)\n\n\t/**\n\t * DELETE /records/force\n\t * Force deletes records and all related FK records\n\t * @param {DatabaseSchemaType} query - The database to use\n\t * @param {DeleteRecordSchemaType} json - The data for the deletes\n\t * @returns {ApiHandler<string>} A success message\n\t */\n\t.delete(\n\t\t\"/force\",\n\t\tzValidator(\"query\", databaseSchema),\n\t\tzValidator(\"json\", deleteRecordSchema),\n\t\tasync (c): ApiHandler<{ deletedCount: number }> => {\n\t\t\tconst { db } = c.req.valid(\"query\");\n\t\t\tconst { tableName, primaryKeys } = c.req.valid(\"json\");\n\t\t\tconst deletedCount = await forceDeleteRecords({ tableName, primaryKeys, db });\n\t\t\treturn c.json({ data: deletedCount }, 200);\n\t\t},\n\t)\n\n\t/**\n\t * POST /records/bulk\n\t * Bulk inserts multiple records into a table\n\t * @param {DatabaseSchemaType} query - The database to use\n\t * @param {BulkInsertRecordsParamsType} json - The data for the bulk insert\n\t * @returns {BaseResponseType<BulkInsertResult>} Success and failure counts\n\t */\n\t.post(\n\t\t\"/bulk\",\n\t\tzValidator(\"query\", databaseSchema),\n\t\tzValidator(\"json\", bulkInsertRecordsSchema),\n\t\tasync (c): ApiHandler<object> => {\n\t\t\tconst { db } = c.req.valid(\"query\");\n\t\t\tconst { tableName, records } = c.req.valid(\"json\");\n\t\t\tconst result = await bulkInsertRecords({ tableName, records, db });\n\t\t\tconsole.log(\"result\", result);\n\t\t\treturn c.json({ data: result }, 200);\n\t\t},\n\t);\n\nexport type RecordsRoutes = typeof recordsRoutes;\n","import type {\n\tCreateTableSchemaType,\n\tDatabaseSchemaType,\n\tFieldDataType,\n\tForeignKeyDataType,\n} from \"shared/types\";\nimport { getDbPool } from \"@/db-manager.js\";\n\nexport async function createTable({\n\ttableData,\n\tdb,\n}: {\n\ttableData: CreateTableSchemaType;\n\tdb: DatabaseSchemaType[\"db\"];\n}) {\n\tconst { tableName, fields, foreignKeys } = tableData;\n\tconst pool = getDbPool(db);\n\n\t// Build column definitions\n\tconst columnDefinitions = fields.map((field: FieldDataType) => {\n\t\tlet columnDef = `\"${field.columnName}\" ${field.columnType}`;\n\n\t\t// Add array suffix if needed\n\t\tif (field.isArray) {\n\t\t\tcolumnDef += \"[]\";\n\t\t}\n\n\t\t// Add PRIMARY KEY constraint\n\t\tif (field.isPrimaryKey) {\n\t\t\tcolumnDef += \" PRIMARY KEY\";\n\t\t}\n\n\t\t// Add UNIQUE constraint\n\t\tif (field.isUnique && !field.isPrimaryKey) {\n\t\t\tcolumnDef += \" UNIQUE\";\n\t\t}\n\n\t\t// Add NOT NULL constraint (if not nullable)\n\t\tif (!field.isNullable) {\n\t\t\tcolumnDef += \" NOT NULL\";\n\t\t}\n\n\t\t// Add GENERATED ALWAYS AS IDENTITY for identity columns\n\t\tif (field.isIdentity) {\n\t\t\tcolumnDef += \" GENERATED ALWAYS AS IDENTITY\";\n\t\t}\n\n\t\t// Add default value\n\t\tif (field.defaultValue && !field.isIdentity) {\n\t\t\tcolumnDef += ` DEFAULT ${field.defaultValue}`;\n\t\t}\n\n\t\treturn columnDef;\n\t});\n\n\t// Build foreign key constraints\n\tconst foreignKeyConstraints =\n\t\tforeignKeys?.map((fk: ForeignKeyDataType) => {\n\t\t\tconst constraintName = `fk_${tableName}_${fk.columnName}_${fk.referencedTable}_${fk.referencedColumn}`;\n\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}) || [];\n\n\t// Combine column definitions and foreign key constraints\n\tconst allDefinitions = [...columnDefinitions, ...foreignKeyConstraints];\n\n\t// Create the table\n\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\tawait pool.query(createTableSQL);\n}\n","import { HTTPException } from \"hono/http-exception\";\nimport type { DeleteColumnParamsSchemaType } from \"shared/types\";\nimport { getDbPool } from \"@/db-manager.js\";\n\n/**\n * Deletes a column from a table using ALTER TABLE DROP COLUMN.\n * Uses CASCADE to drop dependent objects, or RESTRICT to fail if there are dependencies.\n *\n * @param params.tableName - Name of the table containing the column\n * @param params.columnName - Name of the column to delete\n * @param params.cascade - If true, uses CASCADE; if false, uses RESTRICT\n * @param params.db - Optional database name to connect to\n * @returns {Object} Object with deleted count\n * @throws HTTPException if table or column does not exist\n */\nexport async function deleteColumn(\n\tparams: DeleteColumnParamsSchemaType,\n): Promise<{ deletedCount: number }> {\n\tconst { tableName, columnName, cascade, db } = params;\n\tconst pool = getDbPool(db);\n\n\t// Check if table exists\n\tconst tableExistsQuery = `\n\t\tSELECT EXISTS (\n\t\t\tSELECT 1 FROM information_schema.tables \n\t\t\tWHERE table_name = $1 AND table_schema = 'public'\n\t\t) as exists;\n\t`;\n\tconst { rows: tableRows } = await pool.query(tableExistsQuery, [tableName]);\n\tif (!tableRows[0]?.exists) {\n\t\tthrow new HTTPException(404, {\n\t\t\tmessage: `Table \"${tableName}\" does not exist`,\n\t\t});\n\t}\n\n\t// Check if column exists\n\tconst columnExistsQuery = `\n\t\tSELECT EXISTS (\n\t\t\tSELECT 1 FROM information_schema.columns \n\t\t\tWHERE table_name = $1 AND column_name = $2 AND table_schema = 'public'\n\t\t) as exists;\n\t`;\n\tconst { rows: columnRows } = await pool.query(columnExistsQuery, [tableName, columnName]);\n\tif (!columnRows[0]?.exists) {\n\t\tthrow new HTTPException(404, {\n\t\t\tmessage: `Column \"${columnName}\" does not exist in table \"${tableName}\"`,\n\t\t});\n\t}\n\n\t// Use CASCADE to drop dependent objects, or RESTRICT to fail if there are dependencies\n\tconst dropMode = cascade ? \"CASCADE\" : \"RESTRICT\";\n\tconst dropColumnSQL = `ALTER TABLE \"${tableName}\" DROP COLUMN \"${columnName}\" ${dropMode}`;\n\n\tconst { rowCount } = await pool.query(dropColumnSQL);\n\n\treturn { deletedCount: rowCount ?? 0 };\n}\n","import { HTTPException } from \"hono/http-exception\";\nimport type { CellValue, DatabaseSchemaType, TableNameSchemaType } from \"shared/types\";\nimport { getDbPool } from \"@/db-manager.js\";\n\nexport async function exportTableData({\n\ttableName,\n\tdb,\n}: {\n\ttableName: TableNameSchemaType[\"tableName\"];\n\tdb: DatabaseSchemaType[\"db\"];\n}): Promise<{ cols: string[]; rows: Record<string, CellValue>[] }> {\n\tconst pool = getDbPool(db);\n\tconst { rows } = await pool.query(`SELECT * FROM \"${tableName}\"`);\n\n\tif (!rows || rows.length === 0) {\n\t\tthrow new HTTPException(404, {\n\t\t\tmessage: `Table \"${tableName}\" does not exist or has no data`,\n\t\t});\n\t}\n\n\tconst cols = Object.keys(rows[0]);\n\n\treturn { cols, rows };\n}\n","import { HTTPException } from \"hono/http-exception\";\nimport type { TableInfoSchemaType } from \"shared/types\";\nimport type { DatabaseSchemaType } from \"shared/types/database.types.js\";\nimport { getDbPool } from \"@/db-manager.js\";\n\nexport async function getTablesList(\n\tdb: DatabaseSchemaType[\"db\"],\n): Promise<TableInfoSchemaType[]> {\n\tconst pool = getDbPool(db);\n\tconst query = `\n\tSELECT \n t.table_name as \"tableName\",\n CASE \n WHEN s.n_live_tup IS NULL OR s.n_live_tup = 0 \n THEN (SELECT COUNT(*) FROM information_schema.tables \n WHERE table_schema = 'public' \n AND table_name = t.table_name)\n ELSE s.n_live_tup \n END::integer as \"rowCount\"\nFROM information_schema.tables t\nLEFT JOIN pg_stat_user_tables s ON t.table_name = s.relname\nWHERE t.table_schema = 'public'\n AND t.table_type = 'BASE TABLE'\nORDER BY t.table_name;\n\t`;\n\n\tconst { rows } = await pool.query(query);\n\tif (!rows[0]) {\n\t\tthrow new HTTPException(500, {\n\t\t\tmessage: \"No tables returned from database\",\n\t\t});\n\t}\n\n\treturn rows;\n}\n","import type { CursorData, FilterType, SortDirection, SortType } from \"shared/types\";\n\nexport function buildWhereClause(filters: FilterType[]): {\n\tclause: string;\n\tvalues: unknown[];\n} {\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\nexport function buildSortClause(sorts: SortType[] | 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 function buildCursorWhereClause(\n\tcursorData: CursorData,\n\tdirection: SortDirection,\n\tsortDirection: SortDirection,\n\tstartParamIndex: number,\n): { clause: string; values: unknown[] } {\n\tconst { values, sortColumns } = cursorData;\n\tconst conditions: string[] = [];\n\tconst queryValues: unknown[] = [];\n\n\t// Determine comparison operator based on direction and sort order\n\t// Forward + ASC = >, Forward + DESC = <\n\t// Backward + ASC = <, Backward + DESC = >\n\tconst isAscending = sortDirection === \"asc\";\n\tconst isForward = direction === \"asc\";\n\tconst useGreaterThan = isAscending === isForward;\n\n\t// Build row comparison for multi-column cursor\n\t// Uses tuple comparison: (col1, col2, ...) > (val1, val2, ...)\n\tif (sortColumns.length > 0) {\n\t\tconst columnList = sortColumns.map((col) => `\"${col}\"`).join(\", \");\n\t\tconst placeholders = sortColumns.map((_, i) => `$${startParamIndex + i}`).join(\", \");\n\t\tconst operator = useGreaterThan ? \">\" : \"<\";\n\n\t\tconditions.push(`(${columnList}) ${operator} (${placeholders})`);\n\t\tfor (const col of sortColumns) {\n\t\t\tqueryValues.push(values[col]);\n\t\t}\n\t}\n\n\treturn {\n\t\tclause: conditions.length > 0 ? `(${conditions.join(\" AND \")})` : \"\",\n\t\tvalues: queryValues,\n\t};\n}\n","import type {\n\tCursorData,\n\tDatabaseSchemaType,\n\tFilterType,\n\tSortDirection,\n\tSortType,\n\tTableDataResultSchemaType,\n} from \"shared/types\";\nimport { getDbPool } from \"@/db-manager.js\";\nimport {\n\tbuildCursorWhereClause,\n\tbuildSortClause,\n\tbuildWhereClause,\n} from \"@/utils/build-clauses.js\";\n\n// Encode cursor data to base64 string\nconst encodeCursor = (data: CursorData): string => {\n\treturn Buffer.from(JSON.stringify(data)).toString(\"base64url\");\n};\n\n// Decode base64 cursor string to cursor data\nconst decodeCursor = (cursor: string): CursorData | null => {\n\ttry {\n\t\treturn JSON.parse(Buffer.from(cursor, \"base64url\").toString(\"utf-8\"));\n\t} catch {\n\t\treturn null;\n\t}\n};\n\n// Get primary key column(s) for a table\nconst getPrimaryKeyColumns = async (\n\tpool: ReturnType<typeof getDbPool>,\n\ttableName: string,\n): Promise<string[]> => {\n\t// Quote the table name to preserve case sensitivity in PostgreSQL\n\tconst quotedTableName = `\"${tableName}\"`;\n\tconst result = await pool.query(\n\t\t`SELECT a.attname as column_name\n\t\t FROM pg_index i\n\t\t JOIN pg_attribute a ON a.attrelid = i.indrelid AND a.attnum = ANY(i.indkey)\n\t\t WHERE i.indrelid = $1::regclass AND i.indisprimary\n\t\t ORDER BY array_position(i.indkey, a.attnum)`,\n\t\t[quotedTableName],\n\t);\n\treturn result.rows.map((row) => row.column_name);\n};\n\nexport interface GetTableDataParams {\n\ttableName: string;\n\tcursor?: string;\n\tlimit?: number;\n\tdirection?: SortDirection;\n\tsort?: string | SortType[];\n\torder?: SortDirection;\n\tfilters?: FilterType[];\n\tdb: DatabaseSchemaType[\"db\"];\n}\n\nexport const getTableData = async ({\n\ttableName,\n\tcursor = \"\",\n\tlimit = 50,\n\tdirection = \"asc\",\n\tsort = [],\n\torder = \"asc\",\n\tfilters = [],\n\tdb,\n}: GetTableDataParams): Promise<TableDataResultSchemaType> => {\n\tconst pool = getDbPool(db);\n\n\t// Get primary key columns for stable cursor pagination\n\tconst primaryKeyColumns = await getPrimaryKeyColumns(pool, tableName);\n\n\t// Determine sort columns - use provided sort or fall back to primary key\n\tlet sortColumns: string[] = [];\n\tlet effectiveSortDirection: SortDirection = order;\n\n\tif (Array.isArray(sort) && sort.length > 0) {\n\t\tsortColumns = sort.map((s) => s.columnName);\n\t\teffectiveSortDirection = sort[0].direction;\n\t} else if (typeof sort === \"string\" && sort) {\n\t\tsortColumns = [sort];\n\t}\n\t// Always include primary key columns for stable pagination\n\tconst cursorColumns = [\n\t\t...sortColumns,\n\t\t...primaryKeyColumns.filter((pk) => !sortColumns.includes(pk)),\n\t];\n\n\t// If no sort columns and no primary key, fall back to ctid (PostgreSQL internal row id)\n\tif (cursorColumns.length === 0) {\n\t\tcursorColumns.push(\"ctid\");\n\t}\n\t// Build filter WHERE clause\n\tconst { clause: filterWhereClause, values: filterValues } = buildWhereClause(filters);\n\t// Build cursor WHERE clause if cursor is provided\n\tlet cursorWhereClause = \"\";\n\tlet cursorValues: unknown[] = [];\n\n\tif (cursor) {\n\t\tconst cursorData = decodeCursor(cursor);\n\t\tif (cursorData) {\n\t\t\tconst cursorResult = buildCursorWhereClause(\n\t\t\t\tcursorData,\n\t\t\t\tdirection,\n\t\t\t\teffectiveSortDirection,\n\t\t\t\tfilterValues.length + 1,\n\t\t\t);\n\t\t\tcursorWhereClause = cursorResult.clause;\n\t\t\tcursorValues = cursorResult.values;\n\t\t}\n\t}\n\t// Combine WHERE clauses\n\tlet combinedWhereClause = \"\";\n\tif (filterWhereClause && cursorWhereClause) {\n\t\t// Remove \"WHERE \" prefix from filterWhereClause and combine\n\t\tconst filterCondition = filterWhereClause.replace(/^WHERE\\s+/i, \"\");\n\t\tcombinedWhereClause = `WHERE ${filterCondition} AND ${cursorWhereClause}`;\n\t} else if (filterWhereClause) {\n\t\tcombinedWhereClause = filterWhereClause;\n\t} else if (cursorWhereClause) {\n\t\tcombinedWhereClause = `WHERE ${cursorWhereClause}`;\n\t}\n\n\t// Build sort clause\n\tconst sortClause = buildSortClause(Array.isArray(sort) ? sort : sort, order);\n\n\t// For backward pagination, reverse the sort order\n\tlet effectiveSortClause = sortClause;\n\tif (direction === \"desc\") {\n\t\tif (sortClause) {\n\t\t\teffectiveSortClause = sortClause\n\t\t\t\t.replace(/\\bASC\\b/gi, \"TEMP_DESC\")\n\t\t\t\t.replace(/\\bDESC\\b/gi, \"ASC\")\n\t\t\t\t.replace(/TEMP_DESC/g, \"DESC\");\n\t\t} else {\n\t\t\t// Default sort by cursor columns in reverse\n\t\t\tconst reverseSortParts = cursorColumns.map(\n\t\t\t\t(col) => `\"${col}\" ${effectiveSortDirection === \"asc\" ? \"DESC\" : \"ASC\"}`,\n\t\t\t);\n\t\t\teffectiveSortClause = `ORDER BY ${reverseSortParts.join(\", \")}`;\n\t\t}\n\t} else if (!sortClause && cursorColumns.length > 0) {\n\t\t// Default sort by cursor columns\n\t\tconst defaultSortParts = cursorColumns.map(\n\t\t\t(col) => `\"${col}\" ${effectiveSortDirection.toUpperCase()}`,\n\t\t);\n\t\teffectiveSortClause = `ORDER BY ${defaultSortParts.join(\", \")}`;\n\t}\n\n\t// Get total count (with filters only, not cursor)\n\tconst countRes = await pool.query(\n\t\t`SELECT COUNT(*) as total FROM \"${tableName}\" ${filterWhereClause}`,\n\t\tfilterValues,\n\t);\n\tconst totalRows = Number(countRes.rows[0].total);\n\t// Fetch one extra row to determine if there are more results\n\tconst limitParamIndex = filterValues.length + cursorValues.length + 1;\n\tconst dataRes = await pool.query(\n\t\t`SELECT * FROM \"${tableName}\" ${combinedWhereClause} ${effectiveSortClause} LIMIT $${limitParamIndex}`,\n\t\t[...filterValues, ...cursorValues, limit + 1],\n\t);\n\t// Check if table has columns\n\tconst hasColumns = dataRes.fields && dataRes.fields.length > 0;\n\t// Filter out empty objects\n\tlet rows = hasColumns\n\t\t? dataRes.rows.filter((row) => Object.keys(row).length > 0)\n\t\t: dataRes.rows;\n\t// Determine if there are more results\n\tconst hasMore = rows.length > limit;\n\tif (hasMore) {\n\t\trows = rows.slice(0, limit);\n\t}\n\t// For backward pagination, reverse the results to maintain correct order\n\tif (direction === \"desc\") {\n\t\trows = rows.reverse();\n\t}\n\t// Build cursors for next/previous pages\n\tlet nextCursor: string | null = null;\n\tlet prevCursor: string | null = null;\n\tif (rows.length > 0) {\n\t\tconst firstRow = rows[0];\n\t\tconst lastRow = rows[rows.length - 1];\n\t\t// Create cursor from row values\n\t\tconst createCursorFromRow = (row: Record<string, unknown>): CursorData => ({\n\t\t\tvalues: Object.fromEntries(cursorColumns.map((col) => [col, row[col]])),\n\t\t\tsortColumns: cursorColumns,\n\t\t});\n\t\t// For forward pagination\n\t\tif (direction === \"asc\") {\n\t\t\t// Next cursor: if there are more results, encode the last row\n\t\t\tif (hasMore) {\n\t\t\t\tnextCursor = encodeCursor(createCursorFromRow(lastRow));\n\t\t\t}\n\t\t\t// Previous cursor: if we used a cursor to get here, encode the first row\n\t\t\tif (cursor) {\n\t\t\t\tprevCursor = encodeCursor(createCursorFromRow(firstRow));\n\t\t\t}\n\t\t} else {\n\t\t\t// For backward pagination\n\t\t\t// Next cursor: if we used a cursor, encode the last row (to go forward again)\n\t\t\tif (cursor) {\n\t\t\t\tnextCursor = encodeCursor(createCursorFromRow(lastRow));\n\t\t\t}\n\t\t\t// Previous cursor: if there are more results going backward, encode the first row\n\t\t\tif (hasMore) {\n\t\t\t\tprevCursor = encodeCursor(createCursorFromRow(firstRow));\n\t\t\t}\n\t\t}\n\t}\n\treturn {\n\t\tdata: rows,\n\t\tmeta: {\n\t\t\tlimit,\n\t\t\ttotal: totalRows,\n\t\t\thasNextPage: direction === \"asc\" ? hasMore : !!cursor,\n\t\t\thasPreviousPage: direction === \"asc\" ? !!cursor : hasMore,\n\t\t\tnextCursor,\n\t\t\tprevCursor,\n\t\t},\n\t};\n};\n","import type { CellValue, FormatType } from \"shared/types\";\nimport { utils, write } from \"xlsx\";\n\ninterface ExportFileOptions {\n\tcols: string[];\n\trows: Record<string, CellValue>[];\n\tformat: FormatType;\n\ttableName: string;\n}\n\n/**\n * Converts table data to the specified export format (CSV, XLSX, or JSON)\n *\n * @param options - The export options\n * @param options.cols - Array of column names\n * @param options.rows - Array of row data objects\n * @param options.format - The export format ('csv', 'xlsx', or 'json')\n * @param options.tableName - The name of the table being exported\n * @returns The file content as a Uint8Array\n */\nexport function getExportFile({ cols, rows, format, tableName }: ExportFileOptions): BodyInit {\n\tswitch (format) {\n\t\tcase \"json\": {\n\t\t\tconst jsonContent = JSON.stringify(rows ?? [], null, 2);\n\t\t\treturn new Uint8Array(Buffer.from(jsonContent, \"utf-8\"));\n\t\t}\n\n\t\tcase \"csv\": {\n\t\t\tconst data: CellValue[][] = [\n\t\t\t\tcols,\n\t\t\t\t...(rows?.map((row) => cols?.map((col) => row[col])) ?? []),\n\t\t\t];\n\t\t\tconst worksheet = utils.aoa_to_sheet(data);\n\t\t\tconst csvContent = utils.sheet_to_csv(worksheet);\n\t\t\treturn new Uint8Array(Buffer.from(csvContent, \"utf-8\"));\n\t\t}\n\n\t\tcase \"xlsx\": {\n\t\t\tconst data: CellValue[][] = [\n\t\t\t\tcols,\n\t\t\t\t...(rows?.map((row) => cols?.map((col) => row[col])) ?? []),\n\t\t\t];\n\t\t\tconst worksheet = utils.aoa_to_sheet(data);\n\t\t\tconst workbook = utils.book_new();\n\t\t\tutils.book_append_sheet(workbook, worksheet, tableName.slice(0, 31));\n\t\t\tconst buffer = write(workbook, {\n\t\t\t\tbookType: \"xlsx\",\n\t\t\t\ttype: \"buffer\",\n\t\t\t}) as Buffer;\n\t\t\treturn new Uint8Array(buffer);\n\t\t}\n\t}\n}\n","import { zValidator } from \"@hono/zod-validator\";\nimport { Hono } from \"hono\";\nimport {\n\ttype ColumnInfoSchemaType,\n\tcreateTableSchema,\n\tdatabaseSchema,\n\tdeleteColumnParamSchema,\n\tdeleteColumnQuerySchema,\n\texportTableSchema,\n\ttype TableDataResultSchemaType,\n\ttype TableInfoSchemaType,\n\ttableDataQuerySchema,\n\ttableNameSchema,\n} from \"shared/types\";\nimport type { ApiHandler } from \"@/app.types.js\";\nimport { createTable } from \"@/dao/create-table.dao.js\";\nimport { deleteColumn } from \"@/dao/delete-column.dao.js\";\nimport { exportTableData } from \"@/dao/export-table.dao.js\";\nimport { getTableColumns } from \"@/dao/table-columns.dao.js\";\nimport { getTablesList } from \"@/dao/table-list.dao.js\";\nimport { getTableData } from \"@/dao/tables-data.dao.js\";\nimport { getExportFile } from \"@/utils/get-export-file.js\";\n\nexport const tablesRoutes = new Hono()\n\t/**\n\t * Base path for the endpoints, /:dbType/tables/...\n\t */\n\t.basePath(\"/tables\")\n\n\t/**\n\t * GET /tables\n\t * Returns list of all tables in the currently connected database\n\t * @returns {Array} List of table info objects\n\t */\n\t.get(\n\t\t\"/\",\n\t\tzValidator(\"query\", databaseSchema),\n\t\tasync (c): ApiHandler<TableInfoSchemaType[]> => {\n\t\t\tconst { db } = c.req.valid(\"query\");\n\t\t\tconst tablesList = await getTablesList(db);\n\t\t\treturn c.json({ data: tablesList }, 200);\n\t\t},\n\t)\n\n\t/**\n\t * POST /tables\n\t * Creates a new table in the currently connected database\n\t * @param {CreateTableSchemaType} body - The data for the new table\n\t * @returns {string} A success message\n\t */\n\t.post(\n\t\t\"/\",\n\t\tzValidator(\"query\", databaseSchema),\n\t\tzValidator(\"json\", createTableSchema),\n\t\tasync (c): ApiHandler<string> => {\n\t\t\tconst { db } = c.req.valid(\"query\");\n\t\t\tconst body = c.req.valid(\"json\");\n\t\t\tawait createTable({ tableData: body, db });\n\t\t\treturn c.json({ data: `Table ${body.tableName} created successfully` }, 200);\n\t\t},\n\t)\n\n\t/**\n\t * DELETE /tables/:tableName/columns/:columnName\n\t * Deletes a column from a table\n\t * @param {DatabaseSchemaType} query - The query parameters\n\t * @param {DeleteColumnParamSchemaType} param - The URL parameters\n\t * @returns {DeleteColumnResponseType} The response\n\t */\n\t.delete(\n\t\t\"/:tableName/columns/:columnName\",\n\t\tzValidator(\"query\", deleteColumnQuerySchema),\n\t\tzValidator(\"param\", deleteColumnParamSchema),\n\t\tasync (c): ApiHandler<string> => {\n\t\t\tconst { db, cascade } = c.req.valid(\"query\");\n\t\t\tconst { tableName, columnName } = c.req.valid(\"param\");\n\t\t\tconst { deletedCount } = await deleteColumn({\n\t\t\t\ttableName,\n\t\t\t\tcolumnName,\n\t\t\t\tcascade,\n\t\t\t\tdb,\n\t\t\t});\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\tdata: `Column \"${columnName}\" deleted successfully from table \"${tableName}\" with ${deletedCount} rows deleted`,\n\t\t\t\t},\n\t\t\t\t200,\n\t\t\t);\n\t\t},\n\t)\n\n\t/**\n\t * GET /tables/:tableName/columns\n\t * Returns list of all columns in a table\n\t * @param {DatabaseSchemaType} query - The query parameters\n\t * @param {TableNameSchemaType} param - The URL parameters\n\t * @returns {ColumnInfoSchemaType[]} The response\n\t */\n\t.get(\n\t\t\"/:tableName/columns\",\n\t\tzValidator(\"query\", databaseSchema),\n\t\tzValidator(\"param\", tableNameSchema),\n\t\tasync (c): ApiHandler<ColumnInfoSchemaType[]> => {\n\t\t\tconst { db } = c.req.valid(\"query\");\n\t\t\tconst { tableName } = c.req.valid(\"param\");\n\t\t\tconst columns = await getTableColumns({ tableName, db });\n\t\t\treturn c.json({ data: columns }, 200);\n\t\t},\n\t)\n\n\t/**\n\t * GET /tables/:tableName/data\n\t * Get cursor-paginated data for a table\n\t * @param {TableNameSchemaType} param - The URL parameters\n\t * @param {TableDataQuerySchemaType} query - The query parameters\n\t * @returns {TableDataResultSchemaType} The response\n\t * @throws {HTTPException} If the table does not exist or the query is invalid\n\t */\n\t.get(\n\t\t\"/:tableName/data\",\n\t\tzValidator(\"param\", tableNameSchema),\n\t\tzValidator(\"query\", tableDataQuerySchema),\n\t\tasync (c): ApiHandler<TableDataResultSchemaType> => {\n\t\t\tconst { tableName } = c.req.valid(\"param\");\n\t\t\tconst { cursor, limit, direction, sort, order, filters, db } = c.req.valid(\"query\");\n\t\t\tconst tableData = await getTableData({\n\t\t\t\ttableName,\n\t\t\t\tcursor,\n\t\t\t\tlimit,\n\t\t\t\tdirection,\n\t\t\t\tsort,\n\t\t\t\torder,\n\t\t\t\tfilters,\n\t\t\t\tdb,\n\t\t\t});\n\t\t\treturn c.json({ data: tableData }, 200);\n\t\t},\n\t)\n\n\t/**\n\t * GET /tables/:tableName/export\n\t * Export table data to CSV or XLSX format\n\t * @param {TableNameSchemaType} param - The URL parameters\n\t * @param {ExportTableSchemaType} query - The query parameters (db, format)\n\t * @returns {BodyInit} The file content as a binary response\n\t */\n\t.get(\n\t\t\"/:tableName/export\",\n\t\tzValidator(\"param\", tableNameSchema),\n\t\tzValidator(\"query\", exportTableSchema),\n\t\tasync (c) => {\n\t\t\tconst { tableName } = c.req.valid(\"param\");\n\t\t\tconst { db, format } = c.req.valid(\"query\");\n\n\t\t\tconst { cols, rows } = await exportTableData({ tableName, db });\n\t\t\tconst fileContent = getExportFile({ cols, rows, format, tableName });\n\t\t\tlet contentType: string | undefined;\n\n\t\t\tswitch (format) {\n\t\t\t\tcase \"csv\":\n\t\t\t\t\tcontentType = \"text/csv\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"xlsx\":\n\t\t\t\t\tcontentType = \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"json\":\n\t\t\t\t\tcontentType = \"application/json\";\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\treturn new Response(fileContent, {\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": contentType ?? \"\",\n\t\t\t\t\t\"Content-Disposition\": `attachment; filename=\"${tableName}_export.${format}\"`,\n\t\t\t\t},\n\t\t\t});\n\t\t},\n\t);\n\nexport type TablesRoutes = typeof tablesRoutes.routes;\n","import path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { serveStatic } from \"@hono/node-server/serve-static\";\nimport { zValidator } from \"@hono/zod-validator\";\nimport { Hono } from \"hono\";\nimport { cors } from \"hono/cors\";\nimport { logger } from \"hono/logger\";\nimport { prettyJSON } from \"hono/pretty-json\";\nimport { type DatabaseTypeSchema, databaseTypeParamSchema } from \"shared/types\";\nimport type { AppType } from \"@/app.types.js\";\nimport { handleError, validationHook } from \"@/middlewares/error-handler.js\";\nimport { chatRoutes } from \"@/routes/chat.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\";\n\n/**\n * Get the path to the core distribution directory.\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<AppType>({ strict: false })\n\t\t/**\n\t\t * Enable CORS\n\t\t */\n\t\t.use(\"/*\", cors())\n\n\t\t/**\n\t\t * Pretty print the JSON response\n\t\t */\n\t\t.use(prettyJSON({ space: 2 }))\n\n\t\t/**\n\t\t * Enable logger in development mode\n\t\t */\n\t\t.use(process.env.NODE_ENV === \"development\" ? logger() : (_, next) => next())\n\n\t\t/**\n\t\t * Serve the favicon.ico file\n\t\t */\n\t\t.use(\n\t\t\t\"/favicon.ico\",\n\t\t\tserveStatic({\n\t\t\t\tpath: path.resolve(getCoreDistPath(), \"favicon.ico\"),\n\t\t\t}),\n\t\t)\n\n\t\t/**\n\t\t * Handle CORS requests\n\t\t */\n\t\t.use(\"*\", async (c, next) => {\n\t\t\tc.header(\"Access-Control-Allow-Origin\", \"*\");\n\t\t\tc.header(\"Access-Control-Allow-Methods\", \"GET, POST, PUT, DELETE, OPTIONS\");\n\t\t\tc.header(\"Access-Control-Allow-Headers\", \"Content-Type\");\n\t\t\tawait next();\n\t\t})\n\n\t\t/**\n\t\t * Handle errors\n\t\t */\n\t\t.onError(handleError)\n\n\t\t/**\n\t\t * Database routes - available at root level (no dbType required)\n\t\t */\n\t\t.route(\"/\", databasesRoutes)\n\n\t\t/**\n\t\t * Serve static assets (before dbType validation to avoid conflicts)\n\t\t */\n\t\t.use(\"/assets/*\", serveStatic({ root: getCoreDistPath() }))\n\t\t.use(\"/image.png\", serveStatic({ root: getCoreDistPath() }))\n\n\t\t/**\n\t\t * Routes that require dbType validation - under /:dbType/...\n\t\t */\n\t\t.use(\"/:dbType/*\", zValidator(\"param\", databaseTypeParamSchema, validationHook))\n\t\t.use(\"/:dbType/*\", async (c, next) => {\n\t\t\tconst dbType = c.req.param(\"dbType\") as DatabaseTypeSchema;\n\t\t\tc.set(\"dbType\", dbType);\n\t\t\tawait next();\n\t\t})\n\t\t.route(\"/:dbType\", tablesRoutes)\n\t\t.route(\"/:dbType\", recordsRoutes)\n\t\t.route(\"/:dbType\", queryRoutes)\n\t\t.route(\"/:dbType\", chatRoutes)\n\n\t\t/**\n\t\t * Serve all other static files as fallback (for SPA)\n\t\t */\n\t\t.use(\"/*\", serveStatic({ root: getCoreDistPath() }));\n\n\treturn { app };\n};\n\nexport type { AppType };\n\n// Export the app type for hc client\nexport type AppRoutes = ReturnType<typeof createServer>[\"app\"];\n","import { intro, outro } from \"@clack/prompts\";\nimport { serve } from \"@hono/node-server\";\nimport open from \"open\";\nimport color from \"picocolors\";\nimport { DEFAULTS } from \"shared/constants\";\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\";\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();\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 } = createServer();\n\tserve({\n\t\tfetch: app.fetch,\n\t\tport: PORT,\n\t});\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\";\nimport type { Args } from \"shared/types\";\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\";\n\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 .env file, then process.env\n */\nexport const getDatabaseUrl = async (env?: DotenvParseOutput | null, varName?: string) => {\n\tconst envVarName = varName || \"DATABASE_URL\";\n\n\tif (env?.[envVarName]) {\n\t\treturn env[envVarName];\n\t}\n\n\t// Fall back to process.env (e.g. from shell or package.json script)\n\tif (process.env[envVarName]) {\n\t\treturn process.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 and ${envVarName} not set in process.env`));\n\t} else {\n\t\tnote(color.red(`${envVarName} not found in .env or process.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 { dirname, resolve } from \"node:path\";\n\nimport { parse as parseDotenv } from \"dotenv\";\n\n/**\n * Find .env path: try cwd, then walk up parent directories until root.\n */\nconst findEnvPath = async (startDir: string): Promise<string | null> => {\n\tlet dir = resolve(startDir);\n\tfor (;;) {\n\t\tconst envPath = resolve(dir, \".env\");\n\t\ttry {\n\t\t\tawait access(envPath);\n\t\t\treturn envPath;\n\t\t} catch {\n\t\t\t// ENOENT or other: try parent\n\t\t}\n\t\tconst parent = dirname(dir);\n\t\tif (parent === dir) return null;\n\t\tdir = parent;\n\t}\n};\n\n/**\n * Load the environment variables from the file.\n * When no path is given: tries current directory, then parent directories until a .env is found.\n * When --env path is given: uses that path only (no walk).\n */\nexport const loadEnv = async (env?: string) => {\n\tlet envPath: string | null;\n\n\tif (env) {\n\t\tenvPath = resolve(env);\n\t} else {\n\t\tenvPath = await findEnvPath(process.cwd());\n\t}\n\n\tif (!envPath) return null;\n\n\ttry {\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;\n\t\t}\n\t\tthrow err;\n\t}\n};\n","import { intro, outro } from \"@clack/prompts\";\nimport color from \"picocolors\";\nimport { META } from \"shared/constants/meta.js\";\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: ${META.SITE_DOCS_LINK}`));\n};\n","import { intro, note, outro } from \"@clack/prompts\";\nimport color from \"picocolors\";\nimport { DEFAULTS } from \"shared/constants\";\nimport { loadEnv } from \"@/cmd/load-env.js\";\n\n/**\n * Show connection status\n */\nexport const showStatus = async (env?: string, databaseUrl?: string, varName?: string) => {\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 .env file, then process.env\n\t\tconst ENV = env ? await loadEnv(env) : await loadEnv();\n\t\tif (ENV?.[envVarName]) {\n\t\t\tfoundUrl = ENV[envVarName];\n\t\t} else if (process.env[envVarName]) {\n\t\t\tfoundUrl = process.env[envVarName] ?? null;\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 or set it in process.env`));\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.3.25\",\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 --minify --sourcemap\",\n \"prepack\": \"cd ../core && bun run build && cd ../server && bun run build\",\n \"start\": \"node dist/index.js\",\n \"check\": \"biome check --write --unsafe\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"test:coverage\": \"vitest run --coverage\"\n },\n \"dependencies\": {\n \"@clack/prompts\": \"^0.11.0\",\n \"@hono/node-server\": \"^1.19.7\",\n \"@hono/zod-validator\": \"^0.7.6\",\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 \"xlsx\": \"^0.18.5\",\n \"zod\": \"^4.2.1\"\n },\n \"devDependencies\": {\n \"@biomejs/biome\": \"^2.2.6\",\n \"@types/node\": \"^20.11.17\",\n \"@types/pg\": \"^8.16.0\",\n \"@vitest/coverage-v8\": \"^4.0.17\",\n \"shared\": \"workspace:*\",\n \"tsup\": \"^8.5.1\",\n \"tsx\": \"^4.7.1\",\n \"typescript\": \"^5.8.3\",\n \"vitest\": \"^4.0.17\"\n }\n}"],"mappings":"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","names":["init_chat","__esmMin","DEFAULTS","init_defaults","__esmMin","init_links","__esmMin","META","init_meta","__esmMin","init_proxy_limits","__esmMin","init_constants","__esmMin","init_chat","init_defaults","init_links","init_meta","init_proxy_limits","z","addRecordSchema","init_add_record_types","__esmMin","init_api_response_types","__esmMin","z","bulkInsertRecordsSchema","init_bulk_insert_records_type","__esmMin","z","databaseSchema","DATABASE_TYPES","databaseTypeSchema","currentDatabaseSchema","databaseTypeParamSchema","tableNameSchema","init_database_types","__esmMin","z","chatSchema","init_chat_types","__esmMin","init_database_types","databaseSchema","init_cmd_args_types","__esmMin","z","dataTypes","dataTypesSchema","DataTypes","standardizedDataTypes","standardizedDataTypeSchema","columnInfoSchema","init_column_info_types","__esmMin","mapPostgresToDataType","pgType","normalized","DataTypes","standardizeDataTypeLabel","StandardizedDataType","init_column_type","__esmMin","init_column_info_types","z","FOREIGN_KEY_ACTIONS","foreignKeyActionSchema","fieldDataSchema","foreignKeyDataSchema","createTableSchema","init_create_table_types","__esmMin","z","databaseInfoSchema","databaseListSchema","connectionInfoSchema","init_database_list_types","__esmMin","init_database_types","databaseTypeSchema","init_database_schema_type","__esmMin","z","deleteColumnQuerySchema","deleteColumnParamSchema","deleteColumnParamsSchema","deleteColumnSuccessResponseSchema","init_delete_column_types","__esmMin","init_database_types","databaseSchema","val","z","deleteRecordSchema","init_delete_record_types","__esmMin","z","executeQuerySchema","init_execute_query_types","__esmMin","z","FORMAT_TYPES","exportTableSchema","init_export_table_types","__esmMin","init_database_types","databaseSchema","init_rate_limit_response_type","__esmMin","z","filterSchema","sortDirections","sortSchema","tableDataMetaSchema","tableDataResultSchema","tableDataQuerySchema","init_table_data_types","__esmMin","init_database_types","databaseSchema","val","parsed","z","tableInfoSchema","init_table_info_type","__esmMin","z","updateRecordsSchema","init_update_recors_types","__esmMin","init_types","__esmMin","init_add_record_types","init_api_response_types","init_bulk_insert_records_type","init_chat_types","init_cmd_args_types","init_column_type","init_column_info_types","init_create_table_types","init_database_types","init_database_list_types","init_database_schema_type","init_delete_column_types","init_delete_record_types","init_execute_query_types","init_export_table_types","init_rate_limit_response_type","init_table_data_types","init_table_info_type","init_update_recors_types","HTTPException","DatabaseError","ZodError","handleError","e","c","issue","validationHook","init_error_handler","__esmMin","result","Pool","dbInstance","getPool","db","init_db","__esmMin","err","error","_target","prop","Pool","DatabaseManager","databaseManager","getDbPool","getDbType","init_db_manager","__esmMin","url","protocol","databaseUrl","error","database","connectionString","poolConfig","pool","err","closePromises","HTTPException","getTableColumns","tableName","db","pool","getDbPool","query","rows","r","parsedEnumValues","mapPostgresToDataType","standardizeDataTypeLabel","init_table_columns_dao","__esmMin","init_types","init_db_manager","getTableNames","db","pool","getDbPool","query","rows","r","getTableDescription","tableName","client","getSampleData","convertColumnInfo","col","column","extractRelationships","tables","relationships","table","toTable","toColumn","getDatabaseSchema","options","includeSampleData","includeDescriptions","tablePromises","columns","description","sampleData","getTableColumns","row","key","value","error","getDetailedSchema","init_table_details_schema","__esmMin","init_db","init_db_manager","init_table_columns_dao","generateSystemPrompt","schema","formatSchemaForPrompt","output","table","col","pkIndicator","fkIndicator","nullable","rel","init_system_prompt_generator","__esmMin","zValidator","Hono","chatRoutes","init_chat_routes","__esmMin","init_constants","init_types","init_table_details_schema","init_system_prompt_generator","chatSchema","c","messages","conversationId","db","schema","getDetailedSchema","systemPrompt","generateSystemPrompt","payload","proxyResponse","DEFAULTS","errorData","readable","writable","parseDatabaseUrl","databaseUrl","url","init_parse_database_url","__esmMin","HTTPException","getDatabasesList","pool","getDbPool","query","rows","getCurrentDatabase","getDatabaseConnectionInfo","result","connectionInfoSchema","urlDefaults","parseDatabaseUrl","init_database_list_dao","__esmMin","init_types","init_db_manager","init_parse_database_url","Hono","databasesRoutes","init_databases_routes","__esmMin","init_database_list_dao","init_db_manager","c","databases","getDatabasesList","dbType","getDbType","current","getCurrentDatabase","info","getDatabaseConnectionInfo","HTTPException","executeQuery","init_query_dao","__esmMin","init_db_manager","query","db","pool","getDbPool","cleanedQuery","startTime","result","duration","field","zValidator","Hono","queryRoutes","init_query_routes","__esmMin","init_types","init_query_dao","databaseSchema","executeQuerySchema","c","query","db","data","executeQuery","HTTPException","addRecord","db","params","tableName","data","pool","getDbPool","columns","values","placeholders","_","index","columnNames","col","query","result","init_add_record_dao","__esmMin","init_db_manager","HTTPException","bulkInsertRecords","init_bulk_insert_records_dao","__esmMin","init_db_manager","tableName","records","db","client","getDbPool","columns","columnNames","col","successCount","failureCount","errors","i","record","values","placeholders","_","index","insertSQL","error","HTTPException","getForeignKeyReferences","tableName","db","getDbPool","row","getRelatedRecords","primaryKeys","fkConstraints","relatedRecords","pool","constraintsByTable","constraint","key","pkValues","pk","_tableColumn","constraints","placeholders","_","i","relatedQuery","relatedResult","deleteRecords","pkColumn","query","result","error","forceDeleteRecords","totalRelatedDeleted","deletedTables","deleteRelatedRecursively","targetTable","targetColumn","values","nestedFks","nestedFk","nestedPlaceholders","selectQuery","nestedValues","deletePlaceholders","deleteQuery","deleteResult","init_delete_records_dao","__esmMin","init_db_manager","HTTPException","updateRecords","params","db","tableName","updates","primaryKey","pool","getDbPool","updatesByRow","update","pkValue","totalUpdated","rowUpdates","setClauses","u","index","values","query","result","error","init_update_records_dao","__esmMin","init_db_manager","zValidator","Hono","recordsRoutes","init_records_routes","__esmMin","init_types","init_add_record_dao","init_bulk_insert_records_dao","init_delete_records_dao","init_update_records_dao","databaseSchema","addRecordSchema","c","db","tableName","data","insertedCount","addRecord","updateRecordsSchema","primaryKey","updates","updatedCount","updateRecords","deleteRecordSchema","primaryKeys","deletedCount","fkViolation","relatedRecords","deleteRecords","forceDeleteRecords","bulkInsertRecordsSchema","records","result","bulkInsertRecords","createTable","tableData","db","tableName","fields","foreignKeys","pool","getDbPool","columnDefinitions","field","columnDef","foreignKeyConstraints","fk","allDefinitions","createTableSQL","init_create_table_dao","__esmMin","init_db_manager","HTTPException","deleteColumn","params","tableName","columnName","cascade","db","pool","getDbPool","tableExistsQuery","tableRows","columnExistsQuery","columnRows","dropColumnSQL","rowCount","init_delete_column_dao","__esmMin","init_db_manager","HTTPException","exportTableData","tableName","db","pool","getDbPool","rows","init_export_table_dao","__esmMin","init_db_manager","HTTPException","getTablesList","db","pool","getDbPool","query","rows","init_table_list_dao","__esmMin","init_db_manager","buildWhereClause","filters","conditions","values","filter","paramIndex","columnName","buildSortClause","sorts","order","sort","buildCursorWhereClause","cursorData","direction","sortDirection","startParamIndex","sortColumns","queryValues","useGreaterThan","columnList","col","placeholders","_","i","operator","init_build_clauses","__esmMin","encodeCursor","decodeCursor","getPrimaryKeyColumns","getTableData","init_tables_data_dao","__esmMin","init_db_manager","init_build_clauses","data","cursor","pool","tableName","quotedTableName","row","limit","direction","sort","order","filters","db","getDbPool","primaryKeyColumns","sortColumns","effectiveSortDirection","s","cursorColumns","pk","filterWhereClause","filterValues","buildWhereClause","cursorWhereClause","cursorValues","cursorData","cursorResult","buildCursorWhereClause","combinedWhereClause","sortClause","buildSortClause","effectiveSortClause","col","countRes","totalRows","limitParamIndex","dataRes","rows","hasMore","nextCursor","prevCursor","firstRow","lastRow","createCursorFromRow","utils","write","getExportFile","cols","rows","format","tableName","jsonContent","data","row","col","worksheet","csvContent","workbook","buffer","init_get_export_file","__esmMin","zValidator","Hono","tablesRoutes","init_tables_routes","__esmMin","init_types","init_create_table_dao","init_delete_column_dao","init_export_table_dao","init_table_columns_dao","init_table_list_dao","init_tables_data_dao","init_get_export_file","databaseSchema","c","db","tablesList","getTablesList","createTableSchema","body","createTable","deleteColumnQuerySchema","deleteColumnParamSchema","cascade","tableName","columnName","deletedCount","deleteColumn","tableNameSchema","columns","getTableColumns","tableDataQuerySchema","cursor","limit","direction","sort","order","filters","tableData","getTableData","exportTableSchema","format","cols","rows","exportTableData","fileContent","getExportFile","contentType","create_server_exports","__export","createServer","path","fileURLToPath","serveStatic","zValidator","Hono","cors","logger","prettyJSON","getCoreDistPath","init_create_server","__esmMin","init_types","init_error_handler","init_chat_routes","init_databases_routes","init_query_routes","init_records_routes","init_tables_routes","__dirname","_","next","c","handleError","databasesRoutes","databaseTypeParamSchema","validationHook","dbType","tablesRoutes","recordsRoutes","queryRoutes","chatRoutes","init_constants","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","dirname","resolve","parseDotenv","findEnvPath","startDir","dir","envPath","parent","loadEnv","env","content","err","init_meta","intro","outro","color","showHelp","META","init_constants","intro","note","outro","color","showStatus","env","databaseUrl","varName","intro","color","envVarName","DEFAULTS","foundUrl","ENV","loadEnv","outro","note","intro","outro","color","package_default","showVersion","intro","color","outro","package_default","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","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.
|
|
4
|
+
"version": "1.3.25",
|
|
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",
|