Changed the change_user and change_product API to get rid of the update -> write -> undo on failure pattern.

This commit is contained in:
s3lph 2018-07-19 21:51:35 +02:00
parent fcc64d1662
commit c4018156f5

View file

@ -232,12 +232,23 @@ class MatematDatabase(object):
'tkhash': tkhash 'tkhash': tkhash
}) })
def change_user(self, user: User) -> None: def change_user(self, user: User, **kwargs)\
-> None:
""" """
Write changes in the User object to the database. Commit changes to the user in the database. If writing the requested changes succeeded, the values are updated
:param user: The user object to update in the database. in the provided user object. Otherwise the user object is left untouched. The user to update is identified by
the ID field in the provided user object.
:param user: The user object to update and to identify the requested user by.
:param kwargs: The properties to change.
:raises DatabaseConsistencyError: If the user represented by the object does not exist. :raises DatabaseConsistencyError: If the user represented by the object does not exist.
""" """
# Resolve the values to change
name: str = kwargs['name'] if 'name' in kwargs else user.name
email: str = kwargs['email'] if 'email' in kwargs else user.email
balance: int = kwargs['balance'] if 'balance' in kwargs else user.balance
is_admin: bool = kwargs['is_admin'] if 'is_admin' in kwargs else user.is_admin
is_member: bool = kwargs['is_member'] if 'is_member' in kwargs else user.is_member
with self.db.transaction() as c: with self.db.transaction() as c:
c.execute(''' c.execute('''
UPDATE users SET UPDATE users SET
@ -250,16 +261,22 @@ class MatematDatabase(object):
WHERE user_id = :user_id WHERE user_id = :user_id
''', { ''', {
'user_id': user.id, 'user_id': user.id,
'username': user.name, 'username': name,
'email': user.email, 'email': email,
'balance': user.balance, 'balance': balance,
'is_admin': user.is_admin, 'is_admin': is_admin,
'is_member': user.is_member 'is_member': is_member
}) })
affected = c.execute('SELECT changes()').fetchone()[0] affected = c.execute('SELECT changes()').fetchone()[0]
if affected != 1: if affected != 1:
raise DatabaseConsistencyError( raise DatabaseConsistencyError(
f'change_user should affect 1 users row, but affected {affected}') f'change_user should affect 1 users row, but affected {affected}')
# Only update the actual user object after the changes in the database succeeded
user.name = name
user.email = email
user.balance = balance
user.is_admin = is_admin
user.is_member = is_member
def delete_user(self, user: User) -> None: def delete_user(self, user: User) -> None:
""" """
@ -337,7 +354,21 @@ class MatematDatabase(object):
product_id = int(c.fetchone()[0]) product_id = int(c.fetchone()[0])
return Product(product_id, name, price_member, price_non_member, 0) return Product(product_id, name, price_member, price_non_member, 0)
def change_product(self, product: Product) -> None: def change_product(self, product: Product, **kwargs) -> None:
"""
Commit changes to the product in the database. If writing the requested changes succeeded, the values are
updated in the provided product object. Otherwise the product object is left untouched. The product to update
is identified by the ID field in the provided product object.
:param product: The product object to update and to identify the requested product by.
:param kwargs: The properties to change.
:raises DatabaseConsistencyError: If the product represented by the object does not exist.
"""
# Resolve the values to change
name: str = kwargs['name'] if 'name' in kwargs else product.name
price_member: int = kwargs['price_member'] if 'price_member' in kwargs else product.price_member
price_non_member: int = kwargs['price_non_member'] if 'price_non_member' in kwargs else product.price_non_member
stock: int = kwargs['stock'] if 'stock' in kwargs else product.stock
with self.db.transaction() as c: with self.db.transaction() as c:
c.execute(''' c.execute('''
UPDATE products UPDATE products
@ -349,15 +380,20 @@ class MatematDatabase(object):
WHERE product_id = :product_id WHERE product_id = :product_id
''', { ''', {
'product_id': product.id, 'product_id': product.id,
'name': product.name, 'name': name,
'price_member': product.price_member, 'price_member': price_member,
'price_non_member': product.price_non_member, 'price_non_member': price_non_member,
'stock': product.stock 'stock': stock
}) })
affected = c.execute('SELECT changes()').fetchone()[0] affected = c.execute('SELECT changes()').fetchone()[0]
if affected != 1: if affected != 1:
raise DatabaseConsistencyError( raise DatabaseConsistencyError(
f'change_product should affect 1 products row, but affected {affected}') f'change_product should affect 1 products row, but affected {affected}')
# Only update the actual product object after the changes in the database succeeded
product.name = name
product.price_member = price_member
product.price_non_member = price_non_member
product.stock = stock
def delete_product(self, product: Product) -> None: def delete_product(self, product: Product) -> None:
""" """