diff --git a/CHANGES.md b/CHANGES.md index ab8e32b..7027a0e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,17 @@ # SQLAlchemy-JSONAPI Changelog +## 4.0.5 + +*2016-03-20* + +* Fixed missing jsonapi_permissions attribute when patching relationships. + +## 4.0.4 + +*2016-02-27* + +* Fixed session being flushed error during POST to collection. + ## 4.0.1 - 4.0.3 *2016-01-21* diff --git a/setup.py b/setup.py index 5c6bd66..969b08b 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,7 @@ requirements.append('enum34') setup(name='SQLAlchemy-JSONAPI', - version='4.0.3', + version='4.0.5', url='http://github.com/coltonprovias/sqlalchemy-jsonapi', license='MIT', author='Colton J. Provias', diff --git a/sqlalchemy_jsonapi/serializer.py b/sqlalchemy_jsonapi/serializer.py index 5e24c11..d2a002c 100644 --- a/sqlalchemy_jsonapi/serializer.py +++ b/sqlalchemy_jsonapi/serializer.py @@ -140,7 +140,7 @@ def __init__(self): self.status_code = 200 self.data = { 'jsonapi': {'version': '1.0'}, - 'meta': {'sqlalchemy_jsonapi_version': '4.0.3'} + 'meta': {'sqlalchemy_jsonapi_version': '4.0.5'} } @@ -152,7 +152,7 @@ def get_permission_test(model, field, permission, instance=None): :param field: Name of the field or None for instance/model-wide :param permission: Permission to check for """ - return model.__jsonapi_permissions__\ + return getattr(model, '__jsonapi_permissions__', {})\ .get(field, {})\ .get(permission, lambda x: True) @@ -1050,8 +1050,9 @@ def post_collection(self, session, data, api_type): setter = get_attr_desc(resource, key, AttributeActions.SET) setter(resource, data['data']['attributes'][api_key]) - session.add(resource) - session.commit() + session.add(resource) + session.commit() + except IntegrityError as e: session.rollback() raise ValidationError(str(e.orig)) diff --git a/test.py b/test.py new file mode 100644 index 0000000..897d72e --- /dev/null +++ b/test.py @@ -0,0 +1,93 @@ +import re +from collections import OrderedDict + +TESTS = { + 'email == "cj@coltonprovias.com"': 'User.email == "cj@coltonprovias.com"', + 'email.lower() == "cj@coltonprovias.com"': 'User.email.lower() == "cj@coltonprovias.com"', + 'email ilike \'cj@%\'': 'User.email.ilike(\'cj@%\')', + 'published_at!=null': 'User.published_at != None', + '(5('([^'\\]*(?:\\.[^'\\]*)*)'" + r'|"([^"\\]*(?:\\.[^"\\]*)*)"))' + +REGEX = [STRING, + r'(?P\s+)', + r'(?P\b[a-zA-Z_][a-zA-Z0-9_]*\b)', + r'(?P\()', + r'(?P\))', + r'(?P\[)', + r'(?P\])', + r'(?P\>)', + r'(?P\<)', + r'(?P\>\=)', + r'(?P\<\=)', + r'(?P(\|\||or))', + r'(?P(\&\&|and))', + r'(?P(\!|not))', + r'(?Pin)', + r'(?P\.)', + r'(?P,)', + r'(?P\=\=)', + r'(?P\!\=)', + r'(?P\+)', + r'(?P\-)', + r'(?P\*)', + r'(?P\/)', + r'(?P\/\/)', + r'(?P\%)', + r'(?P\*\*)', + r'(?P\d+)', + r'(?P\d+\.\d+)' +] + +### +# EQ +# NE +# LT +# LE +# GT +# GE +# NEG +# GETITEM +# CONCAT +# LIKE +# ILIKE +# IN_ +# NOTIN_ +# NOTLIKE +# NOTILIKE +# IS_ +# ISNOT +# STARTSWITH +# ENDSWITH +# CONTAINS +# MATCH +# ADD +# SUBTRACT +# MULTIPLY +# DIVIDE +# MODULUS +# FLOORDIV + +BINARY_OPERATORS = OrderedDict([ + ['EQ', r'(?P\=\=)'], + ['NE', r'(?P\!\=)'] +]) + + +compiled = re.compile(r'|'.join(reversed(REGEX)), re.IGNORECASE) + +for test, final in TESTS.items(): + print(test) + print(final) + finalized = [] + matched = compiled.finditer(test) + prev_key = None + for item in matched: + key = item.lastgroup + value = item.group(0) + print(' {:20}:{}'.format(key, value))