tabletop-frog/src/ttfrog/db/base.py

117 lines
2.9 KiB
Python
Raw Normal View History

2024-02-18 19:30:41 -08:00
import enum
2024-03-26 00:53:21 -07:00
2024-02-02 15:40:45 -08:00
import nanoid
from nanoid_dictionary import human_alphabet
from pyramid_sqlalchemy import BaseObject as _BaseObject
2024-02-08 01:14:35 -08:00
from slugify import slugify
2024-03-26 00:53:21 -07:00
from sqlalchemy import Column, String
2024-02-02 15:40:45 -08:00
2024-02-04 11:40:30 -08:00
2024-02-02 15:40:45 -08:00
def genslug():
return nanoid.generate(human_alphabet[2:], 5)
class SlugMixin:
slug = Column(String, index=True, unique=True, default=genslug)
@property
def uri(self):
2024-03-26 00:53:21 -07:00
return "-".join([self.slug, slugify(self.name.title().replace(" ", ""), ok="", only_ascii=True, lower=False)])
2024-01-31 22:39:54 -08:00
class BaseObject(_BaseObject):
2024-01-31 22:39:54 -08:00
"""
Allows for iterating over Model objects' column names and values
"""
__abstract__ = True
2024-03-26 00:53:21 -07:00
2024-01-31 22:39:54 -08:00
def __iter__(self):
values = vars(self)
for attr in self.__mapper__.columns.keys():
if attr in values:
yield attr, values[attr]
for relname in self.__mapper__.relationships.keys():
relvals = []
2024-02-18 19:30:41 -08:00
reliter = self.__getattribute__(relname)
if not reliter:
yield relname, relvals
continue
for rel in reliter:
try:
2024-03-26 00:53:21 -07:00
relvals.append({k: v for k, v in vars(rel).items() if not k.startswith("_")})
except TypeError:
relvals.append(rel)
yield relname, relvals
2024-01-31 22:39:54 -08:00
def __json__(self):
"""
Provide a custom JSON encoder.
"""
raise NotImplementedError()
2024-01-31 22:39:54 -08:00
2024-02-18 19:30:41 -08:00
def __repr__(self):
return str(dict(self))
2024-01-31 22:39:54 -08:00
2024-03-26 00:53:21 -07:00
def multivalue_string_factory(name, column=Column(String), separator=";"):
2024-02-08 01:14:35 -08:00
"""
Generate a mixin class that adds a string column with getters and setters
that convert list values to strings and back again. Equivalent to:
class MultiValueString:
_name = column
@property
def name_property(self):
return self._name.split(';')
@name.setter
def name(self, val):
return ';'.join(val)
"""
attr = f"_{name}"
prop = property(lambda self: getattr(self, attr).split(separator))
setter = prop.setter(lambda self, val: setattr(self, attr, separator.join(val)))
2024-03-26 00:53:21 -07:00
return type(
"MultiValueString",
(object,),
{
attr: column,
f"{name}_property": prop,
name: setter,
},
)
2024-02-08 01:14:35 -08:00
2024-02-18 19:30:41 -08:00
class EnumField(enum.Enum):
"""
A serializable enum.
"""
2024-03-26 00:53:21 -07:00
def __json__(self):
2024-02-18 19:30:41 -08:00
return self.value
2024-03-26 00:53:21 -07:00
SavingThrowsMixin = multivalue_string_factory("saving_throws")
SkillsMixin = multivalue_string_factory("skills")
STATS = ["STR", "DEX", "CON", "INT", "WIS", "CHA"]
CREATURE_TYPES = [
"aberation",
"beast",
"celestial",
"construct",
"dragon",
"elemental",
"fey",
"fiend",
"Giant",
"humanoid",
"monstrosity",
"ooze",
"plant",
"undead",
]
2024-02-18 19:30:41 -08:00
CreatureTypesEnum = EnumField("CreatureTypesEnum", ((k, k) for k in CREATURE_TYPES))
StatsEnum = EnumField("StatsEnum", ((k, k) for k in STATS))