Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix delete and put item typing when no returnValues set #33

Merged
merged 4 commits into from
Jun 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading