import type { Effect, Stream } from 'effect'; import type { ChangeNotice, DecodedEntity, DecodedSingleEntity, } from '../../../core/index.js'; import type { AnyEntityESchema, AnyUnkeyedESchema, } from '../../../eschema/index.js'; import type { DatabaseError } from '../error/index.js'; import type { EncodedItem, EncodedKey, StdTableService, TransactCheck, TransactPut, } from '../contract/index.js'; import type { AccessPatternDefinition, AccessPatternMap, GlobalSecondaryIndexMap, IndexComponent, KeyedEntityDefinition, LocalSecondaryIndexMap, PatternFor, SingleEntityDefinition, } from '../definition/index.js'; export type TableEffect = Effect.Effect< A, DatabaseError, StdTableService >; export type EntityValue = S['Type']; export type EntityKey< S extends AnyEntityESchema, Pk extends readonly string[], > = Pick< EntityValue, Extract> >; export type InsertValue = EntityValue; export type SingleUpdateInput = | Partial | ((current: S['Type']) => Partial); export type UpdateValue = Partial>; export type EntityInvariant = (current: T) => boolean; export type UpdateFn = ( current: EntityValue, ) => UpdateValue; export type UpdateInput = | UpdateValue | UpdateFn; /** * `check` and `lastWriteWins` are mutually exclusive: an invariant is only * meaningful while the `_u` condition still holds the value it judged. */ export type WriteOptions = | { readonly check?: undefined; readonly lastWriteWins?: boolean } | { readonly check: EntityInvariant; readonly lastWriteWins?: false }; interface TransactTarget { readonly tableName: Name; readonly entityName: string; readonly key: EncodedKey; readonly target: string; readonly readsCurrent: boolean; } export interface TransactOp< Name extends string = string, T extends object = object, > extends TransactTarget { readonly operationKind: | 'insertOp' | 'updateOp' | 'deleteOp' | 'restoreOp' | 'singleUpdateOp'; readonly apply: ( current: EncodedItem | null, version: string, ) => Effect.Effect< { readonly write: TransactPut; readonly entity: DecodedEntity | DecodedSingleEntity; }, DatabaseError >; } export interface CheckOp< Name extends string = string, > extends TransactTarget { readonly operationKind: 'checkOp'; readonly apply: ( current: EncodedItem | null, version: string, ) => Effect.Effect< { readonly write: TransactCheck; readonly entity: null }, DatabaseError >; } export type AnyTransactOp< Name extends string = string, T extends object = object, > = TransactOp | CheckOp; export type SortCondition = | { readonly '=': Sk } | { readonly '<': Sk | null } | { readonly '<=': Sk | null } | { readonly '>': Sk | null } | { readonly '>=': Sk | null } | { readonly between: readonly [Sk, Sk] } | { readonly beginsWith: Sk }; export interface QueryOptions { readonly limit?: number; readonly excludeDeleted?: boolean; readonly after?: DecodedEntity; } export interface QueryPage { readonly items: readonly T[]; readonly hasMore: boolean; } export interface KeyedEntity< Name extends string, S extends AnyEntityESchema, Pk extends readonly string[], Patterns extends AccessPatternMap, > extends KeyedEntityDefinition< Name, S, Pk, readonly [S['idField']], Patterns > { get( key: EntityKey, options?: { readonly excludeDeleted?: boolean }, ): TableEffect> | null, Name>; insert( value: InsertValue, ): TableEffect>, Name>; insertOp( value: InsertValue, ): TableEffect>, Name>; getAndUpdate( key: EntityKey, update: UpdateInput, options?: WriteOptions> & { readonly retries?: number }, ): TableEffect>, Name>; getAndUpdateOp( key: EntityKey, update: UpdateInput, options?: WriteOptions>, ): TableEffect>, Name>; getAndCheckOp( key: EntityKey, check: EntityInvariant>, ): TableEffect, Name>; delete( key: EntityKey, options?: WriteOptions>, ): TableEffect>, Name>; deleteOp( key: EntityKey, options?: WriteOptions>, ): TableEffect>, Name>; restore( key: EntityKey, options?: WriteOptions>, ): TableEffect>, Name>; restoreOp( key: EntityKey, options?: WriteOptions>, ): TableEffect>, Name>; unchangedOp( entity: DecodedEntity>, ): TableEffect, Name>; existsOp(key: EntityKey): TableEffect, Name>; notExistsOp(key: EntityKey): TableEffect, Name>; hardDelete( key: EntityKey, confirmation: 'I KNOW WHAT I AM DOING', ): TableEffect>, Name>; dangerouslyRemoveAllItems( confirmation: 'I KNOW WHAT I AM DOING', ): TableEffect<{ readonly itemsDeleted: number }, Name>; query( pattern: Pattern, input: { readonly pk: Record; } & SortCondition>, options?: QueryOptions>, ): TableEffect>>, Name>; subscribe( filter?: Partial>, ): Stream.Stream>>; } export interface SingleEntity< Name extends string, S extends AnyUnkeyedESchema, > extends SingleEntityDefinition { get(): TableEffect, Name>; put(value: S['Type']): TableEffect, Name>; getAndUpdate( update: SingleUpdateInput, options?: WriteOptions & { readonly retries?: number }, ): TableEffect, Name>; getAndUpdateOp( update: SingleUpdateInput, options?: WriteOptions, ): TableEffect, Name>; unchangedOp( entity: DecodedSingleEntity, ): TableEffect, Name>; reset(): TableEffect, Name>; subscribe( filter?: Partial, ): Stream.Stream>; } export interface KeyedBuilderStart< Name extends string, S extends AnyEntityESchema, Lsis extends LocalSecondaryIndexMap = LocalSecondaryIndexMap, Gsis extends GlobalSecondaryIndexMap = GlobalSecondaryIndexMap, > { primary< const Pk extends readonly Exclude, '_u'>[] = [], >(derivation?: { readonly pk: Pk; }): KeyedBuilder< Name, S, Lsis, Gsis, Pk, Record< 'primary', AccessPatternDefinition > >; } export interface KeyedBuilder< Name extends string, S extends AnyEntityESchema, Lsis extends LocalSecondaryIndexMap, Gsis extends GlobalSecondaryIndexMap, Pk extends readonly string[], Patterns extends AccessPatternMap, > { index< const Slot extends keyof (Lsis & Gsis) & string, const Pattern extends string, const D extends (Slot extends keyof Lsis ? { readonly sk: readonly IndexComponent[]; readonly pk?: never } : { readonly pk: readonly IndexComponent[]; readonly sk?: readonly IndexComponent[]; }), >( slot: Slot, pattern: Pattern, derivation: D, ): KeyedBuilder< Name, S, Lsis, Gsis, Pk, Patterns & Record> >; build(): KeyedEntity; } export interface SingleBuilder< Name extends string, S extends AnyUnkeyedESchema, > { default(value: S['Type']): SingleEntity; } export { makeKeyedEntity } from './keyed.js'; export { makeSingleEntity } from './single.js'; export { broadcast, changesOrEmpty, dbError, failReason, subscribe, } from './effects.js';