forked from s3lph/matemat
Removed all APSW references.
This commit is contained in:
parent
8da1746d0c
commit
5c9d85fa70
4 changed files with 24 additions and 29 deletions
|
@ -18,7 +18,6 @@ This project intends to provide a well-tested and maintainable alternative to
|
|||
|
||||
- Python 3 (>=3.6)
|
||||
- Python dependencies:
|
||||
- apsw
|
||||
- jinja2
|
||||
|
||||
## Usage
|
||||
|
|
|
@ -7,6 +7,7 @@ from hmac import compare_digest
|
|||
from matemat.primitives import User, Product
|
||||
from matemat.exceptions import AuthenticationError, DatabaseConsistencyError
|
||||
from matemat.db import DatabaseWrapper
|
||||
from matemat.db.wrapper import Transaction
|
||||
|
||||
# TODO: Change to METHOD_BLOWFISH when adopting Python 3.7
|
||||
"""
|
||||
|
@ -50,19 +51,19 @@ class MatematDatabase(object):
|
|||
# Pass context manager stuff through to the database wrapper
|
||||
self.db.__exit__(exc_type, exc_val, exc_tb)
|
||||
|
||||
def transaction(self, exclusive: bool = True) -> Any:
|
||||
def transaction(self, exclusive: bool = True) -> Transaction:
|
||||
"""
|
||||
Begin a new SQLite3 transaction (exclusive by default). You should never need to use the returned object (an
|
||||
APSW cursor). It is provided in case there is a real need for it (e.g. for unit testing).
|
||||
Begin a new SQLite3 transaction (exclusive by default). You should never need to use the returned object (a
|
||||
Transaction instance). It is provided in case there is a real need for it (e.g. for unit testing).
|
||||
|
||||
This function should be used with the Context Manager 'with' syntax (PEP 343), e.g.:
|
||||
This function should be used with the Context Manager 'with' syntax (PEP 343), yielding a sqlite3.Cursor, e.g.:
|
||||
|
||||
with db.transaction():
|
||||
db.foo()
|
||||
db.bar()
|
||||
|
||||
:param exclusive: Whether to begin an exclusive transaction or not, defaults to True (exclusive).
|
||||
:return: An APSW cursor.
|
||||
:return: A a transaction object.
|
||||
"""
|
||||
return self.db.transaction(exclusive=exclusive)
|
||||
|
||||
|
|
|
@ -1,43 +1,40 @@
|
|||
|
||||
from typing import Any
|
||||
|
||||
import apsw
|
||||
import sqlite3
|
||||
|
||||
from matemat.exceptions import DatabaseConsistencyError
|
||||
|
||||
|
||||
class Transaction(object):
|
||||
|
||||
def __init__(self, db: apsw.Connection, wrapper: 'DatabaseWrapper', exclusive: bool = True) -> None:
|
||||
self._db: apsw.Connection = db
|
||||
def __init__(self, db: sqlite3.Connection, exclusive: bool = True) -> None:
|
||||
self._db: sqlite3.Connection = db
|
||||
self._cursor = None
|
||||
self._excl = exclusive
|
||||
self._wrapper: DatabaseWrapper = wrapper
|
||||
self._is_dummy: bool = False
|
||||
|
||||
def __enter__(self) -> Any:
|
||||
if self._wrapper._in_transaction:
|
||||
def __enter__(self) -> sqlite3.Cursor:
|
||||
if self._db.in_transaction:
|
||||
self._is_dummy = True
|
||||
return self._db.cursor()
|
||||
else:
|
||||
self._is_dummy = False
|
||||
self._cursor = self._db.cursor()
|
||||
self._wrapper._in_transaction = True
|
||||
if self._excl:
|
||||
self._cursor.execute('BEGIN EXCLUSIVE')
|
||||
self._db.execute('BEGIN EXCLUSIVE')
|
||||
else:
|
||||
self._cursor.execute('BEGIN')
|
||||
self._db.execute('BEGIN')
|
||||
self._cursor = self._db.cursor()
|
||||
return self._cursor
|
||||
|
||||
def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
|
||||
if self._is_dummy:
|
||||
return
|
||||
if exc_type is None:
|
||||
self._cursor.execute('COMMIT')
|
||||
self._db.commit()
|
||||
else:
|
||||
self._cursor.execute('ROLLBACK')
|
||||
self._wrapper._in_transaction = False
|
||||
if exc_type == apsw.ConstraintError:
|
||||
self._db.rollback()
|
||||
if exc_type == sqlite3.IntegrityError:
|
||||
raise DatabaseConsistencyError(str(exc_val))
|
||||
|
||||
|
||||
|
@ -47,7 +44,7 @@ class DatabaseWrapper(object):
|
|||
SCHEMA = '''
|
||||
CREATE TABLE users (
|
||||
user_id INTEGER PRIMARY KEY,
|
||||
username TEXT NOT NULL,
|
||||
username TEXT UNIQUE NOT NULL,
|
||||
email TEXT DEFAULT NULL,
|
||||
password TEXT NOT NULL,
|
||||
touchkey TEXT DEFAULT NULL,
|
||||
|
@ -72,13 +69,12 @@ class DatabaseWrapper(object):
|
|||
ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
FOREIGN KEY (product_id) REFERENCES products(product_id)
|
||||
ON DELETE CASCADE ON UPDATE CASCADE
|
||||
)
|
||||
);
|
||||
'''
|
||||
|
||||
def __init__(self, filename: str) -> None:
|
||||
self._filename: str = filename
|
||||
self._sqlite_db: apsw.Connection = None
|
||||
self._in_transaction: bool = False
|
||||
self._sqlite_db: sqlite3.Connection = None
|
||||
|
||||
def __enter__(self) -> 'DatabaseWrapper':
|
||||
self.connect()
|
||||
|
@ -88,13 +84,13 @@ class DatabaseWrapper(object):
|
|||
self.close()
|
||||
|
||||
def transaction(self, exclusive: bool = True) -> Transaction:
|
||||
return Transaction(self._sqlite_db, self, exclusive)
|
||||
return Transaction(self._sqlite_db, exclusive)
|
||||
|
||||
def _setup(self) -> None:
|
||||
with self.transaction() as c:
|
||||
version: int = self._user_version
|
||||
if version < 1:
|
||||
c.execute(self.SCHEMA)
|
||||
c.executescript(self.SCHEMA)
|
||||
elif version < self.SCHEMA_VERSION:
|
||||
self._upgrade(old=version, new=self.SCHEMA_VERSION)
|
||||
self._user_version = self.SCHEMA_VERSION
|
||||
|
@ -105,7 +101,7 @@ class DatabaseWrapper(object):
|
|||
def connect(self) -> None:
|
||||
if self.is_connected():
|
||||
raise RuntimeError(f'Database connection to {self._filename} is already established.')
|
||||
self._sqlite_db = apsw.Connection(self._filename)
|
||||
self._sqlite_db = sqlite3.connect(self._filename)
|
||||
self._setup()
|
||||
|
||||
def close(self) -> None:
|
||||
|
@ -117,7 +113,7 @@ class DatabaseWrapper(object):
|
|||
self._sqlite_db = None
|
||||
|
||||
def in_transaction(self) -> bool:
|
||||
return self._in_transaction
|
||||
return self._sqlite_db.in_transaction
|
||||
|
||||
def is_connected(self) -> bool:
|
||||
return self._sqlite_db is not None
|
||||
|
|
|
@ -1,2 +1 @@
|
|||
apsw
|
||||
jinja2
|
||||
|
|
Loading…
Reference in a new issue