Esempio n. 1
0
class DeckSearchHasCard(db.Model):
    """A table showing the amount the playset sizes of cards
    present in the deck search"""

    decksearch_id = db.Column("decksearch_id",
                              db.Integer,
                              db.ForeignKey("deck_searches.id"),
                              primary_key=True)
    set_num = db.Column("set_num", db.Integer, primary_key=True)
    card_num = db.Column("card_num", db.Integer, primary_key=True)
    count_in_deck = db.Column("count_in_deck",
                              db.Integer,
                              primary_key=True,
                              nullable=False)
    num_decks_with_count_or_less = db.Column("num_decks_with_count_or_less",
                                             db.Integer,
                                             nullable=False)
    __table_args__ = (
        db.ForeignKeyConstraint(
            (set_num, card_num),
            [models_card.Card.set_num, models_card.Card.card_num]),
        {},
    )

    @staticmethod
    def as_df(decksearch_id: int) -> pd.DataFrame:
        session = db.engine.raw_connection()
        query = f"""\
            SELECT *
            FROM deck_search_has_card
            WHERE decksearch_id = {decksearch_id}"""
        df = pd.read_sql_query(query, session)
        del df["decksearch_id"]
        return df
Esempio n. 2
0
class User(db.Model, UserMixin):
    """Model representing a user."""

    __tablename__ = "users"
    id = db.Column("id", db.Integer(), primary_key=True, autoincrement=True)
    email = db.Column("email", db.String(), unique=True)
    name = db.Column("name", db.String(length=40))
    ew_key = db.Column(
        "ew_key",
        sqlalchemy_utils.EncryptedType(db.String(50),
                                       application.config["SECRET_KEY"],
                                       FernetEngine),
    )
    password = db.Column("password", db.String())
class Card(db.Model):
    """Model representing an Eternal card."""

    __tablename__ = "cards"
    set_num = db.Column("SetNumber", db.Integer, primary_key=True)
    card_num = db.Column("EternalID", db.Integer, primary_key=True)
    name = db.Column("Name", db.String(length=40), unique=True, nullable=False)
    rarity = db.Column("Rarity",
                       db.String(length=9),
                       db.ForeignKey("rarities.Name"),
                       nullable=False)
    image_url = db.Column("ImageUrl",
                          db.String(length=100),
                          unique=True,
                          nullable=False)
    details_url = db.Column("DetailsUrl",
                            db.String(length=100),
                            unique=True,
                            nullable=False)
    is_in_draft_pack = db.Column("IsInDraftPack", db.Boolean, nullable=False)
    is_in_expedition = db.Column("IsInExpedition", db.Boolean, nullable=False)

    @property
    def id(self):
        """Returns the CardId for the Card."""
        try:
            card_id = CardId(set_num=self.set_num, card_num=self.card_num)
        except sqlalchemy.orm.exc.DetachedInstanceError as e:
            logging.error("Detached Instance Error!", self, self.__dict__)
            raise e
        return card_id
Esempio n. 4
0
class WeightedDeckSearch(db.Model):
    """A DeckSearch with a user given weight for its relative importance.

    Allows users to personalize their recommendations."""

    deck_search_id = db.Column(db.Integer,
                               db.ForeignKey("deck_searches.id"),
                               primary_key=True)
    profile_id = db.Column(db.Integer())
    name = db.Column("name", db.String(length=20), primary_key=True)

    weight = db.Column("weight", db.Float)
    deck_search: DeckSearch = db.relationship("DeckSearch",
                                              uselist=False,
                                              cascade_backrefs=False)
Esempio n. 5
0
class DeckHasCard(db.Model):
    """A table showing how many copies of a card a deck has."""

    deck_id = db.Column(
        "deck_id", db.String(length=100), db.ForeignKey("decks.id"), primary_key=True
    )
    set_num = db.Column("set_num", db.Integer, primary_key=True)
    card_num = db.Column("card_num", db.Integer, primary_key=True)
    num_played = db.Column("num_played", db.Integer, nullable=False)
    __table_args__ = (
        db.ForeignKeyConstraint(
            [set_num, card_num], [card.Card.set_num, card.Card.card_num]
        ),
        {},
    )

    def to_card_id(self) -> card.CardId:
        return card.CardId(set_num=self.set_num, card_num=self.card_num)
Esempio n. 6
0
class Deck(db.Model):
    """Model representing an Eternal Deck from Warcry"""

    __tablename__ = "decks"
    id = db.Column("id", db.String(length=100), primary_key=True)
    archetype = db.Column("archetype", db.Enum(Archetype), nullable=True)
    date_added = db.Column("date_added", db.DateTime)
    date_updated = db.Column("date_updated", db.DateTime)
    deck_type = db.Column("deck_type", db.Enum(DeckType))
    description = db.Column("description", db.Text, nullable=True)
    patch = db.Column("patch", db.String(length=10))
    username = db.Column("username", db.String(length=30))
    views = db.Column("views", db.Integer)
    rating = db.Column("rating", db.Integer)
    cards = db.relationship("DeckHasCard")

    @classmethod
    def get_from_id(cls, deck_id: str):
        """Gets the deck matching the deck id."""
        return Deck.query.filter_by(id=deck_id).first()
Esempio n. 7
0
class Rarity(db.Model):
    """A table representing rarities in Eternal.

    Drop rates and crafting costs correspond to rarity."""

    __tablename__ = "rarities"
    name = db.Column("Name", db.String(length=9), primary_key=True)
    num_in_pack = db.Column("NumInPack", db.Float, nullable=False)
    enchant = db.Column("Enchant", db.Integer, nullable=False)
    disenchant = db.Column("Disenchant", db.Integer, nullable=False)
    foil_enchant = db.Column("FoilEnchant", db.Integer, nullable=False)
    foil_disenchant = db.Column("FoilDisenchant", db.Integer, nullable=False)

    @property
    def drop_chance(self):
        """The number of cards of a given rarity that will drop in a pack.

        Integers are assured numbers. A float is a chance that the drop will appear.
        All numbers are correct for long term average."""
        return self.num_in_pack / sum([r.num_in_pack for r in RARITIES])

    def __repr__(self):
        return f"<Rarity {self.name}>"
Esempio n. 8
0
class DeckSearch(db.Model):
    """A table for a set of parameters to filter the list of all decks"""

    __tablename__ = "deck_searches"
    id = db.Column(db.Integer, primary_key=True)
    maximum_age_days = db.Column("maximum_age_days", db.Integer())
    cards: t.List[DeckSearchHasCard] = db.relationship("DeckSearchHasCard")

    def get_decks(self) -> t.List[models_deck.Deck]:
        """Returns all decks belonging to the deck search"""
        time_to_update = datetime.datetime.now() - datetime.timedelta(
            days=self.maximum_age_days)
        is_past_time_to_update = models_deck.Deck.date_updated > time_to_update
        decks = models_deck.Deck.query.filter(is_past_time_to_update)
        return decks

    def get_play_counts(self) -> pd.DataFrame:
        """Gets a dataframe of the number of times each copy of each card is used
        in decks in the deck search."""
        num_decks_with_cards = DeckSearchHasCard.as_df(decksearch_id=self.id)
        return num_decks_with_cards

    def update_playrates(self):
        """Updates a cache of playrates representing the total frequency
        of playsets of cards in the decks.

        This cache is redundant but avoids recalculation.

        This cache can become out of date, and should be recalculated
        regularly."""
        self.delete_playrates()
        playrates = self._get_playrates()
        self._add_playrates(playrates)

    def delete_playrates(self):
        """Delete the playrate cache."""
        DeckSearchHasCard.query.filter_by(decksearch_id=self.id).delete()

    def _get_playrates(self):
        playrate = card_collections.make_card_playset_dict()
        for deck in self.get_decks():
            for card in deck.cards:
                card_id = models_card.CardId(set_num=card.set_num,
                                             card_num=card.card_num)
                for num_played in range(min(card.num_played, 4)):
                    playrate[card_id][num_played] += self._scale_playrate(deck)
        return playrate

    def _scale_playrate(self, deck):
        """This is the adjusted amount a card play counts for,
        scaled on the 'importance' of the deck, so that better decks have more
        influence over the play rates."""
        return deck.views

    def _add_playrates(self, playrates: t.Dict):
        rows = []
        for card_id, counts in tqdm(playrates.items(), desc="Add playrates"):
            for play_count in range(1, 5):
                deck_search_has_card = DeckSearchHasCard(
                    decksearch_id=self.id,
                    set_num=card_id.set_num,
                    card_num=card_id.card_num,
                    count_in_deck=play_count,
                    num_decks_with_count_or_less=counts[play_count - 1],
                )
                rows.append(deck_search_has_card)
        db.session.bulk_save_objects(rows)
        db.session.commit()