✨ feat(dataGrid): 增加复制逐行插入语句的功能

This commit is contained in:
二丫讲梵
2026-07-07 16:39:38 +08:00
committed by GitHub
parent b74e97d530
commit 326c4f5495
13 changed files with 166 additions and 38 deletions
+34 -6
View File
@@ -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)});`;
}
+4
View File
@@ -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",
+4
View File
@@ -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",
+4
View File
@@ -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",
+4
View File
@@ -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: "行を復元",
+4
View File
@@ -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",
+4
View File
@@ -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: "恢复行",
+4
View File
@@ -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";
+41 -1
View File
@@ -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\""));