component rest="true" restPath="db" { /** * GET /db/test — проверить соединение */ remote any function test() httpMethod="GET" returnFormat="json" { try { queryExecute("SELECT 1"); return {"ok": true, "message": "PostgreSQL connected"}; } catch (any e) { return {"ok": false, "error": e.message}; } } /** * GET /db/tables — список таблиц */ remote any function tables() httpMethod="GET" returnFormat="json" { try { var q = queryExecute(" SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' ORDER BY table_name "); var result = []; for (var row in q) { arrayAppend(result, row.table_name); } return {"ok": true, "tables": result}; } catch (any e) { return {"ok": false, "error": e.message}; } } /** * GET /db/query?sql=SELECT... */ remote any function query(string sql) httpMethod="GET" returnFormat="json" { if (!structKeyExists(arguments, "sql") || !len(trim(arguments.sql))) { return {"ok": false, "error": "sql parameter required"}; } try { var q = queryExecute(arguments.sql); var cols = q.getColumnNames(); var rows = []; for (var r in q) { var row = {}; for (var c in cols) { row[c] = r[c]; } arrayAppend(rows, row); } return {"ok": true, "columns": cols, "rows": rows, "count": q.recordCount}; } catch (any e) { return {"ok": false, "error": e.message}; } } /** * POST /db/execute — выполнить INSERT/UPDATE/DELETE * Body: {"sql": "INSERT INTO ...", "params": [...]} */ remote any function execute() httpMethod="POST" returnFormat="json" { var body = deserializeJSON(getHttpRequestData().content); if (!structKeyExists(body, "sql") || !len(trim(body.sql))) { return {"ok": false, "error": "sql required"}; } try { var params = structKeyExists(body, "params") ? body.params : []; var q = queryExecute(body.sql, params); return {"ok": true, "affected": q.recordCount}; } catch (any e) { return {"ok": false, "error": e.message}; } } /** * GET /db/schema — создать схему contracts */ remote any function schema() httpMethod="GET" returnFormat="json" { var ddl = [ "CREATE TABLE IF NOT EXISTS documents ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), filename TEXT NOT NULL, mime_type TEXT NOT NULL, original_bytes BYTEA, parsed_text TEXT, elements_json JSONB, status TEXT DEFAULT 'uploaded', error_message TEXT, created_at TIMESTAMPTZ DEFAULT now() )", "CREATE TABLE IF NOT EXISTS contracts ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), number TEXT NOT NULL, client TEXT, date_signed DATE, status TEXT DEFAULT 'active', created_at TIMESTAMPTZ DEFAULT now() )", "CREATE TABLE IF NOT EXISTS supplements ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), contract_id UUID REFERENCES contracts(id), number TEXT, date_signed DATE, type TEXT DEFAULT 'initial', document_id UUID REFERENCES documents(id), created_at TIMESTAMPTZ DEFAULT now() )", "CREATE TABLE IF NOT EXISTS spec_rows ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), supplement_id UUID REFERENCES supplements(id), row_num INTEGER, name TEXT, price NUMERIC, qty NUMERIC, sum NUMERIC, date_start DATE, date_end DATE, created_at TIMESTAMPTZ DEFAULT now() )", "CREATE TABLE IF NOT EXISTS spec_history ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), contract_id UUID REFERENCES contracts(id), supplement_id UUID REFERENCES supplements(id), row_num INTEGER, change_type TEXT NOT NULL, old_values JSONB, new_values JSONB, created_at TIMESTAMPTZ DEFAULT now() )", "CREATE TABLE IF NOT EXISTS spec_events ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), contract_id UUID REFERENCES contracts(id), supplement_id UUID REFERENCES supplements(id), seq INTEGER NOT NULL, action TEXT NOT NULL, target_hash TEXT, new_values JSONB, comment TEXT, status TEXT DEFAULT 'applied', created_at TIMESTAMPTZ DEFAULT now(), UNIQUE(contract_id, seq) )", "CREATE TABLE IF NOT EXISTS spec_current ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), contract_id UUID REFERENCES contracts(id), name_hash TEXT NOT NULL, name TEXT, price NUMERIC, qty NUMERIC, sum NUMERIC, date_start TEXT, last_event_id UUID REFERENCES spec_events(id), updated_at TIMESTAMPTZ DEFAULT now(), UNIQUE(contract_id, name_hash) )" ]; var results = []; for (var sql in ddl) { try { queryExecute(sql); arrayAppend(results, "OK"); } catch (any e) { arrayAppend(results, e.message); } } return {"ok": true, "results": results}; } }