velocity-python 0.0.35__py3-none-any.whl → 0.0.65__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.
@@ -1,4 +1,5 @@
1
- import re
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(object):
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({}:{})".format(self.engine.sql.server, server, database)
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
- tb_str = "".join(traceback.format_exception(exc_type, exc_val, exc_tb))
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=parms, single=single, cursor=cursor)
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
- action = re.search(r"(\w+)", sql, re.I)
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.ProcessError(sql, parms)
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 exactly one row based on primary key.
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
- Search for row. return row if 1 found.
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
- Search for row. return row if 1 found.
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 ["%s.%s" % x for x in result.as_tuple()]
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, vals = "select oid,typname from pg_type", ()
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
@@ -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
+ }