fix: parse PG brace-style array text in cell coercion to prevent false dirty

coercePostgresArrayValue() only handled JSON [...] format but editor
outputs PG {...} format.  When the user entered and exited edit mode
without changes, the string "{1,2,3}" failed to parse back to an
array, creating a false dirty detection via strict equality.

Add parsePostgresArrayText() recursive descent parser and return
oldValue reference when parsed result is equivalent.
This commit is contained in:
t8y2 committed 2026-06-09 01:00:19 +08:00
1 parent 619573a69d
commit 45a6bb8a58
2 files changed
+199 -6

No files matched your search

+97 -6
View File
@@ -56,13 +56,33 @@ function coercePostgresArrayValue(options: CoerceDataGridCellValueOptions): unkn
if (options.databaseType !== "postgres") return undefined;
if (!isPostgresArrayColumn(options.columnInfo, options.oldValue)) return undefined;
const trimmed = options.value.trim();
if (!trimmed.startsWith("[")) return undefined;
try {
const parsed = JSON.parse(normalizeSmartQuotes(trimmed));
return Array.isArray(parsed) ? parsed : undefined;
} catch {
return undefined;
if (trimmed.startsWith("[")) {
try {
const parsed = JSON.parse(normalizeSmartQuotes(trimmed));
return Array.isArray(parsed) ? parsed : undefined;
} catch {
return undefined;
}
}
if (trimmed.startsWith("{")) {
try {
const parsed = parsePostgresArrayText(trimmed);
if (Array.isArray(options.oldValue) && deepEqual(parsed, options.oldValue)) {
return options.oldValue;
}
return parsed;
} catch {
return undefined;
}
}
return undefined;
}
function deepEqual(a: unknown, b: unknown): boolean {
return JSON.stringify(a) === JSON.stringify(b);
}
function isPostgresArrayColumn(
@@ -115,3 +135,74 @@ function formatPostgresArrayElement(value: unknown): string {
function needsQuotedPostgresArrayElement(value: string): boolean {
return value === "" || /[\s,"{}\\]/.test(value) || value.toUpperCase() === "NULL";
}
function parsePostgresArrayText(value: string): unknown[] {
const trimmed = value.trim();
if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) {
throw new Error("Invalid PG array literal");
}
const inner = trimmed.slice(1, -1);
if (inner.length === 0) return [];
const elements: unknown[] = [];
let i = 0;
while (i < inner.length) {
while (i < inner.length && inner[i] === " ") i++;
if (i >= inner.length) break;
let element: unknown;
if (inner[i] === '"') {
i++;
let str = "";
while (i < inner.length) {
if (inner[i] === "\\" && i + 1 < inner.length) {
i++;
str += inner[i];
i++;
} else if (inner[i] === '"') {
i++;
break;
} else {
str += inner[i];
i++;
}
}
element = str;
} else if (inner[i] === "{") {
let depth = 0;
const start = i;
while (i < inner.length) {
if (inner[i] === "{") depth++;
else if (inner[i] === "}") {
depth--;
if (depth === 0) {
i++;
break;
}
}
i++;
}
element = parsePostgresArrayText(inner.slice(start, i));
} else {
let start = i;
while (i < inner.length && inner[i] !== "," && inner[i] !== "}") i++;
const token = inner.slice(start, i).trim();
if (token.toUpperCase() === "NULL") {
element = null;
} else if (/^(true|false)$/i.test(token)) {
element = token.toLowerCase() === "true";
} else if (/^-?\d+(\.\d+)?([eE][+-]?\d+)?$/.test(token)) {
element = Number(token);
} else {
element = token;
}
}
elements.push(element);
while (i < inner.length && inner[i] === " ") i++;
if (i < inner.length && inner[i] === ",") i++;
}
return elements;
}