Package Camelot :: Package camelot :: Package view :: Module search |
[frames] | no frames]

# Source Code for Module Camelot.camelot.view.search

      1  #  ============================================================================
      2  #
      3  #  Copyright (C) 2007-2008 Conceptive Engineering bvba. All rights reserved.
      4  #  www.conceptive.be / project-camelot@conceptive.be
      5  #
      6  #  This file is part of the Camelot Library.
      7  #
      8  #  This file may be used under the terms of the GNU General Public
      9  #  License version 2.0 as published by the Free Software Foundation
     10  #  and appearing in the file LICENSE.GPL included in the packaging of
     11  #  this file.  Please review the following information to ensure GNU
     12  #  General Public Licensing requirements will be met:
     13  #  http://www.trolltech.com/products/qt/opensource.html
     14  #
     15  #  If you are unsure which license is appropriate for your use, please
     16  #  review the following information:
     17  #  http://www.trolltech.com/products/qt/licensing.html or contact
     18  #  project-camelot@conceptive.be.
     19  #
     20  #  This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
     21  #  WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
     22  #
     23  #  For use of this library in commercial applications, please contact
     24  #  project-camelot@conceptive.be
     25  #
     26  #  ============================================================================
     27
     28  """
     29  Helper functions to search through a collection of entities
     30  """
     31  import logging
     32
     33  logger = logging.getLogger('camelot.view.search')
     34
     35  import sqlalchemy.types
     36  from sqlalchemy.sql import operators
     37
     38  import camelot.types
     39
     40 -def create_entity_search_query_decorator(admin, text):
     41      """create a query decorator to search through a collection of entities
     42      @param admin: the admin interface of the entity
     43      @param text: the text to search for
     44      @return: a function that can be applied to a query to make the query filter
     45      only the objects related to the requested text or None if no such decorator
     46      could be build
     47      """
     48      from elixir import entities
     49      from sqlalchemy import orm, sql
     50      from camelot.view import utils
     51
     52      if len(text.strip()):
     53          from sqlalchemy import Unicode, or_
     54          # arguments for the where clause
     55          args = []
     56          # join conditions : list of join entities
     57          joins = []
     58          search_tables = [admin.entity.table]
     59          for entity in entities:
     60              if issubclass(admin.entity, entity):
     61                  search_tables.append(entity.table)
     62
     63          def append_column(c):
     64              if issubclass(c.type.__class__, camelot.types.Color):
     65                  pass
     66              elif issubclass(c.type.__class__, camelot.types.File):
     67                  pass
     68              elif issubclass(c.type.__class__, camelot.types.Code):
     69                  codes = text.split(c.type.separator)
     70                  args.append(c.like(['%'] + codes + ['%']))
     71                  args.append(c.like(['%'] + codes))
     72                  args.append(c.like(codes + ['%']))
     73              elif issubclass(c.type.__class__, camelot.types.VirtualAddress):
     74                  args.append(c.like(('%','%'+text+'%')))
     75              elif issubclass(c.type.__class__, camelot.types.Image):
     76                  pass
     77              elif issubclass(c.type.__class__, sqlalchemy.types.Integer):
     78                  try:
     79                      args.append(c==utils.int_from_string(text))
     80                  except Exception, utils.ParsingError:
     81                      pass
     82              elif issubclass(c.type.__class__, sqlalchemy.types.Date):
     83                  try:
     84                      args.append(c==utils.date_from_string(text))
     85                  except Exception, utils.ParsingError:
     86                      pass
     87              elif issubclass(c.type.__class__, sqlalchemy.types.Float):
     88                  try:
     89                      float_value = utils.float_from_string(text)
     90                      precision = c.type.precision
     91                      if isinstance(precision, (tuple)):
     92                          precision = precision[1]
     93                      delta = 0.1**precision
     94                      args.append(sql.and_(c>=float_value-delta, c<=float_value+delta))
     95                  except Exception, utils.ParsingError:
     96                      pass
     97              elif issubclass(c.type.__class__, (Unicode, )) or \
     98                              (hasattr(c.type, 'impl') and \
     99                               issubclass(c.type.impl.__class__, (Unicode, ))):
    100                  logger.debug('look in column : %s'%c.name)
    101                  args.append(operators.ilike_op(c, '%'+text+'%'))
    102
    103          for table in search_tables:
    104              for c in table._columns:
    105                  append_column(c)
    106
    107          for column_name in admin.list_search:
    108              path = column_name.split('.')
    109              target = admin.entity
    110              for p in path:
    111                  mapper = orm.class_mapper(target)
    112                  property = mapper.get_property(p, resolve_synonyms=True)
    113                  if isinstance(property, orm.properties.PropertyLoader):
    114                      joins.append(getattr(target, p))
    115                      target = property._get_target().class_
    116                  else:
    117                      append_column(property.columns[0])
    118                      #args.append(property.columns[0].like('%'+text+'%'))
    119
    120          def create_query_decorator(joins, args):
    121
    122              def query_decorator(q):
    123                  for join in joins:
    124                      q = q.join(join)
    125                  if len(args):
    126                      if len(args)>1:
    127                          q = q.filter(or_(*args))
    128                      else:
    129                          q = q.filter(args[0])
    130                  return q
    131
    132              return query_decorator
    133
    134          return create_query_decorator(joins, args)
    135