New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Multiple attrs update #194
Multiple attrs update #194
Conversation
2 similar comments
3 similar comments
i think i'd prefer to move multiple update functionality to a method called thoughts? |
Ok, the code will be a wee bit simpler without the backward compatibility + I'll also try to implement a fix for #195 there. |
6da2455
to
cc4b9ea
Compare
let me know if you have any suggestions about the code. Otherwise I'll just add docs & it's good to go. |
@@ -323,6 +323,8 @@ def update_item(self, attribute, value=None, action=None, conditional_operator=N | |||
:param action: The action to take if this item already exists. | |||
See: http://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateItem.html#DDB-UpdateItem-request-AttributeUpdate | |||
""" | |||
DeprecationWarning("`Model.update_item` is deprecated in favour of `Model.update` now") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does this do anything?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah! fixed.
@@ -162,7 +166,7 @@ | |||
# These are the valid select values for the Scan operation | |||
# See: http://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Scan.html#DDB-Scan-request-Select | |||
NOT_NULL = 'NOT_NULL' | |||
NULL = 'NULL' | |||
#NULL = 'NULL' # declared as a type above |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we just delete this maybe?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can. The reason I've done it this way was if someone would be thinking 'so here NOT_NULL
, but where's NULL
?'
Fixed in the last commit.
|
||
:param value: a value to serialize | ||
""" | ||
serialized = attr.serialize(value) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the passed value is already serialized on 1210 right?
we should either remove that or skip this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will require a few more changes (which I wanted to avoid), but I can give it a try.
if serialized is None: | ||
if not attr.null: | ||
raise ValueError("Attribute '{0}': cannot be None".format(attr.attr_name)) | ||
return {NULL: True} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we just set serialized = True
and let the ATTR_TYPE_MAP
on line 1286 handle the null bit? seems nicer maybe? don't really know tbh
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, this is a fix for #195
kwargs['expected'] = self._build_expected_values(expected_values, UPDATE_FILTER_OPERATOR_MAP) | ||
|
||
for attr, params in attributes.items(): | ||
attribute_cls = self._get_attributes()[attr] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
might move the self._get_attributes()
call outside the loop?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sure
|
||
for attr, params in attributes.items(): | ||
attribute_cls = self._get_attributes()[attr] | ||
action = params['action'] and params['action'].upper() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
won't this return a bool
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no, either False
(in case params['action']
is evaluated to False
) or the value of the second statement)
>>> a = {'none': False, 'one': 'yes'}
>>> a['none'] and a['none'].upper()
False
>>> a['one'] and a['one'].upper()
'YES'
attribute_cls = self._get_attributes()[attr] | ||
action = params['action'] and params['action'].upper() | ||
attr_values = {ACTION: action} | ||
if action != DELETE: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we add a test for DELETE
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
@@ -357,6 +361,52 @@ def update_item(self, attribute, value=None, action=None, conditional_operator=N | |||
setattr(self, name, attr.deserialize(value.get(ATTR_TYPE_MAP[attr.attr_type]))) | |||
return data | |||
|
|||
|
|||
def update(self, attributes, conditional_operator=None, **expected_values): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would it be better to take kwargs that map from the model_field_name to the new value? i see we've already got **expected_values
filling that role though... maybe we could make that a keyword argument
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would be good to do now since this is new...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jmphilli you might need to pass action
for the attributes too. That would mean a bunch of small dictionaries like attribute_name={'value': 1, 'action': 'add'}
.
else: | ||
if attr.is_hash_key: | ||
attrs[HASH] = serialized | ||
attrs[HASH] = list(serialized.values())[0] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I replaced serialized = attr.serialize(value)
above with _serialize_value()
in order to avoid a double call of attr.serialize()
you did not like (I could not remove it inside of serialize_value()
since it's used elsewhere too)
Since _serialize_value()
returns value in the DynamoDB serialization format (ie. {TYPE: VALUE}
), I need to extract the value here.
List conversion is done because Python 3 does not support indexing of the type returned by values()
daniel is out for a week. i'll look at this again today, but i can only give my seal of approval which doesn't really do much for you unfortunately lol. |
np, I appreciate your feedback. |
serialized = attr.serialize(value) | ||
if serialized is None: | ||
|
||
serialized = Model._serialize_value(attr, value, null_check) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
self._serialize_value
action = params['action'] and params['action'].upper() | ||
attr_values = {ACTION: action} | ||
if action != DELETE: | ||
attr_values[VALUE] = Model._serialize_value(attribute_cls, params['value']) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
self._serialize_value
this allows to update multiple attributes at once using a new function
Model.update
(code based on the existing methodModel.update_item()
This fixes #157 and #195