Improved Typescript Interface generation, enabled it for events

This commit is contained in:
Ferdinand Thiessen 2020-10-23 02:03:06 +02:00
parent b8db07b741
commit ba0c76a727
4 changed files with 74 additions and 67 deletions

View File

@ -28,10 +28,9 @@ class UtcDateTime(TypeDecorator):
def process_bind_param(self, value, dialect): def process_bind_param(self, value, dialect):
if value is not None: if value is not None:
if not isinstance(value, datetime.datetime): if not isinstance(value, datetime.datetime):
raise TypeError('expected datetime.datetime, not ' + raise TypeError("expected datetime.datetime, not " + repr(value))
repr(value))
elif value.tzinfo is None: elif value.tzinfo is None:
raise ValueError('naive datetime is disallowed') raise ValueError("naive datetime is disallowed")
return value.astimezone(datetime.timezone.utc) return value.astimezone(datetime.timezone.utc)
def process_result_value(self, value, dialect): def process_result_value(self, value, dialect):

View File

@ -1,65 +1,74 @@
from datetime import datetime
from typing import Optional
from . import ModelSerializeMixin from . import ModelSerializeMixin
from .user import User
from ..database import db from ..database import db
class Event(db.Model, ModelSerializeMixin):
"""Model for an Event"""
__tablename__ = "event"
id = db.Column(db.Integer, primary_key=True)
begin = db.Column(db.DateTime, nullable=False)
end = db.Column(db.DateTime)
description = db.Column(db.String(240))
kind = db.relationship("EventKind")
slots = db.relationship("EventSlot", back_populates="event", cascade="all, delete")
# notices = db.relationship("EventNotice", back_populates="event")
_kind_id = db.Column(db.Integer, db.ForeignKey("event_kind.id", ondelete="CASCADE"), nullable=False)
class EventKind(db.Model, ModelSerializeMixin):
"""Model for an EventKind"""
__tablename__ = "event_kind"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(30), nullable=False, unique=True)
class EventSlot(db.Model, ModelSerializeMixin): class EventSlot(db.Model, ModelSerializeMixin):
"""Model for an EventSlot""" """Model for an EventSlot"""
__tablename__ = "event_slot" __tablename__ = "event_slot"
id = db.Column(db.Integer, primary_key=True) id: int = db.Column(db.Integer, primary_key=True)
start = db.Column(db.DateTime) start: datetime = db.Column(db.DateTime)
end = db.Column(db.DateTime) end: Optional[datetime] = db.Column(db.DateTime)
slots = db.relationship("JobSlot", back_populates="event_slot") slots: [any] = db.relationship("JobSlot", back_populates="_event_slot")
_event_id = db.Column(db.Integer, db.ForeignKey("event.id"), nullable=False) _event_id = db.Column("event_id", db.Integer, db.ForeignKey("event.id"), nullable=False)
_event = db.relationship("Event", back_populates="slots") _event = db.relationship("Event", back_populates="_slots")
class JobSlot(db.Model, ModelSerializeMixin): class EventKind(db.Model, ModelSerializeMixin):
__tablename__ = "job_slot" """Model for an EventKind"""
id = db.Column(db.Integer, primary_key=True)
needed_persons = db.Column(db.Numeric(precision=4, scale=2))
kind = db.relationship("JobKind")
jobs = db.relationship("Job", back_populates="slot")
_event_slot_id = db.Column(db.Integer, db.ForeignKey("event_slot.id")) __tablename__ = "event_kind"
_event_slot = db.relationship("EventSlot", back_populates="slots") name: str = db.Column(db.String(30), nullable=False, unique=True)
_kind_id = db.Column(db.Integer, db.ForeignKey("job_kind.id"))
_id: int = db.Column("id", db.Integer, primary_key=True)
class Event(db.Model, ModelSerializeMixin):
"""Model for an Event"""
__tablename__ = "event"
id: int = db.Column(db.Integer, primary_key=True)
begin: datetime = db.Column(db.DateTime, nullable=False)
end: datetime = db.Column(db.DateTime)
description: str = db.Column(db.String(240))
kind: EventKind = db.relationship("EventKind")
# notices = db.relationship("EventNotice", back_populates="event")
_kind_id = db.Column("kind_id", db.Integer, db.ForeignKey("event_kind.id", ondelete="CASCADE"), nullable=False)
_slots: [EventSlot] = db.relationship("EventSlot", back_populates="_event", cascade="all, delete")
class Job(db.Model, ModelSerializeMixin): class Job(db.Model, ModelSerializeMixin):
__tablename__ = "job" __tablename__ = "job"
user = db.relationship("User") _user: User = db.relationship("User")
value = db.Column(db.Numeric(precision=3, scale=2)) # user: str = column_property(_user.userid)
value: float = db.Column(db.Numeric(precision=3, scale=2))
_user_id = db.Column(db.Integer, db.ForeignKey("user.id")) _id = db.Column("id", db.Integer, primary_key=True)
_slot_id = db.Column(db.Integer, db.ForeignKey("job_slot.id")) _user_id = db.Column("user_id", db.Integer, db.ForeignKey("user.id"))
_slot_id = db.Column("slot_id", db.Integer, db.ForeignKey("job_slot.id"))
_slot = db.relationship("JobSlot") _slot = db.relationship("JobSlot")
_id = db.Column(db.Integer, primary_key=True)
class JobKind(db.Model, ModelSerializeMixin): class JobKind(db.Model, ModelSerializeMixin):
__tablename__ = "job_kind" __tablename__ = "job_kind"
name = db.Column(db.String(30), nullable=False, unique=True) name: str = db.Column(db.String(30), nullable=False, unique=True)
_id = db.Column(db.Integer, primary_key=True) _id = db.Column("id", db.Integer, primary_key=True)
class JobSlot(db.Model, ModelSerializeMixin):
__tablename__ = "job_slot"
id: int = db.Column(db.Integer, primary_key=True)
needed_persons: float = db.Column(db.Numeric(precision=4, scale=2))
kind: JobKind = db.relationship("JobKind")
jobs: [Job] = db.relationship("Job", back_populates="_slot")
_event_slot_id = db.Column("event_slot_id", db.Integer, db.ForeignKey("event_slot.id"))
_event_slot = db.relationship("EventSlot", back_populates="slots")
_kind_id = db.Column("kind_id", db.Integer, db.ForeignKey("job_kind.id"))

View File

@ -92,12 +92,8 @@ class User(db.Model, ModelSerializeMixin):
def get_permissions(self): def get_permissions(self):
return ["user"] + [permission.name for role in self.roles for permission in role.permissions] return ["user"] + [permission.name for role in self.roles for permission in role.permissions]
def has_permissions(self, permissions): def has_permission(self, permission):
for role in self.roles: return permission in self.get_permissions()
for permission in role.permissions:
if permission.name in permissions:
return True
return False
class _UserAttribute(db.Model, ModelSerializeMixin): class _UserAttribute(db.Model, ModelSerializeMixin):

View File

@ -1,11 +1,8 @@
#!/usr/bin/python3 #!/usr/bin/python3
import inspect import inspect
import argparse import argparse
from datetime import datetime
import bjoern import bjoern
import sqlalchemy import typing
from sqlalchemy.orm import RelationshipProperty, ColumnProperty
def install(arguments): def install(arguments):
@ -36,12 +33,16 @@ def export(arguments):
def pytype(cls): def pytype(cls):
if isinstance(cls, list): if isinstance(cls, list):
return "Array<{}>".format(pytype(cls[0])) return "", "Array<{}>".format(pytype(cls[0])[1])
mapper = {"str": "string", "int": "number", "datetime": "Date"} #if typing.get_origin(cls) is typing.Optional:
if cls.__name__ in mapper: # return "?", pytype(typing.get_args(cls)[1])
return mapper[cls.__name__] mapper = {"str": "string", "int": "number", "float": "number", "datetime": "Date"}
else: if hasattr(cls, "__name__"):
return cls.__name__ if cls.__name__ in mapper:
return "", mapper[cls.__name__]
else:
return "", cls.__name__
return "?", "any"
def walker(mod): def walker(mod):
if inspect.ismodule(mod[1]) and mod[1].__name__.startswith(models.__name__) and mod[1].__name__ not in known: if inspect.ismodule(mod[1]) and mod[1].__name__.startswith(models.__name__) and mod[1].__name__ not in known:
@ -58,7 +59,7 @@ def export(arguments):
d = {param: pytype(ptype) for param, ptype in mod[1].__annotations__.items() if not param.startswith("_")} d = {param: pytype(ptype) for param, ptype in mod[1].__annotations__.items() if not param.startswith("_")}
if len(d) == 1: if len(d) == 1:
key, value = d.popitem() key, value = d.popitem()
classes[mod[0]] = value classes[mod[0]] = value[1]
else: else:
classes[mod[0]] = d classes[mod[0]] = d
@ -68,14 +69,16 @@ def export(arguments):
with app.app_context(): with app.app_context():
walker(("models", models)) walker(("models", models))
with open(arguments.file, "w") as file: with open(arguments.file, "w") as file:
file.write("declare namespace FG {\n")
for cls, params in classes.items(): for cls, params in classes.items():
if isinstance(params, str): if isinstance(params, str):
file.write("type {} = {};\n".format(cls, params)) file.write("\ttype {} = {};\n".format(cls, params))
else: else:
file.write("interface {} {{\n".format(cls)) file.write("\tinterface {} {{\n".format(cls))
for name in params: for name in params:
file.write(" {}: {};\n".format(name, params[name])) file.write("\t\t{}{}: {};\n".format(name, *params[name]))
file.write("}\n") file.write("\t}\n")
file.write("}\n")
if __name__ == "__main__": if __name__ == "__main__":