Esempio n. 1
0
 def test_name_match_invert(self):
     """
     Tests that
     """
     root_param = AndParam(True)
     card = create_test_card({'name': 'foo'})
     param = CardNameParam('bar')
     root_param.add_parameter(param)
     self.assertIn(card, Card.objects.filter(root_param.query()))
Esempio n. 2
0
def create_colour_param(colour_params: List[Bit], param_class: type, match_colours: bool,
                        exclude_colours: bool) -> AndParam:
    """
    Creates a series of colour parameters based on the given colours
    :param colour_params: A list of bits flags that should be searched for
    :param param_class: The colour parameter class (either Colour of ColourIdentity)
    :param match_colours: Whether the colours should match exactly or not
    :param exclude_colours: Whether unselected colours should be excluded or not
    :return: A root AndParam with a series of colour parameters underneath
    """
    root_param = AndParam()
    if match_colours:
        colour_root = AndParam()
    else:
        colour_root = OrParam()
    root_param.add_parameter(colour_root)

    for colour in colour_params:
        colour_root.add_parameter(param_class(colour))

    if exclude_colours:
        exclude_param = OrParam(inverse=True)
        root_param.add_parameter(exclude_param)
        for colour in [c for c in Card.colour_flags.values() if c not in colour_params]:
            param = param_class(colour)
            exclude_param.add_parameter(param)

    return root_param
Esempio n. 3
0
 def simple_word_group_parameter(self) -> CardSearchParam:
     """
     Attempts to parse a parameter that has a list of words inside parentheses
     For example "oracle:(foo bar)"
     :return: An AndParam containing the parameters. All the parameters will be of
     the type specified before the colon at the start of the string
     """
     parameter_type = self.match("param_type")
     operator = self.match("operator")
     param_values = self.match("simple_word_group")
     and_param = AndParam()
     for value in param_values:
         param = self.parse_param(parameter_type, operator, value)
         and_param.add_parameter(param)
     return and_param
Esempio n. 4
0
class CardSearch:
    def __init__(self):
        self.root_parameter = AndParam()
        self.sort_params = list()

    def add_sort_param(self, sort_param: CardSortParam):
        self.sort_params.append(sort_param)

    def result_search(self):
        result = self.root_parameter.get_result()
        self.add_sort_param(CardNameSortParam())
        result = result.order_by(*[
            order for sort_param in self.sort_params
            for order in sort_param.get_sort_list()
        ])
        return result
Esempio n. 5
0
 def test_name_match_invert(self) -> None:
     """
     Tests that
     """
     root_param = AndParam()
     root_param.negated = True
     card = create_test_card({"name": "foo"})
     set_obj = create_test_set("Setty", "SET", {})
     printing = create_test_card_printing(card, set_obj, {})
     param = CardNameParam("bar")
     root_param.add_parameter(param)
     self.assertIn(printing,
                   CardPrinting.objects.filter(root_param.query()))
Esempio n. 6
0
    def and_group(self) -> CardSearchParam:
        """
        Attempts to parse a list of parameters separated by "and"s
        :return: The AndParam group, or the single parameter if there is only one
        """
        result = self.match("parameter_group")
        and_group = None
        while True:
            self.maybe_keyword("and")
            param_group = self.maybe_match("parameter_group")
            if not param_group:
                break

            if and_group is None:
                and_group = AndParam()
                and_group.add_parameter(result)
            and_group.add_parameter(param_group)

        return and_group or result
Esempio n. 7
0
def create_colour_param(
    colour_params: List[int],
    param_class: type,
    match_colours: bool,
    exclude_colours: bool,
) -> AndParam:
    """
    Creates a series of colour parameters based on the given colours
    :param colour_params: A list of bits flags that should be searched for
    :param param_class: The colour parameter class (either Colour of ColourIdentity)
    :param match_colours: Whether the colours should match exactly or not
    :param exclude_colours: Whether unselected colours should be excluded or not
    :return: A root AndParam with a series of colour parameters underneath
    """
    root_param = AndParam()
    if match_colours:
        colour_root = AndParam()
    else:
        colour_root = OrParam()
    root_param.add_parameter(colour_root)

    for colour in colour_params:
        colour_root.add_parameter(param_class(colour))

    if exclude_colours:
        exclude_param = OrParam()
        exclude_param.negated = True
        for colour in [
                c for c in Card.colour_flags.values() if c not in colour_params
        ]:
            param = param_class(colour)
            exclude_param.add_parameter(param)

        if exclude_param.child_parameters:
            root_param.add_parameter(exclude_param)

    return root_param
Esempio n. 8
0
 def __init__(self) -> None:
     self.root_parameter: BranchParam = AndParam()
     self.sort_params: List[CardSortParam] = []
     self.paginator: Optional[Paginator] = None
     self.results: List[SearchResult] = []
     self.page: Optional[int] = None
Esempio n. 9
0
class BaseSearch:
    """
    The core searching object. This can be extended to have different fields, but they should
    all use a single root node with parameters haning off of it
    """

    def __init__(self):
        self.root_parameter = AndParam()
        self.sort_params = list()
        self.paginator = None
        self.results = []
        self.page = None

    # pylint: disable=no-self-use
    def build_parameters(self):
        """
        Build the parameters tree for this search object
        :return:
        """
        return

    def search(self, page_number: int = 1, page_size: int = 25):
        """
        Runs the search for this search and constructs
        :param page_number: The result page
        :param page_size: The number of items per page
        """
        queryset = Card.objects.filter(self.root_parameter.query()).distinct()
        self.add_sort_param(CardNameSortParam())
        self.add_sort_param(CardColourSortParam())
        self.add_sort_param(CardPowerSortParam())
        queryset = queryset.order_by(
            *[order for sort_param in self.sort_params for order in sort_param.get_sort_list()])

        self.paginator = Paginator(queryset, page_size)
        try:
            self.page = self.paginator.page(page_number)
        except EmptyPage:
            return
        cards = list(self.page)
        prefetch_related_objects(cards, 'printings__printed_languages__physical_cards__ownerships')
        prefetch_related_objects(cards, 'printings__printed_languages__language')
        prefetch_related_objects(cards, 'printings__set')
        prefetch_related_objects(cards, 'printings__rarity')

        preferred_set = self.get_preferred_set()
        self.results = [SearchResult(card, selected_set=preferred_set) for card in cards]

    def get_preferred_set(self) -> Optional[Set]:
        """
        Gets the set that would be preferred for each card result (this should be overridden)
        :return:
        """
        raise NotImplementedError()

    def get_page_buttons(self, current_page: int, page_span: int) -> List[PageButton]:
        """
        Gets the page buttons that should appear for this search based on the number of pages
        in the results and hoa many pages the buttons should span
        :param current_page: The current page
        :param page_span: The number of pages to the left and right of the current page
        :return: A list of page buttons. Some of them can disabled padding buttons, and there will
        be a next and previous button at the start and end too
        """
        page_buttons = [PageButton(page_number, True, is_active=page_number == current_page)
                        for page_number in self.paginator.page_range
                        if abs(page_number - current_page) <= page_span]

        # if the current page is great enough
        # put a  link to the first page at the start followed by a spacer
        if current_page - page_span > 1:
            page_buttons.insert(0, PageButton(None, False, is_spacer=True))
            page_buttons.insert(0, PageButton(1, True))

        if current_page + page_span <= self.paginator.num_pages - 2:
            page_buttons.append(PageButton(None, False, is_spacer=True))

        if current_page + page_span <= self.paginator.num_pages - 1:
            page_buttons.append(PageButton(self.paginator.num_pages, True))

        page_buttons.insert(0,
                            PageButton(max(current_page - 1, 1), current_page != 1,
                                       is_previous=True))
        page_buttons.append(PageButton(current_page + 1,
                                       current_page != self.paginator.num_pages, is_next=True))

        return page_buttons

    def add_sort_param(self, sort_param: CardSortParam) -> None:
        """
        Adds a sort parameter
        :param sort_param:
        :return:
        """
        self.sort_params.append(sort_param)
Esempio n. 10
0
 def __init__(self):
     self.root_parameter = AndParam()
     self.sort_params = list()
     self.paginator = None
     self.results = []
     self.page = None
Esempio n. 11
0
    def build_parameters(self) -> None:
        """
        Constructs the parameter list for this searching object
        """
        root_param = self.root_parameter

        if self.card_name:
            root_param.add_parameter(CardNameParam(self.card_name))

        if self.rules_text:
            root_param.add_parameter(CardRulesTextParam(self.rules_text))

        if self.flavour_text:
            root_param.add_parameter(CardFlavourTextParam(self.flavour_text))

        if self.type_text:
            root_param.add_parameter(CardTypeParam(self.type_text))

        if self.subtype_text:
            root_param.add_parameter(CardSubtypeParam(self.subtype_text))

        if self.min_cmc is not None:
            root_param.add_parameter(CardCmcParam(self.min_cmc, "GTE"))

        if self.max_cmc is not None:
            root_param.add_parameter(CardCmcParam(self.max_cmc, "LTE"))

        if self.min_power is not None:
            root_param.add_parameter(CardNumPowerParam(self.min_power, "GTE"))

        if self.max_power is not None:
            root_param.add_parameter(CardNumPowerParam(self.max_power, "LTE"))

        if self.min_toughness is not None:
            root_param.add_parameter(
                CardNumToughnessParam(self.min_toughness, "GTE"))

        if self.max_toughness is not None:
            root_param.add_parameter(
                CardNumToughnessParam(self.max_toughness, "LTE"))

        if self.mana_cost is not None and self.mana_cost != "":
            root_param.add_parameter(CardManaCostParam(self.mana_cost, False))

        if self.colours:
            self.root_parameter.add_parameter(
                create_colour_param(
                    self.colours,
                    CardColourParam,
                    match_colours=self.match_colours_exactly,
                    exclude_colours=self.exclude_unselected_colours,
                ))

        if self.colour_identities:
            self.root_parameter.add_parameter(
                create_colour_param(
                    self.colour_identities,
                    CardColourIdentityParam,
                    match_colours=self.match_colour_identities_exactly,
                    exclude_colours=self.exclude_unselected_colour_identities,
                ))

        if self.rarities:
            rarity_node: BranchParam = AndParam(
            ) if self.match_rarities_exactly else OrParam()
            self.root_parameter.add_parameter(rarity_node)
            for rarity in self.rarities:
                rarity_node.add_parameter(CardRarityParam(rarity))

        if self.sets:
            set_node: BranchParam = AndParam(
            ) if self.match_sets_exactly else OrParam()
            self.root_parameter.add_parameter(set_node)
            for set_obj in self.sets:
                set_node.add_parameter(CardSetParam(set_obj))
Esempio n. 12
0
 def __init__(self):
     self.root_parameter = AndParam()
     self.sort_params = list()