1
0
Fork 0
forked from s3lph/matemat

Removed all APSW references.

This commit is contained in:
s3lph 2018-07-14 23:35:32 +02:00
parent 8da1746d0c
commit 5c9d85fa70
4 changed files with 24 additions and 29 deletions

View file

@ -18,7 +18,6 @@ This project intends to provide a well-tested and maintainable alternative to
- Python 3 (>=3.6) - Python 3 (>=3.6)
- Python dependencies: - Python dependencies:
- apsw
- jinja2 - jinja2
## Usage ## Usage

View file

@ -7,6 +7,7 @@ from hmac import compare_digest
from matemat.primitives import User, Product from matemat.primitives import User, Product
from matemat.exceptions import AuthenticationError, DatabaseConsistencyError from matemat.exceptions import AuthenticationError, DatabaseConsistencyError
from matemat.db import DatabaseWrapper from matemat.db import DatabaseWrapper
from matemat.db.wrapper import Transaction
# TODO: Change to METHOD_BLOWFISH when adopting Python 3.7 # 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 # Pass context manager stuff through to the database wrapper
self.db.__exit__(exc_type, exc_val, exc_tb) 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 Begin a new SQLite3 transaction (exclusive by default). You should never need to use the returned object (a
APSW cursor). It is provided in case there is a real need for it (e.g. for unit testing). 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(): with db.transaction():
db.foo() db.foo()
db.bar() db.bar()
:param exclusive: Whether to begin an exclusive transaction or not, defaults to True (exclusive). :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) return self.db.transaction(exclusive=exclusive)

View file

@ -1,43 +1,40 @@
from typing import Any from typing import Any
import apsw import sqlite3
from matemat.exceptions import DatabaseConsistencyError from matemat.exceptions import DatabaseConsistencyError
class Transaction(object): class Transaction(object):
def __init__(self, db: apsw.Connection, wrapper: 'DatabaseWrapper', exclusive: bool = True) -> None: def __init__(self, db: sqlite3.Connection, exclusive: bool = True) -> None:
self._db: apsw.Connection = db self._db: sqlite3.Connection = db
self._cursor = None self._cursor = None
self._excl = exclusive self._excl = exclusive
self._wrapper: DatabaseWrapper = wrapper
self._is_dummy: bool = False self._is_dummy: bool = False
def __enter__(self) -> Any: def __enter__(self) -> sqlite3.Cursor:
if self._wrapper._in_transaction: if self._db.in_transaction:
self._is_dummy = True self._is_dummy = True
return self._db.cursor() return self._db.cursor()
else: else:
self._is_dummy = False self._is_dummy = False
self._cursor = self._db.cursor()
self._wrapper._in_transaction = True
if self._excl: if self._excl:
self._cursor.execute('BEGIN EXCLUSIVE') self._db.execute('BEGIN EXCLUSIVE')
else: else:
self._cursor.execute('BEGIN') self._db.execute('BEGIN')
self._cursor = self._db.cursor()
return self._cursor return self._cursor
def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None: def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
if self._is_dummy: if self._is_dummy:
return return
if exc_type is None: if exc_type is None:
self._cursor.execute('COMMIT') self._db.commit()
else: else:
self._cursor.execute('ROLLBACK') self._db.rollback()
self._wrapper._in_transaction = False if exc_type == sqlite3.IntegrityError:
if exc_type == apsw.ConstraintError:
raise DatabaseConsistencyError(str(exc_val)) raise DatabaseConsistencyError(str(exc_val))
@ -47,7 +44,7 @@ class DatabaseWrapper(object):
SCHEMA = ''' SCHEMA = '''
CREATE TABLE users ( CREATE TABLE users (
user_id INTEGER PRIMARY KEY, user_id INTEGER PRIMARY KEY,
username TEXT NOT NULL, username TEXT UNIQUE NOT NULL,
email TEXT DEFAULT NULL, email TEXT DEFAULT NULL,
password TEXT NOT NULL, password TEXT NOT NULL,
touchkey TEXT DEFAULT NULL, touchkey TEXT DEFAULT NULL,
@ -72,13 +69,12 @@ class DatabaseWrapper(object):
ON DELETE CASCADE ON UPDATE CASCADE, ON DELETE CASCADE ON UPDATE CASCADE,
FOREIGN KEY (product_id) REFERENCES products(product_id) FOREIGN KEY (product_id) REFERENCES products(product_id)
ON DELETE CASCADE ON UPDATE CASCADE ON DELETE CASCADE ON UPDATE CASCADE
) );
''' '''
def __init__(self, filename: str) -> None: def __init__(self, filename: str) -> None:
self._filename: str = filename self._filename: str = filename
self._sqlite_db: apsw.Connection = None self._sqlite_db: sqlite3.Connection = None
self._in_transaction: bool = False
def __enter__(self) -> 'DatabaseWrapper': def __enter__(self) -> 'DatabaseWrapper':
self.connect() self.connect()
@ -88,13 +84,13 @@ class DatabaseWrapper(object):
self.close() self.close()
def transaction(self, exclusive: bool = True) -> Transaction: def transaction(self, exclusive: bool = True) -> Transaction:
return Transaction(self._sqlite_db, self, exclusive) return Transaction(self._sqlite_db, exclusive)
def _setup(self) -> None: def _setup(self) -> None:
with self.transaction() as c: with self.transaction() as c:
version: int = self._user_version version: int = self._user_version
if version < 1: if version < 1:
c.execute(self.SCHEMA) c.executescript(self.SCHEMA)
elif version < self.SCHEMA_VERSION: elif version < self.SCHEMA_VERSION:
self._upgrade(old=version, new=self.SCHEMA_VERSION) self._upgrade(old=version, new=self.SCHEMA_VERSION)
self._user_version = self.SCHEMA_VERSION self._user_version = self.SCHEMA_VERSION
@ -105,7 +101,7 @@ class DatabaseWrapper(object):
def connect(self) -> None: def connect(self) -> None:
if self.is_connected(): if self.is_connected():
raise RuntimeError(f'Database connection to {self._filename} is already established.') 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() self._setup()
def close(self) -> None: def close(self) -> None:
@ -117,7 +113,7 @@ class DatabaseWrapper(object):
self._sqlite_db = None self._sqlite_db = None
def in_transaction(self) -> bool: def in_transaction(self) -> bool:
return self._in_transaction return self._sqlite_db.in_transaction
def is_connected(self) -> bool: def is_connected(self) -> bool:
return self._sqlite_db is not None return self._sqlite_db is not None

View file

@ -1,2 +1 @@
apsw
jinja2 jinja2