@tanstack/db
Version:
A reactive client store for building super fast apps on sync
229 lines (205 loc) • 6.44 kB
text/typescript
import { isPlainObject } from '../../utils/type-guards.js'
const ROUTED_SCALAR_VALUE = Symbol(`tanstack_db_routed_scalar_value`)
const ROUTE_METADATA = Symbol(`tanstack_db_route_metadata`)
export const INCLUDES_PUBLIC_KEY = Symbol(`includesPublicKey`)
export const INCLUDES_ROUTING = Symbol(`includesRouting`)
const INTERNAL_ROUTE_KEYS = new Set<PropertyKey>([
ROUTE_METADATA,
INCLUDES_PUBLIC_KEY,
])
const INTERNAL_CALLBACK_KEYS = new Set<PropertyKey>([
...INTERNAL_ROUTE_KEYS,
INCLUDES_ROUTING,
])
type RoutedResult = {
[ROUTED_SCALAR_VALUE]: unknown
[ROUTE_METADATA]: RouteMetadata
[INCLUDES_PUBLIC_KEY]: unknown
}
type PublicContainerProperty = {
descriptor: PropertyDescriptor
value?: { original: unknown; replacement: unknown }
}
export type RouteMetadata = {
correlationKey: unknown
parentContext: unknown
}
export type RoutedScalarMetadata = {
value: unknown
correlationKey: unknown
parentContext: unknown
publicKey: unknown
}
export function attachRouteMetadata<T extends object>(
value: T,
correlationKey: unknown,
parentContext: unknown,
): T {
return Object.assign(value, {
[ROUTE_METADATA]: { correlationKey, parentContext } satisfies RouteMetadata,
})
}
export function getRouteMetadata(value: unknown): RouteMetadata | undefined {
if (
value == null ||
typeof value !== `object` ||
!(ROUTE_METADATA in value)
) {
return undefined
}
return (value as { [ROUTE_METADATA]: RouteMetadata })[ROUTE_METADATA]
}
export function getNamespacedRouteMetadata(
row: unknown,
source: string,
): RouteMetadata | undefined {
return (
getRouteMetadata(row) ??
(row != null && typeof row === `object`
? getRouteMetadata((row as Record<string, unknown>)[source])
: undefined)
)
}
export function stripRouteMetadata<T extends object>(value: T): T {
const result = { ...value } as T & Record<PropertyKey, unknown>
delete result[ROUTE_METADATA]
return result
}
export function attachRouteMetadataToResult(
value: unknown,
correlationKey: unknown,
parentContext: unknown,
publicKey: unknown,
): unknown {
if (
correlationKey === undefined &&
parentContext === undefined &&
publicKey === undefined
) {
return value
}
if (isPlainObject(value)) {
return {
...value,
[ROUTE_METADATA]: { correlationKey, parentContext },
[INCLUDES_PUBLIC_KEY]: publicKey,
}
}
return {
[ROUTED_SCALAR_VALUE]: value,
[ROUTE_METADATA]: { correlationKey, parentContext },
[INCLUDES_PUBLIC_KEY]: publicKey,
} satisfies RoutedResult
}
export function getRoutedScalarMetadata(
value: unknown,
): RoutedScalarMetadata | undefined {
if (
value == null ||
typeof value !== `object` ||
!(ROUTED_SCALAR_VALUE in value)
) {
return undefined
}
const routed = value as RoutedResult
const route = routed[ROUTE_METADATA]
return {
value: routed[ROUTED_SCALAR_VALUE],
correlationKey: route.correlationKey,
parentContext: route.parentContext,
publicKey: routed[INCLUDES_PUBLIC_KEY],
}
}
/** Copy public containers while removing private route state at every depth. */
export function stripInternalRouteMetadata(value: unknown): unknown {
return transformPublicContainers(value, (leaf) => leaf, INTERNAL_ROUTE_KEYS)
}
/** Remove every compiler-owned key before invoking user code. */
export function stripInternalCallbackMetadata(value: unknown): unknown {
return transformPublicContainers(
value,
(leaf) => leaf,
INTERNAL_CALLBACK_KEYS,
)
}
/** Copy only paths changed by a leaf transform or an omitted private key. */
export function transformPublicContainers(
value: unknown,
transformLeaf: (value: unknown) => unknown,
omittedKeys: ReadonlySet<PropertyKey>,
): unknown {
const rootReplacement = transformLeaf(value)
if (!Object.is(rootReplacement, value)) return rootReplacement
if (!isPublicContainer(value)) return value
const parents = new WeakMap<object, Set<object>>()
const properties = new WeakMap<
object,
Map<PropertyKey, PublicContainerProperty>
>()
const dirty = new Set<object>()
const visit = (current: object): void => {
if (properties.has(current)) return
const currentProperties = new Map<PropertyKey, PublicContainerProperty>()
properties.set(current, currentProperties)
for (const key of Reflect.ownKeys(current)) {
if (omittedKeys.has(key)) {
dirty.add(current)
continue
}
const descriptor = Object.getOwnPropertyDescriptor(current, key)
if (!descriptor) continue
const property: PublicContainerProperty = { descriptor }
currentProperties.set(key, property)
if (!descriptor.enumerable || !(`value` in descriptor)) continue
const child = descriptor.value
const replacement = transformLeaf(child)
property.value = { original: child, replacement }
if (!Object.is(replacement, child)) {
dirty.add(current)
continue
}
if (!isPublicContainer(child)) continue
const childParents = parents.get(child) ?? new Set<object>()
childParents.add(current)
parents.set(child, childParents)
visit(child)
}
}
visit(value)
const queue = [...dirty]
for (const current of queue) {
for (const parent of parents.get(current) ?? []) {
if (dirty.has(parent)) continue
dirty.add(parent)
queue.push(parent)
}
}
if (!dirty.has(value)) return value
const copies = new WeakMap<object, object>()
const copy = (current: object): object => {
if (!dirty.has(current)) return current
const existing = copies.get(current)
if (existing) return existing
const result = Array.isArray(current)
? []
: Object.create(Object.getPrototypeOf(current))
copies.set(current, result)
for (const [key, property] of properties.get(current) ?? []) {
const descriptor = { ...property.descriptor }
if (property.value) {
const { original, replacement } = property.value
descriptor.value = !Object.is(replacement, original)
? replacement
: isPublicContainer(original)
? copy(original)
: original
}
Object.defineProperty(result, key, descriptor)
}
return result
}
return copy(value)
}
function isPublicContainer(value: unknown): value is object {
return Array.isArray(value) || isPlainObject(value)
}