Closed jcjp closed 1 year ago
This isn't something that Dyngoose has implemented. It seems like a great thing to support, but it's never come up before. I'll look into adding explicit support for mixed attribute types in a future release.
For now, the best option I can recommend is to utilize the manipulateRead
utility. It lets you hijack the parsing, primarily designed to help with migrations in case you convert from one attribute type to another (such as, you used to store a value as a number and now it is a string).
@Dyngoose.Attribute.Number({
manipulateRead: (value, attributeValue, attr) => {
// attributeValue can be null if the attribute is not set
return attributeValue?.S != null ? attributeValue.S : value
},
})
age: string | number
As for your other question, Dyngoose can not infer your attribute type and you must use a decorator or the property will not be considered a database attribute and will remain as a class property only (which will not be saved). Dyngoose can support some dynamically created attributes, but you must use the utility methods for getting and setting attributes rather than a class property in that case.
This isn't something that Dyngoose has implemented. It seems like a great thing to support, but it's never come up before. I'll look into adding explicit support for mixed attribute types in a future release.
For now, the best option I can recommend is to utilize the
manipulateRead
utility. It lets you hijack the parsing, primarily designed to help with migrations in case you convert from one attribute type to another (such as, you used to store a value as a number and now it is a string).@Dyngoose.Attribute.Number({ manipulateRead: (value, attributeValue, attr) => { // attributeValue can be null if the attribute is not set return attributeValue?.S != null ? attributeValue.S : value }, }) age: string | number
As for your other question, Dyngoose can not infer your attribute type and you must use a decorator or the property will not be considered a database attribute and will remain as a class property only (which will not be saved). Dyngoose can support some dynamically created attributes, but you must use the utility methods for getting and setting attributes rather than a class property in that case.
Thanks this is very helpful! I will use your suggestion for now. I get a type error trying your suggestion:
Type '(value: number | BigInt | null, attributeValue: AttributeValue | null) => string | number | BigInt | null | undefined' is not assignable to type '(value: number | BigInt | null, attributeValue: AttributeValue | null, attribute: Attribute<any>) => number | BigInt | null'.
Type 'string | number | BigInt | null | undefined' is not assignable to type 'number | BigInt | null'.
Type 'undefined' is not assignable to type 'number | BigInt | null'.ts(2322)
Your example code is when reading but how about writting on the database, do the same concept apply for manipulateWrite
my assumption that since the attribute is Number
when a string is passed it will become null
in value?
@Dyngoose.Attribute.Number({
manipulateWrite: (value, attributeValue, attr) => {
if (!value) return attributeValue.S
return value;
},
})
Yes, you can also use manipulateWrite
to change how an attribute will be written. It is called after the default behavior, allowing you to override and save a value as a different attribute type if you desired.
A complete example may be:
@Dyngoose.Attribute.Number({
manipulateRead: (value, attributeValue, attr) => {
// attributeValue can be null if the attribute is not set
return attributeValue?.S != null ? attributeValue.S : value
},
manipulateWrite: (attributeValue, value, attr) => { // yes, apparently the order of arguments is different
return typeof value === 'string' ? { S: value } : attributeValue;
},
})
You are correct that the attributeValue
would become null
when you a pass a string to the number handler. It may attempt to covert it to a number for you, but if that values, it'd become null. You'll need to create the attribute for DynamoDB. So the above should work out for what you are attempting.
I've addressed this with the new Dynamic
attribute, you can now use:
@Dyngoose.Attribute()
age: string | number
This has a few limitations, see the docs, but this should resolve this request.
I've addressed this with the new
Dynamic
attribute, you can now use:@Dyngoose.Attribute() age: string | number
This has a few limitations, see the docs, but this should resolve this request.
Thank you! Will check the docs.
Multiple attribute type is it possible with DynamoDB or using this library? For example:
Attribute
Any
will convert this to a string, is there a way to add multiple attributes to safely save / persist the correct value and it's type?I have read somewhere that when we don't pass an attribute to a field / property it will be automatically dynamic except the primary and sort keys. Is this do-able with Dyngoose, I tried removing the decorator attribute what happen was the field was skipped and was not saved to the database.