UNPKG

dynamodb-toolbox

Version:

A simple set of tools for working with Amazon DynamoDB and the DocumentClient.

326 lines (325 loc) 20.1 kB
import type { A, B, O, F } from 'ts-toolbelt'; import { NativeAttributeValue } from '@aws-sdk/util-dynamodb'; import { ReturnConsumedCapacity, ReturnItemCollectionMetrics } from '@aws-sdk/client-dynamodb'; import type { Compute, FirstDefined, If } from '../../lib/utils.js'; import type { DynamoDBKeyTypes, DynamoDBTypes, $QueryOptions, TableDef } from '../Table/types.js'; import Entity from './Entity.js'; import { UpdateCommandInput } from '@aws-sdk/lib-dynamodb'; export interface EntityConstructor<EntityTable extends TableDef | undefined = undefined, Name extends string = string, AutoExecute extends boolean = true, AutoParse extends boolean = true, Timestamps extends boolean = true, CreatedAlias extends string = 'created', ModifiedAlias extends string = 'modified', TypeAlias extends string = 'entity', TypeHidden extends boolean = false, ReadonlyAttributeDefinitions extends Readonly<AttributeDefinitions> = Readonly<AttributeDefinitions>> { table?: EntityTable; name: Name; timestamps?: Timestamps; created?: string; modified?: string; createdAlias?: CreatedAlias; modifiedAlias?: ModifiedAlias; typeAlias?: TypeAlias; typeHidden?: TypeHidden; attributes: ReadonlyAttributeDefinitions; autoExecute?: AutoExecute; autoParse?: AutoParse; } export declare type KeyAttributeDefinition = { type: 'string' | 'number' | 'bigint' | 'binary'; default: any; hidden: boolean; delimiter: string; prefix: string; suffix: string; onUpdate: boolean; dependsOn: string | string[]; transform: (value: any, data: any) => any; format: (value: any, data: any) => any; coerce: boolean; save: never; required: never; alias: never; map: never; setType: never; }; export declare type PartitionKeyDefinition = Partial<KeyAttributeDefinition> & { partitionKey: true; sortKey?: false; }; export declare type GSIPartitionKeyDefinition = Partial<KeyAttributeDefinition> & { partitionKey: string; sortKey?: false; }; export declare type SortKeyDefinition = Partial<KeyAttributeDefinition> & { sortKey: true; partitionKey?: false; }; export declare type GSISortKeyDefinition = Partial<KeyAttributeDefinition> & { partitionKey?: false; sortKey: string; }; export declare type PureAttributeDefinition = Partial<{ partitionKey: false; sortKey: false; type: DynamoDBTypes; default: any | ((data: object) => any); dependsOn: string | string[]; transform: (value: any, data: {}) => any; format: (value: any, data: {}) => any; coerce: boolean; save: boolean; onUpdate: boolean; hidden: boolean; required: boolean | 'always'; alias: string; map: string; setType: DynamoDBKeyTypes; delimiter: string; prefix: string; suffix: string; }>; export declare type CompositeAttributeDefinition = [string, number] | [string, number, DynamoDBTypes] | [string, number, PureAttributeDefinition]; export declare type AttributeDefinition = DynamoDBTypes | PartitionKeyDefinition | SortKeyDefinition | GSIPartitionKeyDefinition | GSISortKeyDefinition | PureAttributeDefinition | CompositeAttributeDefinition; export declare type AttributeDefinitions = Record<A.Key, AttributeDefinition>; export declare type InferKeyAttribute<Definitions extends AttributeDefinitions, KeyType extends 'partitionKey' | 'sortKey'> = O.SelectKeys<Definitions, Record<KeyType, true>>; export declare type InferMappedAttributes<Definitions extends AttributeDefinitions, AttributeName extends A.Key> = O.SelectKeys<Definitions, [AttributeName, any, any?]>; export interface ParsedAttributes<Attributes extends A.Key = A.Key> { aliases: Attributes; all: Attributes; default: Attributes; key: { partitionKey: { pure: Attributes; dependsOn: Attributes; mapped: Attributes; all: Attributes; }; sortKey: { pure: Attributes; dependsOn: Attributes; mapped: Attributes; all: Attributes; }; all: Attributes; }; always: { all: Attributes; default: Attributes; input: Attributes; }; required: { all: Attributes; default: Attributes; input: Attributes; }; optional: Attributes; shown: Attributes; } export declare type GetDependsOnAttributes<A extends AttributeDefinition> = A extends { dependsOn: A.Key; } ? A['dependsOn'] : A extends { dependsOn: A.Key[]; } ? A['dependsOn'][number] : never; export declare type ParseAttributes<Definitions extends AttributeDefinitions, Timestamps extends boolean, CreatedAlias extends string, ModifiedAlias extends string, TypeAlias extends string, TypeHidden extends boolean, Aliases extends string = (Timestamps extends true ? CreatedAlias | ModifiedAlias : never) | TypeAlias, Default extends A.Key = O.SelectKeys<Definitions, { default: any; } | [any, any, { default: any; }]> | Aliases, PK extends A.Key = InferKeyAttribute<Definitions, 'partitionKey'>, PKDependsOn extends A.Key = GetDependsOnAttributes<Definitions[PK]>, PKMappedAttribute extends A.Key = InferMappedAttributes<Definitions, PK>, SK extends A.Key = InferKeyAttribute<Definitions, 'sortKey'>, SKDependsOn extends A.Key = GetDependsOnAttributes<Definitions[SK]>, SKMappedAttribute extends A.Key = InferMappedAttributes<Definitions, SK>, KeyAttributes extends A.Key = PK | PKMappedAttribute | SK | SKMappedAttribute, AlwaysAttributes extends A.Key = Exclude<O.SelectKeys<Definitions, { required: 'always'; } | [any, any, { required: 'always'; }]> | (Timestamps extends true ? ModifiedAlias : never), KeyAttributes>, RequiredAttributes extends A.Key = Exclude<O.SelectKeys<Definitions, { required: true; } | [any, any, { required: true; }]> | (Timestamps extends true ? CreatedAlias : never) | TypeAlias, KeyAttributes>, Attribute extends A.Key = keyof Definitions | Aliases, Hidden extends A.Key = O.SelectKeys<Definitions, { hidden: true; } | [any, any, { hidden: true; }]>> = { aliases: Aliases; all: Attribute; default: Default; key: { partitionKey: { pure: PK; mapped: PKMappedAttribute; dependsOn: PKDependsOn; all: PK | PKDependsOn | PKMappedAttribute; }; sortKey: { pure: SK; mapped: SKMappedAttribute; dependsOn: SKDependsOn; all: SK | SKDependsOn | SKMappedAttribute; }; all: KeyAttributes; }; always: { all: AlwaysAttributes; default: Extract<AlwaysAttributes, Default>; input: Exclude<AlwaysAttributes, Default>; }; required: { all: RequiredAttributes; default: Extract<RequiredAttributes, Default>; input: Exclude<RequiredAttributes, Default>; }; optional: Exclude<Attribute, KeyAttributes | AlwaysAttributes | RequiredAttributes>; shown: Exclude<Attribute, Hidden>; }; export declare type FromDynamoData<T extends DynamoDBTypes> = { string: string; boolean: boolean; number: number; bigint: bigint; list: any[]; map: any; binary: any; set: any[]; }[T]; export declare type InferItemAttributeValue<Definitions extends AttributeDefinitions, AttributeName extends keyof Definitions, Definition = Definitions[AttributeName]> = { dynamoDbType: Definition extends DynamoDBTypes ? FromDynamoData<Definition> : never; pure: Definition extends PartitionKeyDefinition | GSIPartitionKeyDefinition | SortKeyDefinition | GSISortKeyDefinition | PureAttributeDefinition ? Definition['type'] extends DynamoDBTypes ? Definition['setType'] extends DynamoDBKeyTypes ? FromDynamoData<NonNullable<Definition['setType']>>[] : FromDynamoData<A.Cast<Definition['type'], DynamoDBTypes>> : any : never; composite: Definition extends CompositeAttributeDefinition ? Definition[0] extends Exclude<keyof Definitions, AttributeName> ? InferItemAttributeValue<Definitions, Definition[0]> : any : never; }[Definition extends DynamoDBTypes ? 'dynamoDbType' : Definition extends PartitionKeyDefinition | GSIPartitionKeyDefinition | SortKeyDefinition | GSISortKeyDefinition | PureAttributeDefinition ? 'pure' : Definition extends CompositeAttributeDefinition ? 'composite' : never]; export declare type InferItem<Definitions extends AttributeDefinitions, Attributes extends ParsedAttributes> = O.Optional<{ [K in Attributes['all']]: K extends keyof Definitions ? InferItemAttributeValue<Definitions, K> : K extends Attributes['aliases'] ? string : never; }, Attributes['optional']>; export declare type CompositePrimaryKeyPart<Item extends O.Object, Attributes extends ParsedAttributes, KeyType extends 'partitionKey' | 'sortKey', KeyPureAttribute extends A.Key = Attributes['key'][KeyType]['pure'], KeyDependsOnAttributes extends A.Key = Attributes['key'][KeyType]['dependsOn'], KeyCompositeAttributes extends A.Key = Attributes['key'][KeyType]['mapped']> = If<A.Equals<KeyPureAttribute, never>, Record<never, unknown>, O.Optional<Pick<Item, KeyPureAttribute> | If<A.Equals<KeyDependsOnAttributes, never>, never, Pick<Item, KeyDependsOnAttributes>> | If<A.Equals<KeyCompositeAttributes, never>, never, Pick<Item, KeyCompositeAttributes>>, If<A.Equals<KeyDependsOnAttributes, never>, Attributes['default'], Exclude<Attributes['default'], KeyPureAttribute>>>>; export declare type InferCompositePrimaryKey<Item extends O.Object, Attributes extends ParsedAttributes> = Compute<CompositePrimaryKeyPart<Item, Attributes, 'partitionKey'> & CompositePrimaryKeyPart<Item, Attributes, 'sortKey'>>; export declare type Overlay = undefined | O.Object; export declare type ConditionOrFilter<Attributes extends A.Key = A.Key> = ({ attr: Attributes; } | { size: string; }) & Partial<{ contains: string; exists: boolean; type: 'S' | 'SS' | 'N' | 'NS' | 'B' | 'BS' | 'BOOL' | 'NULL' | 'L' | 'M'; or: boolean; negate: boolean; entity: string; eq: string | number | bigint | boolean | null; ne: string | number | bigint | boolean | null; lt: string | number; lte: string | bigint | number; gt: string | bigint | number; gte: string | bigint | number; between: [string, string] | [number, number] | [bigint, bigint]; beginsWith: string; in: any[]; }>; export declare type ConditionsOrFilters<Attributes extends A.Key = A.Key> = ConditionOrFilter<Attributes> | ConditionsOrFilters<Attributes>[]; export declare type BaseOptions<Execute extends boolean | undefined = undefined, Parse extends boolean | undefined = undefined> = { capacity: ReturnConsumedCapacity | `${ReturnConsumedCapacity}` | Lowercase<ReturnConsumedCapacity>; execute: Execute; parse: Parse; }; export declare type $ReadOptions<Execute extends boolean | undefined = undefined, Parse extends boolean | undefined = undefined> = BaseOptions<Execute, Parse> & { consistent: boolean; }; export declare type $GetOptions<Attributes extends A.Key = A.Key, Execute extends boolean | undefined = undefined, Parse extends boolean | undefined = undefined> = Partial<$ReadOptions<Execute, Parse> & { attributes: Attributes[]; include: string[]; }>; export declare type EntityQueryOptions<Attributes extends A.Key = A.Key, FiltersAttributes extends A.Key = Attributes, Execute extends boolean | undefined = undefined, Parse extends boolean | undefined = undefined> = Partial<$QueryOptions<Execute, Parse> & { attributes: Attributes[]; filters: ConditionsOrFilters<FiltersAttributes>; }>; export declare type $WriteOptions<Attributes extends A.Key = A.Key, Execute extends boolean | undefined = undefined, Parse extends boolean | undefined = undefined> = BaseOptions<Execute, Parse> & { conditions: ConditionsOrFilters<Attributes>; metrics: ReturnItemCollectionMetrics | `${ReturnItemCollectionMetrics}` | Lowercase<ReturnItemCollectionMetrics>; include: string[]; }; export declare type PutOptionsReturnValues = 'NONE' | 'ALL_OLD'; export declare type $PutOptions<Attributes extends A.Key = A.Key, ReturnValues extends PutOptionsReturnValues = PutOptionsReturnValues, Execute extends boolean | undefined = undefined, Parse extends boolean | undefined = undefined, StrictSchemaCheck extends boolean | undefined = true> = Partial<$WriteOptions<Attributes, Execute, Parse> & { returnValues: ReturnValues; strictSchemaCheck?: StrictSchemaCheck; }>; export declare type $PutBatchOptions<Execute extends boolean | undefined = undefined, Parse extends boolean | undefined = undefined, StrictSchemaCheck extends boolean | undefined = true> = Partial<Pick<BaseOptions<Execute, Parse>, 'execute' | 'parse'> & { strictSchemaCheck?: StrictSchemaCheck; }>; export declare type PutItem<MethodItemOverlay extends Overlay, EntityItemOverlay extends Overlay, CompositePrimaryKey extends O.Object, Item extends O.Object, Attributes extends ParsedAttributes, StrictSchemaCheck extends boolean | undefined = true> = FirstDefined<[ MethodItemOverlay, EntityItemOverlay, Compute<CompositePrimaryKey & Pick<Item, Attributes['always']['input'] | Attributes['required']['input']> & Partial<Pick<Item, Attributes['always']['default'] | Attributes['required']['default']> & O.Update<Item, Attributes['optional'], A.x | null>>> ] | If<A.Equals<StrictSchemaCheck, true>, never, any>>; export declare type UpdateOptionsReturnValues = 'NONE' | 'UPDATED_OLD' | 'UPDATED_NEW' | 'ALL_OLD' | 'ALL_NEW'; export declare type $UpdateOptions<Attributes extends A.Key = A.Key, ReturnValues extends UpdateOptionsReturnValues = UpdateOptionsReturnValues, Execute extends boolean | undefined = undefined, Parse extends boolean | undefined = undefined, StrictSchemaCheck extends boolean | undefined = true> = Partial<$WriteOptions<Attributes, Execute, Parse> & { returnValues: ReturnValues; strictSchemaCheck?: StrictSchemaCheck; }>; export interface UpdateCustomParameters { SET: string[]; REMOVE: string[]; ADD: string[]; DELETE: string[]; } export declare type UpdateCustomParams = Partial<UpdateCustomParameters & UpdateCommandInput>; export declare type UpdateItem<MethodItemOverlay extends Overlay, EntityItemOverlay extends Overlay, CompositePrimaryKey extends O.Object, Item extends O.Object, Attributes extends ParsedAttributes, StrictSchemaCheck extends boolean | undefined = true> = FirstDefined<[ MethodItemOverlay, EntityItemOverlay, Compute<CompositePrimaryKey & { [inputAttr in Attributes['always']['input'] & keyof Item]: AttributeUpdateInput<Item[inputAttr]>; } & { [inputRequiredOrWithDefaultAttribute in (Attributes['required']['all'] | Attributes['always']['default']) & keyof Item]?: AttributeUpdateInput<Item[inputRequiredOrWithDefaultAttribute]>; } & { [inputOptionalAttribute in Attributes['optional'] & keyof Item]?: AttributeUpdateInput<Item[inputOptionalAttribute]> | null; } & { $remove?: Attributes['optional'] | Attributes['optional'][]; }> ] | If<A.Equals<StrictSchemaCheck, true>, never, any>>; export declare type AttributeUpdateInput<AttributeType> = If<B.Or<A.Equals<AttributeType, FromDynamoData<'list' | 'set'>>, A.Equals<AttributeType, FromDynamoData<'list' | 'set'> | undefined>>, { $delete?: string[]; $add?: any; $prepend?: AttributeType; $append?: AttributeType; $remove?: number[]; } | AttributeType, AttributeType> | If<B.Or<A.Equals<AttributeType, number[]>, A.Equals<AttributeType, number[] | undefined>>, { $delete?: number[]; $add?: number[]; $prepend?: AttributeType; $append?: number[]; } | string[]> | If<B.Or<A.Equals<AttributeType, bigint[]>, A.Equals<AttributeType, bigint[] | undefined>>, { $delete?: bigint[]; $add?: bigint[]; $prepend?: AttributeType; $append?: bigint[]; } | string[]> | If<B.Or<A.Equals<AttributeType, string[]>, A.Equals<AttributeType, string[] | undefined>>, { $delete?: string[]; $add?: string[]; $prepend?: AttributeType; $append?: string[]; } | number[]> | If<B.Or<A.Equals<AttributeType, boolean[]>, A.Equals<AttributeType, boolean[] | undefined>>, { $delete?: boolean[]; $add?: boolean[]; $prepend?: AttributeType; $append?: boolean[]; } | boolean[]> | If<B.Or<A.Equals<AttributeType, FromDynamoData<'number'>>, A.Equals<AttributeType, FromDynamoData<'number'> | undefined>>, { $add?: number; }> | If<B.Or<A.Equals<AttributeType, FromDynamoData<'bigint'>>, A.Equals<AttributeType, FromDynamoData<'bigint'> | undefined>>, { $add?: bigint; }>; export declare type DeleteOptionsReturnValues = 'NONE' | 'ALL_OLD'; export declare type RawDeleteOptions<Attributes extends A.Key = A.Key, ReturnValues extends DeleteOptionsReturnValues = DeleteOptionsReturnValues, Execute extends boolean | undefined = undefined, Parse extends boolean | undefined = undefined> = Partial<$WriteOptions<Attributes, Execute, Parse> & { returnValues: ReturnValues; }>; export declare type TransactionOptionsReturnValues = 'NONE' | 'ALL_OLD'; export interface TransactionOptions<Attributes extends A.Key = A.Key, StrictSchemaCheck extends boolean | undefined = true> { conditions?: ConditionsOrFilters<Attributes>; returnValues?: TransactionOptionsReturnValues; strictSchemaCheck?: StrictSchemaCheck; } export declare type ShouldExecute<Execute extends boolean | undefined, AutoExecute extends boolean> = B.Or<A.Equals<Execute, true>, B.And<A.Equals<Execute, undefined>, A.Equals<AutoExecute, true>>>; export declare type ShouldParse<Parse extends boolean | undefined, AutoParse extends boolean> = B.Or<A.Equals<Parse, true>, B.And<A.Equals<Parse, undefined>, A.Equals<AutoParse, true>>>; export declare type Readonly<T> = T extends F.Function | undefined ? T : T extends O.Object ? { readonly [P in keyof T]: Readonly<T[P]>; } : T; export declare type Writable<T> = T extends F.Function | undefined ? T : T extends O.Object ? { -readonly [P in keyof T]: Writable<T[P]>; } : T; export declare type InferEntityItem<E extends Entity, WritableAttributeDefinitions extends AttributeDefinitions = A.Cast<O.Writable<E['attributes'], A.Key, 'deep'>, AttributeDefinitions>, Attributes extends ParsedAttributes = ParseAttributes<WritableAttributeDefinitions, E['timestamps'], E['createdAlias'], E['modifiedAlias'], E['typeAlias'], E['typeHidden']>, Item = InferItem<WritableAttributeDefinitions, Attributes>> = Pick<Item, Extract<Attributes['shown'], keyof Item>>; export declare type EntityItem<E extends Entity> = E['_typesOnly']['_entityItemOverlay'] extends Record<A.Key, any> ? E['_typesOnly']['_entityItemOverlay'] : InferEntityItem<E>; export declare type ExtractAttributes<E extends Entity> = E['_typesOnly']['_entityItemOverlay'] extends Record<A.Key, any> ? ParsedAttributes<keyof E['_typesOnly']['_entityItemOverlay']> : ParseAttributes<A.Cast<O.Writable<E['attributes'], A.Key, 'deep'>, AttributeDefinitions>, E['timestamps'], E['createdAlias'], E['modifiedAlias'], E['typeAlias'], E['typeHidden']>; export declare type GetOptions<E extends Entity, A extends ParsedAttributes = ExtractAttributes<E>> = $GetOptions<A['shown'], boolean | undefined, boolean | undefined>; export declare type QueryOptions<E extends Entity, A extends ParsedAttributes = ExtractAttributes<E>> = EntityQueryOptions<A['shown'], A['all'], boolean | undefined, boolean | undefined>; export declare type PutOptions<E extends Entity, A extends ParsedAttributes = ExtractAttributes<E>> = $PutOptions<A['all'], PutOptionsReturnValues, boolean | undefined, boolean | undefined, boolean | undefined>; export declare type DeleteOptions<E extends Entity, A extends ParsedAttributes = ExtractAttributes<E>> = RawDeleteOptions<A['all'], DeleteOptionsReturnValues, boolean | undefined, boolean | undefined>; export declare type UpdateOptions<E extends Entity, A extends ParsedAttributes = ExtractAttributes<E>> = $UpdateOptions<A['all'], UpdateOptionsReturnValues, boolean | undefined, boolean | undefined, boolean | undefined>; export declare type AttributeMap = Record<string, NativeAttributeValue>;