def test_field_not_provided(self, session): query = session.query(Bar) load_spec = [{}] with pytest.raises(BadLoadFormat) as err: apply_loads(query, load_spec) expected_error = '`fields` is a mandatory attribute.' assert expected_error == error_value(err)
def test_wrong_spec_format(self, session, spec): query = session.query(Bar) load_spec = [spec] with pytest.raises(BadLoadFormat) as err: apply_loads(query, load_spec) expected_error = 'Load spec `{}` should be a dictionary.'.format(spec) assert expected_error == error_value(err)
def test_invalid_field(self, session): query = session.query(Bar) load_spec = [{'fields': ['invalid_field']}] with pytest.raises(FieldNotFound) as err: apply_loads(query, load_spec) expected_error = ( "Model <class 'test.models.Bar'> has no column `invalid_field`.") assert expected_error == error_value(err)
def test_ambiguous_query(self, session): query = session.query(Foo, Bar) loads = [ {'fields': ['count']}, # ambiguous {'model': 'Bar', 'fields': ['count']}, {'model': 'Qux', 'fields': ['count']}, ] with pytest.raises(BadSpec) as err: apply_loads(query, loads) assert 'Ambiguous spec. Please specify a model.' == err.value.args[0]
def test_auto_join_to_invalid_model(self, session): query = session.query(Foo, Bar) loads = [ {'model': 'Foo', 'fields': ['count']}, {'model': 'Bar', 'fields': ['count']}, {'model': 'Qux', 'fields': ['count']}, ] with pytest.raises(BadSpec) as err: apply_loads(query, loads) assert 'The query does not contain model `Qux`.' == err.value.args[0]
def test_eager_load(self, session, db_uri): query = session.query(Foo).options(joinedload(Foo.bar)) load_spec = [ {'model': 'Foo', 'fields': ['name']}, {'model': 'Bar', 'fields': ['count']} ] restricted_query = apply_loads(query, load_spec) join_type = "INNER JOIN" if "mysql" in db_uri else "JOIN" # autojoin has no effect expected = ( "SELECT " "foo.id AS foo_id, foo.name AS foo_name, " "foo.bar_id AS foo_bar_id, " "bar_1.id AS bar_1_id, bar_1.name AS bar_1_name, " "bar_1.count AS bar_1_count \n" "FROM foo {join} bar ON bar.id = foo.bar_id " "LEFT OUTER JOIN bar AS bar_1 ON bar_1.id = foo.bar_id".format( join=join_type ) ) assert str(restricted_query) == expected
def test_no_load_provided(self, session): query = session.query(Bar) load_spec = [] restricted_query = apply_loads(query, load_spec) # defers all fields expected = ("SELECT bar.id AS bar_id \n" "FROM bar") assert str(restricted_query) == expected
def test_single_value(self, session): query = session.query(Bar) loads = [{'fields': ['name']}] restricted_query = apply_loads(query, loads) expected = ("SELECT bar.id AS bar_id, bar.name AS bar_name \n" "FROM bar") assert str(restricted_query) == expected
def test_multiple_values_single_model(self, session): query = session.query(Foo) loads = [{'fields': ['name', 'count']}] restricted_query = apply_loads(query, loads) expected = ("SELECT foo.id AS foo_id, foo.name AS foo_name, " "foo.count AS foo_count \n" "FROM foo") assert str(restricted_query) == expected
def test_a_list_of_fields_can_be_supplied_as_load_spec(self, session): query = session.query(Foo) load_spec = ['name', 'count'] restricted_query = apply_loads(query, load_spec) expected = ("SELECT foo.id AS foo_id, foo.name AS foo_name, " "foo.count AS foo_count \n" "FROM foo") assert str(restricted_query) == expected
def test_multiple_values_multiple_models(self, session): query = session.query(Foo, Bar) loads = [ {'model': 'Foo', 'fields': ['count']}, {'model': 'Bar', 'fields': ['count']}, ] restricted_query = apply_loads(query, loads) expected = ( "SELECT foo.id AS foo_id, foo.count AS foo_count, " "bar.id AS bar_id, bar.count AS bar_count \n" "FROM foo, bar" ) assert str(restricted_query) == expected
def test_noop_if_query_contains_named_models(self, session, db_uri): query = session.query(Foo, Bar).join(Bar) loads = [ {'model': 'Foo', 'fields': ['count']}, {'model': 'Bar', 'fields': ['count']}, ] restricted_query = apply_loads(query, loads) join_type = "INNER JOIN" if "mysql" in db_uri else "JOIN" expected = ( "SELECT foo.id AS foo_id, foo.count AS foo_count, " "bar.id AS bar_id, bar.count AS bar_count \n" "FROM foo {join} bar ON bar.id = foo.bar_id".format(join=join_type) ) assert str(restricted_query) == expected
def test_auto_join(self, session, db_uri): query = session.query(Foo) loads = [ {'fields': ['count']}, {'model': 'Bar', 'fields': ['count']}, ] restricted_query = apply_loads(query, loads) join_type = "INNER JOIN" if "mysql" in db_uri else "JOIN" # Bar is lazily joined, so the second loads directive has no effect expected = ( "SELECT foo.id AS foo_id, foo.count AS foo_count \n" "FROM foo {join} bar ON bar.id = foo.bar_id".format(join=join_type) ) assert str(restricted_query) == expected
def dict2sqla(self, data): """ :param data: :return: """ invalid = [] query = self._model.query fields = data.get('fields') or list(self._model.columns().keys()) related = data.get('related') or {} filters = data.get('filters') or [] sort = data.get('sorting') or [] for k in fields: if k not in self._model.columns().keys(): invalid.append(k) if len(invalid) == 0 and len(fields) > 0: try: query = sqlaf.apply_loads(query, fields) except exceptions.BadLoadFormat: invalid.append(fields) for k in related.keys(): instance, columns = self._model.related(k) if instance is not None: _columns = related.get(k) try: if len(_columns) > 0 and _columns[0] != self._syntax.ALL: _invalid = list(set(related.get(k)) - set(columns)) if len(_invalid) > 0: _columns = _invalid raise ArgumentError else: _columns = columns query = query.join(instance, aliased=False) query = query.options(contains_eager(instance).load_only(*_columns)) except ArgumentError: invalid += _columns else: invalid.append(k) def apply(stm, flt, action): """ :param stm: :param flt: :param action: :return: """ resource = flt.get('model') try: if resource: _, cols = self._model.related(resource) if cols and cols.get(flt.get('field')) is None: raise exceptions.FieldNotFound return action(stm, flt) except exceptions.BadSpec: invalid.append(resource) except exceptions.FieldNotFound: invalid.append(flt.get('field')) except exceptions.BadFilterFormat: invalid.append(flt.get('op')) except exceptions.BadSortFormat: invalid.append(flt.get('direction')) for f in filters: try: query = apply(query, f, sqlaf.apply_filters) except AttributeError: invalid.append(f) for s in sort: try: query = apply(query, s, sqlaf.apply_sort) except AttributeError: invalid.append(s) return query, invalid