1. Introducción

Hola a todos y bienvenidos a un nuevo post de de nuestro querido blog!. En el post anterior vimos como crear filtros complejos a través de graphene-sqlalchemy-filter. Hicimos búsquedas de subtextos haciendo uso del operador like. Sin embargo éste solo puede ser aplicado a atributos de tipo String. En este post definiremos un nuevo filtro, que hemos llamado likeall, que nos permitirá hacer búsquedas de tipo like con independencia del tipo del atributo que se esté considerando.

Es necesario echarle un vistazo al post anterior ya que éste es una continuación del mismo y únicamente mostraremos los elementos nuevos para crear el operador likeall.

Tecnologías empleadas:

  • Python 3.6
  • Flask 1.1.1
  • Graphene 2.1.8
  • Graphene SQLAlchemy Filter 1.10.2
  • SQLAlchemy 1.3.13
  • SQLite

Os podéis descargar el código de mi GitHub que se encuentra aquí.

2. Fuentes

Extendemos la clase FilterSet del fichero filter.py definiendo el nuevo operador a través del atributo EXTRA_EXPRESSIONS. La función a ejecutar se establece a través del atributo filter. En este caso definimos la función likeall_filter que recibirá por parámetro el atributo field que representa una instancia de la clase Field de SQLAlchemy y el valor a aplicar.

...

def likeall_filter(field, value: str):
    return func.lower(func.cast(field, String)).like('%' + str(value).lower() + '%')


class MyFilterSet(FilterSet):
    LIKEALL = 'likeall'

    EXTRA_EXPRESSIONS = {
        'likeall': {
            'graphql_name': 'likeall',
            'for_types': [types.Date, types.DateTime, types.String, types.Int, types.Decimal],
            'filter': likeall_filter,
            'input_type': (
                lambda type_, nullable, doc: graphene.String(nullable=False)
            ),
            'description': 'Filter like for all types',
        }
    }

    class Meta:
        abstract = True


class UserFilter(MyFilterSet):
...

El resto de ficheros permanecen igual que en el post anterior.

3. Testeando la aplicación

Uilizamos unittest. Definimos dos filtros de prueba. Uno para filtrar por el campo alfanumérico name y otro para consultar por el campo numérico age.

...

FILTER_LIKE_ALL_STRING = """
   query{
      user(filters: {nameLikeall: "Jo"}){
        edges{
          node{
            userid
            name
            surname
            age
          }
        }
      }
    }
"""

FILTER_LIKE_ALL_NUMBER = """
    query{
      user(filters: {ageLikeall: "3"}){
        edges{
          node{
            userid
            name
            surname
            age
          }
        }
      }
    }
"""

...

Definición de los tests

...

class UserTest(unittest.TestCase):
    ...

    def test_should_validate_like_all_operator(self):
        self.assertEqual(
            {"data": {"user": {"edges": [{"node": {"userid": "1", "name": "Jorge", "surname": "Hernandez", "age": 32}}, {"node": {"userid": "2", "name": "Jose", "surname": "Hernandez", "age": 32}}]}}},
            self.client.execute(self.FILTER_LIKE_ALL_STRING))

    def test_should_validate_like_all_operator(self):
        self.assertEqual(
            {"data": {"user": {"edges": [{"node": {"userid": "1", "name": "Jorge", "surname": "Hernandez", "age": 32}}, {"node": {"userid": "2", "name": "Jose", "surname": "Hernandez", "age": 32}}]}}},
            self.client.execute(self.FILTER_LIKE_ALL_NUMBER))

4. Referencias