1 | import datetime |
---|
2 | from .._compat import integer_types, basestring, string_types |
---|
3 | from ..adapters.base import SQLAdapter |
---|
4 | from ..helpers.methods import use_common_filters |
---|
5 | from ..objects import Expression, Field, Table, Select |
---|
6 | from . import Dialect, dialects, sqltype_for |
---|
7 | |
---|
8 | long = integer_types[-1] |
---|
9 | |
---|
10 | |
---|
11 | class CommonDialect(Dialect): |
---|
12 | quote_template = "%s" |
---|
13 | |
---|
14 | def _force_bigints(self): |
---|
15 | if "big-id" in self.types and "reference" in self.types: |
---|
16 | self.types["id"] = self.types["big-id"] |
---|
17 | self.types["reference"] = self.types["big-reference"] |
---|
18 | |
---|
19 | def quote(self, val): |
---|
20 | return self.quote_template % val |
---|
21 | |
---|
22 | def varquote(self, val): |
---|
23 | return val |
---|
24 | |
---|
25 | def sequence_name(self, tablename): |
---|
26 | return self.quote("%s_sequence" % tablename) |
---|
27 | |
---|
28 | def trigger_name(self, tablename): |
---|
29 | return "%s_sequence" % tablename |
---|
30 | |
---|
31 | def coalesce_zero(self, val, query_env={}): |
---|
32 | return self.coalesce(val, [0], query_env) |
---|
33 | |
---|
34 | |
---|
35 | @dialects.register_for(SQLAdapter) |
---|
36 | class SQLDialect(CommonDialect): |
---|
37 | quote_template = '"%s"' |
---|
38 | true = "T" |
---|
39 | false = "F" |
---|
40 | true_exp = "1" |
---|
41 | false_exp = "0" |
---|
42 | dt_sep = " " |
---|
43 | |
---|
44 | @sqltype_for("string") |
---|
45 | def type_string(self): |
---|
46 | return "VARCHAR(%(length)s)" |
---|
47 | |
---|
48 | @sqltype_for("boolean") |
---|
49 | def type_boolean(self): |
---|
50 | return "CHAR(1)" |
---|
51 | |
---|
52 | @sqltype_for("text") |
---|
53 | def type_text(self): |
---|
54 | return "TEXT" |
---|
55 | |
---|
56 | @sqltype_for("json") |
---|
57 | def type_json(self): |
---|
58 | return self.types["text"] |
---|
59 | |
---|
60 | @sqltype_for("password") |
---|
61 | def type_password(self): |
---|
62 | return self.types["string"] |
---|
63 | |
---|
64 | @sqltype_for("blob") |
---|
65 | def type_blob(self): |
---|
66 | return "BLOB" |
---|
67 | |
---|
68 | @sqltype_for("upload") |
---|
69 | def type_upload(self): |
---|
70 | return self.types["string"] |
---|
71 | |
---|
72 | @sqltype_for("integer") |
---|
73 | def type_integer(self): |
---|
74 | return "INTEGER" |
---|
75 | |
---|
76 | @sqltype_for("bigint") |
---|
77 | def type_bigint(self): |
---|
78 | return self.types["integer"] |
---|
79 | |
---|
80 | @sqltype_for("float") |
---|
81 | def type_float(self): |
---|
82 | return "FLOAT" |
---|
83 | |
---|
84 | @sqltype_for("double") |
---|
85 | def type_double(self): |
---|
86 | return "DOUBLE" |
---|
87 | |
---|
88 | @sqltype_for("decimal") |
---|
89 | def type_decimal(self): |
---|
90 | return "NUMERIC(%(precision)s,%(scale)s)" |
---|
91 | |
---|
92 | @sqltype_for("date") |
---|
93 | def type_date(self): |
---|
94 | return "DATE" |
---|
95 | |
---|
96 | @sqltype_for("time") |
---|
97 | def type_time(self): |
---|
98 | return "TIME" |
---|
99 | |
---|
100 | @sqltype_for("datetime") |
---|
101 | def type_datetime(self): |
---|
102 | return "TIMESTAMP" |
---|
103 | |
---|
104 | @sqltype_for("id") |
---|
105 | def type_id(self): |
---|
106 | return "INTEGER PRIMARY KEY AUTOINCREMENT" |
---|
107 | |
---|
108 | @sqltype_for("reference") |
---|
109 | def type_reference(self): |
---|
110 | return ( |
---|
111 | "INTEGER REFERENCES %(foreign_key)s " |
---|
112 | + "ON DELETE %(on_delete_action)s %(null)s %(unique)s" |
---|
113 | ) |
---|
114 | |
---|
115 | @sqltype_for("list:integer") |
---|
116 | def type_list_integer(self): |
---|
117 | return self.types["text"] |
---|
118 | |
---|
119 | @sqltype_for("list:string") |
---|
120 | def type_list_string(self): |
---|
121 | return self.types["text"] |
---|
122 | |
---|
123 | @sqltype_for("list:reference") |
---|
124 | def type_list_reference(self): |
---|
125 | return self.types["text"] |
---|
126 | |
---|
127 | @sqltype_for("big-id") |
---|
128 | def type_big_id(self): |
---|
129 | return self.types["id"] |
---|
130 | |
---|
131 | @sqltype_for("big-reference") |
---|
132 | def type_big_reference(self): |
---|
133 | return self.types["reference"] |
---|
134 | |
---|
135 | @sqltype_for("reference FK") |
---|
136 | def type_reference_fk(self): |
---|
137 | return ( |
---|
138 | ', CONSTRAINT "FK_%(constraint_name)s" FOREIGN KEY ' |
---|
139 | + "(%(field_name)s) REFERENCES %(foreign_key)s " |
---|
140 | + "ON DELETE %(on_delete_action)s" |
---|
141 | ) |
---|
142 | |
---|
143 | def alias(self, original, new): |
---|
144 | return ("%s AS " + self.quote_template) % (original, new) |
---|
145 | |
---|
146 | def insert(self, table, fields, values): |
---|
147 | return "INSERT INTO %s(%s) VALUES (%s);" % (table, fields, values) |
---|
148 | |
---|
149 | def insert_empty(self, table): |
---|
150 | return "INSERT INTO %s DEFAULT VALUES;" % table |
---|
151 | |
---|
152 | def where(self, query): |
---|
153 | return "WHERE %s" % query |
---|
154 | |
---|
155 | def update(self, table, values, where=None): |
---|
156 | tablename = self.writing_alias(table) |
---|
157 | whr = "" |
---|
158 | if where: |
---|
159 | whr = " %s" % self.where(where) |
---|
160 | return "UPDATE %s SET %s%s;" % (tablename, values, whr) |
---|
161 | |
---|
162 | def delete(self, table, where=None): |
---|
163 | tablename = self.writing_alias(table) |
---|
164 | whr = "" |
---|
165 | if where: |
---|
166 | whr = " %s" % self.where(where) |
---|
167 | return "DELETE FROM %s%s;" % (tablename, whr) |
---|
168 | |
---|
169 | def select( |
---|
170 | self, |
---|
171 | fields, |
---|
172 | tables, |
---|
173 | where=None, |
---|
174 | groupby=None, |
---|
175 | having=None, |
---|
176 | orderby=None, |
---|
177 | limitby=None, |
---|
178 | distinct=False, |
---|
179 | for_update=False, |
---|
180 | ): |
---|
181 | dst, whr, grp, order, limit, offset, upd = "", "", "", "", "", "", "" |
---|
182 | if distinct is True: |
---|
183 | dst = " DISTINCT" |
---|
184 | elif distinct: |
---|
185 | dst = " DISTINCT ON (%s)" % distinct |
---|
186 | if where: |
---|
187 | whr = " %s" % self.where(where) |
---|
188 | if groupby: |
---|
189 | grp = " GROUP BY %s" % groupby |
---|
190 | if having: |
---|
191 | grp += " HAVING %s" % having |
---|
192 | if orderby: |
---|
193 | order = " ORDER BY %s" % orderby |
---|
194 | if limitby: |
---|
195 | (lmin, lmax) = limitby |
---|
196 | limit = " LIMIT %i" % (lmax - lmin) |
---|
197 | offset = " OFFSET %i" % lmin |
---|
198 | if for_update: |
---|
199 | upd = " FOR UPDATE" |
---|
200 | return "SELECT%s %s FROM %s%s%s%s%s%s%s;" % ( |
---|
201 | dst, |
---|
202 | fields, |
---|
203 | tables, |
---|
204 | whr, |
---|
205 | grp, |
---|
206 | order, |
---|
207 | limit, |
---|
208 | offset, |
---|
209 | upd, |
---|
210 | ) |
---|
211 | |
---|
212 | def count(self, val, distinct=None, query_env={}): |
---|
213 | return ("COUNT(%s)" if not distinct else "COUNT(DISTINCT %s)") % self.expand( |
---|
214 | val, query_env=query_env |
---|
215 | ) |
---|
216 | |
---|
217 | def join(self, val, query_env={}): |
---|
218 | if isinstance(val, (Table, Select)): |
---|
219 | val = val.query_name(query_env.get("parent_scope", [])) |
---|
220 | elif not isinstance(val, basestring): |
---|
221 | val = self.expand(val, query_env=query_env) |
---|
222 | return "JOIN %s" % val |
---|
223 | |
---|
224 | def left_join(self, val, query_env={}): |
---|
225 | # Left join must always have an ON clause |
---|
226 | if not isinstance(val, basestring): |
---|
227 | val = self.expand(val, query_env=query_env) |
---|
228 | return "LEFT JOIN %s" % val |
---|
229 | |
---|
230 | def cross_join(self, val, query_env={}): |
---|
231 | if isinstance(val, (Table, Select)): |
---|
232 | val = val.query_name(query_env.get("parent_scope", [])) |
---|
233 | elif not isinstance(val, basestring): |
---|
234 | val = self.expand(val, query_env=query_env) |
---|
235 | return "CROSS JOIN %s" % val |
---|
236 | |
---|
237 | @property |
---|
238 | def random(self): |
---|
239 | return "Random()" |
---|
240 | |
---|
241 | def _as(self, first, second, query_env={}): |
---|
242 | return "%s AS %s" % (self.expand(first, query_env=query_env), second) |
---|
243 | |
---|
244 | def cast(self, first, second, query_env={}): |
---|
245 | return "CAST(%s)" % self._as(first, second, query_env) |
---|
246 | |
---|
247 | def _not(self, val, query_env={}): |
---|
248 | return "(NOT %s)" % self.expand(val, query_env=query_env) |
---|
249 | |
---|
250 | def _and(self, first, second, query_env={}): |
---|
251 | return "(%s AND %s)" % ( |
---|
252 | self.expand(first, query_env=query_env), |
---|
253 | self.expand(second, query_env=query_env), |
---|
254 | ) |
---|
255 | |
---|
256 | def _or(self, first, second, query_env={}): |
---|
257 | return "(%s OR %s)" % ( |
---|
258 | self.expand(first, query_env=query_env), |
---|
259 | self.expand(second, query_env=query_env), |
---|
260 | ) |
---|
261 | |
---|
262 | def belongs(self, first, second, query_env={}): |
---|
263 | ftype = first.type |
---|
264 | first = self.expand(first, query_env=query_env) |
---|
265 | if isinstance(second, str): |
---|
266 | return "(%s IN (%s))" % (first, second[:-1]) |
---|
267 | elif isinstance(second, Select): |
---|
268 | if len(second._qfields) != 1: |
---|
269 | raise ValueError("Subquery in belongs() must select exactly 1 column") |
---|
270 | sub = second._compile(query_env.get("current_scope", []))[1][:-1] |
---|
271 | return "(%s IN (%s))" % (first, sub) |
---|
272 | if not second: |
---|
273 | return "(1=0)" |
---|
274 | items = ",".join( |
---|
275 | self.expand(item, ftype, query_env=query_env) for item in second |
---|
276 | ) |
---|
277 | return "(%s IN (%s))" % (first, items) |
---|
278 | |
---|
279 | # def regexp(self, first, second): |
---|
280 | # raise NotImplementedError |
---|
281 | |
---|
282 | def lower(self, val, query_env={}): |
---|
283 | return "LOWER(%s)" % self.expand(val, query_env=query_env) |
---|
284 | |
---|
285 | def upper(self, first, query_env={}): |
---|
286 | return "UPPER(%s)" % self.expand(first, query_env=query_env) |
---|
287 | |
---|
288 | def like(self, first, second, escape=None, query_env={}): |
---|
289 | """Case sensitive like operator""" |
---|
290 | if isinstance(second, Expression): |
---|
291 | second = self.expand(second, "string", query_env=query_env) |
---|
292 | else: |
---|
293 | second = self.expand(second, "string", query_env=query_env) |
---|
294 | if escape is None: |
---|
295 | escape = "\\" |
---|
296 | second = second.replace(escape, escape * 2) |
---|
297 | return "(%s LIKE %s ESCAPE '%s')" % ( |
---|
298 | self.expand(first, query_env=query_env), |
---|
299 | second, |
---|
300 | escape, |
---|
301 | ) |
---|
302 | |
---|
303 | def ilike(self, first, second, escape=None, query_env={}): |
---|
304 | """Case insensitive like operator""" |
---|
305 | if isinstance(second, Expression): |
---|
306 | second = self.expand(second, "string", query_env=query_env) |
---|
307 | else: |
---|
308 | second = self.expand(second, "string", query_env=query_env).lower() |
---|
309 | if escape is None: |
---|
310 | escape = "\\" |
---|
311 | second = second.replace(escape, escape * 2) |
---|
312 | return "(%s LIKE %s ESCAPE '%s')" % ( |
---|
313 | self.lower(first, query_env=query_env), |
---|
314 | second, |
---|
315 | escape, |
---|
316 | ) |
---|
317 | |
---|
318 | def _like_escaper_default(self, term): |
---|
319 | if isinstance(term, Expression): |
---|
320 | return term |
---|
321 | term = term.replace("\\", "\\\\") |
---|
322 | term = term.replace(r"%", r"\%").replace("_", r"\_") |
---|
323 | return term |
---|
324 | |
---|
325 | def startswith(self, first, second, query_env={}): |
---|
326 | return "(%s LIKE %s ESCAPE '\\')" % ( |
---|
327 | self.expand(first, query_env=query_env), |
---|
328 | self.expand( |
---|
329 | self._like_escaper_default(second) + "%", "string", query_env=query_env |
---|
330 | ), |
---|
331 | ) |
---|
332 | |
---|
333 | def endswith(self, first, second, query_env={}): |
---|
334 | return "(%s LIKE %s ESCAPE '\\')" % ( |
---|
335 | self.expand(first, query_env=query_env), |
---|
336 | self.expand( |
---|
337 | "%" + self._like_escaper_default(second), "string", query_env=query_env |
---|
338 | ), |
---|
339 | ) |
---|
340 | |
---|
341 | def replace(self, first, tup, query_env={}): |
---|
342 | second, third = tup |
---|
343 | return "REPLACE(%s,%s,%s)" % ( |
---|
344 | self.expand(first, "string", query_env=query_env), |
---|
345 | self.expand(second, "string", query_env=query_env), |
---|
346 | self.expand(third, "string", query_env=query_env), |
---|
347 | ) |
---|
348 | |
---|
349 | def concat(self, *items, **kwargs): |
---|
350 | query_env = kwargs.get("query_env", {}) |
---|
351 | tmp = (self.expand(x, "string", query_env=query_env) for x in items) |
---|
352 | return "(%s)" % " || ".join(tmp) |
---|
353 | |
---|
354 | def contains(self, first, second, case_sensitive=True, query_env={}): |
---|
355 | if first.type in ("string", "text", "json", "jsonb"): |
---|
356 | if isinstance(second, Expression): |
---|
357 | second = Expression( |
---|
358 | second.db, |
---|
359 | self.concat( |
---|
360 | "%", |
---|
361 | Expression( |
---|
362 | second.db, |
---|
363 | self.replace(second, (r"%", r"\%"), query_env=query_env), |
---|
364 | ), |
---|
365 | r"%", |
---|
366 | ), |
---|
367 | ) |
---|
368 | else: |
---|
369 | second = "%" + self._like_escaper_default(str(second)) + r"%" |
---|
370 | elif first.type.startswith("list:"): |
---|
371 | if isinstance(second, Expression): |
---|
372 | second = Expression( |
---|
373 | second.db, |
---|
374 | self.concat( |
---|
375 | r"%|", |
---|
376 | Expression( |
---|
377 | second.db, |
---|
378 | self.replace( |
---|
379 | Expression( |
---|
380 | second.db, |
---|
381 | self.replace(second, (r"%", r"\%"), query_env), |
---|
382 | ), |
---|
383 | ("|", "||"), |
---|
384 | ), |
---|
385 | ), |
---|
386 | r"|%", |
---|
387 | ), |
---|
388 | ) |
---|
389 | else: |
---|
390 | second = str(second).replace("|", "||") |
---|
391 | second = "%|" + self._like_escaper_default(second) + "|%" |
---|
392 | op = case_sensitive and self.like or self.ilike |
---|
393 | return op(first, second, escape="\\", query_env=query_env) |
---|
394 | |
---|
395 | def eq(self, first, second=None, query_env={}): |
---|
396 | if second is None: |
---|
397 | return "(%s IS NULL)" % self.expand(first, query_env=query_env) |
---|
398 | if first.type in ("json", "jsonb"): |
---|
399 | if isinstance(second, (string_types, int, float)): |
---|
400 | return "(%s = '%s')" % ( |
---|
401 | self.expand(first, query_env=query_env), |
---|
402 | self.expand(second, query_env=query_env), |
---|
403 | ) |
---|
404 | return "(%s = %s)" % ( |
---|
405 | self.expand(first, query_env=query_env), |
---|
406 | self.expand(second, first.type, query_env=query_env), |
---|
407 | ) |
---|
408 | |
---|
409 | def ne(self, first, second=None, query_env={}): |
---|
410 | if second is None: |
---|
411 | return "(%s IS NOT NULL)" % self.expand(first, query_env=query_env) |
---|
412 | if first.type in ("json", "jsonb"): |
---|
413 | if isinstance(second, (string_types, int, float)): |
---|
414 | return "(%s <> '%s')" % ( |
---|
415 | self.expand(first, query_env=query_env), |
---|
416 | self.expand(second, query_env=query_env), |
---|
417 | ) |
---|
418 | return "(%s <> %s)" % ( |
---|
419 | self.expand(first, query_env=query_env), |
---|
420 | self.expand(second, first.type, query_env=query_env), |
---|
421 | ) |
---|
422 | |
---|
423 | def lt(self, first, second=None, query_env={}): |
---|
424 | if second is None: |
---|
425 | raise RuntimeError("Cannot compare %s < None" % first) |
---|
426 | if first.type in ("json", "jsonb"): |
---|
427 | if isinstance(second, (string_types, int, float)): |
---|
428 | return "(%s < '%s')" % ( |
---|
429 | self.expand(first, query_env=query_env), |
---|
430 | self.expand(second, query_env=query_env), |
---|
431 | ) |
---|
432 | return "(%s < %s)" % ( |
---|
433 | self.expand(first, query_env=query_env), |
---|
434 | self.expand(second, first.type, query_env=query_env), |
---|
435 | ) |
---|
436 | |
---|
437 | def lte(self, first, second=None, query_env={}): |
---|
438 | if second is None: |
---|
439 | raise RuntimeError("Cannot compare %s <= None" % first) |
---|
440 | if first.type in ("json", "jsonb"): |
---|
441 | if isinstance(second, (string_types, int, float)): |
---|
442 | return "(%s <= '%s')" % ( |
---|
443 | self.expand(first, query_env=query_env), |
---|
444 | self.expand(second, query_env=query_env), |
---|
445 | ) |
---|
446 | return "(%s <= %s)" % ( |
---|
447 | self.expand(first, query_env=query_env), |
---|
448 | self.expand(second, first.type, query_env=query_env), |
---|
449 | ) |
---|
450 | |
---|
451 | def gt(self, first, second=None, query_env={}): |
---|
452 | if second is None: |
---|
453 | raise RuntimeError("Cannot compare %s > None" % first) |
---|
454 | if first.type in ("json", "jsonb"): |
---|
455 | if isinstance(second, (string_types, int, float)): |
---|
456 | return "(%s > '%s')" % ( |
---|
457 | self.expand(first, query_env=query_env), |
---|
458 | self.expand(second, query_env=query_env), |
---|
459 | ) |
---|
460 | return "(%s > %s)" % ( |
---|
461 | self.expand(first, query_env=query_env), |
---|
462 | self.expand(second, first.type, query_env=query_env), |
---|
463 | ) |
---|
464 | |
---|
465 | def gte(self, first, second=None, query_env={}): |
---|
466 | if second is None: |
---|
467 | raise RuntimeError("Cannot compare %s >= None" % first) |
---|
468 | if first.type in ("json", "jsonb"): |
---|
469 | if isinstance(second, (string_types, int, float)): |
---|
470 | return "(%s >= '%s')" % ( |
---|
471 | self.expand(first, query_env=query_env), |
---|
472 | self.expand(second, query_env=query_env), |
---|
473 | ) |
---|
474 | return "(%s >= %s)" % ( |
---|
475 | self.expand(first, query_env=query_env), |
---|
476 | self.expand(second, first.type, query_env=query_env), |
---|
477 | ) |
---|
478 | |
---|
479 | def _is_numerical(self, field_type): |
---|
480 | return field_type in ( |
---|
481 | "integer", |
---|
482 | "float", |
---|
483 | "double", |
---|
484 | "bigint", |
---|
485 | "boolean", |
---|
486 | ) or field_type.startswith("decimal") |
---|
487 | |
---|
488 | def add(self, first, second, query_env={}): |
---|
489 | if self._is_numerical(first.type) or isinstance(first.type, Field): |
---|
490 | return "(%s + %s)" % ( |
---|
491 | self.expand(first, query_env=query_env), |
---|
492 | self.expand(second, first.type, query_env=query_env), |
---|
493 | ) |
---|
494 | else: |
---|
495 | return self.concat(first, second, query_env=query_env) |
---|
496 | |
---|
497 | def sub(self, first, second, query_env={}): |
---|
498 | return "(%s - %s)" % ( |
---|
499 | self.expand(first, query_env=query_env), |
---|
500 | self.expand(second, first.type, query_env=query_env), |
---|
501 | ) |
---|
502 | |
---|
503 | def mul(self, first, second, query_env={}): |
---|
504 | return "(%s * %s)" % ( |
---|
505 | self.expand(first, query_env=query_env), |
---|
506 | self.expand(second, first.type, query_env=query_env), |
---|
507 | ) |
---|
508 | |
---|
509 | def div(self, first, second, query_env={}): |
---|
510 | return "(%s / %s)" % ( |
---|
511 | self.expand(first, query_env=query_env), |
---|
512 | self.expand(second, first.type, query_env=query_env), |
---|
513 | ) |
---|
514 | |
---|
515 | def mod(self, first, second, query_env={}): |
---|
516 | return "(%s %% %s)" % ( |
---|
517 | self.expand(first, query_env=query_env), |
---|
518 | self.expand(second, first.type, query_env=query_env), |
---|
519 | ) |
---|
520 | |
---|
521 | def on(self, first, second, query_env={}): |
---|
522 | table_rname = first.query_name(query_env.get("parent_scope", []))[0] |
---|
523 | if use_common_filters(second): |
---|
524 | second = self.adapter.common_filter(second, [first]) |
---|
525 | return ("%s ON %s") % (table_rname, self.expand(second, query_env=query_env)) |
---|
526 | |
---|
527 | def invert(self, first, query_env={}): |
---|
528 | return "%s DESC" % self.expand(first, query_env=query_env) |
---|
529 | |
---|
530 | def comma(self, first, second, query_env={}): |
---|
531 | return "%s, %s" % ( |
---|
532 | self.expand(first, query_env=query_env), |
---|
533 | self.expand(second, query_env=query_env), |
---|
534 | ) |
---|
535 | |
---|
536 | def extract(self, first, what, query_env={}): |
---|
537 | return "EXTRACT(%s FROM %s)" % (what, self.expand(first, query_env=query_env)) |
---|
538 | |
---|
539 | def epoch(self, val, query_env={}): |
---|
540 | return self.extract(val, "epoch", query_env) |
---|
541 | |
---|
542 | def length(self, val, query_env={}): |
---|
543 | return "LENGTH(%s)" % self.expand(val, query_env=query_env) |
---|
544 | |
---|
545 | def aggregate(self, first, what, query_env={}): |
---|
546 | return "%s(%s)" % (what, self.expand(first, query_env=query_env)) |
---|
547 | |
---|
548 | def not_null(self, default, field_type): |
---|
549 | return "NOT NULL DEFAULT %s" % self.adapter.represent(default, field_type) |
---|
550 | |
---|
551 | @property |
---|
552 | def allow_null(self): |
---|
553 | return "" |
---|
554 | |
---|
555 | def coalesce(self, first, second, query_env={}): |
---|
556 | expressions = [self.expand(first, query_env=query_env)] + [ |
---|
557 | self.expand(val, first.type, query_env=query_env) for val in second |
---|
558 | ] |
---|
559 | return "COALESCE(%s)" % ",".join(expressions) |
---|
560 | |
---|
561 | def raw(self, val, query_env={}): |
---|
562 | return val |
---|
563 | |
---|
564 | def substring(self, field, parameters, query_env={}): |
---|
565 | return "SUBSTR(%s,%s,%s)" % ( |
---|
566 | self.expand(field, query_env=query_env), |
---|
567 | parameters[0], |
---|
568 | parameters[1], |
---|
569 | ) |
---|
570 | |
---|
571 | def case(self, query, true_false, query_env={}): |
---|
572 | _types = {bool: "boolean", int: "integer", float: "double"} |
---|
573 | return "CASE WHEN %s THEN %s ELSE %s END" % ( |
---|
574 | self.expand(query, query_env=query_env), |
---|
575 | self.adapter.represent( |
---|
576 | true_false[0], _types.get(type(true_false[0]), "string") |
---|
577 | ), |
---|
578 | self.adapter.represent( |
---|
579 | true_false[1], _types.get(type(true_false[1]), "string") |
---|
580 | ), |
---|
581 | ) |
---|
582 | |
---|
583 | def primary_key(self, key): |
---|
584 | return "PRIMARY KEY(%s)" % key |
---|
585 | |
---|
586 | def drop_table(self, table, mode): |
---|
587 | return ["DROP TABLE %s;" % table._rname] |
---|
588 | |
---|
589 | def truncate(self, table, mode=""): |
---|
590 | if mode: |
---|
591 | mode = " %s" % mode |
---|
592 | return ["TRUNCATE TABLE %s%s;" % (table._rname, mode)] |
---|
593 | |
---|
594 | def create_index(self, name, table, expressions, unique=False): |
---|
595 | uniq = " UNIQUE" if unique else "" |
---|
596 | with self.adapter.index_expander(): |
---|
597 | rv = "CREATE%s INDEX %s ON %s (%s);" % ( |
---|
598 | uniq, |
---|
599 | self.quote(name), |
---|
600 | table._rname, |
---|
601 | ",".join(self.expand(field) for field in expressions), |
---|
602 | ) |
---|
603 | return rv |
---|
604 | |
---|
605 | def drop_index(self, name, table): |
---|
606 | return "DROP INDEX %s;" % self.quote(name) |
---|
607 | |
---|
608 | def constraint_name(self, table, fieldname): |
---|
609 | return "%s_%s__constraint" % (table, fieldname) |
---|
610 | |
---|
611 | def concat_add(self, tablename): |
---|
612 | return ", ADD " |
---|
613 | |
---|
614 | def writing_alias(self, table): |
---|
615 | return table.sql_fullref |
---|
616 | |
---|
617 | |
---|
618 | class NoSQLDialect(CommonDialect): |
---|
619 | @sqltype_for("string") |
---|
620 | def type_string(self): |
---|
621 | return str |
---|
622 | |
---|
623 | @sqltype_for("boolean") |
---|
624 | def type_boolean(self): |
---|
625 | return bool |
---|
626 | |
---|
627 | @sqltype_for("text") |
---|
628 | def type_text(self): |
---|
629 | return str |
---|
630 | |
---|
631 | @sqltype_for("json") |
---|
632 | def type_json(self): |
---|
633 | return self.types["text"] |
---|
634 | |
---|
635 | @sqltype_for("password") |
---|
636 | def type_password(self): |
---|
637 | return self.types["string"] |
---|
638 | |
---|
639 | @sqltype_for("blob") |
---|
640 | def type_blob(self): |
---|
641 | return self.types["text"] |
---|
642 | |
---|
643 | @sqltype_for("upload") |
---|
644 | def type_upload(self): |
---|
645 | return self.types["string"] |
---|
646 | |
---|
647 | @sqltype_for("integer") |
---|
648 | def type_integer(self): |
---|
649 | return long |
---|
650 | |
---|
651 | @sqltype_for("bigint") |
---|
652 | def type_bigint(self): |
---|
653 | return self.types["integer"] |
---|
654 | |
---|
655 | @sqltype_for("float") |
---|
656 | def type_float(self): |
---|
657 | return float |
---|
658 | |
---|
659 | @sqltype_for("double") |
---|
660 | def type_double(self): |
---|
661 | return self.types["float"] |
---|
662 | |
---|
663 | @sqltype_for("date") |
---|
664 | def type_date(self): |
---|
665 | return datetime.date |
---|
666 | |
---|
667 | @sqltype_for("time") |
---|
668 | def type_time(self): |
---|
669 | return datetime.time |
---|
670 | |
---|
671 | @sqltype_for("datetime") |
---|
672 | def type_datetime(self): |
---|
673 | return datetime.datetime |
---|
674 | |
---|
675 | @sqltype_for("id") |
---|
676 | def type_id(self): |
---|
677 | return long |
---|
678 | |
---|
679 | @sqltype_for("reference") |
---|
680 | def type_reference(self): |
---|
681 | return long |
---|
682 | |
---|
683 | @sqltype_for("list:integer") |
---|
684 | def type_list_integer(self): |
---|
685 | return list |
---|
686 | |
---|
687 | @sqltype_for("list:string") |
---|
688 | def type_list_string(self): |
---|
689 | return list |
---|
690 | |
---|
691 | @sqltype_for("list:reference") |
---|
692 | def type_list_reference(self): |
---|
693 | return list |
---|
694 | |
---|
695 | def quote(self, val): |
---|
696 | return val |
---|