'Resolve the ORDERBY expression.
@param orderby: the orderby expression from the caller
@return: tuple (expr, aggr, fields, tables):
expr: the orderby expression (resolved into Fields)
aggr: the orderby expression with aggregations
fields: the fields in the orderby
tables: the tables required for the orderby
@note: for GROUPBY id (e.g. filter query), all ORDERBY fields
must appear in aggregation functions, otherwise ORDERBY
can be ambiguous => use aggr instead of expr'

def resolve_orderby(self, orderby):

    table = self.resource.table
    tablename = table._tablename
    pkey = str(table._id)
    ljoins = self.ljoins
    ijoins = self.ijoins
    tables = set()
    adapter = S3DAL()
    if orderby:
        db = current.db
        items = self.resolve_expression(orderby)
        expr = []
        aggr = []
        fields = []
        for item in items:
            expression = None
            if (type(item) is Expression):
                f = item.first
                op = item.op
                if (op == adapter.AGGREGATE):
                    expression = item
                elif (isinstance(f, Field) and (op == adapter.INVERT)):
                    direction = 'desc'
                else:
                    continue
            elif isinstance(item, Field):
                direction = 'asc'
                f = item
            elif isinstance(item, str):
                (fn, direction) = (item.strip().split() + ['asc'])[:2]
                (tn, fn) = ([tablename] + fn.split('.', 1))[(-2):]
                try:
                    f = db[tn][fn]
                except (AttributeError, KeyError):
                    continue
            else:
                continue
            fname = str(f)
            tname = fname.split('.', 1)[0]
            if (tname != tablename):
                if ((tname in ljoins) or (tname in ijoins)):
                    tables.add(tname)
                else:
                    continue
            fields.append(f)
            if (expression is None):
                expression = (f if (direction == 'asc') else (~ f))
                expr.append(expression)
                direction = direction.strip().lower()[:3]
                if (fname != pkey):
                    expression = (f.min() if (direction == 'asc') else (~ f.max()))
            else:
                expr.append(expression)
            aggr.append(expression)
    else:
        expr = None
        aggr = None
        fields = None
    return (expr, aggr, fields, tables)
