feat(sql-file): import split SQL ZIP packages with bounded extraction
This commit is contained in:
1 parent
f43bf80015
commit
b0d30e6f73
22 files changed
+550
-118
No files matched your search
@@ -85,6 +85,7 @@ const database = ref("");
|
||||
const databaseOptions = ref<string[]>([]);
|
||||
const loadingDatabases = ref(false);
|
||||
const continueOnError = ref(false);
|
||||
const skipRelationalConstraints = ref(false);
|
||||
|
||||
const running = ref(false);
|
||||
const cancelling = ref(false);
|
||||
@@ -132,6 +133,15 @@ function resetPerFileState() {
|
||||
}
|
||||
|
||||
const sqlConnections = computed(() => store.connections.filter((c) => !["redis", "mongodb", "elasticsearch", "easysearch", "meilisearch", "qdrant", "milvus", "weaviate", "chromadb", "etcd", "zookeeper", "consul", "mq", "nacos"].includes(c.db_type)));
|
||||
// Mirrors the core executor gate (`supports_connection_level_database_bootstrap_target`): the
|
||||
// MySQL-family types it runs for, so the constraint toggle appears wherever the backend honors it.
|
||||
const MYSQL_BOOTSTRAP_IMPORT_TYPES = new Set(["mysql", "doris", "starrocks", "goldendb"]);
|
||||
const MYSQL_BOOTSTRAP_IMPORT_PROFILES = new Set(["mariadb", "tidb", "oceanbase", "custom_mysql", "doris", "starrocks", "selectdb", "goldendb"]);
|
||||
const isMysqlCompatibleTarget = computed(() => {
|
||||
const config = store.getConfig(connectionId.value);
|
||||
if (!config) return false;
|
||||
return MYSQL_BOOTSTRAP_IMPORT_TYPES.has(config.db_type) || (!!config.driver_profile && MYSQL_BOOTSTRAP_IMPORT_PROFILES.has(config.driver_profile.toLowerCase()));
|
||||
});
|
||||
|
||||
const selectedConnection = computed(() => sqlConnections.value.find((c) => c.id === connectionId.value));
|
||||
|
||||
@@ -309,6 +319,7 @@ function resetState() {
|
||||
databaseOptions.value = [];
|
||||
loadingDatabases.value = false;
|
||||
continueOnError.value = false;
|
||||
skipRelationalConstraints.value = false;
|
||||
restoreSelectedTables.value = false;
|
||||
resetExecution();
|
||||
}
|
||||
@@ -386,7 +397,7 @@ async function selectFile() {
|
||||
const { open } = await import("@tauri-apps/plugin-dialog");
|
||||
const selected = await open({
|
||||
multiple: true,
|
||||
filters: [{ name: "SQL", extensions: ["sql", "gz"] }],
|
||||
filters: [{ name: "SQL package", extensions: ["sql", "gz", "zip"] }],
|
||||
});
|
||||
const paths = Array.isArray(selected) ? selected : selected ? [selected] : [];
|
||||
if (paths.length > 0) {
|
||||
@@ -539,16 +550,19 @@ async function startExecution() {
|
||||
|
||||
try {
|
||||
executionStarted.value = true;
|
||||
const executionPaths = previews.value.flatMap((item) => item.packageFilePaths ?? [item.filePath]);
|
||||
await executeSqlFiles(
|
||||
{
|
||||
executionId: batchId,
|
||||
connectionId: connectionId.value,
|
||||
database: database.value.trim(),
|
||||
filePath: previews.value[0]!.filePath,
|
||||
filePath: executionPaths[0]!,
|
||||
continueOnError: continueOnError.value,
|
||||
...(restoreSelectedTables.value ? { selectedTables: selectedTables.value.map((table) => ({ ...table })) } : {}),
|
||||
partCooldownMs: previews.value.some((item) => item.packageFilePaths) ? 500 : 0,
|
||||
skipRelationalConstraints: skipRelationalConstraints.value,
|
||||
},
|
||||
previews.value.map((item) => item.filePath),
|
||||
executionPaths,
|
||||
);
|
||||
const terminal = await terminalProgress;
|
||||
if (terminal.status === "error") {
|
||||
@@ -656,7 +670,7 @@ watch(
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-2">
|
||||
<input ref="fileInput" type="file" accept=".sql,.sql.gz,text/sql,application/gzip" multiple class="hidden" @change="handleFileInputChange" />
|
||||
<input ref="fileInput" type="file" accept=".sql,.sql.gz,.zip,text/sql,application/gzip,application/zip" multiple class="hidden" @change="handleFileInputChange" />
|
||||
<Input :model-value="filePathDisplay" readonly class="h-8 text-xs font-mono" :placeholder="t('sqlFile.selectSqlFile')" />
|
||||
<Button variant="outline" size="sm" class="h-8 shrink-0" :disabled="running || selectingFile" @click="selectFile">
|
||||
<Loader2 v-if="selectingFile || loadingPreview" class="w-3.5 h-3.5 mr-1.5 animate-spin" />
|
||||
@@ -696,6 +710,7 @@ watch(
|
||||
<span>{{ previewLineSummary(activePreview) }}</span>
|
||||
<span class="h-3 w-px bg-border" />
|
||||
<span>{{ formatBytes(activePreview.sizeBytes) }}</span>
|
||||
<span v-if="activePreview.packagePartCount">{{ t("sqlFile.packageParts", { count: activePreview.packagePartCount }) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sql-file-preview-viewer flex max-w-full overflow-auto bg-muted/15 text-xs rounded-b-md border border-t-0" :class="previews.length === 1 ? 'min-h-56 max-h-[min(46vh,420px)]' : 'min-h-0 max-h-[min(46vh,420px)]'">
|
||||
@@ -791,6 +806,11 @@ watch(
|
||||
<Square v-else class="w-3.5 h-3.5 text-muted-foreground/40 shrink-0" />
|
||||
{{ t("sqlFile.continueOnError") }}
|
||||
</button>
|
||||
<button v-if="isMysqlCompatibleTarget" type="button" class="flex items-center gap-2 text-xs text-left" :disabled="running" @click="skipRelationalConstraints = !skipRelationalConstraints">
|
||||
<CheckSquare v-if="skipRelationalConstraints" class="w-3.5 h-3.5 text-primary shrink-0" />
|
||||
<Square v-else class="w-3.5 h-3.5 text-muted-foreground/40 shrink-0" />
|
||||
{{ t("sqlFile.skipRelationalConstraints") }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div v-if="running || terminalStatus !== 'idle' || progress" class="min-w-0 space-y-3">
|
||||
|
||||
@@ -6270,6 +6270,8 @@ export default withEnglishFallback({
|
||||
selectDatabase: "Verilənlər bazası seç",
|
||||
databasePlaceholder: "Verilənlər bazasının adı",
|
||||
options: "Seçimlər",
|
||||
packageParts: "{count} SQL hissəsi",
|
||||
skipRelationalConstraints: "İdxal zamanı əlaqəli məhdudiyyətləri müvəqqəti söndür",
|
||||
continueOnError: "Xəta olduqda davam et",
|
||||
runInBackground: "Arxa planda işlət",
|
||||
cancelling: "Ləğv edilir...",
|
||||
|
||||
@@ -6424,6 +6424,8 @@ export default {
|
||||
databasePlaceholder: "Database name",
|
||||
options: "Options",
|
||||
continueOnError: "Continue on error",
|
||||
skipRelationalConstraints: "Temporarily disable relational constraints during import",
|
||||
packageParts: "{count} SQL parts",
|
||||
runInBackground: "Run in background",
|
||||
cancelling: "Cancelling...",
|
||||
cancel: "Cancel",
|
||||
|
||||
@@ -6040,6 +6040,8 @@ export default withEnglishFallback({
|
||||
selectDatabase: "Seleccionar base de datos",
|
||||
databasePlaceholder: "Nombre de la base de datos",
|
||||
options: "Opciones",
|
||||
packageParts: "{count} partes SQL",
|
||||
skipRelationalConstraints: "Desactivar temporalmente las restricciones relacionales durante la importación",
|
||||
continueOnError: "Continuar en caso de error",
|
||||
runInBackground: "Ejecutar en segundo plano",
|
||||
cancelling: "Cancelando...",
|
||||
|
||||
@@ -6038,6 +6038,8 @@ export default withEnglishFallback({
|
||||
selectDatabase: "Seleziona database",
|
||||
databasePlaceholder: "Nome database",
|
||||
options: "Opzioni",
|
||||
packageParts: "{count} parti SQL",
|
||||
skipRelationalConstraints: "Disattiva temporaneamente i vincoli relazionali durante l'importazione",
|
||||
continueOnError: "Continua in caso di errore",
|
||||
runInBackground: "Esegui in background",
|
||||
cancelling: "Annullamento in corso...",
|
||||
|
||||
@@ -6077,6 +6077,8 @@ export default withEnglishFallback({
|
||||
selectDatabase: "データベースを選択",
|
||||
databasePlaceholder: "データベース名",
|
||||
options: "オプション",
|
||||
packageParts: "{count} 個のSQLパート",
|
||||
skipRelationalConstraints: "インポート中に関連性制約を一時的に無効化",
|
||||
continueOnError: "エラー時に続行",
|
||||
cancelling: "キャンセル中...",
|
||||
cancel: "キャンセル",
|
||||
|
||||
@@ -5755,6 +5755,8 @@ export default withEnglishFallback({
|
||||
selectDatabase: "데이터베이스 선택",
|
||||
databasePlaceholder: "데이터베이스 이름",
|
||||
options: "옵션",
|
||||
packageParts: "SQL 파트 {count}개",
|
||||
skipRelationalConstraints: "가져오기 중 관계형 제약 조건을 일시적으로 해제",
|
||||
continueOnError: "오류 시 계속",
|
||||
runInBackground: "백그라운드에서 실행",
|
||||
cancelling: "취소하는 중...",
|
||||
|
||||
@@ -6040,6 +6040,8 @@ export default withEnglishFallback({
|
||||
selectDatabase: "Selecionar banco de dados",
|
||||
databasePlaceholder: "Nome do banco de dados",
|
||||
options: "Opções",
|
||||
packageParts: "{count} partes SQL",
|
||||
skipRelationalConstraints: "Desabilitar temporariamente restrições relacionais durante a importação",
|
||||
continueOnError: "Continuar em caso de erro",
|
||||
runInBackground: "Executar em segundo plano",
|
||||
cancelling: "Cancelando...",
|
||||
|
||||
@@ -6152,6 +6152,8 @@ export default withEnglishFallback({
|
||||
selectDatabase: "Veritabanı seç",
|
||||
databasePlaceholder: "Veritabanı adı",
|
||||
options: "Seçenekler",
|
||||
packageParts: "{count} SQL bölümü",
|
||||
skipRelationalConstraints: "İçe aktarma sırasında ilişkisel kısıtlamaları geçici olarak devre dışı bırak",
|
||||
continueOnError: "Hatada devam et",
|
||||
runInBackground: "Arka planda çalıştır",
|
||||
cancelling: "İptal ediliyor...",
|
||||
|
||||
@@ -6398,6 +6398,8 @@ export default withEnglishFallback({
|
||||
selectDatabase: "选择数据库",
|
||||
databasePlaceholder: "数据库名称",
|
||||
options: "选项",
|
||||
packageParts: "{count} 个 SQL 分片",
|
||||
skipRelationalConstraints: "导入期间临时禁用关系约束",
|
||||
continueOnError: "出错后继续",
|
||||
runInBackground: "后台运行",
|
||||
cancelling: "正在取消...",
|
||||
|
||||
@@ -5360,6 +5360,8 @@ export default withEnglishFallback({
|
||||
selectDatabase: "選擇資料庫",
|
||||
databasePlaceholder: "資料庫名稱",
|
||||
options: "選項",
|
||||
packageParts: "{count} 個 SQL 分片",
|
||||
skipRelationalConstraints: "匯入期間暫時停用關聯式約束",
|
||||
continueOnError: "錯誤後繼續",
|
||||
cancelling: "正在取消……",
|
||||
cancel: "取消",
|
||||
|
||||
@@ -4769,6 +4769,8 @@ export interface SqlFileRequest {
|
||||
filePath: string;
|
||||
continueOnError: boolean;
|
||||
selectedTables?: SqlFileTable[];
|
||||
partCooldownMs?: number;
|
||||
skipRelationalConstraints?: boolean;
|
||||
}
|
||||
|
||||
export interface SqlFileTable {
|
||||
@@ -4787,6 +4789,8 @@ export interface SqlFilePreview {
|
||||
preview: string;
|
||||
canExecuteWithoutSelectedDatabase: boolean;
|
||||
establishesDatabaseContext?: boolean;
|
||||
packageFilePaths?: string[];
|
||||
packagePartCount?: number;
|
||||
}
|
||||
|
||||
export interface SqlFileProgress {
|
||||
|
||||
Reference in new issue
Block a user