Repository: incubator-ariatosca Updated Branches: refs/heads/support_for_sql_opperands 3987e24ad -> 1575e9c11 (forced update)
added support for opperands in sql mapi Project: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/commit/1575e9c1 Tree: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/tree/1575e9c1 Diff: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/diff/1575e9c1 Branch: refs/heads/support_for_sql_opperands Commit: 1575e9c11ac9f32e6886e9d80823e9bcbe3c628c Parents: e7ffc73 Author: max-orlov <[email protected]> Authored: Tue Apr 4 20:41:59 2017 +0300 Committer: max-orlov <[email protected]> Committed: Wed Apr 5 12:31:16 2017 +0300 ---------------------------------------------------------------------- aria/storage/sql_mapi.py | 24 +++++++++++- tests/storage/test_model_storage.py | 65 ++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/1575e9c1/aria/storage/sql_mapi.py ---------------------------------------------------------------------- diff --git a/aria/storage/sql_mapi.py b/aria/storage/sql_mapi.py index 59e1896..59312b8 100644 --- a/aria/storage/sql_mapi.py +++ b/aria/storage/sql_mapi.py @@ -31,6 +31,13 @@ from . import ( exceptions, ) +_predicates = {'ge': '__ge__', + 'gt': '__gt__', + 'lt': '__lt__', + 'le': '__le__', + 'eq': '__eq__', + 'ne': '__ne__'} + class SQLAlchemyModelAPI(api.ModelAPI): """ @@ -243,7 +250,10 @@ class SQLAlchemyModelAPI(api.ModelAPI): @staticmethod def _add_value_filter(query, filters): for column, value in filters.items(): - if isinstance(value, (list, tuple)): + if isinstance(value, dict): + for predicate, operand in value.items(): + query = query.filter(getattr(column, predicate)(operand)) + elif isinstance(value, (list, tuple)): query = query.filter(column.in_(value)) else: query = query.filter(column == value) @@ -269,12 +279,24 @@ class SQLAlchemyModelAPI(api.ModelAPI): include, filters, sort, joins = self._get_joins_and_converted_columns( include, filters, sort ) + filters = self._convert_operands(filters) query = self._get_base_query(include, joins) query = self._filter_query(query, filters) query = self._sort_query(query, sort) return query + @staticmethod + def _convert_operands(filters): + for column, conditions in filters.items(): + if isinstance(conditions, dict): + for predicate, operand in conditions.items(): + if predicate in _predicates: + del filters[column][predicate] + filters[column][_predicates[predicate]] = operand + + return filters + def _get_joins_and_converted_columns(self, include, filters, http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/1575e9c1/tests/storage/test_model_storage.py ---------------------------------------------------------------------- diff --git a/tests/storage/test_model_storage.py b/tests/storage/test_model_storage.py index e4f3eba..dcfa3f7 100644 --- a/tests/storage/test_model_storage.py +++ b/tests/storage/test_model_storage.py @@ -31,6 +31,16 @@ from tests import ( modeling as tests_modeling ) +from sqlalchemy import ( + Column, + Integer, + Text) + +from aria.modeling import ( + models, + mixins +) + @pytest.fixture def storage(): @@ -150,3 +160,58 @@ def test_mapi_include(context): assert_include(service1) assert_include(service2) + + +class MockModel(models.aria_declarative_base, mixins.ModelMixin): #pylint: disable=abstract-method + __tablename__ = 'op_mock_model' + + name = Column(Text) + value = Column(Integer) + + +class TestFilterOperands(object): + + @pytest.fixture + def values(self): + return {1, 2, 3, 4} + + @pytest.fixture() + def storage(self, values): + model_storage = application_model_storage( + sql_mapi.SQLAlchemyModelAPI, initiator=tests_storage.init_inmemory_model_storage) + model_storage.register(MockModel) + for value in values: + model_storage.op_mock_model.put(MockModel(value=value)) + yield model_storage + tests_storage.release_sqlite_storage(model_storage) + + def test_gt(self, storage): + assert len(storage.op_mock_model.list(filters=dict(value=dict(gt=3)))) == 1 + assert len(storage.op_mock_model.list(filters=dict(value=dict(gt=4)))) == 0 + + def test_ge(self, storage): + assert len(storage.op_mock_model.list(filters=dict(value=dict(ge=3)))) == 2 + assert len(storage.op_mock_model.list(filters=dict(value=dict(ge=5)))) == 0 + + def test_lt(self, storage): + assert len(storage.op_mock_model.list(filters=dict(value=dict(lt=2)))) == 1 + assert len(storage.op_mock_model.list(filters=dict(value=dict(lt=1)))) == 0 + + def test_le(self, storage): + assert len(storage.op_mock_model.list(filters=dict(value=dict(le=2)))) == 2 + assert len(storage.op_mock_model.list(filters=dict(value=dict(le=0)))) == 0 + + def test_eq(self, storage): + assert len(storage.op_mock_model.list(filters=dict(value=dict(eq=2)))) == 1 + assert len(storage.op_mock_model.list(filters=dict(value=dict(eq=0)))) == 0 + + def test_neq(self, storage): + assert len(storage.op_mock_model.list(filters=dict(value=dict(ne=2)))) == 3 + + def test_gt_and_lt(self, storage): + assert len(storage.op_mock_model.list(filters=dict(value=dict(gt=1, lt=3)))) == 1 + assert len(storage.op_mock_model.list(filters=dict(value=dict(gt=2, lt=2)))) == 0 + + def test_eq_and_ne(self, storage): + assert len(storage.op_mock_model.list(filters=dict(value=dict(eq=1, ne=3)))) == 1 + assert len(storage.op_mock_model.list(filters=dict(value=dict(eq=1, ne=1)))) == 0
