tywalch/electrodb

Op.NotExists on non PK/SK does not seem to be working with AWS SDK v3

barqco opened this issue · 1 comments

barqco commented

Describe the bug
It does not seem like a condition expression that is made up of non-primary keys is working correctly. I have produced a reproducible example that seems to fail.

ElectroDB Version
Specify the version of ElectroDB you are using
electrodb: 2.5.1_7z36tjdvug5vdf7fdy3nbvg2ji

ElectroDB Playground Link

using V3 AWS SDK

Entity/Service Definitions
Include your entity model (or a model that sufficiently recreates your issue) to help troubleshoot.

import { EntityConfiguration } from "electrodb";
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import { DynamoDBDocumentClient } from "@aws-sdk/lib-dynamodb";

export const Client = DynamoDBDocumentClient.from(new DynamoDBClient({}));

export const Configuration: EntityConfiguration = {
  // @ts-ignore
  table: "barqco-testing-table"
  client: Client,
};

export const ExpenseEntity = new Entity(
  {
    model: {
      version: "1",
      entity: "Expense",
      service: "barqco",
    },
    attributes: {
      user_id: { type: "string", required: true },
      expense_id: {
        type: "string",
        required: true,
        readOnly: true,
      },
      platform: { type: "string", required: true },
      remote_post_id: { type: "string", required: true },
      remote_user_id: { type: "string", required: true },      
      composite_global_platform_id: {
        type: "string",
        required: false,
        readOnly: true,
        set: (_, schema) => `${schema.platform}#${schema.remote_post_id}`,
      },
    },
    indexes: {
      user_expense: {
        pk: {
          field: "pk",
          composite: ["user_id"],
        },
        sk: {
          field: "sk",
          composite: ["platform", "expense_id"],
        },
      },
    },
  },
  Configuration
);

  const expense = {
    user_id: "1234567890",
    expense_id: "1234567890",
    remote_user_id: "remote_user_id",
    remote_post_id: "remote_post_id",
    platform: "github"
  };

Expected behavior
The write should be blocked, but instead is allowed to go through if you use the electrodb helper method. The params that are generated look exactly correct, but the abstraction does not seem to apply the composite_global_platform_id

Errors

If applicable, paste the errors you received

Additional context
By doing the behavior manually I get the right behavior:

This works

import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import { DynamoDBDocumentClient, PutCommand } from "@aws-sdk/lib-dynamodb";

const Client = DynamoDBDocumentClient.from(new DynamoDBClient({}));

var workingExample = {
  Item: {
    user_id: "01H1G2K1A6ZYPM6VM7MFYVSD53",
    expense_id: "01H1G44RKGGRW41EN8PV5NTNNH2",
    platform: "instagram",
    remote_post_id: "3108193903459295189",
    remote_user_id: "57144742272",
    composite_global_platform_id: "instagram#3108193903459295189",
    pk: "$barqco#user_id_01h1g2k1a6zypm6vm7mfyvsd53",
    sk: "$expense_1#platform_instagram#expense_id_01h1g44rkggrw41en8pv5ntnnh",
    __edb_e__: "Expense",
    __edb_v__: "1",
  },
  TableName: "testing-table",
  ConditionExpression: "attribute_not_exists(#composite_global_platform_id)",
  ExpressionAttributeNames: {
    "#composite_global_platform_id": "composite_global_platform_id",
  },
};

const command = new PutCommand(x);

try {
  const response = await Client.send(command);
  console.log(response);
} catch (error) {
  let error2 = error as any;
  console.log(error2);
  console.log(error2.code);
  console.log(Object.keys(error2));
  error2.code == "ConditionalCheckFailedException"
    ? console.log("yayyyyyyy")
    : console.log("no");
}

Add any other context about the problem here.
I've tried the following with no success

  console.log(ExpenseEntity.client, "ExpenseEntity.client");
  const res = await ExpenseEntity.client
    .send(new PutCommand(electroCall.params()))
    .catch((e: any) => {
      console.log(e);
      console.log(e.code, "e.code");
      console.log(`TRYING TO Prevented from creating duplicate expenses`);
      if (e.code == 4001) {
        console.log(`Prevented from creating duplicate expenses`);
        return { data: "success" };
      }
      return { data: e };
    });
  console.log("res", res);

Thank you so much for any help you can be!

Hi @barqco 👋

I am not able to recreate this error. I can say that in your playground example, it only calls go() on the put statement once, maybe that is the case in your local tests as well?