admindb 2.0.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 +2 -2
- 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 -243
- 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 -432
- 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 -382
- 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 -78
- package/dist/sql/generator.js +1 -308
- 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 +8 -5
- package/dist/views/pages/databases.hbs +0 -18
- package/dist/views/pages/designer.hbs +22 -17
- 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/docs/API.md +144 -0
- package/docs/EXAMPLES.md +576 -0
- package/docs/SECURITY.md +265 -0
- package/package.json +7 -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/db/filters.js
CHANGED
|
@@ -1,158 +1 @@
|
|
|
1
|
-
"
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.escapeLike = escapeLike;
|
|
4
|
-
exports.pushFilterCondition = pushFilterCondition;
|
|
5
|
-
exports.buildFilterClause = buildFilterClause;
|
|
6
|
-
exports.convertPlaceholdersToPostgres = convertPlaceholdersToPostgres;
|
|
7
|
-
const generator_1 = require("../sql/generator");
|
|
8
|
-
/** Escape LIKE wildcards so user filter text is matched literally. */
|
|
9
|
-
function escapeLike(s) {
|
|
10
|
-
return String(s).replace(/[\\%_]/g, (m) => '\\' + m);
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* Build a parameterized WHERE clause from per-column filters.
|
|
14
|
-
*
|
|
15
|
-
* A filter value is either:
|
|
16
|
-
* - the legacy string syntax: `=value` exact, `!=value`, `>value`, `>=value`,
|
|
17
|
-
* `<value`, `<=value`, `value*` prefix, anything else → substring match; or
|
|
18
|
-
* - a structured `FilterCondition` (or array of them) produced by the
|
|
19
|
-
* type-aware filter form (FK dropdowns, boolean toggles, date/number ranges).
|
|
20
|
-
*/
|
|
21
|
-
function pushFilterCondition(conds, params, quotedCol, c) {
|
|
22
|
-
const value = String(c.value ?? '');
|
|
23
|
-
switch (c.op) {
|
|
24
|
-
case 'eq':
|
|
25
|
-
conds.push(`${quotedCol} = ?`);
|
|
26
|
-
params.push(value);
|
|
27
|
-
break;
|
|
28
|
-
case 'neq':
|
|
29
|
-
conds.push(`${quotedCol} != ?`);
|
|
30
|
-
params.push(value);
|
|
31
|
-
break;
|
|
32
|
-
case 'gt':
|
|
33
|
-
conds.push(`${quotedCol} > ?`);
|
|
34
|
-
params.push(value);
|
|
35
|
-
break;
|
|
36
|
-
case 'gte':
|
|
37
|
-
conds.push(`${quotedCol} >= ?`);
|
|
38
|
-
params.push(value);
|
|
39
|
-
break;
|
|
40
|
-
case 'lt':
|
|
41
|
-
conds.push(`${quotedCol} < ?`);
|
|
42
|
-
params.push(value);
|
|
43
|
-
break;
|
|
44
|
-
case 'lte':
|
|
45
|
-
conds.push(`${quotedCol} <= ?`);
|
|
46
|
-
params.push(value);
|
|
47
|
-
break;
|
|
48
|
-
case 'like':
|
|
49
|
-
conds.push(`${quotedCol} LIKE ? ESCAPE '\\'`);
|
|
50
|
-
params.push('%' + escapeLike(value) + '%');
|
|
51
|
-
break;
|
|
52
|
-
case 'prefix':
|
|
53
|
-
conds.push(`${quotedCol} LIKE ? ESCAPE '\\'`);
|
|
54
|
-
params.push(escapeLike(value) + '%');
|
|
55
|
-
break;
|
|
56
|
-
case 'between':
|
|
57
|
-
conds.push(`${quotedCol} >= ?`);
|
|
58
|
-
params.push(value);
|
|
59
|
-
conds.push(`${quotedCol} <= ?`);
|
|
60
|
-
params.push(String(c.max ?? ''));
|
|
61
|
-
break;
|
|
62
|
-
case 'null':
|
|
63
|
-
conds.push(`${quotedCol} IS NULL`);
|
|
64
|
-
break;
|
|
65
|
-
case 'notnull':
|
|
66
|
-
conds.push(`${quotedCol} IS NOT NULL`);
|
|
67
|
-
break;
|
|
68
|
-
default:
|
|
69
|
-
break;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
function buildFilterClause(filters, availableCols) {
|
|
73
|
-
const conds = [];
|
|
74
|
-
const params = [];
|
|
75
|
-
const colSet = new Set(availableCols);
|
|
76
|
-
for (const [col, raw] of Object.entries(filters ?? {})) {
|
|
77
|
-
if (!colSet.has(col))
|
|
78
|
-
continue;
|
|
79
|
-
const q = (0, generator_1.quoteIdentifier)(col);
|
|
80
|
-
if (Array.isArray(raw)) {
|
|
81
|
-
for (const c of raw) {
|
|
82
|
-
if (c && typeof c === 'object')
|
|
83
|
-
pushFilterCondition(conds, params, q, c);
|
|
84
|
-
}
|
|
85
|
-
continue;
|
|
86
|
-
}
|
|
87
|
-
if (raw && typeof raw === 'object') {
|
|
88
|
-
pushFilterCondition(conds, params, q, raw);
|
|
89
|
-
continue;
|
|
90
|
-
}
|
|
91
|
-
// Legacy string syntax.
|
|
92
|
-
const value = String(raw ?? '').trim();
|
|
93
|
-
if (value === '')
|
|
94
|
-
continue;
|
|
95
|
-
if (value.startsWith('>=')) {
|
|
96
|
-
conds.push(`${q} >= ?`);
|
|
97
|
-
params.push(value.slice(2).trim());
|
|
98
|
-
}
|
|
99
|
-
else if (value.startsWith('<=')) {
|
|
100
|
-
conds.push(`${q} <= ?`);
|
|
101
|
-
params.push(value.slice(2).trim());
|
|
102
|
-
}
|
|
103
|
-
else if (value.startsWith('!=')) {
|
|
104
|
-
conds.push(`${q} != ?`);
|
|
105
|
-
params.push(value.slice(2).trim());
|
|
106
|
-
}
|
|
107
|
-
else if (value.startsWith('=')) {
|
|
108
|
-
conds.push(`${q} = ?`);
|
|
109
|
-
params.push(value.slice(1).trim());
|
|
110
|
-
}
|
|
111
|
-
else if (value.startsWith('>')) {
|
|
112
|
-
conds.push(`${q} > ?`);
|
|
113
|
-
params.push(value.slice(1).trim());
|
|
114
|
-
}
|
|
115
|
-
else if (value.startsWith('<')) {
|
|
116
|
-
conds.push(`${q} < ?`);
|
|
117
|
-
params.push(value.slice(1).trim());
|
|
118
|
-
}
|
|
119
|
-
else if (value.endsWith('*')) {
|
|
120
|
-
conds.push(`${q} LIKE ? ESCAPE '\\'`);
|
|
121
|
-
params.push(escapeLike(value.slice(0, -1)) + '%');
|
|
122
|
-
}
|
|
123
|
-
else {
|
|
124
|
-
conds.push(`${q} LIKE ? ESCAPE '\\'`);
|
|
125
|
-
params.push('%' + escapeLike(value) + '%');
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
return { where: conds.length ? ` WHERE ${conds.join(' AND ')}` : '', params };
|
|
129
|
-
}
|
|
130
|
-
/**
|
|
131
|
-
* Replace SQLite-style `?` placeholders with PostgreSQL-style `$1, $2, ...`
|
|
132
|
-
* placeholders while safely preserving single-quoted string literals.
|
|
133
|
-
*/
|
|
134
|
-
function convertPlaceholdersToPostgres(sql, startIdx = 1) {
|
|
135
|
-
let idx = startIdx;
|
|
136
|
-
let inString = false;
|
|
137
|
-
let result = '';
|
|
138
|
-
for (let i = 0; i < sql.length; i++) {
|
|
139
|
-
const ch = sql[i];
|
|
140
|
-
if (ch === "'") {
|
|
141
|
-
if (inString && sql[i + 1] === "'") {
|
|
142
|
-
result += "''";
|
|
143
|
-
i++;
|
|
144
|
-
continue;
|
|
145
|
-
}
|
|
146
|
-
inString = !inString;
|
|
147
|
-
result += ch;
|
|
148
|
-
}
|
|
149
|
-
else if (ch === '?' && !inString) {
|
|
150
|
-
result += `$${idx++}`;
|
|
151
|
-
}
|
|
152
|
-
else {
|
|
153
|
-
result += ch;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
return result;
|
|
157
|
-
}
|
|
158
|
-
//# sourceMappingURL=filters.js.map
|
|
1
|
+
Object.defineProperty(exports,"__esModule",{value:!0}),exports.escapeLike=escapeLike,exports.pushFilterCondition=pushFilterCondition,exports.buildFilterClause=function(filters,availableCols){const conds=[],params=[],colSet=new Set(availableCols);for(const[col,raw]of Object.entries(filters??{})){if(!colSet.has(col))continue;const q=(0,generator_1.quoteIdentifier)(col);if(Array.isArray(raw)){for(const c of raw)c&&"object"==typeof c&&pushFilterCondition(conds,params,q,c);continue}if(raw&&"object"==typeof raw){pushFilterCondition(conds,params,q,raw);continue}const value=String(raw??"").trim();""!==value&&(value.startsWith(">=")?(conds.push(`${q} >= ?`),params.push(value.slice(2).trim())):value.startsWith("<=")?(conds.push(`${q} <= ?`),params.push(value.slice(2).trim())):value.startsWith("!=")?(conds.push(`${q} != ?`),params.push(value.slice(2).trim())):value.startsWith("=")?(conds.push(`${q} = ?`),params.push(value.slice(1).trim())):value.startsWith(">")?(conds.push(`${q} > ?`),params.push(value.slice(1).trim())):value.startsWith("<")?(conds.push(`${q} < ?`),params.push(value.slice(1).trim())):value.endsWith("*")?(conds.push(`${q} LIKE ? ESCAPE '\\'`),params.push(escapeLike(value.slice(0,-1))+"%")):(conds.push(`${q} LIKE ? ESCAPE '\\'`),params.push("%"+escapeLike(value)+"%")))}return{where:conds.length?` WHERE ${conds.join(" AND ")}`:"",params:params}},exports.convertPlaceholdersToPostgres=function(sql,startIdx=1){let idx=startIdx,inString=!1,result="";for(let i=0;i<sql.length;i++){const ch=sql[i];if("'"===ch){if(inString&&"'"===sql[i+1]){result+="''",i++;continue}inString=!inString,result+=ch}else result+="?"!==ch||inString?ch:"$"+idx++}return result};const generator_1=require("../sql/generator");function escapeLike(s){return String(s).replace(/[\\%_]/g,m=>"\\"+m)}function pushFilterCondition(conds,params,quotedCol,c){const value=String(c.value??"");switch(c.op){case"eq":conds.push(`${quotedCol} = ?`),params.push(value);break;case"neq":conds.push(`${quotedCol} != ?`),params.push(value);break;case"gt":conds.push(`${quotedCol} > ?`),params.push(value);break;case"gte":conds.push(`${quotedCol} >= ?`),params.push(value);break;case"lt":conds.push(`${quotedCol} < ?`),params.push(value);break;case"lte":conds.push(`${quotedCol} <= ?`),params.push(value);break;case"like":conds.push(`${quotedCol} LIKE ? ESCAPE '\\'`),params.push("%"+escapeLike(value)+"%");break;case"prefix":conds.push(`${quotedCol} LIKE ? ESCAPE '\\'`),params.push(escapeLike(value)+"%");break;case"between":conds.push(`${quotedCol} >= ?`),params.push(value),conds.push(`${quotedCol} <= ?`),params.push(String(c.max??""));break;case"null":conds.push(`${quotedCol} IS NULL`);break;case"notnull":conds.push(`${quotedCol} IS NOT NULL`)}}
|
package/dist/db/index.d.ts
CHANGED
|
@@ -1,8 +1 @@
|
|
|
1
|
-
export * from './types';
|
|
2
|
-
export * from './filters';
|
|
3
|
-
export * from './introspection';
|
|
4
|
-
export * from './migrations';
|
|
5
|
-
export * from './database';
|
|
6
|
-
export * from './postgres';
|
|
7
|
-
export * from './manager';
|
|
8
|
-
export * from './export';
|
|
1
|
+
export * from './types';export * from './filters';export * from './introspection';export * from './migrations';export * from './database';export * from './postgres';export * from './manager';export * from './export';
|
package/dist/db/index.js
CHANGED
|
@@ -1,25 +1 @@
|
|
|
1
|
-
"
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
-
};
|
|
16
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./types"), exports);
|
|
18
|
-
__exportStar(require("./filters"), exports);
|
|
19
|
-
__exportStar(require("./introspection"), exports);
|
|
20
|
-
__exportStar(require("./migrations"), exports);
|
|
21
|
-
__exportStar(require("./database"), exports);
|
|
22
|
-
__exportStar(require("./postgres"), exports);
|
|
23
|
-
__exportStar(require("./manager"), exports);
|
|
24
|
-
__exportStar(require("./export"), exports);
|
|
25
|
-
//# sourceMappingURL=index.js.map
|
|
1
|
+
var __createBinding=this&&this.__createBinding||(Object.create?function(o,m,k,k2){void 0===k2&&(k2=k);var desc=Object.getOwnPropertyDescriptor(m,k);desc&&!("get"in desc?!m.__esModule:desc.writable||desc.configurable)||(desc={enumerable:!0,get:function(){return m[k]}}),Object.defineProperty(o,k2,desc)}:function(o,m,k,k2){void 0===k2&&(k2=k),o[k2]=m[k]}),__exportStar=this&&this.__exportStar||function(m,exports){for(var p in m)"default"===p||Object.prototype.hasOwnProperty.call(exports,p)||__createBinding(exports,m,p)};Object.defineProperty(exports,"__esModule",{value:!0}),__exportStar(require("./types"),exports),__exportStar(require("./filters"),exports),__exportStar(require("./introspection"),exports),__exportStar(require("./migrations"),exports),__exportStar(require("./database"),exports),__exportStar(require("./postgres"),exports),__exportStar(require("./manager"),exports),__exportStar(require("./export"),exports);
|
|
@@ -1,6 +1 @@
|
|
|
1
|
-
import type Database from 'better-sqlite3';
|
|
2
|
-
import type { ReferencingTableInfo, SchemaInfo, TableInfoData, TableListItem } from './types';
|
|
3
|
-
export declare function listTablesSync(db: Database.Database): TableListItem[];
|
|
4
|
-
export declare function getTableInfoSync(db: Database.Database, table: string): TableInfoData;
|
|
5
|
-
export declare function getSchemaSync(db: Database.Database, table: string): SchemaInfo;
|
|
6
|
-
export declare function getReferencingTablesSync(db: Database.Database, table: string): ReferencingTableInfo[];
|
|
1
|
+
import type Database from 'better-sqlite3';import type {ReferencingTableInfo,SchemaInfo,TableInfoData,TableListItem} from './types';export declare function listTablesSync(db:Database.Database):TableListItem[];export declare function getTableInfoSync(db:Database.Database,table:string):TableInfoData;export declare function getSchemaSync(db:Database.Database,table:string):SchemaInfo;export declare function getReferencingTablesSync(db:Database.Database,table:string):ReferencingTableInfo[];
|
package/dist/db/introspection.js
CHANGED
|
@@ -1,172 +1 @@
|
|
|
1
|
-
"
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.listTablesSync = listTablesSync;
|
|
4
|
-
exports.getTableInfoSync = getTableInfoSync;
|
|
5
|
-
exports.getSchemaSync = getSchemaSync;
|
|
6
|
-
exports.getReferencingTablesSync = getReferencingTablesSync;
|
|
7
|
-
const generator_1 = require("../sql/generator");
|
|
8
|
-
function listTablesSync(db) {
|
|
9
|
-
const rows = db
|
|
10
|
-
.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%' ORDER BY name")
|
|
11
|
-
.all();
|
|
12
|
-
return rows.map((r) => ({ name: r.name }));
|
|
13
|
-
}
|
|
14
|
-
/** Get all tables non-internal in the SQLite database. */
|
|
15
|
-
function getTableNames(db) {
|
|
16
|
-
return db
|
|
17
|
-
.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%'")
|
|
18
|
-
.all().map((r) => r.name);
|
|
19
|
-
}
|
|
20
|
-
/** Discover all foreign keys declared across all other tables pointing to `targetTable`. */
|
|
21
|
-
function getIncomingFks(db, targetTable) {
|
|
22
|
-
const refs = [];
|
|
23
|
-
for (const t of getTableNames(db)) {
|
|
24
|
-
if (t === targetTable)
|
|
25
|
-
continue;
|
|
26
|
-
try {
|
|
27
|
-
const fks = db.prepare(`PRAGMA foreign_key_list(${(0, generator_1.quoteIdentifier)(t)})`).all();
|
|
28
|
-
for (const fk of fks) {
|
|
29
|
-
if (fk.table === targetTable)
|
|
30
|
-
refs.push({ table: t, from: fk.from, to: fk.to ?? '' });
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
catch {
|
|
34
|
-
/* ignore unreadable tables */
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
return refs;
|
|
38
|
-
}
|
|
39
|
-
function getTableInfoSync(db, table) {
|
|
40
|
-
const cols = db.prepare(`PRAGMA table_info(${(0, generator_1.quoteIdentifier)(table)})`).all();
|
|
41
|
-
const fks = db.prepare(`PRAGMA foreign_key_list(${(0, generator_1.quoteIdentifier)(table)})`).all();
|
|
42
|
-
const primaryKey = cols
|
|
43
|
-
.filter((c) => c.pk > 0)
|
|
44
|
-
.sort((a, b) => a.pk - b.pk)
|
|
45
|
-
.map((c) => c.name);
|
|
46
|
-
const indexRows = db
|
|
47
|
-
.prepare(`PRAGMA index_list(${(0, generator_1.quoteIdentifier)(table)})`)
|
|
48
|
-
.all();
|
|
49
|
-
const indexes = indexRows.map((ix) => {
|
|
50
|
-
const ixCols = db
|
|
51
|
-
.prepare(`PRAGMA index_info(${(0, generator_1.quoteIdentifier)(ix.name)})`)
|
|
52
|
-
.all().map((c) => c.name);
|
|
53
|
-
const sqlRow = db
|
|
54
|
-
.prepare("SELECT sql FROM sqlite_master WHERE type = 'index' AND name = ?")
|
|
55
|
-
.get(ix.name);
|
|
56
|
-
return {
|
|
57
|
-
name: ix.name,
|
|
58
|
-
unique: !!ix.unique,
|
|
59
|
-
partial: ix.partial,
|
|
60
|
-
origin: ix.origin,
|
|
61
|
-
columns: ixCols,
|
|
62
|
-
sql: sqlRow?.sql ?? null,
|
|
63
|
-
};
|
|
64
|
-
});
|
|
65
|
-
const ddlRow = db
|
|
66
|
-
.prepare("SELECT sql FROM sqlite_master WHERE type = 'table' AND name = ?")
|
|
67
|
-
.get(table);
|
|
68
|
-
return {
|
|
69
|
-
table,
|
|
70
|
-
columns: cols.map((c) => ({
|
|
71
|
-
cid: c.cid,
|
|
72
|
-
name: c.name,
|
|
73
|
-
type: c.type,
|
|
74
|
-
notnull: c.notnull,
|
|
75
|
-
dflt_value: c.dflt_value,
|
|
76
|
-
pk: c.pk,
|
|
77
|
-
})),
|
|
78
|
-
foreignKeys: fks.map((f) => ({
|
|
79
|
-
id: f.id,
|
|
80
|
-
seq: f.seq,
|
|
81
|
-
table: f.table,
|
|
82
|
-
from: f.from,
|
|
83
|
-
to: f.to,
|
|
84
|
-
on_update: f.on_update,
|
|
85
|
-
on_delete: f.on_delete,
|
|
86
|
-
})),
|
|
87
|
-
primaryKey,
|
|
88
|
-
indexes,
|
|
89
|
-
sql: ddlRow?.sql ?? null,
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
function getSchemaSync(db, table) {
|
|
93
|
-
const info = getTableInfoSync(db, table);
|
|
94
|
-
if (!info || info.columns.length === 0)
|
|
95
|
-
throw new Error(`Table "${table}" does not exist.`);
|
|
96
|
-
const foreignKeys = info.foreignKeys;
|
|
97
|
-
const indexes = info.indexes;
|
|
98
|
-
const uniqueCols = new Set();
|
|
99
|
-
const indexedCols = new Set();
|
|
100
|
-
for (const ix of indexes) {
|
|
101
|
-
if (ix.unique)
|
|
102
|
-
ix.columns.forEach((c) => uniqueCols.add(c));
|
|
103
|
-
if (ix.origin === 'c')
|
|
104
|
-
ix.columns.forEach((c) => indexedCols.add(c));
|
|
105
|
-
}
|
|
106
|
-
const refs = getIncomingFks(db, table);
|
|
107
|
-
const refsByTo = new Map();
|
|
108
|
-
for (const r of refs) {
|
|
109
|
-
const arr = refsByTo.get(r.to) ?? [];
|
|
110
|
-
arr.push({ table: r.table, from: r.from });
|
|
111
|
-
refsByTo.set(r.to, arr);
|
|
112
|
-
}
|
|
113
|
-
const fkByFrom = new Map(foreignKeys.map((fk) => [fk.from, fk]));
|
|
114
|
-
const columns = info.columns.map((c) => {
|
|
115
|
-
const unique = c.pk > 0 || uniqueCols.has(c.name);
|
|
116
|
-
const indexed = indexedCols.has(c.name);
|
|
117
|
-
const referencedBy = refsByTo.get(c.name) ?? [];
|
|
118
|
-
const fk = fkByFrom.get(c.name) ?? null;
|
|
119
|
-
const dropBlockers = [];
|
|
120
|
-
if (c.pk > 0)
|
|
121
|
-
dropBlockers.push('Is part of the primary key');
|
|
122
|
-
if (unique && c.pk === 0)
|
|
123
|
-
dropBlockers.push('Has a UNIQUE constraint');
|
|
124
|
-
if (indexed)
|
|
125
|
-
dropBlockers.push('Is used by an index');
|
|
126
|
-
if (referencedBy.length)
|
|
127
|
-
dropBlockers.push(`Referenced by a foreign key in "${referencedBy[0].table}"`);
|
|
128
|
-
if (fk)
|
|
129
|
-
dropBlockers.push('Is part of a foreign key');
|
|
130
|
-
return {
|
|
131
|
-
...c,
|
|
132
|
-
unique,
|
|
133
|
-
indexed,
|
|
134
|
-
referencedBy,
|
|
135
|
-
fk,
|
|
136
|
-
canDrop: dropBlockers.length === 0,
|
|
137
|
-
dropBlockers,
|
|
138
|
-
};
|
|
139
|
-
});
|
|
140
|
-
return {
|
|
141
|
-
table,
|
|
142
|
-
columns,
|
|
143
|
-
foreignKeys,
|
|
144
|
-
indexes,
|
|
145
|
-
references: refs,
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
function getReferencingTablesSync(db, table) {
|
|
149
|
-
const refs = getIncomingFks(db, table);
|
|
150
|
-
const byTable = new Map();
|
|
151
|
-
for (const r of refs) {
|
|
152
|
-
const arr = byTable.get(r.table) ?? [];
|
|
153
|
-
arr.push({ from: r.from, to: r.to });
|
|
154
|
-
byTable.set(r.table, arr);
|
|
155
|
-
}
|
|
156
|
-
const result = [];
|
|
157
|
-
for (const [t, tRefs] of byTable) {
|
|
158
|
-
let refCount = 0;
|
|
159
|
-
try {
|
|
160
|
-
const conds = tRefs.map((r) => `${(0, generator_1.quoteIdentifier)(r.from)} IS NOT NULL`);
|
|
161
|
-
const row = db.prepare(`SELECT COUNT(*) AS c FROM ${(0, generator_1.quoteIdentifier)(t)} WHERE ${conds.join(' OR ')}`).get();
|
|
162
|
-
refCount = Number(row.c);
|
|
163
|
-
}
|
|
164
|
-
catch {
|
|
165
|
-
/* count is best-effort */
|
|
166
|
-
}
|
|
167
|
-
result.push({ table: t, refs: tRefs, refCount });
|
|
168
|
-
}
|
|
169
|
-
result.sort((a, b) => a.table.localeCompare(b.table));
|
|
170
|
-
return result;
|
|
171
|
-
}
|
|
172
|
-
//# sourceMappingURL=introspection.js.map
|
|
1
|
+
Object.defineProperty(exports,"__esModule",{value:!0}),exports.listTablesSync=function(db){return db.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%' ORDER BY name").all().map(r=>({name:r.name}))},exports.getTableInfoSync=getTableInfoSync,exports.getSchemaSync=function(db,table){const info=getTableInfoSync(db,table);if(!info||0===info.columns.length)throw new Error(`Table "${table}" does not exist.`);const foreignKeys=info.foreignKeys,indexes=info.indexes,uniqueCols=new Set,indexedCols=new Set;for(const ix of indexes)ix.unique&&ix.columns.forEach(c=>uniqueCols.add(c)),"c"===ix.origin&&ix.columns.forEach(c=>indexedCols.add(c));const refs=getIncomingFks(db,table),refsByTo=new Map;for(const r of refs){const arr=refsByTo.get(r.to)??[];arr.push({table:r.table,from:r.from}),refsByTo.set(r.to,arr)}const fkByFrom=new Map(foreignKeys.map(fk=>[fk.from,fk])),columns=info.columns.map(c=>{const unique=c.pk>0||uniqueCols.has(c.name),indexed=indexedCols.has(c.name),referencedBy=refsByTo.get(c.name)??[],fk=fkByFrom.get(c.name)??null,dropBlockers=[];return c.pk>0&&dropBlockers.push("Is part of the primary key"),unique&&0===c.pk&&dropBlockers.push("Has a UNIQUE constraint"),indexed&&dropBlockers.push("Is used by an index"),referencedBy.length&&dropBlockers.push(`Referenced by a foreign key in "${referencedBy[0].table}"`),fk&&dropBlockers.push("Is part of a foreign key"),{...c,unique:unique,indexed:indexed,referencedBy:referencedBy,fk:fk,canDrop:0===dropBlockers.length,dropBlockers:dropBlockers}});return{table:table,columns:columns,foreignKeys:foreignKeys,indexes:indexes,references:refs}},exports.getReferencingTablesSync=function(db,table){const refs=getIncomingFks(db,table),byTable=new Map;for(const r of refs){const arr=byTable.get(r.table)??[];arr.push({from:r.from,to:r.to}),byTable.set(r.table,arr)}const result=[];for(const[t,tRefs]of byTable){let refCount=0;try{const conds=tRefs.map(r=>`${(0,generator_1.quoteIdentifier)(r.from)} IS NOT NULL`),row=db.prepare(`SELECT COUNT(*) AS c FROM ${(0,generator_1.quoteIdentifier)(t)} WHERE ${conds.join(" OR ")}`).get();refCount=Number(row.c)}catch{}result.push({table:t,refs:tRefs,refCount:refCount})}return result.sort((a,b)=>a.table.localeCompare(b.table)),result};const generator_1=require("../sql/generator");function getIncomingFks(db,targetTable){const refs=[];for(const t of function(db){return db.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%'").all().map(r=>r.name)}(db))if(t!==targetTable)try{const fks=db.prepare(`PRAGMA foreign_key_list(${(0,generator_1.quoteIdentifier)(t)})`).all();for(const fk of fks)fk.table===targetTable&&refs.push({table:t,from:fk.from,to:fk.to??""})}catch{}return refs}function getTableInfoSync(db,table){const cols=db.prepare(`PRAGMA table_info(${(0,generator_1.quoteIdentifier)(table)})`).all(),fks=db.prepare(`PRAGMA foreign_key_list(${(0,generator_1.quoteIdentifier)(table)})`).all(),primaryKey=cols.filter(c=>c.pk>0).sort((a,b)=>a.pk-b.pk).map(c=>c.name),indexes=db.prepare(`PRAGMA index_list(${(0,generator_1.quoteIdentifier)(table)})`).all().map(ix=>{const ixCols=db.prepare(`PRAGMA index_info(${(0,generator_1.quoteIdentifier)(ix.name)})`).all().map(c=>c.name),sqlRow=db.prepare("SELECT sql FROM sqlite_master WHERE type = 'index' AND name = ?").get(ix.name);return{name:ix.name,unique:!!ix.unique,partial:ix.partial,origin:ix.origin,columns:ixCols,sql:sqlRow?.sql??null}}),ddlRow=db.prepare("SELECT sql FROM sqlite_master WHERE type = 'table' AND name = ?").get(table);return{table:table,columns:cols.map(c=>({cid:c.cid,name:c.name,type:c.type,notnull:c.notnull,dflt_value:c.dflt_value,pk:c.pk})),foreignKeys:fks.map(f=>({id:f.id,seq:f.seq,table:f.table,from:f.from,to:f.to,on_update:f.on_update,on_delete:f.on_delete})),primaryKey:primaryKey,indexes:indexes,sql:ddlRow?.sql??null}}
|
package/dist/db/manager.d.ts
CHANGED
|
@@ -1,81 +1 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import { type Logger } from '../utils/logger';
|
|
3
|
-
export interface DbManagerOptions {
|
|
4
|
-
/** Directory of database files. Scanned for known extensions; new DBs are created here. */
|
|
5
|
-
dir?: string;
|
|
6
|
-
/** Explicit database file paths or connection strings. */
|
|
7
|
-
files?: string[];
|
|
8
|
-
/** Named database connections map (e.g. { "mydb": "postgresql://...", "name1": "postgresql://..." }). */
|
|
9
|
-
connections?: Record<string, string>;
|
|
10
|
-
/** Open every managed database read-only (no writes, no create/delete of files). */
|
|
11
|
-
readonly?: boolean;
|
|
12
|
-
}
|
|
13
|
-
export interface DatabaseEntry {
|
|
14
|
-
/** Stable, URL-safe id (usually the file name or connection name, deduped on collision). */
|
|
15
|
-
id: string;
|
|
16
|
-
/** Name for display. */
|
|
17
|
-
name: string;
|
|
18
|
-
/** Path on disk or sanitized connection URI. */
|
|
19
|
-
path: string;
|
|
20
|
-
/** Database dialect (sqlite or postgres). */
|
|
21
|
-
dialect: 'sqlite' | 'postgres';
|
|
22
|
-
size: number;
|
|
23
|
-
modified: string;
|
|
24
|
-
/** Whether this specific database is opened in read-only mode. */
|
|
25
|
-
readonly: boolean;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Manages multiple SQLite database files and PostgreSQL database connections.
|
|
29
|
-
*
|
|
30
|
-
* Databases come from three sources:
|
|
31
|
-
* - a `connections` map — named PostgreSQL or SQLite connection strings (e.g. from JSON config),
|
|
32
|
-
* - a `dir` — every SQLite file with a known extension is scanned in,
|
|
33
|
-
* - an explicit `files[]` array — specific file locations or connection strings.
|
|
34
|
-
*/
|
|
35
|
-
export declare class DbManager {
|
|
36
|
-
private logger;
|
|
37
|
-
private dir?;
|
|
38
|
-
private createDir;
|
|
39
|
-
private readonly readonlyMode;
|
|
40
|
-
private files;
|
|
41
|
-
private idByPath;
|
|
42
|
-
private pathById;
|
|
43
|
-
private nameById;
|
|
44
|
-
private readonlyById;
|
|
45
|
-
private openDbs;
|
|
46
|
-
constructor(options: DbManagerOptions | string, logger?: Logger);
|
|
47
|
-
get directory(): string;
|
|
48
|
-
/** True when this manager opens every database read-only. */
|
|
49
|
-
get isReadOnly(): boolean;
|
|
50
|
-
isDbFile(name: string): boolean;
|
|
51
|
-
private registerConnections;
|
|
52
|
-
private registerDirFiles;
|
|
53
|
-
private registerExplicitFiles;
|
|
54
|
-
private addNamedTarget;
|
|
55
|
-
private addFile;
|
|
56
|
-
/** List all managed databases (metadata only — does not open them). */
|
|
57
|
-
list(): DatabaseEntry[];
|
|
58
|
-
has(id: string): boolean;
|
|
59
|
-
/** True if global manager is in readonly mode or this database is explicitly marked read-only. */
|
|
60
|
-
isDbReadOnly(id: string): boolean;
|
|
61
|
-
/** Set or toggle read-only mode for a specific database id. */
|
|
62
|
-
setReadonly(id: string, readonly: boolean): void;
|
|
63
|
-
/** Open (and cache) a database by id; creates the file if it is new SQLite database. */
|
|
64
|
-
open(id: string, readonlyOverride?: boolean): IDatabase;
|
|
65
|
-
/**
|
|
66
|
-
* Register and open an existing database file by path, returning its id.
|
|
67
|
-
* Used by the "Open an existing database" file browser. Validates that the
|
|
68
|
-
* file is a readable SQLite database before keeping it registered.
|
|
69
|
-
*/
|
|
70
|
-
openFile(absPath: string, readonly?: boolean): string;
|
|
71
|
-
get(id: string): IDatabase | undefined;
|
|
72
|
-
/** Count the tables in a database (opens it if necessary). */
|
|
73
|
-
countTables(id: string): Promise<number>;
|
|
74
|
-
/** Create a new (empty) SQLite database. Returns its id. */
|
|
75
|
-
create(name: string): string;
|
|
76
|
-
/** Dynamically register a named PostgreSQL or SQLite connection string. Returns its id. */
|
|
77
|
-
addConnection(name: string, connectionString: string, readonly?: boolean): string;
|
|
78
|
-
/** Close and delete a database file (including WAL/SHM sidecars). */
|
|
79
|
-
remove(id: string): void;
|
|
80
|
-
closeAll(): void;
|
|
81
|
-
}
|
|
1
|
+
import type {IDatabase} from './types';import{type Logger} from '../utils/logger';export interface DbManagerOptions{dir?:string;files?:string[];connections?:Record<string,string>;readonly ?:boolean;}export interface DatabaseEntry{id:string;name:string;path:string;dialect:'sqlite'|'postgres';size:number;modified:string;readonly :boolean;}export declare class DbManager{private logger;private dir?;private createDir;private readonly readonlyMode;private files;private idByPath;private pathById;private nameById;private readonlyById;private openDbs;constructor(options:DbManagerOptions|string,logger?:Logger);get directory():string;get isReadOnly():boolean;isDbFile(name:string):boolean;private registerConnections;private registerDirFiles;private registerExplicitFiles;private addNamedTarget;private addFile;list():DatabaseEntry[];has(id:string):boolean;isDbReadOnly(id:string):boolean;setReadonly(id:string,readonly :boolean):void;open(id:string,readonlyOverride?:boolean):IDatabase;openFile(absPath:string,readonly ?:boolean):string;get(id:string):IDatabase|undefined;countTables(id:string):Promise<number>;create(name:string):string;addConnection(name:string,connectionString:string,readonly ?:boolean):string;remove(id:string):void;closeAll():void;}
|