UNPKG

rotorise

Version:

Supercharge your DynamoDB with Rotorise!

162 lines (148 loc) 9.53 kB
type KeysOfUnion<ObjectType> = ObjectType extends unknown ? keyof ObjectType : never type IsEqual<T, U> = (<G>() => G extends T ? 1 : 2) extends < G, >() => G extends U ? 1 : 2 ? true : false type ArrayElement<T> = T extends readonly unknown[] ? T[0] : never type ExactObject<ParameterType, InputType> = { [Key in keyof ParameterType]: Exact< ParameterType[Key], Key extends keyof InputType ? InputType[Key] : never > } & Record<Exclude<keyof InputType, KeysOfUnion<ParameterType>>, never> type Exact<ParameterType, InputType> = IsEqual< ParameterType, InputType > extends true ? ParameterType : // Convert union of array to array of union: A[] & B[] => (A & B)[] ParameterType extends unknown[] ? Array<Exact<ArrayElement<ParameterType>, ArrayElement<InputType>>> : // In TypeScript, Array is a subtype of ReadonlyArray, so always test Array before ReadonlyArray. ParameterType extends readonly unknown[] ? ReadonlyArray< Exact<ArrayElement<ParameterType>, ArrayElement<InputType>> > : ParameterType extends object ? ExactObject<ParameterType, InputType> : ParameterType type ValueOf< ObjectType, ValueType extends keyof ObjectType = keyof ObjectType, > = ObjectType[ValueType] type evaluate<T> = { [K in keyof T]: T[K] } & unknown type DistributivePick<T, K> = T extends unknown ? K extends keyof T ? Pick<T, K> : never : never type DistributiveOmit<T, K extends keyof T> = T extends unknown ? Omit<T, K> : never type SliceFromStart< T, End extends number, Acc extends unknown[] = [], > = T extends unknown[] ? Acc['length'] extends End ? Acc : T extends [infer Head, ...infer Tail] ? SliceFromStart<Tail, End, [...Acc, Head]> : Acc : never type MergeIntersectionObject<T, Keys = keyof T> = { [K in Keys]: T[K] } // type t = MergeIntersectionObject< // { a: 'a1'; b: 1n; extra: 'extra' } | { a: 'a2'; b: 2 } // > type NonEmptyArray<T> = [T, ...T[]] type Replace<T, U, V> = T extends U ? V : T type CompositeKeyParamsImpl<Entity, InputSpec extends InputSpecShape, skip extends number = 1> = Entity extends unknown ? evaluate<Pick<Entity, extractHeadOrPass<SliceFromStart<InputSpec, number extends skip ? 1 : skip>[number]> & keyof Entity> & Partial<Pick<Entity, extractHeadOrPass<InputSpec[number]> & keyof Entity>>> : never; type CompositeKeyParams<Entity extends Record<string, unknown>, FullSpec extends InputSpec<MergeIntersectionObject<Entity>>[], skip extends number = 1> = CompositeKeyParamsImpl<Entity, FullSpec, skip>; type CompositeKeyBuilderImpl<Entity, Spec, Separator extends string = '#', Deep extends number = number, isPartial extends boolean = false> = Entity extends unknown ? Join<CompositeKeyRec<Entity, number extends Deep ? Spec : SliceFromStart<Spec, Deep>>, Separator, (boolean extends isPartial ? false : isPartial) extends false ? false : true> : never; type CompositeKeyBuilder<Entity extends Record<string, unknown>, Spec extends InputSpec<MergeIntersectionObject<Entity>>[], Separator extends string = '#', Deep extends number = number, isPartial extends boolean = false> = CompositeKeyBuilderImpl<Entity, Spec, Separator, Deep, isPartial>; type joinable = string | number | bigint | boolean | null | undefined; type joinablePair = [joinable, joinable]; type Join<Pairs, Separator extends string, KeepIntermediate extends boolean = false, Acc extends string = '', AllAcc extends string = never> = Pairs extends [infer Head extends joinablePair, ...infer Tail] ? Join<Tail, Separator, KeepIntermediate, Acc extends '' ? `${Head[0]}${Separator}${Head[1]}` : `${Acc}${Separator}${Head[0]}${Separator}${Head[1]}`, KeepIntermediate extends true ? AllAcc | (Acc extends '' ? never : Acc) : never> : AllAcc | Acc; type ExtractPair<Entity, Spec> = Spec extends [ infer Key extends string, (...key: any[]) => infer Value extends joinable ] ? [Uppercase<Key>, Value] : Spec extends keyof Entity & string ? [Uppercase<Spec>, Entity[Spec] & joinable] : never; type CompositeKeyRec<Entity, Spec, Acc extends joinablePair[] = [], KeysCache extends string = keyof Entity & string> = Spec extends [infer Head, ...infer Tail] ? CompositeKeyRec<Entity, Tail, [ ...Acc, ExtractPair<Entity, Head> ], KeysCache> : Acc; type DiscriminatedSchemaShape = { discriminator: PropertyKey; spec: { [k in PropertyKey]: unknown; }; }; type InputSpecShape = ([PropertyKey, (key: any) => unknown] | PropertyKey)[]; type TableEntryImpl<Entity, Schema, Separator extends string = '#'> = Entity extends unknown ? { [Key in keyof Schema]: Schema[Key] extends DiscriminatedSchemaShape ? ValueOf<{ [K in Schema[Key]['discriminator']]: { [V in keyof Schema[Key]['spec']]: ProcessKey<Entity, Schema[Key]['spec'][V], Separator>; }[Entity[K & keyof Entity] & keyof Schema[Key]['spec']]; }> : ProcessKey<Entity, Schema[Key], Separator>; } & Entity : never; type TableEntry<Entity extends Record<string, unknown>, Schema extends Record<string, FullKeySpec<Entity>>, Separator extends string = '#'> = TableEntryImpl<Entity, Schema, Separator>; type InputSpec<E> = { [key in keyof E]: [key, (key: E[key]) => unknown] | (undefined extends E[key] ? never : null extends E[key] ? never : key); }[keyof E]; type extractHeadOrPass<T> = T extends unknown[] ? T[0] : T; type FullKeySpecSimple<Entity> = NonEmptyArray<InputSpec<MergeIntersectionObject<Entity>>> | (keyof Entity & string) | null; type DiscriminatedSchema<Entity, E> = { [key in keyof E]: E[key] extends PropertyKey ? { discriminator: key; spec: { [val in E[key]]: FullKeySpecSimple<Extract<Entity, { [k in key]: val; }>>; }; } : never; }[keyof E]; type FullKeySpec<Entity> = FullKeySpecSimple<Entity> | DiscriminatedSchema<Entity, MergeIntersectionObject<Entity>>; type ProcessSpecType<Entity, Spec, Config extends SpecConfigShape> = Spec extends string ? DistributivePick<Entity, Spec> : Spec extends InputSpecShape ? CompositeKeyParamsImpl<Entity, Spec, Config['allowPartial'] extends true ? 1 : Extract<Config['depth'], number>> : never; type SpecConfig<Spec> = Spec extends string ? never : SpecConfigShape; type SpecConfigShape = { depth?: number; allowPartial?: boolean; }; type VariantType<Entity, K extends PropertyKey, V extends PropertyKey> = [ Entity ] extends [never] ? { [k in K]: V; } : Entity & { [k in K]: V; }; type ProcessVariant<Entity, K extends PropertyKey, V extends PropertyKey, Spec extends DiscriminatedSchemaShape, Config extends SpecConfigShape> = VariantType<ProcessSpecType<VariantType<Entity, K, V>, Spec['spec'][V & keyof Spec['spec']], Config>, K, V>; type OptimizedAttributes<Entity, Spec, Config extends SpecConfigShape> = Spec extends DiscriminatedSchemaShape ? { [K in Spec['discriminator']]: { [V in keyof Spec['spec']]: ProcessVariant<Entity, K, V, Spec, Config>; }[keyof Spec['spec']]; }[Spec['discriminator']] : ProcessSpecType<Entity, Spec, Config>; type ProcessKey<Entity, Spec, Separator extends string, NullAs extends never | undefined = never, Config extends SpecConfigShape = SpecConfigShape, Attributes = Pick<Entity, Spec & keyof Entity>> = [Entity] extends [never] ? never : Spec extends keyof Entity ? Replace<ValueOf<Attributes>, null, undefined> : Spec extends InputSpecShape ? CompositeKeyBuilderImpl<Entity, Spec, Separator, Exclude<Config['depth'], undefined>, Exclude<Config['allowPartial'], undefined>> : Spec extends null ? NullAs : never; type OptimizedBuildedKey<NarrowEntity, Spec, Separator extends string, Config extends SpecConfigShape, Attributes> = Spec extends DiscriminatedSchemaShape ? { [K in Spec['discriminator']]: { [V in keyof Spec['spec']]: ProcessKey<NarrowEntity extends { [k in K]: V; } ? NarrowEntity : never, Spec['spec'][V], Separator, undefined, Config, Attributes>; }[keyof Spec['spec']]; }[Spec['discriminator']] : ProcessKey<NarrowEntity, Spec, Separator, undefined, Config, Attributes>; type TableEntryDefinition<Entity, Schema, Separator extends string> = { toEntry: <const ExactEntity extends Exact<Entity, ExactEntity>>(item: ExactEntity) => ExactEntity extends infer E extends Entity ? TableEntryImpl<E, Schema, Separator> : never; fromEntry: <const Entry extends TableEntryImpl<Entity, Schema, Separator>>(entry: Entry) => DistributiveOmit<Entry, keyof Schema>; key: <const Key extends keyof Schema, const Config extends SpecConfig<Spec>, const Attributes extends OptimizedAttributes<Entity, Spec, Config_>, Spec = Schema[Key], Config_ extends SpecConfigShape = [SpecConfigShape] extends [Config] ? { depth?: undefined; allowPartial?: undefined; } : Config>(key: Key, attributes: Attributes, config?: Config) => OptimizedBuildedKey<Entity & Attributes, Spec, Separator, Config_, Attributes>; infer: TableEntryImpl<Entity, Schema, Separator>; path: () => TableEntryImpl<Entity, Schema, Separator>; }; declare const tableEntry: <const Entity extends Record<string, unknown>>() => <const Schema extends Record<string, FullKeySpec<Entity>>, Separator extends string = "#">(schema: Schema, separator?: Separator) => TableEntryDefinition<Entity, Schema, Separator>; export { type CompositeKeyBuilder, type CompositeKeyParams, type CompositeKeyParamsImpl, type TableEntry, tableEntry };