db-studio 0.0.7 → 0.0.9
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 +21 -21
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var
|
|
2
|
+
var Pe=Object.defineProperty;var E=(a,e)=>()=>(a&&(e=a(a=0)),e);var je=(a,e)=>{for(var t in e)Pe(a,t,{get:e[t],enumerable:!0})};import{Pool as Je}from"pg";var j,Xe,f,w=E(()=>{"use strict";j=null,Xe=()=>{if(!j){if(!process.env.DATABASE_URL)throw new Error("DATABASE_URL is not set. Please provide a database connection string.");j=new Je({connectionString:process.env.DATABASE_URL})}return j},f=new Proxy({},{get(a,e){return Xe()[e]}})});var ee,te=E(()=>{"use strict";w();ee=async a=>{let e=await f.connect();try{let{tableName:t,fields:r,foreignKeys:o}=a,n=r.map(s=>{let d=`"${s.columnName}" ${s.columnType}`;return s.isArray&&(d+="[]"),s.isPrimaryKey&&(d+=" PRIMARY KEY"),s.isUnique&&!s.isPrimaryKey&&(d+=" UNIQUE"),s.isNullable||(d+=" NOT NULL"),s.isIdentity&&(d+=" GENERATED ALWAYS AS IDENTITY"),s.defaultValue&&!s.isIdentity&&(d+=` DEFAULT ${s.defaultValue}`),d}),l=o?.map(s=>`CONSTRAINT "${`fk_${t}_${s.columnName}_${s.referencedTable}_${s.referencedColumn}`}" FOREIGN KEY ("${s.columnName}") REFERENCES "${s.referencedTable}" ("${s.referencedColumn}") ON UPDATE ${s.onUpdate} ON DELETE ${s.onDelete}`)||[],m=[...n,...l],i=`
|
|
3
3
|
CREATE TABLE "${t}" (
|
|
4
|
-
${
|
|
4
|
+
${m.join(`,
|
|
5
5
|
`)}
|
|
6
6
|
);
|
|
7
|
-
`;return
|
|
7
|
+
`;return(void 0)("Creating table with SQL:",i),await e.query(i),{success:!0,tableName:t,message:`Table "${t}" created successfully`}}catch(t){throw(void 0)("Error creating table:",t),t}finally{e.release()}}});var k,Ze,re,oe,ae=E(()=>{"use strict";w();k=async a=>(await f.query(`
|
|
8
8
|
SELECT
|
|
9
9
|
tc.constraint_name,
|
|
10
10
|
tc.table_name as referencing_table,
|
|
@@ -20,29 +20,29 @@ var Oe=Object.defineProperty;var E=(a,e)=>()=>(a&&(e=a(a=0)),e);var Pe=(a,e)=>{f
|
|
|
20
20
|
AND ccu.table_schema = tc.table_schema
|
|
21
21
|
WHERE tc.constraint_type = 'FOREIGN KEY'
|
|
22
22
|
AND ccu.table_name = $1
|
|
23
|
-
`,[a])).rows.map(({row:r})=>({constraintName:r.constraint_name,referencingTable:r.referencing_table,referencingColumn:r.referencing_column,referencedTable:r.referenced_table,referencedColumn:r.referenced_column})),Ze=async(a,e)=>{let t=await
|
|
23
|
+
`,[a])).rows.map(({row:r})=>({constraintName:r.constraint_name,referencingTable:r.referencing_table,referencingColumn:r.referencing_column,referencedTable:r.referenced_table,referencedColumn:r.referenced_column})),Ze=async(a,e)=>{let t=await k(a);if(t.length===0)return[];let r=[],o=new Map;for(let l of t){let m=`${l.referencingTable}.${l.referencingColumn}`;o.has(m)||o.set(m,[]),o.get(m)?.push(l)}let n=e.map(l=>l.value);for(let[l,m]of o){let i=m[0];if(!i||!e.find(p=>p.columnName===i.referencedColumn))continue;let d=n.map((p,y)=>`$${y+1}`).join(", "),g=`
|
|
24
24
|
SELECT * FROM "${i.referencingTable}"
|
|
25
25
|
WHERE "${i.referencingColumn}" IN (${d})
|
|
26
26
|
LIMIT 100
|
|
27
|
-
`;try{let p=await f.query(g,n);p.rows.length>0&&r.push({tableName:i.referencingTable,columnName:i.referencingColumn,constraintName:i.constraintName,records:p.rows})}catch(p){
|
|
27
|
+
`;try{let p=await f.query(g,n);p.rows.length>0&&r.push({tableName:i.referencingTable,columnName:i.referencingColumn,constraintName:i.constraintName,records:p.rows})}catch(p){(void 0)(`Error fetching related records from ${i.referencingTable}:`,p)}}return r},re=async a=>{let{tableName:e,primaryKeys:t}=a,r=await f.connect();try{await r.query("BEGIN");let o=t[0]?.columnName;if(!o)throw new Error("Primary key column name is required");let n=t.map(s=>s.value),l=n.map((s,d)=>`$${d+1}`).join(", "),m=`
|
|
28
28
|
DELETE FROM "${e}"
|
|
29
29
|
WHERE "${o}" IN (${l})
|
|
30
30
|
RETURNING *
|
|
31
|
-
`;
|
|
31
|
+
`;(void 0)("Deleting records with SQL:",m,"Values:",n);let i=await r.query(m,n);return await r.query("COMMIT"),{success:!0,message:`Successfully deleted ${i.rowCount} ${i.rowCount===1?"record":"records"} from "${e}"`,deletedCount:i.rowCount??0}}catch(o){if(await r.query("ROLLBACK"),o.code==="23503")return(void 0)("FK violation detected, fetching related records..."),{success:!1,message:"Cannot delete: Records are referenced by other tables",fkViolation:!0,relatedRecords:await Ze(e,t)};throw(void 0)("Error deleting records:",o),o}finally{r.release()}},oe=async a=>{let{tableName:e,primaryKeys:t}=a,r=await f.connect();try{await r.query("BEGIN");let o=t[0]?.columnName;if(!o)throw new Error("Primary key column name is required");let n=t.map(b=>b.value),l=await k(e),m=0,i=new Set,s=async(b,S,$)=>{let Ae=await k(b);for(let _ of Ae){let x=$.map((K,Oe)=>`$${Oe+1}`).join(", "),xe=`
|
|
32
32
|
SELECT "${_.referencedColumn}" FROM "${b}"
|
|
33
|
-
WHERE "${S}" IN (${
|
|
34
|
-
`,q=(await r.query(
|
|
33
|
+
WHERE "${S}" IN (${x})
|
|
34
|
+
`,q=(await r.query(xe,$)).rows.map(({row:K})=>K[_.referencedColumn]);q.length>0&&await s(_.referencingTable,_.referencingColumn,q)}let $e=$.map((_,x)=>`$${x+1}`).join(", "),Ce=`
|
|
35
35
|
DELETE FROM "${b}"
|
|
36
36
|
WHERE "${S}" IN (${$e})
|
|
37
|
-
`,Le=await r.query(Ce,$);
|
|
37
|
+
`,Le=await r.query(Ce,$);m+=Le.rowCount??0,i.add(b)};for(let b of l)i.has(b.referencingTable)||await s(b.referencingTable,b.referencingColumn,n);let d=n.map((b,S)=>`$${S+1}`).join(", "),g=`
|
|
38
38
|
DELETE FROM "${e}"
|
|
39
39
|
WHERE "${o}" IN (${d})
|
|
40
40
|
RETURNING *
|
|
41
|
-
`;
|
|
42
|
-
INSERT INTO "${e}" (${
|
|
41
|
+
`;(void 0)("Force deleting records with SQL:",g,"Values:",n);let p=await r.query(g,n);await r.query("COMMIT");let y=p.rowCount??0;return{success:!0,message:m>0?`Successfully deleted ${y} ${y===1?"record":"records"} from "${e}" and ${m} related ${m===1?"record":"records"} from other tables`:`Successfully deleted ${y} ${y===1?"record":"records"} from "${e}"`,deletedCount:y+m}}catch(o){throw await r.query("ROLLBACK"),(void 0)("Error force deleting records:",o),o}finally{r.release()}}});var ne,se=E(()=>{"use strict";w();ne=async a=>{let{tableName:e,data:t}=a,r=await f.connect();try{let o=Object.keys(t),n=Object.values(t),l=o.map((d,g)=>`$${g+1}`).join(", "),m=o.map(d=>`"${d}"`).join(", "),i=`
|
|
42
|
+
INSERT INTO "${e}" (${m})
|
|
43
43
|
VALUES (${l})
|
|
44
44
|
RETURNING *
|
|
45
|
-
`;
|
|
45
|
+
`;(void 0)("Inserting record with SQL:",i,"Values:",n);let s=await r.query(i,n);return{success:!0,message:`Record inserted into "${e}" successfully`,data:s.rows[0]}}catch(o){throw(void 0)("Error inserting record:",o),o}finally{r.release()}}});function ie(a){let e=a.toLowerCase().trim();return e.includes("[]")||e==="date"||e==="time"||e==="time without time zone"||e.startsWith("time(")||e==="timestamp"||e==="timestamp without time zone"||e.startsWith("timestamp(")||e==="timestamp with time zone"||e==="timestamptz"||e.startsWith("timestamp with time zone(")?v.date:e==="integer"||e==="int"||e==="int4"||e==="bigint"||e==="int8"||e==="smallint"||e==="int2"||e==="decimal"||e.startsWith("decimal(")||e==="numeric"||e.startsWith("numeric(")||e==="real"||e==="float4"||e==="double precision"||e==="float8"||e==="float"||e==="serial"||e==="serial4"||e==="bigserial"||e==="serial8"||e==="money"?v.number:e==="boolean"||e==="bool"?v.boolean:e==="json"||e==="jsonb"?v.json:(e.startsWith("user-defined")||e==="enum"||e==="text"||e==="xml"||e==="character varying"||e.startsWith("varchar")||e.startsWith("character varying(")||e==="character"||e.startsWith("char")||e.startsWith("character(")||e==="bpchar"||e==="uuid"||e==="interval"||e.startsWith("interval")||e==="bytea"||e==="point"||e==="line"||e==="polygon"||e==="inet"||e==="cidr"||e==="macaddr"||e==="macaddr8",v.text)}function ce(a){let e=a.toLowerCase().trim();return e==="integer"||e==="int"||e==="int4"||e==="serial"||e==="serial4"?u.int:e==="bigint"||e==="int8"||e==="bigserial"||e==="serial8"?u.bigint:e==="smallint"||e==="int2"?u.smallint:e==="decimal"||e.startsWith("decimal(")||e==="numeric"||e.startsWith("numeric(")?u.numeric:e==="real"||e==="float4"?u.float:e==="double precision"||e==="float8"||e==="float"?u.double:e==="money"?u.money:e==="boolean"||e==="bool"?u.boolean:e==="text"?u.text:e==="character varying"||e.startsWith("varchar")||e.startsWith("character varying(")?u.varchar:e==="character"||e.startsWith("char")||e.startsWith("character(")||e==="bpchar"?u.char:e==="json"?u.json:e==="jsonb"?u.jsonb:e==="xml"?u.xml:e==="uuid"?u.uuid:e==="date"?u.date:e==="time"||e==="time without time zone"||e.startsWith("time(")?u.time:e==="timestamp"||e==="timestamp without time zone"||e.startsWith("timestamp(")?u.timestamp:e==="timestamp with time zone"||e==="timestamptz"||e.startsWith("timestamp with time zone(")?u.timestamptz:e==="interval"||e.startsWith("interval")?u.interval:e==="bytea"?u.bytea:e==="inet"?u.inet:e==="cidr"?u.cidr:e==="macaddr"?u.macaddr:e==="macaddr8"?u.macaddr8:e==="point"?u.point:e==="line"?u.line:e==="polygon"?u.polygon:e.startsWith("array")||e.includes("[]")?u.text:e.startsWith("user-defined")||e==="enum"?u.enum:u.text}var v,u,le=E(()=>{"use strict";v={text:"text",boolean:"boolean",number:"number",enum:"enum",json:"json",date:"date",array:"array"};u={int:"int",bigint:"bigint",smallint:"smallint",numeric:"numeric",float:"float",double:"double",money:"money",boolean:"boolean",text:"text",varchar:"varchar",char:"char",json:"json",jsonb:"jsonb",xml:"xml",uuid:"uuid",date:"date",time:"time",timestamp:"timestamp",timestamptz:"timestamptz",interval:"interval",bytea:"bytea",inet:"inet",cidr:"cidr",macaddr:"macaddr",macaddr8:"macaddr8",point:"point",line:"line",polygon:"polygon",array:"array",enum:"enum"}});var me,ue=E(()=>{"use strict";w();le();me=async a=>{let e=await f.connect();try{return(await e.query(`
|
|
46
46
|
SELECT
|
|
47
47
|
c.column_name as "columnName",
|
|
48
48
|
c.data_type as "dataType",
|
|
@@ -91,7 +91,7 @@ var Oe=Object.defineProperty;var E=(a,e)=>()=>(a&&(e=a(a=0)),e);var Pe=(a,e)=>{f
|
|
|
91
91
|
WHERE c.table_schema = 'public'
|
|
92
92
|
AND c.table_name = $1
|
|
93
93
|
ORDER BY c.ordinal_position;
|
|
94
|
-
`,[a])).rows.map(r=>{let o=null;return r.enumValues&&(Array.isArray(r.enumValues)?o=r.enumValues:typeof r.enumValues=="string"&&(o=r.enumValues.replace(/[{}]/g,"").split(",").filter(Boolean))),{columnName:r.columnName,dataType:ie(r.dataType),dataTypeLabel:ce(r.dataType),isNullable:r.isNullable,columnDefault:r.columnDefault,isPrimaryKey:r.isPrimaryKey,isForeignKey:r.isForeignKey,referencedTable:r.referencedTable,referencedColumn:r.referencedColumn,enumValues:o}})}finally{e.release()}}});var de,pe=E(()=>{"use strict";
|
|
94
|
+
`,[a])).rows.map(r=>{let o=null;return r.enumValues&&(Array.isArray(r.enumValues)?o=r.enumValues:typeof r.enumValues=="string"&&(o=r.enumValues.replace(/[{}]/g,"").split(",").filter(Boolean))),{columnName:r.columnName,dataType:ie(r.dataType),dataTypeLabel:ce(r.dataType),isNullable:r.isNullable,columnDefault:r.columnDefault,isPrimaryKey:r.isPrimaryKey,isForeignKey:r.isForeignKey,referencedTable:r.referencedTable,referencedColumn:r.referencedColumn,enumValues:o}})}finally{e.release()}}});var de,pe=E(()=>{"use strict";w();de=async()=>{let a=await f.connect();try{return(await a.query(`
|
|
95
95
|
SELECT
|
|
96
96
|
t.table_name as "tableName",
|
|
97
97
|
COALESCE(s.n_live_tup, 0) as "rowCount"
|
|
@@ -100,16 +100,16 @@ var Oe=Object.defineProperty;var E=(a,e)=>()=>(a&&(e=a(a=0)),e);var Pe=(a,e)=>{f
|
|
|
100
100
|
WHERE t.table_schema = 'public'
|
|
101
101
|
AND t.table_type = 'BASE TABLE'
|
|
102
102
|
ORDER BY t.table_name;
|
|
103
|
-
`)).rows.map(t=>({tableName:t.tableName,rowCount:Number(t.rowCount)}))}finally{a.release()}}});var et,tt,fe,ge=E(()=>{"use strict";
|
|
103
|
+
`)).rows.map(t=>({tableName:t.tableName,rowCount:Number(t.rowCount)}))}finally{a.release()}}});var et,tt,fe,ge=E(()=>{"use strict";w();et=a=>{if(a.length===0)return{clause:"",values:[]};let e=[],t=[];for(let r of a){let o=t.length+1,n=`"${r.columnName}"`;switch(r.operator){case"=":case"!=":case">":case">=":case"<":case"<=":e.push(`${n} ${r.operator} $${o}`),t.push(r.value);break;case"is":r.value.toLowerCase()==="null"?e.push(`${n} IS NULL`):(e.push(`${n} = $${o}`),t.push(r.value));break;case"is not":r.value.toLowerCase()==="null"?e.push(`${n} IS NOT NULL`):(e.push(`${n} != $${o}`),t.push(r.value));break;case"like":e.push(`${n}::text LIKE $${o}`),t.push(r.value);break;case"not like":e.push(`${n}::text NOT LIKE $${o}`),t.push(r.value);break;case"ilike":e.push(`${n}::text ILIKE $${o}`),t.push(r.value);break;case"not ilike":e.push(`${n}::text NOT ILIKE $${o}`),t.push(r.value);break;default:break}}return e.length===0?{clause:"",values:[]}:{clause:`WHERE ${e.join(" AND ")}`,values:t}},tt=(a,e)=>Array.isArray(a)?a.length===0?"":`ORDER BY ${a.map(r=>`"${r.columnName}" ${r.direction.toUpperCase()}`).join(", ")}`:a&&typeof a=="string"?`ORDER BY "${a}" ${e?.toUpperCase()||"ASC"}`:"",fe=async(a,e=1,t=50,r="",o="asc",n=[])=>{let l=tt((Array.isArray(r),r),o),{clause:m,values:i}=et(n),s=await f.connect();try{let d=(e-1)*t,g=await s.query(`SELECT COUNT(*) as total FROM "${a}" ${m}`,i),p=Number(g.rows[0].total),y=Math.ceil(p/t),h=i.length+1,b=i.length+2;return{data:(await s.query(`SELECT * FROM "${a}" ${m} ${l} LIMIT $${h} OFFSET $${b}`,[...i,t,d])).rows,meta:{page:e,limit:t,total:p,totalPages:y,hasNextPage:e<y,hasPreviousPage:e>1}}}finally{s.release()}}});var be,ye=E(()=>{"use strict";w();be=async a=>{let{tableName:e,updates:t,primaryKey:r="id"}=a,o=await f.connect();try{await o.query("BEGIN");let n=new Map;for(let i of t){let s=i.rowData[r];if(s===void 0)throw new Error(`Primary key "${r}" not found in row data. Please ensure the row has a primary key.`);n.has(s)||n.set(s,[]),n.get(s)?.push({columnName:i.columnName,value:i.value,rowData:i.rowData})}let l=[],m=0;for(let[i,s]of n.entries()){let d=s.map((h,b)=>`"${h.columnName}" = $${b+1}`),g=s.map(h=>((void 0)(`Value for ${h.columnName}:`,typeof h.value,h.value),h.value!==null&&typeof h.value=="object"?JSON.stringify(h.value):h.value));g.push(i);let p=`
|
|
104
104
|
UPDATE "${e}"
|
|
105
105
|
SET ${d.join(", ")}
|
|
106
106
|
WHERE "${r}" = $${g.length}
|
|
107
107
|
RETURNING *
|
|
108
|
-
`;
|
|
109
|
-
Usage:`)),
|
|
110
|
-
`),
|
|
111
|
-
`),
|
|
112
|
-
`),
|
|
113
|
-
To configure database connection:`)),
|
|
114
|
-
`)),
|
|
108
|
+
`;(void 0)("Updating record with SQL:",p,"Values:",g);let y=await o.query(p,g);if(y.rowCount===0)throw new Error(`Record with ${r} = ${i} not found in table "${e}"`);l.push(y.rows[0]),m+=y.rowCount||0}return await o.query("COMMIT"),{success:!0,message:`Successfully updated ${m} ${m===1?"row":"rows"} in "${e}"`,data:l,updatedCount:m}}catch(n){throw await o.query("ROLLBACK"),(void 0)("Error updating records:",n),n}finally{o.release()}}});import{z as c}from"zod";var rt,he,ot,at,Ee,I,Ne,we,Te,F,Re=E(()=>{"use strict";rt=["CASCADE","SET NULL","SET DEFAULT","RESTRICT","NO ACTION"],he=c.enum(rt),ot=c.object({columnName:c.string().min(1),columnType:c.string().min(1),defaultValue:c.string(),isPrimaryKey:c.boolean(),isNullable:c.boolean(),isUnique:c.boolean(),isIdentity:c.boolean(),isArray:c.boolean()}),at=c.object({columnName:c.string().min(1),referencedTable:c.string().min(1),referencedColumn:c.string().min(1),onUpdate:he,onDelete:he}),Ee=c.object({tableName:c.string().min(1,"Table name is required"),fields:c.array(ot).min(1,"At least one field is required"),foreignKeys:c.array(at).optional()}),I=c.object({tableName:c.string().min(1,"Table name is required")}),Ne=c.object({page:c.string().optional().default("1").transform(Number),pageSize:c.string().optional().default("50").transform(Number),sort:c.string().optional().default(""),order:c.enum(["asc","desc"]).optional(),filters:c.string().optional().transform(a=>{if(!a)return[];try{return JSON.parse(a)}catch{return[]}})}),we=c.object({tableName:c.string().min(1,"Table name is required")}),Te=c.object({tableName:c.string().min(1,"Table name is required"),updates:c.array(c.object({rowData:c.any(),columnName:c.string().min(1),value:c.any()})).min(1,"At least one update is required"),primaryKey:c.string().optional()}),F=c.object({tableName:c.string().min(1,"Table name is required"),primaryKeys:c.array(c.object({columnName:c.string().min(1),value:c.any()})).min(1,"At least one primary key is required")})});var Se={};je(Se,{createServer:()=>ct});import U from"path";import{fileURLToPath as nt}from"url";import{serveStatic as ve}from"@hono/node-server/serve-static";import{zValidator as T}from"@hono/zod-validator";import{Hono as st}from"hono";import{cors as it}from"hono/cors";var De,ct,_e=E(()=>{"use strict";te();ae();se();ue();pe();ge();ye();Re();De=()=>{let a=U.dirname(nt(import.meta.url));return U.resolve(a,"./core-dist")},ct=()=>{let a=new st().basePath("/");return a.use("/*",it()),a.use("/favicon.ico",ve({path:U.resolve(De(),"favicon.ico")})),a.use("*",async(e,t)=>{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 t()}),a.use("/*",ve({root:De()})),a.get("/tables",async e=>{try{let t=await de();return(void 0)("GET /tables",t),e.json(t)}catch(t){(void 0)("GET /tables error:",t);let r=t instanceof Error?t.message:"Failed to fetch tables",o=!1;return t&&typeof t=="object"&&"code"in t?o=t.code==="ECONNREFUSED":t&&typeof t=="object"&&"errors"in t&&Array.isArray(t.errors)&&(o=t.errors?.some(l=>l.code==="ECONNREFUSED")??!1),o?e.json({success:!1,message:"Cannot connect to database. Please check your DATABASE_URL and ensure the database server is running.",error:r},503):e.json({success:!1,message:r},500)}}),a.get("/tables/:tableName/columns",T("param",I),async e=>{try{let{tableName:t}=e.req.valid("param"),r=await me(t);return(void 0)("GET /tables/:tableName/columns",r),e.json(r)}catch(t){(void 0)("GET /tables/:tableName/columns error:",t);let r=t instanceof Error?t.message:"Failed to fetch columns",o=!1;return t&&typeof t=="object"&&"code"in t?o=t.code==="ECONNREFUSED":t&&typeof t=="object"&&"errors"in t&&Array.isArray(t.errors)&&(o=t.errors?.some(l=>l.code==="ECONNREFUSED")??!1),o?e.json({success:!1,message:"Cannot connect to database. Please check your DATABASE_URL and ensure the database server is running.",error:r},503):e.json({success:!1,message:r},500)}}),a.get("/tables/:tableName/data",T("param",I),T("query",Ne),async e=>{try{let{tableName:t}=e.req.valid("param"),{page:r,pageSize:o,sort:n,order:l,filters:m}=e.req.valid("query"),i="";if(n)try{let d=JSON.parse(n);Array.isArray(d)?i=d:i=n}catch{i=n}let s=await fe(t,r,o,i,l,m);return e.json(s)}catch(t){(void 0)("GET /tables/:tableName/data error:",t);let r=t instanceof Error?t.message:"Failed to fetch table data",o=!1;return t&&typeof t=="object"&&"code"in t?o=t.code==="ECONNREFUSED":t&&typeof t=="object"&&"errors"in t&&Array.isArray(t.errors)&&(o=t.errors?.some(l=>l.code==="ECONNREFUSED")??!1),o?e.json({success:!1,message:"Cannot connect to database. Please check your DATABASE_URL and ensure the database server is running.",error:r},503):e.json({success:!1,message:r},500)}}),a.post("/tables",T("json",Ee),async e=>{try{let t=e.req.valid("json");(void 0)("POST /tables body",t);let r=await ee(t);return(void 0)("POST /tables",r),e.json(r)}catch(t){(void 0)("POST /tables error:",t);let r=t&&typeof t=="object"&&"detail"in t?t.detail:void 0;return e.json({success:!1,message:t instanceof Error?t.message:"Failed to create table",detail:r},500)}}),a.post("/records",T("json",we),async e=>{try{let t=e.req.valid("json"),{tableName:r,...o}=t;(void 0)("POST /records body",{tableName:r,recordData:o});let n=await ne({tableName:r,data:o});return(void 0)("POST /records",n),e.json(n)}catch(t){(void 0)("POST /records error:",t);let r=t&&typeof t=="object"&&"detail"in t?t.detail:void 0;return e.json({success:!1,message:t instanceof Error?t.message:"Failed to create record",detail:r},500)}}),a.patch("/records",T("json",Te),async e=>{try{let t=e.req.valid("json"),{tableName:r,updates:o,primaryKey:n}=t;(void 0)("PATCH /records body",{tableName:r,updates:o,primaryKey:n});let l=await be({tableName:r,updates:o,primaryKey:n});return(void 0)("PATCH /records",l),e.json(l)}catch(t){(void 0)("PATCH /records error:",t);let r=t&&typeof t=="object"&&"detail"in t?t.detail:void 0;return e.json({success:!1,message:t instanceof Error?t.message:"Failed to update records",detail:r},500)}}),a.delete("/records",T("json",F),async e=>{try{let t=e.req.valid("json"),{tableName:r,primaryKeys:o}=t;(void 0)("DELETE /records body",{tableName:r,primaryKeys:o});let n=await re({tableName:r,primaryKeys:o});return(void 0)("DELETE /records result",n),n.fkViolation?e.json(n,409):e.json(n)}catch(t){(void 0)("DELETE /records error:",t);let r=t&&typeof t=="object"&&"detail"in t?t.detail:void 0;return e.json({success:!1,message:t instanceof Error?t.message:"Failed to delete records",detail:r},500)}}),a.delete("/records/force",T("json",F),async e=>{try{let t=e.req.valid("json"),{tableName:r,primaryKeys:o}=t;(void 0)("DELETE /records/force body",{tableName:r,primaryKeys:o});let n=await oe({tableName:r,primaryKeys:o});return(void 0)("DELETE /records/force result",n),e.json(n)}catch(t){(void 0)("DELETE /records/force error:",t);let r=t&&typeof t=="object"&&"detail"in t?t.detail:void 0;return e.json({success:!1,message:t instanceof Error?t.message:"Failed to force delete records",detail:r},500)}}),a}});import{intro as lt,outro as mt}from"@clack/prompts";import{serve as ut}from"@hono/node-server";import L from"picocolors";import{program as V}from"commander";var W=()=>(V.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),V.opts());import{readFile as ke}from"fs/promises";import{resolve as Ie}from"path";import{cancel as C,isCancel as O,note as M,select as Fe,spinner as Ue,text as z}from"@clack/prompts";import{parse as qe}from"dotenv";import P from"picocolors";var B=async(a,e)=>{let t=e||"DATABASE_URL";if(a?.[t])return a[t];let r=Ue();r.start("Looking for database connection..."),a?M(P.red(`${t} not found in .env`)):M(P.red("No .env file found in current directory"));let o=await Fe({message:`How do you want to provide ${t}?`,options:[{value:"manual",label:"Enter connection string manually"},{value:"other-env",label:"Use different .env file"},{value:"cancel",label:"Cancel / Exit"}],initialValue:"manual"});if((O(o)||o==="cancel")&&(C("No database connection provided. Exiting..."),process.exit(0)),o==="other-env"){r.start("Waiting for path...");let l=await z({message:"Enter path to .env file",placeholder:"~/projects/myapp/.env.local or ./special.env",validate(i){if(!i.trim())return"Path is required"}});O(l)&&(C("Cancelled."),process.exit(0)),r.stop("Trying custom .env...");let m=Ie(l);try{let i=await ke(m,"utf-8"),s=qe(i);if(s[t])return s[t];throw new Error(`${t} still missing in custom file`)}catch(i){C(`Cannot read or parse file: ${P.dim(i.message)}`),process.exit(1)}}r.stop("Manual input...");let n=await z({message:`Paste your ${t}`,placeholder:"postgresql://user:password@localhost:5432/mydb",validate(l){if(!l.trim())return"Connection string is required!";try{new URL(l);return}catch{return"Must be a valid URL format"}}});return O(n)&&(C("Cancelled."),process.exit(0)),n.trim()};import{access as Ke,readFile as Ve}from"fs/promises";import{resolve as H}from"path";import{parse as We}from"dotenv";var D=async a=>{let e=a?H(a):H(process.cwd(),".env");try{await Ke(e);let t=await Ve(e,"utf-8");return We(t)}catch(t){if(t instanceof Error&&t.message.includes("ENOENT"))return null;throw t}};import{intro as Me,outro as ze}from"@clack/prompts";import A from"picocolors";var G=()=>{Me(A.inverse(" db-studio ")),(void 0)(A.bold(`
|
|
109
|
+
Usage:`)),(void 0)(` db-studio [options]
|
|
110
|
+
`),(void 0)(A.bold("Options:")),(void 0)(" -e, --env <path> Path to custom .env file"),(void 0)(" -p, --port <port> Port to run the server on (default: 3333)"),(void 0)(" -d, --database-url <url> Database URL to use"),(void 0)(" -n, --var-name <name> Custom environment variable name (default: DATABASE_URL)"),(void 0)(" -s, --status Show status of the database connection"),(void 0)(" -h, --help Show this help message"),(void 0)(` -v, --version Show version number
|
|
111
|
+
`),(void 0)(A.bold("Examples:")),(void 0)(" db-studio"),(void 0)(" db-studio -e .env.local"),(void 0)(" db-studio -p 4000"),(void 0)(" db-studio -d postgresql://user:pass@localhost:5432/mydb"),(void 0)(" db-studio -n MY_DATABASE_URL"),(void 0)(" db-studio -e .env.production -n PROD_DB_URL"),(void 0)(` db-studio --status
|
|
112
|
+
`),ze(A.green("For more information, visit: https://github.com/your-repo/db-studio"))};import{intro as Be,note as He,outro as Q}from"@clack/prompts";import N from"picocolors";var R={PORT:3333,ENV:".env",VAR_NAME:"DATABASE_URL"};var Y=async(a,e,t)=>{Be(N.inverse(" db-studio "));let r=t||R.VAR_NAME,o=null;if(e)o=e;else{let n=a?await D(a):await D(R.ENV);n?.[r]&&(o=n[r])}o?Q(N.green(`\u2713 Database connection configured (using ${r})`)):(He(N.red(`\u2717 ${r} not found`),"Status"),(void 0)(N.yellow(`
|
|
113
|
+
To configure database connection:`)),(void 0)(N.dim(` \u2022 Add ${r} to your .env file`)),(void 0)(N.dim(" \u2022 Use -d flag: db-studio -d <url>")),(void 0)(N.dim(" \u2022 Use -e flag: db-studio -e <path-to-env>")),(void 0)(N.dim(` \u2022 Use -n flag: db-studio -n <var-name>
|
|
114
|
+
`)),Q(N.yellow("\u26A0 No database connection configured")))};import{intro as Qe,outro as Ye}from"@clack/prompts";import X from"picocolors";var J={name:"db-studio",type:"module",version:"0.0.9",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 <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:"tsx src/index.ts",build:"tsup","build:release":"tsup --minify --sourcemap",start:"node dist/index.js",check:"biome check --write --unsafe --verbose"},dependencies:{"@clack/prompts":"^0.11.0","@hono/node-server":"^1.19.7","@hono/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",zod:"^4.2.1"},devDependencies:{"@biomejs/biome":"^2.2.6","@types/node":"^20.11.17","@types/pg":"^8.16.0",tsup:"^8.5.1",tsx:"^4.7.1",typescript:"^5.8.3",wrangler:"^4.4.0"}};var Z=()=>{Qe(X.inverse(" db-studio ")),Ye(X.green(`\u{1F680} db-studio v${J.version}`))};var dt=async()=>{let{env:a,port:e,databaseUrl:t,varName:r,status:o,help:n,version:l}=W();n&&(G(),process.exit(0)),l&&(Z(),process.exit(0)),o&&(await Y(a,t,r),process.exit(0)),lt(L.inverse(" db-studiox "));let m=e?parseInt(e,10):R.PORT,i=r||R.VAR_NAME,s=a?await D(a):await D(R.ENV),d=t||await B(s,i);process.env.DATABASE_URL=d;let{createServer:g}=await Promise.resolve().then(()=>(_e(),Se)),p=g();ut({fetch:p.fetch,port:m}),mt(L.green(`Server running at ${L.cyan(`http://localhost:${m}`)}`))};dt().catch(a=>{(void 0)(L.red(`\u274C Unexpected error: ${a.message}`)),process.exit(1)});export{dt as main};
|
|
115
115
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/db.ts","../src/dao/create-table.dao.ts","../src/dao/delete-records.dao.ts","../src/dao/insert-record.dao.ts","../src/types/column.types.ts","../src/dao/table-columns.dao.ts","../src/dao/table-list.dao.ts","../src/dao/tables-data.dao.ts","../src/dao/update-records.dao.ts","../src/types/create-table.type.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/utils/defaults.ts","../src/cmd/show-version.ts","../../../package.json"],"sourcesContent":["import { Pool } from \"pg\";\n\nlet dbInstance: Pool | null = null;\n\nconst getPool = (): Pool => {\n\tif (!dbInstance) {\n\t\tif (!process.env.DATABASE_URL) {\n\t\t\tthrow new Error(\n\t\t\t\t\"DATABASE_URL is not set. Please provide a database connection string.\",\n\t\t\t);\n\t\t}\n\t\tdbInstance = new Pool({\n\t\t\tconnectionString: process.env.DATABASE_URL,\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\treturn getPool()[prop as keyof Pool];\n\t},\n});\n","import { db } from \"../db.js\";\nimport type { FieldDataType } from \"../types/create-table.type.js\";\nimport type { CreateTableFormData } from \"../types/index.js\";\n\nexport const createTable = async (tableData: CreateTableFormData) => {\n\tconst client = await db.connect();\n\ttry {\n\t\tconst { tableName, fields, foreignKeys } = tableData;\n\n\t\t// Build column definitions\n\t\tconst columnDefinitions = fields.map((field: FieldDataType) => {\n\t\t\tlet columnDef = `\"${field.columnName}\" ${field.columnType}`;\n\n\t\t\t// Add array suffix if needed\n\t\t\tif (field.isArray) {\n\t\t\t\tcolumnDef += \"[]\";\n\t\t\t}\n\n\t\t\t// Add PRIMARY KEY constraint\n\t\t\tif (field.isPrimaryKey) {\n\t\t\t\tcolumnDef += \" PRIMARY KEY\";\n\t\t\t}\n\n\t\t\t// Add UNIQUE constraint\n\t\t\tif (field.isUnique && !field.isPrimaryKey) {\n\t\t\t\tcolumnDef += \" UNIQUE\";\n\t\t\t}\n\n\t\t\t// Add NOT NULL constraint (if not nullable)\n\t\t\tif (!field.isNullable) {\n\t\t\t\tcolumnDef += \" NOT NULL\";\n\t\t\t}\n\n\t\t\t// Add GENERATED ALWAYS AS IDENTITY for identity columns\n\t\t\tif (field.isIdentity) {\n\t\t\t\tcolumnDef += \" GENERATED ALWAYS AS IDENTITY\";\n\t\t\t}\n\n\t\t\t// Add default value\n\t\t\tif (field.defaultValue && !field.isIdentity) {\n\t\t\t\tcolumnDef += ` DEFAULT ${field.defaultValue}`;\n\t\t\t}\n\n\t\t\treturn columnDef;\n\t\t});\n\n\t\t// Build foreign key constraints\n\t\tconst foreignKeyConstraints =\n\t\t\tforeignKeys?.map((fk) => {\n\t\t\t\tconst constraintName = `fk_${tableName}_${fk.columnName}_${fk.referencedTable}_${fk.referencedColumn}`;\n\t\t\t\treturn `CONSTRAINT \"${constraintName}\" FOREIGN KEY (\"${fk.columnName}\") REFERENCES \"${fk.referencedTable}\" (\"${fk.referencedColumn}\") ON UPDATE ${fk.onUpdate} ON DELETE ${fk.onDelete}`;\n\t\t\t}) || [];\n\n\t\t// Combine column definitions and foreign key constraints\n\t\tconst allDefinitions = [...columnDefinitions, ...foreignKeyConstraints];\n\n\t\t// Create the table\n\t\tconst createTableSQL = `\n\t\t\tCREATE TABLE \"${tableName}\" (\n\t\t\t\t${allDefinitions.join(\",\\n\\t\\t\\t\\t\")}\n\t\t\t);\n\t\t`;\n\n\t\tconsole.log(\"Creating table with SQL:\", createTableSQL);\n\t\tawait client.query(createTableSQL);\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\ttableName,\n\t\t\tmessage: `Table \"${tableName}\" created successfully`,\n\t\t};\n\t} catch (error) {\n\t\tconsole.error(\"Error creating table:\", error);\n\t\tthrow error;\n\t} finally {\n\t\tclient.release();\n\t}\n};\n","import { db } from \"../db.js\";\n\nexport interface DeleteRecordParams {\n\ttableName: string;\n\tprimaryKeys: Array<{ columnName: string; value: unknown }>;\n}\n\nexport interface ForeignKeyConstraint {\n\tconstraintName: string;\n\treferencingTable: string;\n\treferencingColumn: string;\n\treferencedTable: string;\n\treferencedColumn: string;\n}\n\nexport interface ForeignKeyConstraintRow {\n\tconstraint_name: string;\n\treferencing_table: string;\n\treferencing_column: string;\n\treferenced_table: string;\n\treferenced_column: string;\n}\n\nexport interface RelatedRecord {\n\ttableName: string;\n\tcolumnName: string;\n\tconstraintName: string;\n\trecords: Array<Record<string, unknown>>;\n}\n\nexport interface DeleteResult {\n\tsuccess: boolean;\n\tmessage: string;\n\tdeletedCount?: number;\n\tfkViolation?: boolean;\n\trelatedRecords?: RelatedRecord[];\n}\n\n/**\n * Gets foreign key constraints that reference the given table\n */\nexport const getForeignKeyReferences = async (\n\ttableName: string,\n): 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 result = await db.query(query, [tableName]);\n\n\treturn result.rows.map(({ row }: { row: ForeignKeyConstraintRow }) => ({\n\t\tconstraintName: row.constraint_name,\n\t\treferencingTable: row.referencing_table,\n\t\treferencingColumn: row.referencing_column,\n\t\treferencedTable: row.referenced_table,\n\t\treferencedColumn: row.referenced_column,\n\t}));\n};\n\n/**\n * Finds all records in other tables that reference the given primary key values\n */\nexport const getRelatedRecords = async (\n\ttableName: string,\n\tprimaryKeys: Array<{ columnName: string; value: unknown }>,\n): Promise<RelatedRecord[]> => {\n\tconst fkConstraints = await getForeignKeyReferences(tableName);\n\n\tif (fkConstraints.length === 0) {\n\t\treturn [];\n\t}\n\n\tconst relatedRecords: RelatedRecord[] = [];\n\n\t// Group constraints by referencing table and column for efficiency\n\tconst constraintsByTable = new Map<string, ForeignKeyConstraint[]>();\n\tfor (const constraint of fkConstraints) {\n\t\tconst key = `${constraint.referencingTable}.${constraint.referencingColumn}`;\n\t\tif (!constraintsByTable.has(key)) {\n\t\t\tconstraintsByTable.set(key, []);\n\t\t}\n\t\tconstraintsByTable.get(key)?.push(constraint);\n\t}\n\n\t// Get the primary key values that we're looking for\n\tconst pkValues = primaryKeys.map((pk) => pk.value);\n\n\tfor (const [_tableColumn, constraints] of constraintsByTable) {\n\t\tconst constraint = constraints[0];\n\t\tif (!constraint) continue;\n\n\t\t// Find which primary key column matches this FK's referenced column\n\t\tconst matchingPk = primaryKeys.find(\n\t\t\t(pk) => pk.columnName === constraint.referencedColumn,\n\t\t);\n\t\tif (!matchingPk) continue;\n\n\t\t// Build query to find related records\n\t\tconst placeholders = pkValues.map((_, i) => `$${i + 1}`).join(\", \");\n\t\tconst query = `\n\t\t\tSELECT * FROM \"${constraint.referencingTable}\"\n\t\t\tWHERE \"${constraint.referencingColumn}\" IN (${placeholders})\n\t\t\tLIMIT 100\n\t\t`;\n\n\t\ttry {\n\t\t\tconst result = await db.query(query, pkValues);\n\n\t\t\tif (result.rows.length > 0) {\n\t\t\t\trelatedRecords.push({\n\t\t\t\t\ttableName: constraint.referencingTable,\n\t\t\t\t\tcolumnName: constraint.referencingColumn,\n\t\t\t\t\tconstraintName: constraint.constraintName,\n\t\t\t\t\trecords: result.rows,\n\t\t\t\t});\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconsole.error(\n\t\t\t\t`Error fetching related records from ${constraint.referencingTable}:`,\n\t\t\t\terror,\n\t\t\t);\n\t\t}\n\t}\n\n\treturn relatedRecords;\n};\n\n/**\n * Attempts to delete records. If FK violation occurs, returns related records.\n */\nexport const deleteRecords = async (\n\tparams: DeleteRecordParams,\n): Promise<DeleteResult> => {\n\tconst { tableName, primaryKeys } = params;\n\tconst client = await db.connect();\n\n\ttry {\n\t\tawait client.query(\"BEGIN\");\n\n\t\t// Build the delete query\n\t\tconst pkColumn = primaryKeys[0]?.columnName;\n\t\tif (!pkColumn) {\n\t\t\tthrow new Error(\"Primary key column name is required\");\n\t\t}\n\n\t\tconst pkValues = primaryKeys.map((pk) => pk.value);\n\t\tconst placeholders = pkValues.map((_, i) => `$${i + 1}`).join(\", \");\n\n\t\tconst deleteSQL = `\n\t\t\tDELETE FROM \"${tableName}\"\n\t\t\tWHERE \"${pkColumn}\" IN (${placeholders})\n\t\t\tRETURNING *\n\t\t`;\n\n\t\tconsole.log(\"Deleting records with SQL:\", deleteSQL, \"Values:\", pkValues);\n\t\tconst result = await client.query(deleteSQL, pkValues);\n\n\t\tawait client.query(\"COMMIT\");\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tmessage: `Successfully deleted ${result.rowCount} ${result.rowCount === 1 ? \"record\" : \"records\"} from \"${tableName}\"`,\n\t\t\tdeletedCount: result.rowCount ?? 0,\n\t\t};\n\t} catch (error) {\n\t\tawait client.query(\"ROLLBACK\");\n\n\t\t// Check if this is a foreign key violation\n\t\tconst pgError = error as { code?: string; detail?: string; constraint?: string };\n\n\t\tif (pgError.code === \"23503\") {\n\t\t\t// Foreign key violation\n\t\t\tconsole.log(\"FK violation detected, fetching related records...\");\n\n\t\t\t// Fetch related records to show the user\n\t\t\tconst relatedRecords = await getRelatedRecords(tableName, primaryKeys);\n\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\tmessage: \"Cannot delete: Records are referenced by other tables\",\n\t\t\t\tfkViolation: true,\n\t\t\t\trelatedRecords,\n\t\t\t};\n\t\t}\n\n\t\tconsole.error(\"Error deleting records:\", error);\n\t\tthrow error;\n\t} finally {\n\t\tclient.release();\n\t}\n};\n\n/**\n * Force deletes records by first deleting all related records in referencing tables (cascade)\n */\nexport const forceDeleteRecords = async (\n\tparams: DeleteRecordParams,\n): Promise<DeleteResult> => {\n\tconst { tableName, primaryKeys } = params;\n\tconst client = await db.connect();\n\n\ttry {\n\t\tawait client.query(\"BEGIN\");\n\n\t\tconst pkColumn = primaryKeys[0]?.columnName;\n\t\tif (!pkColumn) {\n\t\t\tthrow new Error(\"Primary key column name is required\");\n\t\t}\n\n\t\tconst pkValues = primaryKeys.map((pk) => pk.value);\n\n\t\t// Get all FK constraints that reference this table\n\t\tconst fkConstraints = await getForeignKeyReferences(tableName);\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);\n\n\t\t\tfor (const nestedFk of nestedFks) {\n\t\t\t\t// Get the values that will be deleted from the target table\n\t\t\t\tconst placeholders = values.map((_, i) => `$${i + 1}`).join(\", \");\n\t\t\t\tconst selectQuery = `\n\t\t\t\t\tSELECT \"${nestedFk.referencedColumn}\" FROM \"${targetTable}\"\n\t\t\t\t\tWHERE \"${targetColumn}\" IN (${placeholders})\n\t\t\t\t`;\n\n\t\t\t\tconst selectResult = await client.query(selectQuery, values);\n\t\t\t\tconst nestedValues = selectResult.rows.map(\n\t\t\t\t\t({ row }: { row: { [nestedFk.referencedColumn]: unknown } }) =>\n\t\t\t\t\t\trow[nestedFk.referencedColumn],\n\t\t\t\t);\n\n\t\t\t\tif (nestedValues.length > 0) {\n\t\t\t\t\tawait deleteRelatedRecursively(\n\t\t\t\t\t\tnestedFk.referencingTable,\n\t\t\t\t\t\tnestedFk.referencingColumn,\n\t\t\t\t\t\tnestedValues,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Now delete from the target table\n\t\t\tconst placeholders = values.map((_, i) => `$${i + 1}`).join(\", \");\n\t\t\tconst deleteQuery = `\n\t\t\t\tDELETE FROM \"${targetTable}\"\n\t\t\t\tWHERE \"${targetColumn}\" IN (${placeholders})\n\t\t\t`;\n\n\t\t\tconst deleteResult = await client.query(deleteQuery, values);\n\t\t\ttotalRelatedDeleted += deleteResult.rowCount ?? 0;\n\t\t\tdeletedTables.add(targetTable);\n\t\t};\n\n\t\t// Delete from all referencing tables first\n\t\tfor (const constraint of fkConstraints) {\n\t\t\tif (deletedTables.has(constraint.referencingTable)) continue;\n\n\t\t\tawait deleteRelatedRecursively(\n\t\t\t\tconstraint.referencingTable,\n\t\t\t\tconstraint.referencingColumn,\n\t\t\t\tpkValues,\n\t\t\t);\n\t\t}\n\n\t\t// Finally delete the main records\n\t\tconst placeholders = pkValues.map((_, i) => `$${i + 1}`).join(\", \");\n\t\tconst deleteSQL = `\n\t\t\tDELETE FROM \"${tableName}\"\n\t\t\tWHERE \"${pkColumn}\" IN (${placeholders})\n\t\t\tRETURNING *\n\t\t`;\n\n\t\tconsole.log(\"Force deleting records with SQL:\", deleteSQL, \"Values:\", pkValues);\n\t\tconst result = await client.query(deleteSQL, pkValues);\n\n\t\tawait client.query(\"COMMIT\");\n\n\t\tconst mainDeleted = result.rowCount ?? 0;\n\t\tconst message =\n\t\t\ttotalRelatedDeleted > 0\n\t\t\t\t? `Successfully deleted ${mainDeleted} ${mainDeleted === 1 ? \"record\" : \"records\"} from \"${tableName}\" and ${totalRelatedDeleted} related ${totalRelatedDeleted === 1 ? \"record\" : \"records\"} from other tables`\n\t\t\t\t: `Successfully deleted ${mainDeleted} ${mainDeleted === 1 ? \"record\" : \"records\"} from \"${tableName}\"`;\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tmessage,\n\t\t\tdeletedCount: mainDeleted + totalRelatedDeleted,\n\t\t};\n\t} catch (error) {\n\t\tawait client.query(\"ROLLBACK\");\n\t\tconsole.error(\"Error force deleting records:\", error);\n\t\tthrow error;\n\t} finally {\n\t\tclient.release();\n\t}\n};\n","import { db } from \"../db.js\";\n\nexport interface InsertRecordParams {\n\ttableName: string;\n\tdata: Record<string, unknown>;\n}\n\nexport const insertRecord = async (params: InsertRecordParams) => {\n\tconst { tableName, data } = params;\n\tconst client = await db.connect();\n\n\ttry {\n\t\t// Extract column names and values\n\t\tconst columns = Object.keys(data);\n\t\tconst values = Object.values(data);\n\n\t\t// Build the INSERT query\n\t\tconst placeholders = columns.map((_, index) => `$${index + 1}`).join(\", \");\n\t\tconst columnNames = columns.map((col) => `\"${col}\"`).join(\", \");\n\n\t\tconst insertSQL = `\n\t\t\tINSERT INTO \"${tableName}\" (${columnNames})\n\t\t\tVALUES (${placeholders})\n\t\t\tRETURNING *\n\t\t`;\n\n\t\tconsole.log(\"Inserting record with SQL:\", insertSQL, \"Values:\", values);\n\t\tconst result = await client.query(insertSQL, values);\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tmessage: `Record inserted into \"${tableName}\" successfully`,\n\t\t\tdata: result.rows[0],\n\t\t};\n\t} catch (error) {\n\t\tconsole.error(\"Error inserting record:\", error);\n\t\tthrow error;\n\t} finally {\n\t\tclient.release();\n\t}\n};\n","export const DataTypes = {\n\ttext: \"text\",\n\tboolean: \"boolean\",\n\tnumber: \"number\",\n\tenum: \"enum\",\n\tjson: \"json\",\n\tdate: \"date\",\n\tarray: \"array\",\n} as const;\n\nexport type DataTypes = (typeof DataTypes)[keyof typeof DataTypes];\n\n/**\n * Maps PostgreSQL data types to generic DataType enum\n */\nexport function mapPostgresToDataType(pgType: string): DataTypes {\n\tconst normalized = pgType.toLowerCase().trim();\n\n\t// Handle array types and date/time types\n\tif (\n\t\tnormalized.includes(\"[]\") ||\n\t\tnormalized === \"date\" ||\n\t\tnormalized === \"time\" ||\n\t\tnormalized === \"time without time zone\" ||\n\t\tnormalized.startsWith(\"time(\") ||\n\t\tnormalized === \"timestamp\" ||\n\t\tnormalized === \"timestamp without time zone\" ||\n\t\tnormalized.startsWith(\"timestamp(\") ||\n\t\tnormalized === \"timestamp with time zone\" ||\n\t\tnormalized === \"timestamptz\" ||\n\t\tnormalized.startsWith(\"timestamp with time zone(\")\n\t) {\n\t\treturn DataTypes.date;\n\t}\n\n\t// Numeric types\n\tif (\n\t\tnormalized === \"integer\" ||\n\t\tnormalized === \"int\" ||\n\t\tnormalized === \"int4\" ||\n\t\tnormalized === \"bigint\" ||\n\t\tnormalized === \"int8\" ||\n\t\tnormalized === \"smallint\" ||\n\t\tnormalized === \"int2\" ||\n\t\tnormalized === \"decimal\" ||\n\t\tnormalized.startsWith(\"decimal(\") ||\n\t\tnormalized === \"numeric\" ||\n\t\tnormalized.startsWith(\"numeric(\") ||\n\t\tnormalized === \"real\" ||\n\t\tnormalized === \"float4\" ||\n\t\tnormalized === \"double precision\" ||\n\t\tnormalized === \"float8\" ||\n\t\tnormalized === \"float\" ||\n\t\tnormalized === \"serial\" ||\n\t\tnormalized === \"serial4\" ||\n\t\tnormalized === \"bigserial\" ||\n\t\tnormalized === \"serial8\" ||\n\t\tnormalized === \"money\"\n\t) {\n\t\treturn DataTypes.number;\n\t}\n\n\t// Boolean\n\tif (normalized === \"boolean\" || normalized === \"bool\") {\n\t\treturn DataTypes.boolean;\n\t}\n\n\t// JSON types\n\tif (normalized === \"json\" || normalized === \"jsonb\") {\n\t\treturn DataTypes.json;\n\t}\n\n\t// Enum types and long text types\n\tif (\n\t\tnormalized.startsWith(\"user-defined\") ||\n\t\tnormalized === \"enum\" ||\n\t\tnormalized === \"text\" ||\n\t\tnormalized === \"xml\"\n\t) {\n\t\treturn DataTypes.text;\n\t}\n\n\t// Short string types (varchar, char, uuid, etc.)\n\tif (\n\t\tnormalized === \"character varying\" ||\n\t\tnormalized.startsWith(\"varchar\") ||\n\t\tnormalized.startsWith(\"character varying(\") ||\n\t\tnormalized === \"character\" ||\n\t\tnormalized.startsWith(\"char\") ||\n\t\tnormalized.startsWith(\"character(\") ||\n\t\tnormalized === \"bpchar\" ||\n\t\tnormalized === \"uuid\" ||\n\t\tnormalized === \"interval\" ||\n\t\tnormalized.startsWith(\"interval\") ||\n\t\tnormalized === \"bytea\" ||\n\t\tnormalized === \"point\" ||\n\t\tnormalized === \"line\" ||\n\t\tnormalized === \"polygon\" ||\n\t\tnormalized === \"inet\" ||\n\t\tnormalized === \"cidr\" ||\n\t\tnormalized === \"macaddr\" ||\n\t\tnormalized === \"macaddr8\"\n\t) {\n\t\treturn DataTypes.text;\n\t}\n\n\t// Default to short for unrecognized types\n\treturn DataTypes.text;\n}\n\n/**\n * Standardized data type labels\n */\nexport const StandardizedDataType = {\n\t// Numeric types\n\tint: \"int\",\n\tbigint: \"bigint\",\n\tsmallint: \"smallint\",\n\tnumeric: \"numeric\",\n\tfloat: \"float\",\n\tdouble: \"double\",\n\tmoney: \"money\",\n\t// Boolean\n\tboolean: \"boolean\",\n\t// Text types\n\ttext: \"text\",\n\tvarchar: \"varchar\",\n\tchar: \"char\",\n\t// JSON types\n\tjson: \"json\",\n\tjsonb: \"jsonb\",\n\txml: \"xml\",\n\t// UUID\n\tuuid: \"uuid\",\n\t// Date/Time types\n\tdate: \"date\",\n\ttime: \"time\",\n\ttimestamp: \"timestamp\",\n\ttimestamptz: \"timestamptz\",\n\tinterval: \"interval\",\n\t// Binary\n\tbytea: \"bytea\",\n\t// Network types\n\tinet: \"inet\",\n\tcidr: \"cidr\",\n\tmacaddr: \"macaddr\",\n\tmacaddr8: \"macaddr8\",\n\t// Geometric types\n\tpoint: \"point\",\n\tline: \"line\",\n\tpolygon: \"polygon\",\n\t// Complex types\n\tarray: \"array\",\n\tenum: \"enum\",\n} as const;\n\nexport type StandardizedDataType =\n\t(typeof StandardizedDataType)[keyof typeof StandardizedDataType];\n\n/**\n * Maps PostgreSQL data types to standardized display labels\n */\nexport function standardizeDataTypeLabel(pgType: string): StandardizedDataType {\n\tconst normalized = pgType.toLowerCase().trim();\n\n\t// Numeric types\n\tif (\n\t\tnormalized === \"integer\" ||\n\t\tnormalized === \"int\" ||\n\t\tnormalized === \"int4\" ||\n\t\tnormalized === \"serial\" ||\n\t\tnormalized === \"serial4\"\n\t) {\n\t\treturn StandardizedDataType.int;\n\t}\n\n\tif (\n\t\tnormalized === \"bigint\" ||\n\t\tnormalized === \"int8\" ||\n\t\tnormalized === \"bigserial\" ||\n\t\tnormalized === \"serial8\"\n\t) {\n\t\treturn StandardizedDataType.bigint;\n\t}\n\n\tif (normalized === \"smallint\" || normalized === \"int2\") {\n\t\treturn StandardizedDataType.smallint;\n\t}\n\n\tif (\n\t\tnormalized === \"decimal\" ||\n\t\tnormalized.startsWith(\"decimal(\") ||\n\t\tnormalized === \"numeric\" ||\n\t\tnormalized.startsWith(\"numeric(\")\n\t) {\n\t\treturn StandardizedDataType.numeric;\n\t}\n\n\tif (normalized === \"real\" || normalized === \"float4\") {\n\t\treturn StandardizedDataType.float;\n\t}\n\n\tif (\n\t\tnormalized === \"double precision\" ||\n\t\tnormalized === \"float8\" ||\n\t\tnormalized === \"float\"\n\t) {\n\t\treturn StandardizedDataType.double;\n\t}\n\n\tif (normalized === \"money\") {\n\t\treturn StandardizedDataType.money;\n\t}\n\n\t// Boolean\n\tif (normalized === \"boolean\" || normalized === \"bool\") {\n\t\treturn StandardizedDataType.boolean;\n\t}\n\n\t// Text types\n\tif (normalized === \"text\") {\n\t\treturn StandardizedDataType.text;\n\t}\n\n\tif (\n\t\tnormalized === \"character varying\" ||\n\t\tnormalized.startsWith(\"varchar\") ||\n\t\tnormalized.startsWith(\"character varying(\")\n\t) {\n\t\treturn StandardizedDataType.varchar;\n\t}\n\n\tif (\n\t\tnormalized === \"character\" ||\n\t\tnormalized.startsWith(\"char\") ||\n\t\tnormalized.startsWith(\"character(\") ||\n\t\tnormalized === \"bpchar\"\n\t) {\n\t\treturn StandardizedDataType.char;\n\t}\n\n\t// JSON types\n\tif (normalized === \"json\") {\n\t\treturn StandardizedDataType.json;\n\t}\n\n\tif (normalized === \"jsonb\") {\n\t\treturn StandardizedDataType.jsonb;\n\t}\n\n\tif (normalized === \"xml\") {\n\t\treturn StandardizedDataType.xml;\n\t}\n\n\t// UUID\n\tif (normalized === \"uuid\") {\n\t\treturn StandardizedDataType.uuid;\n\t}\n\n\t// Date/Time types\n\tif (normalized === \"date\") {\n\t\treturn StandardizedDataType.date;\n\t}\n\n\tif (\n\t\tnormalized === \"time\" ||\n\t\tnormalized === \"time without time zone\" ||\n\t\tnormalized.startsWith(\"time(\")\n\t) {\n\t\treturn StandardizedDataType.time;\n\t}\n\n\tif (\n\t\tnormalized === \"timestamp\" ||\n\t\tnormalized === \"timestamp without time zone\" ||\n\t\tnormalized.startsWith(\"timestamp(\")\n\t) {\n\t\treturn StandardizedDataType.timestamp;\n\t}\n\n\tif (\n\t\tnormalized === \"timestamp with time zone\" ||\n\t\tnormalized === \"timestamptz\" ||\n\t\tnormalized.startsWith(\"timestamp with time zone(\")\n\t) {\n\t\treturn StandardizedDataType.timestamptz;\n\t}\n\n\tif (normalized === \"interval\" || normalized.startsWith(\"interval\")) {\n\t\treturn StandardizedDataType.interval;\n\t}\n\n\t// Binary\n\tif (normalized === \"bytea\") {\n\t\treturn StandardizedDataType.bytea;\n\t}\n\n\t// Network types\n\tif (normalized === \"inet\") {\n\t\treturn StandardizedDataType.inet;\n\t}\n\n\tif (normalized === \"cidr\") {\n\t\treturn StandardizedDataType.cidr;\n\t}\n\n\tif (normalized === \"macaddr\") {\n\t\treturn StandardizedDataType.macaddr;\n\t}\n\n\tif (normalized === \"macaddr8\") {\n\t\treturn StandardizedDataType.macaddr8;\n\t}\n\n\t// Geometric types\n\tif (normalized === \"point\") {\n\t\treturn StandardizedDataType.point;\n\t}\n\n\tif (normalized === \"line\") {\n\t\treturn StandardizedDataType.line;\n\t}\n\n\tif (normalized === \"polygon\") {\n\t\treturn StandardizedDataType.polygon;\n\t}\n\n\t// Array types\n\t// todo: handle array types\n\tif (normalized.startsWith(\"array\") || normalized.includes(\"[]\")) {\n\t\treturn StandardizedDataType.text;\n\t}\n\n\t// User-defined types (enums)\n\tif (normalized.startsWith(\"user-defined\") || normalized === \"enum\") {\n\t\treturn StandardizedDataType.enum;\n\t}\n\n\t// Default: return the original type\n\treturn StandardizedDataType.text;\n}\n","import { db } from \"../db.js\";\nimport {\n\ttype DataTypes,\n\tmapPostgresToDataType,\n\ttype StandardizedDataType,\n\tstandardizeDataTypeLabel,\n} from \"../types/column.types.js\";\n\nexport interface ColumnInfo {\n\tcolumnName: string; // The column name from the database\n\tdataType: DataTypes; // Generic type mapped to cell variant (text/boolean/number/enum/json/date)\n\tdataTypeLabel: StandardizedDataType; // Exact database type (int/varchar/timestamp/etc.)\n\tisNullable: boolean;\n\tcolumnDefault: string | null;\n\tisPrimaryKey: boolean;\n\tisForeignKey: boolean;\n\treferencedTable: string | null;\n\treferencedColumn: string | null;\n\tenumValues: string[] | null;\n}\n\nexport const getTableColumns = async (tableName: string): Promise<ColumnInfo[]> => {\n\tconst client = await db.connect();\n\ttry {\n\t\tconst res = await client.query(\n\t\t\t`\n SELECT \n c.column_name as \"columnName\",\n c.data_type as \"dataType\",\n c.udt_name as \"udtName\",\n c.is_nullable = 'YES' as \"isNullable\",\n c.column_default as \"columnDefault\",\n CASE WHEN pk.column_name IS NOT NULL THEN true ELSE false END as \"isPrimaryKey\",\n CASE WHEN fk.column_name IS NOT NULL THEN true ELSE false END as \"isForeignKey\",\n fk.referenced_table as \"referencedTable\",\n fk.referenced_column as \"referencedColumn\",\n CASE \n WHEN c.data_type = 'USER-DEFINED' THEN \n (SELECT array_agg(e.enumlabel ORDER BY e.enumsortorder)\n FROM pg_type t\n JOIN pg_enum e ON t.oid = e.enumtypid\n WHERE t.typname = c.udt_name)\n ELSE NULL\n END as \"enumValues\"\n FROM information_schema.columns c\n LEFT JOIN (\n SELECT ku.column_name\n FROM information_schema.table_constraints tc\n JOIN information_schema.key_column_usage ku\n ON tc.constraint_name = ku.constraint_name\n AND tc.table_schema = ku.table_schema\n WHERE tc.constraint_type = 'PRIMARY KEY'\n AND tc.table_schema = 'public'\n AND tc.table_name = $1\n ) pk ON c.column_name = pk.column_name\n LEFT JOIN (\n SELECT \n kcu.column_name,\n ccu.table_name AS referenced_table,\n ccu.column_name AS referenced_column\n FROM information_schema.table_constraints tc\n JOIN information_schema.key_column_usage kcu\n ON tc.constraint_name = kcu.constraint_name\n AND tc.table_schema = kcu.table_schema\n JOIN information_schema.constraint_column_usage ccu\n ON tc.constraint_name = ccu.constraint_name\n AND tc.table_schema = ccu.table_schema\n WHERE tc.constraint_type = 'FOREIGN KEY'\n AND tc.table_schema = 'public'\n AND tc.table_name = $1\n ) fk ON c.column_name = fk.column_name\n WHERE c.table_schema = 'public'\n AND c.table_name = $1\n ORDER BY c.ordinal_position;\n `,\n\t\t\t[tableName],\n\t\t);\n\n\t\treturn res.rows.map((r: any) => {\n\t\t\t// Parse enumValues to always return string[] | null\n\t\t\tlet parsedEnumValues: string[] | null = null;\n\t\t\tif (r.enumValues) {\n\t\t\t\tif (Array.isArray(r.enumValues)) {\n\t\t\t\t\t// Already an array, use as-is\n\t\t\t\t\tparsedEnumValues = r.enumValues;\n\t\t\t\t} else if (typeof r.enumValues === \"string\") {\n\t\t\t\t\t// Parse PostgreSQL array format: \"{VALUE1,VALUE2,VALUE3}\"\n\t\t\t\t\tparsedEnumValues = r.enumValues.replace(/[{}]/g, \"\").split(\",\").filter(Boolean);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tcolumnName: r.columnName,\n\t\t\t\tdataType: mapPostgresToDataType(r.dataType),\n\t\t\t\tdataTypeLabel: standardizeDataTypeLabel(r.dataType),\n\t\t\t\tisNullable: r.isNullable,\n\t\t\t\tcolumnDefault: r.columnDefault,\n\t\t\t\tisPrimaryKey: r.isPrimaryKey,\n\t\t\t\tisForeignKey: r.isForeignKey,\n\t\t\t\treferencedTable: r.referencedTable,\n\t\t\t\treferencedColumn: r.referencedColumn,\n\t\t\t\tenumValues: parsedEnumValues,\n\t\t\t};\n\t\t});\n\t} finally {\n\t\tclient.release();\n\t}\n};\n","import { db } from \"../db.js\";\n\nexport interface TableInfo {\n\ttableName: string;\n\trowCount: number;\n}\n\nexport const getTablesList = async (): Promise<TableInfo[]> => {\n\tconst client = await db.connect();\n\ttry {\n\t\tconst res = await client.query(`\n SELECT \n t.table_name as \"tableName\",\n COALESCE(s.n_live_tup, 0) as \"rowCount\" \n FROM information_schema.tables t\n LEFT JOIN pg_stat_user_tables s ON t.table_name = s.relname\n WHERE t.table_schema = 'public'\n AND t.table_type = 'BASE TABLE'\n ORDER BY t.table_name;\n `);\n\t\treturn res.rows.map((r: any) => ({\n\t\t\ttableName: r.tableName,\n\t\t\trowCount: Number(r.rowCount),\n\t\t}));\n\t} finally {\n\t\tclient.release();\n\t}\n};\n","import { db } from \"../db.js\";\n\nexport interface Filter {\n\tcolumnName: string;\n\toperator: string;\n\tvalue: string;\n}\n\nexport type SortDirection = \"asc\" | \"desc\";\n\nexport type Sort = {\n\tcolumnName: string;\n\tdirection: SortDirection;\n};\n\nexport interface TableDataResult {\n\tdata: Record<string, unknown>[];\n\tmeta: {\n\t\tpage: number;\n\t\tlimit: number;\n\t\ttotal: number;\n\t\ttotalPages: number;\n\t\thasNextPage: boolean;\n\t\thasPreviousPage: boolean;\n\t};\n}\n\nconst buildWhereClause = (filters: Filter[]): { clause: string; values: unknown[] } => {\n\tif (filters.length === 0) {\n\t\treturn { clause: \"\", values: [] };\n\t}\n\n\tconst conditions: string[] = [];\n\tconst values: unknown[] = [];\n\n\tfor (const filter of filters) {\n\t\tconst paramIndex = values.length + 1;\n\t\tconst columnName = `\"${filter.columnName}\"`;\n\n\t\tswitch (filter.operator) {\n\t\t\tcase \"=\":\n\t\t\tcase \"!=\":\n\t\t\tcase \">\":\n\t\t\tcase \">=\":\n\t\t\tcase \"<\":\n\t\t\tcase \"<=\":\n\t\t\t\tconditions.push(`${columnName} ${filter.operator} $${paramIndex}`);\n\t\t\t\tvalues.push(filter.value);\n\t\t\t\tbreak;\n\t\t\tcase \"is\":\n\t\t\t\t// Handle NULL values\n\t\t\t\tif (filter.value.toLowerCase() === \"null\") {\n\t\t\t\t\tconditions.push(`${columnName} IS NULL`);\n\t\t\t\t} else {\n\t\t\t\t\tconditions.push(`${columnName} = $${paramIndex}`);\n\t\t\t\t\tvalues.push(filter.value);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase \"is not\":\n\t\t\t\tif (filter.value.toLowerCase() === \"null\") {\n\t\t\t\t\tconditions.push(`${columnName} IS NOT NULL`);\n\t\t\t\t} else {\n\t\t\t\t\tconditions.push(`${columnName} != $${paramIndex}`);\n\t\t\t\t\tvalues.push(filter.value);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase \"like\":\n\t\t\t\tconditions.push(`${columnName}::text LIKE $${paramIndex}`);\n\t\t\t\tvalues.push(filter.value);\n\t\t\t\tbreak;\n\t\t\tcase \"not like\":\n\t\t\t\tconditions.push(`${columnName}::text NOT LIKE $${paramIndex}`);\n\t\t\t\tvalues.push(filter.value);\n\t\t\t\tbreak;\n\t\t\tcase \"ilike\":\n\t\t\t\tconditions.push(`${columnName}::text ILIKE $${paramIndex}`);\n\t\t\t\tvalues.push(filter.value);\n\t\t\t\tbreak;\n\t\t\tcase \"not ilike\":\n\t\t\t\tconditions.push(`${columnName}::text NOT ILIKE $${paramIndex}`);\n\t\t\t\tvalues.push(filter.value);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\t// Unknown operator, skip\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (conditions.length === 0) {\n\t\treturn { clause: \"\", values: [] };\n\t}\n\n\treturn { clause: `WHERE ${conditions.join(\" AND \")}`, values };\n};\n\nconst buildSortClause = (sorts: Sort[] | string, order: SortDirection): string => {\n\t// Handle array of Sort objects (new format for referenced tables)\n\tif (Array.isArray(sorts)) {\n\t\tif (sorts.length === 0) {\n\t\t\treturn \"\";\n\t\t}\n\t\tconst sortParts = sorts.map(\n\t\t\t(sort) => `\"${sort.columnName}\" ${sort.direction.toUpperCase()}`,\n\t\t);\n\t\treturn `ORDER BY ${sortParts.join(\", \")}`;\n\t}\n\n\t// Handle legacy format (string column name + order)\n\tif (sorts && typeof sorts === \"string\") {\n\t\treturn `ORDER BY \"${sorts}\" ${order?.toUpperCase() || \"ASC\"}`;\n\t}\n\n\treturn \"\";\n};\n\nexport const getTableData = async (\n\ttableName: string,\n\tpage: number = 1,\n\tpageSize: number = 50,\n\tsort: string | Sort[] = \"\",\n\torder: SortDirection = \"asc\",\n\tfilters: Filter[] = [],\n): Promise<TableDataResult> => {\n\tconst sortClause = buildSortClause(\n\t\tArray.isArray(sort) ? sort : sort,\n\t\torder as SortDirection,\n\t);\n\tconst { clause: whereClause, values: filterValues } = buildWhereClause(filters);\n\n\tconst client = await db.connect();\n\ttry {\n\t\t// Calculate offset\n\t\tconst offset = (page - 1) * pageSize;\n\n\t\t// Get total count (with filters)\n\t\tconst countRes = await client.query(\n\t\t\t`SELECT COUNT(*) as total FROM \"${tableName}\" ${whereClause}`,\n\t\t\tfilterValues,\n\t\t);\n\t\tconst totalRows = Number(countRes.rows[0].total);\n\t\tconst totalPages = Math.ceil(totalRows / pageSize);\n\n\t\t// Get paginated data (with filters)\n\t\t// Parameter indices continue after filter values\n\t\tconst limitParamIndex = filterValues.length + 1;\n\t\tconst offsetParamIndex = filterValues.length + 2;\n\n\t\tconst dataRes = await client.query(\n\t\t\t`SELECT * FROM \"${tableName}\" ${whereClause} ${sortClause} LIMIT $${limitParamIndex} OFFSET $${offsetParamIndex}`,\n\t\t\t[...filterValues, pageSize, offset],\n\t\t);\n\n\t\treturn {\n\t\t\tdata: dataRes.rows,\n\t\t\tmeta: {\n\t\t\t\tpage,\n\t\t\t\tlimit: pageSize,\n\t\t\t\ttotal: totalRows,\n\t\t\t\ttotalPages,\n\t\t\t\thasNextPage: page < totalPages,\n\t\t\t\thasPreviousPage: page > 1,\n\t\t\t},\n\t\t};\n\t} finally {\n\t\tclient.release();\n\t}\n};\n","import { db } from \"../db.js\";\n\nexport interface UpdateRecordParams {\n\ttableName: string;\n\tupdates: Array<{\n\t\trowData: Record<string, unknown>; // Original row data to identify the record\n\t\tcolumnName: string;\n\t\tvalue: unknown;\n\t}>;\n\tprimaryKey?: string; // Optional: specify primary key column (defaults to 'id')\n}\n\n/**\n * Updates multiple cells in a table. Can update multiple rows or multiple cells in the same row.\n * Groups updates by row and executes them efficiently.\n */\nexport const updateRecords = async (params: UpdateRecordParams) => {\n\tconst { tableName, updates, primaryKey = \"id\" } = params;\n\tconst client = await db.connect();\n\n\ttry {\n\t\tawait client.query(\"BEGIN\");\n\n\t\t// Group updates by row (using the primary key value)\n\t\tconst updatesByRow = new Map<\n\t\t\tunknown,\n\t\t\tArray<{ columnName: string; value: unknown; rowData: Record<string, unknown> }>\n\t\t>();\n\n\t\tfor (const update of updates) {\n\t\t\tconst pkValue = update.rowData[primaryKey];\n\t\t\tif (pkValue === undefined) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Primary key \"${primaryKey}\" not found in row data. Please ensure the row has a primary key.`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (!updatesByRow.has(pkValue)) {\n\t\t\t\tupdatesByRow.set(pkValue, []);\n\t\t\t}\n\t\t\tupdatesByRow.get(pkValue)?.push({\n\t\t\t\tcolumnName: update.columnName,\n\t\t\t\tvalue: update.value,\n\t\t\t\trowData: update.rowData,\n\t\t\t});\n\t\t}\n\n\t\tconst results = [];\n\t\tlet totalUpdated = 0;\n\n\t\t// Execute updates for each row\n\t\tfor (const [pkValue, rowUpdates] of updatesByRow.entries()) {\n\t\t\tconst setClauses = rowUpdates.map(\n\t\t\t\t(u, index) => `\"${u.columnName}\" = $${index + 1}`,\n\t\t\t);\n\t\t\tconst values = rowUpdates.map((u) => {\n\t\t\t\tconsole.log(`Value for ${u.columnName}:`, typeof u.value, u.value);\n\t\t\t\t// If the value is an object or array, stringify it for JSON/JSONB columns\n\t\t\t\tif (u.value !== null && typeof u.value === \"object\") {\n\t\t\t\t\treturn JSON.stringify(u.value);\n\t\t\t\t}\n\t\t\t\treturn u.value;\n\t\t\t});\n\n\t\t\t// Add the primary key value as the last parameter\n\t\t\tvalues.push(pkValue);\n\n\t\t\tconst updateSQL = `\n\t\t\t\tUPDATE \"${tableName}\"\n\t\t\t\tSET ${setClauses.join(\", \")}\n\t\t\t\tWHERE \"${primaryKey}\" = $${values.length}\n\t\t\t\tRETURNING *\n\t\t\t`;\n\n\t\t\tconsole.log(\"Updating record with SQL:\", updateSQL, \"Values:\", values);\n\t\t\tconst result = await client.query(updateSQL, values);\n\n\t\t\tif (result.rowCount === 0) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Record with ${primaryKey} = ${pkValue} not found in table \"${tableName}\"`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tresults.push(result.rows[0]);\n\t\t\ttotalUpdated += result.rowCount || 0;\n\t\t}\n\n\t\tawait client.query(\"COMMIT\");\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tmessage: `Successfully updated ${totalUpdated} ${totalUpdated === 1 ? \"row\" : \"rows\"} in \"${tableName}\"`,\n\t\t\tdata: results,\n\t\t\tupdatedCount: totalUpdated,\n\t\t};\n\t} catch (error) {\n\t\tawait client.query(\"ROLLBACK\");\n\t\tconsole.error(\"Error updating records:\", error);\n\t\tthrow error;\n\t} finally {\n\t\tclient.release();\n\t}\n};\n","import { z } from \"zod\";\n\nexport const FOREIGN_KEY_ACTIONS = [\n\t\"CASCADE\",\n\t\"SET NULL\",\n\t\"SET DEFAULT\",\n\t\"RESTRICT\",\n\t\"NO ACTION\",\n] as const;\nexport const foreignKeyActionSchema = z.enum(FOREIGN_KEY_ACTIONS);\nexport type ForeignKeyAction = z.infer<typeof foreignKeyActionSchema>;\n\nexport const fieldDataSchema = z.object({\n\tcolumnName: z.string().min(1),\n\tcolumnType: z.string().min(1),\n\tdefaultValue: z.string(),\n\tisPrimaryKey: z.boolean(),\n\tisNullable: z.boolean(),\n\tisUnique: z.boolean(),\n\tisIdentity: z.boolean(),\n\tisArray: z.boolean(),\n});\nexport type FieldDataType = z.infer<typeof fieldDataSchema>;\n\nexport const foreignKeyDataSchema = z.object({\n\tcolumnName: z.string().min(1),\n\treferencedTable: z.string().min(1),\n\treferencedColumn: z.string().min(1),\n\tonUpdate: foreignKeyActionSchema,\n\tonDelete: foreignKeyActionSchema,\n});\nexport type ForeignKeyDataType = z.infer<typeof foreignKeyDataSchema>;\n\nexport const createTableSchema = z.object({\n\ttableName: z.string().min(1, \"Table name is required\"),\n\tfields: z.array(fieldDataSchema).min(1, \"At least one field is required\"),\n\tforeignKeys: z.array(foreignKeyDataSchema).optional(),\n});\nexport type CreateTableFormData = z.infer<typeof createTableSchema>;\n\nexport const tableNameParamSchema = z.object({\n\ttableName: z.string().min(1, \"Table name is required\"),\n});\n\nexport const tableDataQuerySchema = z.object({\n\tpage: z.string().optional().default(\"1\").transform(Number),\n\tpageSize: z.string().optional().default(\"50\").transform(Number),\n\tsort: z.string().optional().default(\"\"),\n\torder: z.enum([\"asc\", \"desc\"]).optional(),\n\tfilters: z\n\t\t.string()\n\t\t.optional()\n\t\t.transform((val) => {\n\t\t\tif (!val) return [];\n\t\t\ttry {\n\t\t\t\treturn JSON.parse(val);\n\t\t\t} catch {\n\t\t\t\treturn [];\n\t\t\t}\n\t\t}),\n});\n\nexport const insertRecordSchema = z.object({\n\ttableName: z.string().min(1, \"Table name is required\"),\n});\n\nexport const updateRecordsSchema = z.object({\n\ttableName: z.string().min(1, \"Table name is required\"),\n\tupdates: z\n\t\t.array(\n\t\t\tz.object({\n\t\t\t\trowData: z.any(),\n\t\t\t\tcolumnName: z.string().min(1),\n\t\t\t\tvalue: z.any(),\n\t\t\t}),\n\t\t)\n\t\t.min(1, \"At least one update is required\"),\n\tprimaryKey: z.string().optional(),\n});\n\nexport const deleteRecordsSchema = z.object({\n\ttableName: z.string().min(1, \"Table name is required\"),\n\tprimaryKeys: z\n\t\t.array(\n\t\t\tz.object({\n\t\t\t\tcolumnName: z.string().min(1),\n\t\t\t\tvalue: z.any(),\n\t\t\t}),\n\t\t)\n\t\t.min(1, \"At least one primary key is required\"),\n});\n","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\";\n\nimport { createTable } from \"../dao/create-table.dao.js\";\nimport { deleteRecords, forceDeleteRecords } from \"../dao/delete-records.dao.js\";\nimport { insertRecord } from \"../dao/insert-record.dao.js\";\nimport { getTableColumns } from \"../dao/table-columns.dao.js\";\nimport { getTablesList } from \"../dao/table-list.dao.js\";\nimport { getTableData, type Sort } from \"../dao/tables-data.dao.js\";\nimport { updateRecords } from \"../dao/update-records.dao.js\";\nimport {\n\tcreateTableSchema,\n\tdeleteRecordsSchema,\n\tinsertRecordSchema,\n\ttableDataQuerySchema,\n\ttableNameParamSchema,\n\tupdateRecordsSchema,\n} from \"../types/create-table.type.js\";\n\nconst getCoreDistPath = () => {\n\tconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\treturn path.resolve(__dirname, \"./core-dist\");\n};\n\nexport const createServer = () => {\n\tconst api = new Hono().basePath(\"/\");\n\n\t// Add CORS middleware to API routes\n\tapi.use(\"/*\", cors());\n\n\tapi.use(\n\t\t\"/favicon.ico\",\n\t\tserveStatic({ path: path.resolve(getCoreDistPath(), \"favicon.ico\") }),\n\t);\n\n\tapi.use(\"*\", async (c, next) => {\n\t\tc.header(\"Access-Control-Allow-Origin\", \"*\");\n\t\tc.header(\"Access-Control-Allow-Methods\", \"GET, POST, PUT, DELETE, OPTIONS\");\n\t\tc.header(\"Access-Control-Allow-Headers\", \"Content-Type\");\n\t\tawait next();\n\t});\n\n\t/**\n\t * Serve static files from the core dist directory\n\t */\n\tapi.use(\"/*\", serveStatic({ root: getCoreDistPath() }));\n\n\t/**\n\t * Tables\n\t * GET /tables - Get all tables\n\t */\n\tapi.get(\"/tables\", async (c) => {\n\t\ttry {\n\t\t\tconst tablesList = await getTablesList();\n\t\t\tconsole.log(\"GET /tables\", tablesList);\n\t\t\treturn c.json(tablesList);\n\t\t} catch (error) {\n\t\t\tconsole.error(\"GET /tables error:\", error);\n\t\t\tconst errorMessage =\n\t\t\t\terror instanceof Error ? error.message : \"Failed to fetch tables\";\n\n\t\t\t// Check for connection errors (can be in AggregateError.errors array or directly)\n\t\t\tlet isConnectionError = false;\n\t\t\tif (error && typeof error === \"object\" && \"code\" in error) {\n\t\t\t\tisConnectionError = (error as { code?: string }).code === \"ECONNREFUSED\";\n\t\t\t} else if (\n\t\t\t\terror &&\n\t\t\t\ttypeof error === \"object\" &&\n\t\t\t\t\"errors\" in error &&\n\t\t\t\tArray.isArray((error as { errors?: unknown[] }).errors)\n\t\t\t) {\n\t\t\t\t// Handle AggregateError\n\t\t\t\tconst aggregateError = error as { errors?: Array<{ code?: string }> };\n\t\t\t\tisConnectionError =\n\t\t\t\t\taggregateError.errors?.some((err) => err.code === \"ECONNREFUSED\") ?? false;\n\t\t\t}\n\n\t\t\tif (isConnectionError) {\n\t\t\t\treturn c.json(\n\t\t\t\t\t{\n\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\t\"Cannot connect to database. Please check your DATABASE_URL and ensure the database server is running.\",\n\t\t\t\t\t\terror: errorMessage,\n\t\t\t\t\t},\n\t\t\t\t\t503,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\tmessage: errorMessage,\n\t\t\t\t},\n\t\t\t\t500,\n\t\t\t);\n\t\t}\n\t});\n\n\t/**\n\t * Columns\n\t * GET /tables/:tableName/columns - Get all columns for a table\n\t */\n\tapi.get(\n\t\t\"/tables/:tableName/columns\",\n\t\tzValidator(\"param\", tableNameParamSchema),\n\t\tasync (c) => {\n\t\t\ttry {\n\t\t\t\tconst { tableName } = c.req.valid(\"param\");\n\t\t\t\tconst columns = await getTableColumns(tableName);\n\t\t\t\tconsole.log(\"GET /tables/:tableName/columns\", columns);\n\t\t\t\treturn c.json(columns);\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(\"GET /tables/:tableName/columns error:\", error);\n\t\t\t\tconst errorMessage =\n\t\t\t\t\terror instanceof Error ? error.message : \"Failed to fetch columns\";\n\n\t\t\t\t// Check for connection errors (can be in AggregateError.errors array or directly)\n\t\t\t\tlet isConnectionError = false;\n\t\t\t\tif (error && typeof error === \"object\" && \"code\" in error) {\n\t\t\t\t\tisConnectionError = (error as { code?: string }).code === \"ECONNREFUSED\";\n\t\t\t\t} else if (\n\t\t\t\t\terror &&\n\t\t\t\t\ttypeof error === \"object\" &&\n\t\t\t\t\t\"errors\" in error &&\n\t\t\t\t\tArray.isArray((error as { errors?: unknown[] }).errors)\n\t\t\t\t) {\n\t\t\t\t\t// Handle AggregateError\n\t\t\t\t\tconst aggregateError = error as { errors?: Array<{ code?: string }> };\n\t\t\t\t\tisConnectionError =\n\t\t\t\t\t\taggregateError.errors?.some((err) => err.code === \"ECONNREFUSED\") ?? false;\n\t\t\t\t}\n\n\t\t\t\tif (isConnectionError) {\n\t\t\t\t\treturn c.json(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\t\t\"Cannot connect to database. Please check your DATABASE_URL and ensure the database server is running.\",\n\t\t\t\t\t\t\terror: errorMessage,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t503,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn c.json(\n\t\t\t\t\t{\n\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\tmessage: errorMessage,\n\t\t\t\t\t},\n\t\t\t\t\t500,\n\t\t\t\t);\n\t\t\t}\n\t\t},\n\t);\n\n\t/**\n\t * Data\n\t * GET /tables/:tableName/data - Get paginated data for a table\n\t * Query params: page (default: 1), pageSize (default: 50), sort (string or JSON array), order, filters (JSON)\n\t */\n\tapi.get(\n\t\t\"/tables/:tableName/data\",\n\t\tzValidator(\"param\", tableNameParamSchema),\n\t\tzValidator(\"query\", tableDataQuerySchema),\n\t\tasync (c) => {\n\t\t\ttry {\n\t\t\t\tconst { tableName } = c.req.valid(\"param\");\n\t\t\t\tconst { page, pageSize, sort: sortParam, order, filters } = c.req.valid(\"query\");\n\n\t\t\t\t// Parse sort - can be either a string (legacy) or JSON array (new format)\n\t\t\t\tlet sort: Sort[] | string = \"\";\n\t\t\t\tif (sortParam) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// Try to parse as JSON first (new format)\n\t\t\t\t\t\tconst parsed = JSON.parse(sortParam);\n\t\t\t\t\t\tif (Array.isArray(parsed)) {\n\t\t\t\t\t\t\tsort = parsed;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tsort = sortParam;\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// If JSON parse fails, use as string (legacy format)\n\t\t\t\t\t\tsort = sortParam;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst data = await getTableData(tableName, page, pageSize, sort, order, filters);\n\t\t\t\treturn c.json(data);\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(\"GET /tables/:tableName/data error:\", error);\n\t\t\t\tconst errorMessage =\n\t\t\t\t\terror instanceof Error ? error.message : \"Failed to fetch table data\";\n\n\t\t\t\t// Check for connection errors (can be in AggregateError.errors array or directly)\n\t\t\t\tlet isConnectionError = false;\n\t\t\t\tif (error && typeof error === \"object\" && \"code\" in error) {\n\t\t\t\t\tisConnectionError = (error as { code?: string }).code === \"ECONNREFUSED\";\n\t\t\t\t} else if (\n\t\t\t\t\terror &&\n\t\t\t\t\ttypeof error === \"object\" &&\n\t\t\t\t\t\"errors\" in error &&\n\t\t\t\t\tArray.isArray((error as { errors?: unknown[] }).errors)\n\t\t\t\t) {\n\t\t\t\t\t// Handle AggregateError\n\t\t\t\t\tconst aggregateError = error as { errors?: Array<{ code?: string }> };\n\t\t\t\t\tisConnectionError =\n\t\t\t\t\t\taggregateError.errors?.some((err) => err.code === \"ECONNREFUSED\") ?? false;\n\t\t\t\t}\n\n\t\t\t\tif (isConnectionError) {\n\t\t\t\t\treturn c.json(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\t\t\"Cannot connect to database. Please check your DATABASE_URL and ensure the database server is running.\",\n\t\t\t\t\t\t\terror: errorMessage,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t503,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn c.json(\n\t\t\t\t\t{\n\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\tmessage: errorMessage,\n\t\t\t\t\t},\n\t\t\t\t\t500,\n\t\t\t\t);\n\t\t\t}\n\t\t},\n\t);\n\n\t/**\n\t * Create Table\n\t * POST /tables - Create a new table\n\t */\n\tapi.post(\"/tables\", zValidator(\"json\", createTableSchema), async (c) => {\n\t\ttry {\n\t\t\tconst body = c.req.valid(\"json\");\n\t\t\tconsole.log(\"POST /tables body\", body);\n\t\t\tconst data = await createTable(body);\n\t\t\tconsole.log(\"POST /tables\", data);\n\t\t\treturn c.json(data);\n\t\t} catch (error) {\n\t\t\tconsole.error(\"POST /tables error:\", error);\n\t\t\tconst errorDetail =\n\t\t\t\terror && typeof error === \"object\" && \"detail\" in error\n\t\t\t\t\t? (error as { detail?: string }).detail\n\t\t\t\t\t: undefined;\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\tmessage: error instanceof Error ? error.message : \"Failed to create table\",\n\t\t\t\t\tdetail: errorDetail,\n\t\t\t\t},\n\t\t\t\t500,\n\t\t\t);\n\t\t}\n\t});\n\n\t/**\n\t * Create Record\n\t * POST /records - Insert a new record into a table\n\t * Body: { tableName: string, ...recordData }\n\t */\n\tapi.post(\"/records\", zValidator(\"json\", insertRecordSchema), async (c) => {\n\t\ttry {\n\t\t\tconst body = c.req.valid(\"json\");\n\t\t\tconst { tableName, ...recordData } = body;\n\n\t\t\tconsole.log(\"POST /records body\", { tableName, recordData });\n\t\t\tconst result = await insertRecord({ tableName, data: recordData });\n\t\t\tconsole.log(\"POST /records\", result);\n\t\t\treturn c.json(result);\n\t\t} catch (error) {\n\t\t\tconsole.error(\"POST /records error:\", error);\n\t\t\tconst errorDetail =\n\t\t\t\terror && typeof error === \"object\" && \"detail\" in error\n\t\t\t\t\t? (error as { detail?: string }).detail\n\t\t\t\t\t: undefined;\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\tmessage: error instanceof Error ? error.message : \"Failed to create record\",\n\t\t\t\t\tdetail: errorDetail,\n\t\t\t\t},\n\t\t\t\t500,\n\t\t\t);\n\t\t}\n\t});\n\n\t/**\n\t * Update Records\n\t * PATCH /records - Update one or more cells in a table\n\t * Body: {\n\t * tableName: string,\n\t * updates: Array<{ rowData: Record<string, unknown>, columnName: string, value: unknown }>,\n\t * primaryKey?: string (optional, defaults to 'id')\n\t * }\n\t */\n\tapi.patch(\"/records\", zValidator(\"json\", updateRecordsSchema), async (c) => {\n\t\ttry {\n\t\t\tconst body = c.req.valid(\"json\");\n\t\t\tconst { tableName, updates, primaryKey } = body;\n\n\t\t\tconsole.log(\"PATCH /records body\", { tableName, updates, primaryKey });\n\t\t\tconst result = await updateRecords({ tableName, updates, primaryKey });\n\t\t\tconsole.log(\"PATCH /records\", result);\n\t\t\treturn c.json(result);\n\t\t} catch (error) {\n\t\t\tconsole.error(\"PATCH /records error:\", error);\n\t\t\tconst errorDetail =\n\t\t\t\terror && typeof error === \"object\" && \"detail\" in error\n\t\t\t\t\t? (error as { detail?: string }).detail\n\t\t\t\t\t: undefined;\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\tmessage: error instanceof Error ? error.message : \"Failed to update records\",\n\t\t\t\t\tdetail: errorDetail,\n\t\t\t\t},\n\t\t\t\t500,\n\t\t\t);\n\t\t}\n\t});\n\n\t/**\n\t * Delete Records\n\t * DELETE /records - Delete records from a table\n\t * Body: {\n\t * tableName: string,\n\t * primaryKeys: Array<{ columnName: string, value: unknown }>,\n\t * }\n\t * Returns:\n\t * - success: true if deleted\n\t * - fkViolation: true if FK constraint prevents deletion, includes relatedRecords\n\t */\n\tapi.delete(\"/records\", zValidator(\"json\", deleteRecordsSchema), async (c) => {\n\t\ttry {\n\t\t\tconst body = c.req.valid(\"json\");\n\t\t\tconst { tableName, primaryKeys } = body;\n\n\t\t\tconsole.log(\"DELETE /records body\", { tableName, primaryKeys });\n\t\t\tconst result = await deleteRecords({ tableName, primaryKeys });\n\t\t\tconsole.log(\"DELETE /records result\", result);\n\n\t\t\t// Return 409 Conflict for FK violations\n\t\t\tif (result.fkViolation) {\n\t\t\t\treturn c.json(result, 409);\n\t\t\t}\n\n\t\t\treturn c.json(result);\n\t\t} catch (error) {\n\t\t\tconsole.error(\"DELETE /records error:\", error);\n\t\t\tconst errorDetail =\n\t\t\t\terror && typeof error === \"object\" && \"detail\" in error\n\t\t\t\t\t? (error as { detail?: string }).detail\n\t\t\t\t\t: undefined;\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\tmessage: error instanceof Error ? error.message : \"Failed to delete records\",\n\t\t\t\t\tdetail: errorDetail,\n\t\t\t\t},\n\t\t\t\t500,\n\t\t\t);\n\t\t}\n\t});\n\n\t/**\n\t * Force Delete Records (Cascade)\n\t * DELETE /records/force - Force delete records and all related FK records\n\t * Body: {\n\t * tableName: string,\n\t * primaryKeys: Array<{ columnName: string, value: unknown }>,\n\t * }\n\t */\n\tapi.delete(\"/records/force\", zValidator(\"json\", deleteRecordsSchema), async (c) => {\n\t\ttry {\n\t\t\tconst body = c.req.valid(\"json\");\n\t\t\tconst { tableName, primaryKeys } = body;\n\n\t\t\tconsole.log(\"DELETE /records/force body\", { tableName, primaryKeys });\n\t\t\tconst result = await forceDeleteRecords({ tableName, primaryKeys });\n\t\t\tconsole.log(\"DELETE /records/force result\", result);\n\n\t\t\treturn c.json(result);\n\t\t} catch (error) {\n\t\t\tconsole.error(\"DELETE /records/force error:\", error);\n\t\t\tconst errorDetail =\n\t\t\t\terror && typeof error === \"object\" && \"detail\" in error\n\t\t\t\t\t? (error as { detail?: string }).detail\n\t\t\t\t\t: undefined;\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\tmessage:\n\t\t\t\t\t\terror instanceof Error ? error.message : \"Failed to force delete records\",\n\t\t\t\t\tdetail: errorDetail,\n\t\t\t\t},\n\t\t\t\t500,\n\t\t\t);\n\t\t}\n\t});\n\n\treturn api;\n};\n","import { intro, outro } from \"@clack/prompts\";\nimport { serve } from \"@hono/node-server\";\nimport color from \"picocolors\";\n\nimport { args } from \"./cmd/args.js\";\nimport { getDatabaseUrl } from \"./cmd/get-db-url.js\";\nimport { loadEnv } from \"./cmd/load-env.js\";\nimport { showHelp } from \"./cmd/show-help.js\";\nimport { showStatus } from \"./cmd/show-status.js\";\nimport { showVersion } from \"./cmd/show-version.js\";\nimport { DEFAULTS } from \"./utils/defaults.js\";\n\nexport const main = async () => {\n\tconst { env, port, databaseUrl, varName, status, help, version } = args();\n\n\t// Handle help flag\n\tif (help) {\n\t\tshowHelp();\n\t\tprocess.exit(0);\n\t}\n\n\t// Handle version flag\n\tif (version) {\n\t\tshowVersion();\n\t\tprocess.exit(0);\n\t}\n\n\t// Handle status flag\n\tif (status) {\n\t\tawait showStatus(env, databaseUrl, varName);\n\t\tprocess.exit(0);\n\t}\n\n\tintro(color.inverse(\" db-studiox \"));\n\n\tconst PORT = port ? parseInt(port, 10) : DEFAULTS.PORT;\n\tconst VAR_NAME = varName || DEFAULTS.VAR_NAME;\n\tconst ENV = env ? await loadEnv(env) : await loadEnv(DEFAULTS.ENV);\n\tconst DATABASE_URL = databaseUrl ? databaseUrl : await getDatabaseUrl(ENV, VAR_NAME);\n\n\t// Set DATABASE_URL in process.env before importing createServer\n\t// This ensures the db pool is initialized with the correct connection string\n\tprocess.env.DATABASE_URL = DATABASE_URL;\n\n\t// Import createServer dynamically after setting DATABASE_URL\n\tconst { createServer } = await import(\"./utils/create-server.js\");\n\tconst server = createServer();\n\tserve({\n\t\tfetch: server.fetch,\n\t\tport: PORT,\n\t});\n\n\toutro(color.green(`Server running at ${color.cyan(`http://localhost:${PORT}`)}`));\n};\n\nmain().catch((err) => {\n\tconsole.error(color.red(`❌ Unexpected error: ${err.message}`));\n\tprocess.exit(1);\n});\n","import { program } from \"commander\";\n\ntype Args = {\n\tenv?: string;\n\tport?: string;\n\tdatabaseUrl?: string;\n\tvarName?: string;\n\tstatus?: boolean;\n\thelp?: boolean;\n\tversion?: boolean;\n};\n\n/**\n * Get the arguments from the command line\n */\nexport const args = () => {\n\tprogram\n\t\t.name(\"db-studio\")\n\t\t.option(\"-e, --env <path>\", \"Path to custom .env file\")\n\t\t.option(\"-p, --port <port>\", \"Port to run the server on\")\n\t\t.option(\"-d, --database-url <url>\", \"Database URL to use\")\n\t\t.option(\n\t\t\t\"-n, --var-name <name>\",\n\t\t\t\"Custom environment variable name (default: DATABASE_URL)\",\n\t\t)\n\t\t.option(\"-s, --status\", \"Show status of the server\")\n\t\t.option(\"-h, --help\", \"Show help\")\n\t\t.option(\"-v, --version\", \"Show version\")\n\t\t.parse(process.argv);\n\n\treturn program.opts<Args>();\n};\n","import { readFile } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport { cancel, isCancel, note, select, spinner, text } from \"@clack/prompts\";\nimport { type DotenvParseOutput, parse as parseDotenv } from \"dotenv\";\nimport color from \"picocolors\";\n\n/**\n * Get the database URL from the environment variables\n */\nexport const getDatabaseUrl = async (\n\tenv?: DotenvParseOutput | null,\n\tvarName?: string,\n) => {\n\tconst envVarName = varName || \"DATABASE_URL\";\n\n\tif (env?.[envVarName]) {\n\t\treturn env[envVarName];\n\t}\n\n\tconst s = spinner();\n\ts.start(\"Looking for database connection...\");\n\n\tif (!env) {\n\t\tnote(color.red(\"No .env file found in current directory\"));\n\t} else {\n\t\tnote(color.red(`${envVarName} not found in .env`));\n\t}\n\n\tconst choice = await select({\n\t\tmessage: `How do you want to provide ${envVarName}?`,\n\t\toptions: [\n\t\t\t{ value: \"manual\", label: \"Enter connection string manually\" },\n\t\t\t{ value: \"other-env\", label: \"Use different .env file\" },\n\t\t\t{ 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: any) {\n\t\t\tcancel(`Cannot read or parse file: ${color.dim(e.message)}`);\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\n\t// 3. Manual input\n\ts.stop(\"Manual input...\");\n\n\tconst dbUrl = await text({\n\t\tmessage: `Paste your ${envVarName}`,\n\t\tplaceholder: \"postgresql://user:password@localhost:5432/mydb\",\n\t\tvalidate(value: string) {\n\t\t\tif (!value.trim()) return \"Connection string is required!\";\n\t\t\ttry {\n\t\t\t\tnew URL(value); // very basic check\n\t\t\t\treturn undefined;\n\t\t\t} catch {\n\t\t\t\treturn \"Must be a valid URL format\";\n\t\t\t}\n\t\t},\n\t});\n\n\tif (isCancel(dbUrl)) {\n\t\tcancel(\"Cancelled.\");\n\t\tprocess.exit(0);\n\t}\n\n\treturn dbUrl.trim();\n};\n","import { access, readFile } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport { parse as parseDotenv } from \"dotenv\";\n\n/**\n * Load the environment variables from the file\n */\nexport const loadEnv = async (env?: string) => {\n\tconst envPath = env ? resolve(env) : resolve(process.cwd(), \".env\");\n\n\ttry {\n\t\tawait access(envPath);\n\t\tconst content = await readFile(envPath, \"utf-8\");\n\t\treturn parseDotenv(content);\n\t} catch (err) {\n\t\tif (err instanceof Error && err.message.includes(\"ENOENT\")) {\n\t\t\treturn null; // we'll handle missing file later\n\t\t}\n\t\tthrow err;\n\t}\n};\n","import { intro, outro } from \"@clack/prompts\";\nimport color from \"picocolors\";\n\n/**\n * Display help information\n */\nexport const showHelp = () => {\n\tintro(color.inverse(\" db-studio \"));\n\n\tconsole.log(color.bold(\"\\nUsage:\"));\n\tconsole.log(\" db-studio [options]\\n\");\n\n\tconsole.log(color.bold(\"Options:\"));\n\tconsole.log(\" -e, --env <path> Path to custom .env file\");\n\tconsole.log(\" -p, --port <port> Port to run the server on (default: 3333)\");\n\tconsole.log(\" -d, --database-url <url> Database URL to use\");\n\tconsole.log(\n\t\t\" -n, --var-name <name> Custom environment variable name (default: DATABASE_URL)\",\n\t);\n\tconsole.log(\" -s, --status Show status of the database connection\");\n\tconsole.log(\" -h, --help Show this help message\");\n\tconsole.log(\" -v, --version Show version number\\n\");\n\n\tconsole.log(color.bold(\"Examples:\"));\n\tconsole.log(\" db-studio\");\n\tconsole.log(\" db-studio -e .env.local\");\n\tconsole.log(\" db-studio -p 4000\");\n\tconsole.log(\" db-studio -d postgresql://user:pass@localhost:5432/mydb\");\n\tconsole.log(\" db-studio -n MY_DATABASE_URL\");\n\tconsole.log(\" db-studio -e .env.production -n PROD_DB_URL\");\n\tconsole.log(\" db-studio --status\\n\");\n\n\toutro(\n\t\tcolor.green(\"For more information, visit: https://github.com/your-repo/db-studio\"),\n\t);\n};\n","import { intro, note, outro } from \"@clack/prompts\";\nimport color from \"picocolors\";\nimport { DEFAULTS } from \"../utils/defaults.js\";\nimport { loadEnv } from \"./load-env.js\";\n\n/**\n * Show connection status\n */\nexport const showStatus = async (\n\tenv?: string,\n\tdatabaseUrl?: string,\n\tvarName?: string,\n) => {\n\tintro(color.inverse(\" db-studio \"));\n\n\tconst envVarName = varName || DEFAULTS.VAR_NAME;\n\tlet foundUrl: string | null = null;\n\n\t// Check if DATABASE_URL is provided via CLI\n\tif (databaseUrl) {\n\t\tfoundUrl = databaseUrl;\n\t} else {\n\t\t// Try to load from .env file\n\t\tconst ENV = env ? await loadEnv(env) : await loadEnv(DEFAULTS.ENV);\n\t\tif (ENV?.[envVarName]) {\n\t\t\tfoundUrl = ENV[envVarName];\n\t\t}\n\t}\n\n\tif (foundUrl) {\n\t\toutro(color.green(`✓ Database connection configured (using ${envVarName})`));\n\t} else {\n\t\tnote(color.red(`✗ ${envVarName} not found`), \"Status\");\n\t\tconsole.log(color.yellow(\"\\n To configure database connection:\"));\n\t\tconsole.log(color.dim(` • Add ${envVarName} to your .env file`));\n\t\tconsole.log(color.dim(\" • Use -d flag: db-studio -d <url>\"));\n\t\tconsole.log(color.dim(\" • Use -e flag: db-studio -e <path-to-env>\"));\n\t\tconsole.log(color.dim(\" • Use -n flag: db-studio -n <var-name>\\n\"));\n\n\t\toutro(color.yellow(\"⚠ No database connection configured\"));\n\t}\n};\n","export const DEFAULTS = {\n\tPORT: 3333,\n\tENV: \".env\",\n\tVAR_NAME: \"DATABASE_URL\",\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 \"workspaces\": [\n \"packages/*\",\n \"www\"\n ],\n \"scripts\": {\n \"dev\": \"concurrently \\\"bun run dev:core\\\" \\\"bun run dev:cli\\\" \\\"bun run dev:server\\\"\",\n \"dev:core\": \"bun run --cwd packages/core dev\",\n \"dev:server\": \"bun run --cwd packages/server dev\",\n \"dev:www\": \"bun run --cwd www dev\",\n \"build\": \"concurrently \\\"bun run build:core\\\" \\\"bun run build:server\\\" \\\"bun run build:www\\\"\",\n \"build:core\": \"bun run --cwd packages/core build\",\n \"build:server\": \"bun run --cwd packages/server build\",\n \"build:release\": \"bun run build:core && bun run --cwd packages/server build:release\",\n \"build:www\": \"bun run --cwd www build\",\n \"deploy:www\": \"bun run --cwd www deploy\",\n \"deploy:www:preview\": \"bun run --cwd www deploy:preview\",\n \"check\": \"bun run --cwd packages/core check && bun run --cwd packages/server check && bun run --cwd www check\",\n \"check:meta\": \"bun run --cwd www check-meta\",\n \"changeset\": \"changeset\",\n \"version\": \"changeset version\",\n \"release\": \"bun run build:release && npm publish --workspace=packages/server\"\n },\n \"devDependencies\": {\n \"@biomejs/biome\": \"^2.2.6\"\n },\n \"peerDependencies\": {\n \"typescript\": \"^5\"\n },\n \"overrides\": {\n \"esbuild\": \"0.25.12\"\n },\n \"engines\": {\n \"node\": \">=20.x\",\n \"bun\": \">=1.2.19\"\n },\n \"packageManager\": \"bun@1.2.19\",\n \"dependencies\": {\n \"@faker-js/faker\": \"^10.1.0\",\n \"@tanstack/react-table\": \"^8.21.3\",\n \"@tanstack/react-virtual\": \"^3.13.13\"\n }\n}"],"mappings":"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","names":["Pool","dbInstance","getPool","db","init_db","__esmMin","_target","prop","createTable","init_create_table_dao","__esmMin","init_db","tableData","client","db","tableName","fields","foreignKeys","columnDefinitions","field","columnDef","foreignKeyConstraints","fk","allDefinitions","createTableSQL","error","getForeignKeyReferences","getRelatedRecords","deleteRecords","forceDeleteRecords","init_delete_records_dao","__esmMin","init_db","tableName","db","row","primaryKeys","fkConstraints","relatedRecords","constraintsByTable","constraint","key","pkValues","pk","_tableColumn","constraints","placeholders","_","i","query","result","error","params","client","pkColumn","deleteSQL","totalRelatedDeleted","deletedTables","deleteRelatedRecursively","targetTable","targetColumn","values","nestedFks","nestedFk","selectQuery","nestedValues","deleteQuery","deleteResult","mainDeleted","insertRecord","init_insert_record_dao","__esmMin","init_db","params","tableName","data","client","db","columns","values","placeholders","_","index","columnNames","col","insertSQL","result","error","mapPostgresToDataType","pgType","normalized","DataTypes","standardizeDataTypeLabel","StandardizedDataType","init_column_types","__esmMin","getTableColumns","init_table_columns_dao","__esmMin","init_db","init_column_types","tableName","client","db","parsedEnumValues","mapPostgresToDataType","standardizeDataTypeLabel","getTablesList","init_table_list_dao","__esmMin","init_db","client","db","r","buildWhereClause","buildSortClause","getTableData","init_tables_data_dao","__esmMin","init_db","filters","conditions","values","filter","paramIndex","columnName","sorts","order","sort","tableName","page","pageSize","sortClause","whereClause","filterValues","client","db","offset","countRes","totalRows","totalPages","limitParamIndex","offsetParamIndex","updateRecords","init_update_records_dao","__esmMin","init_db","params","tableName","updates","primaryKey","client","db","updatesByRow","update","pkValue","results","totalUpdated","rowUpdates","setClauses","u","index","values","updateSQL","result","error","z","FOREIGN_KEY_ACTIONS","foreignKeyActionSchema","fieldDataSchema","foreignKeyDataSchema","createTableSchema","tableNameParamSchema","tableDataQuerySchema","insertRecordSchema","updateRecordsSchema","deleteRecordsSchema","init_create_table_type","__esmMin","val","create_server_exports","__export","createServer","path","fileURLToPath","serveStatic","zValidator","Hono","cors","getCoreDistPath","init_create_server","__esmMin","init_create_table_dao","init_delete_records_dao","init_insert_record_dao","init_table_columns_dao","init_table_list_dao","init_tables_data_dao","init_update_records_dao","init_create_table_type","__dirname","api","c","next","tablesList","getTablesList","error","errorMessage","isConnectionError","err","tableNameParamSchema","tableName","columns","getTableColumns","tableDataQuerySchema","page","pageSize","sortParam","order","filters","sort","parsed","data","getTableData","createTableSchema","body","createTable","errorDetail","insertRecordSchema","recordData","result","insertRecord","updateRecordsSchema","updates","primaryKey","updateRecords","deleteRecordsSchema","primaryKeys","deleteRecords","forceDeleteRecords","intro","outro","serve","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","dbUrl","access","readFile","resolve","parseDotenv","loadEnv","env","envPath","content","err","intro","outro","color","showHelp","intro","note","outro","color","DEFAULTS","showStatus","env","databaseUrl","varName","intro","color","envVarName","DEFAULTS","foundUrl","ENV","loadEnv","outro","note","intro","outro","color","package_default","showVersion","intro","color","outro","package_default","main","env","port","databaseUrl","varName","status","help","version","args","showHelp","showVersion","showStatus","intro","color","PORT","DEFAULTS","VAR_NAME","ENV","loadEnv","DATABASE_URL","getDatabaseUrl","createServer","server","serve","outro","err"]}
|
|
1
|
+
{"version":3,"sources":["../src/db.ts","../src/dao/create-table.dao.ts","../src/dao/delete-records.dao.ts","../src/dao/insert-record.dao.ts","../src/types/column.types.ts","../src/dao/table-columns.dao.ts","../src/dao/table-list.dao.ts","../src/dao/tables-data.dao.ts","../src/dao/update-records.dao.ts","../src/types/create-table.type.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/utils/defaults.ts","../src/cmd/show-version.ts","../package.json"],"sourcesContent":["import { Pool } from \"pg\";\n\nlet dbInstance: Pool | null = null;\n\nconst getPool = (): Pool => {\n\tif (!dbInstance) {\n\t\tif (!process.env.DATABASE_URL) {\n\t\t\tthrow new Error(\n\t\t\t\t\"DATABASE_URL is not set. Please provide a database connection string.\",\n\t\t\t);\n\t\t}\n\t\tdbInstance = new Pool({\n\t\t\tconnectionString: process.env.DATABASE_URL,\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\treturn getPool()[prop as keyof Pool];\n\t},\n});\n","import { db } from \"../db.js\";\nimport type { FieldDataType } from \"../types/create-table.type.js\";\nimport type { CreateTableFormData } from \"../types/index.js\";\n\nexport const createTable = async (tableData: CreateTableFormData) => {\n\tconst client = await db.connect();\n\ttry {\n\t\tconst { tableName, fields, foreignKeys } = tableData;\n\n\t\t// Build column definitions\n\t\tconst columnDefinitions = fields.map((field: FieldDataType) => {\n\t\t\tlet columnDef = `\"${field.columnName}\" ${field.columnType}`;\n\n\t\t\t// Add array suffix if needed\n\t\t\tif (field.isArray) {\n\t\t\t\tcolumnDef += \"[]\";\n\t\t\t}\n\n\t\t\t// Add PRIMARY KEY constraint\n\t\t\tif (field.isPrimaryKey) {\n\t\t\t\tcolumnDef += \" PRIMARY KEY\";\n\t\t\t}\n\n\t\t\t// Add UNIQUE constraint\n\t\t\tif (field.isUnique && !field.isPrimaryKey) {\n\t\t\t\tcolumnDef += \" UNIQUE\";\n\t\t\t}\n\n\t\t\t// Add NOT NULL constraint (if not nullable)\n\t\t\tif (!field.isNullable) {\n\t\t\t\tcolumnDef += \" NOT NULL\";\n\t\t\t}\n\n\t\t\t// Add GENERATED ALWAYS AS IDENTITY for identity columns\n\t\t\tif (field.isIdentity) {\n\t\t\t\tcolumnDef += \" GENERATED ALWAYS AS IDENTITY\";\n\t\t\t}\n\n\t\t\t// Add default value\n\t\t\tif (field.defaultValue && !field.isIdentity) {\n\t\t\t\tcolumnDef += ` DEFAULT ${field.defaultValue}`;\n\t\t\t}\n\n\t\t\treturn columnDef;\n\t\t});\n\n\t\t// Build foreign key constraints\n\t\tconst foreignKeyConstraints =\n\t\t\tforeignKeys?.map((fk) => {\n\t\t\t\tconst constraintName = `fk_${tableName}_${fk.columnName}_${fk.referencedTable}_${fk.referencedColumn}`;\n\t\t\t\treturn `CONSTRAINT \"${constraintName}\" FOREIGN KEY (\"${fk.columnName}\") REFERENCES \"${fk.referencedTable}\" (\"${fk.referencedColumn}\") ON UPDATE ${fk.onUpdate} ON DELETE ${fk.onDelete}`;\n\t\t\t}) || [];\n\n\t\t// Combine column definitions and foreign key constraints\n\t\tconst allDefinitions = [...columnDefinitions, ...foreignKeyConstraints];\n\n\t\t// Create the table\n\t\tconst createTableSQL = `\n\t\t\tCREATE TABLE \"${tableName}\" (\n\t\t\t\t${allDefinitions.join(\",\\n\\t\\t\\t\\t\")}\n\t\t\t);\n\t\t`;\n\n\t\tconsole.log(\"Creating table with SQL:\", createTableSQL);\n\t\tawait client.query(createTableSQL);\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\ttableName,\n\t\t\tmessage: `Table \"${tableName}\" created successfully`,\n\t\t};\n\t} catch (error) {\n\t\tconsole.error(\"Error creating table:\", error);\n\t\tthrow error;\n\t} finally {\n\t\tclient.release();\n\t}\n};\n","import { db } from \"../db.js\";\n\nexport interface DeleteRecordParams {\n\ttableName: string;\n\tprimaryKeys: Array<{ columnName: string; value: unknown }>;\n}\n\nexport interface ForeignKeyConstraint {\n\tconstraintName: string;\n\treferencingTable: string;\n\treferencingColumn: string;\n\treferencedTable: string;\n\treferencedColumn: string;\n}\n\nexport interface ForeignKeyConstraintRow {\n\tconstraint_name: string;\n\treferencing_table: string;\n\treferencing_column: string;\n\treferenced_table: string;\n\treferenced_column: string;\n}\n\nexport interface RelatedRecord {\n\ttableName: string;\n\tcolumnName: string;\n\tconstraintName: string;\n\trecords: Array<Record<string, unknown>>;\n}\n\nexport interface DeleteResult {\n\tsuccess: boolean;\n\tmessage: string;\n\tdeletedCount?: number;\n\tfkViolation?: boolean;\n\trelatedRecords?: RelatedRecord[];\n}\n\n/**\n * Gets foreign key constraints that reference the given table\n */\nexport const getForeignKeyReferences = async (\n\ttableName: string,\n): 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 result = await db.query(query, [tableName]);\n\n\treturn result.rows.map(({ row }: { row: ForeignKeyConstraintRow }) => ({\n\t\tconstraintName: row.constraint_name,\n\t\treferencingTable: row.referencing_table,\n\t\treferencingColumn: row.referencing_column,\n\t\treferencedTable: row.referenced_table,\n\t\treferencedColumn: row.referenced_column,\n\t}));\n};\n\n/**\n * Finds all records in other tables that reference the given primary key values\n */\nexport const getRelatedRecords = async (\n\ttableName: string,\n\tprimaryKeys: Array<{ columnName: string; value: unknown }>,\n): Promise<RelatedRecord[]> => {\n\tconst fkConstraints = await getForeignKeyReferences(tableName);\n\n\tif (fkConstraints.length === 0) {\n\t\treturn [];\n\t}\n\n\tconst relatedRecords: RelatedRecord[] = [];\n\n\t// Group constraints by referencing table and column for efficiency\n\tconst constraintsByTable = new Map<string, ForeignKeyConstraint[]>();\n\tfor (const constraint of fkConstraints) {\n\t\tconst key = `${constraint.referencingTable}.${constraint.referencingColumn}`;\n\t\tif (!constraintsByTable.has(key)) {\n\t\t\tconstraintsByTable.set(key, []);\n\t\t}\n\t\tconstraintsByTable.get(key)?.push(constraint);\n\t}\n\n\t// Get the primary key values that we're looking for\n\tconst pkValues = primaryKeys.map((pk) => pk.value);\n\n\tfor (const [_tableColumn, constraints] of constraintsByTable) {\n\t\tconst constraint = constraints[0];\n\t\tif (!constraint) continue;\n\n\t\t// Find which primary key column matches this FK's referenced column\n\t\tconst matchingPk = primaryKeys.find(\n\t\t\t(pk) => pk.columnName === constraint.referencedColumn,\n\t\t);\n\t\tif (!matchingPk) continue;\n\n\t\t// Build query to find related records\n\t\tconst placeholders = pkValues.map((_, i) => `$${i + 1}`).join(\", \");\n\t\tconst query = `\n\t\t\tSELECT * FROM \"${constraint.referencingTable}\"\n\t\t\tWHERE \"${constraint.referencingColumn}\" IN (${placeholders})\n\t\t\tLIMIT 100\n\t\t`;\n\n\t\ttry {\n\t\t\tconst result = await db.query(query, pkValues);\n\n\t\t\tif (result.rows.length > 0) {\n\t\t\t\trelatedRecords.push({\n\t\t\t\t\ttableName: constraint.referencingTable,\n\t\t\t\t\tcolumnName: constraint.referencingColumn,\n\t\t\t\t\tconstraintName: constraint.constraintName,\n\t\t\t\t\trecords: result.rows,\n\t\t\t\t});\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconsole.error(\n\t\t\t\t`Error fetching related records from ${constraint.referencingTable}:`,\n\t\t\t\terror,\n\t\t\t);\n\t\t}\n\t}\n\n\treturn relatedRecords;\n};\n\n/**\n * Attempts to delete records. If FK violation occurs, returns related records.\n */\nexport const deleteRecords = async (\n\tparams: DeleteRecordParams,\n): Promise<DeleteResult> => {\n\tconst { tableName, primaryKeys } = params;\n\tconst client = await db.connect();\n\n\ttry {\n\t\tawait client.query(\"BEGIN\");\n\n\t\t// Build the delete query\n\t\tconst pkColumn = primaryKeys[0]?.columnName;\n\t\tif (!pkColumn) {\n\t\t\tthrow new Error(\"Primary key column name is required\");\n\t\t}\n\n\t\tconst pkValues = primaryKeys.map((pk) => pk.value);\n\t\tconst placeholders = pkValues.map((_, i) => `$${i + 1}`).join(\", \");\n\n\t\tconst deleteSQL = `\n\t\t\tDELETE FROM \"${tableName}\"\n\t\t\tWHERE \"${pkColumn}\" IN (${placeholders})\n\t\t\tRETURNING *\n\t\t`;\n\n\t\tconsole.log(\"Deleting records with SQL:\", deleteSQL, \"Values:\", pkValues);\n\t\tconst result = await client.query(deleteSQL, pkValues);\n\n\t\tawait client.query(\"COMMIT\");\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tmessage: `Successfully deleted ${result.rowCount} ${result.rowCount === 1 ? \"record\" : \"records\"} from \"${tableName}\"`,\n\t\t\tdeletedCount: result.rowCount ?? 0,\n\t\t};\n\t} catch (error) {\n\t\tawait client.query(\"ROLLBACK\");\n\n\t\t// Check if this is a foreign key violation\n\t\tconst pgError = error as { code?: string; detail?: string; constraint?: string };\n\n\t\tif (pgError.code === \"23503\") {\n\t\t\t// Foreign key violation\n\t\t\tconsole.log(\"FK violation detected, fetching related records...\");\n\n\t\t\t// Fetch related records to show the user\n\t\t\tconst relatedRecords = await getRelatedRecords(tableName, primaryKeys);\n\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\tmessage: \"Cannot delete: Records are referenced by other tables\",\n\t\t\t\tfkViolation: true,\n\t\t\t\trelatedRecords,\n\t\t\t};\n\t\t}\n\n\t\tconsole.error(\"Error deleting records:\", error);\n\t\tthrow error;\n\t} finally {\n\t\tclient.release();\n\t}\n};\n\n/**\n * Force deletes records by first deleting all related records in referencing tables (cascade)\n */\nexport const forceDeleteRecords = async (\n\tparams: DeleteRecordParams,\n): Promise<DeleteResult> => {\n\tconst { tableName, primaryKeys } = params;\n\tconst client = await db.connect();\n\n\ttry {\n\t\tawait client.query(\"BEGIN\");\n\n\t\tconst pkColumn = primaryKeys[0]?.columnName;\n\t\tif (!pkColumn) {\n\t\t\tthrow new Error(\"Primary key column name is required\");\n\t\t}\n\n\t\tconst pkValues = primaryKeys.map((pk) => pk.value);\n\n\t\t// Get all FK constraints that reference this table\n\t\tconst fkConstraints = await getForeignKeyReferences(tableName);\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);\n\n\t\t\tfor (const nestedFk of nestedFks) {\n\t\t\t\t// Get the values that will be deleted from the target table\n\t\t\t\tconst placeholders = values.map((_, i) => `$${i + 1}`).join(\", \");\n\t\t\t\tconst selectQuery = `\n\t\t\t\t\tSELECT \"${nestedFk.referencedColumn}\" FROM \"${targetTable}\"\n\t\t\t\t\tWHERE \"${targetColumn}\" IN (${placeholders})\n\t\t\t\t`;\n\n\t\t\t\tconst selectResult = await client.query(selectQuery, values);\n\t\t\t\tconst nestedValues = selectResult.rows.map(\n\t\t\t\t\t({ row }: { row: { [nestedFk.referencedColumn]: unknown } }) =>\n\t\t\t\t\t\trow[nestedFk.referencedColumn],\n\t\t\t\t);\n\n\t\t\t\tif (nestedValues.length > 0) {\n\t\t\t\t\tawait deleteRelatedRecursively(\n\t\t\t\t\t\tnestedFk.referencingTable,\n\t\t\t\t\t\tnestedFk.referencingColumn,\n\t\t\t\t\t\tnestedValues,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Now delete from the target table\n\t\t\tconst placeholders = values.map((_, i) => `$${i + 1}`).join(\", \");\n\t\t\tconst deleteQuery = `\n\t\t\t\tDELETE FROM \"${targetTable}\"\n\t\t\t\tWHERE \"${targetColumn}\" IN (${placeholders})\n\t\t\t`;\n\n\t\t\tconst deleteResult = await client.query(deleteQuery, values);\n\t\t\ttotalRelatedDeleted += deleteResult.rowCount ?? 0;\n\t\t\tdeletedTables.add(targetTable);\n\t\t};\n\n\t\t// Delete from all referencing tables first\n\t\tfor (const constraint of fkConstraints) {\n\t\t\tif (deletedTables.has(constraint.referencingTable)) continue;\n\n\t\t\tawait deleteRelatedRecursively(\n\t\t\t\tconstraint.referencingTable,\n\t\t\t\tconstraint.referencingColumn,\n\t\t\t\tpkValues,\n\t\t\t);\n\t\t}\n\n\t\t// Finally delete the main records\n\t\tconst placeholders = pkValues.map((_, i) => `$${i + 1}`).join(\", \");\n\t\tconst deleteSQL = `\n\t\t\tDELETE FROM \"${tableName}\"\n\t\t\tWHERE \"${pkColumn}\" IN (${placeholders})\n\t\t\tRETURNING *\n\t\t`;\n\n\t\tconsole.log(\"Force deleting records with SQL:\", deleteSQL, \"Values:\", pkValues);\n\t\tconst result = await client.query(deleteSQL, pkValues);\n\n\t\tawait client.query(\"COMMIT\");\n\n\t\tconst mainDeleted = result.rowCount ?? 0;\n\t\tconst message =\n\t\t\ttotalRelatedDeleted > 0\n\t\t\t\t? `Successfully deleted ${mainDeleted} ${mainDeleted === 1 ? \"record\" : \"records\"} from \"${tableName}\" and ${totalRelatedDeleted} related ${totalRelatedDeleted === 1 ? \"record\" : \"records\"} from other tables`\n\t\t\t\t: `Successfully deleted ${mainDeleted} ${mainDeleted === 1 ? \"record\" : \"records\"} from \"${tableName}\"`;\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tmessage,\n\t\t\tdeletedCount: mainDeleted + totalRelatedDeleted,\n\t\t};\n\t} catch (error) {\n\t\tawait client.query(\"ROLLBACK\");\n\t\tconsole.error(\"Error force deleting records:\", error);\n\t\tthrow error;\n\t} finally {\n\t\tclient.release();\n\t}\n};\n","import { db } from \"../db.js\";\n\nexport interface InsertRecordParams {\n\ttableName: string;\n\tdata: Record<string, unknown>;\n}\n\nexport const insertRecord = async (params: InsertRecordParams) => {\n\tconst { tableName, data } = params;\n\tconst client = await db.connect();\n\n\ttry {\n\t\t// Extract column names and values\n\t\tconst columns = Object.keys(data);\n\t\tconst values = Object.values(data);\n\n\t\t// Build the INSERT query\n\t\tconst placeholders = columns.map((_, index) => `$${index + 1}`).join(\", \");\n\t\tconst columnNames = columns.map((col) => `\"${col}\"`).join(\", \");\n\n\t\tconst insertSQL = `\n\t\t\tINSERT INTO \"${tableName}\" (${columnNames})\n\t\t\tVALUES (${placeholders})\n\t\t\tRETURNING *\n\t\t`;\n\n\t\tconsole.log(\"Inserting record with SQL:\", insertSQL, \"Values:\", values);\n\t\tconst result = await client.query(insertSQL, values);\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tmessage: `Record inserted into \"${tableName}\" successfully`,\n\t\t\tdata: result.rows[0],\n\t\t};\n\t} catch (error) {\n\t\tconsole.error(\"Error inserting record:\", error);\n\t\tthrow error;\n\t} finally {\n\t\tclient.release();\n\t}\n};\n","export const DataTypes = {\n\ttext: \"text\",\n\tboolean: \"boolean\",\n\tnumber: \"number\",\n\tenum: \"enum\",\n\tjson: \"json\",\n\tdate: \"date\",\n\tarray: \"array\",\n} as const;\n\nexport type DataTypes = (typeof DataTypes)[keyof typeof DataTypes];\n\n/**\n * Maps PostgreSQL data types to generic DataType enum\n */\nexport function mapPostgresToDataType(pgType: string): DataTypes {\n\tconst normalized = pgType.toLowerCase().trim();\n\n\t// Handle array types and date/time types\n\tif (\n\t\tnormalized.includes(\"[]\") ||\n\t\tnormalized === \"date\" ||\n\t\tnormalized === \"time\" ||\n\t\tnormalized === \"time without time zone\" ||\n\t\tnormalized.startsWith(\"time(\") ||\n\t\tnormalized === \"timestamp\" ||\n\t\tnormalized === \"timestamp without time zone\" ||\n\t\tnormalized.startsWith(\"timestamp(\") ||\n\t\tnormalized === \"timestamp with time zone\" ||\n\t\tnormalized === \"timestamptz\" ||\n\t\tnormalized.startsWith(\"timestamp with time zone(\")\n\t) {\n\t\treturn DataTypes.date;\n\t}\n\n\t// Numeric types\n\tif (\n\t\tnormalized === \"integer\" ||\n\t\tnormalized === \"int\" ||\n\t\tnormalized === \"int4\" ||\n\t\tnormalized === \"bigint\" ||\n\t\tnormalized === \"int8\" ||\n\t\tnormalized === \"smallint\" ||\n\t\tnormalized === \"int2\" ||\n\t\tnormalized === \"decimal\" ||\n\t\tnormalized.startsWith(\"decimal(\") ||\n\t\tnormalized === \"numeric\" ||\n\t\tnormalized.startsWith(\"numeric(\") ||\n\t\tnormalized === \"real\" ||\n\t\tnormalized === \"float4\" ||\n\t\tnormalized === \"double precision\" ||\n\t\tnormalized === \"float8\" ||\n\t\tnormalized === \"float\" ||\n\t\tnormalized === \"serial\" ||\n\t\tnormalized === \"serial4\" ||\n\t\tnormalized === \"bigserial\" ||\n\t\tnormalized === \"serial8\" ||\n\t\tnormalized === \"money\"\n\t) {\n\t\treturn DataTypes.number;\n\t}\n\n\t// Boolean\n\tif (normalized === \"boolean\" || normalized === \"bool\") {\n\t\treturn DataTypes.boolean;\n\t}\n\n\t// JSON types\n\tif (normalized === \"json\" || normalized === \"jsonb\") {\n\t\treturn DataTypes.json;\n\t}\n\n\t// Enum types and long text types\n\tif (\n\t\tnormalized.startsWith(\"user-defined\") ||\n\t\tnormalized === \"enum\" ||\n\t\tnormalized === \"text\" ||\n\t\tnormalized === \"xml\"\n\t) {\n\t\treturn DataTypes.text;\n\t}\n\n\t// Short string types (varchar, char, uuid, etc.)\n\tif (\n\t\tnormalized === \"character varying\" ||\n\t\tnormalized.startsWith(\"varchar\") ||\n\t\tnormalized.startsWith(\"character varying(\") ||\n\t\tnormalized === \"character\" ||\n\t\tnormalized.startsWith(\"char\") ||\n\t\tnormalized.startsWith(\"character(\") ||\n\t\tnormalized === \"bpchar\" ||\n\t\tnormalized === \"uuid\" ||\n\t\tnormalized === \"interval\" ||\n\t\tnormalized.startsWith(\"interval\") ||\n\t\tnormalized === \"bytea\" ||\n\t\tnormalized === \"point\" ||\n\t\tnormalized === \"line\" ||\n\t\tnormalized === \"polygon\" ||\n\t\tnormalized === \"inet\" ||\n\t\tnormalized === \"cidr\" ||\n\t\tnormalized === \"macaddr\" ||\n\t\tnormalized === \"macaddr8\"\n\t) {\n\t\treturn DataTypes.text;\n\t}\n\n\t// Default to short for unrecognized types\n\treturn DataTypes.text;\n}\n\n/**\n * Standardized data type labels\n */\nexport const StandardizedDataType = {\n\t// Numeric types\n\tint: \"int\",\n\tbigint: \"bigint\",\n\tsmallint: \"smallint\",\n\tnumeric: \"numeric\",\n\tfloat: \"float\",\n\tdouble: \"double\",\n\tmoney: \"money\",\n\t// Boolean\n\tboolean: \"boolean\",\n\t// Text types\n\ttext: \"text\",\n\tvarchar: \"varchar\",\n\tchar: \"char\",\n\t// JSON types\n\tjson: \"json\",\n\tjsonb: \"jsonb\",\n\txml: \"xml\",\n\t// UUID\n\tuuid: \"uuid\",\n\t// Date/Time types\n\tdate: \"date\",\n\ttime: \"time\",\n\ttimestamp: \"timestamp\",\n\ttimestamptz: \"timestamptz\",\n\tinterval: \"interval\",\n\t// Binary\n\tbytea: \"bytea\",\n\t// Network types\n\tinet: \"inet\",\n\tcidr: \"cidr\",\n\tmacaddr: \"macaddr\",\n\tmacaddr8: \"macaddr8\",\n\t// Geometric types\n\tpoint: \"point\",\n\tline: \"line\",\n\tpolygon: \"polygon\",\n\t// Complex types\n\tarray: \"array\",\n\tenum: \"enum\",\n} as const;\n\nexport type StandardizedDataType =\n\t(typeof StandardizedDataType)[keyof typeof StandardizedDataType];\n\n/**\n * Maps PostgreSQL data types to standardized display labels\n */\nexport function standardizeDataTypeLabel(pgType: string): StandardizedDataType {\n\tconst normalized = pgType.toLowerCase().trim();\n\n\t// Numeric types\n\tif (\n\t\tnormalized === \"integer\" ||\n\t\tnormalized === \"int\" ||\n\t\tnormalized === \"int4\" ||\n\t\tnormalized === \"serial\" ||\n\t\tnormalized === \"serial4\"\n\t) {\n\t\treturn StandardizedDataType.int;\n\t}\n\n\tif (\n\t\tnormalized === \"bigint\" ||\n\t\tnormalized === \"int8\" ||\n\t\tnormalized === \"bigserial\" ||\n\t\tnormalized === \"serial8\"\n\t) {\n\t\treturn StandardizedDataType.bigint;\n\t}\n\n\tif (normalized === \"smallint\" || normalized === \"int2\") {\n\t\treturn StandardizedDataType.smallint;\n\t}\n\n\tif (\n\t\tnormalized === \"decimal\" ||\n\t\tnormalized.startsWith(\"decimal(\") ||\n\t\tnormalized === \"numeric\" ||\n\t\tnormalized.startsWith(\"numeric(\")\n\t) {\n\t\treturn StandardizedDataType.numeric;\n\t}\n\n\tif (normalized === \"real\" || normalized === \"float4\") {\n\t\treturn StandardizedDataType.float;\n\t}\n\n\tif (\n\t\tnormalized === \"double precision\" ||\n\t\tnormalized === \"float8\" ||\n\t\tnormalized === \"float\"\n\t) {\n\t\treturn StandardizedDataType.double;\n\t}\n\n\tif (normalized === \"money\") {\n\t\treturn StandardizedDataType.money;\n\t}\n\n\t// Boolean\n\tif (normalized === \"boolean\" || normalized === \"bool\") {\n\t\treturn StandardizedDataType.boolean;\n\t}\n\n\t// Text types\n\tif (normalized === \"text\") {\n\t\treturn StandardizedDataType.text;\n\t}\n\n\tif (\n\t\tnormalized === \"character varying\" ||\n\t\tnormalized.startsWith(\"varchar\") ||\n\t\tnormalized.startsWith(\"character varying(\")\n\t) {\n\t\treturn StandardizedDataType.varchar;\n\t}\n\n\tif (\n\t\tnormalized === \"character\" ||\n\t\tnormalized.startsWith(\"char\") ||\n\t\tnormalized.startsWith(\"character(\") ||\n\t\tnormalized === \"bpchar\"\n\t) {\n\t\treturn StandardizedDataType.char;\n\t}\n\n\t// JSON types\n\tif (normalized === \"json\") {\n\t\treturn StandardizedDataType.json;\n\t}\n\n\tif (normalized === \"jsonb\") {\n\t\treturn StandardizedDataType.jsonb;\n\t}\n\n\tif (normalized === \"xml\") {\n\t\treturn StandardizedDataType.xml;\n\t}\n\n\t// UUID\n\tif (normalized === \"uuid\") {\n\t\treturn StandardizedDataType.uuid;\n\t}\n\n\t// Date/Time types\n\tif (normalized === \"date\") {\n\t\treturn StandardizedDataType.date;\n\t}\n\n\tif (\n\t\tnormalized === \"time\" ||\n\t\tnormalized === \"time without time zone\" ||\n\t\tnormalized.startsWith(\"time(\")\n\t) {\n\t\treturn StandardizedDataType.time;\n\t}\n\n\tif (\n\t\tnormalized === \"timestamp\" ||\n\t\tnormalized === \"timestamp without time zone\" ||\n\t\tnormalized.startsWith(\"timestamp(\")\n\t) {\n\t\treturn StandardizedDataType.timestamp;\n\t}\n\n\tif (\n\t\tnormalized === \"timestamp with time zone\" ||\n\t\tnormalized === \"timestamptz\" ||\n\t\tnormalized.startsWith(\"timestamp with time zone(\")\n\t) {\n\t\treturn StandardizedDataType.timestamptz;\n\t}\n\n\tif (normalized === \"interval\" || normalized.startsWith(\"interval\")) {\n\t\treturn StandardizedDataType.interval;\n\t}\n\n\t// Binary\n\tif (normalized === \"bytea\") {\n\t\treturn StandardizedDataType.bytea;\n\t}\n\n\t// Network types\n\tif (normalized === \"inet\") {\n\t\treturn StandardizedDataType.inet;\n\t}\n\n\tif (normalized === \"cidr\") {\n\t\treturn StandardizedDataType.cidr;\n\t}\n\n\tif (normalized === \"macaddr\") {\n\t\treturn StandardizedDataType.macaddr;\n\t}\n\n\tif (normalized === \"macaddr8\") {\n\t\treturn StandardizedDataType.macaddr8;\n\t}\n\n\t// Geometric types\n\tif (normalized === \"point\") {\n\t\treturn StandardizedDataType.point;\n\t}\n\n\tif (normalized === \"line\") {\n\t\treturn StandardizedDataType.line;\n\t}\n\n\tif (normalized === \"polygon\") {\n\t\treturn StandardizedDataType.polygon;\n\t}\n\n\t// Array types\n\t// todo: handle array types\n\tif (normalized.startsWith(\"array\") || normalized.includes(\"[]\")) {\n\t\treturn StandardizedDataType.text;\n\t}\n\n\t// User-defined types (enums)\n\tif (normalized.startsWith(\"user-defined\") || normalized === \"enum\") {\n\t\treturn StandardizedDataType.enum;\n\t}\n\n\t// Default: return the original type\n\treturn StandardizedDataType.text;\n}\n","import { db } from \"../db.js\";\nimport {\n\ttype DataTypes,\n\tmapPostgresToDataType,\n\ttype StandardizedDataType,\n\tstandardizeDataTypeLabel,\n} from \"../types/column.types.js\";\n\nexport interface ColumnInfo {\n\tcolumnName: string; // The column name from the database\n\tdataType: DataTypes; // Generic type mapped to cell variant (text/boolean/number/enum/json/date)\n\tdataTypeLabel: StandardizedDataType; // Exact database type (int/varchar/timestamp/etc.)\n\tisNullable: boolean;\n\tcolumnDefault: string | null;\n\tisPrimaryKey: boolean;\n\tisForeignKey: boolean;\n\treferencedTable: string | null;\n\treferencedColumn: string | null;\n\tenumValues: string[] | null;\n}\n\nexport const getTableColumns = async (tableName: string): Promise<ColumnInfo[]> => {\n\tconst client = await db.connect();\n\ttry {\n\t\tconst res = await client.query(\n\t\t\t`\n SELECT \n c.column_name as \"columnName\",\n c.data_type as \"dataType\",\n c.udt_name as \"udtName\",\n c.is_nullable = 'YES' as \"isNullable\",\n c.column_default as \"columnDefault\",\n CASE WHEN pk.column_name IS NOT NULL THEN true ELSE false END as \"isPrimaryKey\",\n CASE WHEN fk.column_name IS NOT NULL THEN true ELSE false END as \"isForeignKey\",\n fk.referenced_table as \"referencedTable\",\n fk.referenced_column as \"referencedColumn\",\n CASE \n WHEN c.data_type = 'USER-DEFINED' THEN \n (SELECT array_agg(e.enumlabel ORDER BY e.enumsortorder)\n FROM pg_type t\n JOIN pg_enum e ON t.oid = e.enumtypid\n WHERE t.typname = c.udt_name)\n ELSE NULL\n END as \"enumValues\"\n FROM information_schema.columns c\n LEFT JOIN (\n SELECT ku.column_name\n FROM information_schema.table_constraints tc\n JOIN information_schema.key_column_usage ku\n ON tc.constraint_name = ku.constraint_name\n AND tc.table_schema = ku.table_schema\n WHERE tc.constraint_type = 'PRIMARY KEY'\n AND tc.table_schema = 'public'\n AND tc.table_name = $1\n ) pk ON c.column_name = pk.column_name\n LEFT JOIN (\n SELECT \n kcu.column_name,\n ccu.table_name AS referenced_table,\n ccu.column_name AS referenced_column\n FROM information_schema.table_constraints tc\n JOIN information_schema.key_column_usage kcu\n ON tc.constraint_name = kcu.constraint_name\n AND tc.table_schema = kcu.table_schema\n JOIN information_schema.constraint_column_usage ccu\n ON tc.constraint_name = ccu.constraint_name\n AND tc.table_schema = ccu.table_schema\n WHERE tc.constraint_type = 'FOREIGN KEY'\n AND tc.table_schema = 'public'\n AND tc.table_name = $1\n ) fk ON c.column_name = fk.column_name\n WHERE c.table_schema = 'public'\n AND c.table_name = $1\n ORDER BY c.ordinal_position;\n `,\n\t\t\t[tableName],\n\t\t);\n\n\t\treturn res.rows.map((r: any) => {\n\t\t\t// Parse enumValues to always return string[] | null\n\t\t\tlet parsedEnumValues: string[] | null = null;\n\t\t\tif (r.enumValues) {\n\t\t\t\tif (Array.isArray(r.enumValues)) {\n\t\t\t\t\t// Already an array, use as-is\n\t\t\t\t\tparsedEnumValues = r.enumValues;\n\t\t\t\t} else if (typeof r.enumValues === \"string\") {\n\t\t\t\t\t// Parse PostgreSQL array format: \"{VALUE1,VALUE2,VALUE3}\"\n\t\t\t\t\tparsedEnumValues = r.enumValues.replace(/[{}]/g, \"\").split(\",\").filter(Boolean);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tcolumnName: r.columnName,\n\t\t\t\tdataType: mapPostgresToDataType(r.dataType),\n\t\t\t\tdataTypeLabel: standardizeDataTypeLabel(r.dataType),\n\t\t\t\tisNullable: r.isNullable,\n\t\t\t\tcolumnDefault: r.columnDefault,\n\t\t\t\tisPrimaryKey: r.isPrimaryKey,\n\t\t\t\tisForeignKey: r.isForeignKey,\n\t\t\t\treferencedTable: r.referencedTable,\n\t\t\t\treferencedColumn: r.referencedColumn,\n\t\t\t\tenumValues: parsedEnumValues,\n\t\t\t};\n\t\t});\n\t} finally {\n\t\tclient.release();\n\t}\n};\n","import { db } from \"../db.js\";\n\nexport interface TableInfo {\n\ttableName: string;\n\trowCount: number;\n}\n\nexport const getTablesList = async (): Promise<TableInfo[]> => {\n\tconst client = await db.connect();\n\ttry {\n\t\tconst res = await client.query(`\n SELECT \n t.table_name as \"tableName\",\n COALESCE(s.n_live_tup, 0) as \"rowCount\" \n FROM information_schema.tables t\n LEFT JOIN pg_stat_user_tables s ON t.table_name = s.relname\n WHERE t.table_schema = 'public'\n AND t.table_type = 'BASE TABLE'\n ORDER BY t.table_name;\n `);\n\t\treturn res.rows.map((r: any) => ({\n\t\t\ttableName: r.tableName,\n\t\t\trowCount: Number(r.rowCount),\n\t\t}));\n\t} finally {\n\t\tclient.release();\n\t}\n};\n","import { db } from \"../db.js\";\n\nexport interface Filter {\n\tcolumnName: string;\n\toperator: string;\n\tvalue: string;\n}\n\nexport type SortDirection = \"asc\" | \"desc\";\n\nexport type Sort = {\n\tcolumnName: string;\n\tdirection: SortDirection;\n};\n\nexport interface TableDataResult {\n\tdata: Record<string, unknown>[];\n\tmeta: {\n\t\tpage: number;\n\t\tlimit: number;\n\t\ttotal: number;\n\t\ttotalPages: number;\n\t\thasNextPage: boolean;\n\t\thasPreviousPage: boolean;\n\t};\n}\n\nconst buildWhereClause = (filters: Filter[]): { clause: string; values: unknown[] } => {\n\tif (filters.length === 0) {\n\t\treturn { clause: \"\", values: [] };\n\t}\n\n\tconst conditions: string[] = [];\n\tconst values: unknown[] = [];\n\n\tfor (const filter of filters) {\n\t\tconst paramIndex = values.length + 1;\n\t\tconst columnName = `\"${filter.columnName}\"`;\n\n\t\tswitch (filter.operator) {\n\t\t\tcase \"=\":\n\t\t\tcase \"!=\":\n\t\t\tcase \">\":\n\t\t\tcase \">=\":\n\t\t\tcase \"<\":\n\t\t\tcase \"<=\":\n\t\t\t\tconditions.push(`${columnName} ${filter.operator} $${paramIndex}`);\n\t\t\t\tvalues.push(filter.value);\n\t\t\t\tbreak;\n\t\t\tcase \"is\":\n\t\t\t\t// Handle NULL values\n\t\t\t\tif (filter.value.toLowerCase() === \"null\") {\n\t\t\t\t\tconditions.push(`${columnName} IS NULL`);\n\t\t\t\t} else {\n\t\t\t\t\tconditions.push(`${columnName} = $${paramIndex}`);\n\t\t\t\t\tvalues.push(filter.value);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase \"is not\":\n\t\t\t\tif (filter.value.toLowerCase() === \"null\") {\n\t\t\t\t\tconditions.push(`${columnName} IS NOT NULL`);\n\t\t\t\t} else {\n\t\t\t\t\tconditions.push(`${columnName} != $${paramIndex}`);\n\t\t\t\t\tvalues.push(filter.value);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase \"like\":\n\t\t\t\tconditions.push(`${columnName}::text LIKE $${paramIndex}`);\n\t\t\t\tvalues.push(filter.value);\n\t\t\t\tbreak;\n\t\t\tcase \"not like\":\n\t\t\t\tconditions.push(`${columnName}::text NOT LIKE $${paramIndex}`);\n\t\t\t\tvalues.push(filter.value);\n\t\t\t\tbreak;\n\t\t\tcase \"ilike\":\n\t\t\t\tconditions.push(`${columnName}::text ILIKE $${paramIndex}`);\n\t\t\t\tvalues.push(filter.value);\n\t\t\t\tbreak;\n\t\t\tcase \"not ilike\":\n\t\t\t\tconditions.push(`${columnName}::text NOT ILIKE $${paramIndex}`);\n\t\t\t\tvalues.push(filter.value);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\t// Unknown operator, skip\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (conditions.length === 0) {\n\t\treturn { clause: \"\", values: [] };\n\t}\n\n\treturn { clause: `WHERE ${conditions.join(\" AND \")}`, values };\n};\n\nconst buildSortClause = (sorts: Sort[] | string, order: SortDirection): string => {\n\t// Handle array of Sort objects (new format for referenced tables)\n\tif (Array.isArray(sorts)) {\n\t\tif (sorts.length === 0) {\n\t\t\treturn \"\";\n\t\t}\n\t\tconst sortParts = sorts.map(\n\t\t\t(sort) => `\"${sort.columnName}\" ${sort.direction.toUpperCase()}`,\n\t\t);\n\t\treturn `ORDER BY ${sortParts.join(\", \")}`;\n\t}\n\n\t// Handle legacy format (string column name + order)\n\tif (sorts && typeof sorts === \"string\") {\n\t\treturn `ORDER BY \"${sorts}\" ${order?.toUpperCase() || \"ASC\"}`;\n\t}\n\n\treturn \"\";\n};\n\nexport const getTableData = async (\n\ttableName: string,\n\tpage: number = 1,\n\tpageSize: number = 50,\n\tsort: string | Sort[] = \"\",\n\torder: SortDirection = \"asc\",\n\tfilters: Filter[] = [],\n): Promise<TableDataResult> => {\n\tconst sortClause = buildSortClause(\n\t\tArray.isArray(sort) ? sort : sort,\n\t\torder as SortDirection,\n\t);\n\tconst { clause: whereClause, values: filterValues } = buildWhereClause(filters);\n\n\tconst client = await db.connect();\n\ttry {\n\t\t// Calculate offset\n\t\tconst offset = (page - 1) * pageSize;\n\n\t\t// Get total count (with filters)\n\t\tconst countRes = await client.query(\n\t\t\t`SELECT COUNT(*) as total FROM \"${tableName}\" ${whereClause}`,\n\t\t\tfilterValues,\n\t\t);\n\t\tconst totalRows = Number(countRes.rows[0].total);\n\t\tconst totalPages = Math.ceil(totalRows / pageSize);\n\n\t\t// Get paginated data (with filters)\n\t\t// Parameter indices continue after filter values\n\t\tconst limitParamIndex = filterValues.length + 1;\n\t\tconst offsetParamIndex = filterValues.length + 2;\n\n\t\tconst dataRes = await client.query(\n\t\t\t`SELECT * FROM \"${tableName}\" ${whereClause} ${sortClause} LIMIT $${limitParamIndex} OFFSET $${offsetParamIndex}`,\n\t\t\t[...filterValues, pageSize, offset],\n\t\t);\n\n\t\treturn {\n\t\t\tdata: dataRes.rows,\n\t\t\tmeta: {\n\t\t\t\tpage,\n\t\t\t\tlimit: pageSize,\n\t\t\t\ttotal: totalRows,\n\t\t\t\ttotalPages,\n\t\t\t\thasNextPage: page < totalPages,\n\t\t\t\thasPreviousPage: page > 1,\n\t\t\t},\n\t\t};\n\t} finally {\n\t\tclient.release();\n\t}\n};\n","import { db } from \"../db.js\";\n\nexport interface UpdateRecordParams {\n\ttableName: string;\n\tupdates: Array<{\n\t\trowData: Record<string, unknown>; // Original row data to identify the record\n\t\tcolumnName: string;\n\t\tvalue: unknown;\n\t}>;\n\tprimaryKey?: string; // Optional: specify primary key column (defaults to 'id')\n}\n\n/**\n * Updates multiple cells in a table. Can update multiple rows or multiple cells in the same row.\n * Groups updates by row and executes them efficiently.\n */\nexport const updateRecords = async (params: UpdateRecordParams) => {\n\tconst { tableName, updates, primaryKey = \"id\" } = params;\n\tconst client = await db.connect();\n\n\ttry {\n\t\tawait client.query(\"BEGIN\");\n\n\t\t// Group updates by row (using the primary key value)\n\t\tconst updatesByRow = new Map<\n\t\t\tunknown,\n\t\t\tArray<{ columnName: string; value: unknown; rowData: Record<string, unknown> }>\n\t\t>();\n\n\t\tfor (const update of updates) {\n\t\t\tconst pkValue = update.rowData[primaryKey];\n\t\t\tif (pkValue === undefined) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Primary key \"${primaryKey}\" not found in row data. Please ensure the row has a primary key.`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (!updatesByRow.has(pkValue)) {\n\t\t\t\tupdatesByRow.set(pkValue, []);\n\t\t\t}\n\t\t\tupdatesByRow.get(pkValue)?.push({\n\t\t\t\tcolumnName: update.columnName,\n\t\t\t\tvalue: update.value,\n\t\t\t\trowData: update.rowData,\n\t\t\t});\n\t\t}\n\n\t\tconst results = [];\n\t\tlet totalUpdated = 0;\n\n\t\t// Execute updates for each row\n\t\tfor (const [pkValue, rowUpdates] of updatesByRow.entries()) {\n\t\t\tconst setClauses = rowUpdates.map(\n\t\t\t\t(u, index) => `\"${u.columnName}\" = $${index + 1}`,\n\t\t\t);\n\t\t\tconst values = rowUpdates.map((u) => {\n\t\t\t\tconsole.log(`Value for ${u.columnName}:`, typeof u.value, u.value);\n\t\t\t\t// If the value is an object or array, stringify it for JSON/JSONB columns\n\t\t\t\tif (u.value !== null && typeof u.value === \"object\") {\n\t\t\t\t\treturn JSON.stringify(u.value);\n\t\t\t\t}\n\t\t\t\treturn u.value;\n\t\t\t});\n\n\t\t\t// Add the primary key value as the last parameter\n\t\t\tvalues.push(pkValue);\n\n\t\t\tconst updateSQL = `\n\t\t\t\tUPDATE \"${tableName}\"\n\t\t\t\tSET ${setClauses.join(\", \")}\n\t\t\t\tWHERE \"${primaryKey}\" = $${values.length}\n\t\t\t\tRETURNING *\n\t\t\t`;\n\n\t\t\tconsole.log(\"Updating record with SQL:\", updateSQL, \"Values:\", values);\n\t\t\tconst result = await client.query(updateSQL, values);\n\n\t\t\tif (result.rowCount === 0) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Record with ${primaryKey} = ${pkValue} not found in table \"${tableName}\"`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tresults.push(result.rows[0]);\n\t\t\ttotalUpdated += result.rowCount || 0;\n\t\t}\n\n\t\tawait client.query(\"COMMIT\");\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tmessage: `Successfully updated ${totalUpdated} ${totalUpdated === 1 ? \"row\" : \"rows\"} in \"${tableName}\"`,\n\t\t\tdata: results,\n\t\t\tupdatedCount: totalUpdated,\n\t\t};\n\t} catch (error) {\n\t\tawait client.query(\"ROLLBACK\");\n\t\tconsole.error(\"Error updating records:\", error);\n\t\tthrow error;\n\t} finally {\n\t\tclient.release();\n\t}\n};\n","import { z } from \"zod\";\n\nexport const FOREIGN_KEY_ACTIONS = [\n\t\"CASCADE\",\n\t\"SET NULL\",\n\t\"SET DEFAULT\",\n\t\"RESTRICT\",\n\t\"NO ACTION\",\n] as const;\nexport const foreignKeyActionSchema = z.enum(FOREIGN_KEY_ACTIONS);\nexport type ForeignKeyAction = z.infer<typeof foreignKeyActionSchema>;\n\nexport const fieldDataSchema = z.object({\n\tcolumnName: z.string().min(1),\n\tcolumnType: z.string().min(1),\n\tdefaultValue: z.string(),\n\tisPrimaryKey: z.boolean(),\n\tisNullable: z.boolean(),\n\tisUnique: z.boolean(),\n\tisIdentity: z.boolean(),\n\tisArray: z.boolean(),\n});\nexport type FieldDataType = z.infer<typeof fieldDataSchema>;\n\nexport const foreignKeyDataSchema = z.object({\n\tcolumnName: z.string().min(1),\n\treferencedTable: z.string().min(1),\n\treferencedColumn: z.string().min(1),\n\tonUpdate: foreignKeyActionSchema,\n\tonDelete: foreignKeyActionSchema,\n});\nexport type ForeignKeyDataType = z.infer<typeof foreignKeyDataSchema>;\n\nexport const createTableSchema = z.object({\n\ttableName: z.string().min(1, \"Table name is required\"),\n\tfields: z.array(fieldDataSchema).min(1, \"At least one field is required\"),\n\tforeignKeys: z.array(foreignKeyDataSchema).optional(),\n});\nexport type CreateTableFormData = z.infer<typeof createTableSchema>;\n\nexport const tableNameParamSchema = z.object({\n\ttableName: z.string().min(1, \"Table name is required\"),\n});\n\nexport const tableDataQuerySchema = z.object({\n\tpage: z.string().optional().default(\"1\").transform(Number),\n\tpageSize: z.string().optional().default(\"50\").transform(Number),\n\tsort: z.string().optional().default(\"\"),\n\torder: z.enum([\"asc\", \"desc\"]).optional(),\n\tfilters: z\n\t\t.string()\n\t\t.optional()\n\t\t.transform((val) => {\n\t\t\tif (!val) return [];\n\t\t\ttry {\n\t\t\t\treturn JSON.parse(val);\n\t\t\t} catch {\n\t\t\t\treturn [];\n\t\t\t}\n\t\t}),\n});\n\nexport const insertRecordSchema = z.object({\n\ttableName: z.string().min(1, \"Table name is required\"),\n});\n\nexport const updateRecordsSchema = z.object({\n\ttableName: z.string().min(1, \"Table name is required\"),\n\tupdates: z\n\t\t.array(\n\t\t\tz.object({\n\t\t\t\trowData: z.any(),\n\t\t\t\tcolumnName: z.string().min(1),\n\t\t\t\tvalue: z.any(),\n\t\t\t}),\n\t\t)\n\t\t.min(1, \"At least one update is required\"),\n\tprimaryKey: z.string().optional(),\n});\n\nexport const deleteRecordsSchema = z.object({\n\ttableName: z.string().min(1, \"Table name is required\"),\n\tprimaryKeys: z\n\t\t.array(\n\t\t\tz.object({\n\t\t\t\tcolumnName: z.string().min(1),\n\t\t\t\tvalue: z.any(),\n\t\t\t}),\n\t\t)\n\t\t.min(1, \"At least one primary key is required\"),\n});\n","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\";\n\nimport { createTable } from \"../dao/create-table.dao.js\";\nimport { deleteRecords, forceDeleteRecords } from \"../dao/delete-records.dao.js\";\nimport { insertRecord } from \"../dao/insert-record.dao.js\";\nimport { getTableColumns } from \"../dao/table-columns.dao.js\";\nimport { getTablesList } from \"../dao/table-list.dao.js\";\nimport { getTableData, type Sort } from \"../dao/tables-data.dao.js\";\nimport { updateRecords } from \"../dao/update-records.dao.js\";\nimport {\n\tcreateTableSchema,\n\tdeleteRecordsSchema,\n\tinsertRecordSchema,\n\ttableDataQuerySchema,\n\ttableNameParamSchema,\n\tupdateRecordsSchema,\n} from \"../types/create-table.type.js\";\n\nconst getCoreDistPath = () => {\n\tconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\treturn path.resolve(__dirname, \"./core-dist\");\n};\n\nexport const createServer = () => {\n\tconst api = new Hono().basePath(\"/\");\n\n\t// Add CORS middleware to API routes\n\tapi.use(\"/*\", cors());\n\n\tapi.use(\n\t\t\"/favicon.ico\",\n\t\tserveStatic({ path: path.resolve(getCoreDistPath(), \"favicon.ico\") }),\n\t);\n\n\tapi.use(\"*\", async (c, next) => {\n\t\tc.header(\"Access-Control-Allow-Origin\", \"*\");\n\t\tc.header(\"Access-Control-Allow-Methods\", \"GET, POST, PUT, DELETE, OPTIONS\");\n\t\tc.header(\"Access-Control-Allow-Headers\", \"Content-Type\");\n\t\tawait next();\n\t});\n\n\t/**\n\t * Serve static files from the core dist directory\n\t */\n\tapi.use(\"/*\", serveStatic({ root: getCoreDistPath() }));\n\n\t/**\n\t * Tables\n\t * GET /tables - Get all tables\n\t */\n\tapi.get(\"/tables\", async (c) => {\n\t\ttry {\n\t\t\tconst tablesList = await getTablesList();\n\t\t\tconsole.log(\"GET /tables\", tablesList);\n\t\t\treturn c.json(tablesList);\n\t\t} catch (error) {\n\t\t\tconsole.error(\"GET /tables error:\", error);\n\t\t\tconst errorMessage =\n\t\t\t\terror instanceof Error ? error.message : \"Failed to fetch tables\";\n\n\t\t\t// Check for connection errors (can be in AggregateError.errors array or directly)\n\t\t\tlet isConnectionError = false;\n\t\t\tif (error && typeof error === \"object\" && \"code\" in error) {\n\t\t\t\tisConnectionError = (error as { code?: string }).code === \"ECONNREFUSED\";\n\t\t\t} else if (\n\t\t\t\terror &&\n\t\t\t\ttypeof error === \"object\" &&\n\t\t\t\t\"errors\" in error &&\n\t\t\t\tArray.isArray((error as { errors?: unknown[] }).errors)\n\t\t\t) {\n\t\t\t\t// Handle AggregateError\n\t\t\t\tconst aggregateError = error as { errors?: Array<{ code?: string }> };\n\t\t\t\tisConnectionError =\n\t\t\t\t\taggregateError.errors?.some((err) => err.code === \"ECONNREFUSED\") ?? false;\n\t\t\t}\n\n\t\t\tif (isConnectionError) {\n\t\t\t\treturn c.json(\n\t\t\t\t\t{\n\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\t\"Cannot connect to database. Please check your DATABASE_URL and ensure the database server is running.\",\n\t\t\t\t\t\terror: errorMessage,\n\t\t\t\t\t},\n\t\t\t\t\t503,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\tmessage: errorMessage,\n\t\t\t\t},\n\t\t\t\t500,\n\t\t\t);\n\t\t}\n\t});\n\n\t/**\n\t * Columns\n\t * GET /tables/:tableName/columns - Get all columns for a table\n\t */\n\tapi.get(\n\t\t\"/tables/:tableName/columns\",\n\t\tzValidator(\"param\", tableNameParamSchema),\n\t\tasync (c) => {\n\t\t\ttry {\n\t\t\t\tconst { tableName } = c.req.valid(\"param\");\n\t\t\t\tconst columns = await getTableColumns(tableName);\n\t\t\t\tconsole.log(\"GET /tables/:tableName/columns\", columns);\n\t\t\t\treturn c.json(columns);\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(\"GET /tables/:tableName/columns error:\", error);\n\t\t\t\tconst errorMessage =\n\t\t\t\t\terror instanceof Error ? error.message : \"Failed to fetch columns\";\n\n\t\t\t\t// Check for connection errors (can be in AggregateError.errors array or directly)\n\t\t\t\tlet isConnectionError = false;\n\t\t\t\tif (error && typeof error === \"object\" && \"code\" in error) {\n\t\t\t\t\tisConnectionError = (error as { code?: string }).code === \"ECONNREFUSED\";\n\t\t\t\t} else if (\n\t\t\t\t\terror &&\n\t\t\t\t\ttypeof error === \"object\" &&\n\t\t\t\t\t\"errors\" in error &&\n\t\t\t\t\tArray.isArray((error as { errors?: unknown[] }).errors)\n\t\t\t\t) {\n\t\t\t\t\t// Handle AggregateError\n\t\t\t\t\tconst aggregateError = error as { errors?: Array<{ code?: string }> };\n\t\t\t\t\tisConnectionError =\n\t\t\t\t\t\taggregateError.errors?.some((err) => err.code === \"ECONNREFUSED\") ?? false;\n\t\t\t\t}\n\n\t\t\t\tif (isConnectionError) {\n\t\t\t\t\treturn c.json(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\t\t\"Cannot connect to database. Please check your DATABASE_URL and ensure the database server is running.\",\n\t\t\t\t\t\t\terror: errorMessage,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t503,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn c.json(\n\t\t\t\t\t{\n\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\tmessage: errorMessage,\n\t\t\t\t\t},\n\t\t\t\t\t500,\n\t\t\t\t);\n\t\t\t}\n\t\t},\n\t);\n\n\t/**\n\t * Data\n\t * GET /tables/:tableName/data - Get paginated data for a table\n\t * Query params: page (default: 1), pageSize (default: 50), sort (string or JSON array), order, filters (JSON)\n\t */\n\tapi.get(\n\t\t\"/tables/:tableName/data\",\n\t\tzValidator(\"param\", tableNameParamSchema),\n\t\tzValidator(\"query\", tableDataQuerySchema),\n\t\tasync (c) => {\n\t\t\ttry {\n\t\t\t\tconst { tableName } = c.req.valid(\"param\");\n\t\t\t\tconst { page, pageSize, sort: sortParam, order, filters } = c.req.valid(\"query\");\n\n\t\t\t\t// Parse sort - can be either a string (legacy) or JSON array (new format)\n\t\t\t\tlet sort: Sort[] | string = \"\";\n\t\t\t\tif (sortParam) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// Try to parse as JSON first (new format)\n\t\t\t\t\t\tconst parsed = JSON.parse(sortParam);\n\t\t\t\t\t\tif (Array.isArray(parsed)) {\n\t\t\t\t\t\t\tsort = parsed;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tsort = sortParam;\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// If JSON parse fails, use as string (legacy format)\n\t\t\t\t\t\tsort = sortParam;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst data = await getTableData(tableName, page, pageSize, sort, order, filters);\n\t\t\t\treturn c.json(data);\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(\"GET /tables/:tableName/data error:\", error);\n\t\t\t\tconst errorMessage =\n\t\t\t\t\terror instanceof Error ? error.message : \"Failed to fetch table data\";\n\n\t\t\t\t// Check for connection errors (can be in AggregateError.errors array or directly)\n\t\t\t\tlet isConnectionError = false;\n\t\t\t\tif (error && typeof error === \"object\" && \"code\" in error) {\n\t\t\t\t\tisConnectionError = (error as { code?: string }).code === \"ECONNREFUSED\";\n\t\t\t\t} else if (\n\t\t\t\t\terror &&\n\t\t\t\t\ttypeof error === \"object\" &&\n\t\t\t\t\t\"errors\" in error &&\n\t\t\t\t\tArray.isArray((error as { errors?: unknown[] }).errors)\n\t\t\t\t) {\n\t\t\t\t\t// Handle AggregateError\n\t\t\t\t\tconst aggregateError = error as { errors?: Array<{ code?: string }> };\n\t\t\t\t\tisConnectionError =\n\t\t\t\t\t\taggregateError.errors?.some((err) => err.code === \"ECONNREFUSED\") ?? false;\n\t\t\t\t}\n\n\t\t\t\tif (isConnectionError) {\n\t\t\t\t\treturn c.json(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\t\t\"Cannot connect to database. Please check your DATABASE_URL and ensure the database server is running.\",\n\t\t\t\t\t\t\terror: errorMessage,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t503,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn c.json(\n\t\t\t\t\t{\n\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\tmessage: errorMessage,\n\t\t\t\t\t},\n\t\t\t\t\t500,\n\t\t\t\t);\n\t\t\t}\n\t\t},\n\t);\n\n\t/**\n\t * Create Table\n\t * POST /tables - Create a new table\n\t */\n\tapi.post(\"/tables\", zValidator(\"json\", createTableSchema), async (c) => {\n\t\ttry {\n\t\t\tconst body = c.req.valid(\"json\");\n\t\t\tconsole.log(\"POST /tables body\", body);\n\t\t\tconst data = await createTable(body);\n\t\t\tconsole.log(\"POST /tables\", data);\n\t\t\treturn c.json(data);\n\t\t} catch (error) {\n\t\t\tconsole.error(\"POST /tables error:\", error);\n\t\t\tconst errorDetail =\n\t\t\t\terror && typeof error === \"object\" && \"detail\" in error\n\t\t\t\t\t? (error as { detail?: string }).detail\n\t\t\t\t\t: undefined;\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\tmessage: error instanceof Error ? error.message : \"Failed to create table\",\n\t\t\t\t\tdetail: errorDetail,\n\t\t\t\t},\n\t\t\t\t500,\n\t\t\t);\n\t\t}\n\t});\n\n\t/**\n\t * Create Record\n\t * POST /records - Insert a new record into a table\n\t * Body: { tableName: string, ...recordData }\n\t */\n\tapi.post(\"/records\", zValidator(\"json\", insertRecordSchema), async (c) => {\n\t\ttry {\n\t\t\tconst body = c.req.valid(\"json\");\n\t\t\tconst { tableName, ...recordData } = body;\n\n\t\t\tconsole.log(\"POST /records body\", { tableName, recordData });\n\t\t\tconst result = await insertRecord({ tableName, data: recordData });\n\t\t\tconsole.log(\"POST /records\", result);\n\t\t\treturn c.json(result);\n\t\t} catch (error) {\n\t\t\tconsole.error(\"POST /records error:\", error);\n\t\t\tconst errorDetail =\n\t\t\t\terror && typeof error === \"object\" && \"detail\" in error\n\t\t\t\t\t? (error as { detail?: string }).detail\n\t\t\t\t\t: undefined;\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\tmessage: error instanceof Error ? error.message : \"Failed to create record\",\n\t\t\t\t\tdetail: errorDetail,\n\t\t\t\t},\n\t\t\t\t500,\n\t\t\t);\n\t\t}\n\t});\n\n\t/**\n\t * Update Records\n\t * PATCH /records - Update one or more cells in a table\n\t * Body: {\n\t * tableName: string,\n\t * updates: Array<{ rowData: Record<string, unknown>, columnName: string, value: unknown }>,\n\t * primaryKey?: string (optional, defaults to 'id')\n\t * }\n\t */\n\tapi.patch(\"/records\", zValidator(\"json\", updateRecordsSchema), async (c) => {\n\t\ttry {\n\t\t\tconst body = c.req.valid(\"json\");\n\t\t\tconst { tableName, updates, primaryKey } = body;\n\n\t\t\tconsole.log(\"PATCH /records body\", { tableName, updates, primaryKey });\n\t\t\tconst result = await updateRecords({ tableName, updates, primaryKey });\n\t\t\tconsole.log(\"PATCH /records\", result);\n\t\t\treturn c.json(result);\n\t\t} catch (error) {\n\t\t\tconsole.error(\"PATCH /records error:\", error);\n\t\t\tconst errorDetail =\n\t\t\t\terror && typeof error === \"object\" && \"detail\" in error\n\t\t\t\t\t? (error as { detail?: string }).detail\n\t\t\t\t\t: undefined;\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\tmessage: error instanceof Error ? error.message : \"Failed to update records\",\n\t\t\t\t\tdetail: errorDetail,\n\t\t\t\t},\n\t\t\t\t500,\n\t\t\t);\n\t\t}\n\t});\n\n\t/**\n\t * Delete Records\n\t * DELETE /records - Delete records from a table\n\t * Body: {\n\t * tableName: string,\n\t * primaryKeys: Array<{ columnName: string, value: unknown }>,\n\t * }\n\t * Returns:\n\t * - success: true if deleted\n\t * - fkViolation: true if FK constraint prevents deletion, includes relatedRecords\n\t */\n\tapi.delete(\"/records\", zValidator(\"json\", deleteRecordsSchema), async (c) => {\n\t\ttry {\n\t\t\tconst body = c.req.valid(\"json\");\n\t\t\tconst { tableName, primaryKeys } = body;\n\n\t\t\tconsole.log(\"DELETE /records body\", { tableName, primaryKeys });\n\t\t\tconst result = await deleteRecords({ tableName, primaryKeys });\n\t\t\tconsole.log(\"DELETE /records result\", result);\n\n\t\t\t// Return 409 Conflict for FK violations\n\t\t\tif (result.fkViolation) {\n\t\t\t\treturn c.json(result, 409);\n\t\t\t}\n\n\t\t\treturn c.json(result);\n\t\t} catch (error) {\n\t\t\tconsole.error(\"DELETE /records error:\", error);\n\t\t\tconst errorDetail =\n\t\t\t\terror && typeof error === \"object\" && \"detail\" in error\n\t\t\t\t\t? (error as { detail?: string }).detail\n\t\t\t\t\t: undefined;\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\tmessage: error instanceof Error ? error.message : \"Failed to delete records\",\n\t\t\t\t\tdetail: errorDetail,\n\t\t\t\t},\n\t\t\t\t500,\n\t\t\t);\n\t\t}\n\t});\n\n\t/**\n\t * Force Delete Records (Cascade)\n\t * DELETE /records/force - Force delete records and all related FK records\n\t * Body: {\n\t * tableName: string,\n\t * primaryKeys: Array<{ columnName: string, value: unknown }>,\n\t * }\n\t */\n\tapi.delete(\"/records/force\", zValidator(\"json\", deleteRecordsSchema), async (c) => {\n\t\ttry {\n\t\t\tconst body = c.req.valid(\"json\");\n\t\t\tconst { tableName, primaryKeys } = body;\n\n\t\t\tconsole.log(\"DELETE /records/force body\", { tableName, primaryKeys });\n\t\t\tconst result = await forceDeleteRecords({ tableName, primaryKeys });\n\t\t\tconsole.log(\"DELETE /records/force result\", result);\n\n\t\t\treturn c.json(result);\n\t\t} catch (error) {\n\t\t\tconsole.error(\"DELETE /records/force error:\", error);\n\t\t\tconst errorDetail =\n\t\t\t\terror && typeof error === \"object\" && \"detail\" in error\n\t\t\t\t\t? (error as { detail?: string }).detail\n\t\t\t\t\t: undefined;\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\tmessage:\n\t\t\t\t\t\terror instanceof Error ? error.message : \"Failed to force delete records\",\n\t\t\t\t\tdetail: errorDetail,\n\t\t\t\t},\n\t\t\t\t500,\n\t\t\t);\n\t\t}\n\t});\n\n\treturn api;\n};\n","import { intro, outro } from \"@clack/prompts\";\nimport { serve } from \"@hono/node-server\";\nimport color from \"picocolors\";\n\nimport { args } from \"./cmd/args.js\";\nimport { getDatabaseUrl } from \"./cmd/get-db-url.js\";\nimport { loadEnv } from \"./cmd/load-env.js\";\nimport { showHelp } from \"./cmd/show-help.js\";\nimport { showStatus } from \"./cmd/show-status.js\";\nimport { showVersion } from \"./cmd/show-version.js\";\nimport { DEFAULTS } from \"./utils/defaults.js\";\n\nexport const main = async () => {\n\tconst { env, port, databaseUrl, varName, status, help, version } = args();\n\n\t// Handle help flag\n\tif (help) {\n\t\tshowHelp();\n\t\tprocess.exit(0);\n\t}\n\n\t// Handle version flag\n\tif (version) {\n\t\tshowVersion();\n\t\tprocess.exit(0);\n\t}\n\n\t// Handle status flag\n\tif (status) {\n\t\tawait showStatus(env, databaseUrl, varName);\n\t\tprocess.exit(0);\n\t}\n\n\tintro(color.inverse(\" db-studiox \"));\n\n\tconst PORT = port ? parseInt(port, 10) : DEFAULTS.PORT;\n\tconst VAR_NAME = varName || DEFAULTS.VAR_NAME;\n\tconst ENV = env ? await loadEnv(env) : await loadEnv(DEFAULTS.ENV);\n\tconst DATABASE_URL = databaseUrl ? databaseUrl : await getDatabaseUrl(ENV, VAR_NAME);\n\n\t// Set DATABASE_URL in process.env before importing createServer\n\t// This ensures the db pool is initialized with the correct connection string\n\tprocess.env.DATABASE_URL = DATABASE_URL;\n\n\t// Import createServer dynamically after setting DATABASE_URL\n\tconst { createServer } = await import(\"./utils/create-server.js\");\n\tconst server = createServer();\n\tserve({\n\t\tfetch: server.fetch,\n\t\tport: PORT,\n\t});\n\n\toutro(color.green(`Server running at ${color.cyan(`http://localhost:${PORT}`)}`));\n};\n\nmain().catch((err) => {\n\tconsole.error(color.red(`❌ Unexpected error: ${err.message}`));\n\tprocess.exit(1);\n});\n","import { program } from \"commander\";\n\ntype Args = {\n\tenv?: string;\n\tport?: string;\n\tdatabaseUrl?: string;\n\tvarName?: string;\n\tstatus?: boolean;\n\thelp?: boolean;\n\tversion?: boolean;\n};\n\n/**\n * Get the arguments from the command line\n */\nexport const args = () => {\n\tprogram\n\t\t.name(\"db-studio\")\n\t\t.option(\"-e, --env <path>\", \"Path to custom .env file\")\n\t\t.option(\"-p, --port <port>\", \"Port to run the server on\")\n\t\t.option(\"-d, --database-url <url>\", \"Database URL to use\")\n\t\t.option(\n\t\t\t\"-n, --var-name <name>\",\n\t\t\t\"Custom environment variable name (default: DATABASE_URL)\",\n\t\t)\n\t\t.option(\"-s, --status\", \"Show status of the server\")\n\t\t.option(\"-h, --help\", \"Show help\")\n\t\t.option(\"-v, --version\", \"Show version\")\n\t\t.parse(process.argv);\n\n\treturn program.opts<Args>();\n};\n","import { readFile } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport { cancel, isCancel, note, select, spinner, text } from \"@clack/prompts\";\nimport { type DotenvParseOutput, parse as parseDotenv } from \"dotenv\";\nimport color from \"picocolors\";\n\n/**\n * Get the database URL from the environment variables\n */\nexport const getDatabaseUrl = async (\n\tenv?: DotenvParseOutput | null,\n\tvarName?: string,\n) => {\n\tconst envVarName = varName || \"DATABASE_URL\";\n\n\tif (env?.[envVarName]) {\n\t\treturn env[envVarName];\n\t}\n\n\tconst s = spinner();\n\ts.start(\"Looking for database connection...\");\n\n\tif (!env) {\n\t\tnote(color.red(\"No .env file found in current directory\"));\n\t} else {\n\t\tnote(color.red(`${envVarName} not found in .env`));\n\t}\n\n\tconst choice = await select({\n\t\tmessage: `How do you want to provide ${envVarName}?`,\n\t\toptions: [\n\t\t\t{ value: \"manual\", label: \"Enter connection string manually\" },\n\t\t\t{ value: \"other-env\", label: \"Use different .env file\" },\n\t\t\t{ 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: any) {\n\t\t\tcancel(`Cannot read or parse file: ${color.dim(e.message)}`);\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\n\t// 3. Manual input\n\ts.stop(\"Manual input...\");\n\n\tconst dbUrl = await text({\n\t\tmessage: `Paste your ${envVarName}`,\n\t\tplaceholder: \"postgresql://user:password@localhost:5432/mydb\",\n\t\tvalidate(value: string) {\n\t\t\tif (!value.trim()) return \"Connection string is required!\";\n\t\t\ttry {\n\t\t\t\tnew URL(value); // very basic check\n\t\t\t\treturn undefined;\n\t\t\t} catch {\n\t\t\t\treturn \"Must be a valid URL format\";\n\t\t\t}\n\t\t},\n\t});\n\n\tif (isCancel(dbUrl)) {\n\t\tcancel(\"Cancelled.\");\n\t\tprocess.exit(0);\n\t}\n\n\treturn dbUrl.trim();\n};\n","import { access, readFile } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport { parse as parseDotenv } from \"dotenv\";\n\n/**\n * Load the environment variables from the file\n */\nexport const loadEnv = async (env?: string) => {\n\tconst envPath = env ? resolve(env) : resolve(process.cwd(), \".env\");\n\n\ttry {\n\t\tawait access(envPath);\n\t\tconst content = await readFile(envPath, \"utf-8\");\n\t\treturn parseDotenv(content);\n\t} catch (err) {\n\t\tif (err instanceof Error && err.message.includes(\"ENOENT\")) {\n\t\t\treturn null; // we'll handle missing file later\n\t\t}\n\t\tthrow err;\n\t}\n};\n","import { intro, outro } from \"@clack/prompts\";\nimport color from \"picocolors\";\n\n/**\n * Display help information\n */\nexport const showHelp = () => {\n\tintro(color.inverse(\" db-studio \"));\n\n\tconsole.log(color.bold(\"\\nUsage:\"));\n\tconsole.log(\" db-studio [options]\\n\");\n\n\tconsole.log(color.bold(\"Options:\"));\n\tconsole.log(\" -e, --env <path> Path to custom .env file\");\n\tconsole.log(\" -p, --port <port> Port to run the server on (default: 3333)\");\n\tconsole.log(\" -d, --database-url <url> Database URL to use\");\n\tconsole.log(\n\t\t\" -n, --var-name <name> Custom environment variable name (default: DATABASE_URL)\",\n\t);\n\tconsole.log(\" -s, --status Show status of the database connection\");\n\tconsole.log(\" -h, --help Show this help message\");\n\tconsole.log(\" -v, --version Show version number\\n\");\n\n\tconsole.log(color.bold(\"Examples:\"));\n\tconsole.log(\" db-studio\");\n\tconsole.log(\" db-studio -e .env.local\");\n\tconsole.log(\" db-studio -p 4000\");\n\tconsole.log(\" db-studio -d postgresql://user:pass@localhost:5432/mydb\");\n\tconsole.log(\" db-studio -n MY_DATABASE_URL\");\n\tconsole.log(\" db-studio -e .env.production -n PROD_DB_URL\");\n\tconsole.log(\" db-studio --status\\n\");\n\n\toutro(\n\t\tcolor.green(\"For more information, visit: https://github.com/your-repo/db-studio\"),\n\t);\n};\n","import { intro, note, outro } from \"@clack/prompts\";\nimport color from \"picocolors\";\nimport { DEFAULTS } from \"../utils/defaults.js\";\nimport { loadEnv } from \"./load-env.js\";\n\n/**\n * Show connection status\n */\nexport const showStatus = async (\n\tenv?: string,\n\tdatabaseUrl?: string,\n\tvarName?: string,\n) => {\n\tintro(color.inverse(\" db-studio \"));\n\n\tconst envVarName = varName || DEFAULTS.VAR_NAME;\n\tlet foundUrl: string | null = null;\n\n\t// Check if DATABASE_URL is provided via CLI\n\tif (databaseUrl) {\n\t\tfoundUrl = databaseUrl;\n\t} else {\n\t\t// Try to load from .env file\n\t\tconst ENV = env ? await loadEnv(env) : await loadEnv(DEFAULTS.ENV);\n\t\tif (ENV?.[envVarName]) {\n\t\t\tfoundUrl = ENV[envVarName];\n\t\t}\n\t}\n\n\tif (foundUrl) {\n\t\toutro(color.green(`✓ Database connection configured (using ${envVarName})`));\n\t} else {\n\t\tnote(color.red(`✗ ${envVarName} not found`), \"Status\");\n\t\tconsole.log(color.yellow(\"\\n To configure database connection:\"));\n\t\tconsole.log(color.dim(` • Add ${envVarName} to your .env file`));\n\t\tconsole.log(color.dim(\" • Use -d flag: db-studio -d <url>\"));\n\t\tconsole.log(color.dim(\" • Use -e flag: db-studio -e <path-to-env>\"));\n\t\tconsole.log(color.dim(\" • Use -n flag: db-studio -n <var-name>\\n\"));\n\n\t\toutro(color.yellow(\"⚠ No database connection configured\"));\n\t}\n};\n","export const DEFAULTS = {\n\tPORT: 3333,\n\tENV: \".env\",\n\tVAR_NAME: \"DATABASE_URL\",\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\": \"0.0.9\",\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\": \"tsx src/index.ts\",\n \"build\": \"tsup\",\n \"build:release\": \"tsup --minify --sourcemap\",\n \"start\": \"node dist/index.js\",\n \"check\": \"biome check --write --unsafe --verbose\"\n },\n \"dependencies\": {\n \"@clack/prompts\": \"^0.11.0\",\n \"@hono/node-server\": \"^1.19.7\",\n \"@hono/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 \"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 \"tsup\": \"^8.5.1\",\n \"tsx\": \"^4.7.1\",\n \"typescript\": \"^5.8.3\",\n \"wrangler\": \"^4.4.0\"\n }\n}"],"mappings":"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","names":["Pool","dbInstance","getPool","db","init_db","__esmMin","_target","prop","createTable","init_create_table_dao","__esmMin","init_db","tableData","client","db","tableName","fields","foreignKeys","columnDefinitions","field","columnDef","foreignKeyConstraints","fk","allDefinitions","createTableSQL","error","getForeignKeyReferences","getRelatedRecords","deleteRecords","forceDeleteRecords","init_delete_records_dao","__esmMin","init_db","tableName","db","row","primaryKeys","fkConstraints","relatedRecords","constraintsByTable","constraint","key","pkValues","pk","_tableColumn","constraints","placeholders","_","i","query","result","error","params","client","pkColumn","deleteSQL","totalRelatedDeleted","deletedTables","deleteRelatedRecursively","targetTable","targetColumn","values","nestedFks","nestedFk","selectQuery","nestedValues","deleteQuery","deleteResult","mainDeleted","insertRecord","init_insert_record_dao","__esmMin","init_db","params","tableName","data","client","db","columns","values","placeholders","_","index","columnNames","col","insertSQL","result","error","mapPostgresToDataType","pgType","normalized","DataTypes","standardizeDataTypeLabel","StandardizedDataType","init_column_types","__esmMin","getTableColumns","init_table_columns_dao","__esmMin","init_db","init_column_types","tableName","client","db","parsedEnumValues","mapPostgresToDataType","standardizeDataTypeLabel","getTablesList","init_table_list_dao","__esmMin","init_db","client","db","r","buildWhereClause","buildSortClause","getTableData","init_tables_data_dao","__esmMin","init_db","filters","conditions","values","filter","paramIndex","columnName","sorts","order","sort","tableName","page","pageSize","sortClause","whereClause","filterValues","client","db","offset","countRes","totalRows","totalPages","limitParamIndex","offsetParamIndex","updateRecords","init_update_records_dao","__esmMin","init_db","params","tableName","updates","primaryKey","client","db","updatesByRow","update","pkValue","results","totalUpdated","rowUpdates","setClauses","u","index","values","updateSQL","result","error","z","FOREIGN_KEY_ACTIONS","foreignKeyActionSchema","fieldDataSchema","foreignKeyDataSchema","createTableSchema","tableNameParamSchema","tableDataQuerySchema","insertRecordSchema","updateRecordsSchema","deleteRecordsSchema","init_create_table_type","__esmMin","val","create_server_exports","__export","createServer","path","fileURLToPath","serveStatic","zValidator","Hono","cors","getCoreDistPath","init_create_server","__esmMin","init_create_table_dao","init_delete_records_dao","init_insert_record_dao","init_table_columns_dao","init_table_list_dao","init_tables_data_dao","init_update_records_dao","init_create_table_type","__dirname","api","c","next","tablesList","getTablesList","error","errorMessage","isConnectionError","err","tableNameParamSchema","tableName","columns","getTableColumns","tableDataQuerySchema","page","pageSize","sortParam","order","filters","sort","parsed","data","getTableData","createTableSchema","body","createTable","errorDetail","insertRecordSchema","recordData","result","insertRecord","updateRecordsSchema","updates","primaryKey","updateRecords","deleteRecordsSchema","primaryKeys","deleteRecords","forceDeleteRecords","intro","outro","serve","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","dbUrl","access","readFile","resolve","parseDotenv","loadEnv","env","envPath","content","err","intro","outro","color","showHelp","intro","note","outro","color","DEFAULTS","showStatus","env","databaseUrl","varName","intro","color","envVarName","DEFAULTS","foundUrl","ENV","loadEnv","outro","note","intro","outro","color","package_default","showVersion","intro","color","outro","package_default","main","env","port","databaseUrl","varName","status","help","version","args","showHelp","showVersion","showStatus","intro","color","PORT","DEFAULTS","VAR_NAME","ENV","loadEnv","DATABASE_URL","getDatabaseUrl","createServer","server","serve","outro","err"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "db-studio",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.9",
|
|
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",
|