set() not called when changing watched nested attributes in maps
Describe the bug
You can watch attributes so set() is executed whenever that attribute changes. However, this doesn't seem to work when changing a property inside a map.
ElectroDB Version
3.0.1
ElectroDB Playground Link ElectroDB Playground
Entity/Service Definitions
{
model: {
entity: 'task',
version: '1',
service: 'myService'
},
attributes: {
id: {
type: 'string',
default: () => crypto.randomUUID()
},
organizationId: {
type: 'string',
},
nestedMap: {
type: 'map',
properties: {
myString: {
type: 'string',
required: true
},
myNumber: {
type: 'number',
default: 42
}
},
required: true
},
myStringFromNested: {
watch: ['nestedMap'],
type: 'string',
readOnly: true,
set: (_, item) => item.nestedMap.myString
}
},
indexes: {
task: {
pk: {
field: 'pk',
composite: ['organizationId'],
},
sk: {
field: 'sk',
composite: ['id'],
},
}
}
}
In this example myStringFromNested should always mirror the value from nestedMap.myString.
Behavior When I change the value of the string inside the map like this:
await tasks.patch({
organizationId,
id: newTask.data.id,
})
.data((attributes, operations) => {
operations.set(attributes.nestedMap.myString, 'New');
})
.go();
then the value in nestedMap.myString gets changed as it should, but myStringFromNested is still the old value.
Hi @xxluke 👋
Thanks for creating an issue! Unfortunately, for your use case, watch is working as intended. The watch mechanism is very simplistic, and is only set up to react to changes to direct sibling attributes. The last time I looked at this, I found that things can get pretty hairy with nested attributes and they can make for an unintuitive DX. I wish I could remember all my findings, but get + set + watch apis are not the right abstraction to own more complex item transformations. Ultimately, this is why the watch api is kept simple.
If you have ideas on any alternative APIs that accomplish your same use case, or mechanisms you've found work well in other tools, I'm all ears.
Thank you for your answer! I agree that it's not the most intuitive way in terms of DX when you have to use watch+set+readOnly, when all you want to do is copy a value from somewhere. However, I'd still be happy to see it work as long as there is no other way besides writing the values manually in both places 😃
I'm currently testing different TypeScript DynamoDB libraries. DynamoDB-Toolbox uses link, which is a nice idea in concept but in the current implementation also more complicated than I wish it was. It works though.