1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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
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
55 args = []
56
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
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