forked from coleifer/peewee
-
Notifications
You must be signed in to change notification settings - Fork 0
/
apsw_ext.py
161 lines (127 loc) · 4.64 KB
/
apsw_ext.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
"""
Peewee integration with APSW, "another python sqlite wrapper".
Project page: https://code.google.com/p/apsw/
APSW is a really neat library that provides a thin wrapper on top of SQLite's
C interface.
Here are just a few reasons to use APSW, taken from the documentation:
* APSW gives all functionality of SQLite, including virtual tables, virtual
file system, blob i/o, backups and file control.
* Connections can be shared across threads without any additional locking.
* Transactions are managed explicitly by your code.
* APSW can handle nested transactions.
* Unicode is handled correctly.
* APSW is faster.
"""
import apsw
from peewee import *
from peewee import _sqlite_date_part
from peewee import _sqlite_date_trunc
from peewee import BooleanField as _BooleanField
from peewee import DateField as _DateField
from peewee import DateTimeField as _DateTimeField
from peewee import DecimalField as _DecimalField
from peewee import logger
from peewee import PY3
from peewee import TimeField as _TimeField
from peewee import transaction as _transaction
class ConnectionWrapper(apsw.Connection):
def cursor(self):
base_cursor = super(ConnectionWrapper, self).cursor()
return CursorProxy(base_cursor)
class CursorProxy(object):
def __init__(self, cursor_obj):
self.cursor_obj = cursor_obj
self.implements = set(['description', 'fetchone'])
def __getattr__(self, attr):
if attr in self.implements:
return self.__getattribute__(attr)
return getattr(self.cursor_obj, attr)
@property
def description(self):
try:
return self.cursor_obj.getdescription()
except apsw.ExecutionCompleteError:
return []
if PY3:
def fetchone(self):
try:
return next(self.cursor_obj)
except StopIteration:
pass
else:
def fetchone(self):
try:
return self.cursor_obj.next()
except StopIteration:
pass
class transaction(_transaction):
def __init__(self, db, lock_type='deferred'):
self.db = db
self.lock_type = lock_type
def _begin(self):
self.db.begin(self.lock_type)
class APSWDatabase(SqliteDatabase):
def __init__(self, database, timeout=None, **kwargs):
self.timeout = timeout
self._modules = {}
super(APSWDatabase, self).__init__(database, **kwargs)
def register_module(self, mod_name, mod_inst):
self._modules[mod_name] = mod_inst
def unregister_module(self, mod_name):
del(self._modules[mod_name])
def _connect(self, database, **kwargs):
conn = ConnectionWrapper(database, **kwargs)
if self.timeout is not None:
conn.setbusytimeout(self.timeout)
conn.createscalarfunction('date_part', _sqlite_date_part, 2)
conn.createscalarfunction('date_trunc', _sqlite_date_trunc, 2)
for mod_name, mod_inst in self._modules.items():
conn.createmodule(mod_name, mod_inst)
return conn
def _execute_sql(self, cursor, sql, params):
cursor.execute(sql, params or ())
return cursor
def execute_sql(self, sql, params=None, require_commit=True):
cursor = self.get_cursor()
wrap_transaction = require_commit and self.get_autocommit()
if wrap_transaction:
cursor.execute('begin;')
try:
self._execute_sql(cursor, sql, params)
except:
cursor.execute('rollback;')
raise
else:
cursor.execute('commit;')
else:
cursor = self._execute_sql(cursor, sql, params)
logger.debug((sql, params))
return cursor
def last_insert_id(self, cursor, model):
return cursor.getconnection().last_insert_rowid()
def rows_affected(self, cursor):
return cursor.getconnection().changes()
def begin(self, lock_type='deferred'):
self.get_cursor().execute('begin %s;' % lock_type)
def commit(self):
self.get_cursor().execute('commit;')
def rollback(self):
self.get_cursor().execute('rollback;')
def transaction(self, lock_type='deferred'):
return transaction(self, lock_type)
def nh(s, v):
if v is not None:
return str(v)
class BooleanField(_BooleanField):
def db_value(self, v):
v = super(BooleanField, self).db_value(v)
if v is not None:
return v and 1 or 0
class DateField(_DateField):
db_value = nh
class TimeField(_TimeField):
db_value = nh
class DateTimeField(_DateTimeField):
db_value = nh
class DecimalField(_DecimalField):
db_value = nh