def test_get_cast_for_param(self):
     self.assertEqual(get_cast_for_param([], 'a'), '')
     self.assertEqual(get_cast_for_param({'a': True}, 'a'), '::boolean')
     self.assertEqual(get_cast_for_param({'a': datetime.datetime}, 'a'), '::timestamp')
     self.assertEqual(get_cast_for_param({'a': datetime.time}, 'a'), '::time')
     self.assertEqual(get_cast_for_param({'a': int}, 'a'), '::bigint')
     self.assertEqual(get_cast_for_param({'a': float}, 'a'), '::float8')
     from decimal import Decimal
     self.assertEqual(get_cast_for_param({'a': Decimal}, 'a'), '::numeric')
Пример #2
0
    def as_postgresql(self, compiler, connection):
        lhs, lhs_params = self.process_lhs(compiler, connection)
        rhs, rhs_params = self.process_rhs(compiler, connection)
        if len(rhs_params) == 1 and isinstance(rhs_params[0], dict):
            param = rhs_params[0]
            sign = (self.lookup_name[0] == 'g' and '>%s' or '<%s') % (self.lookup_name[-1] == 'e' and '=' or '')
            param_keys = list(param.keys())
            conditions = []

            for key in param_keys:
                cast = get_cast_for_param(self.value_annot, key)
                conditions.append('(%s->\'%s\')%s %s %%s' % (lhs, key, cast, sign))

            return (" AND ".join(conditions), param.values())

        raise ValueError('invalid value')
Пример #3
0
    def as_postgresql(self, qn, connection):
        lhs, lhs_params = self.process_lhs(qn, connection)
        rhs, rhs_params = self.process_rhs(qn, connection)
        if len(rhs_params) == 1 and isinstance(rhs_params[0], dict):
            param = rhs_params[0]
            sign = (self.lookup_name[0] == 'g' and '>%s'
                    or '<%s') % (self.lookup_name[-1] == 'e' and '=' or '')
            param_keys = list(param.keys())
            conditions = []

            for key in param_keys:
                cast = get_cast_for_param(self.value_annot, key)
                conditions.append('(%s->\'%s\')%s %s %%s' %
                                  (lhs, key, cast, sign))

            return (" AND ".join(conditions), param.values())

        raise ValueError('invalid value')
Пример #4
0
    def as_postgresql(self, compiler, connection):
        lhs, lhs_params = self.process_lhs(compiler, connection)
        # FIXME: ::text cast is added by ``django.db.backends.postgresql_psycopg2.DatabaseOperations.lookup_cast``;
        # maybe there's a cleaner way to fix the cast for hstore columns
        if lhs.endswith('::text'):
            lhs = '{0}{1}'.format(lhs[:-4], 'hstore')
        param = self.rhs

        if isinstance(param, dict):
            values = list(param.values())
            keys = list(param.keys())
            if len(values) == 1 and isinstance(values[0], (list, tuple)):
                # Can't cast here because the list could contain multiple types
                return '%s->\'%s\' = ANY(%%s)' % (lhs, keys[0]), [[
                    str(x) for x in values[0]
                ]]
            elif len(keys) == 1 and len(values) == 1:
                # Retrieve key and compare to param instead of using '@>' in order to cast hstore value
                cast = get_cast_for_param(self.value_annot, keys[0])
                return ('(%s->\'%s\')%s = %%s' % (lhs, keys[0], cast),
                        [values[0]])
            return '%s @> %%s' % lhs, [param]
        elif isinstance(param, (list, tuple)):
            if len(param) == 0:
                raise ValueError('invalid value')
            if len(param) < 2:
                return '%s ? %%s' % lhs, [param[0]]
            if param:
                return '%s ?& %%s' % lhs, [param]
        elif isinstance(param, six.string_types):
            # if looking for a string perform the normal text lookup
            # that is: look for occurence of string in all the keys
            pass
        # needed for SerializedDictionaryField
        elif hasattr(self.lhs.target, 'serializer'):
            try:
                self.lhs.target._serialize_value(param)
                pass
            except Exception:
                raise ValueError('invalid value')
        else:
            raise ValueError('invalid value')
        return super(HStoreContains, self).as_sql(compiler, connection)
Пример #5
0
    def as_postgresql(self, compiler, connection):
        lhs, lhs_params = self.process_lhs(compiler, connection)
        # FIXME: ::text cast is added by ``django.db.backends.postgresql_psycopg2.DatabaseOperations.lookup_cast``;
        # maybe there's a cleaner way to fix the cast for hstore columns
        if lhs.endswith('::text'):
            lhs = '{0}{1}'.format(lhs[:-4], 'hstore')
        param = self.rhs

        if isinstance(param, dict):
            values = list(param.values())
            keys = list(param.keys())
            if len(values) == 1 and isinstance(values[0], (list, tuple)):
                # Can't cast here because the list could contain multiple types
                return '%s->\'%s\' = ANY(%%s)' % (lhs, keys[0]), [[str(x) for x in values[0]]]
            elif len(keys) == 1 and len(values) == 1:
                # Retrieve key and compare to param instead of using '@>' in order to cast hstore value
                cast = get_cast_for_param(self.value_annot, keys[0])
                return ('(%s->\'%s\')%s = %%s' % (lhs, keys[0], cast), [values[0]])
            return '%s @> %%s' % lhs, [param]
        elif isinstance(param, (list, tuple)):
            if len(param) == 0:
                raise ValueError('invalid value')
            if len(param) < 2:
                return '%s ? %%s' % lhs, [param[0]]
            if param:
                return '%s ?& %%s' % lhs, [param]
        elif isinstance(param, six.string_types):
            # if looking for a string perform the normal text lookup
            # that is: look for occurence of string in all the keys
            pass
        # needed for SerializedDictionaryField
        elif hasattr(self.lhs.target, 'serializer'):
            try:
                self.lhs.target._serialize_value(param)
                pass
            except Exception:
                raise ValueError('invalid value')
        else:
            raise ValueError('invalid value')
        return super(HStoreContains, self).as_sql(compiler, connection)
Пример #6
0
    def make_atom(self, child, qn, connection):
        lvalue, lookup_type, value_annot, param = child
        kwargs = {'connection': connection}

        if lvalue and lvalue.field and hasattr(
                lvalue.field,
                'db_type') and lvalue.field.db_type(**kwargs) == 'hstore':
            try:
                lvalue, params = lvalue.process(lookup_type, param, connection)
            except EmptyShortCircuit:
                raise EmptyResultSet()
            field = self.sql_for_columns(lvalue, qn, connection)

            if lookup_type == 'exact':
                if isinstance(param, dict):
                    return ('{0} = %s'.format(field), [param])
                raise ValueError('invalid value')
            elif lookup_type in ('gt', 'gte', 'lt', 'lte'):
                if isinstance(param, dict):
                    sign = (lookup_type[0] == 'g' and '>%s'
                            or '<%s') % (lookup_type[-1] == 'e' and '=' or '')
                    param_keys = list(param.keys())
                    conditions = []
                    for key in param_keys:
                        cast = get_cast_for_param(value_annot, key)
                        conditions.append('(%s->\'%s\')%s %s %%s' %
                                          (field, key, cast, sign))
                    return (" AND ".join(conditions), param.values())
                raise ValueError('invalid value')
            elif lookup_type in ['contains', 'icontains']:
                if isinstance(param, dict):
                    values = list(param.values())
                    keys = list(param.keys())
                    if len(values) == 1 and isinstance(values[0],
                                                       (list, tuple)):
                        # Can't cast here because the list could contain multiple types
                        return ('%s->\'%s\' = ANY(%%s)' % (field, keys[0]),
                                [[str(x) for x in values[0]]])
                    elif len(keys) == 1 and len(values) == 1:
                        # Retrieve key and compare to param instead of using '@>' in order to cast hstore value
                        cast = get_cast_for_param(value_annot, keys[0])
                        return ('(%s->\'%s\')%s = %%s' %
                                (field, keys[0], cast), [values[0]])
                    return ('%s @> %%s' % field, [param])
                elif isinstance(param, (list, tuple)):
                    if len(param) == 0:
                        raise ValueError('invalid value')
                    if len(param) < 2:
                        return ('%s ? %%s' % field, [param[0]])
                    if param:
                        return ('%s ?& %%s' % field, [param])
                    raise ValueError('invalid value')
                elif isinstance(param, six.string_types):
                    # if looking for a string perform the normal text lookup
                    # that is: look for occurence of string in all the keys
                    pass
                elif hasattr(child[0].field, 'serializer'):
                    try:
                        child[0].field._serialize_value(param)
                        pass
                    except Exception:
                        raise ValueError('invalid value')
                else:
                    raise ValueError('invalid value')
            elif lookup_type == 'isnull':
                if isinstance(param, dict):
                    param_keys = list(param.keys())
                    conditions = []
                    for key in param_keys:
                        op = 'IS NULL' if value_annot[key] else 'IS NOT NULL'
                        conditions.append('(%s->\'%s\') %s' % (field, key, op))
                    return (" AND ".join(conditions), [])
                # do not perform any special format
                return super(HStoreWhereNode,
                             self).make_atom(child, qn, connection)
            else:
                raise TypeError('invalid lookup type')
        return super(HStoreWhereNode, self).make_atom(child, qn, connection)
Пример #7
0
    def make_atom(self, child, qn, connection):
        lvalue, lookup_type, value_annot, param = child
        kwargs = {'connection': connection} if VERSION[:2] >= (1, 3) else {}

        if lvalue and lvalue.field and hasattr(lvalue.field, 'db_type') and lvalue.field.db_type(**kwargs) == 'hstore':
            try:
                lvalue, params = lvalue.process(lookup_type, param, connection)
            except EmptyShortCircuit:
                raise EmptyResultSet()
            field = self.sql_for_columns(lvalue, qn, connection)

            if lookup_type == 'exact':
                if isinstance(param, dict):
                    return ('{0} = %s'.format(field), [param])
                raise ValueError('invalid value')
            elif lookup_type in ('gt', 'gte', 'lt', 'lte'):
                if isinstance(param, dict):
                    sign = (lookup_type[0] == 'g' and '>%s' or '<%s') % (lookup_type[-1] == 'e' and '=' or '')
                    param_keys = list(param.keys())
                    conditions = []
                    for key in param_keys:
                        cast = get_cast_for_param(value_annot, key)
                        conditions.append('(%s->\'%s\')%s %s %%s' % (field, key, cast, sign))
                    return (" AND ".join(conditions), param.values())
                raise ValueError('invalid value')
            elif lookup_type in ['contains', 'icontains']:
                if isinstance(param, dict):
                    values = list(param.values())
                    keys = list(param.keys())
                    if len(values) == 1 and isinstance(values[0], (list, tuple)):
                        # Can't cast here because the list could contain multiple types
                        return ('%s->\'%s\' = ANY(%%s)' % (field, keys[0]), [[str(x) for x in values[0]]])
                    elif len(keys) == 1 and len(values) == 1:
                        # Retrieve key and compare to param instead of using '@>' in order to cast hstore value
                        cast = get_cast_for_param(value_annot, keys[0])
                        return ('(%s->\'%s\')%s = %%s' % (field, keys[0], cast), [values[0]])
                    return ('%s @> %%s' % field, [param])
                elif isinstance(param, (list, tuple)):
                    if len(param) == 0:
                        raise ValueError('invalid value')
                    if len(param) < 2:
                        return ('%s ? %%s' % field, [param[0]])
                    if param:
                        return ('%s ?& %%s' % field, [param])
                    raise ValueError('invalid value')
                elif isinstance(param, six.string_types):
                    # if looking for a string perform the normal text lookup
                    # that is: look for occurence of string in all the keys
                    pass
                elif hasattr(child[0].field, 'serializer'):
                    try:
                        child[0].field._serialize_value(param)
                        pass
                    except Exception:
                        raise ValueError('invalid value')
                else:
                    raise ValueError('invalid value')
            elif lookup_type == 'isnull':
                if isinstance(param, dict):
                    param_keys = list(param.keys())
                    conditions = []
                    for key in param_keys:
                        op = 'IS NULL' if value_annot[key] else 'IS NOT NULL'
                        conditions.append('(%s->\'%s\') %s' % (field, key, op))
                    return (" AND ".join(conditions), [])
                # do not perform any special format
                return super(HStoreWhereNode, self).make_atom(child, qn, connection)
            else:
                raise TypeError('invalid lookup type')
        return super(HStoreWhereNode, self).make_atom(child, qn, connection)
Пример #8
0
    def make_atom(self, child, qn, connection):
        lvalue, lookup_type, value_annot, param = child
        kwargs = {"connection": connection}

        if lvalue and lvalue.field and hasattr(lvalue.field, "db_type") and lvalue.field.db_type(**kwargs) == "hstore":
            try:
                lvalue, params = lvalue.process(lookup_type, param, connection)
            except EmptyShortCircuit:
                raise EmptyResultSet()
            field = self.sql_for_columns(lvalue, qn, connection)

            if lookup_type == "exact":
                if isinstance(param, dict):
                    return ("{0} = %s".format(field), [param])
                raise ValueError("invalid value")
            elif lookup_type in ("gt", "gte", "lt", "lte"):
                if isinstance(param, dict):
                    sign = (lookup_type[0] == "g" and ">%s" or "<%s") % (lookup_type[-1] == "e" and "=" or "")
                    param_keys = list(param.keys())
                    conditions = []
                    for key in param_keys:
                        cast = get_cast_for_param(value_annot, key)
                        conditions.append("(%s->'%s')%s %s %%s" % (field, key, cast, sign))
                    return (" AND ".join(conditions), param.values())
                raise ValueError("invalid value")
            elif lookup_type in ["contains", "icontains"]:
                if isinstance(param, dict):
                    values = list(param.values())
                    keys = list(param.keys())
                    if len(values) == 1 and isinstance(values[0], (list, tuple)):
                        # Can't cast here because the list could contain multiple types
                        return ("%s->'%s' = ANY(%%s)" % (field, keys[0]), [[str(x) for x in values[0]]])
                    elif len(keys) == 1 and len(values) == 1:
                        # Retrieve key and compare to param instead of using '@>' in order to cast hstore value
                        cast = get_cast_for_param(value_annot, keys[0])
                        return ("(%s->'%s')%s = %%s" % (field, keys[0], cast), [values[0]])
                    return ("%s @> %%s" % field, [param])
                elif isinstance(param, (list, tuple)):
                    if len(param) == 0:
                        raise ValueError("invalid value")
                    if len(param) < 2:
                        return ("%s ? %%s" % field, [param[0]])
                    if param:
                        return ("%s ?& %%s" % field, [param])
                    raise ValueError("invalid value")
                elif isinstance(param, six.string_types):
                    # if looking for a string perform the normal text lookup
                    # that is: look for occurence of string in all the keys
                    pass
                elif hasattr(child[0].field, "serializer"):
                    try:
                        child[0].field._serialize_value(param)
                        pass
                    except Exception:
                        raise ValueError("invalid value")
                else:
                    raise ValueError("invalid value")
            elif lookup_type == "isnull":
                if isinstance(param, dict):
                    param_keys = list(param.keys())
                    conditions = []
                    for key in param_keys:
                        op = "IS NULL" if value_annot[key] else "IS NOT NULL"
                        conditions.append("(%s->'%s') %s" % (field, key, op))
                    return (" AND ".join(conditions), [])
                # do not perform any special format
                return super(HStoreWhereNode, self).make_atom(child, qn, connection)
            else:
                raise TypeError("invalid lookup type")
        return super(HStoreWhereNode, self).make_atom(child, qn, connection)