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

feat: add deleteitem function to write interface #16

Merged
merged 11 commits into from
Sep 10, 2024
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ table, err := dynago.NewClient(ctx, dynago.ClientOptions{
### Run dynago.locally

```sh
docker run -p docker run -p 8000:8000 amazon/dynago.local
docker run -p 8000:8000 amazon/dynamodb-local
```

```go
Expand Down
12 changes: 6 additions & 6 deletions delete_item.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,20 @@ import (
* @param sk the sort key of the record
* @return true if the record was deleted, false otherwise
*/
func (t *Client) DeleteItem(ctx context.Context, pk string, sk string) error {
func (t *Client) DeleteItem(ctx context.Context, pk Attribute, sk Attribute) error {

//delete item from dynamodb
vankongv marked this conversation as resolved.
Show resolved Hide resolved
input := &dynamodb.DeleteItemInput{
TableName: &t.TableName,
Key: map[string]types.AttributeValue{
"pk": &types.AttributeValueMemberS{Value: pk},
"sk": &types.AttributeValueMemberS{Value: sk},
"pk": pk,
"sk": sk,
},
}
resp, err := t.client.DeleteItem(ctx, input)
_, err := t.client.DeleteItem(ctx, input)

vankongv marked this conversation as resolved.
Show resolved Hide resolved
if err != nil && resp == nil {
log.Println("failed to delete record into database. Error:" + err.Error())
if err != nil {
log.Println("failed to delete record from database. Error:" + err.Error())
return err
}

Expand Down
1 change: 1 addition & 0 deletions interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ type WriteAPI interface {
// Create or update given item in DynamoDB. Must implemenmt DynamoRecord interface.
// DynamoRecord.GetKeys will be called to get values for parition and sort keys.
PutItem(ctx context.Context, pk Attribute, sk Attribute, item interface{}) error
DeleteItem(ctx context.Context, pk Attribute, sk Attribute) error
}

type TransactionAPI interface {
Expand Down
179 changes: 179 additions & 0 deletions tests/delete_item_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
package tests
vankongv marked this conversation as resolved.
Show resolved Hide resolved

import (
"context"
"fmt"
"slices"
"testing"

"github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
"github.com/oolio-group/dynago"
)

type user struct {
Name string
Phone string
}

type userKeys struct {
Pk string
Sk string
}

type testCase struct {
title string
itemsToDelete []userKeys
itemsLeft int
seedData []tableRecord
}

func TestDeleteItem(t *testing.T) {
ctx := context.TODO()
table := prepareTable(t, dynamoEndpoint, "delete_test")

records := []tableRecord{
{
Pk: "users#org1",
Sk: "user#1",
Record: user{
Name: "User 1",
Phone: "xyz",
},
},
{
Pk: "users#org1",
Sk: "user#2",
Record: user{
Name: "User 2",
Phone: "asd",
},
},
{
Pk: "users#org1",
Sk: "user#3",
Record: user{
Name: "User 3",
Phone: "qwe",
},
},
{
Pk: "users#org2",
Sk: "user#4",
Record: user{
Name: "User 4",
Phone: "fgh",
},
},
}

cases := []testCase{
{
title: "Delete User 2",
itemsToDelete: []userKeys{
{
Pk: "users#org1",
Sk: "user#2",
},
},
itemsLeft: 3,
seedData: records, //each test case will have the same seed data
},
{
title: "Delete all users",
itemsToDelete: []userKeys{
{
Pk: "users#org1",
Sk: "user#1",
},
{
Pk: "users#org1",
Sk: "user#2",
},
{
Pk: "users#org1",
Sk: "user#3",
},
{
Pk: "users#org2",
Sk: "user#4",
},
},
itemsLeft: 0,
seedData: records,
},
{
title: "Delete wrong user",
itemsToDelete: []userKeys{
{
Pk: "users#org1",
Sk: "user#none",
},
},
itemsLeft: 4,
seedData: records,
},
{
title: "Delete user with invalid keys",
itemsToDelete: []userKeys{
{
Pk: "invalid#org",
Sk: "invalid#user",
},
},
itemsLeft: 4,
seedData: records,
},
}

for _, c := range cases {
t.Run(c.title, func(t *testing.T) {
//prepare records
err := seedRecords(ctx, table, c.seedData)
if err != nil {
t.Fatalf("failed to prepare records; got %s", err)
}

//delete records
for _, item := range c.itemsToDelete {
err = table.DeleteItem(ctx, dynago.StringValue(item.Pk), dynago.StringValue(item.Sk))
if err != nil {
t.Fatalf("unable to delete records; got %s", err)
}
}

//get original seed records
itemsToGet := make([]map[string]types.AttributeValue, 0, len(c.seedData))
for _, v := range c.seedData {
itemsToGet = append(itemsToGet, map[string]types.AttributeValue{
"pk": dynago.StringValue(v.Pk),
"sk": dynago.StringValue(v.Sk),
})
}

var out []tableRecord

err = table.BatchGetItems(ctx, itemsToGet, &out)
if err != nil {
t.Fatalf("Unable to get seed data: %s", err)
}

//check if deleted items are not in db
dataKeys := make([]string, 0, len(out))
for _, item := range out {
dataKeys = append(dataKeys, fmt.Sprintf("%s--%s", item.Pk, item.Sk))
}

for _, v := range c.itemsToDelete {
recKey := fmt.Sprintf("%s--%s", v.Pk, v.Sk)
if slices.Contains(dataKeys, recKey) {
t.Fatalf("expected items to deleted in db but found it, pk %s; sk %s", v.Pk, v.Sk)
}
}

//check if remaining records match expected number of items left
if len(out) != c.itemsLeft {
t.Fatalf("expected items in db; %v found; %v", c.itemsLeft, len(out))
}
})
}
}
35 changes: 35 additions & 0 deletions tests/seed_table_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package tests

import (
"context"
"fmt"

"github.com/oolio-group/dynago"
)

type tableRecord struct {
Pk string `dynamodbav:"pk"`
Sk string `dynamodbav:"sk"`
Record interface{}
}

func seedRecords(ctx context.Context, table *dynago.Client, input []tableRecord) error {
//insert items
items := make([]*dynago.TransactPutItemsInput, 0, len(input))
for _, item := range input {
in := dynago.TransactPutItemsInput{
PartitionKeyValue: dynago.StringValue(item.Pk),
SortKeyValue: dynago.StringValue(item.Sk),
Item: item,
}

items = append(items, &in)
}

err := table.TransactPutItems(ctx, items)
if err != nil {
return fmt.Errorf("failed to insert items; got %s", err)
}

return nil
}
3 changes: 2 additions & 1 deletion tests/transact_items_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func TestTransactItems(t *testing.T) {
items := make([]*dynago.TransactPutItemsInput, 0, len(tc.newItems))
for _, item := range tc.newItems {
items = append(items, &dynago.TransactPutItemsInput{
dynago.StringValue(item.Pk), dynago.StringValue(item.Sk), item,
PartitionKeyValue: dynago.StringValue(item.Pk), SortKeyValue: dynago.StringValue(item.Sk), Item: item,
})
}
err := table.TransactPutItems(ctx, items)
Expand All @@ -98,6 +98,7 @@ func TestTransactItems(t *testing.T) {
}
}
//perform operations

if len(tc.operations) > 0 {
err := table.TransactItems(ctx, tc.operations...)
if err != nil {
Expand Down
Loading