sqlite-hub 1.4.0 → 1.5.0
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 +9 -0
- package/bin/sqlite-hub.js +555 -122
- package/docs/API.md +30 -0
- package/docs/CLI.md +22 -0
- package/docs/CLI_API_PARITY.md +61 -0
- package/docs/changelog.md +9 -1
- package/docs/guidelines/AGENTS.md +32 -0
- package/docs/{DESIGN_GUIDELINES.md → guidelines/DESIGN.md} +10 -0
- package/docs/todo.md +1 -13
- package/frontend/js/api.js +45 -0
- package/frontend/js/app.js +192 -2
- package/frontend/js/components/connectionCard.js +3 -1
- package/frontend/js/components/modal.js +356 -15
- package/frontend/js/components/sidebar.js +41 -7
- package/frontend/js/components/topNav.js +2 -14
- package/frontend/js/router.js +10 -0
- package/frontend/js/store.js +448 -0
- package/frontend/js/utils/inputClear.js +36 -0
- package/frontend/js/utils/syntheticData.js +240 -0
- package/frontend/js/views/backups.js +52 -0
- package/frontend/js/views/data.js +16 -0
- package/frontend/js/views/logs.js +339 -0
- package/frontend/js/views/settings.js +77 -27
- package/frontend/js/views/structure.js +6 -0
- package/frontend/js/views/tableAdvisor.js +385 -0
- package/frontend/js/views/tableDesigner.js +6 -0
- package/frontend/styles/components.css +149 -0
- package/frontend/styles/tailwind.generated.css +1 -1
- package/frontend/styles/views.css +8 -0
- package/package.json +1 -1
- package/server/routes/data.js +45 -0
- package/server/routes/externalApi.js +285 -2
- package/server/routes/logs.js +127 -0
- package/server/server.js +3 -0
- package/server/services/databaseCommandService.js +45 -0
- package/server/services/sqlite/dataBrowserService.js +36 -0
- package/server/services/sqlite/introspection.js +226 -22
- package/server/services/sqlite/syntheticDataGenerator.js +728 -0
- package/server/services/sqlite/tableAdvisor.js +790 -0
- package/server/services/storage/appStateStore.js +773 -169
package/bin/sqlite-hub.js
CHANGED
|
@@ -26,6 +26,9 @@ Usage:
|
|
|
26
26
|
sqlite-hub --database:"name" --documents
|
|
27
27
|
sqlite-hub --database:"name" --documents:"Document Name"
|
|
28
28
|
sqlite-hub --database:"name" --documents:"Document Name" --export
|
|
29
|
+
sqlite-hub --database:"name" --backups
|
|
30
|
+
sqlite-hub --database:"name" --backup
|
|
31
|
+
sqlite-hub --database:"name" --backup:"Before migration"
|
|
29
32
|
sqlite-hub --database:"name" --table:"table_name"
|
|
30
33
|
sqlite-hub --database:"name" --table:"table_name" --export:"primary-key"
|
|
31
34
|
sqlite-hub --database:"name" --table:"table_name" --types:typescript
|
|
@@ -53,6 +56,10 @@ Options:
|
|
|
53
56
|
--documents List Markdown documents for the selected database.
|
|
54
57
|
--documents:"name" Print a document's Markdown content.
|
|
55
58
|
--documents:"name" --export Export a document as a Markdown file.
|
|
59
|
+
--backups List managed backups for the selected database.
|
|
60
|
+
--backup Create and verify a managed backup.
|
|
61
|
+
--backup:"name" Create a backup with a custom name.
|
|
62
|
+
--backup-notes:"text" Add notes to a created backup.
|
|
56
63
|
--table:"table" Print table metadata.
|
|
57
64
|
--table:"table" --export:"pk" Export one row as JSON by primary key or rowid.
|
|
58
65
|
--types:typescript|ts|rust|rs|kotlin|kt|swift
|
|
@@ -191,6 +198,10 @@ function parseCliArguments(argv) {
|
|
|
191
198
|
documents: false,
|
|
192
199
|
documentName: null,
|
|
193
200
|
documentExport: false,
|
|
201
|
+
backups: false,
|
|
202
|
+
backup: false,
|
|
203
|
+
backupName: null,
|
|
204
|
+
backupNotes: null,
|
|
194
205
|
tableName: null,
|
|
195
206
|
typesTarget: null,
|
|
196
207
|
typeName: null,
|
|
@@ -383,6 +394,39 @@ function parseCliArguments(argv) {
|
|
|
383
394
|
continue;
|
|
384
395
|
}
|
|
385
396
|
|
|
397
|
+
if (flag === '--backups') {
|
|
398
|
+
options.backups = true;
|
|
399
|
+
continue;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
if (flag === '--backup') {
|
|
403
|
+
const parsed = takeOptionalFlagValue(value, argv, index);
|
|
404
|
+
|
|
405
|
+
options.backup = true;
|
|
406
|
+
if (parsed.hasValue) {
|
|
407
|
+
options.backupName = parsed.value;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
index = parsed.nextIndex;
|
|
411
|
+
continue;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
if (flag === '--backup-name') {
|
|
415
|
+
const parsed = takeFlagValue(flag, value, argv, index);
|
|
416
|
+
options.backup = true;
|
|
417
|
+
options.backupName = parsed.value;
|
|
418
|
+
index = parsed.nextIndex;
|
|
419
|
+
continue;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
if (flag === '--backup-notes') {
|
|
423
|
+
const parsed = takeFlagValue(flag, value, argv, index);
|
|
424
|
+
options.backup = true;
|
|
425
|
+
options.backupNotes = parsed.value;
|
|
426
|
+
index = parsed.nextIndex;
|
|
427
|
+
continue;
|
|
428
|
+
}
|
|
429
|
+
|
|
386
430
|
if (flag === '--export') {
|
|
387
431
|
if (options.documents && options.documentName && value === undefined) {
|
|
388
432
|
const nextValue = argv[index + 1];
|
|
@@ -506,6 +550,8 @@ function hasDatabaseOperation(options) {
|
|
|
506
550
|
options.documents ||
|
|
507
551
|
options.documentName ||
|
|
508
552
|
options.documentExport ||
|
|
553
|
+
options.backups ||
|
|
554
|
+
options.backup ||
|
|
509
555
|
options.exportTarget ||
|
|
510
556
|
options.tableName ||
|
|
511
557
|
options.typesTarget,
|
|
@@ -825,6 +871,58 @@ function exportDocumentMarkdown({ databaseService, conn, documentName }) {
|
|
|
825
871
|
console.log(`Characters: ${result.document.contentLength}`);
|
|
826
872
|
console.log(`File: ${outputPath}`);
|
|
827
873
|
}
|
|
874
|
+
|
|
875
|
+
function listManagedBackups({ databaseService, conn, options }) {
|
|
876
|
+
const backups = databaseService.listBackups(conn.id);
|
|
877
|
+
|
|
878
|
+
if (options.jsonOutput) {
|
|
879
|
+
console.log(JSON.stringify({ items: backups, total: backups.length }, null, 2));
|
|
880
|
+
return;
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
if (backups.length === 0) {
|
|
884
|
+
console.log(`No backups found for ${conn.label}.`);
|
|
885
|
+
return;
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
console.log(`\nBackups for ${conn.label} (${backups.length}):`);
|
|
889
|
+
console.log('─'.repeat(60));
|
|
890
|
+
|
|
891
|
+
backups.forEach((backup, index) => {
|
|
892
|
+
const fileState = backup.fileExists ? 'available' : 'missing';
|
|
893
|
+
console.log(`${index + 1}. ${backup.name}`);
|
|
894
|
+
console.log(` ID: ${backup.id}`);
|
|
895
|
+
console.log(` Status: ${backup.status} (${fileState})`);
|
|
896
|
+
console.log(` Size: ${formatSize(backup.sizeBytes)}`);
|
|
897
|
+
console.log(` Created: ${backup.createdAt}`);
|
|
898
|
+
console.log(` File: ${backup.path}`);
|
|
899
|
+
if (backup.notes) {
|
|
900
|
+
console.log(` Notes: ${backup.notes}`);
|
|
901
|
+
}
|
|
902
|
+
console.log('');
|
|
903
|
+
});
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
async function createManagedBackup({ databaseService, conn, options }) {
|
|
907
|
+
const backup = await databaseService.createBackup(conn.id, {
|
|
908
|
+
name: options.backupName,
|
|
909
|
+
notes: options.backupNotes,
|
|
910
|
+
context: 'cli',
|
|
911
|
+
});
|
|
912
|
+
|
|
913
|
+
if (options.jsonOutput) {
|
|
914
|
+
console.log(JSON.stringify(backup, null, 2));
|
|
915
|
+
return;
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
console.log(`Backup created: ${backup.name}`);
|
|
919
|
+
console.log(`Status: ${backup.status}`);
|
|
920
|
+
console.log(`Database: ${conn.label}`);
|
|
921
|
+
console.log(`Size: ${formatSize(backup.sizeBytes)}`);
|
|
922
|
+
console.log(`File: ${backup.path}`);
|
|
923
|
+
console.log(`ID: ${backup.id}`);
|
|
924
|
+
}
|
|
925
|
+
|
|
828
926
|
function exportTableRowAsJson({ databaseService, conn, tableName, exportTarget }) {
|
|
829
927
|
const result = databaseService.getTableRow(conn.id, tableName, exportTarget);
|
|
830
928
|
const outputPath = path.resolve(process.cwd(), result.filename);
|
|
@@ -958,191 +1056,526 @@ async function startAndOpen(port) {
|
|
|
958
1056
|
|
|
959
1057
|
function requireDatabaseName(options) {
|
|
960
1058
|
if (!options.databaseName) {
|
|
961
|
-
|
|
962
|
-
process.exit(1);
|
|
1059
|
+
throw new Error('this command requires --database:"name".');
|
|
963
1060
|
}
|
|
964
1061
|
|
|
965
1062
|
return options.databaseName;
|
|
966
1063
|
}
|
|
967
1064
|
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
1065
|
+
function readCliFlags(argv = []) {
|
|
1066
|
+
return argv
|
|
1067
|
+
.filter(argument => String(argument ?? '').startsWith('-'))
|
|
1068
|
+
.map(argument => splitArgument(argument).flag)
|
|
1069
|
+
.filter(Boolean);
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
function describeCliAccess(options, argv = []) {
|
|
1073
|
+
const metadata = {
|
|
1074
|
+
flags: readCliFlags(argv),
|
|
1075
|
+
};
|
|
1076
|
+
const entry = {
|
|
1077
|
+
source: 'cli',
|
|
1078
|
+
action: 'cli.open',
|
|
1079
|
+
targetType: 'app',
|
|
1080
|
+
targetName: 'server',
|
|
1081
|
+
metadata,
|
|
1082
|
+
};
|
|
1083
|
+
|
|
1084
|
+
if (!options) {
|
|
1085
|
+
return {
|
|
1086
|
+
...entry,
|
|
1087
|
+
action: 'cli.parse',
|
|
1088
|
+
targetType: 'command',
|
|
1089
|
+
targetName: 'arguments',
|
|
1090
|
+
};
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
if (options.exportFormat) metadata.exportFormat = options.exportFormat;
|
|
1094
|
+
if (options.typesTarget) metadata.typesTarget = options.typesTarget;
|
|
1095
|
+
if (options.outputPath) metadata.hasOutputPath = true;
|
|
1096
|
+
if (options.jsonOutput) metadata.jsonOutput = true;
|
|
1097
|
+
if (options.force) metadata.force = true;
|
|
971
1098
|
|
|
972
1099
|
if (options.help) {
|
|
973
|
-
|
|
974
|
-
|
|
1100
|
+
return {
|
|
1101
|
+
...entry,
|
|
1102
|
+
action: 'cli.help',
|
|
1103
|
+
targetType: 'app',
|
|
1104
|
+
targetName: 'help',
|
|
1105
|
+
};
|
|
975
1106
|
}
|
|
976
1107
|
|
|
977
1108
|
if (options.version) {
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
1109
|
+
return {
|
|
1110
|
+
...entry,
|
|
1111
|
+
action: 'cli.version',
|
|
1112
|
+
targetType: 'app',
|
|
1113
|
+
targetName: 'version',
|
|
1114
|
+
};
|
|
981
1115
|
}
|
|
982
1116
|
|
|
983
1117
|
if (options.info) {
|
|
984
|
-
|
|
985
|
-
|
|
1118
|
+
return {
|
|
1119
|
+
...entry,
|
|
1120
|
+
action: 'cli.info',
|
|
1121
|
+
targetType: 'app',
|
|
1122
|
+
targetName: 'info',
|
|
1123
|
+
};
|
|
986
1124
|
}
|
|
987
1125
|
|
|
988
1126
|
if (options.open) {
|
|
989
|
-
|
|
990
|
-
|
|
1127
|
+
return entry;
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
if (options.documents) {
|
|
1131
|
+
if (options.documentExport) {
|
|
1132
|
+
return {
|
|
1133
|
+
...entry,
|
|
1134
|
+
action: 'cli.document.export',
|
|
1135
|
+
targetType: 'document',
|
|
1136
|
+
targetName: options.documentName || 'document',
|
|
1137
|
+
};
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
if (options.documentName) {
|
|
1141
|
+
return {
|
|
1142
|
+
...entry,
|
|
1143
|
+
action: 'cli.document.get',
|
|
1144
|
+
targetType: 'document',
|
|
1145
|
+
targetName: options.documentName,
|
|
1146
|
+
};
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
return {
|
|
1150
|
+
...entry,
|
|
1151
|
+
action: 'cli.documents.list',
|
|
1152
|
+
targetType: 'database',
|
|
1153
|
+
targetName: options.databaseName,
|
|
1154
|
+
};
|
|
991
1155
|
}
|
|
992
1156
|
|
|
993
|
-
if (options.
|
|
994
|
-
|
|
1157
|
+
if (options.backups) {
|
|
1158
|
+
return {
|
|
1159
|
+
...entry,
|
|
1160
|
+
action: 'cli.backups.list',
|
|
1161
|
+
targetType: 'database',
|
|
1162
|
+
targetName: options.databaseName,
|
|
1163
|
+
};
|
|
995
1164
|
}
|
|
996
1165
|
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1166
|
+
if (options.backup) {
|
|
1167
|
+
return {
|
|
1168
|
+
...entry,
|
|
1169
|
+
action: 'cli.backup.create',
|
|
1170
|
+
targetType: 'database',
|
|
1171
|
+
targetName: options.databaseName,
|
|
1172
|
+
metadata: {
|
|
1173
|
+
...metadata,
|
|
1174
|
+
hasBackupName: Boolean(options.backupName),
|
|
1175
|
+
hasBackupNotes: Boolean(options.backupNotes),
|
|
1176
|
+
},
|
|
1177
|
+
};
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
if (options.tableName) {
|
|
1181
|
+
if (options.typesTarget) {
|
|
1182
|
+
return {
|
|
1183
|
+
...entry,
|
|
1184
|
+
action: 'cli.table.types.generate',
|
|
1185
|
+
targetType: 'table',
|
|
1186
|
+
targetName: options.tableName,
|
|
1187
|
+
};
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
if (options.exportTarget) {
|
|
1191
|
+
return {
|
|
1192
|
+
...entry,
|
|
1193
|
+
action: 'cli.table.row.export',
|
|
1194
|
+
targetType: 'table',
|
|
1195
|
+
targetName: options.tableName,
|
|
1196
|
+
};
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
return {
|
|
1200
|
+
...entry,
|
|
1201
|
+
action: 'cli.table.get',
|
|
1202
|
+
targetType: 'table',
|
|
1203
|
+
targetName: options.tableName,
|
|
1204
|
+
};
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
if (options.exportTarget) {
|
|
1208
|
+
return {
|
|
1209
|
+
...entry,
|
|
1210
|
+
action: 'cli.query.export',
|
|
1211
|
+
targetType: 'query',
|
|
1212
|
+
targetName: options.exportTarget,
|
|
1213
|
+
};
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
if (options.executeQuery) {
|
|
1217
|
+
return {
|
|
1218
|
+
...entry,
|
|
1219
|
+
action: 'cli.query.execute.saved',
|
|
1220
|
+
targetType: 'query',
|
|
1221
|
+
targetName: options.executeQuery,
|
|
1222
|
+
};
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
if (options.rawQuery) {
|
|
1226
|
+
return {
|
|
1227
|
+
...entry,
|
|
1228
|
+
action: 'cli.query.execute',
|
|
1229
|
+
targetType: 'query',
|
|
1230
|
+
targetName: options.storeName || 'raw query',
|
|
1231
|
+
metadata: {
|
|
1232
|
+
...metadata,
|
|
1233
|
+
hasStoreName: Boolean(options.storeName),
|
|
1234
|
+
},
|
|
1235
|
+
};
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
if (options.showQuery) {
|
|
1239
|
+
return {
|
|
1240
|
+
...entry,
|
|
1241
|
+
action: 'cli.query.get',
|
|
1242
|
+
targetType: 'query',
|
|
1243
|
+
targetName: options.showQuery,
|
|
1244
|
+
};
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
if (options.showNotes) {
|
|
1248
|
+
return {
|
|
1249
|
+
...entry,
|
|
1250
|
+
action: 'cli.query.notes.get',
|
|
1251
|
+
targetType: 'query',
|
|
1252
|
+
targetName: options.showNotes,
|
|
1253
|
+
};
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
if (options.queries) {
|
|
1257
|
+
return {
|
|
1258
|
+
...entry,
|
|
1259
|
+
action: 'cli.queries.list',
|
|
1260
|
+
targetType: 'database',
|
|
1261
|
+
targetName: options.databaseName,
|
|
1262
|
+
};
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
if (options.tables) {
|
|
1266
|
+
return {
|
|
1267
|
+
...entry,
|
|
1268
|
+
action: 'cli.tables.list',
|
|
1269
|
+
targetType: 'database',
|
|
1270
|
+
targetName: options.databaseName,
|
|
1271
|
+
};
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
if (options.pathInfo) {
|
|
1275
|
+
return {
|
|
1276
|
+
...entry,
|
|
1277
|
+
action: 'cli.database.path',
|
|
1278
|
+
targetType: 'database',
|
|
1279
|
+
targetName: options.databaseName,
|
|
1280
|
+
};
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
if (options.sizeInfo) {
|
|
1284
|
+
return {
|
|
1285
|
+
...entry,
|
|
1286
|
+
action: 'cli.database.size',
|
|
1287
|
+
targetType: 'database',
|
|
1288
|
+
targetName: options.databaseName,
|
|
1289
|
+
};
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
if (options.lastOpenedInfo) {
|
|
1293
|
+
return {
|
|
1294
|
+
...entry,
|
|
1295
|
+
action: 'cli.database.lastopened',
|
|
1296
|
+
targetType: 'database',
|
|
1297
|
+
targetName: options.databaseName,
|
|
1298
|
+
};
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
if (options.databaseList && !options.databaseName) {
|
|
1302
|
+
return {
|
|
1303
|
+
...entry,
|
|
1304
|
+
action: 'cli.databases.list',
|
|
1305
|
+
targetType: 'app',
|
|
1306
|
+
targetName: 'databases',
|
|
1307
|
+
};
|
|
1308
|
+
}
|
|
1003
1309
|
|
|
1004
|
-
if (options.
|
|
1005
|
-
|
|
1310
|
+
if (options.databaseName) {
|
|
1311
|
+
return {
|
|
1312
|
+
...entry,
|
|
1313
|
+
action: 'cli.database.get',
|
|
1314
|
+
targetType: 'database',
|
|
1315
|
+
targetName: options.databaseName,
|
|
1316
|
+
};
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
return entry;
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
function recordCliAccess({ appStateStore, entry, startedAtMs, error }) {
|
|
1323
|
+
if (!appStateStore?.recordAccessLog || !entry) {
|
|
1006
1324
|
return;
|
|
1007
1325
|
}
|
|
1008
1326
|
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1327
|
+
try {
|
|
1328
|
+
appStateStore.recordAccessLog({
|
|
1329
|
+
...entry,
|
|
1330
|
+
status: error ? 'error' : 'success',
|
|
1331
|
+
startedAt: new Date(startedAtMs).toISOString(),
|
|
1332
|
+
durationMs: Date.now() - startedAtMs,
|
|
1333
|
+
errorMessage: error ? error.message : null,
|
|
1334
|
+
});
|
|
1335
|
+
} catch {
|
|
1336
|
+
// Access logging must not change CLI behavior or command output.
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1012
1339
|
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1340
|
+
async function main(argv = process.argv.slice(2), dependencies = {}) {
|
|
1341
|
+
const startedAtMs = Date.now();
|
|
1342
|
+
let options = null;
|
|
1343
|
+
let accessEntry = describeCliAccess(null, argv);
|
|
1344
|
+
let accessLogStore = dependencies.appStateStore ?? null;
|
|
1345
|
+
let databaseService = dependencies.databaseService ?? null;
|
|
1346
|
+
let commandError = null;
|
|
1347
|
+
|
|
1348
|
+
function getAccessLogStore() {
|
|
1349
|
+
if (dependencies.disableAccessLog) {
|
|
1350
|
+
return null;
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1353
|
+
if (accessLogStore) {
|
|
1354
|
+
return accessLogStore;
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1357
|
+
if (databaseService?.appStateStore) {
|
|
1358
|
+
accessLogStore = databaseService.appStateStore;
|
|
1359
|
+
return accessLogStore;
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1362
|
+
if (!dependencies.databaseService) {
|
|
1363
|
+
accessLogStore = createAppStateStore();
|
|
1364
|
+
return accessLogStore;
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1367
|
+
return null;
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
try {
|
|
1371
|
+
options = parseCliArguments(argv);
|
|
1372
|
+
accessEntry = describeCliAccess(options, argv);
|
|
1373
|
+
const port = options.port ?? DEFAULT_PORT;
|
|
1374
|
+
|
|
1375
|
+
if (options.help) {
|
|
1376
|
+
printHelp();
|
|
1377
|
+
return;
|
|
1378
|
+
}
|
|
1379
|
+
|
|
1380
|
+
if (options.version) {
|
|
1381
|
+
const { version } = require('../package.json');
|
|
1382
|
+
console.log(`SQLite Hub CLI version ${version}`);
|
|
1383
|
+
return;
|
|
1384
|
+
}
|
|
1385
|
+
|
|
1386
|
+
if (options.info) {
|
|
1387
|
+
await printInfo(port, dependencies);
|
|
1388
|
+
return;
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
if (options.open) {
|
|
1392
|
+
await startAndOpen(port);
|
|
1393
|
+
return;
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1396
|
+
if (options.storeName && !options.rawQuery) {
|
|
1397
|
+
throw new Error('--store requires --query:"sql".');
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1400
|
+
if (options.backup && options.backups) {
|
|
1401
|
+
throw new Error('--backup and --backups cannot be combined.');
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
databaseService =
|
|
1405
|
+
databaseService ??
|
|
1406
|
+
new DatabaseCommandService({
|
|
1407
|
+
appStateStore: getAccessLogStore(),
|
|
1408
|
+
});
|
|
1409
|
+
const connections = databaseService.listDatabases();
|
|
1410
|
+
|
|
1411
|
+
if (options.databaseList && !options.databaseName && !hasDatabaseOperation(options)) {
|
|
1412
|
+
printDatabaseList(connections);
|
|
1413
|
+
return;
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
if (options.databaseName || hasDatabaseOperation(options)) {
|
|
1417
|
+
const dbName = requireDatabaseName(options);
|
|
1418
|
+
const conn = databaseService.getDatabase(dbName);
|
|
1419
|
+
accessEntry.databaseKey = conn.id;
|
|
1420
|
+
accessEntry.metadata = {
|
|
1421
|
+
...(accessEntry.metadata ?? {}),
|
|
1422
|
+
databaseLabel: conn.label ?? null,
|
|
1423
|
+
};
|
|
1424
|
+
|
|
1425
|
+
if (options.backups) {
|
|
1426
|
+
listManagedBackups({ databaseService, conn, options });
|
|
1427
|
+
return;
|
|
1428
|
+
}
|
|
1429
|
+
|
|
1430
|
+
if (options.backup) {
|
|
1431
|
+
await createManagedBackup({ databaseService, conn, options });
|
|
1432
|
+
return;
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
if (options.documents) {
|
|
1436
|
+
if (options.documentName) {
|
|
1437
|
+
if (options.documentExport) {
|
|
1438
|
+
exportDocumentMarkdown({
|
|
1439
|
+
databaseService,
|
|
1440
|
+
conn,
|
|
1441
|
+
documentName: options.documentName,
|
|
1442
|
+
});
|
|
1443
|
+
} else {
|
|
1444
|
+
showDocumentMarkdown({
|
|
1445
|
+
databaseService,
|
|
1446
|
+
conn,
|
|
1447
|
+
documentName: options.documentName,
|
|
1448
|
+
});
|
|
1449
|
+
}
|
|
1450
|
+
return;
|
|
1027
1451
|
}
|
|
1452
|
+
|
|
1453
|
+
listDocuments(databaseService, conn);
|
|
1028
1454
|
return;
|
|
1029
1455
|
}
|
|
1030
1456
|
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1457
|
+
if (
|
|
1458
|
+
options.tableName ||
|
|
1459
|
+
options.tables ||
|
|
1460
|
+
options.queries ||
|
|
1461
|
+
options.executeQuery ||
|
|
1462
|
+
options.rawQuery ||
|
|
1463
|
+
options.showQuery ||
|
|
1464
|
+
options.showNotes ||
|
|
1465
|
+
options.exportTarget ||
|
|
1466
|
+
options.typesTarget
|
|
1467
|
+
) {
|
|
1468
|
+
if (options.tableName) {
|
|
1469
|
+
if (options.typesTarget) {
|
|
1470
|
+
generateTypes({
|
|
1471
|
+
databaseService,
|
|
1472
|
+
conn,
|
|
1473
|
+
tableName: options.tableName,
|
|
1474
|
+
options,
|
|
1475
|
+
});
|
|
1476
|
+
return;
|
|
1477
|
+
}
|
|
1478
|
+
|
|
1479
|
+
if (options.exportTarget) {
|
|
1480
|
+
exportTableRowAsJson({
|
|
1481
|
+
databaseService,
|
|
1482
|
+
conn,
|
|
1483
|
+
tableName: options.tableName,
|
|
1484
|
+
exportTarget: options.exportTarget,
|
|
1485
|
+
});
|
|
1486
|
+
} else {
|
|
1487
|
+
printTableInfo(databaseService.getTable(conn.id, options.tableName));
|
|
1488
|
+
}
|
|
1034
1489
|
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
options.rawQuery ||
|
|
1041
|
-
options.showQuery ||
|
|
1042
|
-
options.showNotes ||
|
|
1043
|
-
options.exportTarget ||
|
|
1044
|
-
options.typesTarget
|
|
1045
|
-
) {
|
|
1046
|
-
if (options.tableName) {
|
|
1047
|
-
if (options.typesTarget) {
|
|
1048
|
-
generateTypes({
|
|
1490
|
+
return;
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1493
|
+
if (options.exportTarget) {
|
|
1494
|
+
exportSavedQuery({
|
|
1049
1495
|
databaseService,
|
|
1050
1496
|
conn,
|
|
1051
|
-
|
|
1052
|
-
options,
|
|
1497
|
+
queryName: options.exportTarget,
|
|
1498
|
+
format: options.exportFormat,
|
|
1053
1499
|
});
|
|
1054
1500
|
return;
|
|
1055
1501
|
}
|
|
1056
1502
|
|
|
1057
|
-
if (options.
|
|
1058
|
-
|
|
1503
|
+
if (options.executeQuery) {
|
|
1504
|
+
executeSavedQuery({
|
|
1059
1505
|
databaseService,
|
|
1060
1506
|
conn,
|
|
1061
|
-
|
|
1062
|
-
exportTarget: options.exportTarget,
|
|
1507
|
+
queryName: options.executeQuery,
|
|
1063
1508
|
});
|
|
1064
|
-
|
|
1065
|
-
printTableInfo(databaseService.getTable(conn.id, options.tableName));
|
|
1509
|
+
return;
|
|
1066
1510
|
}
|
|
1067
1511
|
|
|
1068
|
-
|
|
1069
|
-
|
|
1512
|
+
if (options.rawQuery) {
|
|
1513
|
+
executeRawQuery({
|
|
1514
|
+
databaseService,
|
|
1515
|
+
conn,
|
|
1516
|
+
sql: options.rawQuery,
|
|
1517
|
+
storeName: options.storeName,
|
|
1518
|
+
});
|
|
1519
|
+
return;
|
|
1520
|
+
}
|
|
1070
1521
|
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
queryName: options.exportTarget,
|
|
1076
|
-
format: options.exportFormat,
|
|
1077
|
-
});
|
|
1078
|
-
return;
|
|
1079
|
-
}
|
|
1522
|
+
if (options.showQuery) {
|
|
1523
|
+
showSavedQuery({ databaseService, conn, queryName: options.showQuery });
|
|
1524
|
+
return;
|
|
1525
|
+
}
|
|
1080
1526
|
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
queryName: options.executeQuery,
|
|
1086
|
-
});
|
|
1087
|
-
return;
|
|
1088
|
-
}
|
|
1527
|
+
if (options.showNotes) {
|
|
1528
|
+
showSavedQueryNotes({ databaseService, conn, queryName: options.showNotes });
|
|
1529
|
+
return;
|
|
1530
|
+
}
|
|
1089
1531
|
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
sql: options.rawQuery,
|
|
1095
|
-
storeName: options.storeName,
|
|
1096
|
-
});
|
|
1097
|
-
return;
|
|
1098
|
-
}
|
|
1532
|
+
if (options.queries) {
|
|
1533
|
+
listSavedQueries(databaseService, conn);
|
|
1534
|
+
return;
|
|
1535
|
+
}
|
|
1099
1536
|
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1537
|
+
if (options.tables) {
|
|
1538
|
+
printTables(conn, databaseService.listTables(conn.id));
|
|
1539
|
+
return;
|
|
1540
|
+
}
|
|
1103
1541
|
}
|
|
1104
1542
|
|
|
1105
|
-
if (options.
|
|
1106
|
-
|
|
1543
|
+
if (options.pathInfo) {
|
|
1544
|
+
console.log(conn.path);
|
|
1107
1545
|
return;
|
|
1108
1546
|
}
|
|
1109
1547
|
|
|
1110
|
-
if (options.
|
|
1111
|
-
|
|
1548
|
+
if (options.sizeInfo) {
|
|
1549
|
+
console.log(formatSize(conn.sizeBytes));
|
|
1112
1550
|
return;
|
|
1113
1551
|
}
|
|
1114
1552
|
|
|
1115
|
-
if (options.
|
|
1116
|
-
|
|
1553
|
+
if (options.lastOpenedInfo) {
|
|
1554
|
+
console.log(conn.lastOpenedAt);
|
|
1117
1555
|
return;
|
|
1118
1556
|
}
|
|
1119
|
-
}
|
|
1120
|
-
|
|
1121
|
-
if (options.pathInfo) {
|
|
1122
|
-
console.log(conn.path);
|
|
1123
|
-
return;
|
|
1124
|
-
}
|
|
1125
1557
|
|
|
1126
|
-
|
|
1127
|
-
console.log(formatSize(conn.sizeBytes));
|
|
1558
|
+
printSingleDatabaseInfo(conn);
|
|
1128
1559
|
return;
|
|
1129
1560
|
}
|
|
1130
1561
|
|
|
1131
|
-
if (options.
|
|
1132
|
-
|
|
1562
|
+
if (options.databaseList) {
|
|
1563
|
+
printDatabaseList(connections);
|
|
1133
1564
|
return;
|
|
1134
1565
|
}
|
|
1135
1566
|
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1567
|
+
await startAndOpen(port);
|
|
1568
|
+
} catch (error) {
|
|
1569
|
+
commandError = error;
|
|
1570
|
+
throw error;
|
|
1571
|
+
} finally {
|
|
1572
|
+
recordCliAccess({
|
|
1573
|
+
appStateStore: getAccessLogStore(),
|
|
1574
|
+
entry: accessEntry,
|
|
1575
|
+
startedAtMs,
|
|
1576
|
+
error: commandError,
|
|
1577
|
+
});
|
|
1143
1578
|
}
|
|
1144
|
-
|
|
1145
|
-
await startAndOpen(port);
|
|
1146
1579
|
}
|
|
1147
1580
|
|
|
1148
1581
|
if (require.main === module) {
|