db-studio 0.0.6 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +112 -0
- package/dist/index.js.map +1 -0
- package/package.json +4 -4
- package/dist/create-server-D149I1Qz.mjs +0 -109
- package/dist/create-server-D149I1Qz.mjs.map +0 -1
- package/dist/index.mjs +0 -9
- package/dist/index.mjs.map +0 -1
package/dist/index.js
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
var Oe=Object.defineProperty;var E=(a,e)=>()=>(a&&(e=a(a=0)),e);var Pe=(a,e)=>{for(var t in e)Oe(a,t,{get:e[t],enumerable:!0})};import{Pool as Je}from"pg";var P,Xe,f,N=E(()=>{"use strict";P=null,Xe=()=>{if(!P){if(!process.env.DATABASE_URL)throw new Error("DATABASE_URL is not set. Please provide a database connection string.");P=new Je({connectionString:process.env.DATABASE_URL})}return P},f=new Proxy({},{get(a,e){return Xe()[e]}})});var ee,te=E(()=>{"use strict";N();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}`)||[],u=[...n,...l],i=`
|
|
3
|
+
CREATE TABLE "${t}" (
|
|
4
|
+
${u.join(`,
|
|
5
|
+
`)}
|
|
6
|
+
);
|
|
7
|
+
`;return await e.query(i),{success:!0,tableName:t,message:`Table "${t}" created successfully`}}catch(t){throw t}finally{e.release()}}});var j,Ze,re,oe,ae=E(()=>{"use strict";N();j=async a=>(await f.query(`
|
|
8
|
+
SELECT
|
|
9
|
+
tc.constraint_name,
|
|
10
|
+
tc.table_name as referencing_table,
|
|
11
|
+
kcu.column_name as referencing_column,
|
|
12
|
+
ccu.table_name AS referenced_table,
|
|
13
|
+
ccu.column_name AS referenced_column
|
|
14
|
+
FROM information_schema.table_constraints AS tc
|
|
15
|
+
JOIN information_schema.key_column_usage AS kcu
|
|
16
|
+
ON tc.constraint_name = kcu.constraint_name
|
|
17
|
+
AND tc.table_schema = kcu.table_schema
|
|
18
|
+
JOIN information_schema.constraint_column_usage AS ccu
|
|
19
|
+
ON ccu.constraint_name = tc.constraint_name
|
|
20
|
+
AND ccu.table_schema = tc.table_schema
|
|
21
|
+
WHERE tc.constraint_type = 'FOREIGN KEY'
|
|
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 j(a);if(t.length===0)return[];let r=[],o=new Map;for(let l of t){let u=`${l.referencingTable}.${l.referencingColumn}`;o.has(u)||o.set(u,[]),o.get(u)?.push(l)}let n=e.map(l=>l.value);for(let[l,u]of o){let i=u[0];if(!i||!e.find(p=>p.columnName===i.referencedColumn))continue;let d=n.map((p,y)=>`$${y+1}`).join(", "),g=`
|
|
24
|
+
SELECT * FROM "${i.referencingTable}"
|
|
25
|
+
WHERE "${i.referencingColumn}" IN (${d})
|
|
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){`${i.referencingTable}`}}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(", "),u=`
|
|
28
|
+
DELETE FROM "${e}"
|
|
29
|
+
WHERE "${o}" IN (${l})
|
|
30
|
+
RETURNING *
|
|
31
|
+
`,i=await r.query(u,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{success:!1,message:"Cannot delete: Records are referenced by other tables",fkViolation:!0,relatedRecords:await Ze(e,t)};throw 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 j(e),u=0,i=new Set,s=async(b,S,$)=>{let Ae=await j(b);for(let _ of Ae){let k=$.map((K,xe)=>`$${xe+1}`).join(", "),ke=`
|
|
32
|
+
SELECT "${_.referencedColumn}" FROM "${b}"
|
|
33
|
+
WHERE "${S}" IN (${k})
|
|
34
|
+
`,q=(await r.query(ke,$)).rows.map(({row:K})=>K[_.referencedColumn]);q.length>0&&await s(_.referencingTable,_.referencingColumn,q)}let $e=$.map((_,k)=>`$${k+1}`).join(", "),Ce=`
|
|
35
|
+
DELETE FROM "${b}"
|
|
36
|
+
WHERE "${S}" IN (${$e})
|
|
37
|
+
`,Le=await r.query(Ce,$);u+=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
|
+
DELETE FROM "${e}"
|
|
39
|
+
WHERE "${o}" IN (${d})
|
|
40
|
+
RETURNING *
|
|
41
|
+
`,p=await r.query(g,n);await r.query("COMMIT");let y=p.rowCount??0;return{success:!0,message:u>0?`Successfully deleted ${y} ${y===1?"record":"records"} from "${e}" and ${u} related ${u===1?"record":"records"} from other tables`:`Successfully deleted ${y} ${y===1?"record":"records"} from "${e}"`,deletedCount:y+u}}catch(o){throw await r.query("ROLLBACK"),o}finally{r.release()}}});var ne,se=E(()=>{"use strict";N();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(", "),u=o.map(d=>`"${d}"`).join(", "),i=`
|
|
42
|
+
INSERT INTO "${e}" (${u})
|
|
43
|
+
VALUES (${l})
|
|
44
|
+
RETURNING *
|
|
45
|
+
`,s=await r.query(i,n);return{success:!0,message:`Record inserted into "${e}" successfully`,data:s.rows[0]}}catch(o){throw 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(")?R.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"?R.number:e==="boolean"||e==="bool"?R.boolean:e==="json"||e==="jsonb"?R.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",R.text)}function ce(a){let e=a.toLowerCase().trim();return e==="integer"||e==="int"||e==="int4"||e==="serial"||e==="serial4"?m.int:e==="bigint"||e==="int8"||e==="bigserial"||e==="serial8"?m.bigint:e==="smallint"||e==="int2"?m.smallint:e==="decimal"||e.startsWith("decimal(")||e==="numeric"||e.startsWith("numeric(")?m.numeric:e==="real"||e==="float4"?m.float:e==="double precision"||e==="float8"||e==="float"?m.double:e==="money"?m.money:e==="boolean"||e==="bool"?m.boolean:e==="text"?m.text:e==="character varying"||e.startsWith("varchar")||e.startsWith("character varying(")?m.varchar:e==="character"||e.startsWith("char")||e.startsWith("character(")||e==="bpchar"?m.char:e==="json"?m.json:e==="jsonb"?m.jsonb:e==="xml"?m.xml:e==="uuid"?m.uuid:e==="date"?m.date:e==="time"||e==="time without time zone"||e.startsWith("time(")?m.time:e==="timestamp"||e==="timestamp without time zone"||e.startsWith("timestamp(")?m.timestamp:e==="timestamp with time zone"||e==="timestamptz"||e.startsWith("timestamp with time zone(")?m.timestamptz:e==="interval"||e.startsWith("interval")?m.interval:e==="bytea"?m.bytea:e==="inet"?m.inet:e==="cidr"?m.cidr:e==="macaddr"?m.macaddr:e==="macaddr8"?m.macaddr8:e==="point"?m.point:e==="line"?m.line:e==="polygon"?m.polygon:e.startsWith("array")||e.includes("[]")?m.text:e.startsWith("user-defined")||e==="enum"?m.enum:m.text}var R,m,le=E(()=>{"use strict";R={text:"text",boolean:"boolean",number:"number",enum:"enum",json:"json",date:"date",array:"array"};m={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 ue,me=E(()=>{"use strict";N();le();ue=async a=>{let e=await f.connect();try{return(await e.query(`
|
|
46
|
+
SELECT
|
|
47
|
+
c.column_name as "columnName",
|
|
48
|
+
c.data_type as "dataType",
|
|
49
|
+
c.udt_name as "udtName",
|
|
50
|
+
c.is_nullable = 'YES' as "isNullable",
|
|
51
|
+
c.column_default as "columnDefault",
|
|
52
|
+
CASE WHEN pk.column_name IS NOT NULL THEN true ELSE false END as "isPrimaryKey",
|
|
53
|
+
CASE WHEN fk.column_name IS NOT NULL THEN true ELSE false END as "isForeignKey",
|
|
54
|
+
fk.referenced_table as "referencedTable",
|
|
55
|
+
fk.referenced_column as "referencedColumn",
|
|
56
|
+
CASE
|
|
57
|
+
WHEN c.data_type = 'USER-DEFINED' THEN
|
|
58
|
+
(SELECT array_agg(e.enumlabel ORDER BY e.enumsortorder)
|
|
59
|
+
FROM pg_type t
|
|
60
|
+
JOIN pg_enum e ON t.oid = e.enumtypid
|
|
61
|
+
WHERE t.typname = c.udt_name)
|
|
62
|
+
ELSE NULL
|
|
63
|
+
END as "enumValues"
|
|
64
|
+
FROM information_schema.columns c
|
|
65
|
+
LEFT JOIN (
|
|
66
|
+
SELECT ku.column_name
|
|
67
|
+
FROM information_schema.table_constraints tc
|
|
68
|
+
JOIN information_schema.key_column_usage ku
|
|
69
|
+
ON tc.constraint_name = ku.constraint_name
|
|
70
|
+
AND tc.table_schema = ku.table_schema
|
|
71
|
+
WHERE tc.constraint_type = 'PRIMARY KEY'
|
|
72
|
+
AND tc.table_schema = 'public'
|
|
73
|
+
AND tc.table_name = $1
|
|
74
|
+
) pk ON c.column_name = pk.column_name
|
|
75
|
+
LEFT JOIN (
|
|
76
|
+
SELECT
|
|
77
|
+
kcu.column_name,
|
|
78
|
+
ccu.table_name AS referenced_table,
|
|
79
|
+
ccu.column_name AS referenced_column
|
|
80
|
+
FROM information_schema.table_constraints tc
|
|
81
|
+
JOIN information_schema.key_column_usage kcu
|
|
82
|
+
ON tc.constraint_name = kcu.constraint_name
|
|
83
|
+
AND tc.table_schema = kcu.table_schema
|
|
84
|
+
JOIN information_schema.constraint_column_usage ccu
|
|
85
|
+
ON tc.constraint_name = ccu.constraint_name
|
|
86
|
+
AND tc.table_schema = ccu.table_schema
|
|
87
|
+
WHERE tc.constraint_type = 'FOREIGN KEY'
|
|
88
|
+
AND tc.table_schema = 'public'
|
|
89
|
+
AND tc.table_name = $1
|
|
90
|
+
) fk ON c.column_name = fk.column_name
|
|
91
|
+
WHERE c.table_schema = 'public'
|
|
92
|
+
AND c.table_name = $1
|
|
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";N();de=async()=>{let a=await f.connect();try{return(await a.query(`
|
|
95
|
+
SELECT
|
|
96
|
+
t.table_name as "tableName",
|
|
97
|
+
COALESCE(s.n_live_tup, 0) as "rowCount"
|
|
98
|
+
FROM information_schema.tables t
|
|
99
|
+
LEFT JOIN pg_stat_user_tables s ON t.table_name = s.relname
|
|
100
|
+
WHERE t.table_schema = 'public'
|
|
101
|
+
AND t.table_type = 'BASE TABLE'
|
|
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";N();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:u,values:i}=et(n),s=await f.connect();try{let d=(e-1)*t,g=await s.query(`SELECT COUNT(*) as total FROM "${a}" ${u}`,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}" ${u} ${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";N();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=[],u=0;for(let[i,s]of n.entries()){let d=s.map((h,b)=>`"${h.columnName}" = $${b+1}`),g=s.map(h=>(`${h.columnName}`,h.value,h.value,h.value!==null&&typeof h.value=="object"?JSON.stringify(h.value):h.value));g.push(i);let p=`
|
|
104
|
+
UPDATE "${e}"
|
|
105
|
+
SET ${d.join(", ")}
|
|
106
|
+
WHERE "${r}" = $${g.length}
|
|
107
|
+
RETURNING *
|
|
108
|
+
`,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]),u+=y.rowCount||0}return await o.query("COMMIT"),{success:!0,message:`Successfully updated ${u} ${u===1?"row":"rows"} in "${e}"`,data:l,updatedCount:u}}catch(n){throw await o.query("ROLLBACK"),n}finally{o.release()}}});import{z as c}from"zod";var rt,he,ot,at,Ee,F,we,Ne,Te,U,ve=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()}),F=c.object({tableName:c.string().min(1,"Table name is required")}),we=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[]}})}),Ne=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()}),U=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={};Pe(Se,{createServer:()=>ct});import I from"path";import{fileURLToPath as nt}from"url";import{serveStatic as Re}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();me();pe();ge();ye();ve();De=()=>{let a=I.dirname(nt(import.meta.url));return I.resolve(a,"./core-dist")},ct=()=>{let a=new st().basePath("/");return a.use("/*",it()),a.use("/favicon.ico",Re({path:I.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("/*",Re({root:De()})),a.get("/tables",async e=>{try{let t=await de();return e.json(t)}catch(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",F),async e=>{try{let{tableName:t}=e.req.valid("param"),r=await ue(t);return e.json(r)}catch(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",F),T("query",we),async e=>{try{let{tableName:t}=e.req.valid("param"),{page:r,pageSize:o,sort:n,order:l,filters:u}=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,u);return e.json(s)}catch(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"),r=await ee(t);return e.json(r)}catch(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",Ne),async e=>{try{let t=e.req.valid("json"),{tableName:r,...o}=t,n=await ne({tableName:r,data:o});return e.json(n)}catch(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,l=await be({tableName:r,updates:o,primaryKey:n});return e.json(l)}catch(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",U),async e=>{try{let t=e.req.valid("json"),{tableName:r,primaryKeys:o}=t,n=await re({tableName:r,primaryKeys:o});return n.fkViolation?e.json(n,409):e.json(n)}catch(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",U),async e=>{try{let t=e.req.valid("json"),{tableName:r,primaryKeys:o}=t,n=await oe({tableName:r,primaryKeys:o});return e.json(n)}catch(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 ut}from"@clack/prompts";import{serve as mt}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 je}from"fs/promises";import{resolve as Fe}from"path";import{cancel as C,isCancel as x,note as M,select as Ue,spinner as Ie,text as B}from"@clack/prompts";import{parse as qe}from"dotenv";import O from"picocolors";var z=async(a,e)=>{let t=e||"DATABASE_URL";if(a?.[t])return a[t];let r=Ie();r.start("Looking for database connection..."),a?M(O.red(`${t} not found in .env`)):M(O.red("No .env file found in current directory"));let o=await Ue({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((x(o)||o==="cancel")&&(C("No database connection provided. Exiting..."),process.exit(0)),o==="other-env"){r.start("Waiting for path...");let l=await B({message:"Enter path to .env file",placeholder:"~/projects/myapp/.env.local or ./special.env",validate(i){if(!i.trim())return"Path is required"}});x(l)&&(C("Cancelled."),process.exit(0)),r.stop("Trying custom .env...");let u=Fe(l);try{let i=await je(u,"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: ${O.dim(i.message)}`),process.exit(1)}}r.stop("Manual input...");let n=await B({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 x(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 Be}from"@clack/prompts";import A from"picocolors";var G=()=>{Me(A.inverse(" db-studio ")),A.bold(`
|
|
109
|
+
Usage:`),A.bold("Options:"),A.bold("Examples:"),Be(A.green("For more information, visit: https://github.com/your-repo/db-studio"))};import{intro as ze,note as He,outro as Y}from"@clack/prompts";import w from"picocolors";var v={PORT:3333,ENV:".env",VAR_NAME:"DATABASE_URL"};var Q=async(a,e,t)=>{ze(w.inverse(" db-studio "));let r=t||v.VAR_NAME,o=null;if(e)o=e;else{let n=a?await D(a):await D(v.ENV);n?.[r]&&(o=n[r])}o?Y(w.green(`\u2713 Database connection configured (using ${r})`)):(He(w.red(`\u2717 ${r} not found`),"Status"),w.yellow(`
|
|
110
|
+
To configure database connection:`),w.dim(` \u2022 Add ${r} to your .env file`),w.dim(" \u2022 Use -d flag: db-studio -d <url>"),w.dim(" \u2022 Use -e flag: db-studio -e <path-to-env>"),w.dim(` \u2022 Use -n flag: db-studio -n <var-name>
|
|
111
|
+
`),Y(w.yellow("\u26A0 No database connection configured")))};import{intro as Ye,outro as Qe}from"@clack/prompts";import X from"picocolors";var J={name:"db-studio",workspaces:["packages/*","www"],scripts:{dev:'concurrently "bun run dev:core" "bun run dev:cli" "bun run dev:server"',"dev:core":"bun run --cwd packages/core dev","dev:server":"bun run --cwd packages/server dev","dev:www":"bun run --cwd www dev",build:'concurrently "bun run build:core" "bun run build:server" "bun run build:www"',"build:core":"bun run --cwd packages/core build","build:server":"bun run --cwd packages/server build","build:release":"bun run build:core && bun run --cwd packages/server build:release","build:www":"bun run --cwd www build","deploy:www":"bun run --cwd www deploy","deploy:www:preview":"bun run --cwd www deploy:preview",check:"bun run --cwd packages/core check && bun run --cwd packages/server check && bun run --cwd www check","check:meta":"bun run --cwd www check-meta",changeset:"changeset",version:"changeset version",release:"bun run build:release && npm publish --workspace=packages/server"},devDependencies:{"@biomejs/biome":"^2.2.6"},peerDependencies:{typescript:"^5"},overrides:{esbuild:"0.25.12"},engines:{node:">=20.x",bun:">=1.2.19"},packageManager:"bun@1.2.19",dependencies:{"@faker-js/faker":"^10.1.0","@tanstack/react-table":"^8.21.3","@tanstack/react-virtual":"^3.13.13"}};var Z=()=>{Ye(X.inverse(" db-studio ")),Qe(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 Q(a,t,r),process.exit(0)),lt(L.inverse(" db-studiox "));let u=e?parseInt(e,10):v.PORT,i=r||v.VAR_NAME,s=a?await D(a):await D(v.ENV),d=t||await z(s,i);process.env.DATABASE_URL=d;let{createServer:g}=await Promise.resolve().then(()=>(_e(),Se)),p=g();mt({fetch:p.fetch,port:u}),ut(L.green(`Server running at ${L.cyan(`http://localhost:${u}`)}`))};dt().catch(a=>{L.red(`\u274C Unexpected error: ${a.message}`),process.exit(1)});export{dt as main};
|
|
112
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +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"]}
|
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.8",
|
|
5
5
|
"description": "Modern database client for PostgreSQL with spreadsheet-like grid, AI-powered SQL assistance, ER diagrams, fast data browsing and editing. CLI tool, upcoming desktop & web versions.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"database",
|
|
@@ -42,8 +42,8 @@
|
|
|
42
42
|
],
|
|
43
43
|
"scripts": {
|
|
44
44
|
"dev": "tsx src/index.ts",
|
|
45
|
-
"build": "
|
|
46
|
-
"build:release": "
|
|
45
|
+
"build": "tsup",
|
|
46
|
+
"build:release": "tsup --minify --sourcemap",
|
|
47
47
|
"start": "node dist/index.js",
|
|
48
48
|
"check": "biome check --write --unsafe --verbose"
|
|
49
49
|
},
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"@biomejs/biome": "^2.2.6",
|
|
64
64
|
"@types/node": "^20.11.17",
|
|
65
65
|
"@types/pg": "^8.16.0",
|
|
66
|
-
"
|
|
66
|
+
"tsup": "^8.5.1",
|
|
67
67
|
"tsx": "^4.7.1",
|
|
68
68
|
"typescript": "^5.8.3",
|
|
69
69
|
"wrangler": "^4.4.0"
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import e from"node:path";import{fileURLToPath as t}from"node:url";import{serveStatic as n}from"@hono/node-server/serve-static";import{zValidator as r}from"@hono/zod-validator";import{Hono as i}from"hono";import{cors as a}from"hono/cors";import{Pool as o}from"pg";import{z as s}from"zod";let c=null;const l=()=>{if(!c){if(!process.env.DATABASE_URL)throw Error(`DATABASE_URL is not set. Please provide a database connection string.`);c=new o({connectionString:process.env.DATABASE_URL})}return c},u=new Proxy({},{get(e,t){return l()[t]}}),d=async e=>{let t=await u.connect();try{let{tableName:n,fields:r,foreignKeys:i}=e,a=r.map(e=>{let t=`"${e.columnName}" ${e.columnType}`;return e.isArray&&(t+=`[]`),e.isPrimaryKey&&(t+=` PRIMARY KEY`),e.isUnique&&!e.isPrimaryKey&&(t+=` UNIQUE`),e.isNullable||(t+=` NOT NULL`),e.isIdentity&&(t+=` GENERATED ALWAYS AS IDENTITY`),e.defaultValue&&!e.isIdentity&&(t+=` DEFAULT ${e.defaultValue}`),t}),o=i?.map(e=>`CONSTRAINT "${`fk_${n}_${e.columnName}_${e.referencedTable}_${e.referencedColumn}`}" FOREIGN KEY ("${e.columnName}") REFERENCES "${e.referencedTable}" ("${e.referencedColumn}") ON UPDATE ${e.onUpdate} ON DELETE ${e.onDelete}`)||[],s=`
|
|
3
|
-
CREATE TABLE "${n}" (
|
|
4
|
-
${[...a,...o].join(`,
|
|
5
|
-
`)}
|
|
6
|
-
);
|
|
7
|
-
`;return console.log(`Creating table with SQL:`,s),await t.query(s),{success:!0,tableName:n,message:`Table "${n}" created successfully`}}catch(e){throw console.error(`Error creating table:`,e),e}finally{t.release()}},f=async e=>(await u.query(`
|
|
8
|
-
SELECT
|
|
9
|
-
tc.constraint_name,
|
|
10
|
-
tc.table_name as referencing_table,
|
|
11
|
-
kcu.column_name as referencing_column,
|
|
12
|
-
ccu.table_name AS referenced_table,
|
|
13
|
-
ccu.column_name AS referenced_column
|
|
14
|
-
FROM information_schema.table_constraints AS tc
|
|
15
|
-
JOIN information_schema.key_column_usage AS kcu
|
|
16
|
-
ON tc.constraint_name = kcu.constraint_name
|
|
17
|
-
AND tc.table_schema = kcu.table_schema
|
|
18
|
-
JOIN information_schema.constraint_column_usage AS ccu
|
|
19
|
-
ON ccu.constraint_name = tc.constraint_name
|
|
20
|
-
AND ccu.table_schema = tc.table_schema
|
|
21
|
-
WHERE tc.constraint_type = 'FOREIGN KEY'
|
|
22
|
-
AND ccu.table_name = $1
|
|
23
|
-
`,[e])).rows.map(({row:e})=>({constraintName:e.constraint_name,referencingTable:e.referencing_table,referencingColumn:e.referencing_column,referencedTable:e.referenced_table,referencedColumn:e.referenced_column})),p=async(e,t)=>{let n=await f(e);if(n.length===0)return[];let r=[],i=new Map;for(let e of n){let t=`${e.referencingTable}.${e.referencingColumn}`;i.has(t)||i.set(t,[]),i.get(t)?.push(e)}let a=t.map(e=>e.value);for(let[e,n]of i){let e=n[0];if(!e||!t.find(t=>t.columnName===e.referencedColumn))continue;let i=a.map((e,t)=>`$${t+1}`).join(`, `),o=`
|
|
24
|
-
SELECT * FROM "${e.referencingTable}"
|
|
25
|
-
WHERE "${e.referencingColumn}" IN (${i})
|
|
26
|
-
LIMIT 100
|
|
27
|
-
`;try{let t=await u.query(o,a);t.rows.length>0&&r.push({tableName:e.referencingTable,columnName:e.referencingColumn,constraintName:e.constraintName,records:t.rows})}catch(t){console.error(`Error fetching related records from ${e.referencingTable}:`,t)}}return r},m=async e=>{let{tableName:t,primaryKeys:n}=e,r=await u.connect();try{await r.query(`BEGIN`);let e=n[0]?.columnName;if(!e)throw Error(`Primary key column name is required`);let i=n.map(e=>e.value),a=`
|
|
28
|
-
DELETE FROM "${t}"
|
|
29
|
-
WHERE "${e}" IN (${i.map((e,t)=>`$${t+1}`).join(`, `)})
|
|
30
|
-
RETURNING *
|
|
31
|
-
`;console.log(`Deleting records with SQL:`,a,`Values:`,i);let o=await r.query(a,i);return await r.query(`COMMIT`),{success:!0,message:`Successfully deleted ${o.rowCount} ${o.rowCount===1?`record`:`records`} from "${t}"`,deletedCount:o.rowCount??0}}catch(e){if(await r.query(`ROLLBACK`),e.code===`23503`)return console.log(`FK violation detected, fetching related records...`),{success:!1,message:`Cannot delete: Records are referenced by other tables`,fkViolation:!0,relatedRecords:await p(t,n)};throw console.error(`Error deleting records:`,e),e}finally{r.release()}},h=async e=>{let{tableName:t,primaryKeys:n}=e,r=await u.connect();try{await r.query(`BEGIN`);let e=n[0]?.columnName;if(!e)throw Error(`Primary key column name is required`);let i=n.map(e=>e.value),a=await f(t),o=0,s=new Set,c=async(e,t,n)=>{let i=await f(e);for(let a of i){let i=n.map((e,t)=>`$${t+1}`).join(`, `),o=`
|
|
32
|
-
SELECT "${a.referencedColumn}" FROM "${e}"
|
|
33
|
-
WHERE "${t}" IN (${i})
|
|
34
|
-
`,s=(await r.query(o,n)).rows.map(({row:e})=>e[a.referencedColumn]);s.length>0&&await c(a.referencingTable,a.referencingColumn,s)}let a=`
|
|
35
|
-
DELETE FROM "${e}"
|
|
36
|
-
WHERE "${t}" IN (${n.map((e,t)=>`$${t+1}`).join(`, `)})
|
|
37
|
-
`,l=await r.query(a,n);o+=l.rowCount??0,s.add(e)};for(let e of a)s.has(e.referencingTable)||await c(e.referencingTable,e.referencingColumn,i);let l=`
|
|
38
|
-
DELETE FROM "${t}"
|
|
39
|
-
WHERE "${e}" IN (${i.map((e,t)=>`$${t+1}`).join(`, `)})
|
|
40
|
-
RETURNING *
|
|
41
|
-
`;console.log(`Force deleting records with SQL:`,l,`Values:`,i);let u=await r.query(l,i);await r.query(`COMMIT`);let d=u.rowCount??0;return{success:!0,message:o>0?`Successfully deleted ${d} ${d===1?`record`:`records`} from "${t}" and ${o} related ${o===1?`record`:`records`} from other tables`:`Successfully deleted ${d} ${d===1?`record`:`records`} from "${t}"`,deletedCount:d+o}}catch(e){throw await r.query(`ROLLBACK`),console.error(`Error force deleting records:`,e),e}finally{r.release()}},g=async e=>{let{tableName:t,data:n}=e,r=await u.connect();try{let e=Object.keys(n),i=Object.values(n),a=e.map((e,t)=>`$${t+1}`).join(`, `),o=`
|
|
42
|
-
INSERT INTO "${t}" (${e.map(e=>`"${e}"`).join(`, `)})
|
|
43
|
-
VALUES (${a})
|
|
44
|
-
RETURNING *
|
|
45
|
-
`;console.log(`Inserting record with SQL:`,o,`Values:`,i);let s=await r.query(o,i);return{success:!0,message:`Record inserted into "${t}" successfully`,data:s.rows[0]}}catch(e){throw console.error(`Error inserting record:`,e),e}finally{r.release()}},_={text:`text`,boolean:`boolean`,number:`number`,enum:`enum`,json:`json`,date:`date`,array:`array`};function v(e){let t=e.toLowerCase().trim();return t.includes(`[]`)||t===`date`||t===`time`||t===`time without time zone`||t.startsWith(`time(`)||t===`timestamp`||t===`timestamp without time zone`||t.startsWith(`timestamp(`)||t===`timestamp with time zone`||t===`timestamptz`||t.startsWith(`timestamp with time zone(`)?_.date:t===`integer`||t===`int`||t===`int4`||t===`bigint`||t===`int8`||t===`smallint`||t===`int2`||t===`decimal`||t.startsWith(`decimal(`)||t===`numeric`||t.startsWith(`numeric(`)||t===`real`||t===`float4`||t===`double precision`||t===`float8`||t===`float`||t===`serial`||t===`serial4`||t===`bigserial`||t===`serial8`||t===`money`?_.number:t===`boolean`||t===`bool`?_.boolean:t===`json`||t===`jsonb`?_.json:(t.startsWith(`user-defined`)||t===`enum`||t===`text`||t===`xml`||t===`character varying`||t.startsWith(`varchar`)||t.startsWith(`character varying(`)||t===`character`||t.startsWith(`char`)||t.startsWith(`character(`)||t===`bpchar`||t===`uuid`||t===`interval`||t.startsWith(`interval`),_.text)}const y={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`};function b(e){let t=e.toLowerCase().trim();return t===`integer`||t===`int`||t===`int4`||t===`serial`||t===`serial4`?y.int:t===`bigint`||t===`int8`||t===`bigserial`||t===`serial8`?y.bigint:t===`smallint`||t===`int2`?y.smallint:t===`decimal`||t.startsWith(`decimal(`)||t===`numeric`||t.startsWith(`numeric(`)?y.numeric:t===`real`||t===`float4`?y.float:t===`double precision`||t===`float8`||t===`float`?y.double:t===`money`?y.money:t===`boolean`||t===`bool`?y.boolean:t===`text`?y.text:t===`character varying`||t.startsWith(`varchar`)||t.startsWith(`character varying(`)?y.varchar:t===`character`||t.startsWith(`char`)||t.startsWith(`character(`)||t===`bpchar`?y.char:t===`json`?y.json:t===`jsonb`?y.jsonb:t===`xml`?y.xml:t===`uuid`?y.uuid:t===`date`?y.date:t===`time`||t===`time without time zone`||t.startsWith(`time(`)?y.time:t===`timestamp`||t===`timestamp without time zone`||t.startsWith(`timestamp(`)?y.timestamp:t===`timestamp with time zone`||t===`timestamptz`||t.startsWith(`timestamp with time zone(`)?y.timestamptz:t===`interval`||t.startsWith(`interval`)?y.interval:t===`bytea`?y.bytea:t===`inet`?y.inet:t===`cidr`?y.cidr:t===`macaddr`?y.macaddr:t===`macaddr8`?y.macaddr8:t===`point`?y.point:t===`line`?y.line:t===`polygon`?y.polygon:t.startsWith(`array`)||t.includes(`[]`)?y.text:t.startsWith(`user-defined`)||t===`enum`?y.enum:y.text}const x=async e=>{let t=await u.connect();try{return(await t.query(`
|
|
46
|
-
SELECT
|
|
47
|
-
c.column_name as "columnName",
|
|
48
|
-
c.data_type as "dataType",
|
|
49
|
-
c.udt_name as "udtName",
|
|
50
|
-
c.is_nullable = 'YES' as "isNullable",
|
|
51
|
-
c.column_default as "columnDefault",
|
|
52
|
-
CASE WHEN pk.column_name IS NOT NULL THEN true ELSE false END as "isPrimaryKey",
|
|
53
|
-
CASE WHEN fk.column_name IS NOT NULL THEN true ELSE false END as "isForeignKey",
|
|
54
|
-
fk.referenced_table as "referencedTable",
|
|
55
|
-
fk.referenced_column as "referencedColumn",
|
|
56
|
-
CASE
|
|
57
|
-
WHEN c.data_type = 'USER-DEFINED' THEN
|
|
58
|
-
(SELECT array_agg(e.enumlabel ORDER BY e.enumsortorder)
|
|
59
|
-
FROM pg_type t
|
|
60
|
-
JOIN pg_enum e ON t.oid = e.enumtypid
|
|
61
|
-
WHERE t.typname = c.udt_name)
|
|
62
|
-
ELSE NULL
|
|
63
|
-
END as "enumValues"
|
|
64
|
-
FROM information_schema.columns c
|
|
65
|
-
LEFT JOIN (
|
|
66
|
-
SELECT ku.column_name
|
|
67
|
-
FROM information_schema.table_constraints tc
|
|
68
|
-
JOIN information_schema.key_column_usage ku
|
|
69
|
-
ON tc.constraint_name = ku.constraint_name
|
|
70
|
-
AND tc.table_schema = ku.table_schema
|
|
71
|
-
WHERE tc.constraint_type = 'PRIMARY KEY'
|
|
72
|
-
AND tc.table_schema = 'public'
|
|
73
|
-
AND tc.table_name = $1
|
|
74
|
-
) pk ON c.column_name = pk.column_name
|
|
75
|
-
LEFT JOIN (
|
|
76
|
-
SELECT
|
|
77
|
-
kcu.column_name,
|
|
78
|
-
ccu.table_name AS referenced_table,
|
|
79
|
-
ccu.column_name AS referenced_column
|
|
80
|
-
FROM information_schema.table_constraints tc
|
|
81
|
-
JOIN information_schema.key_column_usage kcu
|
|
82
|
-
ON tc.constraint_name = kcu.constraint_name
|
|
83
|
-
AND tc.table_schema = kcu.table_schema
|
|
84
|
-
JOIN information_schema.constraint_column_usage ccu
|
|
85
|
-
ON tc.constraint_name = ccu.constraint_name
|
|
86
|
-
AND tc.table_schema = ccu.table_schema
|
|
87
|
-
WHERE tc.constraint_type = 'FOREIGN KEY'
|
|
88
|
-
AND tc.table_schema = 'public'
|
|
89
|
-
AND tc.table_name = $1
|
|
90
|
-
) fk ON c.column_name = fk.column_name
|
|
91
|
-
WHERE c.table_schema = 'public'
|
|
92
|
-
AND c.table_name = $1
|
|
93
|
-
ORDER BY c.ordinal_position;
|
|
94
|
-
`,[e])).rows.map(e=>{let t=null;return e.enumValues&&(Array.isArray(e.enumValues)?t=e.enumValues:typeof e.enumValues==`string`&&(t=e.enumValues.replace(/[{}]/g,``).split(`,`).filter(Boolean))),{columnName:e.columnName,dataType:v(e.dataType),dataTypeLabel:b(e.dataType),isNullable:e.isNullable,columnDefault:e.columnDefault,isPrimaryKey:e.isPrimaryKey,isForeignKey:e.isForeignKey,referencedTable:e.referencedTable,referencedColumn:e.referencedColumn,enumValues:t}})}finally{t.release()}},S=async()=>{let e=await u.connect();try{return(await e.query(`
|
|
95
|
-
SELECT
|
|
96
|
-
t.table_name as "tableName",
|
|
97
|
-
COALESCE(s.n_live_tup, 0) as "rowCount"
|
|
98
|
-
FROM information_schema.tables t
|
|
99
|
-
LEFT JOIN pg_stat_user_tables s ON t.table_name = s.relname
|
|
100
|
-
WHERE t.table_schema = 'public'
|
|
101
|
-
AND t.table_type = 'BASE TABLE'
|
|
102
|
-
ORDER BY t.table_name;
|
|
103
|
-
`)).rows.map(e=>({tableName:e.tableName,rowCount:Number(e.rowCount)}))}finally{e.release()}},C=e=>{if(e.length===0)return{clause:``,values:[]};let t=[],n=[];for(let r of e){let e=n.length+1,i=`"${r.columnName}"`;switch(r.operator){case`=`:case`!=`:case`>`:case`>=`:case`<`:case`<=`:t.push(`${i} ${r.operator} $${e}`),n.push(r.value);break;case`is`:r.value.toLowerCase()===`null`?t.push(`${i} IS NULL`):(t.push(`${i} = $${e}`),n.push(r.value));break;case`is not`:r.value.toLowerCase()===`null`?t.push(`${i} IS NOT NULL`):(t.push(`${i} != $${e}`),n.push(r.value));break;case`like`:t.push(`${i}::text LIKE $${e}`),n.push(r.value);break;case`not like`:t.push(`${i}::text NOT LIKE $${e}`),n.push(r.value);break;case`ilike`:t.push(`${i}::text ILIKE $${e}`),n.push(r.value);break;case`not ilike`:t.push(`${i}::text NOT ILIKE $${e}`),n.push(r.value);break;default:break}}return t.length===0?{clause:``,values:[]}:{clause:`WHERE ${t.join(` AND `)}`,values:n}},w=(e,t)=>Array.isArray(e)?e.length===0?``:`ORDER BY ${e.map(e=>`"${e.columnName}" ${e.direction.toUpperCase()}`).join(`, `)}`:e&&typeof e==`string`?`ORDER BY "${e}" ${t?.toUpperCase()||`ASC`}`:``,T=async(e,t=1,n=50,r=``,i=`asc`,a=[])=>{let o=w(r,i),{clause:s,values:c}=C(a),l=await u.connect();try{let r=(t-1)*n,i=await l.query(`SELECT COUNT(*) as total FROM "${e}" ${s}`,c),a=Number(i.rows[0].total),u=Math.ceil(a/n),d=c.length+1,f=c.length+2;return{data:(await l.query(`SELECT * FROM "${e}" ${s} ${o} LIMIT $${d} OFFSET $${f}`,[...c,n,r])).rows,meta:{page:t,limit:n,total:a,totalPages:u,hasNextPage:t<u,hasPreviousPage:t>1}}}finally{l.release()}},E=async e=>{let{tableName:t,updates:n,primaryKey:r=`id`}=e,i=await u.connect();try{await i.query(`BEGIN`);let e=new Map;for(let t of n){let n=t.rowData[r];if(n===void 0)throw Error(`Primary key "${r}" not found in row data. Please ensure the row has a primary key.`);e.has(n)||e.set(n,[]),e.get(n)?.push({columnName:t.columnName,value:t.value,rowData:t.rowData})}let a=[],o=0;for(let[n,s]of e.entries()){let e=s.map((e,t)=>`"${e.columnName}" = $${t+1}`),c=s.map(e=>(console.log(`Value for ${e.columnName}:`,typeof e.value,e.value),e.value!==null&&typeof e.value==`object`?JSON.stringify(e.value):e.value));c.push(n);let l=`
|
|
104
|
-
UPDATE "${t}"
|
|
105
|
-
SET ${e.join(`, `)}
|
|
106
|
-
WHERE "${r}" = $${c.length}
|
|
107
|
-
RETURNING *
|
|
108
|
-
`;console.log(`Updating record with SQL:`,l,`Values:`,c);let u=await i.query(l,c);if(u.rowCount===0)throw Error(`Record with ${r} = ${n} not found in table "${t}"`);a.push(u.rows[0]),o+=u.rowCount||0}return await i.query(`COMMIT`),{success:!0,message:`Successfully updated ${o} ${o===1?`row`:`rows`} in "${t}"`,data:a,updatedCount:o}}catch(e){throw await i.query(`ROLLBACK`),console.error(`Error updating records:`,e),e}finally{i.release()}},D=s.enum([`CASCADE`,`SET NULL`,`SET DEFAULT`,`RESTRICT`,`NO ACTION`]),O=s.object({columnName:s.string().min(1),columnType:s.string().min(1),defaultValue:s.string(),isPrimaryKey:s.boolean(),isNullable:s.boolean(),isUnique:s.boolean(),isIdentity:s.boolean(),isArray:s.boolean()}),k=s.object({columnName:s.string().min(1),referencedTable:s.string().min(1),referencedColumn:s.string().min(1),onUpdate:D,onDelete:D}),A=s.object({tableName:s.string().min(1,`Table name is required`),fields:s.array(O).min(1,`At least one field is required`),foreignKeys:s.array(k).optional()}),j=s.object({tableName:s.string().min(1,`Table name is required`)}),M=s.object({page:s.string().optional().default(`1`).transform(Number),pageSize:s.string().optional().default(`50`).transform(Number),sort:s.string().optional().default(``),order:s.enum([`asc`,`desc`]).optional(),filters:s.string().optional().transform(e=>{if(!e)return[];try{return JSON.parse(e)}catch{return[]}})}),N=s.object({tableName:s.string().min(1,`Table name is required`)}),P=s.object({tableName:s.string().min(1,`Table name is required`),updates:s.array(s.object({rowData:s.any(),columnName:s.string().min(1),value:s.any()})).min(1,`At least one update is required`),primaryKey:s.string().optional()}),F=s.object({tableName:s.string().min(1,`Table name is required`),primaryKeys:s.array(s.object({columnName:s.string().min(1),value:s.any()})).min(1,`At least one primary key is required`)}),I=()=>{let n=e.dirname(t(import.meta.url));return e.resolve(n,`./core-dist`)},L=()=>{let t=new i().basePath(`/`);return t.use(`/*`,a()),t.use(`/favicon.ico`,n({path:e.resolve(I(),`favicon.ico`)})),t.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()}),t.use(`/*`,n({root:I()})),t.get(`/tables`,async e=>{try{let t=await S();return console.log(`GET /tables`,t),e.json(t)}catch(t){console.error(`GET /tables error:`,t);let n=t instanceof Error?t.message:`Failed to fetch tables`,r=!1;return t&&typeof t==`object`&&`code`in t?r=t.code===`ECONNREFUSED`:t&&typeof t==`object`&&`errors`in t&&Array.isArray(t.errors)&&(r=t.errors?.some(e=>e.code===`ECONNREFUSED`)??!1),r?e.json({success:!1,message:`Cannot connect to database. Please check your DATABASE_URL and ensure the database server is running.`,error:n},503):e.json({success:!1,message:n},500)}}),t.get(`/tables/:tableName/columns`,r(`param`,j),async e=>{try{let{tableName:t}=e.req.valid(`param`),n=await x(t);return console.log(`GET /tables/:tableName/columns`,n),e.json(n)}catch(t){console.error(`GET /tables/:tableName/columns error:`,t);let n=t instanceof Error?t.message:`Failed to fetch columns`,r=!1;return t&&typeof t==`object`&&`code`in t?r=t.code===`ECONNREFUSED`:t&&typeof t==`object`&&`errors`in t&&Array.isArray(t.errors)&&(r=t.errors?.some(e=>e.code===`ECONNREFUSED`)??!1),r?e.json({success:!1,message:`Cannot connect to database. Please check your DATABASE_URL and ensure the database server is running.`,error:n},503):e.json({success:!1,message:n},500)}}),t.get(`/tables/:tableName/data`,r(`param`,j),r(`query`,M),async e=>{try{let{tableName:t}=e.req.valid(`param`),{page:n,pageSize:r,sort:i,order:a,filters:o}=e.req.valid(`query`),s=``;if(i)try{let e=JSON.parse(i);s=Array.isArray(e)?e:i}catch{s=i}let c=await T(t,n,r,s,a,o);return e.json(c)}catch(t){console.error(`GET /tables/:tableName/data error:`,t);let n=t instanceof Error?t.message:`Failed to fetch table data`,r=!1;return t&&typeof t==`object`&&`code`in t?r=t.code===`ECONNREFUSED`:t&&typeof t==`object`&&`errors`in t&&Array.isArray(t.errors)&&(r=t.errors?.some(e=>e.code===`ECONNREFUSED`)??!1),r?e.json({success:!1,message:`Cannot connect to database. Please check your DATABASE_URL and ensure the database server is running.`,error:n},503):e.json({success:!1,message:n},500)}}),t.post(`/tables`,r(`json`,A),async e=>{try{let t=e.req.valid(`json`);console.log(`POST /tables body`,t);let n=await d(t);return console.log(`POST /tables`,n),e.json(n)}catch(t){console.error(`POST /tables error:`,t);let n=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:n},500)}}),t.post(`/records`,r(`json`,N),async e=>{try{let{tableName:t,...n}=e.req.valid(`json`);console.log(`POST /records body`,{tableName:t,recordData:n});let r=await g({tableName:t,data:n});return console.log(`POST /records`,r),e.json(r)}catch(t){console.error(`POST /records error:`,t);let n=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:n},500)}}),t.patch(`/records`,r(`json`,P),async e=>{try{let{tableName:t,updates:n,primaryKey:r}=e.req.valid(`json`);console.log(`PATCH /records body`,{tableName:t,updates:n,primaryKey:r});let i=await E({tableName:t,updates:n,primaryKey:r});return console.log(`PATCH /records`,i),e.json(i)}catch(t){console.error(`PATCH /records error:`,t);let n=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:n},500)}}),t.delete(`/records`,r(`json`,F),async e=>{try{let{tableName:t,primaryKeys:n}=e.req.valid(`json`);console.log(`DELETE /records body`,{tableName:t,primaryKeys:n});let r=await m({tableName:t,primaryKeys:n});return console.log(`DELETE /records result`,r),r.fkViolation?e.json(r,409):e.json(r)}catch(t){console.error(`DELETE /records error:`,t);let n=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:n},500)}}),t.delete(`/records/force`,r(`json`,F),async e=>{try{let{tableName:t,primaryKeys:n}=e.req.valid(`json`);console.log(`DELETE /records/force body`,{tableName:t,primaryKeys:n});let r=await h({tableName:t,primaryKeys:n});return console.log(`DELETE /records/force result`,r),e.json(r)}catch(t){console.error(`DELETE /records/force error:`,t);let n=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:n},500)}}),t};export{L as createServer};
|
|
109
|
-
//# sourceMappingURL=create-server-D149I1Qz.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"create-server-D149I1Qz.mjs","names":["dbInstance: Pool | null","relatedRecords: RelatedRecord[]","parsedEnumValues: string[] | null","conditions: string[]","values: unknown[]","sort: Sort[] | string"],"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"],"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"],"mappings":"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"}
|
package/dist/index.mjs
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import{cancel as e,intro as t,isCancel as n,note as r,outro as i,select as a,spinner as o,text as s}from"@clack/prompts";import{serve as c}from"@hono/node-server";import l from"picocolors";import{program as u}from"commander";import{access as d,readFile as f}from"node:fs/promises";import{resolve as p}from"node:path";import{parse as m}from"dotenv";const h=()=>(u.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),u.opts()),g=async(t,i)=>{let c=i||`DATABASE_URL`;if(t?.[c])return t[c];let u=o();u.start(`Looking for database connection...`),r(t?l.red(`${c} not found in .env`):l.red(`No .env file found in current directory`));let d=await a({message:`How do you want to provide ${c}?`,options:[{value:`manual`,label:`Enter connection string manually`},{value:`other-env`,label:`Use different .env file`},{value:`cancel`,label:`Cancel / Exit`}],initialValue:`manual`});if((n(d)||d===`cancel`)&&(e(`No database connection provided. Exiting...`),process.exit(0)),d===`other-env`){u.start(`Waiting for path...`);let t=await s({message:`Enter path to .env file`,placeholder:`~/projects/myapp/.env.local or ./special.env`,validate(e){if(!e.trim())return`Path is required`}});n(t)&&(e(`Cancelled.`),process.exit(0)),u.stop(`Trying custom .env...`);let r=p(t);try{let e=m(await f(r,`utf-8`));if(e[c])return e[c];throw Error(`${c} still missing in custom file`)}catch(t){e(`Cannot read or parse file: ${l.dim(t.message)}`),process.exit(1)}}u.stop(`Manual input...`);let h=await s({message:`Paste your ${c}`,placeholder:`postgresql://user:password@localhost:5432/mydb`,validate(e){if(!e.trim())return`Connection string is required!`;try{new URL(e);return}catch{return`Must be a valid URL format`}}});return n(h)&&(e(`Cancelled.`),process.exit(0)),h.trim()},_=async e=>{let t=e?p(e):p(process.cwd(),`.env`);try{return await d(t),m(await f(t,`utf-8`))}catch(e){if(e instanceof Error&&e.message.includes(`ENOENT`))return null;throw e}},v=()=>{t(l.inverse(` db-studio `)),console.log(l.bold(`
|
|
3
|
-
Usage:`)),console.log(` db-studio [options]
|
|
4
|
-
`),console.log(l.bold(`Options:`)),console.log(` -e, --env <path> Path to custom .env file`),console.log(` -p, --port <port> Port to run the server on (default: 3333)`),console.log(` -d, --database-url <url> Database URL to use`),console.log(` -n, --var-name <name> Custom environment variable name (default: DATABASE_URL)`),console.log(` -s, --status Show status of the database connection`),console.log(` -h, --help Show this help message`),console.log(` -v, --version Show version number
|
|
5
|
-
`),console.log(l.bold(`Examples:`)),console.log(` db-studio`),console.log(` db-studio -e .env.local`),console.log(` db-studio -p 4000`),console.log(` db-studio -d postgresql://user:pass@localhost:5432/mydb`),console.log(` db-studio -n MY_DATABASE_URL`),console.log(` db-studio -e .env.production -n PROD_DB_URL`),console.log(` db-studio --status
|
|
6
|
-
`),i(l.green(`For more information, visit: https://github.com/your-repo/db-studio`))},y={PORT:3333,ENV:`.env`,VAR_NAME:`DATABASE_URL`},b=async(e,n,a)=>{t(l.inverse(` db-studio `));let o=a||y.VAR_NAME,s=null;if(n)s=n;else{let t=e?await _(e):await _(y.ENV);t?.[o]&&(s=t[o])}s?i(l.green(`✓ Database connection configured (using ${o})`)):(r(l.red(`✗ ${o} not found`),`Status`),console.log(l.yellow(`
|
|
7
|
-
To configure database connection:`)),console.log(l.dim(` • Add ${o} to your .env file`)),console.log(l.dim(` • Use -d flag: db-studio -d <url>`)),console.log(l.dim(` • Use -e flag: db-studio -e <path-to-env>`)),console.log(l.dim(` • Use -n flag: db-studio -n <var-name>
|
|
8
|
-
`)),i(l.yellow(`⚠ No database connection configured`)))};var x={name:`db-studio`,workspaces:[`packages/*`,`www`],scripts:{dev:`concurrently "bun run dev:core" "bun run dev:cli" "bun run dev:server"`,"dev:core":`bun run --cwd packages/core dev`,"dev:server":`bun run --cwd packages/server dev`,"dev:www":`bun run --cwd www dev`,build:`concurrently "bun run build:core" "bun run build:server" "bun run build:www"`,"build:core":`bun run --cwd packages/core build`,"build:server":`bun run --cwd packages/server build`,"build:release":`bun run build:core && bun run --cwd packages/server build:release`,"build:www":`bun run --cwd www build`,"deploy:www":`bun run --cwd www deploy`,"deploy:www:preview":`bun run --cwd www deploy:preview`,check:`bun run --cwd packages/core check && bun run --cwd packages/server check && bun run --cwd www check`,"check:meta":`bun run --cwd www check-meta`,changeset:`changeset`,version:`changeset version`,release:`bun run build:release && npm publish --workspace=packages/server`},devDependencies:{"@biomejs/biome":`^2.2.6`},peerDependencies:{typescript:`^5`},overrides:{esbuild:`0.25.12`},engines:{node:`>=20.x`,bun:`>=1.2.19`},packageManager:`bun@1.2.19`,dependencies:{"@faker-js/faker":`^10.1.0`,"@tanstack/react-table":`^8.21.3`,"@tanstack/react-virtual":`^3.13.13`}};const S=()=>{t(l.inverse(` db-studio `)),i(l.green(`🚀 db-studio v${x.version}`))},C=async()=>{let{env:e,port:n,databaseUrl:r,varName:a,status:o,help:s,version:u}=h();s&&(v(),process.exit(0)),u&&(S(),process.exit(0)),o&&(await b(e,r,a),process.exit(0)),t(l.inverse(` db-studiox `));let d=n?parseInt(n,10):y.PORT,f=a||y.VAR_NAME,p=e?await _(e):await _(y.ENV),m=r||await g(p,f);process.env.DATABASE_URL=m;let{createServer:x}=await import(`./create-server-D149I1Qz.mjs`);c({fetch:x().fetch,port:d}),i(l.green(`Server running at ${l.cyan(`http://localhost:${d}`)}`))};C().catch(e=>{console.error(l.red(`❌ Unexpected error: ${e.message}`)),process.exit(1)});export{C as main};
|
|
9
|
-
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["parseDotenv","e: any","parseDotenv","foundUrl: string | null"],"sources":["../src/cmd/args.ts","../src/cmd/get-db-url.ts","../src/cmd/load-env.ts","../src/cmd/show-help.ts","../src/utils/defaults.ts","../src/cmd/show-status.ts","../../../package.json","../src/cmd/show-version.ts","../src/index.ts"],"sourcesContent":["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","export const DEFAULTS = {\n\tPORT: 3333,\n\tENV: \".env\",\n\tVAR_NAME: \"DATABASE_URL\",\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","","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","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"],"mappings":"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"}
|