Source code for zensols.db.sqlite

"""Convenience wrapper for the Python DB-API library, and some specificly for
the SQLite library.

"""
__author__ = 'Paul Landes'

import logging
from dataclasses import dataclass, field
from pathlib import Path
import sqlite3
from . import DBError, ConnectionManager, DbStash

logger = logging.getLogger(__name__)


[docs] @dataclass class SqliteConnectionManager(ConnectionManager): """An SQLite connection factory. """ db_file: Path = field() """The SQLite database file to read or create.""" create_db: bool = field(default=True) """If ``True``, create the database if it does not already exist. Otherwise, :class:`.DBError` is raised (see :meth:`create`). """
[docs] def create(self) -> sqlite3.Connection: """Create a connection by accessing the SQLite file. :raise DBError: if the SQLite file does not exist (caveat see :`obj:create_db`) """ db_file = self.db_file if logger.isEnabledFor(logging.DEBUG): logger.debug(f'creating connection to {db_file}') created = False if not db_file.exists(): if not self.create_db: raise DBError(f'database file {db_file} does not exist') if not db_file.parent.exists(): if logger.isEnabledFor(logging.INFO): logger.info(f'creating sql db directory {db_file.parent}') db_file.parent.mkdir(parents=True) if logger.isEnabledFor(logging.INFO): logger.info(f'creating sqlite db file: {db_file}') created = True types = sqlite3.PARSE_DECLTYPES | sqlite3.PARSE_COLNAMES conn = sqlite3.connect(str(db_file.absolute()), detect_types=types) if created: logger.info('initializing database...') for sql in self.persister.parser.get_init_db_sqls(): if logger.isEnabledFor(logging.DEBUG): logger.debug(f'invoking sql: {sql}') conn.execute(sql) conn.commit() return conn
[docs] def drop(self) -> bool: """Delete the SQLite database file from the file system.""" logger.info(f'deleting: {self.db_file}') if self.db_file.exists(): self.db_file.unlink() return True return False
[docs] @dataclass class SqliteAttachConnectionManager(ConnectionManager): """An SQLite connection factory that attaches a file as a database. """ db_file: Path = field() """The SQLite database file to read or create.""" database_name: str = field() """The name of the database used to attach to :obj:`db_file`."""
[docs] def create(self) -> sqlite3.Connection: """Create a connection as an attached database to a file.""" conn = sqlite3.connect(':memory:') conn.execute( f'ATTACH DATABASE ? AS {self.database_name}', (str(self.db_file),)) return conn
[docs] def drop(self) -> bool: """Dropping a memory SQLite connection is not supported.""" return False
[docs] @dataclass class SqliteDbStash(DbStash): """A :class:`~zensols.persist.domain.Stash` implementation that uses an SQLite database to store data. """ path: Path = field(default=None) """The directory of where to store the files.""" def _create_connection_manager(self) -> ConnectionManager: if self.path is None: raise DBError(f'No configured path for {type(self)} stash') return SqliteConnectionManager(self.path)