X-Git-Url: https://git.stderr.nl/gitweb?p=matthijs%2Fupstream%2Fdjango-ldapdb.git;a=blobdiff_plain;f=ldapdb%2Fmodels%2Fquery.py;h=e84748c4ee00a35475d34e913e4824ed70a88cbe;hp=7346608505d888c759e0ace78beb0f8734cc612f;hb=8174a9ef106740eb32151e47dad21a999f70b595;hpb=56baef02291c62a08688253b860cd9093cbcd6e0 diff --git a/ldapdb/models/query.py b/ldapdb/models/query.py index 7346608..e84748c 100644 --- a/ldapdb/models/query.py +++ b/ldapdb/models/query.py @@ -1,99 +1,95 @@ # -*- coding: utf-8 -*- # # django-ldapdb -# Copyright (C) 2009 Bolloré telecom +# Copyright (c) 2009-2010, Bolloré telecom +# All rights reserved. +# # See AUTHORS file for a full list of contributors. # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. +# 3. Neither the name of Bolloré telecom nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # -# -*- coding: utf-8 -*- - from copy import deepcopy import ldap +from django.db import connections from django.db.models.query import QuerySet as BaseQuerySet from django.db.models.query_utils import Q -from django.db.models.sql import BaseQuery -from django.db.models.sql.where import WhereNode as BaseWhereNode, AND, OR +from django.db.models.sql import Query +from django.db.models.sql.where import WhereNode as BaseWhereNode, Constraint as BaseConstraint, AND, OR -import ldapdb +from ldapdb.backends.ldap import compiler +from ldapdb.models.fields import CharField -class WhereNode(BaseWhereNode): - def as_sql(self): - bits = [] - for item in self.children: - if isinstance(item, WhereNode): - bits.append(item.as_sql()) - continue - table, column, type, x, y, values = item - if self.negated: - bits.append('(!(%s=%s))' % (column,values[0])) - else: - bits.append('(%s=%s)' % (column,values[0])) - if len(bits) == 1: - return bits[0] - elif self.connector == AND: - return '(&%s)' % ''.join(bits) - elif self.connector == OR: - return '(|%s)' % ''.join(bits) - else: - raise Exception("Unhandled WHERE connector: %s" % self.connector) +class Constraint(BaseConstraint): + """ + An object that can be passed to WhereNode.add() and knows how to + pre-process itself prior to including in the WhereNode. -class Query(BaseQuery): - def results_iter(self): - # FIXME: use all object classes - filterstr = '(objectClass=%s)' % self.model._meta.object_classes[0] - filterstr += self.where.as_sql() - filterstr = '(&%s)' % filterstr - attrlist = [ x.db_column for x in self.model._meta.local_fields if x.db_column ] + NOTES: + - we redefine this class, because when self.field is None calls + Field().get_db_prep_lookup(), which short-circuits our LDAP-specific code. + """ + def process(self, lookup_type, value, connection): + """ + Returns a tuple of data suitable for inclusion in a WhereNode + instance. + """ + # Because of circular imports, we need to import this here. + from django.db.models.base import ObjectDoesNotExist try: - vals = ldapdb.connection.search_s( - self.model._meta.dn, - ldap.SCOPE_SUBTREE, - filterstr=filterstr, - attrlist=attrlist, - ) - except: - raise self.model.DoesNotExist + if self.field: + params = self.field.get_db_prep_lookup(lookup_type, value, + connection=connection, prepared=True) + db_type = self.field.db_type() + else: + params = CharField().get_db_prep_lookup(lookup_type, value, + connection=connection, prepared=True) + db_type = None + except ObjectDoesNotExist: + raise EmptyShortCircuit - # perform sorting - if self.extra_order_by: - ordering = self.extra_order_by - elif not self.default_ordering: - ordering = self.order_by - else: - ordering = self.order_by or self.model._meta.ordering - def getkey(x): - keys = [] - for k in ordering: - attr = self.model._meta.get_field(k).db_column - keys.append(x[1][attr]) - return keys - vals = sorted(vals, key=lambda x: getkey(x)) + return (self.alias, self.col, db_type), params + +class WhereNode(BaseWhereNode): + def add(self, data, connector): + if not isinstance(data, (list, tuple)): + super(WhereNode, self).add(data, connector) + return - # process results - for dn, attrs in vals: - row = [dn] - for field in iter(self.model._meta.fields): - row.append(attrs.get(field.db_column, None)) - yield row + # we replace the native Constraint by our own + obj, lookup_type, value = data + if hasattr(obj, "process"): + obj = Constraint(obj.alias, obj.col, obj.field) + super(WhereNode, self).add((obj, lookup_type, value), connector) class QuerySet(BaseQuerySet): - def __init__(self, model=None, query=None): + def __init__(self, model=None, query=None, using=None): if not query: - query = Query(model, None, WhereNode) - super(QuerySet, self).__init__(model, query) + query = Query(model, WhereNode) + super(QuerySet, self).__init__(model=model, query=query, using=using)