sam-goodwin / typesafe-dynamodb

TypeSafe type definitions for the AWS DynamoDB API
Apache License 2.0
207 stars 11 forks source link

`TypeSafeQueryDocumentCommand` omits ExpressionAttributeValues #42

Closed volkanunsal closed 2 years ago

volkanunsal commented 2 years ago

When I use TypeSafeQueryDocumentCommand (QueryCmd in the picture), it wrongly omits ExpressionAttributeValues from the base type's keys.

Screen Shot 2022-06-25 at 12 01 19 PM

Type error:

Type '{ TableName: string; IndexName: string; KeyConditionExpression: string; ExpressionAttributeValues: { ':pk': string; }; }' is not assignable to type 'QueryInput<IAccount<string, string>, string | undefined, string | undefined, string | undefined, keyof IAccount<string, string> | undefined, JsonFormat.Document>'.
  Object literal may only specify known properties, and 'ExpressionAttributeValues' does not exist in type 'QueryInput<IAccount<string, string>, string | undefined, string | undefined, string | undefined, keyof IAccount<string, string> | undefined, JsonFormat.Document>'.
sam-goodwin commented 2 years ago

Interesting use-case, when I re-produce it in isolation, I don't see that error.

interface Person {
  email: string;
}

const queryperson = TypeSafeQueryDocumentCommand<Person>()

new queryperson({
  TableName: "",
  IndexName: "gsi2",
  KeyConditionExpression: `GSI2PK = :pk`,
  ExpressionAttributeValues: {
    ":pk": "email"
  }
})

So, I believe the root cause of this problem is ConstructorParameters<typeof QueryCmd>[0].

The QueryCommand type determines the ExpressionAttributeValues based on the input data, i.e. based on the value of KeyConditionExpression. Since you've explicitly typed the return as ConstructorParameters<typeof QueryCmd>[0], the type is not aware of "GSI2PK = :pk", so it doesn't enforce the correct ExpressionAttributeValues.

Workaround is to use the QueryInput type.

interface Person {
  email: string;
}

const QueryCmd = TypeSafeQueryDocumentCommand<Person>();

function mkArgs(
  email: string
): QueryInput<
  Person,
  "GSI2PK = :pk",
  undefined,
  undefined,
  undefined,
  JsonFormat.Document
> {
  return {
    TableName: "",
    IndexName: "gsi2",
    KeyConditionExpression: `GSI2PK = :pk`,
    ExpressionAttributeValues: {
      ":pk": "email",
    },
  };
}
github-actions[bot] commented 2 years ago

This issue is now marked as stale because it hasn't seen activity for a while. Add a comment or it will be closed soon. If you wish to exclude this issue from being marked as stale, add the "backlog" label.

github-actions[bot] commented 2 years ago

Closing this issue as it hasn't seen activity for a while. Please add a comment @mentioning a maintainer to reopen. If you wish to exclude this issue from being marked as stale, add the "backlog" label.