From 6767721c4a78efa5f3be3468bfa141c7baeeacac Mon Sep 17 00:00:00 2001 From: timbu Date: Mon, 19 Jun 2017 14:44:14 +0100 Subject: [PATCH 1/5] allow field or aggregate based queries --- sqlalchemy_filters/models.py | 2 +- test/interface/test_filters.py | 27 +++++++++++++++++++++++++++ test/interface/test_models.py | 24 +++++++++++++++++++++++- 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/sqlalchemy_filters/models.py b/sqlalchemy_filters/models.py index 34e314d..2cc4f0d 100644 --- a/sqlalchemy_filters/models.py +++ b/sqlalchemy_filters/models.py @@ -37,6 +37,6 @@ def get_query_models(query): A dictionary with all the models included in the query. """ return { - entity['type'].__name__: entity['type'] + entity['entity'].__name__: entity['entity'] for entity in query.column_descriptions } diff --git a/test/interface/test_filters.py b/test/interface/test_filters.py index b088b95..7324bbf 100644 --- a/test/interface/test_filters.py +++ b/test/interface/test_filters.py @@ -3,6 +3,7 @@ import datetime import pytest +from sqlalchemy import func from sqlalchemy_filters import apply_filters from sqlalchemy_filters.exceptions import ( BadFilterFormat, FieldNotFound, BadQuery @@ -240,6 +241,32 @@ def test_a_single_dict_can_be_supplied_as_filters(self, session): assert result[1].name == 'name_1' +class TestApplyFilterOnFieldBasedQuery(TestFiltersMixin): + + @pytest.mark.usefixtures('multiple_bars_inserted') + def test_apply_filter_on_single_field_query(self, session): + query = session.query(Bar.id) + filters = [{'field': 'name', 'op': '==', 'value': 'name_1'}] + + filtered_query = apply_filters(query, filters) + result = filtered_query.all() + + assert len(result) == 2 + assert result[0] == (1,) + assert result[1] == (3,) + + @pytest.mark.usefixtures('multiple_bars_inserted') + def test_apply_filter_on_aggregate_query(self, session): + query = session.query(func.count(Bar.id)) + filters = [{'field': 'name', 'op': '==', 'value': 'name_1'}] + + filtered_query = apply_filters(query, filters) + result = filtered_query.all() + + assert len(result) == 1 + assert result[0] == (2,) + + class TestApplyEqualToFilter(TestFiltersMixin): @pytest.mark.parametrize('operator', ['==', 'eq']) diff --git a/test/interface/test_models.py b/test/interface/test_models.py index f5da37d..e90a3e5 100644 --- a/test/interface/test_models.py +++ b/test/interface/test_models.py @@ -1,5 +1,6 @@ +from sqlalchemy import func from sqlalchemy_filters import get_query_models -from test.models import Bar, Qux +from test.models import Bar, Foo, Qux class TestGetQueryModels(object): @@ -31,3 +32,24 @@ def test_query_with_duplicated_models(self, session): entities = get_query_models(query) assert {'Bar': Bar, 'Qux': Qux} == entities + + def test_query_with_one_field(self, session): + query = session.query(Foo.id) + + entities = get_query_models(query) + + assert {'Foo': Foo} == entities + + def test_query_with_multiple_fields(self, session): + query = session.query(Foo.id, Bar.id, Bar.name) + + entities = get_query_models(query) + + assert {'Foo': Foo, 'Bar': Bar} == entities + + def test_query_with_aggregate_func(self, session): + query = session.query(func.count(Foo.id)) + + entities = get_query_models(query) + + assert {'Foo': Foo} == entities From a1ef9f5b38422fe57d455562f9e08bbb2b09a174 Mon Sep 17 00:00:00 2001 From: timbu Date: Mon, 19 Jun 2017 14:51:06 +0100 Subject: [PATCH 2/5] rename entity variable --- sqlalchemy_filters/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sqlalchemy_filters/models.py b/sqlalchemy_filters/models.py index 2cc4f0d..ff72a22 100644 --- a/sqlalchemy_filters/models.py +++ b/sqlalchemy_filters/models.py @@ -37,6 +37,6 @@ def get_query_models(query): A dictionary with all the models included in the query. """ return { - entity['entity'].__name__: entity['entity'] - for entity in query.column_descriptions + col_desc['entity'].__name__: col_desc['entity'] + for col_desc in query.column_descriptions } From 93a8454d30fdea766b960cac0ddbb027e29cbf3b Mon Sep 17 00:00:00 2001 From: timbu Date: Tue, 20 Jun 2017 11:10:26 +0100 Subject: [PATCH 3/5] bump version, add changes --- CHANGELOG.rst | 8 ++++++++ setup.py | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 6a4f3ba..6156452 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +6,14 @@ versions, where semantic versioning is used: *major.minor.patch*. Backwards-compatible changes increment the minor version number only. + +Version 0.4.0 +------------- + +Released 2017-06-21 + +* Adds support for queries based on model fields or aggregate functions. + Version 0.3.0 ------------- diff --git a/setup.py b/setup.py index ba4ecaa..36a5142 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ setup( name='sqlalchemy-filters', - version='0.3.0', + version='0.4.0', description='A library to filter SQLAlchemy queries.', long_description=readme, author='Student.com', From 741b671ec2600cca5abb252a82e2cde0daff0b25 Mon Sep 17 00:00:00 2001 From: timbu Date: Tue, 20 Jun 2017 14:57:54 +0100 Subject: [PATCH 4/5] Update README.rst --- README.rst | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 1ffbb92..fda49a9 100644 --- a/README.rst +++ b/README.rst @@ -33,7 +33,7 @@ model: # ... - query = self.session.query(Foo) + query = self.session.query(Foo) Then we can apply filters to that ``query`` object (multiple times): @@ -51,6 +51,14 @@ Then we can apply filters to that ``query`` object (multiple times): result = filtered_query.all() +Note that we can also apply filters to queries defined by fields or functions: + +.. code-block:: python + + query_alt_1 = self.session.query(Foo.id, Foo.name) + query_alt_2 = self.session.query(func.count(Foo.id)) + + Sort ---- From 4d21c5299c013d25eac5cef6f01788fd181658c2 Mon Sep 17 00:00:00 2001 From: timbu Date: Tue, 20 Jun 2017 16:38:43 +0100 Subject: [PATCH 5/5] remove rogue spaces from README --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index fda49a9..5253314 100644 --- a/README.rst +++ b/README.rst @@ -33,7 +33,7 @@ model: # ... - query = self.session.query(Foo) + query = self.session.query(Foo) Then we can apply filters to that ``query`` object (multiple times):