UNPKG

@tanstack/db

Version:

A reactive client store for building super fast apps on sync

105 lines (92 loc) 3.07 kB
import { serializeValue } from '@tanstack/db-ivm' import { normalizeValue } from '../utils/comparison.js' import { createRuntimeReferenceIdentityFactory, getRuntimeReferenceIdentity, } from './runtime-reference-identity.js' const PARENT_CONTEXT = Symbol(`tanstack_db_parent_context`) type ParentContext = { [PARENT_CONTEXT]: true value: Record<string, unknown> identity: unknown } type ReferenceIdentity = typeof getRuntimeReferenceIdentity export type ValueIdentity = { equality: (value: unknown) => unknown exact: (value: unknown) => unknown serializeEquality: (value: unknown) => string } function equalityIdentity( value: unknown, referenceIdentity: ReferenceIdentity, ): unknown { const normalized = normalizeValue(value) if ( (typeof normalized === `object` && normalized !== null) || typeof normalized === `function` || typeof normalized === `symbol` ) { return referenceIdentity(normalized as object | symbol) } return normalized } function exactIdentity( value: unknown, referenceIdentity: ReferenceIdentity, ): unknown { if ( (typeof value === `object` && value !== null) || typeof value === `function` || typeof value === `symbol` ) { return referenceIdentity(value) } if (typeof value === `number`) { if (Object.is(value, -0)) return [`number`, `-0`] if (Number.isNaN(value)) return [`number`, `NaN`] } return value } export function createValueIdentity(): ValueIdentity { const referenceIdentity = createRuntimeReferenceIdentityFactory() const equality = (value: unknown) => equalityIdentity(value, referenceIdentity) return { equality, exact: (value) => exactIdentity(value, referenceIdentity), serializeEquality: (value) => serializeValue(equality(value)), } } /** Preserve the value relation used by equality predicates in keyed state. */ export function getEqualityValueIdentity(value: unknown): unknown { return equalityIdentity(value, getRuntimeReferenceIdentity) } /** Keep compiler identity outside the namespace that holds user aliases. */ export function createParentContext( value: Record<string, unknown>, identity: unknown, ): ParentContext { return { [PARENT_CONTEXT]: true, value, identity } } function isParentContext(context: unknown): context is ParentContext { return ( typeof context === `object` && context !== null && PARENT_CONTEXT in context ) } export function getParentContextValue( context: unknown, ): Record<string, unknown> | undefined { if (isParentContext(context)) return context.value if (typeof context === `object` && context !== null) { return context as Record<string, unknown> } return undefined } /** * The envelope is structural D2 state, but its value keeps the user's alias * namespace separate from compiler identity. A later insert or retract can * therefore rebuild the same route without reserving a user-visible key. */ export function getParentContextIdentity(context: unknown): unknown { return isParentContext(context) ? context.identity : context }