feat(query): support editing without selected primary keys

This commit is contained in:
zipg authored and GitHub committed 2026-07-10 18:57:37 +08:00
1 parent 7b47c81ad7
commit c35e5c560a
11 files changed
+935 -88

No files matched your search

+12 -2
View File
@@ -22,6 +22,7 @@ export interface EditableQueryInfo {
sources?: EditableQuerySource[];
editableSourceKey?: string;
multiSource?: boolean;
allowInsert?: boolean;
allowInsertDelete?: boolean;
distinct?: boolean;
}
@@ -83,10 +84,11 @@ export function analyzeEditableQueryEditability(sql: string): QueryEditability {
const rawSelectBody = normalized.slice("SELECT".length, fromIndex).trim();
const distinct = /^DISTINCT\b/i.test(rawSelectBody);
const selectBody = distinct ? rawSelectBody.replace(/^DISTINCT\b/i, "").trimStart() : rawSelectBody;
const selectBodyWithoutDistinct = distinct ? rawSelectBody.replace(/^DISTINCT\b/i, "").trimStart() : rawSelectBody;
// DISTINCT ON selects a representative row using database-specific ordering,
// so it cannot be mapped to base rows like an ordinary DISTINCT projection.
if (distinct && /^ON\b/i.test(selectBody)) return { editable: false, reason: "aggregation" };
if (distinct && /^ON\b/i.test(selectBodyWithoutDistinct)) return { editable: false, reason: "aggregation" };
const selectBody = stripSqlServerTopClause(selectBodyWithoutDistinct);
const groupIndex = findTopLevelKeyword(normalized, "GROUP", fromIndex + 4);
const havingIndex = findTopLevelKeyword(normalized, "HAVING", fromIndex + 4);
@@ -133,6 +135,14 @@ export function queryEditabilityMessageKey(reason: QueryEditabilityReason): stri
return `grid.queryEditUnsupported.${reason}`;
}
function stripSqlServerTopClause(body: string): string {
const topMatch = body.match(/^TOP(?:\s+|(?=\())(?:\((?:[^()'"`[\]]|"[^"]*"|'(?:''|[^'])*'|`[^`]*`|\[[^\]]*\])+\)|\d+)\s*/i);
if (!topMatch) return body;
let remaining = body.slice(topMatch[0].length).trimStart();
remaining = remaining.replace(/^PERCENT\b\s*/i, "").replace(/^WITH\s+TIES\b\s*/i, "");
return remaining || body;
}
function parseSelectColumns(body: string, sources?: EditableQuerySource[]): EditableQueryColumn[] {
const cols: EditableQueryColumn[] = [];
let depth = 0;