import { RECORD_FIELDS, withoutRecordFields } from '../db/identity.ts'; import type { Store } from '../db/store.ts'; import type { MockServerConfig, Row } from '../types.ts'; import { isLegacyFidelity } from './fidelity.ts'; export type RowOperation = 'INSERT' | 'MODIFY' | 'DELETE'; // Stamps a row with DETAILS.OPERATION/ROW_REF, the only fields the client's // dataServerResultFilter uses to distinguish INSERT/MODIFY/DELETE on a // QUERY_UPDATE (both for the snapshot pages and later unsolicited pushes on // the same SOURCE_REF — the envelope is otherwise identical). OPERATION must // be exactly 'INSERT' | 'MODIFY' | 'DELETE'; anything else is silently // dropped client-side. GSF puts ROW_REF in DETAILS only; clients copy it onto // the row themselves (`row.DETAILS[rowId] ?? row[rowId]`). Legacy mode also // set it on the row itself, as this engine did up to 15.47. export function stampRow(row: Row, rowRef: unknown, operation: RowOperation, legacy = false): Row { const DETAILS = { OPERATION: operation, ROW_REF: rowRef }; return legacy ? { ...row, ROW_REF: rowRef, DETAILS } : { ...row, DETAILS }; } // DETAILS.ROW_REF for a row of a dataserver's source: the record's RECORD_ID // as a string, as GSF sends it (a view row's comes from its base row). Legacy // mode used the pk value, or the '|'-joined composite key. Read per call, so // flipping `fidelity` on a running server applies to the next push. export function rowRefFor( config: MockServerConfig, store: Store, resourceName: string, row: Row, ): unknown { return isLegacyFidelity(config) ? store.getRowRef(resourceName, row) : store.getRecordRef(resourceName, row); } // RECORD_ID and TIMESTAMP on a dataserver row: the real dataserver never // sends them unless the query's fields block names them. `projected` is the // row already narrowed to the query's columns; `source` the stored row the // values come from. export function dataserverRow(projected: Row, source: Row, fields: string[] | undefined): Row { const row = { ...withoutRecordFields(projected) }; for (const field of RECORD_FIELDS) { if (fields?.includes(field) && source[field] !== undefined) row[field] = source[field]; } return row; }