Turn the tuple of filters into SQL WHERE statements

        The key (column name) & operator have already been vetted
        so they can be trusted but the value could still be evil
        so it MUST be a parameterized input!

        That is done by creating a param dict where they key name
        & val look like:

            '{}_{}'.format(key, oper): val

        The key is constructed the way it is to ensure uniqueness,
        if we just used the key name then it could get clobbered.

        Ultimately the WHERE statement will look something like:

            age >= {age_gte}

        where age_gte is the key name in the param dict with a
        value of the evil user input. In the end, a string
        statement & dict param are returned as a tuple if any
        filters were provided otherwise None.

        :return: tuple (string, dict)

def filters_query(filters):
        """ Turn the tuple of filters into SQL WHERE statements

        The key (column name) & operator have already been vetted
        so they can be trusted but the value could still be evil
        so it MUST be a parameterized input!

        That is done by creating a param dict where they key name
        & val look like:

            '{}_{}'.format(key, oper): val

        The key is constructed the way it is to ensure uniqueness,
        if we just used the key name then it could get clobbered.

        Ultimately the WHERE statement will look something like:

            age >= {age_gte}

        where age_gte is the key name in the param dict with a
        value of the evil user input. In the end, a string
        statement & dict param are returned as a tuple if any
        filters were provided otherwise None.

        :return: tuple (string, dict)
        """

        def _cast_val(filtr):
            """ Perform any needed casting on the filter value

            This could be tasks like including '%' signs at
            certain anchor points based on the filter or
            even wrapping it in certain functions.
            """

            val = filtr.val

            if filtr.oper in ('contains', 'icontains'):
                val = '%' + filtr.val + '%'
            elif filtr.oper == 'endswith':
                val = '%' + filtr.val
            elif filtr.oper == 'startswith':
                val = filtr.val + '%'

            return val

        def _filter(filtr):
            """ Process each individual Filter object """

            oper = FILTER_TABLE[filtr.oper]
            prop = '{field}_{oper}'.format(
                field=filtr.field.replace('.', '_'),
                oper=filtr.oper,
            )

            if isinstance(filtr, FilterRel):
                stmt = _filter_rel(filtr, oper, prop)
            else:
                stmt = '{field} {oper} %({prop})s'.format(
                    field=filtr.field,
                    oper=oper,
                    prop=prop,
                )

            return stmt, {prop: _cast_val(filtr)}

        def _filter_or(filters):
            """ Given a FilterOr object return a SQL query """

            param = {}
            stmts = []

            for filtr in filters:
                vals = _filter(filtr)

                param.update(vals[1])
                stmts.append(vals[0])

            stmt = ' OR '.join(stmts)
            stmt = '({})'.format(stmt)

            return stmt, param

        def _filter_rel(rel, oper, prop):
            """ Given a FilterRel object return a SQL sub query """

            stmt = """
                   {field} IN (SELECT {foreign_field} FROM {foreign_rtype}
                               WHERE {foreign_filter} {oper} %({prop})s)
                   """

            return stmt.format(
                field=rel.local_field,
                foreign_field=rel.foreign_field,
                foreign_filter=rel.foreign_filter,
                foreign_rtype=rel.foreign_rtype,
                oper=oper,
                prop=prop,
            )

        param = {}
        stmts = []

        for filtr in filters:
            if isinstance(filtr, FilterOr):
                vals = _filter_or(filtr)
            else:
                vals = _filter(filtr)

            param.update(vals[1])
            stmts.append(vals[0])

        if stmts:
            stmt = ' AND '.join(stmts)
            stmt = ' WHERE ' + stmt

        return stmt, param