mirror of
https://github.com/t8y2/dbx.git
synced 2026-10-21 06:00:39 +00:00
✨ feat(dataGrid): 增加复制逐行插入语句的功能
This commit is contained in:
@@ -7335,8 +7335,14 @@ function onRowContext(rowId: number, rowIndex: number) {
|
||||
|
||||
async function prefetchCopyStatements() {
|
||||
await prefetchRowAsInsertStatement(false);
|
||||
if (isMultiRow.value) {
|
||||
await prefetchRowAsInsertStatement(false, "row-by-row");
|
||||
}
|
||||
if (canCopyRowAsInsertWithoutPrimaryKeys.value) {
|
||||
await prefetchRowAsInsertStatement(true);
|
||||
if (isMultiRow.value) {
|
||||
await prefetchRowAsInsertStatement(true, "row-by-row");
|
||||
}
|
||||
}
|
||||
if (canCopyRowAsUpdate.value) {
|
||||
await prefetchRowAsUpdateStatement();
|
||||
@@ -7945,7 +7951,11 @@ function copyRowLabels() {
|
||||
return {
|
||||
row: isMultiRow.value ? t("grid.copyRows", { count }) : t("grid.copyRow"),
|
||||
insert: isMultiRow.value ? t("grid.copyRowsInsert", { count }) : t("grid.copyRowInsert"),
|
||||
insertMerged: t("grid.copyRowsInsertMerged", { count }),
|
||||
insertRowByRow: t("grid.copyRowsInsertRowByRow", { count }),
|
||||
insertNoPk: isMultiRow.value ? t("grid.copyRowsInsertWithoutPrimaryKeys", { count }) : t("grid.copyRowInsertWithoutPrimaryKeys"),
|
||||
insertNoPkMerged: t("grid.copyRowsInsertWithoutPrimaryKeysMerged", { count }),
|
||||
insertNoPkRowByRow: t("grid.copyRowsInsertWithoutPrimaryKeysRowByRow", { count }),
|
||||
update: isMultiRow.value ? t("grid.copyRowsUpdate", { count }) : t("grid.copyRowUpdate"),
|
||||
};
|
||||
}
|
||||
@@ -7977,13 +7987,31 @@ function copySubmenu(): ContextMenuItem {
|
||||
items.push({ label: t("grid.copyCell"), action: copyCell });
|
||||
}
|
||||
items.push({ label: labels.row, action: copyRow });
|
||||
items.push({ label: labels.insert, action: copyRowAsInsert, disabled: !canCopyPreparedInsert(false) });
|
||||
if (isMultiRow.value) {
|
||||
items.push({ label: labels.insertMerged, action: () => copyRowAsInsert("merged"), disabled: !canCopyPreparedInsert(false, "merged") });
|
||||
items.push({ label: labels.insertRowByRow, action: () => copyRowAsInsert("row-by-row"), disabled: !canCopyPreparedInsert(false, "row-by-row") });
|
||||
} else {
|
||||
items.push({ label: labels.insert, action: () => copyRowAsInsert(), disabled: !canCopyPreparedInsert(false) });
|
||||
}
|
||||
if (canCopyRowAsInsertWithoutPrimaryKeys.value) {
|
||||
items.push({
|
||||
label: labels.insertNoPk,
|
||||
action: copyRowAsInsertWithoutPrimaryKeys,
|
||||
disabled: !canCopyPreparedInsert(true),
|
||||
});
|
||||
if (isMultiRow.value) {
|
||||
items.push({
|
||||
label: labels.insertNoPkMerged,
|
||||
action: () => copyRowAsInsertWithoutPrimaryKeys("merged"),
|
||||
disabled: !canCopyPreparedInsert(true, "merged"),
|
||||
});
|
||||
items.push({
|
||||
label: labels.insertNoPkRowByRow,
|
||||
action: () => copyRowAsInsertWithoutPrimaryKeys("row-by-row"),
|
||||
disabled: !canCopyPreparedInsert(true, "row-by-row"),
|
||||
});
|
||||
} else {
|
||||
items.push({
|
||||
label: labels.insertNoPk,
|
||||
action: () => copyRowAsInsertWithoutPrimaryKeys(),
|
||||
disabled: !canCopyPreparedInsert(true),
|
||||
});
|
||||
}
|
||||
}
|
||||
if (canCopyRowAsUpdate.value) {
|
||||
items.push({ label: labels.update, action: copyRowAsUpdate, disabled: !canCopyPreparedUpdate() });
|
||||
|
||||
@@ -258,7 +258,7 @@ onBeforeUnmount(() => {
|
||||
<slot :onContextMenu="onContextMenu" />
|
||||
<!-- Main menu -->
|
||||
<Teleport to="body">
|
||||
<div v-if="show" ref="menuRef" :style="{ position: 'fixed', left: x + 'px', top: y + 'px', zIndex: 9999 }" class="bg-popover text-popover-foreground min-w-40 rounded-[6px] p-1 overflow-x-hidden overflow-y-auto ring-1 ring-foreground/10 shadow-lg">
|
||||
<div v-if="show" ref="menuRef" :style="{ position: 'fixed', left: x + 'px', top: y + 'px', zIndex: 9999 }" class="bg-popover text-popover-foreground min-w-40 w-max max-w-[calc(100vw-16px)] rounded-[6px] p-1 overflow-y-auto ring-1 ring-foreground/10 shadow-lg">
|
||||
<template v-for="(item, index) in items" :key="index">
|
||||
<template v-if="item.visible !== false">
|
||||
<div v-if="item.separator" class="-mx-1 my-1 flex items-center px-1">
|
||||
@@ -268,7 +268,7 @@ onBeforeUnmount(() => {
|
||||
<span class="flex size-4 shrink-0 items-center justify-center">
|
||||
<component :is="item.icon" v-if="item.icon" :class="['size-4', item.iconClass]" />
|
||||
</span>
|
||||
<span class="min-w-0 flex-1 truncate">{{ item.label }}</span>
|
||||
<span class="flex-1 whitespace-nowrap">{{ item.label }}</span>
|
||||
<span v-if="item.shortcut" class="ml-8 inline-flex shrink-0 items-center gap-1 text-muted-foreground">
|
||||
<kbd v-for="key in shortcutKeys(item.shortcut)" :key="key" class="min-w-4 rounded border border-border/70 bg-muted/60 px-1 py-0.5 text-center font-mono text-[10px] leading-none text-muted-foreground shadow-xs">{{ key }}</kbd>
|
||||
</span>
|
||||
@@ -284,7 +284,7 @@ onBeforeUnmount(() => {
|
||||
v-if="show && activeSubIndex !== null && items[activeSubIndex]?.children?.length"
|
||||
ref="subRef"
|
||||
:style="{ position: 'fixed', left: subX + 'px', top: subY + 'px', zIndex: 10000, maxHeight: 'min(420px, calc(100vh - 16px))' }"
|
||||
class="bg-popover text-popover-foreground w-56 max-w-[calc(100vw-16px)] rounded-[6px] p-1 overflow-x-hidden overflow-y-auto ring-1 ring-foreground/10 shadow-lg"
|
||||
class="bg-popover text-popover-foreground min-w-56 w-max max-w-[calc(100vw-16px)] rounded-[6px] p-1 overflow-y-auto ring-1 ring-foreground/10 shadow-lg"
|
||||
@mouseenter="onSubMouseEnter"
|
||||
@mouseleave="onSubMouseLeave"
|
||||
>
|
||||
@@ -297,7 +297,7 @@ onBeforeUnmount(() => {
|
||||
<span class="flex size-4 shrink-0 items-center justify-center">
|
||||
<component :is="child.icon" v-if="child.icon" :class="['size-4', child.iconClass]" />
|
||||
</span>
|
||||
<span class="min-w-0 flex-1 truncate">{{ child.label }}</span>
|
||||
<span class="flex-1 whitespace-nowrap">{{ child.label }}</span>
|
||||
<span v-if="child.shortcut" class="ml-8 inline-flex shrink-0 items-center gap-1 text-muted-foreground">
|
||||
<kbd v-for="key in shortcutKeys(child.shortcut)" :key="key" class="min-w-4 rounded border border-border/70 bg-muted/60 px-1 py-0.5 text-center font-mono text-[10px] leading-none text-muted-foreground shadow-xs">{{ key }}</kbd>
|
||||
</span>
|
||||
|
||||
@@ -7,7 +7,7 @@ import { useToast } from "@/composables/useToast";
|
||||
import { displayCellValue, type CellValue } from "@/lib/dataGrid/cellValue";
|
||||
import { tryStartExclusiveActivation, type ActionActivationGuard } from "@/lib/connection/actionActivation";
|
||||
import { copyToClipboard } from "@/lib/common/clipboard";
|
||||
import { buildDataGridCopyInsertStatement, buildDataGridCopyUpdateStatements, type DataGridTableMeta } from "@/lib/dataGrid/dataGridSql";
|
||||
import { buildDataGridCopyInsertStatement, buildDataGridCopyUpdateStatements, type DataGridCopyInsertMode, type DataGridTableMeta } from "@/lib/dataGrid/dataGridSql";
|
||||
import { formatSqlInsert } from "@/lib/export/exportFormats";
|
||||
import { uuid } from "@/lib/common/utils";
|
||||
import { useSettingsStore } from "@/stores/settingsStore";
|
||||
@@ -102,12 +102,24 @@ export function useDataGridExport(options: UseDataGridExportOptions) {
|
||||
loading: false,
|
||||
ready: false,
|
||||
});
|
||||
const copyRowInsertRowByRowCache = ref<CopyStatementCache>({
|
||||
key: "",
|
||||
text: "",
|
||||
loading: false,
|
||||
ready: false,
|
||||
});
|
||||
const copyRowInsertWithoutPrimaryKeysCache = ref<CopyStatementCache>({
|
||||
key: "",
|
||||
text: "",
|
||||
loading: false,
|
||||
ready: false,
|
||||
});
|
||||
const copyRowInsertWithoutPrimaryKeysRowByRowCache = ref<CopyStatementCache>({
|
||||
key: "",
|
||||
text: "",
|
||||
loading: false,
|
||||
ready: false,
|
||||
});
|
||||
const copyRowUpdateCache = ref<CopyStatementCache>({
|
||||
key: "",
|
||||
text: "",
|
||||
@@ -217,7 +229,7 @@ export function useDataGridExport(options: UseDataGridExportOptions) {
|
||||
});
|
||||
}
|
||||
|
||||
function insertCopyKey(excludePrimaryKeys: boolean): string {
|
||||
function insertCopyKey(excludePrimaryKeys: boolean, insertMode: DataGridCopyInsertMode): string {
|
||||
const rows = copyStatementRowsKey(insertEligibleRows());
|
||||
return JSON.stringify({
|
||||
databaseType: databaseType.value ?? null,
|
||||
@@ -227,6 +239,7 @@ export function useDataGridExport(options: UseDataGridExportOptions) {
|
||||
columns: columns.value,
|
||||
sourceColumns: sourceColumns.value ?? null,
|
||||
excludePrimaryKeys,
|
||||
insertMode,
|
||||
rows,
|
||||
});
|
||||
}
|
||||
@@ -236,13 +249,22 @@ export function useDataGridExport(options: UseDataGridExportOptions) {
|
||||
return rows.map((item) => ({ id: item.id, data: item.data }));
|
||||
}
|
||||
|
||||
function insertCopyCache(excludePrimaryKeys: boolean): CopyStatementCache {
|
||||
return excludePrimaryKeys ? copyRowInsertWithoutPrimaryKeysCache.value : copyRowInsertCache.value;
|
||||
function insertCopyCache(excludePrimaryKeys: boolean, insertMode: DataGridCopyInsertMode): CopyStatementCache {
|
||||
if (excludePrimaryKeys) {
|
||||
return insertMode === "row-by-row" ? copyRowInsertWithoutPrimaryKeysRowByRowCache.value : copyRowInsertWithoutPrimaryKeysCache.value;
|
||||
}
|
||||
return insertMode === "row-by-row" ? copyRowInsertRowByRowCache.value : copyRowInsertCache.value;
|
||||
}
|
||||
|
||||
function setInsertCopyCache(excludePrimaryKeys: boolean, cache: CopyStatementCache) {
|
||||
function setInsertCopyCache(excludePrimaryKeys: boolean, insertMode: DataGridCopyInsertMode, cache: CopyStatementCache) {
|
||||
if (excludePrimaryKeys) {
|
||||
copyRowInsertWithoutPrimaryKeysCache.value = cache;
|
||||
if (insertMode === "row-by-row") {
|
||||
copyRowInsertWithoutPrimaryKeysRowByRowCache.value = cache;
|
||||
} else {
|
||||
copyRowInsertWithoutPrimaryKeysCache.value = cache;
|
||||
}
|
||||
} else if (insertMode === "row-by-row") {
|
||||
copyRowInsertRowByRowCache.value = cache;
|
||||
} else {
|
||||
copyRowInsertCache.value = cache;
|
||||
}
|
||||
@@ -252,10 +274,10 @@ export function useDataGridExport(options: UseDataGridExportOptions) {
|
||||
copyRowUpdateCache.value = cache;
|
||||
}
|
||||
|
||||
async function prefetchRowAsInsertStatement(excludePrimaryKeys: boolean) {
|
||||
async function prefetchRowAsInsertStatement(excludePrimaryKeys: boolean, insertMode: DataGridCopyInsertMode = "merged") {
|
||||
const rows = insertEligibleRows();
|
||||
if (!rows.length) {
|
||||
setInsertCopyCache(excludePrimaryKeys, {
|
||||
setInsertCopyCache(excludePrimaryKeys, insertMode, {
|
||||
key: "",
|
||||
text: "",
|
||||
loading: false,
|
||||
@@ -263,11 +285,11 @@ export function useDataGridExport(options: UseDataGridExportOptions) {
|
||||
});
|
||||
return;
|
||||
}
|
||||
const key = insertCopyKey(excludePrimaryKeys);
|
||||
const current = insertCopyCache(excludePrimaryKeys);
|
||||
const key = insertCopyKey(excludePrimaryKeys, insertMode);
|
||||
const current = insertCopyCache(excludePrimaryKeys, insertMode);
|
||||
if ((current.loading || current.ready) && current.key === key) return;
|
||||
|
||||
setInsertCopyCache(excludePrimaryKeys, {
|
||||
setInsertCopyCache(excludePrimaryKeys, insertMode, {
|
||||
key,
|
||||
text: "",
|
||||
loading: true,
|
||||
@@ -283,6 +305,7 @@ export function useDataGridExport(options: UseDataGridExportOptions) {
|
||||
sourceColumns: sourceColumns.value,
|
||||
rows: rows.map((item) => item.data),
|
||||
excludePrimaryKeys,
|
||||
insertMode,
|
||||
})
|
||||
: await buildDataGridCopyInsertStatement({
|
||||
databaseType: databaseType.value,
|
||||
@@ -291,19 +314,20 @@ export function useDataGridExport(options: UseDataGridExportOptions) {
|
||||
sourceColumns: sourceColumns.value,
|
||||
rows: rows.map((item) => item.data),
|
||||
excludePrimaryKeys,
|
||||
insertMode,
|
||||
});
|
||||
const latest = insertCopyCache(excludePrimaryKeys);
|
||||
const latest = insertCopyCache(excludePrimaryKeys, insertMode);
|
||||
if (latest.key !== key) return;
|
||||
setInsertCopyCache(excludePrimaryKeys, {
|
||||
setInsertCopyCache(excludePrimaryKeys, insertMode, {
|
||||
key,
|
||||
text: statement ?? "",
|
||||
loading: false,
|
||||
ready: !!statement,
|
||||
});
|
||||
} catch {
|
||||
const latest = insertCopyCache(excludePrimaryKeys);
|
||||
const latest = insertCopyCache(excludePrimaryKeys, insertMode);
|
||||
if (latest.key !== key) return;
|
||||
setInsertCopyCache(excludePrimaryKeys, {
|
||||
setInsertCopyCache(excludePrimaryKeys, insertMode, {
|
||||
key,
|
||||
text: "",
|
||||
loading: false,
|
||||
@@ -312,14 +336,14 @@ export function useDataGridExport(options: UseDataGridExportOptions) {
|
||||
}
|
||||
}
|
||||
|
||||
function canCopyPreparedInsert(excludePrimaryKeys: boolean): boolean {
|
||||
const cache = insertCopyCache(excludePrimaryKeys);
|
||||
return cache.ready && cache.key === insertCopyKey(excludePrimaryKeys);
|
||||
function canCopyPreparedInsert(excludePrimaryKeys: boolean, insertMode: DataGridCopyInsertMode = "merged"): boolean {
|
||||
const cache = insertCopyCache(excludePrimaryKeys, insertMode);
|
||||
return cache.ready && cache.key === insertCopyKey(excludePrimaryKeys, insertMode);
|
||||
}
|
||||
|
||||
function copyPreparedRowAsInsert(excludePrimaryKeys: boolean): boolean {
|
||||
if (!canCopyPreparedInsert(excludePrimaryKeys)) return false;
|
||||
void copyText(insertCopyCache(excludePrimaryKeys).text);
|
||||
function copyPreparedRowAsInsert(excludePrimaryKeys: boolean, insertMode: DataGridCopyInsertMode = "merged"): boolean {
|
||||
if (!canCopyPreparedInsert(excludePrimaryKeys, insertMode)) return false;
|
||||
void copyText(insertCopyCache(excludePrimaryKeys, insertMode).text);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -478,12 +502,12 @@ export function useDataGridExport(options: UseDataGridExportOptions) {
|
||||
return targetedRows().filter((item) => !item.isDraft);
|
||||
}
|
||||
|
||||
async function copyRowAsInsert() {
|
||||
copyPreparedRowAsInsert(false);
|
||||
async function copyRowAsInsert(insertMode: DataGridCopyInsertMode = "merged") {
|
||||
copyPreparedRowAsInsert(false, insertMode);
|
||||
}
|
||||
|
||||
async function copyRowAsInsertWithoutPrimaryKeys() {
|
||||
copyPreparedRowAsInsert(true);
|
||||
async function copyRowAsInsertWithoutPrimaryKeys(insertMode: DataGridCopyInsertMode = "merged") {
|
||||
copyPreparedRowAsInsert(true, insertMode);
|
||||
}
|
||||
|
||||
async function copyRowAsUpdate() {
|
||||
@@ -1147,7 +1171,7 @@ function replaceControlCharacters(value: string, replacement: string): string {
|
||||
.join("");
|
||||
}
|
||||
|
||||
function buildMongoCopyInsertStatement(options: { collection: string; columns: string[]; sourceColumns?: Array<string | undefined>; rows: CellValue[][]; excludePrimaryKeys?: boolean }): string | undefined {
|
||||
function buildMongoCopyInsertStatement(options: { collection: string; columns: string[]; sourceColumns?: Array<string | undefined>; rows: CellValue[][]; excludePrimaryKeys?: boolean; insertMode?: DataGridCopyInsertMode }): string | undefined {
|
||||
const saveColumns = effectiveColumns(options.sourceColumns, options.columns);
|
||||
const columnIndexes = saveColumns.map((column, index) => ({ column, index })).filter((item): item is { column: string; index: number } => !!item.column);
|
||||
if (columnIndexes.length === 0 || options.rows.length === 0) return undefined;
|
||||
@@ -1155,6 +1179,9 @@ function buildMongoCopyInsertStatement(options: { collection: string; columns: s
|
||||
const documents = options.rows.map((row) => buildMongoCopyInsertDocument(columnIndexes.map((item) => row[item.index]) as MongoInputValue[], documentColumns, { excludePrimaryKeys: options.excludePrimaryKeys }));
|
||||
const collection = `db.getCollection(${JSON.stringify(options.collection)})`;
|
||||
if (documents.length === 1) return `${collection}.insert(${formatMongoShellLiteral(documents[0])});`;
|
||||
if (options.insertMode === "row-by-row") {
|
||||
return documents.map((document) => `${collection}.insert(${formatMongoShellLiteral(document)});`).join("\n");
|
||||
}
|
||||
return `${collection}.insertMany(${formatMongoShellLiteral(documents)});`;
|
||||
}
|
||||
|
||||
|
||||
@@ -832,7 +832,11 @@ export default {
|
||||
copyRows: "Copy {count} Rows (JSON)",
|
||||
copyColumnsJson: "Copy {count} Columns (JSON)",
|
||||
copyRowsInsert: "Copy {count} Rows as INSERT",
|
||||
copyRowsInsertMerged: "Copy {count} Rows as INSERT (Merged)",
|
||||
copyRowsInsertRowByRow: "Copy {count} Rows as INSERT (Row by Row)",
|
||||
copyRowsInsertWithoutPrimaryKeys: "Copy {count} Rows as INSERT without Primary Keys",
|
||||
copyRowsInsertWithoutPrimaryKeysMerged: "Copy {count} Rows as INSERT without Primary Keys (Merged)",
|
||||
copyRowsInsertWithoutPrimaryKeysRowByRow: "Copy {count} Rows as INSERT without Primary Keys (Row by Row)",
|
||||
copyRowsUpdate: "Copy {count} Rows as UPDATE",
|
||||
selectedRows: "{count} rows selected",
|
||||
restoreRow: "Restore Row",
|
||||
|
||||
@@ -786,7 +786,11 @@ export default withEnglishFallback({
|
||||
copyRows: "Copiar {count} filas (JSON)",
|
||||
copyColumnsJson: "Copiar {count} columnas (JSON)",
|
||||
copyRowsInsert: "Copiar {count} filas como INSERT",
|
||||
copyRowsInsertMerged: "Copiar {count} filas como INSERT (combinado)",
|
||||
copyRowsInsertRowByRow: "Copiar {count} filas como INSERT (fila por fila)",
|
||||
copyRowsInsertWithoutPrimaryKeys: "Copiar {count} filas como INSERT sin claves primarias",
|
||||
copyRowsInsertWithoutPrimaryKeysMerged: "Copiar {count} filas como INSERT sin claves primarias (combinado)",
|
||||
copyRowsInsertWithoutPrimaryKeysRowByRow: "Copiar {count} filas como INSERT sin claves primarias (fila por fila)",
|
||||
copyRowsUpdate: "Copiar {count} filas como UPDATE",
|
||||
selectedRows: "{count} filas seleccionadas",
|
||||
restoreRow: "Restaurar fila",
|
||||
|
||||
@@ -784,7 +784,11 @@ export default withEnglishFallback({
|
||||
copyRows: "Copia {count} Righe (JSON)",
|
||||
copyColumnsJson: "Copia {count} Colonne (JSON)",
|
||||
copyRowsInsert: "Copia {count} Righe come INSERT",
|
||||
copyRowsInsertMerged: "Copia {count} Righe come INSERT (unito)",
|
||||
copyRowsInsertRowByRow: "Copia {count} Righe come INSERT (riga per riga)",
|
||||
copyRowsInsertWithoutPrimaryKeys: "Copia {count} Righe come INSERT senza Chiavi Primarie",
|
||||
copyRowsInsertWithoutPrimaryKeysMerged: "Copia {count} Righe come INSERT senza Chiavi Primarie (unito)",
|
||||
copyRowsInsertWithoutPrimaryKeysRowByRow: "Copia {count} Righe come INSERT senza Chiavi Primarie (riga per riga)",
|
||||
copyRowsUpdate: "Copia {count} Righe come UPDATE",
|
||||
selectedRows: "{count} righe selezionate",
|
||||
restoreRow: "Ripristina Riga",
|
||||
|
||||
@@ -780,7 +780,11 @@ export default withEnglishFallback({
|
||||
copyRows: "{count}行をコピー (JSON)",
|
||||
copyColumnsJson: "{count}列をコピー (JSON)",
|
||||
copyRowsInsert: "{count}行をINSERTとしてコピー",
|
||||
copyRowsInsertMerged: "{count}行をINSERTとしてコピー(まとめて)",
|
||||
copyRowsInsertRowByRow: "{count}行をINSERTとしてコピー(行ごと)",
|
||||
copyRowsInsertWithoutPrimaryKeys: "{count}行を主キーなしでINSERTとしてコピー",
|
||||
copyRowsInsertWithoutPrimaryKeysMerged: "{count}行を主キーなしでINSERTとしてコピー(まとめて)",
|
||||
copyRowsInsertWithoutPrimaryKeysRowByRow: "{count}行を主キーなしでINSERTとしてコピー(行ごと)",
|
||||
copyRowsUpdate: "{count}行をUPDATEとしてコピー",
|
||||
selectedRows: "{count}行選択中",
|
||||
restoreRow: "行を復元",
|
||||
|
||||
@@ -785,7 +785,11 @@ export default withEnglishFallback({
|
||||
copyRows: "Copiar {count} Linhas (JSON)",
|
||||
copyColumnsJson: "Copiar {count} Colunas (JSON)",
|
||||
copyRowsInsert: "Copiar {count} Linhas como INSERT",
|
||||
copyRowsInsertMerged: "Copiar {count} Linhas como INSERT (mesclado)",
|
||||
copyRowsInsertRowByRow: "Copiar {count} Linhas como INSERT (linha por linha)",
|
||||
copyRowsInsertWithoutPrimaryKeys: "Copiar {count} Linhas como INSERT sem Chaves Primárias",
|
||||
copyRowsInsertWithoutPrimaryKeysMerged: "Copiar {count} Linhas como INSERT sem Chaves Primárias (mesclado)",
|
||||
copyRowsInsertWithoutPrimaryKeysRowByRow: "Copiar {count} Linhas como INSERT sem Chaves Primárias (linha por linha)",
|
||||
copyRowsUpdate: "Copiar {count} Linhas como UPDATE",
|
||||
selectedRows: "{count} linhas selecionadas",
|
||||
restoreRow: "Restaurar Linha",
|
||||
|
||||
@@ -834,7 +834,11 @@ export default withEnglishFallback({
|
||||
copyRows: "复制 {count} 行 (JSON)",
|
||||
copyColumnsJson: "复制 {count} 列 (JSON)",
|
||||
copyRowsInsert: "复制 {count} 行为 INSERT",
|
||||
copyRowsInsertMerged: "复制 {count} 行为 INSERT(合并)",
|
||||
copyRowsInsertRowByRow: "复制 {count} 行为 INSERT(逐行)",
|
||||
copyRowsInsertWithoutPrimaryKeys: "复制 {count} 行为 INSERT(不含主键)",
|
||||
copyRowsInsertWithoutPrimaryKeysMerged: "复制 {count} 行为 INSERT(不含主键,合并)",
|
||||
copyRowsInsertWithoutPrimaryKeysRowByRow: "复制 {count} 行为 INSERT(不含主键,逐行)",
|
||||
copyRowsUpdate: "复制 {count} 行为 UPDATE",
|
||||
selectedRows: "已选 {count} 行",
|
||||
restoreRow: "恢复行",
|
||||
|
||||
@@ -785,7 +785,11 @@ export default withEnglishFallback({
|
||||
copyRows: "複製 {count} 筆 (JSON)",
|
||||
copyColumnsJson: "複製 {count} 欄 (JSON)",
|
||||
copyRowsInsert: "複製 {count} 筆為 INSERT",
|
||||
copyRowsInsertMerged: "複製 {count} 筆為 INSERT(合併)",
|
||||
copyRowsInsertRowByRow: "複製 {count} 筆為 INSERT(逐筆)",
|
||||
copyRowsInsertWithoutPrimaryKeys: "複製 {count} 筆為 INSERT(不含主鍵)",
|
||||
copyRowsInsertWithoutPrimaryKeysMerged: "複製 {count} 筆為 INSERT(不含主鍵,合併)",
|
||||
copyRowsInsertWithoutPrimaryKeysRowByRow: "複製 {count} 筆為 INSERT(不含主鍵,逐筆)",
|
||||
copyRowsUpdate: "複製 {count} 筆為 UPDATE",
|
||||
selectedRows: "已選 {count} 筆",
|
||||
restoreRow: "復原資料",
|
||||
|
||||
@@ -38,6 +38,8 @@ export interface DataGridCopyUpdateStatementOptions {
|
||||
rows: GridCellValue[][];
|
||||
}
|
||||
|
||||
export type DataGridCopyInsertMode = "merged" | "row-by-row";
|
||||
|
||||
export interface DataGridCopyInsertStatementOptions {
|
||||
databaseType?: DatabaseType;
|
||||
tableMeta?: DataGridTableMeta;
|
||||
@@ -45,6 +47,7 @@ export interface DataGridCopyInsertStatementOptions {
|
||||
sourceColumns?: Array<string | undefined>;
|
||||
rows: GridCellValue[][];
|
||||
excludePrimaryKeys?: boolean;
|
||||
insertMode?: DataGridCopyInsertMode;
|
||||
}
|
||||
|
||||
export type DataGridContextFilterMode = "equals" | "not-equals" | "is-null" | "is-not-null" | "like" | "not-like" | "less-than" | "greater-than";
|
||||
|
||||
@@ -96,6 +96,16 @@ pub struct DataGridCopyInsertStatementOptions {
|
||||
pub rows: Vec<Vec<Value>>,
|
||||
#[serde(default)]
|
||||
pub exclude_primary_keys: bool,
|
||||
#[serde(default)]
|
||||
pub insert_mode: DataGridCopyInsertMode,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub enum DataGridCopyInsertMode {
|
||||
#[default]
|
||||
Merged,
|
||||
RowByRow,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
||||
@@ -359,7 +369,9 @@ pub fn build_data_grid_copy_insert_statement(options: DataGridCopyInsertStatemen
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
if options.database_type.is_some_and(uses_single_row_insert_statements) {
|
||||
if options.insert_mode == DataGridCopyInsertMode::RowByRow
|
||||
|| options.database_type.is_some_and(uses_single_row_insert_statements)
|
||||
{
|
||||
return Some(
|
||||
value_rows
|
||||
.iter()
|
||||
@@ -2067,6 +2079,7 @@ mod tests {
|
||||
source_columns: None,
|
||||
rows: vec![vec![json!(1), json!("ada"), json!("Ada")], vec![json!(2), json!("linus"), json!("Linus")]],
|
||||
exclude_primary_keys: true,
|
||||
insert_mode: DataGridCopyInsertMode::Merged,
|
||||
});
|
||||
assert_eq!(
|
||||
statement.as_deref(),
|
||||
@@ -2074,6 +2087,30 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn builds_copy_insert_statement_row_by_row() {
|
||||
let statement = build_data_grid_copy_insert_statement(DataGridCopyInsertStatementOptions {
|
||||
database_type: Some(DatabaseType::Mysql),
|
||||
table_meta: Some(DataGridTableMeta {
|
||||
schema: None,
|
||||
table_name: "users".to_string(),
|
||||
primary_keys: vec!["id".to_string()],
|
||||
columns: None,
|
||||
}),
|
||||
columns: vec!["id".to_string(), "login_name".to_string(), "display_name".to_string()],
|
||||
source_columns: None,
|
||||
rows: vec![vec![json!(1), json!("ada"), json!("Ada")], vec![json!(2), json!("linus"), json!("Linus")]],
|
||||
exclude_primary_keys: false,
|
||||
insert_mode: DataGridCopyInsertMode::RowByRow,
|
||||
});
|
||||
assert_eq!(
|
||||
statement.as_deref(),
|
||||
Some(
|
||||
"INSERT INTO `users` (`id`, `login_name`, `display_name`) VALUES (1, 'ada', 'Ada');\nINSERT INTO `users` (`id`, `login_name`, `display_name`) VALUES (2, 'linus', 'Linus');"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn oracle_copy_insert_statement_uses_one_statement_per_row() {
|
||||
let statement = build_data_grid_copy_insert_statement(DataGridCopyInsertStatementOptions {
|
||||
@@ -2088,6 +2125,7 @@ mod tests {
|
||||
source_columns: None,
|
||||
rows: vec![vec![json!(1), json!("Ada")], vec![json!(2), json!("Linus")]],
|
||||
exclude_primary_keys: false,
|
||||
insert_mode: DataGridCopyInsertMode::Merged,
|
||||
});
|
||||
|
||||
assert_eq!(
|
||||
@@ -2114,6 +2152,7 @@ mod tests {
|
||||
source_columns: None,
|
||||
rows: rows.clone(),
|
||||
exclude_primary_keys: false,
|
||||
insert_mode: DataGridCopyInsertMode::Merged,
|
||||
});
|
||||
assert_eq!(
|
||||
insert.as_deref(),
|
||||
@@ -2174,6 +2213,7 @@ mod tests {
|
||||
source_columns: None,
|
||||
rows: vec![vec![json!(1), json!("Hello"), json!("'hello':1A")]],
|
||||
exclude_primary_keys: false,
|
||||
insert_mode: DataGridCopyInsertMode::Merged,
|
||||
});
|
||||
|
||||
assert_eq!(
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use dbx_core::data_grid_sql::{
|
||||
build_data_grid_copy_insert_statement, DataGridColumnInfo, DataGridCopyInsertStatementOptions, DataGridTableMeta,
|
||||
build_data_grid_copy_insert_statement, DataGridColumnInfo, DataGridCopyInsertMode,
|
||||
DataGridCopyInsertStatementOptions, DataGridTableMeta,
|
||||
};
|
||||
use dbx_core::database_export::{build_export_insert_statements, BuildExportInsertStatementsOptions};
|
||||
use dbx_core::db::postgres;
|
||||
@@ -72,6 +73,7 @@ async fn postgres_tsvector_generated_columns_are_readable_and_omitted_from_inser
|
||||
source_columns: None,
|
||||
rows: result.rows.clone(),
|
||||
exclude_primary_keys: false,
|
||||
insert_mode: DataGridCopyInsertMode::Merged,
|
||||
})
|
||||
.expect("copy insert");
|
||||
assert!(copy_insert.contains("\"id\", \"title\", \"body\""));
|
||||
|
||||
Reference in New Issue
Block a user