mirror of
https://github.com/t8y2/dbx.git
synced 2026-11-02 00:29:30 +00:00
feat(grid): copy insert without primary keys
This commit is contained in:
@@ -2155,7 +2155,9 @@ const {
|
||||
copyCell,
|
||||
copyRow,
|
||||
copyRowAsInsert,
|
||||
copyRowAsInsertWithoutPrimaryKeys,
|
||||
copyRowAsUpdate,
|
||||
canCopyRowAsInsertWithoutPrimaryKeys,
|
||||
canCopyRowAsUpdate,
|
||||
copyAll,
|
||||
copySelectionTsv,
|
||||
@@ -2179,8 +2181,6 @@ const {
|
||||
selectedRange,
|
||||
contextCell: exportContextCell,
|
||||
getRowItem: (rowId: number) => visibleDisplayItems.value.find((item) => item.id === rowId),
|
||||
quoteIdent,
|
||||
escapeVal,
|
||||
selectedRowIds,
|
||||
hasRowSelection,
|
||||
});
|
||||
@@ -4473,6 +4473,13 @@ defineExpose({
|
||||
<ContextMenuItem @click="copyRowAsInsert">
|
||||
{{ isMultiRow ? t("grid.copyRowsInsert", { count: multiRowCount }) : t("grid.copyRowInsert") }}
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem v-if="canCopyRowAsInsertWithoutPrimaryKeys" @click="copyRowAsInsertWithoutPrimaryKeys">
|
||||
{{
|
||||
isMultiRow
|
||||
? t("grid.copyRowsInsertWithoutPrimaryKeys", { count: multiRowCount })
|
||||
: t("grid.copyRowInsertWithoutPrimaryKeys")
|
||||
}}
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem v-if="canCopyRowAsUpdate" @click="copyRowAsUpdate">
|
||||
{{ isMultiRow ? t("grid.copyRowsUpdate", { count: multiRowCount }) : t("grid.copyRowUpdate") }}
|
||||
</ContextMenuItem>
|
||||
|
||||
@@ -14,7 +14,7 @@ import { useToast } from "@/composables/useToast";
|
||||
import { displayCellValue, type CellValue } from "@/lib/cellValue";
|
||||
import { tryStartExclusiveActivation, type ActionActivationGuard } from "@/lib/actionActivation";
|
||||
import { copyToClipboard } from "@/lib/clipboard";
|
||||
import { buildDataGridCopyUpdateStatements } from "@/lib/dataGridSql";
|
||||
import { buildDataGridCopyInsertStatement, buildDataGridCopyUpdateStatements } from "@/lib/dataGridSql";
|
||||
import type { DatabaseType } from "@/types/database";
|
||||
|
||||
interface RowItem {
|
||||
@@ -42,8 +42,6 @@ export interface UseDataGridExportOptions {
|
||||
| Ref<{ rowId: number; rowIndex: number; col: number } | null>
|
||||
| ComputedRef<{ rowId: number; rowIndex: number; col: number } | null>;
|
||||
getRowItem: (rowId: number) => RowItem | undefined;
|
||||
quoteIdent: (name: string) => string;
|
||||
escapeVal: (value: CellValue) => string;
|
||||
selectedRowIds: Ref<Set<number>> | ComputedRef<Set<number>>;
|
||||
hasRowSelection: ComputedRef<boolean>;
|
||||
}
|
||||
@@ -65,8 +63,6 @@ export function useDataGridExport(options: UseDataGridExportOptions) {
|
||||
selectedRange,
|
||||
contextCell,
|
||||
getRowItem,
|
||||
quoteIdent,
|
||||
escapeVal,
|
||||
selectedRowIds,
|
||||
hasRowSelection,
|
||||
} = options;
|
||||
@@ -168,32 +164,29 @@ export function useDataGridExport(options: UseDataGridExportOptions) {
|
||||
await copyText(JSON.stringify(obj, null, 2));
|
||||
}
|
||||
|
||||
function insertEligibleRows(): RowItem[] {
|
||||
return targetedRows();
|
||||
}
|
||||
|
||||
async function copyRowAsInsertStatement(excludePrimaryKeys: boolean) {
|
||||
const statement = buildDataGridCopyInsertStatement({
|
||||
databaseType: databaseType.value,
|
||||
tableMeta: tableMeta.value,
|
||||
columns: columns.value,
|
||||
sourceColumns: sourceColumns.value,
|
||||
rows: insertEligibleRows().map((item) => item.data),
|
||||
excludePrimaryKeys,
|
||||
});
|
||||
if (!statement) return;
|
||||
await copyText(statement);
|
||||
}
|
||||
|
||||
async function copyRowAsInsert() {
|
||||
const table = tableMeta.value
|
||||
? (tableMeta.value.schema ? `${quoteIdent(tableMeta.value.schema)}.` : "") + quoteIdent(tableMeta.value.tableName)
|
||||
: "table_name";
|
||||
const cols = columns.value.map((c) => quoteIdent(c)).join(", ");
|
||||
await copyRowAsInsertStatement(false);
|
||||
}
|
||||
|
||||
if (hasRowSelection.value && selectedRowIds.value.size > 0) {
|
||||
const items = displayItems.value.filter((item) => selectedRowIds.value.has(item.id));
|
||||
const valueRows = items.map((item) => `(${item.data.map((v) => escapeVal(v)).join(", ")})`);
|
||||
await copyText(`INSERT INTO ${table} (${cols}) VALUES\n${valueRows.join(",\n")};`);
|
||||
return;
|
||||
}
|
||||
|
||||
const range = selectedRange.value;
|
||||
if (range && range.startRow !== range.endRow) {
|
||||
const items = displayItems.value.slice(range.startRow, range.endRow + 1);
|
||||
const valueRows = items.map((item) => `(${item.data.map((v) => escapeVal(v)).join(", ")})`);
|
||||
await copyText(`INSERT INTO ${table} (${cols}) VALUES\n${valueRows.join(",\n")};`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!contextCell.value) return;
|
||||
const item = getRowItem(contextCell.value.rowId);
|
||||
if (!item) return;
|
||||
const vals = item.data.map((v) => escapeVal(v)).join(", ");
|
||||
await copyText(`INSERT INTO ${table} (${cols}) VALUES (${vals});`);
|
||||
async function copyRowAsInsertWithoutPrimaryKeys() {
|
||||
await copyRowAsInsertStatement(true);
|
||||
}
|
||||
|
||||
async function copyRowAsUpdate() {
|
||||
@@ -224,6 +217,20 @@ export function useDataGridExport(options: UseDataGridExportOptions) {
|
||||
);
|
||||
});
|
||||
|
||||
const canCopyRowAsInsertWithoutPrimaryKeys = computed(() => {
|
||||
if (!tableMeta.value?.primaryKeys.length) return false;
|
||||
const rows = insertEligibleRows();
|
||||
if (!rows.length) return false;
|
||||
return !!buildDataGridCopyInsertStatement({
|
||||
databaseType: databaseType.value,
|
||||
tableMeta: tableMeta.value,
|
||||
columns: columns.value,
|
||||
sourceColumns: sourceColumns.value,
|
||||
rows: [rows[0].data],
|
||||
excludePrimaryKeys: true,
|
||||
});
|
||||
});
|
||||
|
||||
async function copyAll() {
|
||||
const header = columns.value.join("\t");
|
||||
const body = displayItems.value.map((item) => item.data.map((c) => displayCellValue(c)).join("\t")).join("\n");
|
||||
@@ -370,7 +377,9 @@ export function useDataGridExport(options: UseDataGridExportOptions) {
|
||||
copyCell,
|
||||
copyRow,
|
||||
copyRowAsInsert,
|
||||
copyRowAsInsertWithoutPrimaryKeys,
|
||||
copyRowAsUpdate,
|
||||
canCopyRowAsInsertWithoutPrimaryKeys,
|
||||
canCopyRowAsUpdate,
|
||||
copyAll,
|
||||
copySelectionTsv,
|
||||
|
||||
@@ -255,6 +255,7 @@ export default {
|
||||
copyCell: "Copy Cell",
|
||||
copyRow: "Copy Row (JSON)",
|
||||
copyRowInsert: "Copy as INSERT",
|
||||
copyRowInsertWithoutPrimaryKeys: "Copy as INSERT without Primary Keys",
|
||||
copyRowUpdate: "Copy as UPDATE",
|
||||
copyAll: "Copy All (TSV)",
|
||||
selection: "Selection",
|
||||
@@ -351,6 +352,7 @@ export default {
|
||||
restoreRows: "Restore {count} Rows",
|
||||
copyRows: "Copy {count} Rows (JSON)",
|
||||
copyRowsInsert: "Copy {count} Rows as INSERT",
|
||||
copyRowsInsertWithoutPrimaryKeys: "Copy {count} Rows as INSERT without Primary Keys",
|
||||
copyRowsUpdate: "Copy {count} Rows as UPDATE",
|
||||
selectedRows: "{count} rows selected",
|
||||
restoreRow: "Restore Row",
|
||||
|
||||
@@ -250,6 +250,7 @@ export default {
|
||||
copyCell: "Copiar celda",
|
||||
copyRow: "Copiar fila (JSON)",
|
||||
copyRowInsert: "Copiar como INSERT",
|
||||
copyRowInsertWithoutPrimaryKeys: "Copiar como INSERT sin claves primarias",
|
||||
copyRowUpdate: "Copiar como UPDATE",
|
||||
copyAll: "Copiar todo (TSV)",
|
||||
selection: "Selección",
|
||||
@@ -319,6 +320,7 @@ export default {
|
||||
restoreRows: "Restaurar {count} filas",
|
||||
copyRows: "Copiar {count} filas (JSON)",
|
||||
copyRowsInsert: "Copiar {count} filas como INSERT",
|
||||
copyRowsInsertWithoutPrimaryKeys: "Copiar {count} filas como INSERT sin claves primarias",
|
||||
copyRowsUpdate: "Copiar {count} filas como UPDATE",
|
||||
selectedRows: "{count} filas seleccionadas",
|
||||
restoreRow: "Restaurar fila",
|
||||
|
||||
@@ -253,6 +253,7 @@ export default {
|
||||
copyCell: "复制单元格",
|
||||
copyRow: "复制行 (JSON)",
|
||||
copyRowInsert: "复制为 INSERT 语句",
|
||||
copyRowInsertWithoutPrimaryKeys: "复制为 INSERT 语句(不含主键)",
|
||||
copyRowUpdate: "复制为 UPDATE 语句",
|
||||
copyAll: "复制全部 (TSV)",
|
||||
selection: "选区",
|
||||
@@ -348,6 +349,7 @@ export default {
|
||||
restoreRows: "恢复 {count} 行",
|
||||
copyRows: "复制 {count} 行 (JSON)",
|
||||
copyRowsInsert: "复制 {count} 行为 INSERT",
|
||||
copyRowsInsertWithoutPrimaryKeys: "复制 {count} 行为 INSERT(不含主键)",
|
||||
copyRowsUpdate: "复制 {count} 行为 UPDATE",
|
||||
selectedRows: "已选 {count} 行",
|
||||
restoreRow: "恢复行",
|
||||
|
||||
@@ -45,6 +45,15 @@ export interface DataGridCopyUpdateStatementOptions {
|
||||
rows: GridCellValue[][];
|
||||
}
|
||||
|
||||
export interface DataGridCopyInsertStatementOptions {
|
||||
databaseType?: DatabaseType;
|
||||
tableMeta?: DataGridTableMeta;
|
||||
columns: string[];
|
||||
sourceColumns?: Array<string | undefined>;
|
||||
rows: GridCellValue[][];
|
||||
excludePrimaryKeys?: boolean;
|
||||
}
|
||||
|
||||
export interface DataGridSaveValidationOptions {
|
||||
databaseType?: DatabaseType;
|
||||
tableMeta?: DataGridTableMeta;
|
||||
@@ -249,6 +258,43 @@ export function buildDataGridCopyUpdateStatements(options: DataGridCopyUpdateSta
|
||||
return statements;
|
||||
}
|
||||
|
||||
export function buildDataGridCopyInsertStatement(options: DataGridCopyInsertStatementOptions): string | undefined {
|
||||
const saveColumns = effectiveColumns(options.sourceColumns, options.columns);
|
||||
const columnInfo = columnInfoByName(options.tableMeta?.columns);
|
||||
const primaryKeySet = new Set(
|
||||
(options.tableMeta?.primaryKeys ?? []).map((primaryKey) => normalizeColumnName(primaryKey)),
|
||||
);
|
||||
const insertableColumns = saveColumns
|
||||
.map((column, index) => ({ column, index }))
|
||||
.filter((entry): entry is { column: string; index: number } => !!entry.column)
|
||||
.filter((entry) => !isOracleRowId(options.databaseType, entry.column));
|
||||
const insertColumns = insertableColumns.filter(
|
||||
(entry) => !options.excludePrimaryKeys || !primaryKeySet.has(normalizeColumnName(entry.column)),
|
||||
);
|
||||
|
||||
if (options.excludePrimaryKeys && insertColumns.length === insertableColumns.length) return undefined;
|
||||
if (insertColumns.length === 0 || options.rows.length === 0) return undefined;
|
||||
|
||||
const table = options.tableMeta
|
||||
? qualifiedTableName({
|
||||
databaseType: options.databaseType,
|
||||
schema: options.tableMeta.schema,
|
||||
tableName: options.tableMeta.tableName,
|
||||
})
|
||||
: "table_name";
|
||||
const columns = insertColumns.map((entry) => quoteIdent(options.databaseType, entry.column)).join(", ");
|
||||
const valueRows = options.rows.map(
|
||||
(row) =>
|
||||
`(${insertColumns
|
||||
.map(({ column, index }) =>
|
||||
formatGridSqlLiteral(row[index], options.databaseType, columnInfo.get(normalizeColumnName(column))),
|
||||
)
|
||||
.join(", ")})`,
|
||||
);
|
||||
|
||||
return `INSERT INTO ${table} (${columns}) VALUES${valueRows.length === 1 ? " " : "\n"}${valueRows.join(",\n")};`;
|
||||
}
|
||||
|
||||
function buildTdengineDataGridSaveStatements(options: DataGridSaveStatementOptions): string[] {
|
||||
const saveColumns = effectiveColumns(options.sourceColumns, options.columns);
|
||||
const statements: string[] = [];
|
||||
|
||||
Reference in New Issue
Block a user