admindb 2.1.0 → 2.1.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 +1 -1
- package/dist/app.d.ts +1 -69
- package/dist/app.js +1 -257
- package/dist/auth/config.d.ts +1 -19
- package/dist/auth/config.js +1 -147
- package/dist/auth/crypto.d.ts +1 -27
- package/dist/auth/crypto.js +1 -133
- package/dist/auth/index.d.ts +1 -5
- package/dist/auth/index.js +1 -22
- package/dist/auth/middleware.d.ts +1 -14
- package/dist/auth/middleware.js +1 -100
- package/dist/auth/routes.d.ts +1 -7
- package/dist/auth/routes.js +1 -78
- package/dist/auth/types.d.ts +1 -35
- package/dist/auth/types.js +1 -11
- package/dist/cli/args.d.ts +1 -45
- package/dist/cli/args.js +1 -328
- package/dist/cli/config.d.ts +1 -56
- package/dist/cli/config.js +1 -133
- package/dist/cli/index.d.ts +1 -4
- package/dist/cli/index.js +1 -21
- package/dist/cli/runner.d.ts +1 -1
- package/dist/cli/runner.js +1 -222
- package/dist/cli.d.ts +1 -2
- package/dist/cli.js +1 -5
- package/dist/data/datasets.d.ts +1 -17
- package/dist/data/datasets.js +1 -133
- package/dist/data/detector.d.ts +1 -30
- package/dist/data/detector.js +1 -472
- package/dist/data/engine.d.ts +1 -10
- package/dist/data/engine.js +1 -211
- package/dist/data/index.d.ts +1 -5
- package/dist/data/index.js +1 -22
- package/dist/data/strategies.d.ts +1 -30
- package/dist/data/strategies.js +1 -343
- package/dist/data/types.d.ts +1 -73
- package/dist/data/types.js +1 -8
- package/dist/db/database.d.ts +1 -119
- package/dist/db/database.js +1 -471
- package/dist/db/export.d.ts +1 -12
- package/dist/db/export.js +1 -42
- package/dist/db/filters.d.ts +1 -22
- package/dist/db/filters.js +1 -158
- package/dist/db/index.d.ts +1 -8
- package/dist/db/index.js +1 -25
- package/dist/db/introspection.d.ts +1 -6
- package/dist/db/introspection.js +1 -172
- package/dist/db/manager.d.ts +1 -81
- package/dist/db/manager.js +1 -397
- package/dist/db/migrations.d.ts +1 -5
- package/dist/db/migrations.js +1 -110
- package/dist/db/postgres.d.ts +1 -85
- package/dist/db/postgres.js +1 -745
- package/dist/db/types.d.ts +1 -206
- package/dist/db/types.js +1 -7
- package/dist/index.d.ts +1 -23
- package/dist/index.js +1 -66
- 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/databases.js +1 -235
- package/dist/public/js/designer.js +1 -258
- package/dist/public/js/forms.js +1 -826
- package/dist/public/js/icons.js +1 -51
- 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/helpers.d.ts +1 -42
- package/dist/routes/api/helpers.js +1 -133
- package/dist/routes/api/import-export.d.ts +1 -3
- package/dist/routes/api/import-export.js +1 -85
- package/dist/routes/api/index.d.ts +1 -4
- package/dist/routes/api/index.js +1 -37
- package/dist/routes/api/query.d.ts +1 -3
- package/dist/routes/api/query.js +1 -76
- package/dist/routes/api/rows.d.ts +1 -3
- package/dist/routes/api/rows.js +1 -373
- package/dist/routes/api/seed.d.ts +1 -3
- package/dist/routes/api/seed.js +1 -82
- package/dist/routes/api/tables.d.ts +1 -3
- package/dist/routes/api/tables.js +1 -160
- package/dist/routes/databases.d.ts +1 -26
- package/dist/routes/databases.js +1 -230
- package/dist/routes/index.d.ts +1 -3
- package/dist/routes/index.js +1 -20
- package/dist/routes/pages.d.ts +1 -9
- package/dist/routes/pages.js +1 -390
- package/dist/serverless.d.ts +1 -40
- package/dist/serverless.js +1 -210
- package/dist/sql/classifier.d.ts +1 -19
- package/dist/sql/classifier.js +1 -37
- package/dist/sql/generator.d.ts +1 -81
- package/dist/sql/generator.js +1 -348
- package/dist/sql/index.d.ts +1 -2
- package/dist/sql/index.js +1 -19
- package/dist/types/api.d.ts +1 -412
- package/dist/types/api.js +1 -9
- package/dist/utils/colors.d.ts +1 -40
- package/dist/utils/colors.js +1 -64
- package/dist/utils/common.d.ts +1 -50
- package/dist/utils/common.js +1 -229
- package/dist/utils/csv.d.ts +1 -15
- package/dist/utils/csv.js +1 -80
- package/dist/utils/datatype.d.ts +1 -49
- package/dist/utils/datatype.js +1 -222
- package/dist/utils/icons.d.ts +1 -11
- package/dist/utils/icons.js +1 -72
- package/dist/utils/index.d.ts +1 -4
- package/dist/utils/index.js +1 -21
- package/dist/utils/logger.d.ts +1 -10
- package/dist/utils/logger.js +1 -40
- package/dist/views/layouts/main.hbs +0 -4
- package/dist/views/pages/databases.hbs +0 -18
- package/dist/views/pages/designer.hbs +0 -10
- package/dist/views/pages/error.hbs +0 -2
- package/dist/views/pages/form.hbs +0 -5
- package/dist/views/pages/home.hbs +0 -8
- package/dist/views/pages/login.hbs +0 -13
- package/dist/views/pages/query.hbs +0 -9
- package/dist/views/pages/schema.hbs +0 -20
- package/dist/views/pages/seed.hbs +0 -31
- 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 +0 -8
- package/package.json +3 -2
- 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/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
package/dist/routes/api/rows.js
CHANGED
|
@@ -1,373 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.registerRowRoutes = registerRowRoutes;
|
|
4
|
-
const common_1 = require("../../utils/common");
|
|
5
|
-
const datatype_1 = require("../../utils/datatype");
|
|
6
|
-
const csv_1 = require("../../utils/csv");
|
|
7
|
-
const generator_1 = require("../../sql/generator");
|
|
8
|
-
const helpers_1 = require("./helpers");
|
|
9
|
-
function registerRowRoutes(router, ctx) {
|
|
10
|
-
const { db } = ctx;
|
|
11
|
-
// ---- Rows --------------------------------------------------------------
|
|
12
|
-
router.get('/api/tables/:table/rows', (0, helpers_1.wrap)(async (req, res) => {
|
|
13
|
-
const page = Number.parseInt(String(req.query.page ?? '1'), 10);
|
|
14
|
-
const limit = Number.parseInt(String(req.query.limit ?? '50'), 10);
|
|
15
|
-
const orderBy = req.query.orderBy ? String(req.query.orderBy) : undefined;
|
|
16
|
-
const orderDir = req.query.orderDir === 'desc' ? 'desc' : 'asc';
|
|
17
|
-
const filters = (0, common_1.parseFilters)(req.query.f);
|
|
18
|
-
const [rowsR, totalR] = await Promise.all([
|
|
19
|
-
db.getRows(req.params.table, { page, limit, orderBy, orderDir, filters }),
|
|
20
|
-
db.getRowCount(req.params.table, filters),
|
|
21
|
-
]);
|
|
22
|
-
if (!rowsR.success)
|
|
23
|
-
return (0, helpers_1.fail)(res, rowsR.error ?? 'Failed to load rows.');
|
|
24
|
-
const rows = (rowsR.data ?? []).map(common_1.normalizeRow);
|
|
25
|
-
(0, helpers_1.ok)(res, {
|
|
26
|
-
rows,
|
|
27
|
-
total: totalR.success ? totalR.data : rows.length,
|
|
28
|
-
page,
|
|
29
|
-
limit,
|
|
30
|
-
});
|
|
31
|
-
}));
|
|
32
|
-
router.get('/api/tables/:table/rows/count', (0, helpers_1.wrap)(async (req, res) => {
|
|
33
|
-
const filters = (0, common_1.parseFilters)(req.query.f);
|
|
34
|
-
const r = await db.getRowCount(req.params.table, filters);
|
|
35
|
-
if (!r.success)
|
|
36
|
-
return (0, helpers_1.fail)(res, r.error ?? 'Failed to count rows.');
|
|
37
|
-
(0, helpers_1.ok)(res, { count: r.data });
|
|
38
|
-
}));
|
|
39
|
-
// Fetch single row
|
|
40
|
-
router.get('/api/tables/:table/row/:id', (0, helpers_1.wrap)(async (req, res) => {
|
|
41
|
-
const info = await (0, helpers_1.requireTable)(db, req.params.table);
|
|
42
|
-
if (!info)
|
|
43
|
-
return (0, helpers_1.fail)(res, `Table "${req.params.table}" does not exist.`, 404);
|
|
44
|
-
const where = (0, helpers_1.pkWhere)(info, req.params.id);
|
|
45
|
-
if (!where)
|
|
46
|
-
return (0, helpers_1.fail)(res, 'Invalid primary key.', 400);
|
|
47
|
-
const r = await db.getRow(req.params.table, where);
|
|
48
|
-
if (!r.success)
|
|
49
|
-
return (0, helpers_1.fail)(res, r.error ?? 'Failed to load row.');
|
|
50
|
-
if (!r.data)
|
|
51
|
-
return (0, helpers_1.fail)(res, 'Row not found.', 404);
|
|
52
|
-
(0, helpers_1.ok)(res, (0, common_1.normalizeRow)(r.data));
|
|
53
|
-
}));
|
|
54
|
-
// Serve raw BLOB binary data with auto-detected Content-Type and download support
|
|
55
|
-
router.get('/api/tables/:table/row/:id/blob/:column', (0, helpers_1.wrap)(async (req, res) => {
|
|
56
|
-
const info = await (0, helpers_1.requireTable)(db, req.params.table);
|
|
57
|
-
if (!info)
|
|
58
|
-
return (0, helpers_1.fail)(res, `Table "${req.params.table}" does not exist.`, 404);
|
|
59
|
-
const where = (0, helpers_1.pkWhere)(info, req.params.id);
|
|
60
|
-
if (!where)
|
|
61
|
-
return (0, helpers_1.fail)(res, 'Invalid primary key.', 400);
|
|
62
|
-
const r = await db.getRow(req.params.table, where);
|
|
63
|
-
if (!r.success)
|
|
64
|
-
return (0, helpers_1.fail)(res, r.error ?? 'Failed to load row.');
|
|
65
|
-
if (!r.data)
|
|
66
|
-
return (0, helpers_1.fail)(res, 'Row not found.', 404);
|
|
67
|
-
const colName = req.params.column;
|
|
68
|
-
const rawVal = r.data[colName];
|
|
69
|
-
if (rawVal === null || rawVal === undefined) {
|
|
70
|
-
return (0, helpers_1.fail)(res, 'Column value is NULL.', 404);
|
|
71
|
-
}
|
|
72
|
-
let buf;
|
|
73
|
-
if (Buffer.isBuffer(rawVal) || rawVal instanceof Uint8Array) {
|
|
74
|
-
buf = Buffer.isBuffer(rawVal) ? rawVal : Buffer.from(rawVal);
|
|
75
|
-
}
|
|
76
|
-
else if (typeof rawVal === 'string' && (/^0x[0-9a-f]*$/i.test(rawVal))) {
|
|
77
|
-
buf = Buffer.from(rawVal.slice(2), 'hex');
|
|
78
|
-
}
|
|
79
|
-
else {
|
|
80
|
-
buf = Buffer.from(String(rawVal), 'utf8');
|
|
81
|
-
}
|
|
82
|
-
const mimeInfo = (0, datatype_1.sniffMimeType)(buf);
|
|
83
|
-
res.setHeader('Content-Type', mimeInfo.mime);
|
|
84
|
-
res.setHeader('Content-Length', buf.length);
|
|
85
|
-
res.setHeader('Cache-Control', 'no-cache');
|
|
86
|
-
if (req.query.download === '1' || req.query.download === 'true') {
|
|
87
|
-
const filename = `${req.params.table}_${colName}_${req.params.id}.${mimeInfo.ext}`;
|
|
88
|
-
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
|
|
89
|
-
}
|
|
90
|
-
res.end(buf);
|
|
91
|
-
}));
|
|
92
|
-
// Return BLOB metadata and formatted hex dump
|
|
93
|
-
router.get('/api/tables/:table/row/:id/blob/:column/meta', (0, helpers_1.wrap)(async (req, res) => {
|
|
94
|
-
const info = await (0, helpers_1.requireTable)(db, req.params.table);
|
|
95
|
-
if (!info)
|
|
96
|
-
return (0, helpers_1.fail)(res, `Table "${req.params.table}" does not exist.`, 404);
|
|
97
|
-
const where = (0, helpers_1.pkWhere)(info, req.params.id);
|
|
98
|
-
if (!where)
|
|
99
|
-
return (0, helpers_1.fail)(res, 'Invalid primary key.', 400);
|
|
100
|
-
const r = await db.getRow(req.params.table, where);
|
|
101
|
-
if (!r.success)
|
|
102
|
-
return (0, helpers_1.fail)(res, r.error ?? 'Failed to load row.');
|
|
103
|
-
if (!r.data)
|
|
104
|
-
return (0, helpers_1.fail)(res, 'Row not found.', 404);
|
|
105
|
-
const colName = req.params.column;
|
|
106
|
-
const rawVal = r.data[colName];
|
|
107
|
-
if (rawVal === null || rawVal === undefined) {
|
|
108
|
-
return (0, helpers_1.ok)(res, { isNull: true, size: 0, sizeFormatted: '0 B' });
|
|
109
|
-
}
|
|
110
|
-
const meta = (0, datatype_1.analyzeBlob)(rawVal);
|
|
111
|
-
(0, helpers_1.ok)(res, { isNull: false, ...meta });
|
|
112
|
-
}));
|
|
113
|
-
// Update BLOB binary value directly (accepts Base64 or Hex payload)
|
|
114
|
-
router.put('/api/tables/:table/row/:id/blob/:column', (0, helpers_1.wrap)(async (req, res) => {
|
|
115
|
-
const info = await (0, helpers_1.requireTable)(db, req.params.table);
|
|
116
|
-
if (!info)
|
|
117
|
-
return (0, helpers_1.fail)(res, `Table "${req.params.table}" does not exist.`, 404);
|
|
118
|
-
const where = (0, helpers_1.pkWhere)(info, req.params.id);
|
|
119
|
-
if (!where)
|
|
120
|
-
return (0, helpers_1.fail)(res, 'Invalid primary key.', 400);
|
|
121
|
-
const colName = req.params.column;
|
|
122
|
-
let buf;
|
|
123
|
-
if (req.body?.data !== undefined) {
|
|
124
|
-
const format = req.body.format || 'base64';
|
|
125
|
-
if (format === 'base64') {
|
|
126
|
-
// Strip data:image/...;base64, prefix if present
|
|
127
|
-
const base64Str = String(req.body.data).replace(/^data:[^;]+;base64,/, '');
|
|
128
|
-
buf = Buffer.from(base64Str, 'base64');
|
|
129
|
-
}
|
|
130
|
-
else if (format === 'hex') {
|
|
131
|
-
const hexStr = String(req.body.data).replace(/^0x/i, '');
|
|
132
|
-
buf = Buffer.from(hexStr, 'hex');
|
|
133
|
-
}
|
|
134
|
-
else {
|
|
135
|
-
buf = Buffer.from(String(req.body.data), 'utf8');
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
else {
|
|
139
|
-
return (0, helpers_1.fail)(res, 'Payload data is required.');
|
|
140
|
-
}
|
|
141
|
-
const updateRes = await db.updateRow(req.params.table, [{ column: colName, value: buf }], where);
|
|
142
|
-
if (!updateRes.success)
|
|
143
|
-
return (0, helpers_1.fail)(res, updateRes.error ?? 'Failed to update BLOB.');
|
|
144
|
-
(0, helpers_1.ok)(res, { message: `Updated BLOB in column "${colName}".`, size: buf.length });
|
|
145
|
-
}));
|
|
146
|
-
// Preview generated INSERT SQL without executing
|
|
147
|
-
router.post('/api/tables/:table/rows/generate', (0, helpers_1.wrap)(async (req, res) => {
|
|
148
|
-
const info = await (0, helpers_1.requireTable)(db, req.params.table);
|
|
149
|
-
if (!info)
|
|
150
|
-
return (0, helpers_1.fail)(res, `Table "${req.params.table}" does not exist.`, 404);
|
|
151
|
-
const fields = (0, helpers_1.buildFields)(info, req.body?.values ?? req.body ?? {});
|
|
152
|
-
if (!fields.length)
|
|
153
|
-
return (0, helpers_1.fail)(res, 'No valid column values provided.');
|
|
154
|
-
const sql = (0, generator_1.generateInsert)(req.params.table, fields);
|
|
155
|
-
(0, helpers_1.ok)(res, { sql });
|
|
156
|
-
}));
|
|
157
|
-
// Preview generated UPDATE SQL without executing
|
|
158
|
-
const generateUpdateHandler = (0, helpers_1.wrap)(async (req, res) => {
|
|
159
|
-
const info = await (0, helpers_1.requireTable)(db, req.params.table);
|
|
160
|
-
if (!info)
|
|
161
|
-
return (0, helpers_1.fail)(res, `Table "${req.params.table}" does not exist.`, 404);
|
|
162
|
-
const id = req.params.id || (req.query.id ? String(req.query.id) : null);
|
|
163
|
-
if (!id)
|
|
164
|
-
return (0, helpers_1.fail)(res, 'Primary key id is required.');
|
|
165
|
-
const where = (0, helpers_1.pkWhere)(info, id);
|
|
166
|
-
if (!where)
|
|
167
|
-
return (0, helpers_1.fail)(res, 'Invalid primary key.', 400);
|
|
168
|
-
const nulls = Array.isArray(req.body?.nulls) ? req.body.nulls : [];
|
|
169
|
-
const fields = (0, helpers_1.buildUpdateFields)(info, req.body?.values ?? req.body ?? {}, nulls);
|
|
170
|
-
if (!fields.length)
|
|
171
|
-
return (0, helpers_1.fail)(res, 'No fields to update.');
|
|
172
|
-
const sql = (0, generator_1.generateUpdate)(req.params.table, fields, where);
|
|
173
|
-
(0, helpers_1.ok)(res, { sql });
|
|
174
|
-
});
|
|
175
|
-
router.put('/api/tables/:table/row/:id/generate', generateUpdateHandler);
|
|
176
|
-
router.post('/api/tables/:table/row/:id/generate', generateUpdateHandler);
|
|
177
|
-
router.put('/api/tables/:table/rows/generate', generateUpdateHandler);
|
|
178
|
-
router.post('/api/tables/:table/rows', (0, helpers_1.wrap)(async (req, res) => {
|
|
179
|
-
const info = await (0, helpers_1.requireTable)(db, req.params.table);
|
|
180
|
-
if (!info)
|
|
181
|
-
return (0, helpers_1.fail)(res, `Table "${req.params.table}" does not exist.`, 404);
|
|
182
|
-
const isBatch = Array.isArray(req.body?.rows);
|
|
183
|
-
const rowList = isBatch
|
|
184
|
-
? req.body.rows
|
|
185
|
-
: [req.body?.values ?? req.body ?? {}];
|
|
186
|
-
if (!rowList.length)
|
|
187
|
-
return (0, helpers_1.fail)(res, 'No rows provided.');
|
|
188
|
-
const fieldsList = rowList.map((row) => (0, helpers_1.buildFields)(info, row));
|
|
189
|
-
if (!isBatch) {
|
|
190
|
-
const fields = fieldsList[0];
|
|
191
|
-
if (!fields.length)
|
|
192
|
-
return (0, helpers_1.fail)(res, 'No valid column values provided.');
|
|
193
|
-
const r = await db.insertRow(req.params.table, fields);
|
|
194
|
-
if (!r.success)
|
|
195
|
-
return (0, helpers_1.fail)(res, r.error ?? 'Failed to insert row.');
|
|
196
|
-
return (0, helpers_1.ok)(res, { message: 'Row inserted.', id: r.data?.lastInsertRowid }, 201);
|
|
197
|
-
}
|
|
198
|
-
const r = await db.insertRows(req.params.table, fieldsList);
|
|
199
|
-
if (!r.success)
|
|
200
|
-
return (0, helpers_1.fail)(res, r.error ?? 'Failed to insert rows.');
|
|
201
|
-
(0, helpers_1.ok)(res, { message: `${r.data?.inserted ?? 0} row(s) inserted.`, inserted: r.data?.inserted }, 201);
|
|
202
|
-
}));
|
|
203
|
-
const updateSingleRowHandler = (0, helpers_1.wrap)(async (req, res) => {
|
|
204
|
-
const info = await (0, helpers_1.requireTable)(db, req.params.table);
|
|
205
|
-
if (!info)
|
|
206
|
-
return (0, helpers_1.fail)(res, `Table "${req.params.table}" does not exist.`, 404);
|
|
207
|
-
const id = req.params.id || (req.query.id ? String(req.query.id) : null);
|
|
208
|
-
if (!id)
|
|
209
|
-
return (0, helpers_1.fail)(res, 'Primary key id is required.');
|
|
210
|
-
const where = (0, helpers_1.pkWhere)(info, id);
|
|
211
|
-
if (!where)
|
|
212
|
-
return (0, helpers_1.fail)(res, 'Invalid primary key.');
|
|
213
|
-
const nulls = Array.isArray(req.body?.nulls) ? req.body.nulls : [];
|
|
214
|
-
const fields = (0, helpers_1.buildUpdateFields)(info, req.body?.values ?? req.body ?? {}, nulls);
|
|
215
|
-
if (!fields.length)
|
|
216
|
-
return (0, helpers_1.fail)(res, 'No fields to update.');
|
|
217
|
-
const r = await db.updateRow(req.params.table, fields, where);
|
|
218
|
-
if (!r.success)
|
|
219
|
-
return (0, helpers_1.fail)(res, r.error ?? 'Failed to update row.');
|
|
220
|
-
(0, helpers_1.ok)(res, { message: 'Row updated.' });
|
|
221
|
-
});
|
|
222
|
-
const bulkUpdateHandler = (0, helpers_1.wrap)(async (req, res) => {
|
|
223
|
-
const info = await (0, helpers_1.requireTable)(db, req.params.table);
|
|
224
|
-
if (!info)
|
|
225
|
-
return (0, helpers_1.fail)(res, `Table "${req.params.table}" does not exist.`, 404);
|
|
226
|
-
if (Array.isArray(req.body?.updates)) {
|
|
227
|
-
const updates = req.body.updates;
|
|
228
|
-
if (!updates.length)
|
|
229
|
-
return (0, helpers_1.fail)(res, 'No updates provided.');
|
|
230
|
-
if (updates.length > helpers_1.MAX_BULK_ROWS)
|
|
231
|
-
return (0, helpers_1.fail)(res, `Cannot update more than ${helpers_1.MAX_BULK_ROWS} rows at once.`);
|
|
232
|
-
const rowUpdates = [];
|
|
233
|
-
for (const u of updates) {
|
|
234
|
-
if (!u.id)
|
|
235
|
-
return (0, helpers_1.fail)(res, 'Every update requires an id.');
|
|
236
|
-
const where = (0, helpers_1.pkWhere)(info, String(u.id));
|
|
237
|
-
if (!where)
|
|
238
|
-
return (0, helpers_1.fail)(res, `Invalid primary key: "${u.id}".`);
|
|
239
|
-
const nulls = Array.isArray(u.nulls) ? u.nulls.map(String) : [];
|
|
240
|
-
const fields = (0, helpers_1.buildUpdateFields)(info, u.values ?? {}, nulls);
|
|
241
|
-
if (fields.length)
|
|
242
|
-
rowUpdates.push({ fields, where });
|
|
243
|
-
}
|
|
244
|
-
if (!rowUpdates.length)
|
|
245
|
-
return (0, helpers_1.ok)(res, { message: 'No changes to apply.', updated: 0 });
|
|
246
|
-
const r = await db.updateRows(req.params.table, rowUpdates);
|
|
247
|
-
if (!r.success)
|
|
248
|
-
return (0, helpers_1.fail)(res, r.error ?? 'Failed to update rows.');
|
|
249
|
-
return (0, helpers_1.ok)(res, { message: `${r.data?.updated ?? 0} row(s) updated.`, updated: r.data?.updated });
|
|
250
|
-
}
|
|
251
|
-
return updateSingleRowHandler(req, res);
|
|
252
|
-
});
|
|
253
|
-
router.put('/api/tables/:table/row/:id', updateSingleRowHandler);
|
|
254
|
-
router.put('/api/tables/:table/rows', bulkUpdateHandler);
|
|
255
|
-
router.post('/api/tables/:table/rows/bulk-update', bulkUpdateHandler);
|
|
256
|
-
const deleteSingleRowHandler = (0, helpers_1.wrap)(async (req, res) => {
|
|
257
|
-
const info = await (0, helpers_1.requireTable)(db, req.params.table);
|
|
258
|
-
if (!info)
|
|
259
|
-
return (0, helpers_1.fail)(res, `Table "${req.params.table}" does not exist.`, 404);
|
|
260
|
-
const id = req.params.id || (req.query.id ? String(req.query.id) : null);
|
|
261
|
-
if (!id)
|
|
262
|
-
return (0, helpers_1.fail)(res, 'Primary key id is required.');
|
|
263
|
-
const where = (0, helpers_1.pkWhere)(info, id);
|
|
264
|
-
if (!where)
|
|
265
|
-
return (0, helpers_1.fail)(res, 'Invalid primary key.');
|
|
266
|
-
const r = await db.deleteRow(req.params.table, where);
|
|
267
|
-
if (!r.success)
|
|
268
|
-
return (0, helpers_1.fail)(res, r.error ?? 'Failed to delete row.');
|
|
269
|
-
(0, helpers_1.ok)(res, { message: 'Row deleted.' });
|
|
270
|
-
});
|
|
271
|
-
router.delete('/api/tables/:table/row/:id', deleteSingleRowHandler);
|
|
272
|
-
router.delete('/api/tables/:table/rows', deleteSingleRowHandler);
|
|
273
|
-
// ---- Row references ----------------------------------------------------
|
|
274
|
-
router.get('/api/tables/:table/rows/:id/references', (0, helpers_1.wrap)(async (req, res) => {
|
|
275
|
-
const info = await (0, helpers_1.requireTable)(db, req.params.table);
|
|
276
|
-
if (!info)
|
|
277
|
-
return (0, helpers_1.fail)(res, `Table "${req.params.table}" does not exist.`, 404);
|
|
278
|
-
const where = (0, helpers_1.pkWhere)(info, req.params.id);
|
|
279
|
-
if (!where)
|
|
280
|
-
return (0, helpers_1.fail)(res, 'Invalid primary key.', 400);
|
|
281
|
-
const rowR = await db.getRow(req.params.table, where);
|
|
282
|
-
if (!rowR.success || !rowR.data)
|
|
283
|
-
return (0, helpers_1.fail)(res, 'Row not found.', 404);
|
|
284
|
-
const refInfoR = await db.getReferencingTables(req.params.table);
|
|
285
|
-
const referencing = refInfoR.data ?? [];
|
|
286
|
-
const results = [];
|
|
287
|
-
for (const item of referencing) {
|
|
288
|
-
for (const ref of item.refs) {
|
|
289
|
-
const targetCol = ref.to || info.primaryKey[0];
|
|
290
|
-
if (!targetCol)
|
|
291
|
-
continue;
|
|
292
|
-
const val = rowR.data[targetCol];
|
|
293
|
-
if (val == null)
|
|
294
|
-
continue;
|
|
295
|
-
const fkR = await db.getRowsByFk(item.table, ref.from, val);
|
|
296
|
-
if (fkR.success && fkR.data) {
|
|
297
|
-
const rows = fkR.data.rows.map(common_1.normalizeRow);
|
|
298
|
-
const columns = rows.length > 0 ? Object.keys(rows[0]) : [];
|
|
299
|
-
results.push({
|
|
300
|
-
table: item.table,
|
|
301
|
-
from: ref.from,
|
|
302
|
-
to: targetCol,
|
|
303
|
-
value: val,
|
|
304
|
-
columns,
|
|
305
|
-
rows,
|
|
306
|
-
count: fkR.data.total,
|
|
307
|
-
total: fkR.data.total,
|
|
308
|
-
});
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
(0, helpers_1.ok)(res, { references: results });
|
|
313
|
-
}));
|
|
314
|
-
// ---- Bulk row operations -----------------------------------------------
|
|
315
|
-
router.post('/api/tables/:table/rows/bulk-delete', (0, helpers_1.wrap)(async (req, res) => {
|
|
316
|
-
const info = await (0, helpers_1.requireTable)(db, req.params.table);
|
|
317
|
-
if (!info)
|
|
318
|
-
return (0, helpers_1.fail)(res, `Table "${req.params.table}" does not exist.`, 404);
|
|
319
|
-
const ids = (req.body?.ids ?? []);
|
|
320
|
-
if (!Array.isArray(ids) || !ids.length)
|
|
321
|
-
return (0, helpers_1.fail)(res, 'No row IDs provided.');
|
|
322
|
-
if (ids.length > helpers_1.MAX_BULK_ROWS)
|
|
323
|
-
return (0, helpers_1.fail)(res, `Cannot delete more than ${helpers_1.MAX_BULK_ROWS} rows at once.`);
|
|
324
|
-
const wheres = (0, helpers_1.resolvePkRows)(info, ids);
|
|
325
|
-
if (!wheres)
|
|
326
|
-
return (0, helpers_1.fail)(res, 'Invalid or unresolvable row IDs.');
|
|
327
|
-
const r = await db.deleteRows(req.params.table, wheres);
|
|
328
|
-
if (!r.success)
|
|
329
|
-
return (0, helpers_1.fail)(res, r.error ?? 'Failed to delete rows.');
|
|
330
|
-
(0, helpers_1.ok)(res, { message: `${r.data?.deleted ?? 0} row(s) deleted.`, deleted: r.data?.deleted });
|
|
331
|
-
}));
|
|
332
|
-
router.post('/api/tables/:table/rows/bulk-impact', (0, helpers_1.wrap)(async (req, res) => {
|
|
333
|
-
const info = await (0, helpers_1.requireTable)(db, req.params.table);
|
|
334
|
-
if (!info)
|
|
335
|
-
return (0, helpers_1.fail)(res, `Table "${req.params.table}" does not exist.`, 404);
|
|
336
|
-
const ids = (req.body?.ids ?? []);
|
|
337
|
-
if (!Array.isArray(ids) || !ids.length)
|
|
338
|
-
return (0, helpers_1.ok)(res, { references: [], total: 0 });
|
|
339
|
-
const wheres = (0, helpers_1.resolvePkRows)(info, ids);
|
|
340
|
-
if (!wheres)
|
|
341
|
-
return (0, helpers_1.ok)(res, { references: [], total: 0 });
|
|
342
|
-
const impact = await (0, helpers_1.computeBulkImpact)(db, info, wheres);
|
|
343
|
-
(0, helpers_1.ok)(res, impact);
|
|
344
|
-
}));
|
|
345
|
-
router.post('/api/tables/:table/rows/bulk-export', (0, helpers_1.wrap)(async (req, res) => {
|
|
346
|
-
const info = await (0, helpers_1.requireTable)(db, req.params.table);
|
|
347
|
-
if (!info)
|
|
348
|
-
return (0, helpers_1.fail)(res, `Table "${req.params.table}" does not exist.`, 404);
|
|
349
|
-
const ids = (req.body?.ids ?? []);
|
|
350
|
-
if (!Array.isArray(ids) || !ids.length)
|
|
351
|
-
return (0, helpers_1.fail)(res, 'No row IDs provided.');
|
|
352
|
-
if (ids.length > helpers_1.MAX_BULK_ROWS)
|
|
353
|
-
return (0, helpers_1.fail)(res, `Cannot export more than ${helpers_1.MAX_BULK_ROWS} rows at once.`);
|
|
354
|
-
const wheres = (0, helpers_1.resolvePkRows)(info, ids);
|
|
355
|
-
if (!wheres)
|
|
356
|
-
return (0, helpers_1.fail)(res, 'Invalid or unresolvable row IDs.');
|
|
357
|
-
const format = String(req.body?.format ?? 'csv').toLowerCase();
|
|
358
|
-
const rowsR = await db.getRowsByPks(req.params.table, wheres);
|
|
359
|
-
if (!rowsR.success)
|
|
360
|
-
return (0, helpers_1.fail)(res, rowsR.error ?? 'Failed to load rows.');
|
|
361
|
-
const rows = (rowsR.data ?? []).map(common_1.normalizeRow);
|
|
362
|
-
const columns = info.columns.map((c) => c.name);
|
|
363
|
-
if (format === 'json') {
|
|
364
|
-
res.setHeader('Content-Type', 'application/json; charset=utf-8');
|
|
365
|
-
res.setHeader('Content-Disposition', `attachment; filename="${req.params.table}_selected.json"`);
|
|
366
|
-
return res.send((0, csv_1.toJson)(rows));
|
|
367
|
-
}
|
|
368
|
-
res.setHeader('Content-Type', 'text/csv; charset=utf-8');
|
|
369
|
-
res.setHeader('Content-Disposition', `attachment; filename="${req.params.table}_selected.csv"`);
|
|
370
|
-
res.send((0, csv_1.toCsv)(rows, columns));
|
|
371
|
-
}));
|
|
372
|
-
}
|
|
373
|
-
//# sourceMappingURL=rows.js.map
|
|
1
|
+
Object.defineProperty(exports,"__esModule",{value:!0}),exports.registerRowRoutes=function(router,ctx){const{db:db}=ctx;router.get("/api/tables/:table/rows",(0,helpers_1.wrap)(async(req,res)=>{const page=Number.parseInt(String(req.query.page??"1"),10),limit=Number.parseInt(String(req.query.limit??"50"),10),orderBy=req.query.orderBy?String(req.query.orderBy):void 0,orderDir="desc"===req.query.orderDir?"desc":"asc",filters=(0,common_1.parseFilters)(req.query.f),[rowsR,totalR]=await Promise.all([db.getRows(req.params.table,{page:page,limit:limit,orderBy:orderBy,orderDir:orderDir,filters:filters}),db.getRowCount(req.params.table,filters)]);if(!rowsR.success)return(0,helpers_1.fail)(res,rowsR.error??"Failed to load rows.");const rows=(rowsR.data??[]).map(common_1.normalizeRow);(0,helpers_1.ok)(res,{rows:rows,total:totalR.success?totalR.data:rows.length,page:page,limit:limit})})),router.get("/api/tables/:table/rows/count",(0,helpers_1.wrap)(async(req,res)=>{const filters=(0,common_1.parseFilters)(req.query.f),r=await db.getRowCount(req.params.table,filters);if(!r.success)return(0,helpers_1.fail)(res,r.error??"Failed to count rows.");(0,helpers_1.ok)(res,{count:r.data})})),router.get("/api/tables/:table/row/:id",(0,helpers_1.wrap)(async(req,res)=>{const info=await(0,helpers_1.requireTable)(db,req.params.table);if(!info)return(0,helpers_1.fail)(res,`Table "${req.params.table}" does not exist.`,404);const where=(0,helpers_1.pkWhere)(info,req.params.id);if(!where)return(0,helpers_1.fail)(res,"Invalid primary key.",400);const r=await db.getRow(req.params.table,where);return r.success?r.data?void(0,helpers_1.ok)(res,(0,common_1.normalizeRow)(r.data)):(0,helpers_1.fail)(res,"Row not found.",404):(0,helpers_1.fail)(res,r.error??"Failed to load row.")})),router.get("/api/tables/:table/row/:id/blob/:column",(0,helpers_1.wrap)(async(req,res)=>{const info=await(0,helpers_1.requireTable)(db,req.params.table);if(!info)return(0,helpers_1.fail)(res,`Table "${req.params.table}" does not exist.`,404);const where=(0,helpers_1.pkWhere)(info,req.params.id);if(!where)return(0,helpers_1.fail)(res,"Invalid primary key.",400);const r=await db.getRow(req.params.table,where);if(!r.success)return(0,helpers_1.fail)(res,r.error??"Failed to load row.");if(!r.data)return(0,helpers_1.fail)(res,"Row not found.",404);const colName=req.params.column,rawVal=r.data[colName];if(null==rawVal)return(0,helpers_1.fail)(res,"Column value is NULL.",404);let buf;buf=Buffer.isBuffer(rawVal)||rawVal instanceof Uint8Array?Buffer.isBuffer(rawVal)?rawVal:Buffer.from(rawVal):"string"==typeof rawVal&&/^0x[0-9a-f]*$/i.test(rawVal)?Buffer.from(rawVal.slice(2),"hex"):Buffer.from(String(rawVal),"utf8");const mimeInfo=(0,datatype_1.sniffMimeType)(buf);if(res.setHeader("Content-Type",mimeInfo.mime),res.setHeader("Content-Length",buf.length),res.setHeader("Cache-Control","no-cache"),"1"===req.query.download||"true"===req.query.download){const filename=`${req.params.table}_${colName}_${req.params.id}.${mimeInfo.ext}`;res.setHeader("Content-Disposition",`attachment; filename="${filename}"`)}res.end(buf)})),router.get("/api/tables/:table/row/:id/blob/:column/meta",(0,helpers_1.wrap)(async(req,res)=>{const info=await(0,helpers_1.requireTable)(db,req.params.table);if(!info)return(0,helpers_1.fail)(res,`Table "${req.params.table}" does not exist.`,404);const where=(0,helpers_1.pkWhere)(info,req.params.id);if(!where)return(0,helpers_1.fail)(res,"Invalid primary key.",400);const r=await db.getRow(req.params.table,where);if(!r.success)return(0,helpers_1.fail)(res,r.error??"Failed to load row.");if(!r.data)return(0,helpers_1.fail)(res,"Row not found.",404);const colName=req.params.column,rawVal=r.data[colName];if(null==rawVal)return(0,helpers_1.ok)(res,{isNull:!0,size:0,sizeFormatted:"0 B"});const meta=(0,datatype_1.analyzeBlob)(rawVal);(0,helpers_1.ok)(res,{isNull:!1,...meta})})),router.put("/api/tables/:table/row/:id/blob/:column",(0,helpers_1.wrap)(async(req,res)=>{const info=await(0,helpers_1.requireTable)(db,req.params.table);if(!info)return(0,helpers_1.fail)(res,`Table "${req.params.table}" does not exist.`,404);const where=(0,helpers_1.pkWhere)(info,req.params.id);if(!where)return(0,helpers_1.fail)(res,"Invalid primary key.",400);const colName=req.params.column;let buf;if(void 0===req.body?.data)return(0,helpers_1.fail)(res,"Payload data is required.");{const format=req.body.format||"base64";if("base64"===format){const base64Str=String(req.body.data).replace(/^data:[^;]+;base64,/,"");buf=Buffer.from(base64Str,"base64")}else if("hex"===format){const hexStr=String(req.body.data).replace(/^0x/i,"");buf=Buffer.from(hexStr,"hex")}else buf=Buffer.from(String(req.body.data),"utf8")}const updateRes=await db.updateRow(req.params.table,[{column:colName,value:buf}],where);if(!updateRes.success)return(0,helpers_1.fail)(res,updateRes.error??"Failed to update BLOB.");(0,helpers_1.ok)(res,{message:`Updated BLOB in column "${colName}".`,size:buf.length})})),router.post("/api/tables/:table/rows/generate",(0,helpers_1.wrap)(async(req,res)=>{const info=await(0,helpers_1.requireTable)(db,req.params.table);if(!info)return(0,helpers_1.fail)(res,`Table "${req.params.table}" does not exist.`,404);const fields=(0,helpers_1.buildFields)(info,req.body?.values??req.body??{});if(!fields.length)return(0,helpers_1.fail)(res,"No valid column values provided.");const sql=(0,generator_1.generateInsert)(req.params.table,fields);(0,helpers_1.ok)(res,{sql:sql})}));const generateUpdateHandler=(0,helpers_1.wrap)(async(req,res)=>{const info=await(0,helpers_1.requireTable)(db,req.params.table);if(!info)return(0,helpers_1.fail)(res,`Table "${req.params.table}" does not exist.`,404);const id=req.params.id||(req.query.id?String(req.query.id):null);if(!id)return(0,helpers_1.fail)(res,"Primary key id is required.");const where=(0,helpers_1.pkWhere)(info,id);if(!where)return(0,helpers_1.fail)(res,"Invalid primary key.",400);const nulls=Array.isArray(req.body?.nulls)?req.body.nulls:[],fields=(0,helpers_1.buildUpdateFields)(info,req.body?.values??req.body??{},nulls);if(!fields.length)return(0,helpers_1.fail)(res,"No fields to update.");const sql=(0,generator_1.generateUpdate)(req.params.table,fields,where);(0,helpers_1.ok)(res,{sql:sql})});router.put("/api/tables/:table/row/:id/generate",generateUpdateHandler),router.post("/api/tables/:table/row/:id/generate",generateUpdateHandler),router.put("/api/tables/:table/rows/generate",generateUpdateHandler),router.post("/api/tables/:table/rows",(0,helpers_1.wrap)(async(req,res)=>{const info=await(0,helpers_1.requireTable)(db,req.params.table);if(!info)return(0,helpers_1.fail)(res,`Table "${req.params.table}" does not exist.`,404);const isBatch=Array.isArray(req.body?.rows),rowList=isBatch?req.body.rows:[req.body?.values??req.body??{}];if(!rowList.length)return(0,helpers_1.fail)(res,"No rows provided.");const fieldsList=rowList.map(row=>(0,helpers_1.buildFields)(info,row));if(!isBatch){const fields=fieldsList[0];if(!fields.length)return(0,helpers_1.fail)(res,"No valid column values provided.");const r=await db.insertRow(req.params.table,fields);return r.success?(0,helpers_1.ok)(res,{message:"Row inserted.",id:r.data?.lastInsertRowid},201):(0,helpers_1.fail)(res,r.error??"Failed to insert row.")}const r=await db.insertRows(req.params.table,fieldsList);if(!r.success)return(0,helpers_1.fail)(res,r.error??"Failed to insert rows.");(0,helpers_1.ok)(res,{message:`${r.data?.inserted??0} row(s) inserted.`,inserted:r.data?.inserted},201)}));const updateSingleRowHandler=(0,helpers_1.wrap)(async(req,res)=>{const info=await(0,helpers_1.requireTable)(db,req.params.table);if(!info)return(0,helpers_1.fail)(res,`Table "${req.params.table}" does not exist.`,404);const id=req.params.id||(req.query.id?String(req.query.id):null);if(!id)return(0,helpers_1.fail)(res,"Primary key id is required.");const where=(0,helpers_1.pkWhere)(info,id);if(!where)return(0,helpers_1.fail)(res,"Invalid primary key.");const nulls=Array.isArray(req.body?.nulls)?req.body.nulls:[],fields=(0,helpers_1.buildUpdateFields)(info,req.body?.values??req.body??{},nulls);if(!fields.length)return(0,helpers_1.fail)(res,"No fields to update.");const r=await db.updateRow(req.params.table,fields,where);if(!r.success)return(0,helpers_1.fail)(res,r.error??"Failed to update row.");(0,helpers_1.ok)(res,{message:"Row updated."})}),bulkUpdateHandler=(0,helpers_1.wrap)(async(req,res)=>{const info=await(0,helpers_1.requireTable)(db,req.params.table);if(!info)return(0,helpers_1.fail)(res,`Table "${req.params.table}" does not exist.`,404);if(Array.isArray(req.body?.updates)){const updates=req.body.updates;if(!updates.length)return(0,helpers_1.fail)(res,"No updates provided.");if(updates.length>helpers_1.MAX_BULK_ROWS)return(0,helpers_1.fail)(res,`Cannot update more than ${helpers_1.MAX_BULK_ROWS} rows at once.`);const rowUpdates=[];for(const u of updates){if(!u.id)return(0,helpers_1.fail)(res,"Every update requires an id.");const where=(0,helpers_1.pkWhere)(info,String(u.id));if(!where)return(0,helpers_1.fail)(res,`Invalid primary key: "${u.id}".`);const nulls=Array.isArray(u.nulls)?u.nulls.map(String):[],fields=(0,helpers_1.buildUpdateFields)(info,u.values??{},nulls);fields.length&&rowUpdates.push({fields:fields,where:where})}if(!rowUpdates.length)return(0,helpers_1.ok)(res,{message:"No changes to apply.",updated:0});const r=await db.updateRows(req.params.table,rowUpdates);return r.success?(0,helpers_1.ok)(res,{message:`${r.data?.updated??0} row(s) updated.`,updated:r.data?.updated}):(0,helpers_1.fail)(res,r.error??"Failed to update rows.")}return updateSingleRowHandler(req,res)});router.put("/api/tables/:table/row/:id",updateSingleRowHandler),router.put("/api/tables/:table/rows",bulkUpdateHandler),router.post("/api/tables/:table/rows/bulk-update",bulkUpdateHandler);const deleteSingleRowHandler=(0,helpers_1.wrap)(async(req,res)=>{const info=await(0,helpers_1.requireTable)(db,req.params.table);if(!info)return(0,helpers_1.fail)(res,`Table "${req.params.table}" does not exist.`,404);const id=req.params.id||(req.query.id?String(req.query.id):null);if(!id)return(0,helpers_1.fail)(res,"Primary key id is required.");const where=(0,helpers_1.pkWhere)(info,id);if(!where)return(0,helpers_1.fail)(res,"Invalid primary key.");const r=await db.deleteRow(req.params.table,where);if(!r.success)return(0,helpers_1.fail)(res,r.error??"Failed to delete row.");(0,helpers_1.ok)(res,{message:"Row deleted."})});router.delete("/api/tables/:table/row/:id",deleteSingleRowHandler),router.delete("/api/tables/:table/rows",deleteSingleRowHandler),router.get("/api/tables/:table/rows/:id/references",(0,helpers_1.wrap)(async(req,res)=>{const info=await(0,helpers_1.requireTable)(db,req.params.table);if(!info)return(0,helpers_1.fail)(res,`Table "${req.params.table}" does not exist.`,404);const where=(0,helpers_1.pkWhere)(info,req.params.id);if(!where)return(0,helpers_1.fail)(res,"Invalid primary key.",400);const rowR=await db.getRow(req.params.table,where);if(!rowR.success||!rowR.data)return(0,helpers_1.fail)(res,"Row not found.",404);const referencing=(await db.getReferencingTables(req.params.table)).data??[],results=[];for(const item of referencing)for(const ref of item.refs){const targetCol=ref.to||info.primaryKey[0];if(!targetCol)continue;const val=rowR.data[targetCol];if(null==val)continue;const fkR=await db.getRowsByFk(item.table,ref.from,val);if(fkR.success&&fkR.data){const rows=fkR.data.rows.map(common_1.normalizeRow),columns=rows.length>0?Object.keys(rows[0]):[];results.push({table:item.table,from:ref.from,to:targetCol,value:val,columns:columns,rows:rows,count:fkR.data.total,total:fkR.data.total})}}(0,helpers_1.ok)(res,{references:results})})),router.post("/api/tables/:table/rows/bulk-delete",(0,helpers_1.wrap)(async(req,res)=>{const info=await(0,helpers_1.requireTable)(db,req.params.table);if(!info)return(0,helpers_1.fail)(res,`Table "${req.params.table}" does not exist.`,404);const ids=req.body?.ids??[];if(!Array.isArray(ids)||!ids.length)return(0,helpers_1.fail)(res,"No row IDs provided.");if(ids.length>helpers_1.MAX_BULK_ROWS)return(0,helpers_1.fail)(res,`Cannot delete more than ${helpers_1.MAX_BULK_ROWS} rows at once.`);const wheres=(0,helpers_1.resolvePkRows)(info,ids);if(!wheres)return(0,helpers_1.fail)(res,"Invalid or unresolvable row IDs.");const r=await db.deleteRows(req.params.table,wheres);if(!r.success)return(0,helpers_1.fail)(res,r.error??"Failed to delete rows.");(0,helpers_1.ok)(res,{message:`${r.data?.deleted??0} row(s) deleted.`,deleted:r.data?.deleted})})),router.post("/api/tables/:table/rows/bulk-impact",(0,helpers_1.wrap)(async(req,res)=>{const info=await(0,helpers_1.requireTable)(db,req.params.table);if(!info)return(0,helpers_1.fail)(res,`Table "${req.params.table}" does not exist.`,404);const ids=req.body?.ids??[];if(!Array.isArray(ids)||!ids.length)return(0,helpers_1.ok)(res,{references:[],total:0});const wheres=(0,helpers_1.resolvePkRows)(info,ids);if(!wheres)return(0,helpers_1.ok)(res,{references:[],total:0});const impact=await(0,helpers_1.computeBulkImpact)(db,info,wheres);(0,helpers_1.ok)(res,impact)})),router.post("/api/tables/:table/rows/bulk-export",(0,helpers_1.wrap)(async(req,res)=>{const info=await(0,helpers_1.requireTable)(db,req.params.table);if(!info)return(0,helpers_1.fail)(res,`Table "${req.params.table}" does not exist.`,404);const ids=req.body?.ids??[];if(!Array.isArray(ids)||!ids.length)return(0,helpers_1.fail)(res,"No row IDs provided.");if(ids.length>helpers_1.MAX_BULK_ROWS)return(0,helpers_1.fail)(res,`Cannot export more than ${helpers_1.MAX_BULK_ROWS} rows at once.`);const wheres=(0,helpers_1.resolvePkRows)(info,ids);if(!wheres)return(0,helpers_1.fail)(res,"Invalid or unresolvable row IDs.");const format=String(req.body?.format??"csv").toLowerCase(),rowsR=await db.getRowsByPks(req.params.table,wheres);if(!rowsR.success)return(0,helpers_1.fail)(res,rowsR.error??"Failed to load rows.");const rows=(rowsR.data??[]).map(common_1.normalizeRow),columns=info.columns.map(c=>c.name);if("json"===format)return res.setHeader("Content-Type","application/json; charset=utf-8"),res.setHeader("Content-Disposition",`attachment; filename="${req.params.table}_selected.json"`),res.send((0,csv_1.toJson)(rows));res.setHeader("Content-Type","text/csv; charset=utf-8"),res.setHeader("Content-Disposition",`attachment; filename="${req.params.table}_selected.csv"`),res.send((0,csv_1.toCsv)(rows,columns))}))};const common_1=require("../../utils/common"),datatype_1=require("../../utils/datatype"),csv_1=require("../../utils/csv"),generator_1=require("../../sql/generator"),helpers_1=require("./helpers");
|
|
@@ -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
|
@@ -1,82 +1 @@
|
|
|
1
|
-
"
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.registerSeedRoutes = registerSeedRoutes;
|
|
4
|
-
const generator_1 = require("../../sql/generator");
|
|
5
|
-
const index_1 = require("../../data/index");
|
|
6
|
-
const helpers_1 = require("./helpers");
|
|
7
|
-
function registerSeedRoutes(router, ctx) {
|
|
8
|
-
const { db } = ctx;
|
|
9
|
-
// ---- Data generator / seeder ------------------------------------------
|
|
10
|
-
// Per-column generator config (strategies + detected defaults) for the "Seed data" page
|
|
11
|
-
router.get('/api/tables/:table/seed/config', (0, helpers_1.wrap)(async (req, res) => {
|
|
12
|
-
const info = await (0, helpers_1.requireTable)(db, req.params.table);
|
|
13
|
-
if (!info)
|
|
14
|
-
return (0, helpers_1.fail)(res, `Table "${req.params.table}" does not exist.`, 404);
|
|
15
|
-
(0, helpers_1.ok)(res, { table: req.params.table, columns: (0, index_1.buildColumnConfigs)(info), maxRows: index_1.MAX_SEED_ROWS });
|
|
16
|
-
}));
|
|
17
|
-
// Legacy alias for seed config
|
|
18
|
-
router.get('/api/tables/:table/seed/plan', (0, helpers_1.wrap)(async (req, res) => {
|
|
19
|
-
const info = await (0, helpers_1.requireTable)(db, req.params.table);
|
|
20
|
-
if (!info)
|
|
21
|
-
return (0, helpers_1.fail)(res, `Table "${req.params.table}" does not exist.`, 404);
|
|
22
|
-
(0, helpers_1.ok)(res, { table: req.params.table, columns: (0, index_1.buildColumnConfigs)(info), maxRows: index_1.MAX_SEED_ROWS });
|
|
23
|
-
}));
|
|
24
|
-
// Preview: generate the rows and return the INSERT statements without executing them
|
|
25
|
-
router.post('/api/tables/:table/seed/generate', (0, helpers_1.wrap)(async (req, res) => {
|
|
26
|
-
const info = await (0, helpers_1.requireTable)(db, req.params.table);
|
|
27
|
-
if (!info)
|
|
28
|
-
return (0, helpers_1.fail)(res, `Table "${req.params.table}" does not exist.`, 404);
|
|
29
|
-
const { count, plan } = (0, helpers_1.parseSeedRequest)(req.body);
|
|
30
|
-
const configs = (0, index_1.buildColumnConfigs)(info);
|
|
31
|
-
const gen = await (0, index_1.generateRows)(db, info, configs, count, plan);
|
|
32
|
-
(0, helpers_1.ok)(res, {
|
|
33
|
-
table: req.params.table,
|
|
34
|
-
count: gen.rows.length,
|
|
35
|
-
sql: (0, index_1.buildSeedInsertSql)(req.params.table, gen.rows),
|
|
36
|
-
previewRows: gen.previewRows,
|
|
37
|
-
warnings: gen.warnings,
|
|
38
|
-
});
|
|
39
|
-
}));
|
|
40
|
-
// Interactive grid preview
|
|
41
|
-
router.post('/api/tables/:table/seed/preview', (0, helpers_1.wrap)(async (req, res) => {
|
|
42
|
-
const info = await (0, helpers_1.requireTable)(db, req.params.table);
|
|
43
|
-
if (!info)
|
|
44
|
-
return (0, helpers_1.fail)(res, `Table "${req.params.table}" does not exist.`, 404);
|
|
45
|
-
const { count, plan } = (0, helpers_1.parseSeedRequest)(req.body);
|
|
46
|
-
const configs = (0, index_1.buildColumnConfigs)(info);
|
|
47
|
-
const gen = await (0, index_1.generateRows)(db, info, configs, Math.min(50, count), plan);
|
|
48
|
-
(0, helpers_1.ok)(res, {
|
|
49
|
-
table: req.params.table,
|
|
50
|
-
previewRows: gen.previewRows,
|
|
51
|
-
warnings: gen.warnings,
|
|
52
|
-
});
|
|
53
|
-
}));
|
|
54
|
-
// Insert the generated rows inside a single transaction
|
|
55
|
-
router.post('/api/tables/:table/seed', (0, helpers_1.wrap)(async (req, res) => {
|
|
56
|
-
const info = await (0, helpers_1.requireTable)(db, req.params.table);
|
|
57
|
-
if (!info)
|
|
58
|
-
return (0, helpers_1.fail)(res, `Table "${req.params.table}" does not exist.`, 404);
|
|
59
|
-
const { count, plan, truncate } = (0, helpers_1.parseSeedRequest)(req.body);
|
|
60
|
-
const configs = (0, index_1.buildColumnConfigs)(info);
|
|
61
|
-
const t0 = Date.now();
|
|
62
|
-
if (truncate) {
|
|
63
|
-
const clearRes = await db.run(`DELETE FROM ${(0, generator_1.quoteIdentifier)(req.params.table)}`);
|
|
64
|
-
if (!clearRes.success) {
|
|
65
|
-
return (0, helpers_1.fail)(res, clearRes.error ?? 'Failed to clear table before seeding.', 400);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
const gen = await (0, index_1.generateRows)(db, info, configs, count, plan);
|
|
69
|
-
const result = await db.insertRows(req.params.table, gen.rows);
|
|
70
|
-
if (!result.success)
|
|
71
|
-
return (0, helpers_1.fail)(res, result.error ?? 'Seed failed.', 400);
|
|
72
|
-
const elapsedMs = Date.now() - t0;
|
|
73
|
-
(0, helpers_1.ok)(res, {
|
|
74
|
-
message: `${truncate ? 'Cleared table and inserted' : 'Inserted'} ${result.data?.inserted ?? 0} row(s) in ${elapsedMs}ms.`,
|
|
75
|
-
inserted: result.data?.inserted ?? 0,
|
|
76
|
-
skipped: result.data?.skipped ?? 0,
|
|
77
|
-
warnings: gen.warnings,
|
|
78
|
-
elapsedMs,
|
|
79
|
-
}, 201);
|
|
80
|
-
}));
|
|
81
|
-
}
|
|
82
|
-
//# sourceMappingURL=seed.js.map
|
|
1
|
+
Object.defineProperty(exports,"__esModule",{value:!0}),exports.registerSeedRoutes=function(router,ctx){const{db:db}=ctx;router.get("/api/tables/:table/seed/config",(0,helpers_1.wrap)(async(req,res)=>{const info=await(0,helpers_1.requireTable)(db,req.params.table);if(!info)return(0,helpers_1.fail)(res,`Table "${req.params.table}" does not exist.`,404);(0,helpers_1.ok)(res,{table:req.params.table,columns:(0,index_1.buildColumnConfigs)(info),maxRows:index_1.MAX_SEED_ROWS})})),router.get("/api/tables/:table/seed/plan",(0,helpers_1.wrap)(async(req,res)=>{const info=await(0,helpers_1.requireTable)(db,req.params.table);if(!info)return(0,helpers_1.fail)(res,`Table "${req.params.table}" does not exist.`,404);(0,helpers_1.ok)(res,{table:req.params.table,columns:(0,index_1.buildColumnConfigs)(info),maxRows:index_1.MAX_SEED_ROWS})})),router.post("/api/tables/:table/seed/generate",(0,helpers_1.wrap)(async(req,res)=>{const info=await(0,helpers_1.requireTable)(db,req.params.table);if(!info)return(0,helpers_1.fail)(res,`Table "${req.params.table}" does not exist.`,404);const{count:count,plan:plan}=(0,helpers_1.parseSeedRequest)(req.body),configs=(0,index_1.buildColumnConfigs)(info),gen=await(0,index_1.generateRows)(db,info,configs,count,plan);(0,helpers_1.ok)(res,{table:req.params.table,count:gen.rows.length,sql:(0,index_1.buildSeedInsertSql)(req.params.table,gen.rows),previewRows:gen.previewRows,warnings:gen.warnings})})),router.post("/api/tables/:table/seed/preview",(0,helpers_1.wrap)(async(req,res)=>{const info=await(0,helpers_1.requireTable)(db,req.params.table);if(!info)return(0,helpers_1.fail)(res,`Table "${req.params.table}" does not exist.`,404);const{count:count,plan:plan}=(0,helpers_1.parseSeedRequest)(req.body),configs=(0,index_1.buildColumnConfigs)(info),gen=await(0,index_1.generateRows)(db,info,configs,Math.min(50,count),plan);(0,helpers_1.ok)(res,{table:req.params.table,previewRows:gen.previewRows,warnings:gen.warnings})})),router.post("/api/tables/:table/seed",(0,helpers_1.wrap)(async(req,res)=>{const info=await(0,helpers_1.requireTable)(db,req.params.table);if(!info)return(0,helpers_1.fail)(res,`Table "${req.params.table}" does not exist.`,404);const{count:count,plan:plan,truncate:truncate}=(0,helpers_1.parseSeedRequest)(req.body),configs=(0,index_1.buildColumnConfigs)(info),t0=Date.now();if(truncate){const clearRes=await db.run(`DELETE FROM ${(0,generator_1.quoteIdentifier)(req.params.table)}`);if(!clearRes.success)return(0,helpers_1.fail)(res,clearRes.error??"Failed to clear table before seeding.",400)}const gen=await(0,index_1.generateRows)(db,info,configs,count,plan),result=await db.insertRows(req.params.table,gen.rows);if(!result.success)return(0,helpers_1.fail)(res,result.error??"Seed failed.",400);const elapsedMs=Date.now()-t0;(0,helpers_1.ok)(res,{message:`${truncate?"Cleared table and inserted":"Inserted"} ${result.data?.inserted??0} row(s) in ${elapsedMs}ms.`,inserted:result.data?.inserted??0,skipped:result.data?.skipped??0,warnings:gen.warnings,elapsedMs:elapsedMs},201)}))};const generator_1=require("../../sql/generator"),index_1=require("../../data/index"),helpers_1=require("./helpers");
|
|
@@ -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;
|