-
-
Save ThomasAribart/618a3b097a29cbfb26094ed064c39041 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
declare module 'dynamodb-toolbox' { | |
// Imports | |
import type { DocumentClient } from 'aws-sdk/lib/dynamodb/document_client'; | |
// Helpers | |
type Writeable<O> = O extends | |
| Record<string, unknown> | |
| Record<number, unknown> | |
? { -readonly [K in keyof O]: Writeable<O[K]> } | |
: O; | |
type Replace< | |
O extends Record<string | number | symbol, any>, | |
K extends keyof O, | |
V | |
> = Omit<O, K> & { [key in K]: V }; | |
type Merge< | |
A extends Record<string, unknown>, | |
B extends Record<string, unknown> | |
// Somehow this double check is necessary for a nice rendering in hover windows | |
> = A extends Record<string, unknown> | |
? B extends Record<string, unknown> | |
? { | |
[K in keyof (A & B)]: K extends keyof B | |
? B[K] | |
: K extends keyof A | |
? A[K] | |
: never; | |
} | |
: never | |
: never; | |
type Filter< | |
Item extends Record<string, unknown>, | |
ReqProps extends keyof Item, | |
OptProps extends keyof Item, | |
FiltProps extends keyof Item = keyof Item | |
> = Merge< | |
{ | |
[Key in FiltProps & OptProps]?: Item[Key]; | |
}, | |
{ | |
[Key in FiltProps & ReqProps]: Item[Key]; | |
} | |
>; | |
type If<C, T, F> = C extends true ? T : F; | |
type DoesExtend<A, B> = A extends B ? true : false; | |
// Table | |
type TableAttributes = Record<string, DynamoDBType>; | |
type Indexes = Record<string, { partitionKey?: string; sortKey?: string }>; | |
interface TableConstructor { | |
name: string; | |
alias?: string; | |
partitionKey: string; | |
sortKey?: string; | |
entityField?: boolean | string; | |
attributes?: TableAttributes; | |
indexes?: Indexes; | |
autoExecute?: boolean; | |
autoParse?: boolean; | |
DocumentClient?: DocumentClient; | |
} | |
type WriteOperation = Record<string, Record<string, unknown>>; | |
type GetOperation = Record<string, Record<string, unknown>>; | |
export class Table { | |
name: string; | |
constructor(options: TableConstructor); | |
// Methods | |
batchWrite( | |
operations: WriteOperation[], | |
options?: Record<string, unknown>, | |
parameters?: Record<string, unknown>, | |
): Promise<DocumentClient.BatchWriteItemOutput>; | |
batchGet( | |
operations: GetOperation[], | |
options?: Record<string, unknown>, | |
parameters?: Record<string, unknown>, | |
): Promise<DocumentClient.BatchGetItemOutput>; | |
scan( | |
options?: Record<string, unknown>, | |
parameters?: Record<string, unknown>, | |
): Promise< | |
DocumentClient.ScanOutput & { | |
next?: () => Promise<DocumentClient.ScanOutput>; | |
} | |
>; | |
query( | |
partitionKey: string, | |
options?: Record<string, unknown>, | |
parameters?: Record<string, unknown>, | |
): Promise<DocumentClient.QueryOutput>; | |
} | |
// Entity | |
type EntityPureAttrDef = Partial<{ | |
partitionKey: boolean; | |
sortKey: boolean; | |
hidden: boolean; | |
type: DynamoDBType; | |
map: string; | |
save: boolean; | |
default: unknown; | |
required: boolean | 'always'; | |
}>; | |
type EntityMappedAttrDef = | |
| [string, number] | |
| [string, number, EntityPureAttrDef]; | |
type EntityAttrDef = DynamoDBType | EntityPureAttrDef | EntityMappedAttrDef; | |
type EntityAttrDefs = Record<string, EntityAttrDef>; | |
type EntityReadonlyPureAttrDef = Readonly<EntityPureAttrDef>; | |
type EntityReadonlyMappedAttrDef = Readonly< | |
[string, number] | [string, number, EntityReadonlyPureAttrDef] | |
>; | |
type EntityReadonlyAttrDef = | |
| DynamoDBType | |
| EntityReadonlyPureAttrDef | |
| EntityReadonlyMappedAttrDef; | |
type EntityReadonlyAttrDefs = Readonly<Record<string, EntityReadonlyAttrDef>>; | |
// Attributes parsing | |
type InferKeyOfType< | |
A extends EntityAttrDefs, | |
KeyType extends 'partitionKey' | 'sortKey' | |
> = { | |
[key in keyof A]: A[key] extends EntityPureAttrDef | |
? KeyType extends keyof A[key] | |
? A[key][KeyType] extends true | |
? Extract<key, string> | |
: never | |
: never | |
: never; | |
}[keyof A]; | |
type InferIsKeyMapped< | |
A extends EntityAttrDefs, | |
K extends string | |
> = DoesExtend< | |
true, | |
{ | |
[attr in keyof A]: A[attr] extends EntityMappedAttrDef | |
? DoesExtend<K, A[attr][0]> | |
: false; | |
}[keyof A] | |
>; | |
type InferMappedAttr<A extends EntityAttrDefs, K extends string> = { | |
[key in keyof A]: A[key] extends EntityMappedAttrDef | |
? K extends A[key][0] | |
? Extract<key, string> | |
: never | |
: never; | |
}[keyof A]; | |
type InferAttrValue<A extends EntityAttrDefs, K extends keyof A> = { | |
dynamoDbType: A[K] extends DynamoDBType ? InferValueType<A[K]> : never; | |
entityPureAttrDef: A[K] extends EntityPureAttrDef | |
? 'type' extends keyof A[K] | |
? InferValueType<A[K]['type']> | |
: unknown | |
: never; | |
entityMappedAttrDef: A[K] extends EntityMappedAttrDef | |
? A[K][0] extends keyof A | |
? InferAttrValue<A, A[K][0]> | |
: unknown | |
: never; | |
}[A[K] extends DynamoDBType | |
? 'dynamoDbType' | |
: A[K] extends EntityPureAttrDef | |
? 'entityPureAttrDef' | |
: A[K] extends EntityMappedAttrDef | |
? 'entityMappedAttrDef' | |
: never]; | |
type InferItem<A extends EntityAttrDefs> = { | |
[K in keyof A]: InferAttrValue<A, K>; | |
}; | |
type InferIsAttrAlways<A extends EntityPureAttrDef> = If< | |
DoesExtend<'default', keyof A>, | |
false, | |
DoesExtend<A['required'], 'always'> | |
>; | |
type InferAlwaysAttr<A extends EntityAttrDefs> = { | |
[K in keyof A]: A[K] extends EntityPureAttrDef | |
? If<InferIsAttrAlways<A[K]>, K, never> | |
: A[K] extends EntityMappedAttrDef | |
? 2 extends keyof A[K] | |
? If<InferIsAttrAlways<A[K][2]>, K, never> | |
: never | |
: never; | |
}[keyof A]; | |
type InferIsAttrReq<A extends EntityPureAttrDef> = If< | |
DoesExtend<'default', keyof A>, | |
false, | |
DoesExtend<A['required'], true> | |
>; | |
type InferReqAttr<A extends EntityAttrDefs> = { | |
[K in keyof A]: A[K] extends EntityPureAttrDef | |
? If<InferIsAttrReq<A[K]>, K, never> | |
: A[K] extends EntityMappedAttrDef | |
? 2 extends keyof A[K] | |
? If<InferIsAttrReq<A[K][2]>, K, never> | |
: never | |
: never; | |
}[keyof A]; | |
interface GetOptions { | |
consistent: boolean; | |
capacity: 'none' | 'total' | 'indexes'; | |
execute: boolean; | |
parse: boolean; | |
} | |
interface QueryOptions { | |
index: string; | |
beginsWith: string; | |
eq: string; | |
reverse: boolean; | |
filters: unknown; | |
between: unknown[]; | |
consistent: boolean; | |
limit: number; | |
} | |
export class Entity< | |
Name extends string, | |
ReadonlyAttrDefs extends EntityAttrDefs | EntityReadonlyAttrDefs, | |
AttrDefs extends EntityAttrDefs = Writeable<ReadonlyAttrDefs>, | |
Item extends Record<string, unknown> = InferItem<AttrDefs>, | |
PK extends string = InferKeyOfType<AttrDefs, 'partitionKey'>, | |
IsPKMapped extends boolean = InferIsKeyMapped<AttrDefs, PK>, | |
PKMappedAttr extends string = IsPKMapped extends true | |
? InferMappedAttr<AttrDefs, PK> | |
: never, | |
/** | |
* @debt dynamodb-toolbox-typing "Handle no SK edge case" | |
*/ | |
SK extends string = InferKeyOfType<AttrDefs, 'sortKey'>, | |
IsSKMapped extends boolean = InferIsKeyMapped<AttrDefs, SK>, | |
SKMappedAttr extends string = IsSKMapped extends true | |
? InferMappedAttr<AttrDefs, SK> | |
: never, | |
PrimaryKey extends Record<string, unknown> = (IsPKMapped extends true | |
? Pick<Item, PK> | Pick<Item, PKMappedAttr> | |
: Pick<Item, PK>) & | |
(IsSKMapped extends true | |
? Pick<Item, SK> | Pick<Item, SKMappedAttr> | |
: Pick<Item, SK>), | |
Attr extends keyof Item = keyof Item, | |
KeyAttr extends Attr = Extract<PK | PKMappedAttr | SK | SKMappedAttr, Attr>, | |
AlwaysAttr extends Attr = Exclude< | |
Extract<InferAlwaysAttr<AttrDefs>, Attr>, | |
KeyAttr | |
>, | |
ReqAttr extends Attr = Exclude< | |
Extract<InferReqAttr<AttrDefs>, Attr>, | |
KeyAttr | |
>, | |
OptAttr extends Attr = Exclude<Attr, KeyAttr | AlwaysAttr | ReqAttr> | |
> { | |
constructor( | |
options: { name: Name; attributes: ReadonlyAttrDefs } & Record< | |
string, | |
unknown | |
>, | |
); | |
// Properties | |
readonly name: Name; | |
table: Table; | |
readonly DocumentClient: DocumentClient; | |
autoExecute: boolean; | |
autoParse: boolean; | |
readonly partitionKey: PK; | |
readonly sortKey: SK; | |
// Get | |
getParams<A extends Attr[]>( | |
primaryKey: PrimaryKey, | |
options?: Partial<{ attributes: A } & GetOptions>, | |
parameters?: Record<string, unknown>, | |
): DocumentClient.GetItemInput; | |
get<A extends Attr[]>( | |
primaryKey: PrimaryKey, | |
options?: Partial<{ attributes: A } & GetOptions>, | |
parameters?: Record<string, unknown>, | |
): Promise< | |
Replace< | |
DocumentClient.GetItemOutput, | |
'Item', | |
/** | |
* @debt dynamodb-toolbox-typing "Use hidden directive to hide pk/sk from result type ?" | |
*/ | |
Filter<Item, KeyAttr | AlwaysAttr | ReqAttr, OptAttr, A[number]> | |
> | |
>; | |
// Delete | |
deleteParams( | |
primaryKey: PrimaryKey, | |
options?: Record<string, unknown>, | |
parameters?: Record<string, unknown>, | |
): DocumentClient.DeleteItemInput; | |
delete( | |
primaryKey: PrimaryKey, | |
options?: Record<string, unknown>, | |
parameters?: Record<string, unknown>, | |
): Promise<DocumentClient.DeleteItemOutput>; | |
// Put | |
putParams( | |
item: PrimaryKey & | |
{ [reqAttr in AlwaysAttr | ReqAttr]: Item[reqAttr] } & | |
{ [optAttr in OptAttr]?: Item[optAttr] }, | |
/** | |
* @debt dynamodb-toolbox-typing "Use Attr in conditions attr" | |
*/ | |
options?: Record<string, unknown>, | |
parameters?: Record<string, unknown>, | |
): DocumentClient.PutItemInput; | |
put( | |
item: PrimaryKey & | |
{ [reqAttr in AlwaysAttr | ReqAttr]: Item[reqAttr] } & | |
{ [optAttr in OptAttr]?: Item[optAttr] }, | |
/** | |
* @debt dynamodb-toolbox-typing "Use Attr in conditions attr" | |
*/ | |
options?: Record<string, unknown>, | |
parameters?: Record<string, unknown>, | |
/** | |
* @debt dynamodb-toolbox-typing "Type put return value" | |
*/ | |
): Promise<DocumentClient.PutItemOutput>; | |
// Update | |
updateParams( | |
primaryKey: PrimaryKey & | |
{ [attr in AlwaysAttr]: Item[attr] } & | |
{ | |
[attr in OptAttr | ReqAttr]?: | |
| Item[attr] | |
| { $delete?: string[]; $add?: unknown }; | |
} & { $remove?: OptAttr[] }, | |
options?: Record<string, unknown>, | |
parameters?: Record<string, unknown>, | |
): DocumentClient.UpdateItemInput; | |
update( | |
primaryKey: PrimaryKey & | |
{ [attr in AlwaysAttr]: Item[attr] } & | |
{ | |
[attr in OptAttr | ReqAttr]?: | |
| Item[attr] | |
| { $delete?: string[]; $add?: unknown }; | |
} & { $remove?: OptAttr[] }, | |
options?: Record<string, unknown>, | |
parameters?: Record<string, unknown>, | |
): Promise< | |
Replace< | |
DocumentClient.UpdateItemOutput, | |
'Attributes', | |
/** | |
* @debt dynamodb-toolbox-typing "TODO: Use returnValues argument" | |
*/ | |
Filter<Item, KeyAttr | AlwaysAttr | ReqAttr, OptAttr> | |
> | |
>; | |
// Query | |
queryParams<A extends Attr[]>( | |
partitionKey: unknown, | |
options?: Partial<{ attributes: A } & QueryOptions>, | |
parameters?: Record<string, unknown>, | |
): DocumentClient.QueryInput; | |
query<A extends Attr[]>( | |
partitionKey: unknown, | |
options?: Partial<{ attributes: A } & QueryOptions>, | |
parameters?: Record<string, unknown>, | |
): Promise< | |
Replace< | |
DocumentClient.QueryOutput, | |
'Items', | |
Filter<Item, KeyAttr | AlwaysAttr | ReqAttr, OptAttr, A[number]>[] | |
> | |
>; | |
putBatch( | |
item: Record<string, unknown>, | |
options?: Record<string, unknown>, | |
parameters?: Record<string, unknown>, | |
): WriteOperation; | |
deleteBatch( | |
primaryKey: Record<string, unknown>, | |
options?: Record<string, unknown>, | |
parameters?: Record<string, unknown>, | |
): WriteOperation; | |
} | |
// DynamoDB | |
type DynamoDBStringType = 'string'; | |
type DynamoDBBooleanType = 'boolean'; | |
type DynamoDBNumberType = 'number'; | |
type DynamoDBListType = 'list'; | |
type DynamoDBMapType = 'map'; | |
type DynamoDBBinaryType = 'binary'; | |
type DynamoDBSetType = 'set'; | |
type DynamoDBType = | |
| DynamoDBStringType | |
| DynamoDBBooleanType | |
| DynamoDBNumberType | |
| DynamoDBListType | |
| DynamoDBMapType | |
| DynamoDBBinaryType | |
| DynamoDBSetType; | |
type InferValueType<T extends DynamoDBType> = { | |
string: string; | |
boolean: boolean; | |
number: number; | |
list: any[]; | |
map: any; | |
binary: unknown; | |
set: Set<unknown>; | |
}[T]; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment