diff --git a/resources/migrations/00013_add_owned_foil_count_to_cards_table.down.sql b/resources/migrations/00013_add_owned_foil_count_to_cards_table.down.sql new file mode 100644 index 0000000..aadaa45 --- /dev/null +++ b/resources/migrations/00013_add_owned_foil_count_to_cards_table.down.sql @@ -0,0 +1,5 @@ +DROP TRIGGER IF EXISTS cards_update_owned_foil_count_trigger ON collection; + +DROP FUNCTION IF EXISTS update_card_owned_foil_count(); + +ALTER TABLE cards DROP COLUMN IF EXISTS owned_foil_count; diff --git a/resources/migrations/00013_add_owned_foil_count_to_cards_table.up.sql b/resources/migrations/00013_add_owned_foil_count_to_cards_table.up.sql new file mode 100644 index 0000000..c7b930f --- /dev/null +++ b/resources/migrations/00013_add_owned_foil_count_to_cards_table.up.sql @@ -0,0 +1,49 @@ +ALTER TABLE cards ADD COLUMN owned_foil_count INT NOT NULL DEFAULT 0; + +CREATE INDEX cards_owned_foil_count_idx ON cards (owned_foil_count); + +-- +-- trigger to run whenever a collection row is added/updated that fills in +-- the owned_foil_count column in the corresponding card +-- + +CREATE OR REPLACE FUNCTION update_card_owned_foil_count() + RETURNS TRIGGER +AS $update_card_owned_foil_count$ +DECLARE + update_card_id TEXT; +BEGIN + IF (TG_OP = 'DELETE') THEN + update_card_id = OLD.card_id; + ELSE + update_card_id = NEW.card_id; + END IF; + + UPDATE cards + SET + owned_foil_count = ( + SELECT COALESCE(SUM(quantity), 0) + FROM collection cl + WHERE cl.card_id = update_card_id AND cl.foil = TRUE + ) + WHERE id = update_card_id; + RETURN NULL; +END; +$update_card_owned_foil_count$ LANGUAGE plpgsql; + +CREATE TRIGGER cards_update_owned_foil_count_trigger +AFTER INSERT OR UPDATE OR DELETE ON collection +FOR EACH ROW EXECUTE PROCEDURE update_card_owned_foil_count(); + + +-- +-- fill in owned_foil_count in any existing cards +-- + +UPDATE cards c +SET + owned_foil_count = ( + SELECT COALESCE(SUM(quantity), 0) + FROM collection cl + WHERE cl.card_id = c.id AND cl.foil = TRUE + ); diff --git a/src/mtgcoll/client/components/search.cljs b/src/mtgcoll/client/components/search.cljs index 8a2a9bd..d3117c0 100644 --- a/src/mtgcoll/client/components/search.cljs +++ b/src/mtgcoll/client/components/search.cljs @@ -118,21 +118,23 @@ :< "Less Than"}) (def search-filter-defs - {:name {:label "Name" :type :text :comparisons [:like :=]} - :set-code {:label "Set" :type :text :comparisons [:=] :component set-search-field-element} - :colors {:label "Colors" :type :checkbox :comparisons [:like :=] :choices ["Black" "Blue" "Green" "Red" "White"] :component checkboxes-search-field-element} - :color-identity {:label "Color Identity" :type :checkbox :comparisons [:like :=] :choices [["Black" "B"] ["Blue" "U"] ["Green" "G"] ["Red" "R"] ["White" "W"]] :component checkboxes-search-field-element} - :type {:label "Type" :type :text :comparisons [:like :=]} - :rarity {:label "Rarity" :type :dropdown :comparisons [:=] :choices ["Basic Land" "Common" "Mythic Rare" "Rare" "Special" "Uncommon"]} - :text {:label "Card Text" :type :text :comparisons [:like :=]} - :artist {:label "Artist" :type :text :comparisons [:like :=]} - :number {:label "Card Number" :type :text :comparisons [:=]} - :power {:label "Power" :type :text :comparisons [:=]} - :toughness {:label "Toughness" :type :text :comparisons [:=]} - :owned? {:label "Owned?" :type :boolean :comparisons [:=]} - :owned-count {:label "Owned Amount" :type :numeric :comparisons [:= :> :<] :validation-fn valid-integer? :transform-fn js/parseInt} - :paper-price {:label "Price (Paper)" :type :numeric :comparisons [:= :> :<] :validation-fn valid-float? :transform-fn js/parseFloat} - :online-price {:label "Price (Online)" :type :numeric :comparisons [:= :> :<] :validation-fn valid-float? :transform-fn js/parseFloat}}) + {:name {:label "Name" :type :text :comparisons [:like :=]} + :set-code {:label "Set" :type :text :comparisons [:=] :component set-search-field-element} + :colors {:label "Colors" :type :checkbox :comparisons [:like :=] :choices ["Black" "Blue" "Green" "Red" "White"] :component checkboxes-search-field-element} + :color-identity {:label "Color Identity" :type :checkbox :comparisons [:like :=] :choices [["Black" "B"] ["Blue" "U"] ["Green" "G"] ["Red" "R"] ["White" "W"]] :component checkboxes-search-field-element} + :type {:label "Type" :type :text :comparisons [:like :=]} + :rarity {:label "Rarity" :type :dropdown :comparisons [:=] :choices ["Basic Land" "Common" "Mythic Rare" "Rare" "Special" "Uncommon"]} + :text {:label "Card Text" :type :text :comparisons [:like :=]} + :artist {:label "Artist" :type :text :comparisons [:like :=]} + :number {:label "Card Number" :type :text :comparisons [:=]} + :power {:label "Power" :type :text :comparisons [:=]} + :toughness {:label "Toughness" :type :text :comparisons [:=]} + :owned? {:label "Owned?" :type :boolean :comparisons [:=]} + :owned-foil? {:label "Owned Foil?" :type :boolean :comparisons [:=]} + :owned-count {:label "Owned Amount" :type :numeric :comparisons [:= :> :<] :validation-fn valid-integer? :transform-fn js/parseInt} + :owned-foil-count {:label "Owned Foil Amount" :type :numeric :comparisons [:= :> :<] :validation-fn valid-integer? :transform-fn js/parseInt} + :paper-price {:label "Price (Paper)" :type :numeric :comparisons [:= :> :<] :validation-fn valid-float? :transform-fn js/parseFloat} + :online-price {:label "Price (Online)" :type :numeric :comparisons [:= :> :<] :validation-fn valid-float? :transform-fn js/parseFloat}}) (defn ->search-field-map [field & [filter-id]] diff --git a/src/mtgcoll/views/functions/cards.clj b/src/mtgcoll/views/functions/cards.clj index 64f8aeb..e6b2195 100644 --- a/src/mtgcoll/views/functions/cards.clj +++ b/src/mtgcoll/views/functions/cards.clj @@ -66,7 +66,8 @@ s.online_only, c.paper_price, c.online_price, - c.owned_count + c.owned_count, + c.owned_foil_count from cards c join sets s on c.set_code = s.code where c.id = ?" id]) @@ -137,39 +138,45 @@ :< (compare-fn fields :< value)))) (def search-field-where-clauses - {:name (text-comparison-fn [:name :normalized_name]) - :set-code (text-comparison-fn [:set_code] true) - :colors (fn [value comparison] - (let [colors (as-> value x - (map string/trim x) - (map string/capitalize x) - (sort x))] - (case comparison - := [:= :colors (string/join "," colors)] - :like [:ilike :colors (str "%" (string/join "%" colors) "%")]))) - :color-identity (fn [value comparison] - (let [colors (as-> value x - (map string/trim x) - (map string/upper-case x) - (sort x))] - (case comparison - := [:= :color_identity (string/join "," colors)] - :like [:like :color_identity (str "%" (string/join "%" colors) "%")]))) - :type (text-comparison-fn [:type]) - :rarity (text-comparison-fn [:rarity] true) - :text (text-comparison-fn [:text]) - :artist (text-comparison-fn [:artist]) - :number (text-comparison-fn [:number] true) - :power (text-comparison-fn [:power] true) - :toughness (text-comparison-fn [:toughness] true) - :owned-count (numeric-comparison-fn [:owned_count]) - :paper-price (numeric-comparison-fn [:paper_price]) - :online-price (numeric-comparison-fn [:online_price]) - :owned? (fn [value comparison] - (assert (= := comparison)) - (case value - true [:> :owned_count 0] - false [:= :owned_count 0]))}) + {:name (text-comparison-fn [:name :normalized_name]) + :set-code (text-comparison-fn [:set_code] true) + :colors (fn [value comparison] + (let [colors (as-> value x + (map string/trim x) + (map string/capitalize x) + (sort x))] + (case comparison + := [:= :colors (string/join "," colors)] + :like [:ilike :colors (str "%" (string/join "%" colors) "%")]))) + :color-identity (fn [value comparison] + (let [colors (as-> value x + (map string/trim x) + (map string/upper-case x) + (sort x))] + (case comparison + := [:= :color_identity (string/join "," colors)] + :like [:like :color_identity (str "%" (string/join "%" colors) "%")]))) + :type (text-comparison-fn [:type]) + :rarity (text-comparison-fn [:rarity] true) + :text (text-comparison-fn [:text]) + :artist (text-comparison-fn [:artist]) + :number (text-comparison-fn [:number] true) + :power (text-comparison-fn [:power] true) + :toughness (text-comparison-fn [:toughness] true) + :owned-count (numeric-comparison-fn [:owned_count]) + :owned-foil-count (numeric-comparison-fn [:owned_foil_count]) + :paper-price (numeric-comparison-fn [:paper_price]) + :online-price (numeric-comparison-fn [:online_price]) + :owned? (fn [value comparison] + (assert (= := comparison)) + (case value + true [:> :owned_count 0] + false [:= :owned_count 0])) + :owned-foil? (fn [value comparison] + (assert (= := comparison)) + (case value + true [:> :owned_foil_count 0] + false [:= :owned_foil_count 0]))}) (defn- filter->hsql-where-criteria [{:keys [field value comparison]}] @@ -199,7 +206,8 @@ :c.loyalty :c.paper_price :c.online_price - :c.owned_count] + :c.owned_count + :c.owned_foil_count] :from [[:cards :c]] :join [[:sets :s] [:= :c.set_code :s.code]]} (if order-by