Skip to content

Commit

Permalink
Merge pull request woltsu#33 from mindler-sasu/perkele
Browse files Browse the repository at this point in the history
fix delete and put item typing when no returnValues set
  • Loading branch information
woltsu authored Jun 12, 2024
2 parents 9a5812c + fb72f4f commit 72b04bf
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 54 deletions.
44 changes: 44 additions & 0 deletions src/queryBuilders/deleteItemQueryBuilder.integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,48 @@ describe("DeleteItemQueryBuilder", () => {

expect(res).toBeDefined();
});
it("doesn't return values if no returnValues is specified or its set to NONE", async () => {
await tsynamoClient
.putItem("myTable")
.item({
userId: "1",
dataTimestamp: 2,
})
.execute();

const res = await tsynamoClient
.deleteItem("myTable")
.keys({ userId: "1", dataTimestamp: 2 })
.execute();

expectTypeOf(res).toBeNever();
expect(res).toBeUndefined();

const res2 = await tsynamoClient
.deleteItem("myTable")
.keys({ userId: "1", dataTimestamp: 2 })
.returnValues("NONE")
.execute();

expectTypeOf(res2).toBeNever();
expect(res2).toBeUndefined();
});
it("does return values if returnValues is specified", async () => {
await tsynamoClient
.putItem("myTable")
.item({
userId: "1",
dataTimestamp: 2,
})
.execute();

const res = await tsynamoClient
.deleteItem("myTable")
.keys({ userId: "1", dataTimestamp: 2 })
.returnValues("ALL_OLD")
.execute();

expectTypeOf(res).not.toBeNever();
expect(res).toBeDefined();
});
});
61 changes: 39 additions & 22 deletions src/queryBuilders/deleteItemQueryBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
export interface DeleteItemQueryBuilderInterface<
DDB,
Table extends keyof DDB,
O extends DDB[Table]
O
> {
/**
* A condition that must be satisfied in order for a DeleteItem operation to be executed.
Expand Down Expand Up @@ -134,17 +134,25 @@ export interface DeleteItemQueryBuilderInterface<
*
* The values returned are strongly consistent.
*/
returnValues(
option: Extract<ReturnValuesOptions, "NONE" | "ALL_OLD">
): DeleteItemQueryBuilder<DDB, Table, O>;
returnValues<Choice extends "NONE" | "ALL_OLD">(
option: Extract<ReturnValuesOptions, Choice>
): DeleteItemQueryBuilder<
DDB,
Table,
"NONE" extends Choice ? O : ExecuteOutput<DDB[Table]>
>;

/**
*
* Returns the item attributes for a DeleteItem operation that failed a condition check.
*/
returnValuesOnConditionCheckFailure(
option: Extract<ReturnValuesOptions, "NONE" | "ALL_OLD">
): DeleteItemQueryBuilder<DDB, Table, O>;
returnValuesOnConditionCheckFailure<Choice extends "NONE" | "ALL_OLD">(
option: Extract<ReturnValuesOptions, Choice>
): DeleteItemQueryBuilder<
DDB,
Table,
"NONE" extends Choice ? O : ExecuteOutput<DDB[Table]>
>;

/**
* An object of attribute names to attribute values, representing the primary key of the item to delete.
Expand All @@ -171,17 +179,18 @@ export interface DeleteItemQueryBuilderInterface<
* Compiles into an DynamoDB DocumentClient Command.
*/
compile(): DeleteCommand;

/**
* Executes the command and returns its output.
*/
execute(): Promise<ExecuteOutput<O>[] | undefined>;
execute(): Promise<O[] | undefined>;
}

export class DeleteItemQueryBuilder<
DDB,
Table extends keyof DDB,
O extends DDB[Table]
> implements DeleteItemQueryBuilderInterface<DDB, Table, O>
/**
* @todo support ReturnValuesOnConditionCheckFailure
*/
export class DeleteItemQueryBuilder<DDB, Table extends keyof DDB, O>
implements DeleteItemQueryBuilderInterface<DDB, Table, O>
{
readonly #props: DeleteItemQueryBuilderProps;

Expand Down Expand Up @@ -225,10 +234,14 @@ export class DeleteItemQueryBuilder<
});
}

returnValues(
option: Extract<ReturnValuesOptions, "NONE" | "ALL_OLD">
): DeleteItemQueryBuilder<DDB, Table, O> {
return new DeleteItemQueryBuilder<DDB, Table, O>({
returnValues<Choice extends "NONE" | "ALL_OLD">(
option: Extract<ReturnValuesOptions, Choice>
): DeleteItemQueryBuilder<
DDB,
Table,
"NONE" extends Choice ? O : ExecuteOutput<DDB[Table]>
> {
return new DeleteItemQueryBuilder({
...this.#props,
node: {
...this.#props.node,
Expand All @@ -240,10 +253,14 @@ export class DeleteItemQueryBuilder<
});
}

returnValuesOnConditionCheckFailure(
option: Extract<ReturnValuesOptions, "NONE" | "ALL_OLD">
): DeleteItemQueryBuilder<DDB, Table, O> {
return new DeleteItemQueryBuilder<DDB, Table, O>({
returnValuesOnConditionCheckFailure<Choice extends "NONE" | "ALL_OLD">(
option: Extract<ReturnValuesOptions, Choice>
): DeleteItemQueryBuilder<
DDB,
Table,
"NONE" extends Choice ? O : ExecuteOutput<DDB[Table]>
> {
return new DeleteItemQueryBuilder({
...this.#props,
node: {
...this.#props.node,
Expand Down Expand Up @@ -274,7 +291,7 @@ export class DeleteItemQueryBuilder<
return this.#props.queryCompiler.compile(this.#props.node);
};

execute = async (): Promise<ExecuteOutput<O>[] | undefined> => {
execute = async (): Promise<unknown extends O ? never : O[] | undefined> => {
const deleteCommand = this.compile();
const data = await this.#props.ddbClient.send(deleteCommand);
return data.Attributes as any;
Expand Down
7 changes: 2 additions & 5 deletions src/queryBuilders/expressionBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,11 +228,8 @@ export type ExprArgs<
| AttributeBetweenExprArg<DDB, Table, Key>
| BuilderExprArg<DDB, Table, O, AllowKeysInExpression>
| NotExprArg<DDB, Table, O, AllowKeysInExpression>;
export class ExpressionBuilder<
DDB,
Table extends keyof DDB,
O extends DDB[Table]
> implements ExpressionBuilderInterface<DDB, Table, O>
export class ExpressionBuilder<DDB, Table extends keyof DDB, O>
implements ExpressionBuilderInterface<DDB, Table, O>
{
readonly #props: ExpressionBuilderProps;

Expand Down
21 changes: 21 additions & 0 deletions src/queryBuilders/putItemQueryBuilder.integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,34 @@ describe("PutItemQueryBuilder", () => {
expect(result).toEqual(itemToPut);
});

it("doesnt return values without returnValues or when its set to NONE", async () => {
let result = await tsynamoClient
.putItem("myTable")
.item(itemToPut)
.execute();

expectTypeOf(result).toBeNever();
expect(result).toBeUndefined();

let result2 = await tsynamoClient
.putItem("myTable")
.item(itemToPut)
.returnValues("NONE")
.execute();

expectTypeOf(result2).toBeNever();
expect(result2).toBeUndefined();
});

it("handles ReturnValues option", async () => {
let result = await tsynamoClient
.putItem("myTable")
.item(itemToPut)
.returnValues("ALL_OLD")
.execute();

expectTypeOf(result).not.toBeNever();

expect(result).toBeUndefined();

result = await tsynamoClient
Expand Down
44 changes: 23 additions & 21 deletions src/queryBuilders/putItemQueryBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,7 @@ import {
NotExprArg,
} from "./expressionBuilder";

export interface PutItemQueryBuilderInterface<
DDB,
Table extends keyof DDB,
O extends DDB[Table]
> {
export interface PutItemQueryBuilderInterface<DDB, Table extends keyof DDB, O> {
/**
* A condition that must be satisfied in order for a PutItem operation to be executed.
*
Expand Down Expand Up @@ -129,9 +125,13 @@ export interface PutItemQueryBuilderInterface<
*
* The values returned are strongly consistent.
*/
returnValues(
option: Extract<ReturnValuesOptions, "NONE" | "ALL_OLD">
): PutItemQueryBuilder<DDB, Table, O>;
returnValues<Choice extends "NONE" | "ALL_OLD">(
option: Extract<ReturnValuesOptions, Choice>
): PutItemQueryBuilder<
DDB,
Table,
"NONE" extends Choice ? O : ExecuteOutput<DDB[Table]>
>;

/**
* The item that is put into the table.
Expand All @@ -155,25 +155,23 @@ export interface PutItemQueryBuilderInterface<
* .execute()
* ```
*/
item<Item extends ExecuteOutput<O>>(
item<Item extends ExecuteOutput<DDB[Table]>>(
item: Item
): PutItemQueryBuilder<DDB, Table, O>;

/**
* Compiles into an DynamoDB DocumentClient Command.
*/
compile(): PutCommand;

/**
* Executes the command and returns its output.
*/
execute(): Promise<ExecuteOutput<O>[] | undefined>;
execute(): Promise<O[] | undefined>;
}

export class PutItemQueryBuilder<
DDB,
Table extends keyof DDB,
O extends DDB[Table]
> implements PutItemQueryBuilderInterface<DDB, Table, O>
export class PutItemQueryBuilder<DDB, Table extends keyof DDB, O>
implements PutItemQueryBuilderInterface<DDB, Table, O>
{
readonly #props: PutItemQueryBuilderProps;

Expand Down Expand Up @@ -217,7 +215,7 @@ export class PutItemQueryBuilder<
});
}

item<Item extends ExecuteOutput<O>>(
item<Item extends ExecuteOutput<DDB[Table]>>(
item: Item
): PutItemQueryBuilder<DDB, Table, O> {
return new PutItemQueryBuilder<DDB, Table, O>({
Expand All @@ -232,10 +230,14 @@ export class PutItemQueryBuilder<
});
}

returnValues(
option: Extract<ReturnValuesOptions, "NONE" | "ALL_OLD">
): PutItemQueryBuilder<DDB, Table, O> {
return new PutItemQueryBuilder<DDB, Table, O>({
returnValues<Choice extends "NONE" | "ALL_OLD">(
option: Extract<ReturnValuesOptions, Choice>
): PutItemQueryBuilder<
DDB,
Table,
"NONE" extends Choice ? O : ExecuteOutput<DDB[Table]>
> {
return new PutItemQueryBuilder({
...this.#props,
node: {
...this.#props.node,
Expand All @@ -251,7 +253,7 @@ export class PutItemQueryBuilder<
return this.#props.queryCompiler.compile(this.#props.node);
};

execute = async (): Promise<ExecuteOutput<O>[] | undefined> => {
execute = async (): Promise<unknown extends O ? never : O[] | undefined> => {
const putCommand = this.compile();
const data = await this.#props.ddbClient.send(putCommand);
return data.Attributes as any;
Expand Down
12 changes: 6 additions & 6 deletions src/queryCreator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,10 @@ export class QueryCreator<DDB> {
*
* @see https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/dynamodb/command/PutItemCommand/
*/
putItem<Table extends keyof DDB & string>(
putItem<Table extends keyof DDB & string, O>(
table: Table
): PutItemQueryBuilder<DDB, Table, DDB[Table]> {
return new PutItemQueryBuilder<DDB, Table, DDB[Table]>({
): PutItemQueryBuilder<DDB, Table, O> {
return new PutItemQueryBuilder({
node: {
kind: "PutNode",
table: {
Expand Down Expand Up @@ -166,10 +166,10 @@ export class QueryCreator<DDB> {
*
* @see https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/dynamodb/command/DeleteItemCommand/
*/
deleteItem<Table extends keyof DDB & string>(
deleteItem<Table extends keyof DDB & string, O>(
table: Table
): DeleteItemQueryBuilder<DDB, Table, DDB[Table]> {
return new DeleteItemQueryBuilder<DDB, Table, DDB[Table]>({
): DeleteItemQueryBuilder<DDB, Table, O> {
return new DeleteItemQueryBuilder({
node: {
kind: "DeleteNode",
table: {
Expand Down

0 comments on commit 72b04bf

Please sign in to comment.