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

Simplest implementation of unique constraint for non-key attributes #385

Closed
jckdn opened this issue May 20, 2024 · 2 comments
Closed

Simplest implementation of unique constraint for non-key attributes #385

jckdn opened this issue May 20, 2024 · 2 comments

Comments

@jckdn
Copy link

jckdn commented May 20, 2024

I see a suggested pattern in the docs to implement a unique constraint for non-key attributes: https://electrodb.dev/en/mutations/transact-write/

I'm wondering if there is a simpler way to implement this. The example includes a PK, SK, and a GSI also with its own PK and SK. The index is called gsi1pk-gsi2sk-index (btw I think this is a typo and should actually be gsi1pk-gsi1sk-index). This entity design is similar to other examples in the docs. But I'm wondering if this example is as complex just for consistency or if it can be simplified, i.e, the SK and GSI might not be required?

An AWS blog describes how to implement unique constraints like so: https://aws.amazon.com/blogs/database/simulating-amazon-dynamodb-unique-constraints-using-transactions/

My table will only have one entity, with a PK, and a few attributes one of which I need to also be unique, and so doesn't really require single table design aside from what's needed to implement the unique constraint. I'd like to know if it's possible to simplify the electrodb pattern at all, perhaps in a way similar to the pattern in the AWS blog.

Reminder of what the electrodb "constraint" entity example looks like:

// entity that owns unique constraints
const constraint = new Entity(
  {
    model: {
      entity: "constraint",
      version: "1",
      service: "MI6",
    },
    attributes: {
      name: {
        type: "string",
        required: true,
      },
      value: {
        type: "string",
        required: true,
      },
      entity: {
        type: "string",
        required: true,
      },
    },
    indexes: {
      value: {
        pk: {
          field: "pk",
          composite: ["value"],
        },
        sk: {
          field: "sk",
          composite: ["name", "entity"],
        },
      },
      name: {
        index: "gsi1pk-gsi2sk-index",
        pk: {
          field: "gsi1pk",
          composite: ["name", "entity"],
        },
        sk: {
          field: "gsi1sk",
          composite: ["value"],
        },
      },
    },
  },
  { table, client },
);
@tywalch
Copy link
Owner

tywalch commented Jul 20, 2024

Hi @jckdn 👋

Great topic! Yes I think things can be greatly simplified here! The example you pasted is ultimately just a learning tool; it has more "features" than you might actually need, like the ability to query values by name and the additional fields to generically namespace the value.

Here's an example that's about as stripped down as you can get -- note it assumes your table only as a pk like you mentioned:

// entity that owns unique constraints
const constraint = new Entity(
  {
    model: {
      entity: "constraint",
      version: "1",
      service: "global",
    },
    attributes: {
      value: {
        type: "string",
        required: true,
      },
    },
    indexes: {
      unique: {
        pk: {
          field: "pk",
          composite: ["value"],
        },
      },
    },
  },
  { table },
);

constraint.create({value: 'your_name@your_email.com'}).go();

Any time you'd want to use it you'd use the create() method to ensure it fails if the value already exists. Let me know if this helps or you have any other questions!

@jckdn
Copy link
Author

jckdn commented Jul 29, 2024

Thanks @tywalch, that worked as expected!

@jckdn jckdn closed this as completed Jul 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants