/** * Effect-based update operations for entities. * * Uses Ref for atomic state mutation, Effect Schema for validation, * and typed errors (ValidationError, NotFoundError, ForeignKeyError). * * Preserves all update operators: $increment, $decrement, $multiply, * $append, $prepend, $remove, $toggle, $set. */ import { Effect, PubSub, Ref, type Schema } from "effect"; import { type ForeignKeyError, type HookError, NotFoundError, type UniqueConstraintError, ValidationError } from "../../errors/crud-errors.js"; import type { ComputedFieldsConfig } from "../../types/computed-types.js"; import type { MinimalEntity, UpdateManyResult, UpdateWithOperators } from "../../types/crud-types.js"; import type { DerivedIdConfig } from "../../types/database-config-types.js"; import type { HooksConfig } from "../../types/hook-types.js"; import type { CollectionIndexes } from "../../types/index-types.js"; import type { ChangeEvent } from "../../types/reactive-types.js"; import type { SearchIndexMap } from "../../types/search-types.js"; import { type NormalizedConstraints } from "./unique-check.js"; type HasId = { readonly id: string; }; type RelationshipConfig = { readonly type: "ref" | "inverse"; readonly target: string; readonly foreignKey?: string; }; /** * Deep merge an update object into a current object, handling operators at any level. * * Rules: * 1. If update value has $-prefixed keys → it's an operator, apply to current value * 2. If update value is a plain object with no $-keys AND current value is also a plain object → recurse * 3. Otherwise → direct assignment (replace current value with update value) * * This allows nested updates like: * - `{ metadata: { views: 500 } }` → merges into metadata, preserving other fields * - `{ metadata: { views: { $increment: 1 } } }` → applies operator to metadata.views * - `{ metadata: { $set: { views: 0 } } }` → replaces entire metadata * * @param current - The current object to merge into * @param updates - The update object containing values and/or operators * @returns A new object with updates applied */ export declare function deepMergeUpdates(current: Record, updates: Record): Record; /** * Apply update operations to an entity. * Handles both direct value assignments and operator objects at any nesting level. * Uses deepMergeUpdates for nested object merging with operator support. * Automatically sets updatedAt timestamp. */ export declare function applyUpdates(entity: T, updates: UpdateWithOperators): T; /** * Validate that an update doesn't violate immutable fields (id, createdAt). */ export declare function validateImmutableFields(updates: UpdateWithOperators): { readonly valid: boolean; readonly field?: string; }; /** * Update a single entity by ID with validation, hooks, and foreign key checks. * * Steps: * 1. Validate immutable fields are not being modified * 2. Look up entity by ID in Ref state (O(1)) - capture as previous * 3. Run beforeUpdate hooks (can transform update payload) * 4. Apply update operators to produce new entity * 5. Validate through Effect Schema * 6. Validate foreign key constraints if relationship fields changed * 7. Atomically update in Ref state * 8. Update indexes if provided */ export declare const update: (collectionName: string, schema: Schema.Codec, relationships: Record, ref: Ref.Ref>, stateRefs: Record>>, indexes?: CollectionIndexes, hooks?: HooksConfig, uniqueFields?: NormalizedConstraints, computed?: ComputedFieldsConfig, searchIndexRef?: Ref.Ref, searchIndexFields?: ReadonlyArray, changePubSub?: PubSub.PubSub, derivedId?: DerivedIdConfig) => (id: string, updates: UpdateWithOperators) => Effect.Effect; /** * Update multiple entities matching a filter predicate. * * Uses a predicate function to select which entities to update. * The caller (database factory) can use the Stream-based filter pipeline * to build the predicate from a WhereClause. * * Runs hooks per entity: beforeUpdate can transform the update payload, * afterUpdate and onChange run after state mutation. * * All matching entities are updated atomically in a single Ref.update call. */ export declare const updateMany: (collectionName: string, schema: Schema.Codec, relationships: Record, ref: Ref.Ref>, stateRefs: Record>>, indexes?: CollectionIndexes, hooks?: HooksConfig, uniqueFields?: NormalizedConstraints, computed?: ComputedFieldsConfig, searchIndexRef?: Ref.Ref, searchIndexFields?: ReadonlyArray, changePubSub?: PubSub.PubSub, derivedId?: DerivedIdConfig) => (predicate: (entity: T) => boolean, updates: UpdateWithOperators) => Effect.Effect, ValidationError | ForeignKeyError | HookError | UniqueConstraintError>; /** * Extract fields that were actually changed between two entity versions. */ export declare function getChangedFields(original: T, updated: T): string[]; export {}; //# sourceMappingURL=update.d.ts.map