This may be related to the questions posed in #21, but I figured it best to post a fresh topic to express how important validation functions are. Coincidentally, it's the main reason I am having to look into this package. I have a JSON field where I want to store a simple list of strings. Now that SQLite support JSON fields as of version 3.9 (thanks to JSON1) I attempted to setup a list field a few different ways, but unfortunately quickly realized the limitations with mutations on these fields.
I've searched for possible solutions to this issue, which led me to this article, which inevitably led me to this package.
models.py
from sqlalchemy_json import NestedMutableJson # because I need to store a list, not a dict
from sqlalchemy.ext.mutable import MutableList
from sqlalchemy.orm import validates
from app import db # SQLAlchemy instance via flask_sqlalchemy
# SQLALCHEMY_DATABASE_URI = 'sqlite:///:memory:'
class Portal(db.Model):
__tablename__ = 'portal'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), nullable=False)
# ex: valid_kwargs will be json array of ['full_year']
valid_kwargs = db.Column(MutableList.as_mutable(db.JSON), nullable=False, default=list())
class Account(db.Model):
__tablename__ = 'account'
id = db.Column(db.Integer, primary_key=True)
portal_id = db.Column(db.Integer, db.ForeignKey('portal.id')) # one-to-one relationship
username = db.Column(db.String(100), nullable=False)
password = db.Column(db.String(100), nullable=False)
# portal = accessible thanks to portal_id/portal.id ForeignKey
# for extra fields, specific to each portal
# ATTEMPT 1 - using sqlalchemy.ext.mutable.MutableList, no extra packages
kwargs = db.Column(MutableList.as_mutable(db.JSON), nullable=False, default=list())
# ATTEMPT 2 - using NestedMutableJson from sqlalchemy_json
kwargs = db.Column(NestedMutableJson, nullable=False, default=list())
@validates('kwargs')
def validates_kwargs(self, key, value):
# make sure that only valid_kwargs are added to the account
if value and not all([kw in self.portal.valid_kwargs for kw in value]):
raise ValueError('Invalid value provided in kwargs')
return value
unit_tests/test_models.py
def test_account(test_db, account):
"""
GIVEN a database instance
WHEN a new account is created
THEN check that the username, password, kwargs, and reports fields are defined correctly
"""
test_db.session.add(account)
test_db.session.commit()
assert Account.query.count() == 1
assert account.username == 'mhill'
assert account.password == 'password1'
assert isinstance(account.kwargs, list) and len(account.kwargs) == 0 # check that kwargs defaults to an empty list
assert account.reports.count() == 0 # check that reports relationship is present
assert isinstance(account.portal, Portal) # check that portal relationship is present
account.portal.valid_kwargs.append('full_year')
account.kwargs.append('full_year')
test_db.session.add(account)
test_db.session.commit()
assert len(account.kwargs) == 1
assert 'full_year' in account.kwargs
"""
GIVEN an account whose associated portal has valid_kwargs
WHEN kwargs are added to the account
THEN check that only the kwargs in the portal's valid_kwargs are allowed to be added
"""
# FIXME: Doesn't throw an error
with pytest.raises(ValueError):
account.kwargs.append('illegal_kwarg')
test_db.session.add(account)
test_db.session.commit()
This may be related to the questions posed in #21, but I figured it best to post a fresh topic to express how important validation functions are. Coincidentally, it's the main reason I am having to look into this package. I have a JSON field where I want to store a simple list of strings. Now that SQLite support JSON fields as of version 3.9 (thanks to JSON1) I attempted to setup a list field a few different ways, but unfortunately quickly realized the limitations with mutations on these fields.
I've searched for possible solutions to this issue, which led me to this article, which inevitably led me to this package.
models.py
unit_tests/test_models.py