Initial import

This commit is contained in:
evilchili
2024-01-28 11:01:18 -08:00
parent 6b5fe2be42
commit a382bad7ff
16 changed files with 416 additions and 0 deletions
+4
View File
@@ -0,0 +1,4 @@
from .manager import db, session
__ALL__ = [db, session]
+47
View File
@@ -0,0 +1,47 @@
import base64
import hashlib
import logging
from ttfrog.db import db, session
# move this to json or whatever
data = {
'ancestry': [
{'name': 'human'},
{'name': 'dragonborn'},
],
}
def slug_from_rec(rec):
"""
Create a uniquish slug from a dictionary.
"""
sha1bytes = hashlib.sha1(str(rec).encode())
return '-'.join([
base64.urlsafe_b64encode(sha1bytes.digest()).decode("ascii")[:10],
rec.get('name', '') # will need to normalize this for URLs
])
def bootstrap():
"""
Initialize the database with source data. Idempotent; will skip anything that already exists.
"""
db.init_model()
for table_name, table in db.tables.items():
if table_name not in data:
logging.debug("No bootstrap data for table {table_name}; skipping.")
continue
for rec in data[table_name]:
if 'slug' in table.columns:
rec['slug'] = slug_from_rec(rec)
stmt = table.insert().values(**rec).prefix_with("OR IGNORE")
result = session.execute(stmt)
session.commit()
last_id = result.inserted_primary_key[0]
if last_id == 0:
logging.info(f"Skipped existing {table_name} {rec}")
else:
logging.info(f"Created {table_name} {result.inserted_primary_key[0]}: {rec}")
+54
View File
@@ -0,0 +1,54 @@
from functools import cached_property
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
from ttfrog.path import database
from ttfrog.db.schema import metadata
class SQLDatabaseManager:
"""
A context manager for working with sqllite database.
"""
@cached_property
def url(self):
return f"sqlite:///{database()}"
@cached_property
def engine(self):
return create_engine(self.url, future=True)
@cached_property
def DBSession(self):
maker = sessionmaker(bind=self.engine, future=True, autoflush=True)
return scoped_session(maker)
@cached_property
def tables(self):
return dict((t.name, t) for t in metadata.sorted_tables)
def query(self, *args, **kwargs):
return self.DBSession.query(*args, **kwargs)
def init_model(self, engine=None):
metadata.create_all(bind=engine or self.engine)
return self.DBSession
def __getattr__(self, name: str):
try:
return self.tables[name]
except KeyError:
raise AttributeError(f"{self} does not contain the attribute '{name}'.")
def __enter__(self):
self.init_model(self.engine)
return self
def __exit__(self, exc_type, exc_value, traceback):
if self.DBSession:
self.DBSession.close()
db = SQLDatabaseManager()
session = db.DBSession
+30
View File
@@ -0,0 +1,30 @@
from sqlalchemy import MetaData
from sqlalchemy import Table
from sqlalchemy import Column
from sqlalchemy import Integer
from sqlalchemy import String
from sqlalchemy import UnicodeText
from sqlalchemy import ForeignKey
# from sqlalchemy import PrimaryKeyConstraint
# from sqlalchemy import DateTime
metadata = MetaData()
Ancestry = Table(
"ancestry",
metadata,
Column("id", Integer, primary_key=True, autoincrement=True),
Column("slug", String, index=True, unique=True),
Column("name", String, index=True, unique=True),
Column("description", UnicodeText),
)
Character = Table(
"character",
metadata,
Column("id", Integer, primary_key=True, autoincrement=True),
Column("slug", String, index=True, unique=True),
Column("name", String),
Column("ancestry_id", Integer, ForeignKey("ancestry.id")),
)