Example #1
0
    def build_filter(self, filter_expr, *args, **kwargs):
        if isinstance(filter_expr, Q):
            return super().build_filter(filter_expr, *args, **kwargs)

        if filter_expr[0].startswith('old__'):
            alias = 'OLD'
        elif filter_expr[0].startswith('new__'):
            alias = 'NEW'
        else:  # pragma: no cover
            raise ValueError(
                'Filter expression on trigger.Q object must reference'
                ' old__ or new__')

        filter_expr = (filter_expr[0][5:], filter_expr[1])
        node, _ = super().build_filter(filter_expr, *args, **kwargs)

        self.alias_map[alias] = BaseTable(alias, alias)
        for child in node.children:
            child.lhs = Col(
                alias=alias,
                target=child.lhs.target,
                output_field=child.lhs.output_field,
            )

        return node, {alias}
Example #2
0
 def test_expressions(self):
     self.assertEqual(
         repr(Case(When(a=1))),
         "<Case: CASE WHEN <Q: (AND: ('a', 1))> THEN Value(None), ELSE Value(None)>"
     )
     self.assertEqual(repr(Col('alias', 'field')), "Col(alias, field)")
     self.assertEqual(repr(Date('published', 'exact')),
                      "Date(published, exact)")
     self.assertEqual(repr(DateTime('published', 'exact', utc)),
                      "DateTime(published, exact, %s)" % utc)
     self.assertEqual(repr(F('published')), "F(published)")
     self.assertEqual(repr(F('cost') + F('tax')),
                      "<CombinedExpression: F(cost) + F(tax)>")
     self.assertEqual(
         repr(ExpressionWrapper(
             F('cost') + F('tax'), models.IntegerField())),
         "ExpressionWrapper(F(cost) + F(tax))")
     self.assertEqual(repr(Func('published', function='TO_CHAR')),
                      "Func(F(published), function=TO_CHAR)")
     self.assertEqual(repr(OrderBy(Value(1))),
                      'OrderBy(Value(1), descending=False)')
     self.assertEqual(repr(Random()), "Random()")
     self.assertEqual(repr(RawSQL('table.col', [])),
                      "RawSQL(table.col, [])")
     self.assertEqual(repr(Ref('sum_cost', Sum('cost'))),
                      "Ref(sum_cost, Sum(F(cost)))")
     self.assertEqual(repr(Value(1)), "Value(1)")
Example #3
0
    def add_select(self, *fields, **kwargs):
        "Replaces the `SELECT` columns with the ones provided."
        if 'queryset' in kwargs:
            queryset = kwargs.pop('queryset')
        else:
            queryset = self.get_queryset()

        queryset.query.default_cols = False
        include_pk = kwargs.pop('include_pk', True)

        if include_pk:
            fields = [self.root_model._meta.pk] + list(fields)

        aliases = []

        for pair in fields:
            if isinstance(pair, (list, tuple)):
                model, field = pair
            else:
                field = pair
                model = field.model

            queryset, alias = self.add_joins(model, queryset)

            aliases.append(Col(alias, field, field))

        if aliases:
            queryset.query.select = aliases

        return queryset
Example #4
0
    def _create_index_sql(self, model, *, fields=None, **kwargs):
        if fields is None or len(fields) != 1 or not hasattr(
                fields[0], 'geodetic'):
            return super()._create_index_sql(model, fields=fields, **kwargs)

        field = fields[0]
        expressions = None
        opclasses = None
        if field.geom_type == 'RASTER':
            # For raster fields, wrap index creation SQL statement with ST_ConvexHull.
            # Indexes on raster columns are based on the convex hull of the raster.
            expressions = Func(Col(None, field),
                               template=self.rast_index_template)
            fields = None
        elif field.dim > 2 and not field.geography:
            # Use "nd" ops which are fast on multidimensional cases
            opclasses = [self.geom_index_ops_nd]
        name = kwargs.get('name')
        if not name:
            name = self._create_index_name(model._meta.db_table,
                                           [field.column], '_id')

        return super()._create_index_sql(
            model,
            fields=fields,
            name=name,
            using=' USING %s' % self.geom_index_type,
            opclasses=opclasses,
            expressions=expressions,
        )
Example #5
0
 def get_extra_restriction(self, where_class, alias, remote_alias):
     field = self.rel.to._meta.get_field_by_name(self.content_type_field_name)[0]
     contenttype_pk = self.get_content_type().pk
     cond = where_class()
     lookup = field.get_lookup('exact')(Col(remote_alias, field, field), contenttype_pk)
     cond.add(lookup, 'AND')
     return cond
Example #6
0
 def get_col(self, alias, output_field=None):
     if output_field is None:
         output_field = self
     if alias != self.model._meta.db_table or output_field != self:
         from django.db.models.expressions import Col
         return Col(alias, self, output_field)
     else:
         return self.cached_col
Example #7
0
    def as_sql(self, compiler, connection):
        """ Generate SQL for the language constraint.
            Use the language set by the queryset onto the query object.
            Replace None with current language, providing lazy evaluation of language(None)
        """
        language = compiler.query.language_code or translation.get_language()
        if language == 'all':
            assert hasattr(compiler.query.model._meta, 'shared_model')
            value = Col(compiler.query.get_initial_alias(),
                        compiler.query.model._meta.get_field('language_code'),
                        models.CharField())
        else:
            value = Value(language)

        col_sql, col_params = self.col.as_sql(compiler, connection)
        val_sql, val_params = value.as_sql(compiler, connection)
        return ('%s = %s' % (col_sql, val_sql), col_params + val_params)
Example #8
0
 def get_extra_restriction(self, where_class, alias, related_alias):
     """ Inject the LanguageConstraint into the join clause. Actual language
         will be resolved by the constraint itself.
     """
     related_model = self.related_model
     return LanguageConstraint(
         Col(alias, related_model._meta.get_field('language_code'),
             models.CharField()))
Example #9
0
 def get_select(self):
     """ Special case for if we are preparing a count() query """
     if self.is_count_qry is True:
         col = (Col("__count", None), ("COUNT(*)", []), None)
         klass_info = {"model": self.query.model, "select_fields": ["__count"]}
         annotations = dict()
         return (col,), klass_info, annotations
     else:
         return super().get_select()
Example #10
0
 def add_alias_constraints(queryset, alias, **kwargs):
     model, alias = alias
     clause = queryset.query.where_class()
     for lookup, value in kwargs.items():
         field_name, lookup = lookup.split('__')
         clause.add(
             queryset.query.build_lookup(
                 [lookup], Col(alias, model._meta.get_field(field_name)),
                 value), AND)
     queryset.query.where.add(clause, AND)
Example #11
0
    def _resolve_ref(self, name):
        """
        Gets called when a column reference is accessed via the CTE instance `.col.name`
        """
        if name not in self.fields:
            raise RuntimeError("No field with name `{}`".format(name))

        field = self.fields.get(name)
        field.set_attributes_from_name(name)
        return Col(self.name, field, output_field=field)
Example #12
0
    def resolve_ref(name: str, *_: Any, **__: Any) -> 'Col':
        from django.db.models.expressions import Col
        from django.db.models.fields import Field
        # We need to do some faking of the ref resolution.
        # This essentially enables us to have a bit more complete
        # workings of F().

        # An interesting point to raise here is, we need to pass a Field in.
        # However, it doesn't need to be the "correct" field. At this point,
        # all conversion has been done, so now we just need to get a valid
        # target in.
        return Col(name, Field())
Example #13
0
def add_alias_constraints(queryset, alias, **kwargs):
    """ Add constraints to queryset, for given alias.
        Bypass high-level API to prevent ORM from creating a new JOIN.
        alias   - table name or alias to modify; must already be in query
        kwargs  - Django-style lookup=value conditions.
    """
    model, alias = alias
    clause = queryset.query.where_class()
    for lookup, value in kwargs.items():
        field_name, lookup = lookup.split('__')
        clause.add(queryset.query.build_lookup(
            [lookup],
            Col(alias, model._meta.get_field(field_name)),
            value
        ), AND)
    queryset.query.where.add(clause, AND)
Example #14
0
    def add_select(self, field_name, lookup_type, order='ASC'):
        """
        Converts the query into an extraction query.
        """
        try:
            field, _, _, joins, _ = self.setup_joins(
                field_name.split(LOOKUP_SEP),
                self.get_meta(),
                self.get_initial_alias(),
            )
        except FieldError:
            raise FieldDoesNotExist("%s has no field named '%s'" %
                                    (self.get_meta().object_name, field_name))
        self._check_field(field)  # overridden in DateTimeQuery
        alias = joins[-1]
        select = self._get_select(Col(alias, field), lookup_type)
        self.clear_select_clause()
        self.select = [SelectInfo(select, None)]
        self.distinct = True
        self.order_by = [1] if order == 'ASC' else [-1]

        if field.null:
            self.add_filter(("%s__isnull" % field_name, False))
Example #15
0
    def get_fields(self, query, keys_only=False):
        """
        Get the fields to select, this returns the SELECT -> XXX <- part

        This will also popular the 'fieldstrs' field

        :return: The list of fields to query, properly quoted, as a string
        """

        # Field names to place back into the database
        q = query
        pk_field = q.get_meta().pk
        opts = q.get_meta()
        self.pk_col_name = pk_field.column

        if q.distinct_fields:
            raise Exception("Can't handle distinct_fields yet")

        columns_str = []

        fields = []
        if not self.aggregate_only:
            if q.select:
                fields = q.select
            elif q.default_cols:
                fields = [Col('_dummy_', x, x) for x in opts.fields]

        # pprint(vars(q))
        for col in fields:
            field = col.output_field
            column = field.column

            # Get the document field to select.
            if column == pk_field.column:
                sel_field = 'META({}).id'.format(
                    n1ql_escape(BUCKET_PLACEHOLDER))
            elif keys_only:
                continue
            else:
                sel_field = n1ql_escape(column)

            # See if there's a lookup type.
            if hasattr(col, 'lookup_type'):
                # pprint(vars(q))
                col_alias = self._gen_alias()
                selstr, convfld = Transforms.transform(col.lookup_type,
                                                       sel_field)
                if q.distinct:
                    self._nopk_where = True
                    selstr = 'DISTINCT({0})'.format(selstr)
                selstr += ' AS ' + col_alias
                columns_str.append(selstr)
                self.queried_fields.append((col_alias, convfld))
            else:
                if column == pk_field.column:
                    columns_str.append(sel_field + ' AS ' + column)
                else:
                    columns_str.append(sel_field)

                self.queried_fields.append((column, field))

        for alias, annotation in q.annotation_select.items():
            colspec = annotation.input_field.value

            if not alias:
                alias = self._gen_alias()

            fn = annotation.function
            agstr = '{0}({1}) AS {2}'.format(fn, colspec, n1ql_escape(alias))
            self.queried_fields.append((alias, None))
            columns_str.append(agstr)

        columns_str += self.handle_extra_select(query)
        return ','.join(columns_str)
Example #16
0
 def get_col(self, alias, output_field=None):
     output_field = output_field or self.output_field
     return Col(alias, self, output_field)
Example #17
0
 def resolve_expression(self, query=None, *args, **kwargs):
     return Col(
         alias=self.row_alias,
         target=query.model._meta.get_field(self.col_name),
     )
Example #18
0
 def cached_col(self):
     from django.db.models.expressions import Col
     return Col(self.model._meta.db_table, self)
 def __init__(self, alias, target, output_field=None):
     super().__init__(alias, target, output_field)
     self.children = [Col(alias, key, output_field) for key in target.keys]