HeadspaceMeditation / beyonce

Type-safe DynamoDB query builder for TypeScript. Designed with single-table architecture in mind.
Apache License 2.0
6 stars 5 forks source link

beyonce.batchWriteWithTransaction with Updates #64

Open e-nouri opened 3 years ago

e-nouri commented 3 years ago

Is there a way to do batch write with updates, puts and deletes ? I think I red on the doc that conditional updates are not yet possible to ?!

Right now I am using the dynamodb client to make something like this work :

client.transactWrite({
    TransactItems : [
        {
            "Put": {
                "TableName": `${process.env.DATA_TABLE}`,
                "Item": {
                    "pk": {"S": `${BeginsWith.User}-${userId}`},
                    "sk": {"S": `${BeginsWith.Friend}-${firendId}`},
                    "followedUser": {"S": userId},
                    "followingUser": {"S": firendId},
                    "timestamp": {"S": +new Date},
                },
                "ConditionExpression": "attribute_not_exists(sk)",
                "ReturnValuesOnConditionCheckFailure": "ALL_OLD",
            }
        },
        {
            "Update": {
                "TableName": `${process.env.DATA_TABLE}`,
                "Key": {"pk": {"S": `${BeginsWith.User}-${firendId}`}, "sk": {"S": `${BeginsWith.User}-${firendId}`}},
                "UpdateExpression": "SET followers = followers + :i",
                "ExpressionAttributeValues": {":i": {"N": "1"}},
                "ReturnValuesOnConditionCheckFailure": "ALL_OLD",
            }
        },
        {
            "Update": {
                "TableName": `${process.env.DATA_TABLE}`,
                "Key": {"pk": {"S": `${BeginsWith.User}-${userId}`}, "sk": {"S": `${BeginsWith.User}-${userId}`}},
                "UpdateExpression": "SET following = following + :i",
                "ExpressionAttributeValues": {":i": {"N": "1"}},
                "ReturnValuesOnConditionCheckFailure": "ALL_OLD",
            }
        },
    ]
})

Thank you so much again for this library, Beyonce rocks !

e-nouri commented 3 years ago

Related to the same update use case, partial updates like this does not work, because the lens does not have access to the actual value. Can the generated expression detect that and add a update expression with + :1 ?

                let user = await db.update(UserModel.key({ id: userId }), (user)=>{
                    user.followeesNbr =+1
                })
jcarver989 commented 3 years ago

Hey,

Is there a way to do batch write with updates, puts and deletes ?

Not currently, no. Right now we support puts + deletes via batchWrite, but not (yet) updates.

Related to the same update use case, partial updates like this does not work, because the lens does not have access to the actual value. Can the generated expression detect that and add a update expression with + :1 ?

This isn't currently supported, but should be possible. Dynamo supports an ADD operation in update expressions. So it'd be a matter of teaching the proxy object we use for updates how to generate ADD statements.

Of the top of my head, I'm not sure if JS proxies can differentiate between foo.a = 1 and foo.a += 1, so it might have to look something more like foo.a.add(1).

Re: batch updates, it'd be nice to preserve the same syntax as the singular update method, so maybe something like this:

await beyonce.batchWrite({ 
  putItems: [ ... ],
  deleteItems: [ ... ],
  updateItems: [
    [AuthorModel.key({ id: "1" }), (author) => {   author.bookCount.add(1) }]
  ]
})

I'm out of office for the next month, so will be slow to respond, but either of these we'd be happy to accept a PR for. Otherwise, I can probably get to this when I'm back.