Contact: fumanchu@aminus.org

Log in as guest/geniusql to create tickets

root/trunk/geniusql/queries.py

Revision 310 (checked in by lakin, 4 months ago)

geniusql - fixing whitespcae

  • Property svn:eol-style set to native
Line 
1 from types import FunctionType
2
3 from geniusql import logic
4
5
6 __all__ = ['Join', 'Query', 'Statement']
7
8
9
10 class Query(object):
11     """A query with relation, attributes, and restriction expressions.
12
13     relation: Either a single Table object, or a Join (of Tables).
14     attributes:
15         SELECT:
16             If the relation is a single Table, this value must be a
17             sequence of column names for that Table. If the relation
18             is a Join, this must be a sequence of sequences of column
19             names. That is:
20                 [(table1.col1.name, table1.col2.name, ...),
21                  (table2.col1.name, ...),
22                  ...]
23             The order of sequences must match the order of tables given in
24             the relation (and therefore the restriction args, if applicable).
25             A final option is to pass a lambda (or Expression) which returns
26             the attributes as a tuple or list; e.g.:
27                 lambda t1, t2: (t1.a, t1.b - now(), t1.c + t2.a)
28             This allows access to binary operations and builtin functions.
29         INSERT/UPDATE:
30             If the relation is a single Table, this value must be a
31             dict whose keys are column names for that Table, and whose
32             values or either scalars or Expressions (or lambdas)
33             representing the new values for those columns. For example:
34                 {'Name': 'Ali Bayan',
35                  'Age': (lambda t: now() - t.Birthdate),
36                  ...
37                  }
38             If the relation is a Join, this must be a list of such dicts,
39             one per table, in the same order as the tables in the relation.
40         DELETE:
41             This should be a single empty list.
42     restriction: an Expression (or lambda) to restrict the rows returned;
43         if given, this will be used to construct a WHERE clause. The args
44         must be in the same order as the tables in the relation.
45     """
46
47     def __init__(self, relation, attributes, restriction=None):
48         self.relation = relation
49
50         if isinstance(attributes, FunctionType):
51             attributes = logic.Expression(attributes)
52         self.attributes = attributes
53
54         if restriction is None:
55             restriction = logic.Expression(lambda *args: True)
56         elif not isinstance(restriction, logic.Expression):
57             restriction = logic.Expression(restriction)
58         self.restriction = restriction
59
60     def from_genexp(cls, expr):
61         # this would allow consumers to write:
62         #     select(([t1.a, t1.b + t2.a] for t1, t2 in relation if t1.a > 13))
63         from geniusql import genexp
64         dep = genexp.GenexpParser(expr)
65         dep.verbose = True
66         dep.walk()
67
68         newq = cls(dep.relation, dep.attributes, dep.restriction)
69         return newq
70     from_genexp = classmethod(from_genexp)
71
72
73 class Join(object):
74     """A join between two tables."""
75
76     def __init__(self, table1, table2, leftbiased=None):
77         self.table1 = table1
78         self.table2 = table2
79         self.leftbiased = leftbiased
80         self.path = None
81
82     def __str__(self):
83         if self.leftbiased is None:
84             op = "&"
85         elif self.leftbiased is True:
86             op = "<<"
87         else:
88             op = ">>"
89         if isinstance(self.table1, Join):
90             name1 = str(self.table1)
91         elif isinstance(self.table1, type):
92             name1 = self.table1.__name__
93         else:
94             name1 = repr(self.table1)
95
96         if isinstance(self.table2, Join):
97             name2 = str(self.table2)
98         elif isinstance(self.table2, type):
99             name2 = self.table2.__name__
100         else:
101             name2 = repr(self.table2)
102
103         return "(%s %s %s)" % (name1, op, name2)
104     __repr__ = __str__
105
106     def __iter__(self):
107         return JoinIterator(self)
108
109     def __lshift__(self, other):
110         return Join(self, other, leftbiased=True)
111     __rrshift__ = __lshift__
112
113     def __rshift__(self, other):
114         return Join(self, other, leftbiased=False)
115     __rlshift__ = __rshift__
116
117     def __add__(self, other):
118         return Join(self, other)
119     __and__ = __add__
120
121     def __radd__(self, other):
122         return Join(other, self)
123     __rand__ = __radd__
124
125     def __eq__(self, other):
126         return (self.table1 == other.table1 and
127                 self.table2 == other.table2 and
128                 self.leftbiased == other.leftbiased and
129                 self.path == other.path)
130
131
132 class JoinIterator(object):
133
134     def __init__(self, join):
135         if isinstance(join.table1, Join):
136             t1 = list(join.table1)
137         else:
138             t1 = [join.table1]
139
140         if isinstance(join.table2, Join):
141             t2 = list(join.table2)
142         else:
143             t2 = [join.table2]
144
145         self.tableiter = iter(t1 + t2)
146
147     def __iter__(self):
148         return self
149
150     def next(self):
151         return self.tableiter.next()
152
153
154 class Statement(object):
155     """A relational statement, including query, order, limit, offset, and distinct.
156
157     query: a Query instance, or a tuple of arguments to form a Query.
158
159     order: if given, this will be used to construct an ORDER BY clause.
160         If the relation is a single Table, this value may be a sequence
161         of column names for the Table. If the relation is a Join, this must
162         be an Expression (or lambda) which returns a tuple or list of
163         attributes; the args must be in the same order as the tables in the
164         relation.
165     """
166
167     def __init__(self, query, order=None, limit=None, offset=None, distinct=None):
168         if not isinstance(query, Query):
169             query = Query(*query)
170         self.query = query
171
172         self.order = order
173         self.limit = limit
174         self.offset = offset
175         self.distinct = distinct
176
Note: See TracBrowser for help on using the browser.