1
+ import re
2
+ from abc import ABC , abstractmethod
3
+ from typing import Optional , Sequence
4
+
5
+ import psycopg2
6
+ from mysql .connector .abstracts import MySQLConnectionAbstract , MySQLCursorAbstract
7
+ import mysql .connector
8
+ from psycopg2 .extensions import connection as PostgreSQLConnectionRaw
9
+ from psycopg2 .extensions import cursor as PostgreSQLCursorRaw
10
+
11
+ class AbstractCursor (ABC ):
12
+ @abstractmethod
13
+ def execute (self , query : str , param_list : Sequence = None ):
14
+ pass
15
+
16
+ @abstractmethod
17
+ def rowcount (self ):
18
+ pass
19
+
20
+ @abstractmethod
21
+ def lastrowid (self ):
22
+ pass
23
+
24
+ @abstractmethod
25
+ def description (self ):
26
+ pass
27
+
28
+ @abstractmethod
29
+ def fetchone (self ):
30
+ pass
31
+
32
+ @abstractmethod
33
+ def fetchall (self ):
34
+ pass
35
+
36
+ @abstractmethod
37
+ def fetchmany (self , size : int ):
38
+ pass
39
+
40
+ @abstractmethod
41
+ def close (self ):
42
+ pass
43
+
44
+ class AbstractConnection (ABC ):
45
+ @abstractmethod
46
+ def cursor (self , * args , ** kwargs ) -> AbstractCursor :
47
+ pass
48
+
49
+ @abstractmethod
50
+ def close (self ):
51
+ pass
52
+
53
+ @abstractmethod
54
+ def set_autocommit (self , autocommit : bool ):
55
+ pass
56
+
57
+ @abstractmethod
58
+ def start_transaction (self ):
59
+ pass
60
+
61
+ @abstractmethod
62
+ def commit (self ):
63
+ pass
64
+
65
+ @abstractmethod
66
+ def rollback (self ):
67
+ pass
68
+
69
+
70
+ class MySQLCursor (AbstractCursor ):
71
+ def __init__ (self , cursor : MySQLCursorAbstract , * args , ** kwargs ):
72
+ self .cursor = cursor
73
+
74
+ def execute (self , query : str , param_list : Sequence = None ):
75
+ return self .cursor .execute (query , param_list )
76
+
77
+ def rowcount (self ):
78
+ return self .cursor .rowcount
79
+
80
+ def lastrowid (self ):
81
+ return self .cursor .lastrowid
82
+
83
+ def description (self ):
84
+ return self .cursor .description
85
+
86
+ def fetchone (self ):
87
+ return self .cursor .fetchone ()
88
+
89
+ def fetchall (self ):
90
+ return self .cursor .fetchall ()
91
+
92
+ def fetchmany (self , size : int ):
93
+ return self .cursor .fetchmany (size )
94
+
95
+ def close (self ):
96
+ self .cursor .close ()
97
+
98
+ def __enter__ (self ):
99
+ return self
100
+
101
+ def __exit__ (self , exc_type , exc_val , exc_tb ):
102
+ self .cursor .close ()
103
+ if exc_type :
104
+ print (f"An exception occurred: { exc_val } " )
105
+ return False
106
+
107
+
108
+ class MySQLConnection (AbstractConnection ):
109
+ def __init__ (self , conn : MySQLConnectionAbstract ):
110
+ self .conn = conn
111
+
112
+ def cursor (self , * args , ** kwargs ) -> AbstractCursor :
113
+ return MySQLCursor (cursor = self .conn .cursor (* args , ** kwargs ))
114
+
115
+ def close (self ):
116
+ self .conn .close ()
117
+
118
+ def set_autocommit (self , autocommit : bool ):
119
+ self .conn .autocommit = autocommit
120
+
121
+ def start_transaction (self ):
122
+ self .set_autocommit (False )
123
+
124
+ def commit (self ):
125
+ self .conn .commit ()
126
+
127
+ def rollback (self ):
128
+ self .conn .rollback ()
129
+
130
+ class PostgreSQLCursor (AbstractCursor ):
131
+ def __init__ (self , cursor : PostgreSQLCursorRaw , prepared = False ):
132
+ self .prepared = prepared
133
+ self .cursor = cursor
134
+ self .replace_pattern = re .compile (r"\?" )
135
+
136
+ def execute (self , query : str , param_list :Sequence = None ):
137
+ query = self .replace_pattern .sub ("%s" , query )
138
+ return self .cursor .execute (query , param_list )
139
+
140
+ def rowcount (self ):
141
+ return self .cursor .rowcount
142
+
143
+ def lastrowid (self ):
144
+ return self .cursor .fetchone ()[0 ]
145
+
146
+ def description (self ):
147
+ return self .cursor .description
148
+
149
+ def fetchone (self ):
150
+ return self .cursor .fetchone ()
151
+
152
+ def fetchall (self ):
153
+ return self .cursor .fetchall ()
154
+
155
+ def fetchmany (self , size : int ):
156
+ return self .cursor .fetchmany (size )
157
+
158
+ def close (self ):
159
+ self .cursor .close ()
160
+
161
+ def __enter__ (self ):
162
+ return self
163
+
164
+ def __exit__ (self , exc_type , exc_val , exc_tb ):
165
+ self .cursor .close ()
166
+ if exc_type :
167
+ print (f"An exception occurred: { exc_val } " )
168
+ return False
169
+
170
+
171
+ class PostgreSQLConnection (AbstractConnection ):
172
+ def __init__ (self , conn : PostgreSQLConnectionRaw ):
173
+ self .conn = conn
174
+ self .prepared = False
175
+
176
+ def cursor (self , * args , ** kwargs ) -> AbstractCursor :
177
+ prepared = False
178
+ if 'prepared' in kwargs :
179
+ prepared = kwargs ['prepared' ]
180
+ del kwargs ['prepared' ]
181
+ return PostgreSQLCursor (cursor = self .conn .cursor (* args , ** kwargs ), prepared = prepared )
182
+
183
+ def close (self ):
184
+ self .conn .close ()
185
+
186
+ def set_autocommit (self , autocommit : bool ):
187
+ self .conn .autocommit = autocommit
188
+
189
+ def start_transaction (self ):
190
+ pass
191
+
192
+ def commit (self ):
193
+ self .conn .commit ()
194
+
195
+ def rollback (self ):
196
+ self .conn .rollback ()
197
+
198
+
199
+ class ConnectionFactory (ABC ):
200
+ @staticmethod
201
+ def get_connection (* args , ** kwargs ) -> Optional [AbstractConnection ]:
202
+ dbms_name = kwargs .get ("dbms_name" )
203
+ del kwargs ['dbms_name' ]
204
+ if dbms_name == 'mysql' :
205
+ conn = mysql .connector .connect (
206
+ ** kwargs
207
+ )
208
+ return MySQLConnection (conn )
209
+ elif dbms_name == 'postgresql' :
210
+ conn = psycopg2 .connect (
211
+ ** kwargs
212
+ )
213
+ return PostgreSQLConnection (conn )
0 commit comments