feat(mongo): preserve BSON types when cloning and saving documents
This commit is contained in:
12 files changed
+239
-36
No files matched your search
@@ -60,9 +60,9 @@ type GridScrollerRef =
|
||||
};
|
||||
|
||||
export interface CustomSaveHandler {
|
||||
save: (changes: { dirtyRows: Map<number, Map<number, CellValue>>; newRows: CellValue[][]; deletedRows: Set<number>; columns: string[]; rows: CellValue[][] }) => Promise<void>;
|
||||
save: (changes: { dirtyRows: Map<number, Map<number, CellValue>>; newRows: CellValue[][]; newRowMeta: GridNewRowMeta[]; deletedRows: Set<number>; columns: string[]; rows: CellValue[][] }) => Promise<void>;
|
||||
applySavedChanges?: (changes: { dirtyRows: Map<number, Map<number, CellValue>>; columns: string[] }) => void;
|
||||
preview?: (changes: { dirtyRows: Map<number, Map<number, CellValue>>; newRows: CellValue[][]; deletedRows: Set<number>; columns: string[]; rows: CellValue[][] }) => Promise<string[]>;
|
||||
preview?: (changes: { dirtyRows: Map<number, Map<number, CellValue>>; newRows: CellValue[][]; newRowMeta: GridNewRowMeta[]; deletedRows: Set<number>; columns: string[]; rows: CellValue[][] }) => Promise<string[]>;
|
||||
canInsert?: boolean;
|
||||
canDelete?: boolean;
|
||||
readonlyColumns?: string[];
|
||||
@@ -126,6 +126,7 @@ interface PendingChangesSnapshot {
|
||||
interface PendingSaveSnapshot {
|
||||
newRows: CellValue[][];
|
||||
newRowRefs: CellValue[][];
|
||||
newRowMeta: GridNewRowMeta[];
|
||||
dirtyRows: Map<number, Map<number, CellValue>>;
|
||||
deletedRows: Set<number>;
|
||||
}
|
||||
@@ -220,11 +221,37 @@ export function useDataGridEditor(options: UseDataGridEditorOptions) {
|
||||
// Kept in lockstep with every structural mutation of newRows.
|
||||
const newRowMeta = ref<GridNewRowMeta[]>([]);
|
||||
let nextNewRowToken = 1;
|
||||
function allocateNewRowMeta(placement: GridNewRowPlacement | null): GridNewRowMeta {
|
||||
return { token: nextNewRowToken++, placement };
|
||||
function allocateNewRowMeta(placement: GridNewRowPlacement | null, sourceIndex?: number, editedColumns?: readonly number[]): GridNewRowMeta {
|
||||
return { token: nextNewRowToken++, placement, sourceIndex, editedColumns: editedColumns?.length ? [...editedColumns] : undefined };
|
||||
}
|
||||
function cloneNewRowMeta(meta: readonly GridNewRowMeta[]): GridNewRowMeta[] {
|
||||
return meta.map((item) => ({ token: item.token, placement: item.placement ? { ...item.placement } : null }));
|
||||
return meta.map((item) => ({ token: item.token, placement: item.placement ? { ...item.placement } : null, sourceIndex: item.sourceIndex, editedColumns: item.editedColumns ? [...item.editedColumns] : undefined }));
|
||||
}
|
||||
|
||||
function updateClonedRowEditedColumns(newIndex: number, col: number, value: CellValue) {
|
||||
const meta = newRowMeta.value[newIndex];
|
||||
if (!meta || meta.sourceIndex === undefined) return;
|
||||
const baseline = result.value.rows[meta.sourceIndex]?.[col];
|
||||
const edited = new Set(meta.editedColumns);
|
||||
if (value === baseline) edited.delete(col);
|
||||
else edited.add(col);
|
||||
meta.editedColumns = edited.size > 0 ? [...edited].sort((left, right) => left - right) : undefined;
|
||||
}
|
||||
|
||||
function clonedRowMeta(item: RowItem, row: readonly CellValue[]): GridNewRowMeta {
|
||||
const inherited = item.newIndex === undefined ? undefined : newRowMeta.value[item.newIndex];
|
||||
const sourceIndex = item.sourceIndex ?? inherited?.sourceIndex;
|
||||
const edited = new Set(inherited?.editedColumns);
|
||||
if (item.sourceIndex !== undefined) {
|
||||
for (const column of dirtyRows.value.get(item.sourceIndex)?.keys() ?? []) edited.add(column);
|
||||
}
|
||||
if (sourceIndex !== undefined) {
|
||||
const baseline = result.value.rows[sourceIndex] ?? [];
|
||||
row.forEach((value, column) => {
|
||||
if (value !== baseline[column]) edited.add(column);
|
||||
});
|
||||
}
|
||||
return allocateNewRowMeta(null, sourceIndex, [...edited]);
|
||||
}
|
||||
// Restore a metadata snapshot and resume token allocation past its maximum so
|
||||
// newly created rows never collide with tokens held by restored rows (a fresh
|
||||
@@ -742,8 +769,10 @@ export function useDataGridEditor(options: UseDataGridEditorOptions) {
|
||||
if (changed) pushUndoSnapshot();
|
||||
if (newRows.value[item.newIndex]) {
|
||||
newRows.value[item.newIndex][col] = newVal;
|
||||
updateClonedRowEditedColumns(item.newIndex, col, newVal);
|
||||
}
|
||||
newRows.value = [...newRows.value];
|
||||
newRowMeta.value = [...newRowMeta.value];
|
||||
if (changed) touchPendingChanges();
|
||||
editingCell.value = null;
|
||||
isCommitting = false;
|
||||
@@ -849,9 +878,11 @@ export function useDataGridEditor(options: UseDataGridEditorOptions) {
|
||||
pushUndoSnapshot();
|
||||
}
|
||||
row[col] = newVal;
|
||||
updateClonedRowEditedColumns(item.newIndex, col, newVal);
|
||||
markBatchMutated();
|
||||
if (!isBatching) {
|
||||
newRows.value = [...newRows.value];
|
||||
newRowMeta.value = [...newRowMeta.value];
|
||||
touchPendingChanges();
|
||||
}
|
||||
return;
|
||||
@@ -924,7 +955,9 @@ export function useDataGridEditor(options: UseDataGridEditorOptions) {
|
||||
if (!row || row[col] === null) return;
|
||||
pushUndoSnapshot();
|
||||
row[col] = null;
|
||||
updateClonedRowEditedColumns(item.newIndex, col, null);
|
||||
newRows.value = [...newRows.value];
|
||||
newRowMeta.value = [...newRowMeta.value];
|
||||
touchPendingChanges();
|
||||
return;
|
||||
}
|
||||
@@ -1111,7 +1144,7 @@ export function useDataGridEditor(options: UseDataGridEditorOptions) {
|
||||
pushUndoSnapshot();
|
||||
rowStatusFilter.value = rowStatusFilterAfterAddingRow(rowStatusFilter.value);
|
||||
newRows.value.push(clonedData);
|
||||
newRowMeta.value.push(allocateNewRowMeta(null));
|
||||
newRowMeta.value.push(clonedRowMeta(item, clonedData));
|
||||
newRows.value = [...newRows.value];
|
||||
newRowMeta.value = [...newRowMeta.value];
|
||||
touchPendingChanges();
|
||||
@@ -1134,7 +1167,7 @@ export function useDataGridEditor(options: UseDataGridEditorOptions) {
|
||||
for (const item of rowsToClone) {
|
||||
const clonedData = clonedRowData(item);
|
||||
newRows.value.push(clonedData);
|
||||
newRowMeta.value.push(allocateNewRowMeta(null));
|
||||
newRowMeta.value.push(clonedRowMeta(item, clonedData));
|
||||
}
|
||||
newRows.value = [...newRows.value];
|
||||
newRowMeta.value = [...newRowMeta.value];
|
||||
@@ -1263,6 +1296,7 @@ export function useDataGridEditor(options: UseDataGridEditorOptions) {
|
||||
dirtyRows: new Map([...dirtyRows.value.entries()].map(([rowIndex, changes]) => [rowIndex, new Map(changes)])),
|
||||
newRows: currentNewRows.map((row) => [...row]),
|
||||
newRowRefs: currentNewRows,
|
||||
newRowMeta: cloneNewRowMeta(newRowMeta.value),
|
||||
deletedRows: new Set(deletedRows.value),
|
||||
};
|
||||
}
|
||||
@@ -1452,6 +1486,7 @@ export function useDataGridEditor(options: UseDataGridEditorOptions) {
|
||||
await customHandler.save({
|
||||
dirtyRows: snapshot.dirtyRows,
|
||||
newRows: snapshot.newRows,
|
||||
newRowMeta: snapshot.newRowMeta,
|
||||
deletedRows: snapshot.deletedRows,
|
||||
columns: result.value.columns,
|
||||
rows: result.value.rows,
|
||||
@@ -1680,7 +1715,7 @@ export function useDataGridEditor(options: UseDataGridEditorOptions) {
|
||||
try {
|
||||
if (customSaveHandler?.value) {
|
||||
const preview = customSaveHandler.value.preview;
|
||||
if (preview) return await preview({ dirtyRows: dirtyRows.value, newRows: newRows.value, deletedRows: deletedRows.value, columns: result.value.columns, rows: result.value.rows });
|
||||
if (preview) return await preview({ dirtyRows: dirtyRows.value, newRows: newRows.value, newRowMeta: cloneNewRowMeta(newRowMeta.value), deletedRows: deletedRows.value, columns: result.value.columns, rows: result.value.rows });
|
||||
return [];
|
||||
}
|
||||
const stmtOptions = saveStatementOptions();
|
||||
|
||||
Reference in new issue
Block a user