Project

General

Profile

« Previous | Next » 

Revision 2260

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.

View differences:

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