Advertisement
caffeinatedmike

Untitled

Jan 18th, 2022
680
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. @declarative_mixin
  2. class EntityRefMixin:
  3.     entity_id = db.Column(db.Integer, nullable=False)
  4.     entity_type = db.Column(
  5.         db.Enum("reporter", "account", "report", "job", name="entity_type_enum"),
  6.         nullable=False
  7.     )
  8.  
  9.     @property
  10.     def entity(self):
  11.         return getattr(self, self.entity_type)
  12.  
  13.  
  14. @declarative_mixin
  15. class EntityRelationshipMixin:
  16.     @classmethod
  17.     def __declare_last__(cls):
  18.         """
  19.        Use __tablename__ to populate entity_type at time of creation.
  20.        Function gets called after mappings are completed.
  21.        https://docs.sqlalchemy.org/en/14/orm/declarative_config.html#declare-last
  22.        """
  23.         event.listen(cls.gs, "set", cls.set_entity_type, retval=False)
  24.         event.listen(cls.bq, "set", cls.set_entity_type, retval=False)
  25.         event.listen(cls.reporter_fields, "append", cls.append_entity_type, retval=False)
  26.  
  27.     @classmethod
  28.     def set_entity_type(cls, target, new_value, old_value, initiator):
  29.         new_value.entity_type = cls.__tablename__
  30.  
  31.     @classmethod
  32.     def append_entity_type(cls, state, value, initiator):
  33.         value.entity_type = cls.__tablename__
  34.  
  35.     @classmethod
  36.     def join_builder(cls, remote_cls):
  37.         return and_(
  38.             foreign(remote_cls.entity_type) == cls.__tablename__,
  39.             foreign(remote_cls.entity_id) == cls.id
  40.         )
  41.  
  42.     # region relationships
  43.     @declared_attr
  44.     def gs(cls):  # noqa
  45.         return db.relationship(
  46.             "GoogleStorage",
  47.             primaryjoin=lambda: cls.join_builder(GoogleStorage),
  48.             backref=db.backref(cls.__tablename__, uselist=False, overlaps="reporter,account"),
  49.             overlaps=f"reporter,account,gs,{cls.__tablename__}",
  50.             uselist=False
  51.         )
  52.  
  53.     @declared_attr
  54.     def bq(cls):  # noqa
  55.         return db.relationship(
  56.             "BigQuery",
  57.             primaryjoin=lambda: cls.join_builder(BigQuery),
  58.             backref=db.backref(cls.__tablename__, uselist=False, overlaps="reporter,account"),
  59.             overlaps=f"reporter,account,bq,{cls.__tablename__}",
  60.             uselist=False
  61.         )
  62.  
  63.     @declared_attr
  64.     def reporter_fields(cls):  # noqa
  65.         return db.relationship(
  66.             "ParameterValue",
  67.             primaryjoin=lambda: cls.join_builder(ParameterValue),
  68.             lazy="dynamic",
  69.             backref=db.backref(cls.__tablename__, overlaps="reporter,account"),
  70.             overlaps=f"reporter,account,reporter_fields,{cls.__tablename__}"
  71.         )
  72.     # endregion
  73.  
  74. class GoogleStorage(EntityRefMixin, db.Model):
  75.     __tablename__ = "google_storage"
  76.     id = db.Column(db.Integer, primary_key=True)
  77.     use_gs = db.Column(db.Boolean, default=False)
  78.     bucket_name = db.Column(db.String(50), nullable=True)
  79.     folder_path = db.Column(db.String(100), nullable=True)
  80.  
  81.  
  82. class BigQuery(EntityRefMixin, db.Model):
  83.     __tablename__ = "google_bigquery"
  84.     id = db.Column(db.Integer, primary_key=True)
  85.     use_bq = db.Column(db.Boolean, default=False)
  86.     # bq_project = db.Column(db.String(50), nullable=True)  # future feature
  87.     dataset = db.Column(db.String(50), nullable=True)
  88.     table = db.Column(db.String(50), nullable=True)
  89.     columns = db.Column(MutableList.as_mutable(db.JSON), nullable=False, default=list())
  90.     ingestion_action = db.Column(
  91.         db.Enum("WRITE_TRUNCATE", "WRITE_APPEND", name="bq_ingestion_action_enum"),
  92.         nullable=False,
  93.         default="WRITE_APPEND"
  94.     )
  95.  
  96.  
  97. class ParameterValue(EntityRefMixin, db.Model):
  98.     """Assigns a value to a parameter and assigns the parameter to an entity."""
  99.     __tablename__ = "parameter_value"
  100.     __table_args__ = (
  101.         db.UniqueConstraint(
  102.             "entity_id", "entity_type", "parameter_id",
  103.             name="entity_parameter_uc"
  104.         ),
  105.     )
  106.     id = db.Column(db.Integer, primary_key=True)
  107.     parameter_id = db.Column(db.Integer, db.ForeignKey("parameter.id"), nullable=False)
  108.     str_value = db.Column(db.String(100), nullable=True)
  109.     int_value = db.Column(db.Integer, nullable=True)
  110.     bool_value = db.Column(db.Boolean, nullable=True)
  111.     list_value = db.Column(MutableList.as_mutable(db.JSON), nullable=True)
  112.  
  113.     def __init__(self, **kwargs):
  114.         """Explicit __init__ added to accommodate hybrid_property."""
  115.         self.parameter = kwargs.pop("parameter")
  116.         for kwarg, value in kwargs.items():
  117.             setattr(self, kwarg, value)
  118.  
  119.     # region value hybrid_property
  120.     @hybrid_property
  121.     def value(self):
  122.         return getattr(self, f"{self.parameter.type}_value")
  123.  
  124.     @value.setter  # noqa
  125.     def value(self, new_value):
  126.         setattr(self, f"{self.parameter.type}_value", new_value)
  127.  
  128.     @value.deleter
  129.     def value(self):
  130.         # self._set_value(None)
  131.         setattr(self, f"{self.parameter.type}_value", None)
  132.     # endregion
  133.  
  134.  
  135. class Parameter(db.Model):
  136.     __tablename__ = "parameter"
  137.     id = db.Column(db.Integer, primary_key=True)
  138.     # universal parameters, like skip_normalization and skip_archival fields, will not be assigned to a reporter
  139.     reporter_id = db.Column(db.Integer, db.ForeignKey("reporter.id"), nullable=True)
  140.     name = db.Column(db.String(45), nullable=False)
  141.     type = db.Column(
  142.         db.Enum("str", "int", "bool", "list", name="parameter_type_enum"),
  143.         nullable=False,
  144.         default="str"
  145.     )
  146.     display_name = db.Column(db.String(100), nullable=False)  # nullable=True, default=None)
  147.     is_required = db.Column(db.Boolean, default=False)
  148.     help_text = db.Column(db.String(100), nullable=True, default=None)
  149.  
  150.     values = db.relationship("ParameterValue", backref="parameter")
  151.  
  152.  
  153. class Reporter(EntityRelationshipMixin, db.Model):
  154.     __tablename__ = "reporter"
  155.     # region internally-used fields
  156.     id = db.Column(db.Integer, primary_key=True)
  157.     module = db.Column(db.String(50), nullable=False)
  158.     klass = db.Column(db.String(50), nullable=False)
  159.     # endregion
  160.     # region meta fields
  161.     data_source = db.Column(db.String(50), nullable=True)
  162.     display_name = db.Column(db.String(50), nullable=False, unique=True)
  163.     # endregion
  164.     # region behaviors
  165.     omit_credentials = db.Column(db.Boolean, default=False)
  166.     requires_otp = db.Column(db.Boolean, nullable=False, default=False)
  167.     # endregion
  168.     # region relationships
  169.     # for managing the parameters to show for each Reporter
  170.     parameters = db.relationship("Parameter", backref="reporter", lazy="dynamic", cascade="all, delete")
  171.     accounts = db.relationship("Account", backref="reporter", cascade="all, delete")
  172.     # endregion
Advertisement
Advertisement
Advertisement
RAW Paste Data Copied
Advertisement