Skip to content
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

Optional Auto-Generation of VersionAttribute Conditions #718

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

Flips01
Copy link

@Flips01 Flips01 commented Nov 3, 2019

Once a model contains version attribute pynamodb automatically creates a condition constraint for all operations related to the model (e.g. update() or delete()). This default behavior requires a read operation before a write operation can take place because you need to know the current version.

I've run into a situation were such a read is technically not required as demonstrated by the following pseudo-code:

UserProfile(Model):
  user_id = UnicodeAttribute(hash_key=True)
  own_groups = ListAttribute()
  [..]
  version = VersionAttribute()

Group(Model):
  group_id = UnicodeAttribute(hash_key=True)
  [..]

If I want to create a new group for a given user I am performing a TransactWrite that contains of an update to the UserProfile-Table and a save to the Group-Table. Given the current implementation I would be forced to first perform a read of the UserProfile to obtain the current version and then include this value into the transaction. There is no benefit in doing this for the given example.

Therefore I am proposing to include a new Model.Meta- and Settings-Property that controls whether there should be a automatically generated version-condition.

…automatic condition to validate the version of a model instance.
@Flips01 Flips01 changed the title Created a new optional setting to control whether there should be an … Optional Auto-Generation of VersionAttribute Conditions Nov 3, 2019
@ikonst
Copy link
Contributor

ikonst commented Nov 4, 2019

Can you explain why version conflicts are not possible in your scenario?

@Flips01
Copy link
Author

Flips01 commented Nov 5, 2019

group = Group()
group.group_id = '321'

with TransactWrite(connection=Connection()) as tx:
    tx.update(
        UserProfile(hash_key='123'),
        actions=[
            UserProfile.groups.set((UserProfile.groups|[]).append([group.group_id]))
        ]
    )
    tx.save(group, condition=Group.group_id.does_not_exist())

The given code does not need a version condition. A transaction will only be committed if all operations can be performed. Therefore the Group-condition ensures that no duplicate id's end up in UserProfile.groups. This operation is also totally unrelated to all other possible UserProfile attributes: If a user creates a group I don't care if there was an update to his name or email address in the meantime. I just want to ensure that the created group is linked in his profile.

If there will be an operation where I care about other updates to the UserProfile I can work explicitly with the version attribute in this case and create a condition that involves it. The given code would still include an update to the version attribute.

@ikonst
Copy link
Contributor

ikonst commented Nov 5, 2019

When you introduce a versioning to a model, it invariably feels like unneeded overhead (and a new failure mode) in cases where you're modifying an "isolated part" of the model. One thing to consider, though, is that if you do not increase the version number within your tx.update, code running in parallel and doing UserProfile.get('123').save() will revert the appending of the group. This is because Model.save performs a PutItem with the entire model's contents rather than only the attributes that were changed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants