fix(oracle): preserve DATE time in display and export

This commit is contained in:
zipg authored and GitHub committed 2026-07-09 15:04:34 +08:00
1 parent aa0abcd670
commit ce8cb2b509
17 files changed
+504 -58

No files matched your search

@@ -0,0 +1,34 @@
import { describe, expect, it } from "vitest";
import { dataGridCellDisplayText } from "@/lib/dataGrid/dataGridCellCoercion";
describe("dataGridCellDisplayText", () => {
it("formats Oracle DATE values without RFC3339 separators", () => {
expect(
dataGridCellDisplayText({
value: "2022-08-25T09:58:43Z",
databaseType: "oracle",
columnInfo: { data_type: "DATE" },
}),
).toBe("2022-08-25 09:58:43");
});
it("formats midnight Oracle DATE values as a date", () => {
expect(
dataGridCellDisplayText({
value: "2022-08-25T00:00:00Z",
databaseType: "oracle",
columnInfo: { data_type: "DATE" },
}),
).toBe("2022-08-25");
});
it("does not format non-date Oracle strings", () => {
expect(
dataGridCellDisplayText({
value: "2022-08-25T09:58:43Z",
databaseType: "oracle",
columnInfo: { data_type: "VARCHAR2(64)" },
}),
).toBeUndefined();
});
});
@@ -45,6 +45,9 @@ export function dataGridCellDisplayText(options: { value: GridCellValue; databas
if (Array.isArray(options.value) && options.databaseType === "postgres" && isPostgresArrayColumn(options.columnInfo, options.value)) {
return formatPostgresArrayText(options.value);
}
if (typeof options.value === "string" && isOracleDateColumn(options.databaseType, options.columnInfo)) {
return formatOracleDateDisplayText(options.value);
}
return undefined;
}
@@ -113,6 +116,39 @@ function normalizeDataType(dataType: string | undefined): string {
return (dataType ?? "").trim().toLowerCase();
}
function isOracleDateColumn(databaseType: DatabaseType | undefined, columnInfo: Pick<ColumnInfo, "data_type"> | undefined): boolean {
if (databaseType !== "oracle" && databaseType !== "oceanbase-oracle") return false;
const base = normalizeDataType(columnInfo?.data_type).split(/[()\s\t\n]/)[0] ?? "";
return base === "date";
}
function formatOracleDateDisplayText(value: string): string | undefined {
const parts = parseOracleDateLikeText(value);
if (!parts) return undefined;
if (parts.time === "00:00:00" && !parts.fraction) return parts.date;
return `${parts.date} ${parts.time}${parts.fraction ?? ""}`;
}
function parseOracleDateLikeText(value: string): { date: string; time: string; fraction?: string } | undefined {
if (!/^\d{4}-\d{2}-\d{2}/.test(value)) return undefined;
const date = value.slice(0, 10);
if (value.length === 10) return { date, time: "00:00:00" };
const separator = value[10];
if (separator !== "T" && separator !== " ") return undefined;
if (!/^\d{2}:\d{2}:\d{2}/.test(value.slice(11))) return undefined;
const time = value.slice(11, 19);
let rest = value.slice(19);
let fraction: string | undefined;
if (rest.startsWith(".")) {
const match = rest.match(/^(\.\d{1,9})(.*)$/);
if (!match) return undefined;
fraction = match[1];
rest = match[2];
}
if (rest && !/^z$/i.test(rest) && !/^[+-]\d{2}:\d{2}$/.test(rest)) return undefined;
return { date, time, fraction };
}
function isExactDecimalDataType(dataType: string): boolean {
return /\b(?:decimal|numeric|number|dec|money|smallmoney|bigdecimal|bignumeric|big_numeric|fixed)\b/.test(dataType);
}
@@ -45,6 +45,7 @@ export interface DataGridCopyInsertStatementOptions {
databaseType?: DatabaseType;
tableMeta?: DataGridTableMeta;
columns: string[];
columnTypes?: Array<string | null | undefined>;
sourceColumns?: Array<string | undefined>;
rows: GridCellValue[][];
excludePrimaryKeys?: boolean;