|
2 | 2 |
|
3 | 3 |
|
4 | 4 | def render_query(dataset, tables, select=None, conditions=None,
|
5 |
| - groupings=None, order_by=None): |
| 5 | + groupings=None, having=None, order_by=None): |
6 | 6 | """Render a query that will run over the given tables using the specified
|
7 | 7 | parameters.
|
8 | 8 |
|
@@ -46,12 +46,13 @@ def render_query(dataset, tables, select=None, conditions=None,
|
46 | 46 | if None in (dataset, tables):
|
47 | 47 | return None
|
48 | 48 |
|
49 |
| - query = "%s %s %s %s %s" % ( |
| 49 | + query = "%s %s %s %s %s %s" % ( |
50 | 50 | _render_select(select),
|
51 | 51 | _render_sources(dataset, tables),
|
52 | 52 | _render_conditions(conditions),
|
53 | 53 | _render_groupings(groupings),
|
54 |
| - _render_order(order_by), |
| 54 | + _render_having(having), |
| 55 | + _render_order(order_by) |
55 | 56 | )
|
56 | 57 |
|
57 | 58 | return query
|
@@ -85,7 +86,7 @@ def _render_select(selections):
|
85 | 86 | for options_dict in options:
|
86 | 87 | name = original_name
|
87 | 88 | alias = options_dict.get('alias')
|
88 |
| - alias = "as %s" % alias if alias else "" |
| 89 | + alias = "AS %s" % alias if alias else "" |
89 | 90 |
|
90 | 91 | formatter = options_dict.get('format')
|
91 | 92 | if formatter:
|
@@ -133,8 +134,20 @@ def _render_sources(dataset, tables):
|
133 | 134 | a string that represents the from part of a query.
|
134 | 135 | """
|
135 | 136 |
|
136 |
| - return "FROM " + ", ".join( |
137 |
| - ["[%s.%s]" % (dataset, table) for table in tables]) |
| 137 | + if isinstance(tables, dict): |
| 138 | + if tables['date_range']: |
| 139 | + try: |
| 140 | + dataset_table = '.'.join([dataset, tables['table']]) |
| 141 | + return "FROM (TABLE_DATE_RANGE([{}], TIMESTAMP('{}'),"\ |
| 142 | + " TIMESTAMP('{}'))) ".format(dataset_table, |
| 143 | + tables['from_date'], |
| 144 | + tables['to_date']) |
| 145 | + except KeyError as exp: |
| 146 | + raise Exception('Missing parameter %s' % (exp)) |
| 147 | + |
| 148 | + else: |
| 149 | + return "FROM " + ", ".join( |
| 150 | + ["[%s.%s]" % (dataset, table) for table in tables]) |
138 | 151 |
|
139 | 152 |
|
140 | 153 | def _render_conditions(conditions):
|
@@ -206,6 +219,12 @@ def _render_condition(field, field_type, comparators):
|
206 | 219 | else:
|
207 | 220 | value = _render_condition_value(value, field_type)
|
208 | 221 | value = "(" + value + ")"
|
| 222 | + elif condition == "BETWEEN": |
| 223 | + if isinstance(value, (tuple, list)): |
| 224 | + value = ' AND '.join( |
| 225 | + sorted([_render_condition_value(v, field_type) |
| 226 | + for v in value]) |
| 227 | + ) |
209 | 228 | else:
|
210 | 229 | value = _render_condition_value(value, field_type)
|
211 | 230 |
|
@@ -242,25 +261,40 @@ def _render_condition_value(value, field_type):
|
242 | 261 | value = 1 if value else 0
|
243 | 262 | elif field_type in ("STRING", "INTEGER", "FLOAT"):
|
244 | 263 | value = "'%s'" % (value)
|
| 264 | + elif field_type in ("TIMESTAMP"): |
| 265 | + value = "'%s'" % (str(value)) |
245 | 266 | return "%s(%s)" % (field_type, value)
|
246 | 267 |
|
247 | 268 |
|
| 269 | +def _render_having(having): |
| 270 | + """Render the having part of a query. |
| 271 | +
|
| 272 | + Args: |
| 273 | + having: accepts the having query as it is. |
| 274 | +
|
| 275 | + Returns: |
| 276 | + a string that represents the having part of a query. |
| 277 | + """ |
| 278 | + |
| 279 | + return "HAVING %s" % (having) if having else "" |
| 280 | + |
| 281 | + |
248 | 282 | def _render_order(order):
|
249 | 283 | """Render the order by part of a query.
|
250 | 284 |
|
251 | 285 | Args:
|
252 | 286 | order: a dictionary with two keys, field and direction.
|
253 | 287 | Such that the dictionary should be formatted as
|
254 |
| - {'field':'TimeStamp, 'direction':'desc'}. |
| 288 | + {'fields': ['TimeStamp'], 'direction':'desc'}. |
255 | 289 |
|
256 | 290 | Returns:
|
257 | 291 | a string that represents the order by part of a query.
|
258 | 292 | """
|
259 | 293 |
|
260 |
| - if not order or 'field' not in order or 'direction' not in order: |
| 294 | + if not order or 'fields' not in order or 'direction' not in order: |
261 | 295 | return ''
|
262 | 296 |
|
263 |
| - return "ORDER BY %s %s" % (order['field'], order['direction']) |
| 297 | + return "ORDER BY %s %s" % (", ".join(order['fields']), order['direction']) |
264 | 298 |
|
265 | 299 |
|
266 | 300 | def _render_groupings(fields):
|
|
0 commit comments