Skip to content

Commit

Permalink
add support for UPDATE operation in transaction
Browse files Browse the repository at this point in the history
  • Loading branch information
mindler-olli committed Apr 18, 2024
1 parent ba663e1 commit 1e57bb1
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 36 deletions.
2 changes: 2 additions & 0 deletions src/nodes/TransactItemNode.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { DeleteNode } from "./deleteNode";
import { PutNode } from "./putNode";
import { UpdateNode } from "./updateNode";

export type TransactItemNode = {
readonly kind: "TransactItemNode";
readonly Put?: PutNode;
readonly Delete?: DeleteNode;
readonly Update?: UpdateNode;
};
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,35 @@ exports[`TransactionBuilder > handles puts 1`] = `
},
]
`;

exports[`TransactionBuilder > handles transaction with puts 1`] = `
[
{
"dataTimestamp": 1,
"userId": "9999",
},
{
"dataTimestamp": 2,
"userId": "9999",
},
]
`;

exports[`TransactionBuilder > handles transaction with updates 1`] = `
[
{
"dataTimestamp": 1,
"someBoolean": true,
"userId": "9999",
},
{
"dataTimestamp": 2,
"tags": [
"a",
"b",
"c",
],
"userId": "9999",
},
]
`;
41 changes: 39 additions & 2 deletions src/queryBuilders/transactionBuilder.integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ describe("TransactionBuilder", () => {
});
});

it("handles puts", async () => {
it("handles transaction with puts", async () => {
const trx = tsynamoClient.createTransaction();

trx.addItem({
Expand All @@ -41,7 +41,7 @@ describe("TransactionBuilder", () => {
expect(result).toMatchSnapshot();
});

it("handles deletes", async () => {
it("handles transaction with deletes", async () => {
await tsynamoClient
.putItem("myTable")
.item({ userId: "9999", dataTimestamp: 1 })
Expand Down Expand Up @@ -110,4 +110,41 @@ describe("TransactionBuilder", () => {

expect(foundItem).toBeUndefined();
});

it("handles transaction with updates", async () => {
await tsynamoClient
.putItem("myTable")
.item({ userId: "1", dataTimestamp: 1 })
.execute();

await tsynamoClient
.putItem("myTable")
.item({ userId: "1", dataTimestamp: 2 })
.execute();

const trx = tsynamoClient.createTransaction();

trx.addItem({
Update: tsynamoClient
.updateItem("myTable")
.keys({ userId: "9999", dataTimestamp: 1 })
.set("someBoolean", "=", true),
});

trx.addItem({
Update: tsynamoClient
.updateItem("myTable")
.keys({ userId: "9999", dataTimestamp: 2 })
.set("tags", "=", ["a", "b", "c"]),
});

await trx.execute();

const result = await tsynamoClient
.query("myTable")
.keyCondition("userId", "=", "9999")
.execute();

expect(result).toMatchSnapshot();
});
});
6 changes: 5 additions & 1 deletion src/queryBuilders/transactionBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@ import { TransactionNode } from "../nodes/transactionNode";
import { QueryCompiler } from "../queryCompiler";
import { PutItemQueryBuilder } from "./putItemQueryBuilder";
import { DeleteItemQueryBuilder } from "./deleteItemQueryBuilder";
import { UpdateItemQueryBuilder } from "./updateItemQueryBuilder";

export interface TransactionBuilderInterface<DDB> {
/**
* TODO: Update, ConditionCheck
* TODO: ConditionCheck
*/
addItem(item: {
Put?: PutItemQueryBuilder<DDB, any, any>;
Delete?: DeleteItemQueryBuilder<DDB, any, any>;
Update?: UpdateItemQueryBuilder<DDB, any, any>;
}): void;

execute(): Promise<void>;
Expand All @@ -28,11 +30,13 @@ export class TransactionBuilder<DDB>
addItem(item: {
Put?: PutItemQueryBuilder<DDB, any, any>;
Delete?: DeleteItemQueryBuilder<DDB, any, any>;
Update?: UpdateItemQueryBuilder<DDB, any, any>;
}) {
this.#props.node.transactItems.push({
kind: "TransactItemNode",
Put: item.Put?.node,
Delete: item.Delete?.node,
Update: item.Update?.node,
});
}

Expand Down
64 changes: 34 additions & 30 deletions src/queryBuilders/updateItemQueryBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,96 +31,96 @@ import { SetUpdateExpressionFunctionQueryBuilder } from "./setUpdateExpressionFu
export interface UpdateItemQueryBuilderInterface<
DDB,
Table extends keyof DDB,
O
O extends DDB[Table]
> {
// conditionExpression
conditionExpression<Key extends ObjectKeyPaths<DDB[Table]>>(
...args: ComparatorExprArg<DDB, Table, Key>
): UpdateItemQueryBuilderInterface<DDB, Table, O>;
): UpdateItemQueryBuilder<DDB, Table, O>;

conditionExpression<Key extends ObjectKeyPaths<DDB[Table]>>(
...args: AttributeFuncExprArg<Key>
): UpdateItemQueryBuilderInterface<DDB, Table, O>;
): UpdateItemQueryBuilder<DDB, Table, O>;

conditionExpression<Key extends ObjectKeyPaths<DDB[Table]>>(
...args: AttributeBeginsWithExprArg<Key>
): UpdateItemQueryBuilderInterface<DDB, Table, O>;
): UpdateItemQueryBuilder<DDB, Table, O>;

conditionExpression<Key extends ObjectKeyPaths<DDB[Table]>>(
...args: AttributeContainsExprArg<DDB, Table, Key>
): UpdateItemQueryBuilderInterface<DDB, Table, O>;
): UpdateItemQueryBuilder<DDB, Table, O>;

conditionExpression<Key extends ObjectKeyPaths<DDB[Table]>>(
...args: AttributeBetweenExprArg<DDB, Table, Key>
): UpdateItemQueryBuilderInterface<DDB, Table, O>;
): UpdateItemQueryBuilder<DDB, Table, O>;

conditionExpression<Key extends ObjectKeyPaths<DDB[Table]>>(
...args: NotExprArg<DDB, Table, Key>
): UpdateItemQueryBuilderInterface<DDB, Table, O>;
): UpdateItemQueryBuilder<DDB, Table, O>;

conditionExpression<Key extends ObjectKeyPaths<DDB[Table]>>(
...args: BuilderExprArg<DDB, Table, Key>
): UpdateItemQueryBuilderInterface<DDB, Table, O>;
): UpdateItemQueryBuilder<DDB, Table, O>;

// orConditionExpression
orConditionExpression<Key extends ObjectKeyPaths<DDB[Table]>>(
...args: ComparatorExprArg<DDB, Table, Key>
): UpdateItemQueryBuilderInterface<DDB, Table, O>;
): UpdateItemQueryBuilder<DDB, Table, O>;

orConditionExpression<Key extends ObjectKeyPaths<DDB[Table]>>(
...args: AttributeFuncExprArg<Key>
): UpdateItemQueryBuilderInterface<DDB, Table, O>;
): UpdateItemQueryBuilder<DDB, Table, O>;

orConditionExpression<Key extends ObjectKeyPaths<DDB[Table]>>(
...args: AttributeBeginsWithExprArg<Key>
): UpdateItemQueryBuilderInterface<DDB, Table, O>;
): UpdateItemQueryBuilder<DDB, Table, O>;

orConditionExpression<Key extends ObjectKeyPaths<DDB[Table]>>(
...args: AttributeContainsExprArg<DDB, Table, Key>
): UpdateItemQueryBuilderInterface<DDB, Table, O>;
): UpdateItemQueryBuilder<DDB, Table, O>;

orConditionExpression<Key extends ObjectKeyPaths<DDB[Table]>>(
...args: AttributeBetweenExprArg<DDB, Table, Key>
): UpdateItemQueryBuilderInterface<DDB, Table, O>;
): UpdateItemQueryBuilder<DDB, Table, O>;

orConditionExpression<Key extends ObjectKeyPaths<DDB[Table]>>(
...args: NotExprArg<DDB, Table, Key>
): UpdateItemQueryBuilderInterface<DDB, Table, O>;
): UpdateItemQueryBuilder<DDB, Table, O>;

orConditionExpression<Key extends ObjectKeyPaths<DDB[Table]>>(
...args: BuilderExprArg<DDB, Table, Key>
): UpdateItemQueryBuilderInterface<DDB, Table, O>;
): UpdateItemQueryBuilder<DDB, Table, O>;

set<Key extends ObjectKeyPaths<PickNonKeys<DDB[Table]>>>(
key: Key,
operand: UpdateExpressionOperands,
value: StripKeys<GetFromPath<DDB[Table], Key>>
): UpdateItemQueryBuilderInterface<DDB, Table, O>;
): UpdateItemQueryBuilder<DDB, Table, O>;

set<Key extends ObjectKeyPaths<PickNonKeys<DDB[Table]>>>(
key: Key,
operand: Extract<UpdateExpressionOperands, "=">,
value: (
builder: SetUpdateExpressionFunctionQueryBuilder<DDB, Table, DDB[Table]>
) => SetUpdateExpressionFunction
): UpdateItemQueryBuilderInterface<DDB, Table, O>;
): UpdateItemQueryBuilder<DDB, Table, O>;

set<Key extends ObjectKeyPaths<PickNonKeys<DDB[Table]>>>(
key: Key,
operand: Exclude<UpdateExpressionOperands, "=">,
value: (
builder: SetUpdateExpressionFunctionQueryBuilder<DDB, Table, DDB[Table]>
) => [SetUpdateExpressionFunction, number]
): UpdateItemQueryBuilderInterface<DDB, Table, O>;
): UpdateItemQueryBuilder<DDB, Table, O>;

keys<Keys extends PickPk<DDB[Table]> & PickSkRequired<DDB[Table]>>(
pk: Keys
): UpdateItemQueryBuilderInterface<DDB, Table, O>;
): UpdateItemQueryBuilder<DDB, Table, O>;

// TODO: Make it possible to delete a whole object, and not just nested keys
remove<Key extends ObjectKeyPaths<PickNonKeys<DDB[Table]>>>(
attribute: Key
): UpdateItemQueryBuilderInterface<DDB, Table, O>;
): UpdateItemQueryBuilder<DDB, Table, O>;

add<
Key extends ObjectKeyPaths<
Expand All @@ -129,7 +129,7 @@ export interface UpdateItemQueryBuilderInterface<
>(
attribute: Key,
value: StripKeys<GetFromPath<DDB[Table], Key>>
): UpdateItemQueryBuilderInterface<DDB, Table, O>;
): UpdateItemQueryBuilder<DDB, Table, O>;

delete<
Key extends ObjectKeyPaths<
Expand All @@ -138,11 +138,11 @@ export interface UpdateItemQueryBuilderInterface<
>(
attribute: Key,
value: StripKeys<GetFromPath<DDB[Table], Key>>
): UpdateItemQueryBuilderInterface<DDB, Table, O>;
): UpdateItemQueryBuilder<DDB, Table, O>;

returnValues(
option: ReturnValuesOptions
): UpdateItemQueryBuilderInterface<DDB, Table, O>;
): UpdateItemQueryBuilder<DDB, Table, O>;

compile(): UpdateCommand;
execute(): Promise<ExecuteOutput<O>[] | undefined>;
Expand All @@ -162,7 +162,7 @@ export class UpdateItemQueryBuilder<

conditionExpression<Key extends ObjectKeyPaths<DDB[Table]>>(
...args: ExprArgs<DDB, Table, O, Key>
): UpdateItemQueryBuilderInterface<DDB, Table, O> {
): UpdateItemQueryBuilder<DDB, Table, O> {
const eB = new ExpressionBuilder<DDB, Table, O>({
node: { ...this.#props.node.conditionExpression },
});
Expand All @@ -180,7 +180,7 @@ export class UpdateItemQueryBuilder<

orConditionExpression<Key extends ObjectKeyPaths<DDB[Table]>>(
...args: ExprArgs<DDB, Table, O, Key>
): UpdateItemQueryBuilderInterface<DDB, Table, O> {
): UpdateItemQueryBuilder<DDB, Table, O> {
const eB = new ExpressionBuilder<DDB, Table, O>({
node: { ...this.#props.node.conditionExpression },
});
Expand Down Expand Up @@ -225,7 +225,7 @@ export class UpdateItemQueryBuilder<
>
) => [SetUpdateExpressionFunction, number]
]
): UpdateItemQueryBuilderInterface<DDB, Table, O> {
): UpdateItemQueryBuilder<DDB, Table, O> {
const [key, operand, right] = args;

if (typeof right === "function") {
Expand Down Expand Up @@ -312,7 +312,7 @@ export class UpdateItemQueryBuilder<

remove<Key extends ObjectKeyPaths<PickNonKeys<DDB[Table]>>>(
attribute: Key
): UpdateItemQueryBuilderInterface<DDB, Table, O> {
): UpdateItemQueryBuilder<DDB, Table, O> {
return new UpdateItemQueryBuilder<DDB, Table, O>({
...this.#props,
node: {
Expand All @@ -332,7 +332,7 @@ export class UpdateItemQueryBuilder<
add<Key extends ObjectKeyPaths<PickNonKeys<DDB[Table]>>>(
attribute: Key,
value: StripKeys<GetFromPath<DDB[Table], Key>>
): UpdateItemQueryBuilderInterface<DDB, Table, O> {
): UpdateItemQueryBuilder<DDB, Table, O> {
return new UpdateItemQueryBuilder<DDB, Table, O>({
...this.#props,
node: {
Expand All @@ -355,7 +355,7 @@ export class UpdateItemQueryBuilder<
>(
attribute: Key,
value: StripKeys<GetFromPath<DDB[Table], Key>>
): UpdateItemQueryBuilderInterface<DDB, Table, O> {
): UpdateItemQueryBuilder<DDB, Table, O> {
return new UpdateItemQueryBuilder<DDB, Table, O>({
...this.#props,
node: {
Expand All @@ -375,7 +375,7 @@ export class UpdateItemQueryBuilder<

returnValues(
option: ReturnValuesOptions
): UpdateItemQueryBuilderInterface<DDB, Table, O> {
): UpdateItemQueryBuilder<DDB, Table, O> {
return new UpdateItemQueryBuilder<DDB, Table, O>({
...this.#props,
node: {
Expand Down Expand Up @@ -412,6 +412,10 @@ export class UpdateItemQueryBuilder<
const data = await this.#props.ddbClient.send(putCommand);
return data.Attributes as any;
};

public get node() {
return this.#props.node;
}
}

preventAwait(
Expand Down
Loading

0 comments on commit 1e57bb1

Please sign in to comment.