Use abstract base class to help the subclass know what to do.

This commit is contained in:
voussoir 2021-10-09 12:12:18 -07:00
parent 8eefc4a095
commit 5b6a1b4c9c
No known key found for this signature in database
GPG key ID: 5F7554F8C26DACCB

View file

@ -1,6 +1,7 @@
''' '''
Worms is an SQL ORM with the strength and resilience of the humble earthworm. Worms is an SQL ORM with the strength and resilience of the humble earthworm.
''' '''
import abc
import functools import functools
import re import re
import typing import typing
@ -57,7 +58,7 @@ def transaction(method):
return wrapped_transaction return wrapped_transaction
class Database: class Database(metaclass=abc.ABCMeta):
''' '''
When your class subclasses this class, you need to ensure the following: When your class subclasses this class, you need to ensure the following:
- self.COLUMNS is a dictionary of {table: [columns]} like what comes out of - self.COLUMNS is a dictionary of {table: [columns]} like what comes out of
@ -73,6 +74,25 @@ class Database:
self.on_rollback_queue = [] self.on_rollback_queue = []
self.savepoints = [] self.savepoints = []
@abc.abstractmethod
def _init_column_index(self):
'''
Your subclass needs to set self.COLUMNS and self.COLUMN_INDEX, where
COLUMNS is a dictionary of {'table': ['column1', 'column2', ...]} and
COLUMN_INDEX is a dict of {'table': {'column1': 0, 'column2': 1}}.
These outputs can come from sqlhelpers.extract_table_column_map and
reverse_table_column_map.
'''
raise NotImplementedError
@abc.abstractmethod
def _init_sql(self):
'''
Your subclass needs to set self.sql, which is a database connection.
'''
raise NotImplementedError
def assert_table_exists(self, table) -> None: def assert_table_exists(self, table) -> None:
if table not in self.get_tables(): if table not in self.get_tables():
raise BadTable(f'Table {table} does not exist.') raise BadTable(f'Table {table} does not exist.')
@ -334,11 +354,23 @@ class Database:
query = f'UPDATE {table} {qmarks}' query = f'UPDATE {table} {qmarks}'
self.execute(query, bindings) self.execute(query, bindings)
class DatabaseWithCaching(Database): class DatabaseWithCaching(Database, metaclass=abc.ABCMeta):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.caches = {} self.caches = {}
def _init_caches(self):
'''
Your subclass needs to set self.caches, which is a dictionary of
{object: cache} where object is one of your data object types
(use the class itself as the key) and cache is a dictionary or
cacheclass.Cache or anything that supports subscripting.
If any types are omitted from this dictionary, objects of those
types will not be cached.
'''
raise NotImplementedError
def clear_all_caches(self) -> None: def clear_all_caches(self) -> None:
for cache in self.caches: for cache in self.caches:
cache.clear() cache.clear()
@ -483,7 +515,7 @@ class DatabaseWithCaching(Database):
for object_row in object_rows: for object_row in object_rows:
yield self.get_cached_instance(object_class, object_row) yield self.get_cached_instance(object_class, object_row)
class Object: class Object(metaclass=abc.ABCMeta):
''' '''
When your objects subclass this class, you need to ensure the following: When your objects subclass this class, you need to ensure the following: