velocity-python 0.0.105__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 -792
- velocity/db/core/result.py +36 -22
- velocity/db/core/row.py +15 -3
- velocity/db/core/table.py +283 -44
- 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.105.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.105.dist-info/RECORD +0 -56
- {velocity_python-0.0.105.dist-info → velocity_python-0.0.155.dist-info}/WHEEL +0 -0
- {velocity_python-0.0.105.dist-info → velocity_python-0.0.155.dist-info}/licenses/LICENSE +0 -0
- {velocity_python-0.0.105.dist-info → velocity_python-0.0.155.dist-info}/top_level.txt +0 -0
velocity/db/servers/sqlite.py
DELETED
|
@@ -1,968 +0,0 @@
|
|
|
1
|
-
import re
|
|
2
|
-
import hashlib
|
|
3
|
-
import decimal
|
|
4
|
-
import datetime
|
|
5
|
-
|
|
6
|
-
from velocity.db import exceptions
|
|
7
|
-
from .sqlite_reserved import reserved_words
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
def initialize(config):
|
|
11
|
-
import sqlite3
|
|
12
|
-
from velocity.db.core.engine import Engine
|
|
13
|
-
|
|
14
|
-
return Engine(sqlite3, config, SQL)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def quote(data):
|
|
18
|
-
if isinstance(data, list):
|
|
19
|
-
new = []
|
|
20
|
-
for item in data:
|
|
21
|
-
new.append(quote(item))
|
|
22
|
-
return new
|
|
23
|
-
else:
|
|
24
|
-
parts = data.split(".")
|
|
25
|
-
new = []
|
|
26
|
-
for part in parts:
|
|
27
|
-
if '"' in part:
|
|
28
|
-
new.append(part)
|
|
29
|
-
elif part.upper() in reserved_words:
|
|
30
|
-
new.append('"' + part + '"')
|
|
31
|
-
elif re.findall("[/]", part):
|
|
32
|
-
new.append('"' + part + '"')
|
|
33
|
-
else:
|
|
34
|
-
new.append(part)
|
|
35
|
-
return ".".join(new)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
class SQL(object):
|
|
39
|
-
server = "SQLite3"
|
|
40
|
-
type_column_identifier = "data_type"
|
|
41
|
-
is_nullable = "is_nullable"
|
|
42
|
-
|
|
43
|
-
default_schema = ""
|
|
44
|
-
|
|
45
|
-
ApplicationErrorCodes = []
|
|
46
|
-
|
|
47
|
-
DatabaseMissingErrorCodes = []
|
|
48
|
-
TableMissingErrorCodes = []
|
|
49
|
-
ColumnMissingErrorCodes = []
|
|
50
|
-
ForeignKeyMissingErrorCodes = []
|
|
51
|
-
|
|
52
|
-
ConnectionErrorCodes = []
|
|
53
|
-
DuplicateKeyErrorCodes = []
|
|
54
|
-
RetryTransactionCodes = []
|
|
55
|
-
TruncationErrorCodes = []
|
|
56
|
-
LockTimeoutErrorCodes = []
|
|
57
|
-
DatabaseObjectExistsErrorCodes = []
|
|
58
|
-
|
|
59
|
-
@classmethod
|
|
60
|
-
def version(cls):
|
|
61
|
-
return "select version()", tuple()
|
|
62
|
-
|
|
63
|
-
@classmethod
|
|
64
|
-
def timestamp(cls):
|
|
65
|
-
return "select current_timestamp", tuple()
|
|
66
|
-
|
|
67
|
-
@classmethod
|
|
68
|
-
def user(cls):
|
|
69
|
-
return "select current_user", tuple()
|
|
70
|
-
|
|
71
|
-
@classmethod
|
|
72
|
-
def databases(cls):
|
|
73
|
-
return "select datname from pg_database where datistemplate = false", tuple()
|
|
74
|
-
|
|
75
|
-
@classmethod
|
|
76
|
-
def schemas(cls):
|
|
77
|
-
return "select schema_name from information_schema.schemata", tuple()
|
|
78
|
-
|
|
79
|
-
@classmethod
|
|
80
|
-
def current_schema(cls):
|
|
81
|
-
return "select current_schema", tuple()
|
|
82
|
-
|
|
83
|
-
@classmethod
|
|
84
|
-
def current_database(cls):
|
|
85
|
-
return "select current_database()", tuple()
|
|
86
|
-
|
|
87
|
-
@classmethod
|
|
88
|
-
def tables(cls, system=False):
|
|
89
|
-
return "SELECT name FROM sqlite_master WHERE type='table';", tuple()
|
|
90
|
-
|
|
91
|
-
@classmethod
|
|
92
|
-
def views(cls, system=False):
|
|
93
|
-
if system:
|
|
94
|
-
return 'SELECT name FROM sqlite_master WHERE type="view";', tuple()
|
|
95
|
-
else:
|
|
96
|
-
return 'SELECT name FROM sqlite_master WHERE type="view";', tuple()
|
|
97
|
-
|
|
98
|
-
@classmethod
|
|
99
|
-
def __has_pointer(cls, columns):
|
|
100
|
-
if columns:
|
|
101
|
-
if isinstance(columns, list):
|
|
102
|
-
columns = ",".join(columns)
|
|
103
|
-
if ">" in columns:
|
|
104
|
-
return True
|
|
105
|
-
return False
|
|
106
|
-
|
|
107
|
-
@classmethod
|
|
108
|
-
def select(
|
|
109
|
-
cls,
|
|
110
|
-
columns=None,
|
|
111
|
-
table=None,
|
|
112
|
-
where=None,
|
|
113
|
-
orderby=None,
|
|
114
|
-
groupby=None,
|
|
115
|
-
having=None,
|
|
116
|
-
start=None,
|
|
117
|
-
qty=None,
|
|
118
|
-
tbl=None,
|
|
119
|
-
):
|
|
120
|
-
is_join = False
|
|
121
|
-
|
|
122
|
-
if isinstance(columns, str) and "distinct" in columns.lower():
|
|
123
|
-
sql = [
|
|
124
|
-
"SELECT",
|
|
125
|
-
columns,
|
|
126
|
-
"FROM",
|
|
127
|
-
quote(table),
|
|
128
|
-
]
|
|
129
|
-
elif cls.__has_pointer(columns):
|
|
130
|
-
if isinstance(columns, str):
|
|
131
|
-
columns = columns.split(",")
|
|
132
|
-
letter = 65
|
|
133
|
-
tables = {table: chr(letter)}
|
|
134
|
-
letter += 1
|
|
135
|
-
__select = []
|
|
136
|
-
__from = ["{} AS {}".format(quote(table), tables.get(table))]
|
|
137
|
-
__left_join = []
|
|
138
|
-
|
|
139
|
-
for column in columns:
|
|
140
|
-
if ">" in column:
|
|
141
|
-
is_join = True
|
|
142
|
-
parts = column.split(">")
|
|
143
|
-
foreign = tbl.foreign_key_info(parts[0])
|
|
144
|
-
if not foreign:
|
|
145
|
-
raise exceptions.DbApplicationError("Foreign key not defined")
|
|
146
|
-
ref_table = foreign["referenced_table_name"]
|
|
147
|
-
ref_schema = foreign["referenced_table_schema"]
|
|
148
|
-
ref_column = foreign["referenced_column_name"]
|
|
149
|
-
lookup = "{}:{}".format(ref_table, parts[0])
|
|
150
|
-
if lookup in tables:
|
|
151
|
-
__select.append(
|
|
152
|
-
'{}."{}" as "{}"'.format(
|
|
153
|
-
tables.get(lookup), parts[1], "_".join(parts)
|
|
154
|
-
)
|
|
155
|
-
)
|
|
156
|
-
else:
|
|
157
|
-
tables[lookup] = chr(letter)
|
|
158
|
-
letter += 1
|
|
159
|
-
__select.append(
|
|
160
|
-
'{}."{}" as "{}"'.format(
|
|
161
|
-
tables.get(lookup), parts[1], "_".join(parts)
|
|
162
|
-
)
|
|
163
|
-
)
|
|
164
|
-
__left_join.append(
|
|
165
|
-
'LEFT OUTER JOIN "{}"."{}" AS {}'.format(
|
|
166
|
-
ref_schema, ref_table, tables.get(lookup)
|
|
167
|
-
)
|
|
168
|
-
)
|
|
169
|
-
__left_join.append(
|
|
170
|
-
'ON {}."{}" = {}."{}"'.format(
|
|
171
|
-
tables.get(table),
|
|
172
|
-
parts[0],
|
|
173
|
-
tables.get(lookup),
|
|
174
|
-
ref_column,
|
|
175
|
-
)
|
|
176
|
-
)
|
|
177
|
-
if orderby and column in orderby:
|
|
178
|
-
orderby = orderby.replace(
|
|
179
|
-
column, "{}.{}".format(tables.get(lookup), parts[1])
|
|
180
|
-
)
|
|
181
|
-
else:
|
|
182
|
-
if "(" in column:
|
|
183
|
-
__select.append(column)
|
|
184
|
-
else:
|
|
185
|
-
__select.append("{}.{}".format(tables.get(table), column))
|
|
186
|
-
sql = ["SELECT"]
|
|
187
|
-
sql.append(",".join(__select))
|
|
188
|
-
sql.append("FROM")
|
|
189
|
-
sql.extend(__from)
|
|
190
|
-
sql.extend(__left_join)
|
|
191
|
-
else:
|
|
192
|
-
if columns:
|
|
193
|
-
if isinstance(columns, str):
|
|
194
|
-
columns = columns.split(",")
|
|
195
|
-
if isinstance(columns, list):
|
|
196
|
-
columns = quote(columns)
|
|
197
|
-
columns = ",".join(columns)
|
|
198
|
-
else:
|
|
199
|
-
columns = "*"
|
|
200
|
-
sql = [
|
|
201
|
-
"SELECT",
|
|
202
|
-
columns,
|
|
203
|
-
"FROM",
|
|
204
|
-
quote(table),
|
|
205
|
-
]
|
|
206
|
-
vals = []
|
|
207
|
-
if where:
|
|
208
|
-
sql.append("WHERE")
|
|
209
|
-
if isinstance(where, dict):
|
|
210
|
-
where = [x for x in where.items()]
|
|
211
|
-
if isinstance(where, list):
|
|
212
|
-
join = ""
|
|
213
|
-
for key, val in where:
|
|
214
|
-
if join:
|
|
215
|
-
sql.append(join)
|
|
216
|
-
if is_join:
|
|
217
|
-
if "." not in key:
|
|
218
|
-
key = "A." + key
|
|
219
|
-
if val == None:
|
|
220
|
-
if "!" in key:
|
|
221
|
-
key = key.replace("!", "")
|
|
222
|
-
sql.append("{} is not NULL".format(quote(key.lower())))
|
|
223
|
-
else:
|
|
224
|
-
sql.append("{} is NULL".format(quote(key.lower())))
|
|
225
|
-
elif isinstance(val, (list, tuple)):
|
|
226
|
-
if "!" in key:
|
|
227
|
-
key = key.replace("!", "")
|
|
228
|
-
sql.append("{} not in ?".format(quote(key.lower())))
|
|
229
|
-
vals.append(tuple(val))
|
|
230
|
-
else:
|
|
231
|
-
sql.append("{} in ?".format(quote(key.lower())))
|
|
232
|
-
vals.append(tuple(val))
|
|
233
|
-
else:
|
|
234
|
-
if "<>" in key:
|
|
235
|
-
key = key.replace("<>", "")
|
|
236
|
-
op = "<>"
|
|
237
|
-
elif "!=" in key:
|
|
238
|
-
key = key.replace("!=", "")
|
|
239
|
-
op = "<>"
|
|
240
|
-
elif "!%" in key:
|
|
241
|
-
key = key.replace("!%", "")
|
|
242
|
-
op = "not ilike"
|
|
243
|
-
elif "%%" in key:
|
|
244
|
-
key = key.replace("%%", "")
|
|
245
|
-
op = "%"
|
|
246
|
-
elif "%>" in key:
|
|
247
|
-
key = key.replace("%>", "")
|
|
248
|
-
op = "%>"
|
|
249
|
-
elif "<%" in key:
|
|
250
|
-
key = key.replace("<%", "")
|
|
251
|
-
op = "<%"
|
|
252
|
-
elif "==" in key:
|
|
253
|
-
key = key.replace("==", "")
|
|
254
|
-
op = "="
|
|
255
|
-
elif "<=" in key:
|
|
256
|
-
key = key.replace("<=", "")
|
|
257
|
-
op = "<="
|
|
258
|
-
elif ">=" in key:
|
|
259
|
-
key = key.replace(">=", "")
|
|
260
|
-
op = ">="
|
|
261
|
-
elif "<" in key:
|
|
262
|
-
key = key.replace("<", "")
|
|
263
|
-
op = "<"
|
|
264
|
-
elif ">" in key:
|
|
265
|
-
key = key.replace(">", "")
|
|
266
|
-
op = ">"
|
|
267
|
-
elif "%" in key:
|
|
268
|
-
key = key.replace("%", "")
|
|
269
|
-
op = "ilike"
|
|
270
|
-
elif "!" in key:
|
|
271
|
-
key = key.replace("!", "")
|
|
272
|
-
op = "<>"
|
|
273
|
-
elif "=" in key:
|
|
274
|
-
key = key.replace("=", "")
|
|
275
|
-
op = "="
|
|
276
|
-
else:
|
|
277
|
-
op = "="
|
|
278
|
-
if isinstance(val, str) and val[:2] == "@@":
|
|
279
|
-
sql.append(
|
|
280
|
-
"{} {} {}".format(quote(key.lower()), op, val[2:])
|
|
281
|
-
)
|
|
282
|
-
else:
|
|
283
|
-
sql.append("{} {} ?".format(quote(key.lower()), op))
|
|
284
|
-
vals.append(val)
|
|
285
|
-
join = "AND"
|
|
286
|
-
else:
|
|
287
|
-
sql.append(where)
|
|
288
|
-
if groupby:
|
|
289
|
-
sql.append("GROUP BY")
|
|
290
|
-
if isinstance(groupby, (list, tuple)):
|
|
291
|
-
groupby = ",".join(groupby)
|
|
292
|
-
sql.append(groupby)
|
|
293
|
-
if having:
|
|
294
|
-
sql.append("HAVING")
|
|
295
|
-
if isinstance(having, (list, tuple)):
|
|
296
|
-
having = ",".join(having)
|
|
297
|
-
sql.append(having)
|
|
298
|
-
if orderby:
|
|
299
|
-
sql.append("ORDER BY")
|
|
300
|
-
if isinstance(orderby, (list, tuple)):
|
|
301
|
-
orderby = ",".join(orderby)
|
|
302
|
-
sql.append(orderby)
|
|
303
|
-
if start and qty:
|
|
304
|
-
sql.append("OFFSET {} ROWS FETCH NEXT {} ROWS ONLY".format(start, qty))
|
|
305
|
-
elif start:
|
|
306
|
-
sql.append("OFFSET {} ROWS".format(start))
|
|
307
|
-
elif qty:
|
|
308
|
-
sql.append("FETCH NEXT {} ROWS ONLY".format(qty))
|
|
309
|
-
sql = " ".join(sql)
|
|
310
|
-
return sql, tuple(vals)
|
|
311
|
-
|
|
312
|
-
@classmethod
|
|
313
|
-
def create_database(cls, name):
|
|
314
|
-
return "create database " + name, tuple()
|
|
315
|
-
|
|
316
|
-
@classmethod
|
|
317
|
-
def last_id(cls, table):
|
|
318
|
-
return "SELECT last_insert_rowid()", tuple()
|
|
319
|
-
|
|
320
|
-
@classmethod
|
|
321
|
-
def drop_database(cls, name):
|
|
322
|
-
return "drop database if exists " + name, tuple()
|
|
323
|
-
|
|
324
|
-
@classmethod
|
|
325
|
-
def create_table(cls, name, columns={}, drop=False):
|
|
326
|
-
sql = []
|
|
327
|
-
if drop:
|
|
328
|
-
sql.append(cls.drop_table(name))
|
|
329
|
-
sql.append(
|
|
330
|
-
"""
|
|
331
|
-
CREATE TABLE {0} (
|
|
332
|
-
sys_id INTEGER PRIMARY KEY,
|
|
333
|
-
sys_modified TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
334
|
-
sys_created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
335
|
-
""".format(
|
|
336
|
-
name
|
|
337
|
-
)
|
|
338
|
-
)
|
|
339
|
-
|
|
340
|
-
for key, val in columns.items():
|
|
341
|
-
sql.append(",\n{} {}".format(quote(key), cls.get_type(val)))
|
|
342
|
-
|
|
343
|
-
sql.append("\n);")
|
|
344
|
-
return "\n\t".join(sql), tuple()
|
|
345
|
-
|
|
346
|
-
@classmethod
|
|
347
|
-
def drop_table(cls, name):
|
|
348
|
-
return "drop table if exists {}".format(quote(name)), tuple()
|
|
349
|
-
|
|
350
|
-
@classmethod
|
|
351
|
-
def columns(cls, name):
|
|
352
|
-
return "PRAGMA table_info({})".format(name), tuple()
|
|
353
|
-
|
|
354
|
-
@classmethod
|
|
355
|
-
def column_info(cls, table, name):
|
|
356
|
-
params = table.split(".")
|
|
357
|
-
params.append(name)
|
|
358
|
-
if "." in table:
|
|
359
|
-
return """
|
|
360
|
-
select *
|
|
361
|
-
from information_schema.columns
|
|
362
|
-
where table_schema = ?
|
|
363
|
-
and table_name = ?
|
|
364
|
-
and column_name = ?
|
|
365
|
-
""", tuple(
|
|
366
|
-
params
|
|
367
|
-
)
|
|
368
|
-
else:
|
|
369
|
-
return """
|
|
370
|
-
select *
|
|
371
|
-
from information_schema.columns
|
|
372
|
-
where table_name = ?
|
|
373
|
-
and column_name = ?
|
|
374
|
-
""", tuple(
|
|
375
|
-
params
|
|
376
|
-
)
|
|
377
|
-
|
|
378
|
-
@classmethod
|
|
379
|
-
def primary_keys(cls, table):
|
|
380
|
-
params = table.split(".")
|
|
381
|
-
params.reverse()
|
|
382
|
-
if "." in table:
|
|
383
|
-
return """
|
|
384
|
-
SELECT
|
|
385
|
-
pg_attribute.attname
|
|
386
|
-
FROM pg_index, pg_class, pg_attribute, pg_namespace
|
|
387
|
-
WHERE
|
|
388
|
-
pg_class.oid = %s::regclass AND
|
|
389
|
-
indrelid = pg_class.oid AND
|
|
390
|
-
nspname = %s AND
|
|
391
|
-
pg_class.relnamespace = pg_namespace.oid AND
|
|
392
|
-
pg_attribute.attrelid = pg_class.oid AND
|
|
393
|
-
pg_attribute.attnum = any(pg_index.indkey)
|
|
394
|
-
AND indisprimary
|
|
395
|
-
""", tuple(
|
|
396
|
-
params
|
|
397
|
-
)
|
|
398
|
-
else:
|
|
399
|
-
return """
|
|
400
|
-
SELECT
|
|
401
|
-
pg_attribute.attname
|
|
402
|
-
FROM pg_index, pg_class, pg_attribute, pg_namespace
|
|
403
|
-
WHERE
|
|
404
|
-
pg_class.oid = %s::regclass AND
|
|
405
|
-
indrelid = pg_class.oid AND
|
|
406
|
-
pg_class.relnamespace = pg_namespace.oid AND
|
|
407
|
-
pg_attribute.attrelid = pg_class.oid AND
|
|
408
|
-
pg_attribute.attnum = any(pg_index.indkey)
|
|
409
|
-
AND indisprimary
|
|
410
|
-
""", tuple(
|
|
411
|
-
params
|
|
412
|
-
)
|
|
413
|
-
|
|
414
|
-
@classmethod
|
|
415
|
-
def foreign_key_info(cls, table=None, column=None, schema=None):
|
|
416
|
-
if "." in table:
|
|
417
|
-
schema, table = table.split(".")
|
|
418
|
-
|
|
419
|
-
sql = """
|
|
420
|
-
SELECT sql
|
|
421
|
-
FROM (
|
|
422
|
-
SELECT
|
|
423
|
-
sql sql,
|
|
424
|
-
type type,
|
|
425
|
-
tbl_name AS referenced_table_name,
|
|
426
|
-
name AS referenced_column_name,
|
|
427
|
-
NULL AS referenced_table_schema
|
|
428
|
-
FROM sqlite_master
|
|
429
|
-
UNION ALL
|
|
430
|
-
SELECT
|
|
431
|
-
sql,
|
|
432
|
-
type,
|
|
433
|
-
referenced_table_name,
|
|
434
|
-
referenced_column_name,
|
|
435
|
-
referenced_table_schema
|
|
436
|
-
FROM sqlite_temp_master
|
|
437
|
-
)
|
|
438
|
-
WHERE type != 'meta'
|
|
439
|
-
AND sql NOTNULL
|
|
440
|
-
AND name NOT LIKE 'sqlite_%'
|
|
441
|
-
ORDER BY substr(type, 2, 1), name
|
|
442
|
-
"""
|
|
443
|
-
|
|
444
|
-
return sql, tuple()
|
|
445
|
-
|
|
446
|
-
@classmethod
|
|
447
|
-
def create_index(
|
|
448
|
-
cls,
|
|
449
|
-
table=None,
|
|
450
|
-
columns=None,
|
|
451
|
-
unique=False,
|
|
452
|
-
direction=None,
|
|
453
|
-
name=None,
|
|
454
|
-
schema=None,
|
|
455
|
-
tbl=None,
|
|
456
|
-
):
|
|
457
|
-
if "." not in table and schema:
|
|
458
|
-
table = "{}.{}".format(schema, table)
|
|
459
|
-
if isinstance(columns, (list, set)):
|
|
460
|
-
columns = ",".join([quote(c.lower()) for c in sorted(columns)])
|
|
461
|
-
else:
|
|
462
|
-
columns = quote(columns)
|
|
463
|
-
sql = ["CREATE"]
|
|
464
|
-
if unique:
|
|
465
|
-
sql.append("UNIQUE")
|
|
466
|
-
sql.append("INDEX")
|
|
467
|
-
tablename = quote(table)
|
|
468
|
-
if not name:
|
|
469
|
-
name = re.sub(r"\([^)]*\)", "", columns.replace(",", "_"))
|
|
470
|
-
sql.append("IDX__{}__{}".format(table.replace(".", "_"), name))
|
|
471
|
-
sql.append("ON")
|
|
472
|
-
sql.append(tablename)
|
|
473
|
-
sql.append("(")
|
|
474
|
-
sql.append(columns)
|
|
475
|
-
sql.append(")")
|
|
476
|
-
return " ".join(sql), tuple()
|
|
477
|
-
|
|
478
|
-
# Copied from PostGreSQL
|
|
479
|
-
@classmethod
|
|
480
|
-
def create_foreign_key(
|
|
481
|
-
cls, table, columns, key_to_table, key_to_columns, name=None, schema=None
|
|
482
|
-
):
|
|
483
|
-
if not name:
|
|
484
|
-
m = hashlib.md5()
|
|
485
|
-
m.update(table.name)
|
|
486
|
-
m.update(" ".join(columns))
|
|
487
|
-
m.update(key_to_table)
|
|
488
|
-
m.update(" ".join(key_to_columns))
|
|
489
|
-
name = "FK_" + m.hexdigest()
|
|
490
|
-
|
|
491
|
-
original_name = table.name
|
|
492
|
-
|
|
493
|
-
# Get SQL query to generate table
|
|
494
|
-
sql = (
|
|
495
|
-
table.tx.table("sqlite_master")
|
|
496
|
-
.select(columns="sql", where={"name": table.name, "type": "table"})
|
|
497
|
-
.scalar()
|
|
498
|
-
)
|
|
499
|
-
|
|
500
|
-
# Rename original table
|
|
501
|
-
table.rename(table.name + "_original_data")
|
|
502
|
-
|
|
503
|
-
key_info = ""
|
|
504
|
-
if isinstance(columns, list) and isinstance(key_to_columns, list):
|
|
505
|
-
for c in columns:
|
|
506
|
-
key_info += """,
|
|
507
|
-
CONSTRAINT {}
|
|
508
|
-
FOREIGN KEY ({})
|
|
509
|
-
REFERENCES {}({})
|
|
510
|
-
""".format(
|
|
511
|
-
name, c, key_to_table, key_to_columns[columns.index(c)]
|
|
512
|
-
)
|
|
513
|
-
elif isinstance(columns, str) and isinstance(key_to_columns, str):
|
|
514
|
-
key_info += """,
|
|
515
|
-
CONSTRAINT {}
|
|
516
|
-
FOREIGN KEY ({})
|
|
517
|
-
REFERENCES {}({})
|
|
518
|
-
""".format(
|
|
519
|
-
name, columns, key_to_table, key_to_columns
|
|
520
|
-
)
|
|
521
|
-
else:
|
|
522
|
-
print('Error parsing argument "columns" or "key_to_columns"')
|
|
523
|
-
|
|
524
|
-
# Splits "CREATE TABLE" portion out to be readded to lines at the end
|
|
525
|
-
sql_data = sql.split("(", 1)
|
|
526
|
-
|
|
527
|
-
# Goes through the SQL code to generate table and adds foreign key info
|
|
528
|
-
sql_list = sql_data[1].replace("\n", " ").split(",")
|
|
529
|
-
new_sql_list = []
|
|
530
|
-
for line in sql_list:
|
|
531
|
-
line = line.strip().lower()
|
|
532
|
-
for line in sql_list:
|
|
533
|
-
if sql_list.index(line) == len(sql_list) - 1:
|
|
534
|
-
if ")" in line:
|
|
535
|
-
if line.index(")") == len(line) - 1:
|
|
536
|
-
new_sql_list.append(line.replace(")", (key_info + ")")))
|
|
537
|
-
else:
|
|
538
|
-
new_sql_list.append(line)
|
|
539
|
-
|
|
540
|
-
# Enable changes to be made to foreign keys
|
|
541
|
-
table.tx.execute("PRAGMA foreign_keys=off;")
|
|
542
|
-
|
|
543
|
-
# Add sql code to recreate original table with foreign keys
|
|
544
|
-
create_db = ",".join(new_sql_list)
|
|
545
|
-
# Adds "CREATE TABLE" portion back into sql code for execution
|
|
546
|
-
create_db = "(".join([sql_data[0], create_db])
|
|
547
|
-
table.tx.execute(create_db)
|
|
548
|
-
|
|
549
|
-
# Create new table with original table name and copy all data from original table
|
|
550
|
-
table.tx.execute(
|
|
551
|
-
"INSERT INTO {} SELECT * FROM {};".format(original_name, table.name)
|
|
552
|
-
)
|
|
553
|
-
# Enable foreign keys
|
|
554
|
-
create_db = "PRAGMA foreign_keys=on;"
|
|
555
|
-
|
|
556
|
-
return create_db, tuple()
|
|
557
|
-
|
|
558
|
-
@classmethod
|
|
559
|
-
def drop_index(cls, table=None, columns=None, name=None, schema=None):
|
|
560
|
-
if "." not in table and schema:
|
|
561
|
-
table = "{}.{}".format(schema, table)
|
|
562
|
-
if isinstance(columns, (list, set)):
|
|
563
|
-
columns = ",".join([quote(c.lower()) for c in sorted(columns)])
|
|
564
|
-
else:
|
|
565
|
-
columns = quote(columns)
|
|
566
|
-
sql = ["DROP"]
|
|
567
|
-
sql.append("INDEX IF EXISTS")
|
|
568
|
-
tablename = quote(table)
|
|
569
|
-
if not name:
|
|
570
|
-
name = re.sub(r"\([^)]*\)", "", columns.replace(",", "_"))
|
|
571
|
-
sql.append("IDX__{}__{}".format(table.replace(".", "_"), name))
|
|
572
|
-
return " ".join(sql), tuple()
|
|
573
|
-
|
|
574
|
-
@classmethod
|
|
575
|
-
def insert(cls, table, data):
|
|
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
|
-
elif isinstance(val, bytearray):
|
|
584
|
-
vals.append("?")
|
|
585
|
-
args.append(bytes(val))
|
|
586
|
-
else:
|
|
587
|
-
vals.append("?")
|
|
588
|
-
args.append(val)
|
|
589
|
-
|
|
590
|
-
sql = ["INSERT INTO"]
|
|
591
|
-
sql.append(quote(table))
|
|
592
|
-
sql.append("(")
|
|
593
|
-
sql.append(",".join(keys))
|
|
594
|
-
sql.append(")")
|
|
595
|
-
sql.append("VALUES")
|
|
596
|
-
sql.append("(")
|
|
597
|
-
sql.append(",".join(vals))
|
|
598
|
-
sql.append(")")
|
|
599
|
-
sql = " ".join(sql)
|
|
600
|
-
return sql, tuple(args)
|
|
601
|
-
|
|
602
|
-
@classmethod
|
|
603
|
-
def update(cls, table, data, pk):
|
|
604
|
-
sql = ["UPDATE"]
|
|
605
|
-
sql.append(quote(table))
|
|
606
|
-
sql.append("SET")
|
|
607
|
-
vals = []
|
|
608
|
-
join = ""
|
|
609
|
-
for key in data.keys():
|
|
610
|
-
val = data[key]
|
|
611
|
-
if join:
|
|
612
|
-
sql.append(join)
|
|
613
|
-
if isinstance(val, str) and val[:2] == "@@":
|
|
614
|
-
sql.append("{} = {}".format(quote(key.lower()), val[2:]))
|
|
615
|
-
elif isinstance(val, bytearray):
|
|
616
|
-
sql.append("{} = ?".format(quote(key.lower())))
|
|
617
|
-
vals.append(bytes(val))
|
|
618
|
-
else:
|
|
619
|
-
sql.append("{} = ?".format(quote(key.lower())))
|
|
620
|
-
vals.append(val)
|
|
621
|
-
join = ","
|
|
622
|
-
if pk:
|
|
623
|
-
if isinstance(pk, list):
|
|
624
|
-
items = pk
|
|
625
|
-
elif isinstance(pk, dict):
|
|
626
|
-
items = pk.items()
|
|
627
|
-
sql.append("\nWHERE")
|
|
628
|
-
join = ""
|
|
629
|
-
for key, val in items:
|
|
630
|
-
if join:
|
|
631
|
-
sql.append(join)
|
|
632
|
-
if val is None:
|
|
633
|
-
if "!" in key:
|
|
634
|
-
key = key.replace("!", "")
|
|
635
|
-
sql.append("{} is not NULL".format(quote(key.lower())))
|
|
636
|
-
else:
|
|
637
|
-
sql.append("{} is NULL".format(quote(key.lower())))
|
|
638
|
-
elif isinstance(val, (tuple, list)):
|
|
639
|
-
if "!" in key:
|
|
640
|
-
key = key.replace("!", "")
|
|
641
|
-
sql.append("{} not in ?".format(quote(key.lower())))
|
|
642
|
-
vals.append(tuple(val))
|
|
643
|
-
else:
|
|
644
|
-
sql.append("{} in ?".format(quote(key.lower())))
|
|
645
|
-
vals.append(tuple(val))
|
|
646
|
-
else:
|
|
647
|
-
if "<>" in key:
|
|
648
|
-
key = key.replace("<>", "")
|
|
649
|
-
op = "<>"
|
|
650
|
-
elif "!=" in key:
|
|
651
|
-
key = key.replace("!=", "")
|
|
652
|
-
op = "<>"
|
|
653
|
-
elif "!%" in key:
|
|
654
|
-
key = key.replace("!%", "")
|
|
655
|
-
op = "not ilike"
|
|
656
|
-
elif "%%" in key:
|
|
657
|
-
key = key.replace("%%", "")
|
|
658
|
-
op = "%"
|
|
659
|
-
elif "%>" in key:
|
|
660
|
-
key = key.replace("%>", "")
|
|
661
|
-
op = "%>"
|
|
662
|
-
elif "<%" in key:
|
|
663
|
-
key = key.replace("<%", "")
|
|
664
|
-
op = "<%"
|
|
665
|
-
elif "==" in key:
|
|
666
|
-
key = key.replace("==", "")
|
|
667
|
-
op = "="
|
|
668
|
-
elif "<=" in key:
|
|
669
|
-
key = key.replace("<=", "")
|
|
670
|
-
op = "<="
|
|
671
|
-
elif ">=" in key:
|
|
672
|
-
key = key.replace(">=", "")
|
|
673
|
-
op = ">="
|
|
674
|
-
elif "<" in key:
|
|
675
|
-
key = key.replace("<", "")
|
|
676
|
-
op = "<"
|
|
677
|
-
elif ">" in key:
|
|
678
|
-
key = key.replace(">", "")
|
|
679
|
-
op = ">"
|
|
680
|
-
elif "%" in key:
|
|
681
|
-
key = key.replace("%", "")
|
|
682
|
-
op = "ilike"
|
|
683
|
-
elif "!" in key:
|
|
684
|
-
key = key.replace("!", "")
|
|
685
|
-
op = "<>"
|
|
686
|
-
elif "=" in key:
|
|
687
|
-
key = key.replace("=", "")
|
|
688
|
-
op = "="
|
|
689
|
-
else:
|
|
690
|
-
op = "="
|
|
691
|
-
if isinstance(val, str) and val[:2] == "@@":
|
|
692
|
-
sql.append("{} {} {}".format(quote(key.lower()), op, val[2:]))
|
|
693
|
-
else:
|
|
694
|
-
sql.append("{} {} ?".format(quote(key.lower()), op))
|
|
695
|
-
vals.append(val)
|
|
696
|
-
join = "AND"
|
|
697
|
-
sql = " ".join(sql)
|
|
698
|
-
return sql, tuple(vals)
|
|
699
|
-
|
|
700
|
-
@classmethod
|
|
701
|
-
def get_type(cls, v):
|
|
702
|
-
if isinstance(v, str):
|
|
703
|
-
if v[:2] == "@@":
|
|
704
|
-
return v[2:] or cls.TYPES.TEXT
|
|
705
|
-
elif isinstance(v, (str, bytes)) or v is str or v is bytes:
|
|
706
|
-
return cls.TYPES.TEXT
|
|
707
|
-
elif isinstance(v, bool) or v is bool:
|
|
708
|
-
return cls.TYPES.BOOLEAN
|
|
709
|
-
elif isinstance(v, int) or v is int:
|
|
710
|
-
if v is int:
|
|
711
|
-
return cls.TYPES.INTEGER
|
|
712
|
-
if v > 2147483647 or v < -2147483648:
|
|
713
|
-
return cls.TYPES.BIGINT
|
|
714
|
-
else:
|
|
715
|
-
return cls.TYPES.INTEGER
|
|
716
|
-
elif isinstance(v, float) or v is float:
|
|
717
|
-
return cls.TYPES.NUMERIC + "(19, 6)"
|
|
718
|
-
elif isinstance(v, decimal.Decimal) or v is decimal.Decimal:
|
|
719
|
-
return cls.TYPES.NUMERIC + "(19, 6)"
|
|
720
|
-
elif isinstance(v, datetime.datetime) or v is datetime.datetime:
|
|
721
|
-
return cls.TYPES.DATETIME
|
|
722
|
-
elif isinstance(v, datetime.date) or v is datetime.date:
|
|
723
|
-
return cls.TYPES.DATE
|
|
724
|
-
elif isinstance(v, datetime.time) or v is datetime.time:
|
|
725
|
-
return cls.TYPES.TIME
|
|
726
|
-
elif isinstance(v, datetime.timedelta) or v is datetime.timedelta:
|
|
727
|
-
return cls.TYPES.INTERVAL
|
|
728
|
-
elif isinstance(v, bytearray) or v is bytearray:
|
|
729
|
-
return cls.TYPES.BINARY
|
|
730
|
-
# Everything else defaults to TEXT, incl. None
|
|
731
|
-
return cls.TYPES.TEXT
|
|
732
|
-
|
|
733
|
-
@classmethod
|
|
734
|
-
def py_type(cls, v):
|
|
735
|
-
v = str(v).upper()
|
|
736
|
-
if v == cls.TYPES.INTEGER:
|
|
737
|
-
return int
|
|
738
|
-
elif v == cls.TYPES.BIGINT:
|
|
739
|
-
return int
|
|
740
|
-
elif v == cls.TYPES.NUMERIC:
|
|
741
|
-
return decimal.Decimal
|
|
742
|
-
elif v == cls.TYPES.TEXT:
|
|
743
|
-
return str
|
|
744
|
-
elif v == cls.TYPES.BOOLEAN:
|
|
745
|
-
return bool
|
|
746
|
-
elif v == cls.TYPES.DATE:
|
|
747
|
-
return datetime.date
|
|
748
|
-
elif v == cls.TYPES.TIME:
|
|
749
|
-
return datetime.time
|
|
750
|
-
elif v == cls.TYPES.DATETIME:
|
|
751
|
-
return datetime.datetime
|
|
752
|
-
elif v == cls.TYPES.INTERVAL:
|
|
753
|
-
return datetime.timedelta
|
|
754
|
-
else:
|
|
755
|
-
raise Exception("unmapped type %s" % v)
|
|
756
|
-
|
|
757
|
-
@classmethod
|
|
758
|
-
def massage_data(cls, data):
|
|
759
|
-
"""
|
|
760
|
-
|
|
761
|
-
:param :
|
|
762
|
-
:param :
|
|
763
|
-
:param :
|
|
764
|
-
:returns:
|
|
765
|
-
"""
|
|
766
|
-
data = {key.lower(): val for key, val in data.items()}
|
|
767
|
-
primaryKey = set(cls.GetPrimaryKeyColumnNames())
|
|
768
|
-
if not primaryKey:
|
|
769
|
-
if not cls.Exists():
|
|
770
|
-
raise exceptions.DbTableMissingError
|
|
771
|
-
dataKeys = set(data.keys()).intersection(primaryKey)
|
|
772
|
-
dataColumns = set(data.keys()).difference(primaryKey)
|
|
773
|
-
pk = {}
|
|
774
|
-
pk.update([(k, data[k]) for k in dataKeys])
|
|
775
|
-
d = {}
|
|
776
|
-
d.update([(k, data[k]) for k in dataColumns])
|
|
777
|
-
return d, pk
|
|
778
|
-
|
|
779
|
-
@classmethod
|
|
780
|
-
def alter_add(cls, table, columns, null_allowed=True):
|
|
781
|
-
sql = []
|
|
782
|
-
null = "NOT NULL" if not null_allowed else ""
|
|
783
|
-
if isinstance(columns, dict):
|
|
784
|
-
for key, val in columns.items():
|
|
785
|
-
sql.append(
|
|
786
|
-
"ALTER TABLE {} ADD {} {} {};".format(
|
|
787
|
-
quote(table), quote(key), cls.get_type(val), null
|
|
788
|
-
)
|
|
789
|
-
)
|
|
790
|
-
return "\n\t".join(sql), tuple()
|
|
791
|
-
|
|
792
|
-
@classmethod
|
|
793
|
-
def alter_drop(cls, table, columns):
|
|
794
|
-
sql = ["ALTER TABLE {} DROP COLUMN".format(quote(table))]
|
|
795
|
-
if isinstance(columns, dict):
|
|
796
|
-
for key, val in columns.items():
|
|
797
|
-
sql.append("{},".format(key))
|
|
798
|
-
if sql[-1][-1] == ",":
|
|
799
|
-
sql[-1] = sql[-1][:-1]
|
|
800
|
-
return "\n\t".join(sql), tuple()
|
|
801
|
-
|
|
802
|
-
@classmethod
|
|
803
|
-
def alter_column_by_type(cls, table, column, value, null_allowed=True):
|
|
804
|
-
sql = ["ALTER TABLE {} ALTER COLUMN".format(quote(table))]
|
|
805
|
-
sql.append("{} {}".format(quote(column), cls.get_type(value)))
|
|
806
|
-
if not null_allowed:
|
|
807
|
-
sql.append("NOT NULL")
|
|
808
|
-
return "\n\t".join(sql), tuple()
|
|
809
|
-
|
|
810
|
-
@classmethod
|
|
811
|
-
def alter_column_by_sql(cls, table, column, value):
|
|
812
|
-
sql = ["ALTER TABLE {} ALTER COLUMN".format(quote(table))]
|
|
813
|
-
sql.append("{} {}".format(quote(column), value))
|
|
814
|
-
return " ".join(sql), tuple()
|
|
815
|
-
|
|
816
|
-
# SQLite3 does not support renaming columns, in order to do so the table must be copied to a version with the new column's name
|
|
817
|
-
@classmethod
|
|
818
|
-
def rename_column(cls, table, orig, new):
|
|
819
|
-
# Solves case parity errors
|
|
820
|
-
orig = orig.lower()
|
|
821
|
-
new = new.lower()
|
|
822
|
-
# Get SQL query to generate table
|
|
823
|
-
sql = (
|
|
824
|
-
table.tx.table("sqlite_master")
|
|
825
|
-
.select(columns="sql", where={"name": table.name, "type": "table"})
|
|
826
|
-
.scalar()
|
|
827
|
-
)
|
|
828
|
-
original_name = table.name
|
|
829
|
-
|
|
830
|
-
# Splits "CREATE TABLE" portion out to be readded to lines at the end
|
|
831
|
-
sql_data = sql.split("(", 1)
|
|
832
|
-
|
|
833
|
-
sql_list = sql_data[1].replace("\n", " ").split(",")
|
|
834
|
-
new_sql_list = []
|
|
835
|
-
for line in sql_list:
|
|
836
|
-
line = line.strip().lower()
|
|
837
|
-
if orig in line:
|
|
838
|
-
if line.index(orig) == 0:
|
|
839
|
-
new_sql_list.append(line.replace(orig, new, 1))
|
|
840
|
-
elif (line[0] == '"' or line[0] == "'") and line.index(orig) == 1:
|
|
841
|
-
new_sql_list.append(line.replace(orig, new, 1))
|
|
842
|
-
else:
|
|
843
|
-
new_sql_list.append(line)
|
|
844
|
-
else:
|
|
845
|
-
new_sql_list.append(line)
|
|
846
|
-
|
|
847
|
-
create_db = ",".join(new_sql_list)
|
|
848
|
-
|
|
849
|
-
# Adds "CREATE TABLE" portion back into sql code for execution
|
|
850
|
-
create_db = "(".join([sql_data[0], create_db])
|
|
851
|
-
create_db += ";"
|
|
852
|
-
|
|
853
|
-
# Rename original table
|
|
854
|
-
table.rename(table.name + "_original_data")
|
|
855
|
-
|
|
856
|
-
table.tx.execute(create_db)
|
|
857
|
-
# Create new table with original table name and copy all data from original table
|
|
858
|
-
create_db = "INSERT INTO {} SELECT * FROM {};".format(original_name, table.name)
|
|
859
|
-
return create_db, tuple()
|
|
860
|
-
|
|
861
|
-
@classmethod
|
|
862
|
-
def rename_table(cls, table, new):
|
|
863
|
-
return "ALTER TABLE {} RENAME TO {};".format(quote(table), quote(new)), tuple()
|
|
864
|
-
|
|
865
|
-
@classmethod
|
|
866
|
-
def create_savepoint(cls, sp):
|
|
867
|
-
return "SAVEPOINT {};".format(sp), tuple()
|
|
868
|
-
|
|
869
|
-
@classmethod
|
|
870
|
-
def release_savepoint(cls, sp):
|
|
871
|
-
return "RELEASE SAVEPOINT {};".format(sp), tuple()
|
|
872
|
-
|
|
873
|
-
@classmethod
|
|
874
|
-
def rollback_savepoint(cls, sp):
|
|
875
|
-
return "ROLLBACK TO SAVEPOINT {};".format(sp), tuple()
|
|
876
|
-
|
|
877
|
-
@classmethod
|
|
878
|
-
def find_duplicates(cls, table, columns, key):
|
|
879
|
-
if isinstance(columns, str):
|
|
880
|
-
columns = [columns]
|
|
881
|
-
return (
|
|
882
|
-
"""
|
|
883
|
-
SELECT {2}
|
|
884
|
-
FROM (SELECT {2},
|
|
885
|
-
ROW_NUMBER() OVER (partition BY {1} ORDER BY {2}) AS rnum
|
|
886
|
-
FROM {0}) t
|
|
887
|
-
WHERE t.rnum > 1;
|
|
888
|
-
""".format(
|
|
889
|
-
table, ",".join(quote(columns)), key
|
|
890
|
-
),
|
|
891
|
-
tuple(),
|
|
892
|
-
)
|
|
893
|
-
|
|
894
|
-
@classmethod
|
|
895
|
-
def delete_duplicates(cls, table, columns, key):
|
|
896
|
-
if isinstance(columns, str):
|
|
897
|
-
columns = [columns]
|
|
898
|
-
return (
|
|
899
|
-
"""
|
|
900
|
-
DELETE FROM {0}
|
|
901
|
-
WHERE {2} IN (SELECT {2}
|
|
902
|
-
FROM (SELECT {2},
|
|
903
|
-
ROW_NUMBER() OVER (partition BY {1} ORDER BY {2}) AS rnum
|
|
904
|
-
FROM {0}) t
|
|
905
|
-
WHERE t.rnum > 1);
|
|
906
|
-
""".format(
|
|
907
|
-
table, ",".join(quote(columns)), key
|
|
908
|
-
),
|
|
909
|
-
tuple(),
|
|
910
|
-
)
|
|
911
|
-
|
|
912
|
-
@classmethod
|
|
913
|
-
def delete(cls, table, where):
|
|
914
|
-
sql = ["DELETE FROM {}".format(table)]
|
|
915
|
-
sql.append("WHERE")
|
|
916
|
-
vals = []
|
|
917
|
-
if isinstance(where, dict):
|
|
918
|
-
join = ""
|
|
919
|
-
for key in sorted(where.keys()):
|
|
920
|
-
if join:
|
|
921
|
-
sql.append(join)
|
|
922
|
-
if where[key] == None:
|
|
923
|
-
sql.append("{} is NULL".format(quote(key.lower())))
|
|
924
|
-
else:
|
|
925
|
-
sql.append("{} = ?".format(quote(key.lower())))
|
|
926
|
-
vals.append(where[key])
|
|
927
|
-
join = "AND"
|
|
928
|
-
else:
|
|
929
|
-
sql.append(where)
|
|
930
|
-
return " ".join(sql), tuple(vals)
|
|
931
|
-
|
|
932
|
-
@classmethod
|
|
933
|
-
def truncate(cls, table):
|
|
934
|
-
return "truncate table {}".format(quote(table)), tuple()
|
|
935
|
-
|
|
936
|
-
@classmethod
|
|
937
|
-
def create_view(cls, name, query, temp=False, silent=True):
|
|
938
|
-
sql = ["CREATE"]
|
|
939
|
-
if silent:
|
|
940
|
-
sql.append("OR REPLACE")
|
|
941
|
-
if temp:
|
|
942
|
-
sql.append("TEMPORARY")
|
|
943
|
-
sql.append("VIEW")
|
|
944
|
-
sql.append(name)
|
|
945
|
-
sql.append("AS")
|
|
946
|
-
sql.append(query)
|
|
947
|
-
return " ".join(sql), tuple()
|
|
948
|
-
|
|
949
|
-
@classmethod
|
|
950
|
-
def drop_view(cls, name, silent=True):
|
|
951
|
-
sql = ["DROP VIEW"]
|
|
952
|
-
if silent:
|
|
953
|
-
sql.append("IF EXISTS")
|
|
954
|
-
sql.append(name)
|
|
955
|
-
return " ".join(sql), tuple()
|
|
956
|
-
|
|
957
|
-
class TYPES(object):
|
|
958
|
-
TEXT = "TEXT"
|
|
959
|
-
INTEGER = "INTEGER"
|
|
960
|
-
NUMERIC = "NUMERIC"
|
|
961
|
-
DATETIME = "TIMESTAMP WITHOUT TIME ZONE"
|
|
962
|
-
TIMESTAMP = "TIMESTAMP WITHOUT TIME ZONE"
|
|
963
|
-
DATE = "DATE"
|
|
964
|
-
TIME = "TIME WITHOUT TIME ZONE"
|
|
965
|
-
BIGINT = "BIGINT"
|
|
966
|
-
BOOLEAN = "BOOLEAN"
|
|
967
|
-
BINARY = "BLOB"
|
|
968
|
-
INTERVAL = "INTERVAL"
|