admindb 2.1.0 → 2.2.1
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/README.md +41 -12
- package/dist/app.d.ts +1 -69
- package/dist/app.js +3 -30
- package/dist/auth/config.d.ts +1 -19
- package/dist/auth/config.js +0 -26
- package/dist/auth/crypto.d.ts +1 -27
- package/dist/auth/crypto.js +1 -26
- package/dist/auth/index.d.ts +1 -5
- package/dist/auth/index.js +0 -1
- package/dist/auth/middleware.d.ts +1 -14
- package/dist/auth/middleware.js +0 -15
- package/dist/auth/routes.d.ts +1 -7
- package/dist/auth/routes.js +0 -8
- package/dist/auth/types.d.ts +1 -35
- package/dist/auth/types.js +1 -5
- package/dist/cli/args.d.ts +1 -45
- package/dist/cli/args.js +3 -11
- package/dist/cli/config.d.ts +1 -56
- package/dist/cli/config.js +0 -5
- package/dist/cli/index.d.ts +1 -4
- package/dist/cli/index.js +0 -1
- package/dist/cli/runner.d.ts +1 -1
- package/dist/cli/runner.js +6 -17
- package/dist/cli.d.ts +1 -2
- package/dist/cli.js +0 -1
- package/dist/data/chain.d.ts +1 -0
- package/dist/data/chain.js +707 -0
- package/dist/data/datasets.d.ts +1 -17
- package/dist/data/datasets.js +0 -4
- package/dist/data/detector.d.ts +1 -30
- package/dist/data/detector.js +53 -14
- package/dist/data/engine.d.ts +1 -10
- package/dist/data/engine.js +82 -48
- package/dist/data/index.d.ts +1 -5
- package/dist/data/index.js +1 -1
- package/dist/data/strategies.d.ts +1 -30
- package/dist/data/strategies.js +4 -8
- package/dist/data/types.d.ts +1 -73
- package/dist/data/types.js +0 -3
- package/dist/db/database.d.ts +1 -119
- package/dist/db/database.js +20 -14
- package/dist/db/export.d.ts +1 -12
- package/dist/db/export.js +54 -6
- package/dist/db/filters.d.ts +1 -22
- package/dist/db/filters.js +0 -16
- package/dist/db/index.d.ts +1 -8
- package/dist/db/index.js +0 -1
- package/dist/db/introspection.d.ts +1 -6
- package/dist/db/introspection.js +0 -5
- package/dist/db/manager.d.ts +1 -81
- package/dist/db/manager.js +13 -59
- package/dist/db/migrations.d.ts +1 -5
- package/dist/db/migrations.js +2 -5
- package/dist/db/postgres.d.ts +1 -85
- package/dist/db/postgres.js +21 -31
- package/dist/db/types.d.ts +1 -206
- package/dist/db/types.js +0 -1
- package/dist/index.d.ts +1 -23
- package/dist/index.js +0 -14
- package/dist/public/css/app.css +1 -1
- package/dist/public/js/api.js +1 -47
- package/dist/public/js/app.js +1 -262
- package/dist/public/js/browse.js +1 -1371
- package/dist/public/js/common.js +1 -0
- package/dist/public/js/databases.js +1 -235
- package/dist/public/js/designer.js +1 -258
- package/dist/public/js/forms.js +1 -826
- package/dist/public/js/home.js +1 -0
- package/dist/public/js/inspector.js +1 -638
- package/dist/public/js/query.js +1 -322
- package/dist/public/js/schema.js +1 -447
- package/dist/public/js/seed.js +1 -1090
- package/dist/routes/api/erd.d.ts +1 -0
- package/dist/routes/api/erd.js +50 -0
- package/dist/routes/api/helpers.d.ts +1 -42
- package/dist/routes/api/helpers.js +33 -3
- package/dist/routes/api/import-export.d.ts +1 -3
- package/dist/routes/api/import-export.js +0 -2
- package/dist/routes/api/index.d.ts +1 -4
- package/dist/routes/api/index.js +15 -4
- package/dist/routes/api/query.d.ts +1 -3
- package/dist/routes/api/query.js +13 -11
- package/dist/routes/api/rows.d.ts +1 -3
- package/dist/routes/api/rows.js +0 -11
- package/dist/routes/api/seed.d.ts +1 -3
- package/dist/routes/api/seed.js +79 -8
- package/dist/routes/api/tables.d.ts +1 -3
- package/dist/routes/api/tables.js +77 -6
- package/dist/routes/databases.d.ts +1 -26
- package/dist/routes/databases.js +1 -3
- package/dist/routes/index.d.ts +1 -3
- package/dist/routes/index.js +0 -1
- package/dist/routes/pages.d.ts +1 -9
- package/dist/routes/pages.js +18 -11
- package/dist/serverless.d.ts +1 -40
- package/dist/serverless.js +3 -39
- package/dist/sql/classifier.d.ts +1 -19
- package/dist/sql/classifier.js +0 -13
- package/dist/sql/error-analyzer.d.ts +1 -0
- package/dist/sql/error-analyzer.js +550 -0
- package/dist/sql/generator.d.ts +1 -81
- package/dist/sql/generator.js +0 -29
- package/dist/sql/index.d.ts +1 -2
- package/dist/sql/index.js +0 -1
- package/dist/types/api.d.ts +1 -412
- package/dist/types/api.js +0 -7
- package/dist/utils/colors.d.ts +1 -40
- package/dist/utils/colors.js +0 -10
- package/dist/utils/common.d.ts +1 -50
- package/dist/utils/common.js +19 -23
- package/dist/utils/csv.d.ts +1 -15
- package/dist/utils/csv.js +0 -13
- package/dist/utils/datatype.d.ts +1 -49
- package/dist/utils/datatype.js +0 -41
- package/dist/utils/icons.d.ts +1 -11
- package/dist/utils/icons.js +25 -16
- package/dist/utils/index.d.ts +1 -4
- package/dist/utils/index.js +0 -1
- package/dist/utils/logger.d.ts +1 -10
- package/dist/utils/logger.js +0 -4
- package/dist/views/layouts/main.hbs +14 -5
- package/dist/views/pages/databases.hbs +0 -18
- package/dist/views/pages/designer.hbs +0 -10
- package/dist/views/pages/erd.hbs +1241 -0
- package/dist/views/pages/error.hbs +0 -2
- package/dist/views/pages/form.hbs +0 -5
- package/dist/views/pages/home.hbs +98 -10
- package/dist/views/pages/info.hbs +107 -0
- package/dist/views/pages/login.hbs +0 -13
- package/dist/views/pages/query.hbs +54 -21
- package/dist/views/pages/schema.hbs +0 -20
- package/dist/views/pages/seed.hbs +435 -202
- package/dist/views/pages/table.hbs +0 -14
- package/dist/views/partials/icon.hbs +0 -1
- package/dist/views/partials/navbar.hbs +0 -6
- package/dist/views/partials/sidebar.hbs +12 -8
- package/docs/API.md +6 -1
- package/docs/EXAMPLES.md +3 -0
- package/package.json +7 -5
- package/dist/app.js.map +0 -1
- package/dist/auth/config.js.map +0 -1
- package/dist/auth/crypto.js.map +0 -1
- package/dist/auth/index.js.map +0 -1
- package/dist/auth/middleware.js.map +0 -1
- package/dist/auth/routes.js.map +0 -1
- package/dist/auth/types.js.map +0 -1
- package/dist/cli/args.js.map +0 -1
- package/dist/cli/config.js.map +0 -1
- package/dist/cli/index.js.map +0 -1
- package/dist/cli/runner.js.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/data/datasets.js.map +0 -1
- package/dist/data/detector.js.map +0 -1
- package/dist/data/engine.js.map +0 -1
- package/dist/data/index.js.map +0 -1
- package/dist/data/strategies.js.map +0 -1
- package/dist/data/types.js.map +0 -1
- package/dist/db/database.js.map +0 -1
- package/dist/db/export.js.map +0 -1
- package/dist/db/filters.js.map +0 -1
- package/dist/db/index.js.map +0 -1
- package/dist/db/introspection.js.map +0 -1
- package/dist/db/manager.js.map +0 -1
- package/dist/db/migrations.js.map +0 -1
- package/dist/db/postgres.js.map +0 -1
- package/dist/db/types.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/public/css/input.css +0 -302
- package/dist/public/js/icons.js +0 -51
- package/dist/routes/api/helpers.js.map +0 -1
- package/dist/routes/api/import-export.js.map +0 -1
- package/dist/routes/api/index.js.map +0 -1
- package/dist/routes/api/query.js.map +0 -1
- package/dist/routes/api/rows.js.map +0 -1
- package/dist/routes/api/seed.js.map +0 -1
- package/dist/routes/api/tables.js.map +0 -1
- package/dist/routes/databases.js.map +0 -1
- package/dist/routes/index.js.map +0 -1
- package/dist/routes/pages.js.map +0 -1
- package/dist/serverless.js.map +0 -1
- package/dist/sql/classifier.js.map +0 -1
- package/dist/sql/generator.js.map +0 -1
- package/dist/sql/index.js.map +0 -1
- package/dist/types/api.js.map +0 -1
- package/dist/utils/colors.js.map +0 -1
- package/dist/utils/common.js.map +0 -1
- package/dist/utils/csv.js.map +0 -1
- package/dist/utils/datatype.js.map +0 -1
- package/dist/utils/icons.js.map +0 -1
- package/dist/utils/index.js.map +0 -1
- package/dist/utils/logger.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{type ApiContext} from './helpers';import type {Router} from 'express';export declare function registerErdRoutes(router:Router,ctx:ApiContext):void;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerErdRoutes = registerErdRoutes;
|
|
4
|
+
const helpers_1 = require("./helpers");
|
|
5
|
+
function registerErdRoutes(router, ctx) {
|
|
6
|
+
const { db } = ctx;
|
|
7
|
+
router.get('/api/erd', async (_req, res) => {
|
|
8
|
+
try {
|
|
9
|
+
const tablesResult = await db.listTables();
|
|
10
|
+
if (!tablesResult.success || !tablesResult.data) {
|
|
11
|
+
return (0, helpers_1.fail)(res, tablesResult.error ?? 'Failed to list tables.', 500);
|
|
12
|
+
}
|
|
13
|
+
const tableNames = tablesResult.data.map((t) => t.name);
|
|
14
|
+
const tableDetails = await Promise.all(tableNames.map(async (name) => {
|
|
15
|
+
const infoResult = await db.getTableInfo(name);
|
|
16
|
+
if (!infoResult.success || !infoResult.data) {
|
|
17
|
+
return {
|
|
18
|
+
name,
|
|
19
|
+
columns: [],
|
|
20
|
+
foreignKeys: [],
|
|
21
|
+
primaryKey: [],
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
const { columns, foreignKeys, primaryKey } = infoResult.data;
|
|
25
|
+
return {
|
|
26
|
+
name,
|
|
27
|
+
columns: columns.map((c) => ({
|
|
28
|
+
name: c.name,
|
|
29
|
+
type: c.type,
|
|
30
|
+
pk: c.pk,
|
|
31
|
+
notnull: c.notnull,
|
|
32
|
+
dflt_value: c.dflt_value,
|
|
33
|
+
})),
|
|
34
|
+
foreignKeys: foreignKeys.map((fk) => ({
|
|
35
|
+
from: fk.from,
|
|
36
|
+
table: fk.table,
|
|
37
|
+
to: fk.to ?? '',
|
|
38
|
+
on_delete: fk.on_delete,
|
|
39
|
+
on_update: fk.on_update,
|
|
40
|
+
})),
|
|
41
|
+
primaryKey,
|
|
42
|
+
};
|
|
43
|
+
}));
|
|
44
|
+
(0, helpers_1.ok)(res, { tables: tableDetails });
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
(0, helpers_1.fail)(res, err.message ?? 'Unknown error.', 500);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
}
|
|
@@ -1,42 +1 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { IDatabase, TableInfoData, WhereClause } from '../../db/index';
|
|
3
|
-
import type { Logger } from '../../utils/logger';
|
|
4
|
-
import { type ColumnPlan } from '../../data/index';
|
|
5
|
-
export interface ApiContext {
|
|
6
|
-
db: IDatabase;
|
|
7
|
-
logger: Logger;
|
|
8
|
-
}
|
|
9
|
-
export declare function ok(res: Response, data: unknown, status?: number): Response;
|
|
10
|
-
export declare function fail(res: Response, error: string, status?: number): Response;
|
|
11
|
-
export declare function wrap(fn: (req: Request, res: Response) => unknown): (req: Request, res: Response) => Promise<void>;
|
|
12
|
-
export declare function requireTable(db: IDatabase, table: string): Promise<TableInfoData | null>;
|
|
13
|
-
export declare function buildFields(info: TableInfoData, values: Record<string, unknown>, opts?: {
|
|
14
|
-
excludePk?: boolean;
|
|
15
|
-
}): {
|
|
16
|
-
column: string;
|
|
17
|
-
value: unknown;
|
|
18
|
-
}[];
|
|
19
|
-
export declare function buildUpdateFields(info: TableInfoData, values: Record<string, unknown>, nulls: string[]): {
|
|
20
|
-
column: string;
|
|
21
|
-
value: unknown;
|
|
22
|
-
}[];
|
|
23
|
-
export declare function pkWhere(info: TableInfoData, encodedId: string): {
|
|
24
|
-
column: string;
|
|
25
|
-
value: unknown;
|
|
26
|
-
}[] | null;
|
|
27
|
-
export declare const MAX_BULK_ROWS = 1000;
|
|
28
|
-
export declare function parseSeedRequest(body: unknown): {
|
|
29
|
-
count: number;
|
|
30
|
-
plan: Record<string, ColumnPlan>;
|
|
31
|
-
truncate: boolean;
|
|
32
|
-
};
|
|
33
|
-
export declare function resolvePkRows(info: TableInfoData, ids: unknown): WhereClause[][] | null;
|
|
34
|
-
export declare function computeBulkImpact(db: IDatabase, info: TableInfoData, wheres: WhereClause[][]): Promise<{
|
|
35
|
-
references: {
|
|
36
|
-
table: string;
|
|
37
|
-
from: string;
|
|
38
|
-
to: string;
|
|
39
|
-
count: number;
|
|
40
|
-
}[];
|
|
41
|
-
total: number;
|
|
42
|
-
}>;
|
|
1
|
+
import type {Request,Response} from 'express';import type {IDatabase,TableInfoData,WhereClause} from '../../db/index';import type {Logger} from '../../utils/logger';import{type ColumnPlan,type ErChainScope} from '../../data/index';export interface ApiContext{db:IDatabase;logger:Logger;}export declare function ok(res:Response,data:unknown,status?:number):Response;export declare function fail(res:Response,error:string,status?:number,details?:Record<string,unknown>|null):Response;export declare function wrap(fn:(req:Request,res:Response)=>unknown):(req:Request,res:Response)=>Promise<void>;export declare function requireTable(db:IDatabase,table:string):Promise<TableInfoData|null>;export declare function buildFields(info:TableInfoData,values:Record<string,unknown>,opts?:{excludePk?:boolean;}):{column:string;value:unknown;}[];export declare function buildUpdateFields(info:TableInfoData,values:Record<string,unknown>,nulls:string[]):{column:string;value:unknown;}[];export declare function pkWhere(info:TableInfoData,encodedId:string):{column:string;value:unknown;}[]|null;export declare const MAX_BULK_ROWS=1000;export declare function parseSeedRequest(body:unknown):{count:number;plan:Record<string,ColumnPlan>;truncate:boolean;};export declare function parseChainSeedRequest(body:unknown):{scope:ErChainScope;counts:Record<string,number>;plans:Record<string,Record<string,ColumnPlan>>;truncate:boolean;};export declare function resolvePkRows(info:TableInfoData,ids:unknown):WhereClause[][]|null;export declare function computeBulkImpact(db:IDatabase,info:TableInfoData,wheres:WhereClause[][]):Promise<{references:{table:string; from :string;to:string;count:number;}[];total:number;}>;
|
|
@@ -9,6 +9,7 @@ exports.buildFields = buildFields;
|
|
|
9
9
|
exports.buildUpdateFields = buildUpdateFields;
|
|
10
10
|
exports.pkWhere = pkWhere;
|
|
11
11
|
exports.parseSeedRequest = parseSeedRequest;
|
|
12
|
+
exports.parseChainSeedRequest = parseChainSeedRequest;
|
|
12
13
|
exports.resolvePkRows = resolvePkRows;
|
|
13
14
|
exports.computeBulkImpact = computeBulkImpact;
|
|
14
15
|
const common_1 = require("../../utils/common");
|
|
@@ -17,8 +18,8 @@ const generator_1 = require("../../sql/generator");
|
|
|
17
18
|
function ok(res, data, status = 200) {
|
|
18
19
|
return res.status(status).json({ success: true, data });
|
|
19
20
|
}
|
|
20
|
-
function fail(res, error, status = 400) {
|
|
21
|
-
return res.status(status).json({ success: false, error });
|
|
21
|
+
function fail(res, error, status = 400, details) {
|
|
22
|
+
return res.status(status).json({ success: false, error, ...(details ? { details } : {}) });
|
|
22
23
|
}
|
|
23
24
|
function wrap(fn) {
|
|
24
25
|
return async (req, res) => {
|
|
@@ -89,6 +90,36 @@ function parseSeedRequest(body) {
|
|
|
89
90
|
}
|
|
90
91
|
return { count, plan, truncate };
|
|
91
92
|
}
|
|
93
|
+
function parseChainSeedRequest(body) {
|
|
94
|
+
const b = (body ?? {});
|
|
95
|
+
const scope = b.scope === 'ancestors' || b.scope === 'descendants' || b.scope === 'all' || b.scope === 'single'
|
|
96
|
+
? b.scope
|
|
97
|
+
: 'chain';
|
|
98
|
+
const truncate = Boolean(b.truncate);
|
|
99
|
+
const counts = {};
|
|
100
|
+
if (b.counts && typeof b.counts === 'object') {
|
|
101
|
+
for (const [table, rawN] of Object.entries(b.counts)) {
|
|
102
|
+
const n = Number.parseInt(String(rawN), 10);
|
|
103
|
+
if (Number.isFinite(n) && n > 0)
|
|
104
|
+
counts[table] = Math.min(2000, n);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
const plans = {};
|
|
108
|
+
if (b.plans && typeof b.plans === 'object') {
|
|
109
|
+
for (const [table, tablePlans] of Object.entries(b.plans)) {
|
|
110
|
+
if (tablePlans && typeof tablePlans === 'object') {
|
|
111
|
+
const pMap = {};
|
|
112
|
+
for (const [col, v] of Object.entries(tablePlans)) {
|
|
113
|
+
const p = (0, index_1.sanitizeColumnPlan)(v);
|
|
114
|
+
if (p)
|
|
115
|
+
pMap[col] = p;
|
|
116
|
+
}
|
|
117
|
+
plans[table] = pMap;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return { scope, counts, plans, truncate };
|
|
122
|
+
}
|
|
92
123
|
function resolvePkRows(info, ids) {
|
|
93
124
|
const list = Array.isArray(ids) ? ids : ids == null ? [] : [ids];
|
|
94
125
|
const out = [];
|
|
@@ -130,4 +161,3 @@ async function computeBulkImpact(db, info, wheres) {
|
|
|
130
161
|
const total = results.reduce((acc, r) => acc + r.count, 0);
|
|
131
162
|
return { references: results, total };
|
|
132
163
|
}
|
|
133
|
-
//# sourceMappingURL=helpers.js.map
|
|
@@ -1,3 +1 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import { type ApiContext } from './helpers';
|
|
3
|
-
export declare function registerImportExportRoutes(router: Router, ctx: ApiContext): void;
|
|
1
|
+
import type {Router} from 'express';import{type ApiContext} from './helpers';export declare function registerImportExportRoutes(router:Router,ctx:ApiContext):void;
|
|
@@ -6,7 +6,6 @@ const csv_1 = require("../../utils/csv");
|
|
|
6
6
|
const helpers_1 = require("./helpers");
|
|
7
7
|
function registerImportExportRoutes(router, ctx) {
|
|
8
8
|
const { db } = ctx;
|
|
9
|
-
// ---- Export / Import ---------------------------------------------------
|
|
10
9
|
router.get('/api/tables/:table/export', (0, helpers_1.wrap)(async (req, res) => {
|
|
11
10
|
const info = await (0, helpers_1.requireTable)(db, req.params.table);
|
|
12
11
|
if (!info)
|
|
@@ -82,4 +81,3 @@ function registerImportExportRoutes(router, ctx) {
|
|
|
82
81
|
res.send((0, csv_1.toCsv)(rows, columns));
|
|
83
82
|
}));
|
|
84
83
|
}
|
|
85
|
-
//# sourceMappingURL=import-export.js.map
|
|
@@ -1,4 +1 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import { type ApiContext } from './helpers';
|
|
3
|
-
export { type ApiContext } from './helpers';
|
|
4
|
-
export declare function registerApi(router: Router, ctx: ApiContext): void;
|
|
1
|
+
import type {Router} from 'express';import{type ApiContext} from './helpers';export{type ApiContext} from './helpers';export declare function registerApi(router:Router,ctx:ApiContext):void;
|
package/dist/routes/api/index.js
CHANGED
|
@@ -6,11 +6,10 @@ const rows_1 = require("./rows");
|
|
|
6
6
|
const import_export_1 = require("./import-export");
|
|
7
7
|
const seed_1 = require("./seed");
|
|
8
8
|
const query_1 = require("./query");
|
|
9
|
+
const erd_1 = require("./erd");
|
|
10
|
+
const export_1 = require("../../db/export");
|
|
9
11
|
function registerApi(router, ctx) {
|
|
10
12
|
const { db } = ctx;
|
|
11
|
-
// In read-only mode every mutating request is rejected (GET, the generate-only
|
|
12
|
-
// preview endpoints and the query runner stay available; the query runner
|
|
13
|
-
// rejects write statements itself).
|
|
14
13
|
router.use((req, res, next) => {
|
|
15
14
|
if (!db.isReadOnly || req.method === 'GET')
|
|
16
15
|
return next();
|
|
@@ -33,5 +32,17 @@ function registerApi(router, ctx) {
|
|
|
33
32
|
(0, import_export_1.registerImportExportRoutes)(router, ctx);
|
|
34
33
|
(0, seed_1.registerSeedRoutes)(router, ctx);
|
|
35
34
|
(0, query_1.registerQueryRoutes)(router, ctx);
|
|
35
|
+
(0, erd_1.registerErdRoutes)(router, ctx);
|
|
36
|
+
router.get('/api/info/ddl', async (_req, res) => {
|
|
37
|
+
try {
|
|
38
|
+
const dump = await (0, export_1.generateSchemaDump)(db);
|
|
39
|
+
if (!dump.success) {
|
|
40
|
+
return res.status(500).json({ success: false, error: dump.error });
|
|
41
|
+
}
|
|
42
|
+
res.json({ success: true, data: dump.data });
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
res.status(500).json({ success: false, error: err instanceof Error ? err.message : String(err) });
|
|
46
|
+
}
|
|
47
|
+
});
|
|
36
48
|
}
|
|
37
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1,3 +1 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import { type ApiContext } from './helpers';
|
|
3
|
-
export declare function registerQueryRoutes(router: Router, ctx: ApiContext): void;
|
|
1
|
+
import type {Router} from 'express';import{type ApiContext} from './helpers';export declare function registerQueryRoutes(router:Router,ctx:ApiContext):void;
|
package/dist/routes/api/query.js
CHANGED
|
@@ -2,24 +2,25 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.registerQueryRoutes = registerQueryRoutes;
|
|
4
4
|
const classifier_1 = require("../../sql/classifier");
|
|
5
|
+
const error_analyzer_1 = require("../../sql/error-analyzer");
|
|
5
6
|
const common_1 = require("../../utils/common");
|
|
6
7
|
const helpers_1 = require("./helpers");
|
|
7
8
|
function registerQueryRoutes(router, ctx) {
|
|
8
9
|
const { db } = ctx;
|
|
9
|
-
// ---- Query runner ------------------------------------------------------
|
|
10
10
|
router.post('/api/query', (0, helpers_1.wrap)(async (req, res) => {
|
|
11
11
|
const rawSql = String(req.body?.sql ?? '').trim();
|
|
12
12
|
if (!rawSql)
|
|
13
13
|
return (0, helpers_1.fail)(res, 'SQL query is required.');
|
|
14
14
|
const { kind } = (0, classifier_1.classifySql)(rawSql);
|
|
15
|
-
// Multi-statement script detection
|
|
16
15
|
if (db.hasMultipleStatements(rawSql)) {
|
|
17
16
|
if (db.isReadOnly) {
|
|
18
17
|
return (0, helpers_1.fail)(res, 'Database is open in read-only mode — write statements are disabled.', 403);
|
|
19
18
|
}
|
|
20
19
|
const r = await db.execResult(rawSql);
|
|
21
|
-
if (!r.success)
|
|
22
|
-
|
|
20
|
+
if (!r.success) {
|
|
21
|
+
const details = await (0, error_analyzer_1.analyzeSqlError)(rawSql, r.error ?? 'Script execution failed.', db);
|
|
22
|
+
return (0, helpers_1.fail)(res, r.error ?? 'Query failed.', 400, details);
|
|
23
|
+
}
|
|
23
24
|
return (0, helpers_1.ok)(res, {
|
|
24
25
|
kind: 'script',
|
|
25
26
|
message: 'Script executed successfully.',
|
|
@@ -27,19 +28,22 @@ function registerQueryRoutes(router, ctx) {
|
|
|
27
28
|
}
|
|
28
29
|
if (kind === 'select' || kind === 'read' || kind === 'count') {
|
|
29
30
|
const r = await db.all(rawSql);
|
|
30
|
-
if (!r.success)
|
|
31
|
-
|
|
31
|
+
if (!r.success) {
|
|
32
|
+
const details = await (0, error_analyzer_1.analyzeSqlError)(rawSql, r.error ?? 'Query execution failed.', db);
|
|
33
|
+
return (0, helpers_1.fail)(res, r.error ?? 'Query failed.', 400, details);
|
|
34
|
+
}
|
|
32
35
|
const rows = (r.data ?? []).map(common_1.normalizeRow);
|
|
33
36
|
const columns = rows.length ? Object.keys(rows[0]) : [];
|
|
34
37
|
return (0, helpers_1.ok)(res, { kind: 'select', columns, rows });
|
|
35
38
|
}
|
|
36
|
-
// write statement
|
|
37
39
|
if (db.isReadOnly) {
|
|
38
40
|
return (0, helpers_1.fail)(res, 'Database is open in read-only mode — write statements are disabled.', 403);
|
|
39
41
|
}
|
|
40
42
|
const r = await db.runWrite(rawSql);
|
|
41
|
-
if (!r.success)
|
|
42
|
-
|
|
43
|
+
if (!r.success) {
|
|
44
|
+
const details = await (0, error_analyzer_1.analyzeSqlError)(rawSql, r.error ?? 'Statement execution failed.', db);
|
|
45
|
+
return (0, helpers_1.fail)(res, r.error ?? 'Query failed.', 400, details);
|
|
46
|
+
}
|
|
43
47
|
const changes = r.data?.changes;
|
|
44
48
|
(0, helpers_1.ok)(res, {
|
|
45
49
|
kind: 'write',
|
|
@@ -47,7 +51,6 @@ function registerQueryRoutes(router, ctx) {
|
|
|
47
51
|
message: changes != null ? `${changes} row(s) affected.` : 'Statement executed successfully.',
|
|
48
52
|
});
|
|
49
53
|
}));
|
|
50
|
-
// ---- Saved queries -----------------------------------------------------
|
|
51
54
|
router.get('/api/queries', (0, helpers_1.wrap)(async (_req, res) => {
|
|
52
55
|
const r = await db.listSavedQueries();
|
|
53
56
|
if (!r.success)
|
|
@@ -73,4 +76,3 @@ function registerQueryRoutes(router, ctx) {
|
|
|
73
76
|
(0, helpers_1.ok)(res, { message: 'Query deleted.' });
|
|
74
77
|
}));
|
|
75
78
|
}
|
|
76
|
-
//# sourceMappingURL=query.js.map
|
|
@@ -1,3 +1 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import { type ApiContext } from './helpers';
|
|
3
|
-
export declare function registerRowRoutes(router: Router, ctx: ApiContext): void;
|
|
1
|
+
import type {Router} from 'express';import{type ApiContext} from './helpers';export declare function registerRowRoutes(router:Router,ctx:ApiContext):void;
|
package/dist/routes/api/rows.js
CHANGED
|
@@ -8,7 +8,6 @@ const generator_1 = require("../../sql/generator");
|
|
|
8
8
|
const helpers_1 = require("./helpers");
|
|
9
9
|
function registerRowRoutes(router, ctx) {
|
|
10
10
|
const { db } = ctx;
|
|
11
|
-
// ---- Rows --------------------------------------------------------------
|
|
12
11
|
router.get('/api/tables/:table/rows', (0, helpers_1.wrap)(async (req, res) => {
|
|
13
12
|
const page = Number.parseInt(String(req.query.page ?? '1'), 10);
|
|
14
13
|
const limit = Number.parseInt(String(req.query.limit ?? '50'), 10);
|
|
@@ -36,7 +35,6 @@ function registerRowRoutes(router, ctx) {
|
|
|
36
35
|
return (0, helpers_1.fail)(res, r.error ?? 'Failed to count rows.');
|
|
37
36
|
(0, helpers_1.ok)(res, { count: r.data });
|
|
38
37
|
}));
|
|
39
|
-
// Fetch single row
|
|
40
38
|
router.get('/api/tables/:table/row/:id', (0, helpers_1.wrap)(async (req, res) => {
|
|
41
39
|
const info = await (0, helpers_1.requireTable)(db, req.params.table);
|
|
42
40
|
if (!info)
|
|
@@ -51,7 +49,6 @@ function registerRowRoutes(router, ctx) {
|
|
|
51
49
|
return (0, helpers_1.fail)(res, 'Row not found.', 404);
|
|
52
50
|
(0, helpers_1.ok)(res, (0, common_1.normalizeRow)(r.data));
|
|
53
51
|
}));
|
|
54
|
-
// Serve raw BLOB binary data with auto-detected Content-Type and download support
|
|
55
52
|
router.get('/api/tables/:table/row/:id/blob/:column', (0, helpers_1.wrap)(async (req, res) => {
|
|
56
53
|
const info = await (0, helpers_1.requireTable)(db, req.params.table);
|
|
57
54
|
if (!info)
|
|
@@ -89,7 +86,6 @@ function registerRowRoutes(router, ctx) {
|
|
|
89
86
|
}
|
|
90
87
|
res.end(buf);
|
|
91
88
|
}));
|
|
92
|
-
// Return BLOB metadata and formatted hex dump
|
|
93
89
|
router.get('/api/tables/:table/row/:id/blob/:column/meta', (0, helpers_1.wrap)(async (req, res) => {
|
|
94
90
|
const info = await (0, helpers_1.requireTable)(db, req.params.table);
|
|
95
91
|
if (!info)
|
|
@@ -110,7 +106,6 @@ function registerRowRoutes(router, ctx) {
|
|
|
110
106
|
const meta = (0, datatype_1.analyzeBlob)(rawVal);
|
|
111
107
|
(0, helpers_1.ok)(res, { isNull: false, ...meta });
|
|
112
108
|
}));
|
|
113
|
-
// Update BLOB binary value directly (accepts Base64 or Hex payload)
|
|
114
109
|
router.put('/api/tables/:table/row/:id/blob/:column', (0, helpers_1.wrap)(async (req, res) => {
|
|
115
110
|
const info = await (0, helpers_1.requireTable)(db, req.params.table);
|
|
116
111
|
if (!info)
|
|
@@ -123,7 +118,6 @@ function registerRowRoutes(router, ctx) {
|
|
|
123
118
|
if (req.body?.data !== undefined) {
|
|
124
119
|
const format = req.body.format || 'base64';
|
|
125
120
|
if (format === 'base64') {
|
|
126
|
-
// Strip data:image/...;base64, prefix if present
|
|
127
121
|
const base64Str = String(req.body.data).replace(/^data:[^;]+;base64,/, '');
|
|
128
122
|
buf = Buffer.from(base64Str, 'base64');
|
|
129
123
|
}
|
|
@@ -143,7 +137,6 @@ function registerRowRoutes(router, ctx) {
|
|
|
143
137
|
return (0, helpers_1.fail)(res, updateRes.error ?? 'Failed to update BLOB.');
|
|
144
138
|
(0, helpers_1.ok)(res, { message: `Updated BLOB in column "${colName}".`, size: buf.length });
|
|
145
139
|
}));
|
|
146
|
-
// Preview generated INSERT SQL without executing
|
|
147
140
|
router.post('/api/tables/:table/rows/generate', (0, helpers_1.wrap)(async (req, res) => {
|
|
148
141
|
const info = await (0, helpers_1.requireTable)(db, req.params.table);
|
|
149
142
|
if (!info)
|
|
@@ -154,7 +147,6 @@ function registerRowRoutes(router, ctx) {
|
|
|
154
147
|
const sql = (0, generator_1.generateInsert)(req.params.table, fields);
|
|
155
148
|
(0, helpers_1.ok)(res, { sql });
|
|
156
149
|
}));
|
|
157
|
-
// Preview generated UPDATE SQL without executing
|
|
158
150
|
const generateUpdateHandler = (0, helpers_1.wrap)(async (req, res) => {
|
|
159
151
|
const info = await (0, helpers_1.requireTable)(db, req.params.table);
|
|
160
152
|
if (!info)
|
|
@@ -270,7 +262,6 @@ function registerRowRoutes(router, ctx) {
|
|
|
270
262
|
});
|
|
271
263
|
router.delete('/api/tables/:table/row/:id', deleteSingleRowHandler);
|
|
272
264
|
router.delete('/api/tables/:table/rows', deleteSingleRowHandler);
|
|
273
|
-
// ---- Row references ----------------------------------------------------
|
|
274
265
|
router.get('/api/tables/:table/rows/:id/references', (0, helpers_1.wrap)(async (req, res) => {
|
|
275
266
|
const info = await (0, helpers_1.requireTable)(db, req.params.table);
|
|
276
267
|
if (!info)
|
|
@@ -311,7 +302,6 @@ function registerRowRoutes(router, ctx) {
|
|
|
311
302
|
}
|
|
312
303
|
(0, helpers_1.ok)(res, { references: results });
|
|
313
304
|
}));
|
|
314
|
-
// ---- Bulk row operations -----------------------------------------------
|
|
315
305
|
router.post('/api/tables/:table/rows/bulk-delete', (0, helpers_1.wrap)(async (req, res) => {
|
|
316
306
|
const info = await (0, helpers_1.requireTable)(db, req.params.table);
|
|
317
307
|
if (!info)
|
|
@@ -370,4 +360,3 @@ function registerRowRoutes(router, ctx) {
|
|
|
370
360
|
res.send((0, csv_1.toCsv)(rows, columns));
|
|
371
361
|
}));
|
|
372
362
|
}
|
|
373
|
-
//# sourceMappingURL=rows.js.map
|
|
@@ -1,3 +1 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import { type ApiContext } from './helpers';
|
|
3
|
-
export declare function registerSeedRoutes(router: Router, ctx: ApiContext): void;
|
|
1
|
+
import type {Router} from 'express';import{type ApiContext} from './helpers';export declare function registerSeedRoutes(router:Router,ctx:ApiContext):void;
|
package/dist/routes/api/seed.js
CHANGED
|
@@ -6,22 +6,18 @@ const index_1 = require("../../data/index");
|
|
|
6
6
|
const helpers_1 = require("./helpers");
|
|
7
7
|
function registerSeedRoutes(router, ctx) {
|
|
8
8
|
const { db } = ctx;
|
|
9
|
-
// ---- Data generator / seeder ------------------------------------------
|
|
10
|
-
// Per-column generator config (strategies + detected defaults) for the "Seed data" page
|
|
11
9
|
router.get('/api/tables/:table/seed/config', (0, helpers_1.wrap)(async (req, res) => {
|
|
12
10
|
const info = await (0, helpers_1.requireTable)(db, req.params.table);
|
|
13
11
|
if (!info)
|
|
14
12
|
return (0, helpers_1.fail)(res, `Table "${req.params.table}" does not exist.`, 404);
|
|
15
13
|
(0, helpers_1.ok)(res, { table: req.params.table, columns: (0, index_1.buildColumnConfigs)(info), maxRows: index_1.MAX_SEED_ROWS });
|
|
16
14
|
}));
|
|
17
|
-
// Legacy alias for seed config
|
|
18
15
|
router.get('/api/tables/:table/seed/plan', (0, helpers_1.wrap)(async (req, res) => {
|
|
19
16
|
const info = await (0, helpers_1.requireTable)(db, req.params.table);
|
|
20
17
|
if (!info)
|
|
21
18
|
return (0, helpers_1.fail)(res, `Table "${req.params.table}" does not exist.`, 404);
|
|
22
19
|
(0, helpers_1.ok)(res, { table: req.params.table, columns: (0, index_1.buildColumnConfigs)(info), maxRows: index_1.MAX_SEED_ROWS });
|
|
23
20
|
}));
|
|
24
|
-
// Preview: generate the rows and return the INSERT statements without executing them
|
|
25
21
|
router.post('/api/tables/:table/seed/generate', (0, helpers_1.wrap)(async (req, res) => {
|
|
26
22
|
const info = await (0, helpers_1.requireTable)(db, req.params.table);
|
|
27
23
|
if (!info)
|
|
@@ -37,7 +33,6 @@ function registerSeedRoutes(router, ctx) {
|
|
|
37
33
|
warnings: gen.warnings,
|
|
38
34
|
});
|
|
39
35
|
}));
|
|
40
|
-
// Interactive grid preview
|
|
41
36
|
router.post('/api/tables/:table/seed/preview', (0, helpers_1.wrap)(async (req, res) => {
|
|
42
37
|
const info = await (0, helpers_1.requireTable)(db, req.params.table);
|
|
43
38
|
if (!info)
|
|
@@ -51,7 +46,6 @@ function registerSeedRoutes(router, ctx) {
|
|
|
51
46
|
warnings: gen.warnings,
|
|
52
47
|
});
|
|
53
48
|
}));
|
|
54
|
-
// Insert the generated rows inside a single transaction
|
|
55
49
|
router.post('/api/tables/:table/seed', (0, helpers_1.wrap)(async (req, res) => {
|
|
56
50
|
const info = await (0, helpers_1.requireTable)(db, req.params.table);
|
|
57
51
|
if (!info)
|
|
@@ -65,7 +59,7 @@ function registerSeedRoutes(router, ctx) {
|
|
|
65
59
|
return (0, helpers_1.fail)(res, clearRes.error ?? 'Failed to clear table before seeding.', 400);
|
|
66
60
|
}
|
|
67
61
|
}
|
|
68
|
-
const gen = await (0, index_1.generateRows)(db, info, configs, count, plan);
|
|
62
|
+
const gen = await (0, index_1.generateRows)(db, info, configs, count, plan, truncate);
|
|
69
63
|
const result = await db.insertRows(req.params.table, gen.rows);
|
|
70
64
|
if (!result.success)
|
|
71
65
|
return (0, helpers_1.fail)(res, result.error ?? 'Seed failed.', 400);
|
|
@@ -78,5 +72,82 @@ function registerSeedRoutes(router, ctx) {
|
|
|
78
72
|
elapsedMs,
|
|
79
73
|
}, 201);
|
|
80
74
|
}));
|
|
75
|
+
router.get('/api/tables/:table/seed/chain', (0, helpers_1.wrap)(async (req, res) => {
|
|
76
|
+
const info = await (0, helpers_1.requireTable)(db, req.params.table);
|
|
77
|
+
if (!info)
|
|
78
|
+
return (0, helpers_1.fail)(res, `Table "${req.params.table}" does not exist.`, 404);
|
|
79
|
+
const rawScope = String(req.query.scope ?? 'chain');
|
|
80
|
+
const scope = rawScope === 'ancestors' || rawScope === 'descendants' || rawScope === 'all' || rawScope === 'single'
|
|
81
|
+
? rawScope
|
|
82
|
+
: 'chain';
|
|
83
|
+
const config = await (0, index_1.getErChainConfig)(db, req.params.table, scope);
|
|
84
|
+
(0, helpers_1.ok)(res, config);
|
|
85
|
+
}));
|
|
86
|
+
router.post('/api/tables/:table/seed/chain/preview', (0, helpers_1.wrap)(async (req, res) => {
|
|
87
|
+
const info = await (0, helpers_1.requireTable)(db, req.params.table);
|
|
88
|
+
if (!info)
|
|
89
|
+
return (0, helpers_1.fail)(res, `Table "${req.params.table}" does not exist.`, 404);
|
|
90
|
+
const { scope, counts, plans } = (0, helpers_1.parseChainSeedRequest)(req.body);
|
|
91
|
+
const config = await (0, index_1.getErChainConfig)(db, req.params.table, scope);
|
|
92
|
+
const previewCounts = {};
|
|
93
|
+
for (const t of config.tables) {
|
|
94
|
+
previewCounts[t.name] = Math.min(50, counts[t.name] ?? t.suggestedCount ?? 10);
|
|
95
|
+
}
|
|
96
|
+
const gen = await (0, index_1.generateChainRows)(db, config, plans, previewCounts);
|
|
97
|
+
(0, helpers_1.ok)(res, gen);
|
|
98
|
+
}));
|
|
99
|
+
router.post('/api/tables/:table/seed/chain/generate', (0, helpers_1.wrap)(async (req, res) => {
|
|
100
|
+
const info = await (0, helpers_1.requireTable)(db, req.params.table);
|
|
101
|
+
if (!info)
|
|
102
|
+
return (0, helpers_1.fail)(res, `Table "${req.params.table}" does not exist.`, 404);
|
|
103
|
+
const { scope, counts, plans } = (0, helpers_1.parseChainSeedRequest)(req.body);
|
|
104
|
+
const config = await (0, index_1.getErChainConfig)(db, req.params.table, scope);
|
|
105
|
+
const gen = await (0, index_1.generateChainRows)(db, config, plans, counts);
|
|
106
|
+
(0, helpers_1.ok)(res, gen);
|
|
107
|
+
}));
|
|
108
|
+
router.post('/api/tables/:table/seed/chain', (0, helpers_1.wrap)(async (req, res) => {
|
|
109
|
+
const info = await (0, helpers_1.requireTable)(db, req.params.table);
|
|
110
|
+
if (!info)
|
|
111
|
+
return (0, helpers_1.fail)(res, `Table "${req.params.table}" does not exist.`, 404);
|
|
112
|
+
const { scope, counts, plans, truncate } = (0, helpers_1.parseChainSeedRequest)(req.body);
|
|
113
|
+
const config = await (0, index_1.getErChainConfig)(db, req.params.table, scope);
|
|
114
|
+
const gen = await (0, index_1.generateChainRows)(db, config, plans, counts, truncate);
|
|
115
|
+
const exec = await (0, index_1.executeChainInsert)(db, gen, truncate);
|
|
116
|
+
(0, helpers_1.ok)(res, {
|
|
117
|
+
message: `${truncate ? 'Cleared tables in reverse order and seeded' : 'Seeded'} ${exec.totalInserted} row(s) across ${Object.keys(exec.inserted).length} table(s) in ${exec.elapsedMs}ms.`,
|
|
118
|
+
inserted: exec.inserted,
|
|
119
|
+
totalInserted: exec.totalInserted,
|
|
120
|
+
elapsedMs: exec.elapsedMs,
|
|
121
|
+
warnings: exec.warnings,
|
|
122
|
+
}, 201);
|
|
123
|
+
}));
|
|
124
|
+
router.get('/api/seed/chain', (0, helpers_1.wrap)(async (req, res) => {
|
|
125
|
+
const rawRoot = String(req.query.table ?? '');
|
|
126
|
+
const rawScope = String(req.query.scope ?? (rawRoot ? 'chain' : 'all'));
|
|
127
|
+
const scope = rawScope === 'ancestors' || rawScope === 'descendants' || rawScope === 'all' || rawScope === 'single'
|
|
128
|
+
? rawScope
|
|
129
|
+
: 'all';
|
|
130
|
+
const rootTable = rawRoot || (await db.listTables()).data?.[0]?.name || '';
|
|
131
|
+
if (!rootTable)
|
|
132
|
+
return (0, helpers_1.fail)(res, 'No tables found in database.', 404);
|
|
133
|
+
const config = await (0, index_1.getErChainConfig)(db, rootTable, scope);
|
|
134
|
+
(0, helpers_1.ok)(res, config);
|
|
135
|
+
}));
|
|
136
|
+
router.post('/api/seed/chain', (0, helpers_1.wrap)(async (req, res) => {
|
|
137
|
+
const { scope, counts, plans, truncate } = (0, helpers_1.parseChainSeedRequest)(req.body);
|
|
138
|
+
const rawRoot = String(req.body?.rootTable ?? '');
|
|
139
|
+
const rootTable = rawRoot || (await db.listTables()).data?.[0]?.name || '';
|
|
140
|
+
if (!rootTable)
|
|
141
|
+
return (0, helpers_1.fail)(res, 'No tables found in database.', 404);
|
|
142
|
+
const config = await (0, index_1.getErChainConfig)(db, rootTable, scope);
|
|
143
|
+
const gen = await (0, index_1.generateChainRows)(db, config, plans, counts, truncate);
|
|
144
|
+
const exec = await (0, index_1.executeChainInsert)(db, gen, truncate);
|
|
145
|
+
(0, helpers_1.ok)(res, {
|
|
146
|
+
message: `${truncate ? 'Cleared tables in reverse order and seeded' : 'Seeded'} ${exec.totalInserted} row(s) across ${Object.keys(exec.inserted).length} table(s) in ${exec.elapsedMs}ms.`,
|
|
147
|
+
inserted: exec.inserted,
|
|
148
|
+
totalInserted: exec.totalInserted,
|
|
149
|
+
elapsedMs: exec.elapsedMs,
|
|
150
|
+
warnings: exec.warnings,
|
|
151
|
+
}, 201);
|
|
152
|
+
}));
|
|
81
153
|
}
|
|
82
|
-
//# sourceMappingURL=seed.js.map
|
|
@@ -1,3 +1 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import { type ApiContext } from './helpers';
|
|
3
|
-
export declare function registerTableRoutes(router: Router, ctx: ApiContext): void;
|
|
1
|
+
import type {Router} from 'express';import{type ApiContext} from './helpers';export declare function registerTableRoutes(router:Router,ctx:ApiContext):void;
|
|
@@ -5,7 +5,6 @@ const generator_1 = require("../../sql/generator");
|
|
|
5
5
|
const helpers_1 = require("./helpers");
|
|
6
6
|
function registerTableRoutes(router, ctx) {
|
|
7
7
|
const { db } = ctx;
|
|
8
|
-
// ---- Tables ------------------------------------------------------------
|
|
9
8
|
router.get('/api/tables', (0, helpers_1.wrap)(async (_req, res) => {
|
|
10
9
|
const r = await db.listTables();
|
|
11
10
|
if (!r.success)
|
|
@@ -40,7 +39,6 @@ function registerTableRoutes(router, ctx) {
|
|
|
40
39
|
}
|
|
41
40
|
}
|
|
42
41
|
catch {
|
|
43
|
-
// FK option loading is best-effort.
|
|
44
42
|
}
|
|
45
43
|
}
|
|
46
44
|
(0, helpers_1.ok)(res, options);
|
|
@@ -68,7 +66,83 @@ function registerTableRoutes(router, ctx) {
|
|
|
68
66
|
return (0, helpers_1.fail)(res, r.error ?? 'Failed to drop table.');
|
|
69
67
|
(0, helpers_1.ok)(res, { message: `Table "${req.params.table}" dropped.` });
|
|
70
68
|
}));
|
|
71
|
-
|
|
69
|
+
router.post('/api/tables/bulk-drop', (0, helpers_1.wrap)(async (req, res) => {
|
|
70
|
+
const tables = Array.isArray(req.body?.tables)
|
|
71
|
+
? req.body.tables.filter((t) => typeof t === 'string' && t.trim().length > 0)
|
|
72
|
+
: [];
|
|
73
|
+
const force = Boolean(req.body?.force);
|
|
74
|
+
if (tables.length === 0)
|
|
75
|
+
return (0, helpers_1.fail)(res, 'No tables specified.');
|
|
76
|
+
const dropped = [];
|
|
77
|
+
const failed = [];
|
|
78
|
+
if (force && db.dialect === 'sqlite') {
|
|
79
|
+
await db.run('PRAGMA foreign_keys = OFF');
|
|
80
|
+
}
|
|
81
|
+
for (const table of tables) {
|
|
82
|
+
try {
|
|
83
|
+
if (force && db.dialect === 'postgres') {
|
|
84
|
+
const r = await db.run(`DROP TABLE IF EXISTS ${(0, generator_1.quoteIdentifier)(table)} CASCADE`);
|
|
85
|
+
if (!r.success)
|
|
86
|
+
throw new Error(r.error ?? 'Failed to drop table.');
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
const r = await db.dropTable(table);
|
|
90
|
+
if (!r.success)
|
|
91
|
+
throw new Error(r.error ?? 'Failed to drop table.');
|
|
92
|
+
}
|
|
93
|
+
dropped.push(table);
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
failed.push({ table, error: err.message });
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (force && db.dialect === 'sqlite') {
|
|
100
|
+
await db.run('PRAGMA foreign_keys = ON');
|
|
101
|
+
}
|
|
102
|
+
(0, helpers_1.ok)(res, {
|
|
103
|
+
dropped,
|
|
104
|
+
failed,
|
|
105
|
+
message: `Dropped ${dropped.length} table(s)${failed.length ? `, ${failed.length} failed` : ''}.`,
|
|
106
|
+
});
|
|
107
|
+
}));
|
|
108
|
+
router.post('/api/tables/bulk-truncate', (0, helpers_1.wrap)(async (req, res) => {
|
|
109
|
+
const tables = Array.isArray(req.body?.tables)
|
|
110
|
+
? req.body.tables.filter((t) => typeof t === 'string' && t.trim().length > 0)
|
|
111
|
+
: [];
|
|
112
|
+
const force = Boolean(req.body?.force);
|
|
113
|
+
if (tables.length === 0)
|
|
114
|
+
return (0, helpers_1.fail)(res, 'No tables specified.');
|
|
115
|
+
const cleared = [];
|
|
116
|
+
const failed = [];
|
|
117
|
+
if (force && db.dialect === 'sqlite') {
|
|
118
|
+
await db.run('PRAGMA foreign_keys = OFF');
|
|
119
|
+
}
|
|
120
|
+
for (const table of tables) {
|
|
121
|
+
try {
|
|
122
|
+
let r;
|
|
123
|
+
if (force && db.dialect === 'postgres') {
|
|
124
|
+
r = await db.run(`TRUNCATE ${(0, generator_1.quoteIdentifier)(table)} RESTART IDENTITY CASCADE`);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
r = await db.run(`DELETE FROM ${(0, generator_1.quoteIdentifier)(table)}`);
|
|
128
|
+
}
|
|
129
|
+
if (!r.success)
|
|
130
|
+
throw new Error(r.error ?? 'Failed to clear table.');
|
|
131
|
+
cleared.push(table);
|
|
132
|
+
}
|
|
133
|
+
catch (err) {
|
|
134
|
+
failed.push({ table, error: err.message });
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (force && db.dialect === 'sqlite') {
|
|
138
|
+
await db.run('PRAGMA foreign_keys = ON');
|
|
139
|
+
}
|
|
140
|
+
(0, helpers_1.ok)(res, {
|
|
141
|
+
cleared,
|
|
142
|
+
failed,
|
|
143
|
+
message: `Cleared ${cleared.length} table(s)${failed.length ? `, ${failed.length} failed` : ''}.`,
|
|
144
|
+
});
|
|
145
|
+
}));
|
|
72
146
|
router.post('/api/tables/generate', (0, helpers_1.wrap)(async (req, res) => {
|
|
73
147
|
const name = String(req.body?.name ?? '').trim();
|
|
74
148
|
const columns = (req.body?.columns ?? []);
|
|
@@ -105,7 +179,6 @@ function registerTableRoutes(router, ctx) {
|
|
|
105
179
|
});
|
|
106
180
|
router.post('/api/tables', createTableHandler);
|
|
107
181
|
router.post('/api/tables/create', createTableHandler);
|
|
108
|
-
// ---- Columns -----------------------------------------------------------
|
|
109
182
|
router.post('/api/tables/:table/columns', (0, helpers_1.wrap)(async (req, res) => {
|
|
110
183
|
const col = req.body;
|
|
111
184
|
if (!col || !col.name)
|
|
@@ -139,7 +212,6 @@ function registerTableRoutes(router, ctx) {
|
|
|
139
212
|
return (0, helpers_1.fail)(res, r.error ?? 'Failed to drop column.');
|
|
140
213
|
(0, helpers_1.ok)(res, { message: `Column "${req.params.column}" dropped.` });
|
|
141
214
|
}));
|
|
142
|
-
// ---- Indexes -----------------------------------------------------------
|
|
143
215
|
router.post('/api/tables/:table/indexes', (0, helpers_1.wrap)(async (req, res) => {
|
|
144
216
|
const def = req.body;
|
|
145
217
|
if (!def || !Array.isArray(def.columns) || def.columns.length === 0) {
|
|
@@ -157,4 +229,3 @@ function registerTableRoutes(router, ctx) {
|
|
|
157
229
|
(0, helpers_1.ok)(res, { message: `Index "${req.params.index}" dropped.` });
|
|
158
230
|
}));
|
|
159
231
|
}
|
|
160
|
-
//# sourceMappingURL=tables.js.map
|