velocity-python 0.0.35__py3-none-any.whl → 0.0.64__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.
Potentially problematic release.
This version of velocity-python might be problematic. Click here for more details.
- velocity/__init__.py +1 -1
- velocity/db/core/column.py +25 -105
- velocity/db/core/database.py +79 -23
- velocity/db/core/decorators.py +84 -47
- velocity/db/core/engine.py +179 -184
- velocity/db/core/result.py +94 -49
- velocity/db/core/row.py +81 -46
- velocity/db/core/sequence.py +112 -22
- velocity/db/core/table.py +660 -243
- velocity/db/core/transaction.py +75 -77
- velocity/db/servers/mysql.py +4 -0
- velocity/db/servers/postgres/__init__.py +19 -0
- velocity/db/servers/postgres/operators.py +23 -0
- velocity/db/servers/{postgres.py → postgres/sql.py} +508 -589
- velocity/db/servers/postgres/types.py +109 -0
- velocity/db/servers/tablehelper.py +277 -0
- velocity/misc/conv/iconv.py +277 -91
- velocity/misc/conv/oconv.py +5 -4
- velocity/misc/db.py +2 -2
- velocity/misc/format.py +2 -2
- {velocity_python-0.0.35.dist-info → velocity_python-0.0.64.dist-info}/METADATA +6 -6
- velocity_python-0.0.64.dist-info/RECORD +47 -0
- {velocity_python-0.0.35.dist-info → velocity_python-0.0.64.dist-info}/WHEEL +1 -1
- velocity_python-0.0.35.dist-info/RECORD +0 -43
- /velocity/db/servers/{postgres_reserved.py → postgres/reserved.py} +0 -0
- {velocity_python-0.0.35.dist-info → velocity_python-0.0.64.dist-info}/LICENSE +0 -0
- {velocity_python-0.0.35.dist-info → velocity_python-0.0.64.dist-info}/top_level.txt +0 -0
velocity/db/core/transaction.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import traceback
|
|
2
|
+
|
|
2
3
|
from velocity.db.core.row import Row
|
|
3
4
|
from velocity.db.core.table import Table
|
|
4
5
|
from velocity.db.core.result import Result
|
|
@@ -6,13 +7,14 @@ from velocity.db.core.column import Column
|
|
|
6
7
|
from velocity.db.core.database import Database
|
|
7
8
|
from velocity.db.core.sequence import Sequence
|
|
8
9
|
from velocity.misc.db import randomword
|
|
9
|
-
import traceback
|
|
10
|
-
|
|
11
10
|
|
|
12
11
|
debug = False
|
|
13
12
|
|
|
14
13
|
|
|
15
|
-
class Transaction
|
|
14
|
+
class Transaction:
|
|
15
|
+
"""
|
|
16
|
+
Encapsulates a single transaction in the database (connection + commit/rollback).
|
|
17
|
+
"""
|
|
16
18
|
|
|
17
19
|
def __init__(self, engine, connection=None):
|
|
18
20
|
self.engine = engine
|
|
@@ -23,7 +25,7 @@ class Transaction(object):
|
|
|
23
25
|
c = self.engine.config
|
|
24
26
|
server = c.get("host", c.get("server"))
|
|
25
27
|
database = c.get("database")
|
|
26
|
-
return "{}.transaction({}:{})"
|
|
28
|
+
return f"{self.engine.sql.server}.transaction({server}:{database})"
|
|
27
29
|
|
|
28
30
|
def __enter__(self):
|
|
29
31
|
return self
|
|
@@ -31,104 +33,89 @@ class Transaction(object):
|
|
|
31
33
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
32
34
|
if exc_type:
|
|
33
35
|
if debug:
|
|
34
|
-
print("Transaction.__exit__")
|
|
35
|
-
|
|
36
|
-
if debug:
|
|
37
|
-
print(tb_str)
|
|
36
|
+
print("Transaction.__exit__ - an exception occurred.")
|
|
37
|
+
traceback.print_exc()
|
|
38
38
|
self.rollback()
|
|
39
39
|
self.close()
|
|
40
40
|
|
|
41
41
|
def cursor(self):
|
|
42
|
+
"""
|
|
43
|
+
Retrieves a database cursor, opening a connection if necessary.
|
|
44
|
+
"""
|
|
42
45
|
if not self.connection:
|
|
43
|
-
if debug:
|
|
44
|
-
print(
|
|
45
|
-
">>> {} open connection to {database}".format(
|
|
46
|
-
id(self), **self.engine.config
|
|
47
|
-
)
|
|
48
|
-
)
|
|
49
46
|
self.connection = self.engine.connect()
|
|
50
47
|
if debug:
|
|
51
|
-
print(
|
|
52
|
-
"*** {} open {database}.transaction.connection.cursor".format(
|
|
53
|
-
id(self), **self.engine.config
|
|
54
|
-
)
|
|
55
|
-
)
|
|
48
|
+
print(f"*** {id(self)} --> transaction.cursor()")
|
|
56
49
|
return self.connection.cursor()
|
|
57
50
|
|
|
58
51
|
def close(self):
|
|
52
|
+
"""
|
|
53
|
+
Commits (if needed) and closes the connection.
|
|
54
|
+
"""
|
|
59
55
|
if self.connection:
|
|
60
56
|
self.commit()
|
|
61
57
|
if debug:
|
|
62
|
-
print(
|
|
63
|
-
"<<< {} close connection to {database}".format(
|
|
64
|
-
id(self), **self.engine.config
|
|
65
|
-
)
|
|
66
|
-
)
|
|
58
|
+
print(f"<<< {id(self)} close connection.")
|
|
67
59
|
self.connection.close()
|
|
60
|
+
self.connection = None
|
|
68
61
|
|
|
69
62
|
def execute(self, sql, parms=None, single=False, cursor=None):
|
|
70
|
-
return self._execute(sql, parms
|
|
63
|
+
return self._execute(sql, parms, single, cursor)
|
|
71
64
|
|
|
72
65
|
def _execute(self, sql, parms=None, single=False, cursor=None):
|
|
73
66
|
if single:
|
|
74
67
|
cursor = None
|
|
75
68
|
if not self.connection:
|
|
76
|
-
if debug:
|
|
77
|
-
print(
|
|
78
|
-
">>> {} open connection to {database}".format(
|
|
79
|
-
id(self), **self.engine.config
|
|
80
|
-
)
|
|
81
|
-
)
|
|
82
69
|
self.connection = self.engine.connect()
|
|
83
|
-
|
|
84
|
-
if action:
|
|
85
|
-
action = action.group().lower()
|
|
86
|
-
else:
|
|
87
|
-
action = "None"
|
|
88
|
-
if debug:
|
|
89
|
-
print(action)
|
|
90
|
-
print(id(self), "------------>", sql, "::", parms)
|
|
91
|
-
print()
|
|
70
|
+
|
|
92
71
|
if single:
|
|
93
72
|
self.commit()
|
|
94
73
|
self.connection.autocommit = True
|
|
74
|
+
|
|
95
75
|
if not cursor:
|
|
96
76
|
cursor = self.cursor()
|
|
77
|
+
|
|
97
78
|
try:
|
|
98
79
|
if parms:
|
|
99
80
|
cursor.execute(sql, parms)
|
|
100
81
|
else:
|
|
101
82
|
cursor.execute(sql)
|
|
102
83
|
except:
|
|
103
|
-
self.engine.
|
|
84
|
+
self.engine.process_error(sql, parms)
|
|
85
|
+
|
|
104
86
|
if single:
|
|
105
87
|
self.connection.autocommit = False
|
|
88
|
+
|
|
106
89
|
return Result(cursor, self, sql, parms)
|
|
107
90
|
|
|
108
91
|
def server_execute(self, sql, parms=None):
|
|
92
|
+
"""
|
|
93
|
+
Executes SQL using an existing cursor, typically for server-side usage.
|
|
94
|
+
"""
|
|
109
95
|
return self._execute(sql, parms, cursor=self.cursor())
|
|
110
96
|
|
|
111
97
|
def commit(self):
|
|
98
|
+
"""
|
|
99
|
+
Commits the current transaction if there's an open connection.
|
|
100
|
+
"""
|
|
112
101
|
if self.connection:
|
|
113
102
|
if debug:
|
|
114
|
-
print(
|
|
115
|
-
"{} --- connection commit {database}".format(
|
|
116
|
-
id(self), **self.engine.config
|
|
117
|
-
)
|
|
118
|
-
)
|
|
103
|
+
print(f"{id(self)} --- connection commit.")
|
|
119
104
|
self.connection.commit()
|
|
120
105
|
|
|
121
106
|
def rollback(self):
|
|
107
|
+
"""
|
|
108
|
+
Rolls back the current transaction if there's an open connection.
|
|
109
|
+
"""
|
|
122
110
|
if self.connection:
|
|
123
111
|
if debug:
|
|
124
|
-
print(
|
|
125
|
-
"{} --- connection rollback {database}".format(
|
|
126
|
-
id(self), **self.engine.config
|
|
127
|
-
)
|
|
128
|
-
)
|
|
112
|
+
print(f"{id(self)} --- connection rollback.")
|
|
129
113
|
self.connection.rollback()
|
|
130
114
|
|
|
131
115
|
def create_savepoint(self, sp=None, cursor=None):
|
|
116
|
+
"""
|
|
117
|
+
Creates a savepoint named `sp`. If none given, uses a random name.
|
|
118
|
+
"""
|
|
132
119
|
if not sp:
|
|
133
120
|
sp = randomword()
|
|
134
121
|
sql, vals = self.engine.sql.create_savepoint(sp)
|
|
@@ -137,83 +124,94 @@ class Transaction(object):
|
|
|
137
124
|
return sp
|
|
138
125
|
|
|
139
126
|
def release_savepoint(self, sp=None, cursor=None):
|
|
127
|
+
"""
|
|
128
|
+
Releases the given savepoint.
|
|
129
|
+
"""
|
|
140
130
|
sql, vals = self.engine.sql.release_savepoint(sp)
|
|
141
131
|
if sql:
|
|
142
132
|
self._execute(sql, vals, cursor=cursor)
|
|
143
133
|
|
|
144
134
|
def rollback_savepoint(self, sp=None, cursor=None):
|
|
135
|
+
"""
|
|
136
|
+
Rolls back to the given savepoint.
|
|
137
|
+
"""
|
|
145
138
|
sql, vals = self.engine.sql.rollback_savepoint(sp)
|
|
146
139
|
if sql:
|
|
147
140
|
self._execute(sql, vals, cursor=cursor)
|
|
148
141
|
|
|
149
142
|
def database(self, name=None):
|
|
143
|
+
"""
|
|
144
|
+
Returns a Database object for the given database name or the current one.
|
|
145
|
+
"""
|
|
150
146
|
return Database(self, name)
|
|
151
147
|
|
|
152
148
|
def table(self, tablename):
|
|
149
|
+
"""
|
|
150
|
+
Returns a Table object for the given table name.
|
|
151
|
+
"""
|
|
153
152
|
return Table(self, tablename)
|
|
154
153
|
|
|
155
154
|
def sequence(self, name):
|
|
155
|
+
"""
|
|
156
|
+
Returns a Sequence object for the given sequence name.
|
|
157
|
+
"""
|
|
156
158
|
return Sequence(self, name)
|
|
157
159
|
|
|
158
160
|
def row(self, tablename, pk, lock=None):
|
|
159
161
|
"""
|
|
160
|
-
Returns
|
|
161
|
-
raise exception if primary key not provided.
|
|
162
|
+
Returns a Row for the given table & primary key condition.
|
|
162
163
|
"""
|
|
163
164
|
return Row(self.table(tablename), pk, lock=lock)
|
|
164
165
|
|
|
165
166
|
def get(self, tablename, where, lock=None):
|
|
166
167
|
"""
|
|
167
|
-
|
|
168
|
-
raise exception if duplicates found.
|
|
169
|
-
return new if not found. (creates new/use find otherwise)
|
|
168
|
+
Shortcut to table.get().
|
|
170
169
|
"""
|
|
171
170
|
return self.table(tablename).get(where, lock=lock)
|
|
172
171
|
|
|
173
172
|
def find(self, tablename, where, lock=None):
|
|
174
173
|
"""
|
|
175
|
-
|
|
176
|
-
raise exception if duplicates found.
|
|
177
|
-
return {} if not found. (Does not create new)
|
|
174
|
+
Shortcut to table.find().
|
|
178
175
|
"""
|
|
179
176
|
return self.table(tablename).find(where, lock=lock)
|
|
180
177
|
|
|
181
178
|
def column(self, tablename, colname):
|
|
179
|
+
"""
|
|
180
|
+
Returns a Column object for (table=tablename, column=colname).
|
|
181
|
+
"""
|
|
182
182
|
return Column(self.table(tablename), colname)
|
|
183
183
|
|
|
184
184
|
def current_database(self):
|
|
185
|
+
"""
|
|
186
|
+
Returns the current database name from the server.
|
|
187
|
+
"""
|
|
185
188
|
sql, vals = self.engine.sql.current_database()
|
|
186
189
|
return self.execute(sql, vals).scalar()
|
|
187
190
|
|
|
188
|
-
def vacuum(self, analyze=True, full=False, reindex=True):
|
|
189
|
-
self.connection = self.engine.connect()
|
|
190
|
-
old_isolation_level = self.connection.isolation_level
|
|
191
|
-
self.connection.set_isolation_level(0)
|
|
192
|
-
sql = ["VACUUM"]
|
|
193
|
-
if full:
|
|
194
|
-
sql.append("FULL")
|
|
195
|
-
if analyze:
|
|
196
|
-
sql.append("ANALYZE")
|
|
197
|
-
self.execute(" ".join(sql))
|
|
198
|
-
if reindex:
|
|
199
|
-
database = self.engine.config.get("database")
|
|
200
|
-
self.execute("REINDEX DATABASE {}".format(database))
|
|
201
|
-
self.connection.set_isolation_level(old_isolation_level)
|
|
202
|
-
|
|
203
191
|
def tables(self):
|
|
192
|
+
"""
|
|
193
|
+
Returns a list of tables in the current database as "schema.table" strings.
|
|
194
|
+
"""
|
|
204
195
|
sql, vals = self.engine.sql.tables()
|
|
205
196
|
result = self.execute(sql, vals)
|
|
206
|
-
return ["
|
|
197
|
+
return [f"{x[0]}.{x[1]}" for x in result.as_tuple()]
|
|
207
198
|
|
|
208
199
|
@property
|
|
209
200
|
def pg_types(self):
|
|
201
|
+
"""
|
|
202
|
+
Cached mapping of OID -> type name for columns.
|
|
203
|
+
"""
|
|
210
204
|
if not self.__pg_types:
|
|
211
|
-
sql
|
|
205
|
+
sql = "select oid, typname from pg_type"
|
|
206
|
+
vals = ()
|
|
212
207
|
result = self.execute(sql, vals)
|
|
213
208
|
self.__pg_types = dict(result.as_tuple())
|
|
214
209
|
return self.__pg_types
|
|
215
210
|
|
|
216
211
|
def switch_to_database(self, name):
|
|
212
|
+
"""
|
|
213
|
+
Closes the current connection, changes config, and lazily reconnects for the new DB.
|
|
214
|
+
"""
|
|
217
215
|
if self.connection:
|
|
218
216
|
self.connection.close()
|
|
219
217
|
self.connection = None
|
velocity/db/servers/mysql.py
CHANGED
|
@@ -144,6 +144,10 @@ class SQL:
|
|
|
144
144
|
LockTimeoutErrorCodes = []
|
|
145
145
|
DatabaseObjectExistsErrorCodes = []
|
|
146
146
|
|
|
147
|
+
def get_error(self, e):
|
|
148
|
+
error_code, error_mesg = e.args[:2]
|
|
149
|
+
return error_code, error_mesg
|
|
150
|
+
|
|
147
151
|
@classmethod
|
|
148
152
|
def __has_pointer(cls, columns):
|
|
149
153
|
if columns:
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import psycopg2
|
|
3
|
+
from .sql import SQL
|
|
4
|
+
from velocity.db.core import engine
|
|
5
|
+
|
|
6
|
+
default_config = {
|
|
7
|
+
"database": os.environ["DBDatabase"],
|
|
8
|
+
"host": os.environ["DBHost"],
|
|
9
|
+
"port": os.environ["DBPort"],
|
|
10
|
+
"user": os.environ["DBUser"],
|
|
11
|
+
"password": os.environ["DBPassword"],
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def initialize(config=None, **kwargs):
|
|
16
|
+
if not config:
|
|
17
|
+
config = default_config.copy()
|
|
18
|
+
config.update(kwargs)
|
|
19
|
+
return engine.Engine(psycopg2, config, SQL)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
OPERATORS = {
|
|
2
|
+
"<>": "<>",
|
|
3
|
+
"!=": "<>",
|
|
4
|
+
"!><": "NOT BETWEEN",
|
|
5
|
+
">!<": "NOT BETWEEN",
|
|
6
|
+
"><": "BETWEEN",
|
|
7
|
+
"%%": "ILIKE",
|
|
8
|
+
"!%%": "NOT ILIKE",
|
|
9
|
+
"==": "=",
|
|
10
|
+
"<=": "<=",
|
|
11
|
+
">=": ">=",
|
|
12
|
+
"<": "<",
|
|
13
|
+
">": ">",
|
|
14
|
+
"!~*": "!~*",
|
|
15
|
+
"~*": "~*",
|
|
16
|
+
"!~": "!~",
|
|
17
|
+
"%": "LIKE",
|
|
18
|
+
"!%": "NOT LIKE",
|
|
19
|
+
"~": "~",
|
|
20
|
+
"=": "=",
|
|
21
|
+
"!": "<>",
|
|
22
|
+
"#": "ILIKE",
|
|
23
|
+
}
|