velocity-python 0.0.109__py3-none-any.whl → 0.0.161__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. velocity/__init__.py +3 -1
  2. velocity/app/orders.py +3 -4
  3. velocity/app/tests/__init__.py +1 -0
  4. velocity/app/tests/test_email_processing.py +112 -0
  5. velocity/app/tests/test_payment_profile_sorting.py +191 -0
  6. velocity/app/tests/test_spreadsheet_functions.py +124 -0
  7. velocity/aws/__init__.py +3 -0
  8. velocity/aws/amplify.py +10 -6
  9. velocity/aws/handlers/__init__.py +2 -0
  10. velocity/aws/handlers/base_handler.py +248 -0
  11. velocity/aws/handlers/context.py +251 -2
  12. velocity/aws/handlers/exceptions.py +16 -0
  13. velocity/aws/handlers/lambda_handler.py +24 -85
  14. velocity/aws/handlers/mixins/__init__.py +16 -0
  15. velocity/aws/handlers/mixins/activity_tracker.py +181 -0
  16. velocity/aws/handlers/mixins/aws_session_mixin.py +192 -0
  17. velocity/aws/handlers/mixins/error_handler.py +192 -0
  18. velocity/aws/handlers/mixins/legacy_mixin.py +53 -0
  19. velocity/aws/handlers/mixins/standard_mixin.py +73 -0
  20. velocity/aws/handlers/response.py +1 -1
  21. velocity/aws/handlers/sqs_handler.py +28 -143
  22. velocity/aws/tests/__init__.py +1 -0
  23. velocity/aws/tests/test_lambda_handler_json_serialization.py +120 -0
  24. velocity/aws/tests/test_response.py +163 -0
  25. velocity/db/__init__.py +16 -4
  26. velocity/db/core/decorators.py +48 -13
  27. velocity/db/core/engine.py +187 -840
  28. velocity/db/core/result.py +33 -25
  29. velocity/db/core/row.py +15 -3
  30. velocity/db/core/table.py +493 -50
  31. velocity/db/core/transaction.py +28 -15
  32. velocity/db/exceptions.py +42 -18
  33. velocity/db/servers/base/__init__.py +9 -0
  34. velocity/db/servers/base/initializer.py +70 -0
  35. velocity/db/servers/base/operators.py +98 -0
  36. velocity/db/servers/base/sql.py +503 -0
  37. velocity/db/servers/base/types.py +135 -0
  38. velocity/db/servers/mysql/__init__.py +73 -0
  39. velocity/db/servers/mysql/operators.py +54 -0
  40. velocity/db/servers/{mysql_reserved.py → mysql/reserved.py} +2 -14
  41. velocity/db/servers/mysql/sql.py +718 -0
  42. velocity/db/servers/mysql/types.py +107 -0
  43. velocity/db/servers/postgres/__init__.py +59 -11
  44. velocity/db/servers/postgres/operators.py +34 -0
  45. velocity/db/servers/postgres/sql.py +474 -120
  46. velocity/db/servers/postgres/types.py +88 -2
  47. velocity/db/servers/sqlite/__init__.py +61 -0
  48. velocity/db/servers/sqlite/operators.py +52 -0
  49. velocity/db/servers/sqlite/reserved.py +20 -0
  50. velocity/db/servers/sqlite/sql.py +677 -0
  51. velocity/db/servers/sqlite/types.py +92 -0
  52. velocity/db/servers/sqlserver/__init__.py +73 -0
  53. velocity/db/servers/sqlserver/operators.py +47 -0
  54. velocity/db/servers/sqlserver/reserved.py +32 -0
  55. velocity/db/servers/sqlserver/sql.py +805 -0
  56. velocity/db/servers/sqlserver/types.py +114 -0
  57. velocity/db/servers/tablehelper.py +117 -91
  58. velocity/db/tests/__init__.py +1 -0
  59. velocity/db/tests/common_db_test.py +0 -0
  60. velocity/db/tests/postgres/__init__.py +1 -0
  61. velocity/db/tests/postgres/common.py +49 -0
  62. velocity/db/tests/postgres/test_column.py +29 -0
  63. velocity/db/tests/postgres/test_connections.py +25 -0
  64. velocity/db/tests/postgres/test_database.py +21 -0
  65. velocity/db/tests/postgres/test_engine.py +205 -0
  66. velocity/db/tests/postgres/test_general_usage.py +88 -0
  67. velocity/db/tests/postgres/test_imports.py +8 -0
  68. velocity/db/tests/postgres/test_result.py +19 -0
  69. velocity/db/tests/postgres/test_row.py +137 -0
  70. velocity/db/tests/postgres/test_row_comprehensive.py +720 -0
  71. velocity/db/tests/postgres/test_schema_locking.py +335 -0
  72. velocity/db/tests/postgres/test_schema_locking_unit.py +115 -0
  73. velocity/db/tests/postgres/test_sequence.py +34 -0
  74. velocity/db/tests/postgres/test_sql_comprehensive.py +462 -0
  75. velocity/db/tests/postgres/test_table.py +101 -0
  76. velocity/db/tests/postgres/test_table_comprehensive.py +646 -0
  77. velocity/db/tests/postgres/test_transaction.py +106 -0
  78. velocity/db/tests/sql/__init__.py +1 -0
  79. velocity/db/tests/sql/common.py +177 -0
  80. velocity/db/tests/sql/test_postgres_select_advanced.py +285 -0
  81. velocity/db/tests/sql/test_postgres_select_variances.py +517 -0
  82. velocity/db/tests/test_cursor_rowcount_fix.py +150 -0
  83. velocity/db/tests/test_db_utils.py +270 -0
  84. velocity/db/tests/test_postgres.py +448 -0
  85. velocity/db/tests/test_postgres_unchanged.py +81 -0
  86. velocity/db/tests/test_process_error_robustness.py +292 -0
  87. velocity/db/tests/test_result_caching.py +279 -0
  88. velocity/db/tests/test_result_sql_aware.py +117 -0
  89. velocity/db/tests/test_row_get_missing_column.py +72 -0
  90. velocity/db/tests/test_schema_locking_initializers.py +226 -0
  91. velocity/db/tests/test_schema_locking_simple.py +97 -0
  92. velocity/db/tests/test_sql_builder.py +165 -0
  93. velocity/db/tests/test_tablehelper.py +486 -0
  94. velocity/db/utils.py +129 -51
  95. velocity/misc/conv/__init__.py +2 -0
  96. velocity/misc/conv/iconv.py +5 -4
  97. velocity/misc/export.py +1 -4
  98. velocity/misc/merge.py +1 -1
  99. velocity/misc/tests/__init__.py +1 -0
  100. velocity/misc/tests/test_db.py +90 -0
  101. velocity/misc/tests/test_fix.py +78 -0
  102. velocity/misc/tests/test_format.py +64 -0
  103. velocity/misc/tests/test_iconv.py +203 -0
  104. velocity/misc/tests/test_merge.py +82 -0
  105. velocity/misc/tests/test_oconv.py +144 -0
  106. velocity/misc/tests/test_original_error.py +52 -0
  107. velocity/misc/tests/test_timer.py +74 -0
  108. velocity/misc/tools.py +0 -1
  109. {velocity_python-0.0.109.dist-info → velocity_python-0.0.161.dist-info}/METADATA +2 -2
  110. velocity_python-0.0.161.dist-info/RECORD +129 -0
  111. velocity/db/core/exceptions.py +0 -70
  112. velocity/db/servers/mysql.py +0 -641
  113. velocity/db/servers/sqlite.py +0 -968
  114. velocity/db/servers/sqlite_reserved.py +0 -208
  115. velocity/db/servers/sqlserver.py +0 -921
  116. velocity/db/servers/sqlserver_reserved.py +0 -314
  117. velocity_python-0.0.109.dist-info/RECORD +0 -56
  118. {velocity_python-0.0.109.dist-info → velocity_python-0.0.161.dist-info}/WHEEL +0 -0
  119. {velocity_python-0.0.109.dist-info → velocity_python-0.0.161.dist-info}/licenses/LICENSE +0 -0
  120. {velocity_python-0.0.109.dist-info → velocity_python-0.0.161.dist-info}/top_level.txt +0 -0
@@ -1,641 +0,0 @@
1
- import re
2
- import hashlib
3
- import decimal
4
- import datetime
5
- from velocity.db import exceptions
6
- from .mysql_reserved import reserved_words
7
-
8
-
9
- def initialize(config):
10
- from velocity.db.core.engine import Engine
11
- import mysql.connector
12
-
13
- return Engine(mysql.connector, config, SQL)
14
-
15
-
16
- def make_where(where, sql, vals, is_join=False):
17
- if not where:
18
- return
19
- sql.append("WHERE")
20
- if isinstance(where, str):
21
- sql.append(where)
22
- return
23
- if isinstance(where, dict):
24
- where = where.items()
25
- if isinstance(where, list):
26
- join = ""
27
- for key, val in where:
28
- if join:
29
- sql.append(join)
30
- if is_join:
31
- if "." not in key:
32
- key = "A." + key
33
- if val == None:
34
- if "!" in key:
35
- key = key.replace("!", "")
36
- sql.append("{} is not NULL".format(quote(key.lower())))
37
- else:
38
- sql.append("{} is NULL".format(quote(key.lower())))
39
- elif isinstance(val, (list, tuple)):
40
- if "!" in key:
41
- key = key.replace("!", "")
42
- sql.append("{} not in %s".format(quote(key.lower())))
43
- vals.append(tuple(val))
44
- else:
45
- sql.append("{} in %s".format(quote(key.lower())))
46
- vals.append(tuple(val))
47
- else:
48
- if "<>" in key:
49
- key = key.replace("<>", "")
50
- op = "<>"
51
- elif "!=" in key:
52
- key = key.replace("!=", "")
53
- op = "<>"
54
- elif "!%" in key:
55
- key = key.replace("!%", "")
56
- op = "not like"
57
- elif "%%" in key:
58
- key = key.replace("%%", "")
59
- op = "%"
60
- elif "%>" in key:
61
- key = key.replace("%>", "")
62
- op = "%>"
63
- elif "<%" in key:
64
- key = key.replace("<%", "")
65
- op = "<%"
66
- elif "==" in key:
67
- key = key.replace("==", "")
68
- op = "="
69
- elif "<=" in key:
70
- key = key.replace("<=", "")
71
- op = "<="
72
- elif ">=" in key:
73
- key = key.replace(">=", "")
74
- op = ">="
75
- elif "<" in key:
76
- key = key.replace("<", "")
77
- op = "<"
78
- elif ">" in key:
79
- key = key.replace(">", "")
80
- op = ">"
81
- elif "%" in key:
82
- key = key.replace("%", "")
83
- op = "like"
84
- elif "!" in key:
85
- key = key.replace("!", "")
86
- op = "<>"
87
- elif "=" in key:
88
- key = key.replace("=", "")
89
- op = "="
90
- else:
91
- op = "="
92
- if isinstance(val, str) and val[:2] == "@@":
93
- sql.append("{} {} {}".format(quote(key.lower()), op, val[2:]))
94
- else:
95
- if "like" in op:
96
- sql.append(
97
- "lower({}) {} lower(%s)".format(quote(key.lower()), op)
98
- )
99
- else:
100
- sql.append("{} {} %s".format(quote(key.lower()), op))
101
- vals.append(val)
102
- join = "AND"
103
-
104
-
105
- def quote(data):
106
- if isinstance(data, list):
107
- new = []
108
- for item in data:
109
- new.append(quote(item))
110
- return new
111
- else:
112
- parts = data.split(".")
113
- new = []
114
- for part in parts:
115
- if "`" in part:
116
- new.append(part)
117
- elif part.upper() in reserved_words:
118
- new.append("`" + part + "`")
119
- elif re.findall("[/]", part):
120
- new.append("`" + part + "`")
121
- else:
122
- new.append(part)
123
- return ".".join(new)
124
-
125
-
126
- class SQL:
127
- server = "MySQL"
128
- type_column_identifier = "DATA_TYPE"
129
- is_nullable = "IS_NULLABLE"
130
-
131
- default_schema = "mydb"
132
-
133
- ApplicationErrorCodes = []
134
-
135
- DatabaseMissingErrorCodes = []
136
- TableMissingErrorCodes = [1146]
137
- ColumnMissingErrorCodes = [1054]
138
- ForeignKeyMissingErrorCodes = []
139
-
140
- ConnectionErrorCodes = []
141
- DuplicateKeyErrorCodes = [] # Handled in regex check.
142
- RetryTransactionCodes = []
143
- TruncationErrorCodes = []
144
- LockTimeoutErrorCodes = []
145
- DatabaseObjectExistsErrorCodes = []
146
-
147
- def get_error(self, e):
148
- error_code, error_mesg = e.args[:2]
149
- return error_code, error_mesg
150
-
151
- @classmethod
152
- def __has_pointer(cls, columns):
153
- if columns:
154
- if isinstance(columns, list):
155
- columns = ",".join(columns)
156
- if ">" in columns:
157
- return True
158
- return False
159
-
160
- @classmethod
161
- def alter_add(cls, table, columns, null_allowed=True):
162
- sql = []
163
- null = "NOT NULL" if not null_allowed else ""
164
- if isinstance(columns, dict):
165
- for key, val in columns.items():
166
- key = re.sub("<>!=%", "", key.lower())
167
- sql.append(
168
- "ALTER TABLE {} ADD {} {} {};".format(
169
- quote(table), quote(key), cls.get_type(val), null
170
- )
171
- )
172
- return "\n\t".join(sql), tuple()
173
-
174
- @classmethod
175
- def columns(cls, name):
176
- if "." in name:
177
- return """
178
- SELECT COLUMN_NAME
179
- FROM INFORMATION_SCHEMA.columns
180
- WHERE TABLE_SCHEMA = %s
181
- AND TABLE_NAME = %s
182
- """, tuple(
183
- name.split(".")
184
- )
185
- else:
186
- return """
187
- SELECT COLUMN_NAME
188
- FROM INFORMATION_SCHEMA.columns
189
- WHERE TABLE_SCHEMA = %s
190
- """, tuple(
191
- [
192
- name,
193
- ]
194
- )
195
-
196
- @classmethod
197
- def create_foreign_key(
198
- cls, table, columns, key_to_table, key_to_columns, name=None, schema=None
199
- ):
200
- if "." not in table and schema:
201
- if schema == None:
202
- schema = cls.default_schema
203
- table = "{}.{}".format(schema, table)
204
- if isinstance(key_to_columns, str):
205
- key_to_columns = [key_to_columns]
206
- if isinstance(columns, str):
207
- columns = [columns]
208
- if not name:
209
- m = hashlib.md5()
210
- m.update(table)
211
- m.update(" ".join(columns))
212
- m.update(key_to_table)
213
- m.update(" ".join(key_to_columns))
214
- name = "FK_" + m.hexdigest()
215
- sql = "ALTER TABLE {} ADD CONSTRAINT {} FOREIGN KEY ({}) REFERENCES {} ({}) ON DELETE CASCADE ON UPDATE CASCADE;".format(
216
- table, name, ",".join(columns), key_to_table, ",".join(key_to_columns)
217
- )
218
-
219
- return sql, tuple()
220
-
221
- @classmethod
222
- def create_index(
223
- cls,
224
- table=None,
225
- columns=None,
226
- unique=False,
227
- direction=None,
228
- where=None,
229
- name=None,
230
- schema=None,
231
- trigram=None,
232
- tbl=None,
233
- ):
234
- if "." not in table and schema:
235
- table = "{}.{}".format(schema, table)
236
- if isinstance(columns, (list, set)):
237
- columns = ",".join([quote(c.lower()) for c in sorted(columns)])
238
- else:
239
- columns = quote(columns)
240
- sql = ["CREATE"]
241
- if unique:
242
- sql.append("UNIQUE")
243
- sql.append("INDEX")
244
- tablename = quote(table)
245
- if not name:
246
- name = re.sub(r"\([^)]*\)", "", columns.replace(",", "_"))
247
- sql.append("IDX__{}__{}".format(table.replace(".", "_"), name))
248
- sql.append("ON")
249
- sql.append(tablename)
250
- sql.append("(")
251
- sql.append(columns)
252
- sql.append(")")
253
- return " ".join(sql), tuple()
254
-
255
- @classmethod
256
- def create_table(cls, name, columns={}, drop=False):
257
- trigger = "".format(name)
258
- sql = []
259
- if drop:
260
- sql.append(cls.drop_table(name))
261
- sql.append(
262
- """
263
- CREATE TABLE {0} (
264
- sys_id SERIAL PRIMARY KEY AUTO_INCREMENT,
265
- sys_modified TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
266
- sys_created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
267
- )ENGINE=InnoDB AUTO_INCREMENT=1000;
268
- """.format(
269
- quote(name)
270
- )
271
- )
272
-
273
- for key, val in columns.items():
274
- key = re.sub("<>!=%", "", key.lower())
275
- if key in ["sys_id", "sys_created", "sys_modified"]:
276
- continue
277
- sql.append(
278
- "ALTER TABLE {} ADD COLUMN {} {};".format(
279
- quote(name), quote(key), cls.get_type(val)
280
- )
281
- )
282
- return "\n\t".join(sql), tuple()
283
-
284
- @classmethod
285
- def delete(cls, table, where):
286
- sql = ["DELETE FROM {}".format(table)]
287
- vals = []
288
- make_where(where, sql, vals)
289
- return " ".join(sql), tuple(vals)
290
-
291
- @classmethod
292
- def drop_table(cls, name):
293
- return "DROP TABLE IF EXISTS %s CASCADE;" % quote(name), tuple()
294
-
295
- @classmethod
296
- def foreign_key_info(cls, table=None, column=None, schema=None):
297
- if "." in table:
298
- schema, table = table.split(".")
299
-
300
- sql = [
301
- """
302
- SELECT
303
- TABLE_NAME AS FK_TABLE_NAME
304
- ,COLUMN_NAME AS FK_COLUMN_NAME
305
- ,CONSTRAINT_NAME AS REFERENCED_CONSTRAINT_NAME
306
- ,REFERENCED_TABLE_NAME
307
- ,REFERENCED_COLUMN_NAME
308
- FROM
309
- INFORMATION_SCHEMA.KEY_COLUMN_USAGE
310
- """
311
- ]
312
- vals = []
313
- where = {}
314
- if schema:
315
- where["LOWER(REFERENCED_TABLE_SCHEMA)"] = schema.lower()
316
- if table:
317
- where["LOWER(REFERENCED_TABLE_NAME)"] = table.lower()
318
- if column:
319
- where["LOWER(REFERENCED_COLUMN_NAME)"] = column.lower()
320
- make_where(where, sql, vals)
321
- return " ".join(sql), tuple(vals)
322
-
323
- @classmethod
324
- def get_type(cls, v):
325
- if isinstance(v, str):
326
- if v[:2] == "@@":
327
- return v[2:] or cls.TYPES.TEXT
328
- elif isinstance(v, (str, bytes)) or v is str or v is bytes:
329
- return cls.TYPES.TEXT
330
- elif isinstance(v, bool) or v is bool:
331
- return cls.TYPES.BOOLEAN
332
- elif isinstance(v, int) or v is int:
333
- if v is int:
334
- return cls.TYPES.INTEGER
335
- if v > 2147483647 or v < -2147483648:
336
- return cls.TYPES.BIGINT
337
- else:
338
- return cls.TYPES.INTEGER
339
- elif isinstance(v, float) or v is float:
340
- return cls.TYPES.NUMERIC + "(19, 6)"
341
- elif isinstance(v, decimal.Decimal) or v is decimal.Decimal:
342
- return cls.TYPES.NUMERIC + "(19, 6)"
343
- elif isinstance(v, datetime.datetime) or v is datetime.datetime:
344
- return cls.TYPES.DATETIME
345
- elif isinstance(v, datetime.date) or v is datetime.date:
346
- return cls.TYPES.DATE
347
- elif isinstance(v, datetime.time) or v is datetime.time:
348
- return cls.TYPES.TIME
349
- elif isinstance(v, datetime.timedelta) or v is datetime.timedelta:
350
- return cls.TYPES.INTERVAL
351
- elif isinstance(v, bytearray) or v is bytearray:
352
- return cls.TYPES.BINARY
353
- # Everything else defaults to TEXT, incl. None
354
- return cls.TYPES.TEXT
355
-
356
- @classmethod
357
- def insert(cls, table, data):
358
- keys = []
359
- vals = []
360
- args = []
361
- for key, val in data.items():
362
- keys.append(quote(key.lower()))
363
- if isinstance(val, str) and len(val) > 2 and val[:2] == "@@":
364
- vals.append(val[2:])
365
- else:
366
- vals.append("%s")
367
- args.append(val)
368
-
369
- sql = ["INSERT INTO"]
370
- sql.append(quote(table))
371
- sql.append("(")
372
- sql.append(",".join(keys))
373
- sql.append(")")
374
- sql.append("VALUES")
375
- sql.append("(")
376
- sql.append(",".join(vals))
377
- sql.append(")")
378
- sql = " ".join(sql)
379
- return sql, tuple(args)
380
-
381
- @classmethod
382
- def last_id(cls, table):
383
- return "SELECT LAST_INSERT_ID();", tuple()
384
-
385
- @classmethod
386
- def create_savepoint(cls, sp):
387
- return None, tuple()
388
-
389
- @classmethod
390
- def rollback_savepoint(cls, sp):
391
- return None, tuple()
392
-
393
- @classmethod
394
- def release_savepoint(cls, sp):
395
- return None, tuple()
396
-
397
- @classmethod
398
- def create_view(cls, name, query, temp=False, silent=True):
399
- sql = ["CREATE"]
400
- if silent:
401
- sql.append("OR REPLACE")
402
- if temp:
403
- sql.append("TEMPORARY")
404
- sql.append("VIEW")
405
- sql.append(name)
406
- sql.append("AS")
407
- sql.append(query)
408
- return " ".join(sql), tuple()
409
-
410
- @classmethod
411
- def drop_view(cls, name, silent=True):
412
- sql = ["DROP VIEW"]
413
- if silent:
414
- sql.append("IF EXISTS")
415
- sql.append(name)
416
- return " ".join(sql), tuple()
417
-
418
- @classmethod
419
- def rename_column(cls, table, orig, new):
420
- return (
421
- "ALTER TABLE {} RENAME COLUMN {} TO {};".format(
422
- quote(table), quote(orig), quote(new)
423
- ),
424
- tuple(),
425
- )
426
-
427
- @classmethod
428
- def select(
429
- cls,
430
- columns=None,
431
- table=None,
432
- where=None,
433
- orderby=None,
434
- groupby=None,
435
- having=None,
436
- start=None,
437
- qty=None,
438
- tbl=None,
439
- ):
440
- is_join = False
441
-
442
- if isinstance(columns, str) and "distinct" in columns.lower():
443
- sql = [
444
- "SELECT",
445
- columns,
446
- "FROM",
447
- quote(table),
448
- ]
449
- elif cls.__has_pointer(columns):
450
- is_join = True
451
- if isinstance(columns, str):
452
- columns = columns.split(",")
453
- letter = 65
454
- tables = {table: chr(letter)}
455
- letter += 1
456
- __select = []
457
- __from = ["{} AS {}".format(quote(table), tables.get(table))]
458
- __left_join = []
459
-
460
- for column in columns:
461
- if ">" in column:
462
- is_join = True
463
- parts = column.split(">")
464
- foreign = tbl.foreign_key_info(parts[0])
465
- if not foreign:
466
- raise exceptions.DbApplicationError("Foreign key not defined")
467
- ref_table = foreign["referenced_table_name"]
468
- ref_schema = foreign["referenced_table_schema"]
469
- ref_column = foreign["referenced_column_name"]
470
- lookup = "{}:{}".format(ref_table, parts[0])
471
- if tables.has_key(lookup):
472
- __select.append(
473
- '{}."{}" as "{}"'.format(
474
- tables.get(lookup), parts[1], "_".join(parts)
475
- )
476
- )
477
- else:
478
- tables[lookup] = chr(letter)
479
- letter += 1
480
- __select.append(
481
- '{}."{}" as "{}"'.format(
482
- tables.get(lookup), parts[1], "_".join(parts)
483
- )
484
- )
485
- __left_join.append(
486
- 'LEFT OUTER JOIN "{}"."{}" AS {}'.format(
487
- ref_schema, ref_table, tables.get(lookup)
488
- )
489
- )
490
- __left_join.append(
491
- 'ON {}."{}" = {}."{}"'.format(
492
- tables.get(table),
493
- parts[0],
494
- tables.get(lookup),
495
- ref_column,
496
- )
497
- )
498
- if orderby and column in orderby:
499
- orderby = orderby.replace(
500
- column, "{}.{}".format(tables.get(lookup), parts[1])
501
- )
502
-
503
- else:
504
- if "(" in column:
505
- __select.append(column)
506
- else:
507
- __select.append("{}.{}".format(tables.get(table), column))
508
- sql = ["SELECT"]
509
- sql.append(",".join(__select))
510
- sql.append("FROM")
511
- sql.extend(__from)
512
- sql.extend(__left_join)
513
- else:
514
- if columns:
515
- if isinstance(columns, str):
516
- columns = columns.split(",")
517
- if isinstance(columns, list):
518
- columns = quote(columns)
519
- columns = ",".join(columns)
520
- else:
521
- columns = "*"
522
- sql = [
523
- "SELECT",
524
- columns,
525
- "FROM",
526
- quote(table),
527
- ]
528
- vals = []
529
- make_where(where, sql, vals, is_join)
530
- if groupby:
531
- sql.append("GROUP BY")
532
- if isinstance(groupby, (list, tuple)):
533
- groupby = ",".join(groupby)
534
- sql.append(groupby)
535
- if having:
536
- sql.append("HAVING")
537
- if isinstance(having, (list, tuple)):
538
- having = ",".join(having)
539
- sql.append(having)
540
- if orderby:
541
- sql.append("ORDER BY")
542
- if isinstance(orderby, (list, tuple)):
543
- orderby = ",".join(orderby)
544
- sql.append(orderby)
545
- if start and qty:
546
- sql.append("OFFSET {} ROWS FETCH NEXT {} ROWS ONLY".format(start, qty))
547
- elif start:
548
- sql.append("OFFSET {} ROWS".format(start))
549
- elif qty:
550
- sql.append("FETCH NEXT {} ROWS ONLY".format(qty))
551
- sql = " ".join(sql)
552
- return sql, tuple(vals)
553
-
554
- @classmethod
555
- def update(cls, table, data, pk):
556
- sql = ["UPDATE"]
557
- sql.append(quote(table))
558
- sql.append("SET")
559
- vals = []
560
- join = ""
561
- for key in data.keys():
562
- val = data[key]
563
- if join:
564
- sql.append(join)
565
- if isinstance(val, str) and val[:2] == "@@":
566
- sql.append("{} = {}".format(quote(key.lower()), val[2:]))
567
- else:
568
- sql.append("{} = %s".format(quote(key.lower())))
569
- vals.append(val)
570
- join = ","
571
- make_where(pk, sql, vals)
572
- return " ".join(sql), tuple(vals)
573
-
574
- @classmethod
575
- def upsert(cls, table, data, pk):
576
- keys = []
577
- vals = []
578
- args = []
579
- for key, val in data.items():
580
- keys.append(quote(key.lower()))
581
- if isinstance(val, str) and len(val) > 2 and val[:2] == "@@":
582
- vals.append(val[2:])
583
- else:
584
- vals.append("%s")
585
- args.append(val)
586
- for key, val in pk.items():
587
- keys.append(quote(key.lower()))
588
- if isinstance(val, str) and len(val) > 2 and val[:2] == "@@":
589
- vals.append(val[2:])
590
- else:
591
- vals.append("%s")
592
- args.append(val)
593
- sql = ["INSERT INTO"]
594
- sql.append(quote(table))
595
- sql.append("(")
596
- sql.append(",".join(keys))
597
- sql.append(")")
598
- sql.append("VALUES")
599
- sql.append("(")
600
- sql.append(",".join(vals))
601
- sql.append(")")
602
- sql.append("ON DUPLICATE KEY UPDATE")
603
- join = ""
604
- for key in data.keys():
605
- val = data[key]
606
- if join:
607
- sql.append(join)
608
- if isinstance(val, str) and val[:2] == "@@":
609
- sql.append("{} = {}".format(quote(key.lower()), val[2:]))
610
- else:
611
- sql.append("{} = %s".format(quote(key.lower())))
612
- args.append(val)
613
- join = ","
614
- return " ".join(sql), tuple(args)
615
-
616
- @classmethod
617
- def views(cls, system=False):
618
- if system:
619
- return (
620
- "SELECT TABLE_SCHEMA, TABLE_NAME FROM information_schema.tables WHERE TABLE_TYPE LIKE 'VIEW';",
621
- tuple(),
622
- )
623
- else:
624
- return (
625
- "SELECT TABLE_SCHEMA, TABLE_NAME FROM information_schema.tables WHERE TABLE_TYPE LIKE 'VIEW';",
626
- tuple(),
627
- )
628
-
629
- class TYPES(object):
630
- TEXT = "TEXT"
631
- INTEGER = "INTEGER"
632
- NUMERIC = "NUMERIC"
633
- DATETIME = "DATETIME"
634
- TIMESTAMP = "TIMESTAMP"
635
- DATE = "DATE"
636
- TIME = "TIME"
637
- BIGINT = "BIGINT"
638
- SMALLINT = "SMALLINT"
639
- BOOLEAN = "BIT"
640
- BINARY = "BLOB"
641
- INTERVAL = "INTERVAL"