Revision 2260
Added by Aaron Marcuse-Kubitza over 12 years ago
lib/sql_gen.py | ||
---|---|---|
57 | 57 |
str_ += sql.esc_name(db, self.name) |
58 | 58 |
return str_ |
59 | 59 |
|
60 |
def as_Col(col, table=None): |
|
61 |
if col == None or isinstance(col, Code): return col |
|
62 |
else: return Col(col, table) |
|
63 |
|
|
60 | 64 |
class NamedCode(Code): |
61 | 65 |
def __init__(self, name, code): |
62 | 66 |
if not isinstance(code, Code): code = Literal(code) |
... | ... | |
115 | 119 |
if neg_ref[0]: str_ = 'NOT ('+str_+')' |
116 | 120 |
return str_ |
117 | 121 |
|
118 |
def as_ValueCond(value): |
|
119 |
if not isinstance(value, ValueCond): return CompareCond(value) |
|
122 |
# Tells as_ValueCond() to assume a non-ValueCond is a literal value |
|
123 |
assume_literal = object() |
|
124 |
|
|
125 |
def as_ValueCond(value, default_table=assume_literal): |
|
126 |
if not isinstance(value, ValueCond): |
|
127 |
if default_table is not assume_literal: |
|
128 |
value = as_Col(value, default_table) |
|
129 |
return CompareCond(value) |
|
120 | 130 |
else: return value |
121 | 131 |
|
132 |
join_using = object() # tells Join to join the column with USING |
|
133 |
|
|
134 |
filter_out = object() # tells Join to filter out rows that match the join |
|
135 |
|
|
136 |
class Join(Code): |
|
137 |
def __init__(self, table, mapping, type_=None): |
|
138 |
''' |
|
139 |
@param mapping dict(right_table_col=left_table_col, ...) |
|
140 |
* if left_table_col is join_using: left_table_col = right_table_col |
|
141 |
@param type_ None (for plain join)|str (e.g. 'LEFT')|filter_out |
|
142 |
* filter_out: equivalent to 'LEFT' with the query filtered by |
|
143 |
`table_pkey IS NULL` (indicating no match) |
|
144 |
''' |
|
145 |
if util.is_str(table): table = Table(table) |
|
146 |
assert type_ == None or util.is_str(type_) or type_ is filter_out |
|
147 |
|
|
148 |
self.table = table |
|
149 |
self.mapping = mapping |
|
150 |
self.type_ = type_ |
|
151 |
|
|
152 |
def to_str(self, db, left_table): |
|
153 |
def join(entry): |
|
154 |
'''Parses non-USING joins''' |
|
155 |
right_table_col, left_table_col = entry |
|
156 |
|
|
157 |
# Parse special values |
|
158 |
if left_table_col is join_using: left_table_col = right_table_col |
|
159 |
|
|
160 |
cond = as_ValueCond(right_table_col, self.table) |
|
161 |
return cond.to_str(db, as_Col(left_table_col, left_table)) |
|
162 |
|
|
163 |
# Create join condition and determine join type |
|
164 |
if reduce(operator.and_, (v is join_using for v in joins.itervalues())): |
|
165 |
# all cols w/ USING, so can use simpler USING syntax |
|
166 |
join_cond = 'USING ('+(', '.join(joins.iterkeys()))+')' |
|
167 |
else: join_cond = 'ON '+(' AND '.join(map(join, joins.iteritems()))) |
|
168 |
|
|
169 |
# Create join |
|
170 |
type_ = self.type_ |
|
171 |
if type_ is filter_out: type_ = 'LEFT' |
|
172 |
return type_+' JOIN '+table+' '+join_cond |
|
173 |
|
|
122 | 174 |
##### Old-style format support |
123 | 175 |
|
124 | 176 |
def unescape_table(table): |
Also available in: Unified diff
sql_gen.py: Added as_Col(). as_ValueCond(): Added support for assuming the value is a column rather than a literal value, using the default_table param. Added Join.