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

Update issue with default

Open mfbx9da4 opened this issue 5 years ago • 10 comments

If you have an entity defined with a field which defaults to some value whenever you call update the default overwrites whatever value was there. This was surprising to me. I would have expected the default value only to write if there was no previous value

e.g.

const Group = new Entity({
  name: 'Group',

  attributes: {
    pk: {
      type: 'string',
      partitionKey: true,
      required: true,
    },
   foo: { type: string },
    enabled: {
      type: 'boolean',
      default: false,
    }
  },

  table: MainTable,
})
const pk = 'asdf'
await Group.put({ pk, enabled: true }) // enabled is true
await Group.update({pk, foo: 'asdf'}) // enabled is now false

side bug is that you can't have a required boolean field set to false

mfbx9da4 avatar Nov 19 '20 18:11 mfbx9da4

Hmm, let me look into this.

jeremydaly avatar Nov 19 '20 19:11 jeremydaly

The library is generating the following parameters:

{
  TableName: 'test-table',
  Key: { pk: 'asdf' },
  UpdateExpression: 'SET #enabled = if_not_exists(#enabled,:enabled), #_ct = if_not_exists(#_ct,:_ct), #_md = :_md, #_et = if_not_exists(#_et,:_et), #foo = :foo',
  ExpressionAttributeNames: {
    '#enabled': 'enabled',
    '#_ct': '_ct',
    '#_md': '_md',
    '#_et': '_et',
    '#foo': 'foo'
  },
  ExpressionAttributeValues: {
    ':enabled': false,
    ':_ct': '2020-11-19T21:19:12.952Z',
    ':_md': '2020-11-19T21:19:12.952Z',
    ':_et': 'Group',
    ':foo': 'asdf'
  }
}

This should be working correctly, but I'll try it out on a live table.

jeremydaly avatar Nov 19 '20 21:11 jeremydaly

Can you use updateParams or add the execute: false flag to your update and post that here? I'm getting the correct parameters for both v0.2 and v0.3.

jeremydaly avatar Nov 20 '20 00:11 jeremydaly

await Group.put({ pk, enabled: true }) 
{
  TableName: 'Group',
  Key: {
    pk: 'asdf',
  },
  UpdateExpression: 'SET #createdAt = if_not_exists(#createdAt,:createdAt), #updatedAt = if_not_exists(#updatedAt,:updatedAt), #enabled = :enabled',
  ExpressionAttributeNames: {
    '#createdAt': 'createdAt',
    '#updatedAt': 'updatedAt',
    '#enabled': 'enabled'
  },
  ExpressionAttributeValues: {
    ':createdAt': 1605888916731,
    ':updatedAt': 1605888916731,
    ':enabled': true
  }
}
await Group.update({pk, foo: 'asdf'})
{
  TableName: 'Group',
  Key: {
    pk: 'asdf',
  },
  UpdateExpression: 'SET #createdAt = if_not_exists(#createdAt,:createdAt), #updatedAt = if_not_exists(#updatedAt,:updatedAt), #enabled = :enabled, #foo = :foo',
  ExpressionAttributeNames: {
    '#createdAt': 'createdAt',
    '#updatedAt': 'updatedAt',
    '#enabled': 'enabled',
    '#foo': 'foo'
  },
  ExpressionAttributeValues: {
    ':createdAt': 1605888916733,
    ':updatedAt': 1605888916733,
    ':enabled': false,
    ':foo': 'asdf'
  }
}

mfbx9da4 avatar Nov 20 '20 16:11 mfbx9da4

Interestingly using enabled: () => false works instead of enabled: false

using the former:

{
  TableName: 'Group',
  Key: {
    key: 'asdf',
  },
  UpdateExpression: 'SET #createdAt = if_not_exists(#createdAt,:createdAt), #updatedAt = if_not_exists(#updatedAt,:updatedAt), #enabled = if_not_exists(#enabled,:enabled), #foo = :foo',
  ExpressionAttributeNames: {
    '#createdAt': 'createdAt',
    '#updatedAt': 'updatedAt',
    '#enabled': 'enabled',
    '#foo': 'foo'
  },
  ExpressionAttributeValues: {
    ':createdAt': 1605889046135,
    ':updatedAt': 1605889046135,
    ':enabled': false,
    ':foo': 'asdf'
  }
}

note the if_not_exists is missing

mfbx9da4 avatar Nov 20 '20 16:11 mfbx9da4

Thanks for this. I'll take another look.

jeremydaly avatar Nov 20 '20 16:11 jeremydaly

Using version 0.2.0-beta.1 FYI 💁‍♂️

mfbx9da4 avatar Nov 20 '20 21:11 mfbx9da4

What is the default behaviour or default?

Should it only populate on first go? Or should default be calculated each time?

darbio avatar Dec 30 '20 08:12 darbio

I still can't duplicate this. Unless onUpdate is set to true, then any default value generates the "if_not_exists" in the UpdateExpression like this: #enabled = if_not_exists(#enabled,:enabled).

Can anyone else replicate this behavior?

jeremydaly avatar Dec 30 '20 20:12 jeremydaly

Can anyone else replicate this behavior?

I can't.

I have done negative testing using 0.3.1 (updating an entity where onUpdate is false) and this is working as intended for me (I.e. the default is not recalculated).

I think this can be closed.

darbio avatar Dec 30 '20 21:12 darbio

Hey @mfbx9da4, thanks for opening this issue, I've also tried to re-create this without success.

I'll be closing this issue, feel free to ping me or open a new issue if this issue still persists for you.

naorpeled avatar Nov 05 '22 15:11 naorpeled