def _get_select_query(self, fields=None): """The raw SQL that will be used to resolve the queryset.""" handler = get_engine_handler(self.db) with handler.patch(): params = copy.deepcopy(self._params) if params['joins']: params['joins'] = [ join(table=(j.pop('table'),), **j) for j in params['joins'] ] table = self.model._meta.db_table alias = params.pop('alias', None) kwargs = {k: v for k, v in params.items() if v} # Inject default field names. # If this query does not contain a GROUP BY clause, we can safely # use a "*" to indicate all fields; # If the query has aggregation (GROUP BY), however, we will need to # choose a value to display for each field (especially pk because # it is needed by Django). Since accessing those fields doesn't # really make sense anyway, We arbitrarily use MIN. table_name = alias or table if fields is not None: kwargs['select'] = [ f if '.' in f or isinstance(f, raw) else raw('{table}.{field}'.format( table=identifier(table_name), field=identifier(f)) ) for f in fields ] elif self._params['group_by']: kwargs['select'] = ( handler.get_aggregated_columns_for_group_by(self, 'MIN') ) else: kwargs['select'] = handler.get_star(self) kwargs['select'].extend(self.extra_fields) if 'offset' in kwargs and 'limit' not in kwargs: kwargs['limit'] = handler.no_limit_value() if alias: table = ((table, alias),) query = select(table, **kwargs) return query
def get_star(self, queryset): """Generates a ``<table_name>.*`` representation :rtype: :class:`mosql.util.raw` """ table = queryset._params['alias'] or queryset.model._meta.db_table return [raw('{table}.*'.format(table=identifier(table)))]
def get_aggregated_columns_for_group_by(self, queryset, aggregate): """Generates a sequence of fully-qualified column names This is used in an aggregated query, when :method:`get_star` cannot be used safety without ambiguity. Values for each field in the model are calculated by a SQL function specified by ``aggregate``, and then injected (using ``AS``) back into the fields. :param: aggregate: The SQL function to be used for aggregation. :type aggregate: str :returns: A sequence of fully qualified ``SELECT`` identifiers. """ table = queryset._params['alias'] or queryset.model._meta.db_table return [ raw('{func}({table}.{field}) AS {field}'.format( func=aggregate, table=identifier(table), field=identifier(field.get_attname_column()[1]))) for field in queryset.model._meta.fields ]