shiftcode / dynamo-easy

DynamoDB client for NodeJS and browser with a fluent api to build requests. We take care of the type mapping between JS and DynamoDB, customizable trough typescript decorators.
https://shiftcode.github.io/dynamo-easy/
MIT License
206 stars 27 forks source link

'Cannot convert undefined or null to object' when updating attribute to null or empty array #276

Closed chrisbrantley closed 4 years ago

chrisbrantley commented 4 years ago

Describe the bug I'm trying to update some attributes to null or [] (empty array) and I'm getting the following error:

TypeError: Cannot convert undefined or null to object
    at Function.getOwnPropertyNames (<anonymous>)
    at Object.toDb (@shiftcoders/dynamo-easy/src/mapper/mapper.ts:56:48)
    at Object.objectToDb [as toDb] (@shiftcoders/dynamo-easy/src/mapper/for-type/object.mapper.ts:23:13)
    at Object.toDbOne (@shiftcoders/dynamo-easy/src/mapper/mapper.ts:140:14)
    at buildDefaultExpression (@shiftcoders/dynamo-easy/src/dynamo/expression/update-expression-builder.ts:112:19)
    at buildUpdateExpression (@shiftcoders/dynamo-easy/src/dynamo/expression/update-expression-builder.ts:62:10)
    at wrapper (lodash/lodash.js:5193:19)
    at @shiftcoders/dynamo-easy/src/dynamo/expression/prepare-and-add-update-expressions.function.ts:24:16
    at Array.map (<anonymous>)
    at Object.prepareAndAddUpdateExpressions (@shiftcoders/dynamo-easy/src/dynamo/expression/prepare-and-add-update-expressions.function.ts:23:8)

To Reproduce

@Model({ tableName: "my-table" })
class TestModel {
  @PartitionKey()
  pk: string;

  @SortKey()
  sk: string;

  myAttribute: string | null;
}

const store = new DynamoStore(TestModel);

await store
      .update("my-primary-key", "my-sort-key")
      .updateAttribute("myAttribute")
      .set(null);

Expected behavior Since both Null and empty arrays are valid DynamoDB values I would expect the operation to succeed.

Additional context This error only happens with update operations. I can call store.put() with the same values and it works correctly.

I am using Typescript.

simonmumenthaler commented 4 years ago

Hi @chrisbrantley Thanks for opening the issue and to provide the code to reproduce it.

This fail happens due to the inability of dynamo-easy to handle null values -> it filters out all null/undefined/empty values.

We will address this in the near future and bring null-value support to dynamo-easy; see #285 stay tuned!

fredspivock commented 4 years ago

I need to update an array with an empty array and get the same error. Setting something to an empty array seems like a valid usecase.

hookercookerman commented 4 years ago

I am facing the same issue as @fredspivock often you want to have lists of objects that can be added and removed, via updating, and a very common scenario is setting that list back to being empty. Removing is not really an option as you want that empty array so you can append objects.

so just to explain further this call does not work and results in Cannot convert undefined or null to object which comes from object mapper toDb call.

example would be in terms of update operations

    const operation = update2(Breakfast, 'eggs').set([]);
    // this currently does not work it kind of should

happy to do make this change if you can point me to a good starting point.

Problem

its here that an empty array will would filtered via the deepfiler call which would always return [] for any empty array instead of [[]]

https://github.com/shiftcode/dynamo-easy/blob/master/src/dynamo/expression/update-expression-builder.ts#L40

without knowing the full details of deepfilter and why it rejects empty array I cannot really deep dive into a fix here. I can make one but it will be hack