mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-08-05 13:27:55 +08:00
🐛 fix(duckdb): 修复无主键结果无法安全编辑
- 为 DuckDB 查询结果和表预览补充隐藏 rowid 定位列,允许无主键表安全提交修改 - DataGrid 提交变更时仅将 rowid 用作定位条件,避免把隐藏定位列写回业务字段 - DuckDB ApplyChanges 对 duckdb-rowid 改用未加引号的 rowid 条件,修复更新和删除失效 - 补充前后端回归测试,覆盖 QueryEditor、DataViewer、rowLocator 与 ApplyChanges 链路
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import {
|
||||
DUCKDB_ROWID_LOCATOR_COLUMN,
|
||||
ORACLE_ROWID_LOCATOR_COLUMN,
|
||||
filterHiddenLocatorColumns,
|
||||
resolveEditRowLocator,
|
||||
@@ -103,6 +104,20 @@ describe('resolveEditRowLocator', () => {
|
||||
readOnly: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('uses DuckDB rowid when no primary or unique key is available', () => {
|
||||
expect(resolveEditRowLocator({
|
||||
dbType: 'duckdb',
|
||||
resultColumns: ['name', DUCKDB_ROWID_LOCATOR_COLUMN],
|
||||
allowDuckDBRowID: true,
|
||||
})).toEqual({
|
||||
strategy: 'duckdb-rowid',
|
||||
columns: ['rowid'],
|
||||
valueColumns: [DUCKDB_ROWID_LOCATOR_COLUMN],
|
||||
hiddenColumns: [DUCKDB_ROWID_LOCATOR_COLUMN],
|
||||
readOnly: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('resolveRowLocatorValues', () => {
|
||||
@@ -131,6 +146,19 @@ describe('resolveRowLocatorValues', () => {
|
||||
error: '定位列 EMAIL 的值为空,无法安全提交修改。',
|
||||
});
|
||||
});
|
||||
|
||||
it('extracts DuckDB rowid locator values from the original row', () => {
|
||||
const locator = resolveEditRowLocator({
|
||||
dbType: 'duckdb',
|
||||
resultColumns: ['name', DUCKDB_ROWID_LOCATOR_COLUMN],
|
||||
allowDuckDBRowID: true,
|
||||
});
|
||||
|
||||
expect(resolveRowLocatorValues(locator, { name: 'launch', [DUCKDB_ROWID_LOCATOR_COLUMN]: 17 })).toEqual({
|
||||
ok: true,
|
||||
values: { rowid: 17 },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('filterHiddenLocatorColumns', () => {
|
||||
@@ -143,4 +171,14 @@ describe('filterHiddenLocatorColumns', () => {
|
||||
|
||||
expect(filterHiddenLocatorColumns(['NAME', ORACLE_ROWID_LOCATOR_COLUMN], locator)).toEqual(['NAME']);
|
||||
});
|
||||
|
||||
it('removes hidden DuckDB rowid columns from displayed columns', () => {
|
||||
const locator = resolveEditRowLocator({
|
||||
dbType: 'duckdb',
|
||||
resultColumns: ['name', DUCKDB_ROWID_LOCATOR_COLUMN],
|
||||
allowDuckDBRowID: true,
|
||||
});
|
||||
|
||||
expect(filterHiddenLocatorColumns(['name', DUCKDB_ROWID_LOCATOR_COLUMN], locator)).toEqual(['name']);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,8 +3,9 @@ import { resolveUniqueKeyGroupsFromIndexes } from '../components/dataGridCopyIns
|
||||
import { isOracleLikeDialect } from './sqlDialect';
|
||||
|
||||
export const ORACLE_ROWID_LOCATOR_COLUMN = '__gonavi_oracle_rowid__';
|
||||
export const DUCKDB_ROWID_LOCATOR_COLUMN = '__gonavi_duckdb_rowid__';
|
||||
|
||||
export type RowLocatorStrategy = 'primary-key' | 'unique-key' | 'oracle-rowid' | 'none';
|
||||
export type RowLocatorStrategy = 'primary-key' | 'unique-key' | 'oracle-rowid' | 'duckdb-rowid' | 'none';
|
||||
|
||||
export type EditRowLocator = {
|
||||
strategy: RowLocatorStrategy;
|
||||
@@ -22,6 +23,7 @@ export type ResolveEditRowLocatorParams = {
|
||||
primaryKeys?: string[];
|
||||
indexes?: IndexDefinition[];
|
||||
allowOracleRowID?: boolean;
|
||||
allowDuckDBRowID?: boolean;
|
||||
};
|
||||
|
||||
export type ResolveRowLocatorValuesResult =
|
||||
@@ -54,6 +56,7 @@ export const resolveEditRowLocator = ({
|
||||
primaryKeys = [],
|
||||
indexes,
|
||||
allowOracleRowID = false,
|
||||
allowDuckDBRowID = false,
|
||||
}: ResolveEditRowLocatorParams): EditRowLocator => {
|
||||
const columns = (resultColumns || []).map(normalizeColumnName).filter(Boolean);
|
||||
const primaryKeyColumns = (primaryKeys || []).map(normalizeColumnName).filter(Boolean);
|
||||
@@ -93,10 +96,25 @@ export const resolveEditRowLocator = ({
|
||||
};
|
||||
}
|
||||
|
||||
if (allowDuckDBRowID && String(dbType || '').trim().toLowerCase() === 'duckdb' && hasColumn(columns, DUCKDB_ROWID_LOCATOR_COLUMN)) {
|
||||
const rowIDColumn = findColumn(columns, DUCKDB_ROWID_LOCATOR_COLUMN);
|
||||
return {
|
||||
strategy: 'duckdb-rowid',
|
||||
columns: ['rowid'],
|
||||
valueColumns: [rowIDColumn],
|
||||
hiddenColumns: [rowIDColumn],
|
||||
readOnly: false,
|
||||
};
|
||||
}
|
||||
|
||||
if (allowOracleRowID && isOracleLikeDialect(dbType)) {
|
||||
return buildReadOnlyLocator('未检测到主键或可用唯一索引,且结果中缺少 Oracle ROWID,无法安全提交修改。');
|
||||
}
|
||||
|
||||
if (allowDuckDBRowID && String(dbType || '').trim().toLowerCase() === 'duckdb') {
|
||||
return buildReadOnlyLocator('未检测到主键、可用唯一索引或 DuckDB rowid,无法安全提交修改。');
|
||||
}
|
||||
|
||||
return buildReadOnlyLocator('未检测到主键或可用唯一索引,无法安全提交修改。');
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user