velocity-python 0.0.109__py3-none-any.whl → 0.0.155__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.
- velocity/__init__.py +3 -1
- velocity/app/orders.py +3 -4
- velocity/app/tests/__init__.py +1 -0
- velocity/app/tests/test_email_processing.py +112 -0
- velocity/app/tests/test_payment_profile_sorting.py +191 -0
- velocity/app/tests/test_spreadsheet_functions.py +124 -0
- velocity/aws/__init__.py +3 -0
- velocity/aws/amplify.py +10 -6
- velocity/aws/handlers/__init__.py +2 -0
- velocity/aws/handlers/base_handler.py +248 -0
- velocity/aws/handlers/context.py +167 -2
- velocity/aws/handlers/exceptions.py +16 -0
- velocity/aws/handlers/lambda_handler.py +24 -85
- velocity/aws/handlers/mixins/__init__.py +16 -0
- velocity/aws/handlers/mixins/activity_tracker.py +181 -0
- velocity/aws/handlers/mixins/aws_session_mixin.py +192 -0
- velocity/aws/handlers/mixins/error_handler.py +192 -0
- velocity/aws/handlers/mixins/legacy_mixin.py +53 -0
- velocity/aws/handlers/mixins/standard_mixin.py +73 -0
- velocity/aws/handlers/response.py +1 -1
- velocity/aws/handlers/sqs_handler.py +28 -143
- velocity/aws/tests/__init__.py +1 -0
- velocity/aws/tests/test_lambda_handler_json_serialization.py +120 -0
- velocity/aws/tests/test_response.py +163 -0
- velocity/db/__init__.py +16 -4
- velocity/db/core/decorators.py +20 -4
- velocity/db/core/engine.py +185 -839
- velocity/db/core/result.py +30 -24
- velocity/db/core/row.py +15 -3
- velocity/db/core/table.py +279 -40
- velocity/db/core/transaction.py +19 -11
- velocity/db/exceptions.py +42 -18
- velocity/db/servers/base/__init__.py +9 -0
- velocity/db/servers/base/initializer.py +70 -0
- velocity/db/servers/base/operators.py +98 -0
- velocity/db/servers/base/sql.py +503 -0
- velocity/db/servers/base/types.py +135 -0
- velocity/db/servers/mysql/__init__.py +73 -0
- velocity/db/servers/mysql/operators.py +54 -0
- velocity/db/servers/{mysql_reserved.py → mysql/reserved.py} +2 -14
- velocity/db/servers/mysql/sql.py +718 -0
- velocity/db/servers/mysql/types.py +107 -0
- velocity/db/servers/postgres/__init__.py +59 -11
- velocity/db/servers/postgres/operators.py +34 -0
- velocity/db/servers/postgres/sql.py +474 -120
- velocity/db/servers/postgres/types.py +88 -2
- velocity/db/servers/sqlite/__init__.py +61 -0
- velocity/db/servers/sqlite/operators.py +52 -0
- velocity/db/servers/sqlite/reserved.py +20 -0
- velocity/db/servers/sqlite/sql.py +677 -0
- velocity/db/servers/sqlite/types.py +92 -0
- velocity/db/servers/sqlserver/__init__.py +73 -0
- velocity/db/servers/sqlserver/operators.py +47 -0
- velocity/db/servers/sqlserver/reserved.py +32 -0
- velocity/db/servers/sqlserver/sql.py +805 -0
- velocity/db/servers/sqlserver/types.py +114 -0
- velocity/db/servers/tablehelper.py +117 -91
- velocity/db/tests/__init__.py +1 -0
- velocity/db/tests/common_db_test.py +0 -0
- velocity/db/tests/postgres/__init__.py +1 -0
- velocity/db/tests/postgres/common.py +49 -0
- velocity/db/tests/postgres/test_column.py +29 -0
- velocity/db/tests/postgres/test_connections.py +25 -0
- velocity/db/tests/postgres/test_database.py +21 -0
- velocity/db/tests/postgres/test_engine.py +205 -0
- velocity/db/tests/postgres/test_general_usage.py +88 -0
- velocity/db/tests/postgres/test_imports.py +8 -0
- velocity/db/tests/postgres/test_result.py +19 -0
- velocity/db/tests/postgres/test_row.py +137 -0
- velocity/db/tests/postgres/test_row_comprehensive.py +720 -0
- velocity/db/tests/postgres/test_schema_locking.py +335 -0
- velocity/db/tests/postgres/test_schema_locking_unit.py +115 -0
- velocity/db/tests/postgres/test_sequence.py +34 -0
- velocity/db/tests/postgres/test_sql_comprehensive.py +462 -0
- velocity/db/tests/postgres/test_table.py +101 -0
- velocity/db/tests/postgres/test_table_comprehensive.py +646 -0
- velocity/db/tests/postgres/test_transaction.py +106 -0
- velocity/db/tests/sql/__init__.py +1 -0
- velocity/db/tests/sql/common.py +177 -0
- velocity/db/tests/sql/test_postgres_select_advanced.py +285 -0
- velocity/db/tests/sql/test_postgres_select_variances.py +517 -0
- velocity/db/tests/test_cursor_rowcount_fix.py +150 -0
- velocity/db/tests/test_db_utils.py +221 -0
- velocity/db/tests/test_postgres.py +448 -0
- velocity/db/tests/test_postgres_unchanged.py +81 -0
- velocity/db/tests/test_process_error_robustness.py +292 -0
- velocity/db/tests/test_result_caching.py +279 -0
- velocity/db/tests/test_result_sql_aware.py +117 -0
- velocity/db/tests/test_row_get_missing_column.py +72 -0
- velocity/db/tests/test_schema_locking_initializers.py +226 -0
- velocity/db/tests/test_schema_locking_simple.py +97 -0
- velocity/db/tests/test_sql_builder.py +165 -0
- velocity/db/tests/test_tablehelper.py +486 -0
- velocity/db/utils.py +62 -47
- velocity/misc/conv/__init__.py +2 -0
- velocity/misc/conv/iconv.py +5 -4
- velocity/misc/export.py +1 -4
- velocity/misc/merge.py +1 -1
- velocity/misc/tests/__init__.py +1 -0
- velocity/misc/tests/test_db.py +90 -0
- velocity/misc/tests/test_fix.py +78 -0
- velocity/misc/tests/test_format.py +64 -0
- velocity/misc/tests/test_iconv.py +203 -0
- velocity/misc/tests/test_merge.py +82 -0
- velocity/misc/tests/test_oconv.py +144 -0
- velocity/misc/tests/test_original_error.py +52 -0
- velocity/misc/tests/test_timer.py +74 -0
- velocity/misc/tools.py +0 -1
- {velocity_python-0.0.109.dist-info → velocity_python-0.0.155.dist-info}/METADATA +2 -2
- velocity_python-0.0.155.dist-info/RECORD +129 -0
- velocity/db/core/exceptions.py +0 -70
- velocity/db/servers/mysql.py +0 -641
- velocity/db/servers/sqlite.py +0 -968
- velocity/db/servers/sqlite_reserved.py +0 -208
- velocity/db/servers/sqlserver.py +0 -921
- velocity/db/servers/sqlserver_reserved.py +0 -314
- velocity_python-0.0.109.dist-info/RECORD +0 -56
- {velocity_python-0.0.109.dist-info → velocity_python-0.0.155.dist-info}/WHEEL +0 -0
- {velocity_python-0.0.109.dist-info → velocity_python-0.0.155.dist-info}/licenses/LICENSE +0 -0
- {velocity_python-0.0.109.dist-info → velocity_python-0.0.155.dist-info}/top_level.txt +0 -0
velocity/db/servers/mysql.py
DELETED
|
@@ -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"
|