dynamodb-toolbox icon indicating copy to clipboard operation
dynamodb-toolbox copied to clipboard

`new Entity()` mutates supplied attributes

Open mxro opened this issue 1 year ago • 0 comments

When defining the attributes for an entity in a constant such as:

export const TagPK = (data: { blog: string; postId: string }): string =>
  `${data.blog}#${data.postId}`;

export const TagEntity = {
  name: 'Tag',
  attributes: {
    pk: {
      partitionKey: true,
      hidden: true,
      default: TagPK,
    },
    tagId: { sortKey: true },
    blog: { type: 'string' },
    postId: { type: 'string' },
    title: { type: 'string' },
  },
} as const;

It is not safe to use the TagEntity constant more than one time when calling new Entity() such as:

const Tags = new Entity({
  ...TagEntity,
  table,
} as const);

...

const Tags = new Entity({
  ...TagEntity,
  table,
} as const);

Upon calling the constructor the second time, the following error is emitted:

 Attributes with a sortKey cannot have a 'map' or 'alias' associated

There is no sortKey attribute in the supplied attributes; however it appears the library mutates the data in the supplied attributes which results in this error.

Workaround

The easiest workaround is to supply the attributes definition directly when calling new Entity():

const Tags = new Entity({
  name: 'Tag',
  attributes: {
    pk: {
      partitionKey: true,
      hidden: true,
      default: TagPK,
    },
    tagId: { sortKey: true },
    blog: { type: 'string' },
    postId: { type: 'string' },
    title: { type: 'string' },
  },
  table,
} as const);

It will also work when adding a making a deep clone before passing in the attributes to the constructor.

Background

I am interested in building a template for a package that can provide DynamoDB capabilities in a JavaScript project with multiple workspaces. As part of that, I would like to define the entities in a centralised place so that consumers of the package can instantiate entities as required.

It seems to be very finicky to pass the correct calculated types to the consumer (also see https://github.com/jeremydaly/dynamodb-toolbox/issues/303). The best way I found so far is to define the attributes as a constant and use that in different places to instantiate the entities which led me to this issue.

mxro avatar Aug 21 '22 01:08 mxro