Skip to content

Commit 5d09de9

Browse files
authored
Merge pull request #103 from plural/card-attributes
Add first batch of advanced card attributes to API & search.
2 parents 8424653 + 3f7c342 commit 5d09de9

File tree

8 files changed

+139
-23
lines changed

8 files changed

+139
-23
lines changed

app/models/card.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,20 @@ class Card < ApplicationRecord
1515
has_many :unified_restrictions
1616

1717
validates :name, uniqueness: true
18+
19+
def advancement_requirement
20+
self[:advancement_requirement] == -1 ? 'X' : self[:advancement_requirement]
21+
end
22+
def link_provided
23+
self[:link_provided] == -1 ? 'X' : self[:link_provided]
24+
end
25+
def mu_provided
26+
self[:mu_provided] == -1 ? 'X' : self[:mu_provided]
27+
end
28+
def num_printed_subroutines
29+
self[:num_printed_subroutines] == -1 ? 'X' : self[:num_printed_subroutines]
30+
end
31+
def recurring_credits_provided
32+
self[:recurring_credits_provided] == -1 ? 'X' : self[:recurring_credits_provided]
33+
end
1834
end

app/resources/api/v3/public/card_resource.rb

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ class Api::V3::Public::CardResource < JSONAPI::Resource
99
attributes :deck_limit, :influence_cost, :influence_limit, :memory_cost
1010
attributes :minimum_deck_size, :strength, :stripped_text, :text, :trash_cost
1111
attributes :is_unique, :display_subtypes, :updated_at
12-
attribute :latest_printing_id
12+
attributes :card_abilities, :latest_printing_id
1313

1414
key_type :string
1515

@@ -23,6 +23,22 @@ def latest_printing_id
2323
@model.printings.max_by { |p| p.date_release } ['id']
2424
end
2525

26+
def card_abilities
27+
{
28+
additional_cost: @model.additional_cost,
29+
advanceable: @model.advanceable,
30+
gains_subroutines: @model.gains_subroutines,
31+
interrupt: @model.interrupt,
32+
link_provided: @model.link_provided,
33+
mu_provided: @model.mu_provided,
34+
num_printed_subroutines: @model.num_printed_subroutines,
35+
on_encounter_effect: @model.on_encounter_effect,
36+
performs_trace: @model.performs_trace,
37+
recurring_credits_provided: @model.recurring_credits_provided,
38+
trash_ability: @model.trash_ability,
39+
}
40+
end
41+
2642
filters :title, :card_type_id, :side_id, :faction_id, :advancement_requirement
2743
filters :agenda_points, :base_link, :cost, :deck_limit, :influence_cost
2844
filters :influence_limit, :memory_cost, :minimum_deck_size, :strength, :trash_cost, :is_unique

app/resources/api/v3/public/printing_resource.rb

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ class Api::V3::Public::PrintingResource < JSONAPI::Resource
1010
attributes :quantity, :date_release, :updated_at
1111

1212
# Parent Card attributes, included inline to make printings a bit more useful.
13-
attributes :advancement_requirement, :agenda_points, :base_link, :card_type_id
14-
attributes :cost, :deck_limit, :display_subtypes, :faction_id, :influence_cost
15-
attributes :influence_limit, :is_unique, :memory_cost, :minimum_deck_size
13+
attributes :advancement_requirement, :agenda_points, :base_link, :card_abilities
14+
attributes :card_type_id, :cost, :deck_limit, :display_subtypes, :faction_id
15+
attributes :influence_cost, :influence_limit, :is_unique, :memory_cost, :minimum_deck_size
1616
attributes :side_id, :strength, :stripped_text, :stripped_title, :text
1717
attributes :title, :trash_cost
1818

@@ -122,6 +122,21 @@ def agenda_points
122122
def base_link
123123
@model.card.base_link
124124
end
125+
def card_abilities
126+
{
127+
additional_cost: @model.card.additional_cost,
128+
advanceable: @model.card.advanceable,
129+
gains_subroutines: @model.card.gains_subroutines,
130+
interrupt: @model.card.interrupt,
131+
link_provided: @model.card.link_provided,
132+
mu_provided: @model.card.mu_provided,
133+
num_printed_subroutines: @model.card.num_printed_subroutines,
134+
on_encounter_effect: @model.card.on_encounter_effect,
135+
performs_trace: @model.card.performs_trace,
136+
recurring_credits_provided: @model.card.recurring_credits_provided,
137+
trash_ability: @model.card.trash_ability,
138+
}
139+
end
125140
def card_type_id
126141
@model.card.card_type_id
127142
end

lib/card_search_parser.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ class CardSearchParser < Parslet::Parser
1818
# Note that while this list should generally be kept sorted, an entry that is a prefix of
1919
# a later entry will clobber the later entries and throw an error parsing text with the later entries.
2020
rule(:keyword) {
21+
str('additional_cost') |
22+
str('advanceable') |
2123
str('advancement_cost') |
2224
str('agenda_points') |
2325
str('base_link') |
@@ -28,19 +30,28 @@ class CardSearchParser < Parslet::Parser
2830
str('eternal_points') |
2931
str('faction') |
3032
str('format') |
33+
str('gains_subroutines') |
3134
str('global_penalty') |
3235
str('illustrator') |
3336
str('in_restriction') |
3437
str('influence_cost') |
38+
str('interrupt') |
3539
str('is_banned') |
3640
str('is_restricted') |
3741
str('is_unique') |
42+
str('link_provided') |
3843
str('memory_usage') |
44+
str('mu_provided') |
45+
str('num_printed_subroutines') |
46+
str('on_encounter_effect') |
47+
str('performs_trace') |
48+
str('recurring_credits_provided') |
3949
str('restriction_id') |
4050
str('side') |
4151
str('strength') |
4252
str('text') |
4353
str('title') |
54+
str('trash_ability') |
4455
str('trash_cost') |
4556
str('universal_faction_cost') |
4657
# Single letter 'short codes'

lib/card_search_query_builder.rb

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
11
class CardSearchQueryBuilder
22
@@parser = CardSearchParser.new
33
@@boolean_keywords = [
4+
'additional_cost',
5+
'advanceable',
46
'b',
57
'banlist',
8+
'gains_subroutines',
69
'in_restriction',
10+
'interrupt',
711
'is_banned',
812
'is_restricted',
913
'is_unique',
14+
'on_encounter_effect',
15+
'performs_trace',
16+
'trash_ability',
1017
'u',
1118
]
1219
@@numeric_keywords = [
@@ -20,11 +27,15 @@ class CardSearchQueryBuilder
2027
'h',
2128
'influence_cost',
2229
'l',
30+
'link_provided',
2331
'm',
2432
'memory_usage',
33+
'mu_provided',
2534
'n',
35+
'num_printed_subroutines',
2636
'o',
2737
'p',
38+
'recurring_credits_provided',
2839
'strength',
2940
'trash_cost',
3041
'universal_faction_cost',
@@ -62,6 +73,8 @@ class CardSearchQueryBuilder
6273
@@term_to_field_map = {
6374
# format should implicitly use the currently active card pool and restriction lists unless another is specified.
6475
'_' => 'cards.stripped_title',
76+
'additional_cost' => 'cards.additional_cost',
77+
'advanceable' => 'cards.advanceable',
6578
'advancement_cost' => 'cards.advancement_requirement',
6679
'agenda_points' => 'cards.agenda_points',
6780
'base_link' => 'cards.base_link',
@@ -75,26 +88,35 @@ class CardSearchQueryBuilder
7588
'faction' => 'cards.faction_id',
7689
'format' => 'unified_restrictions.format_id',
7790
'g' => 'cards.advancement_requirement',
91+
'gains_subroutines' => 'cards.gains_subroutines',
7892
'global_penalty' => 'unified_restrictions.global_penalty',
7993
'h' => 'cards.trash_cost',
8094
'in_restriction' => 'unified_restrictions.in_restriction',
8195
'influence_cost' => 'cards.influence_cost',
96+
'interrupt' => 'cards.interrupt',
8297
'is_banned' => 'unified_restrictions.is_banned',
8398
'is_restricted' => 'unified_restrictions.is_restricted',
8499
'is_unique' => 'cards.is_unique',
85100
'l' => 'cards.base_link',
101+
'link_provided' => 'cards.link_provided',
86102
'm' => 'cards.memory_cost',
87103
'memory_usage' => 'cards.memory_cost',
104+
'mu_provided' => 'cards.mu_provided',
88105
'n' => 'cards.influence_cost',
106+
'num_printed_subroutines' => 'cards.num_printed_subroutines',
89107
'o' => 'cards.cost',
108+
'on_encounter_effect' => 'cards.on_encounter_effect',
90109
'p' => 'cards.strength',
110+
'performs_trace' => 'cards.performs_trace',
111+
'recurring_credits_provided' => 'cards.recurring_credits_provided',
91112
'restriction_id' => 'unified_restrictions.restriction_id',
92113
's' => 'card_subtypes.name',
93114
'side' => 'cards.card_side_id',
94115
'strength' => 'cards.strength',
95116
't' => 'cards.card_type_id',
96117
'text' => 'cards.stripped_text',
97118
'title' => 'cards.stripped_title',
119+
'trash_ability' => 'cards.trash_ability',
98120
'trash_cost' => 'cards.trash_cost',
99121
'u' => 'cards.is_unique',
100122
'universal_faction_cost' => 'unified_restrictions.universal_faction_cost',
@@ -155,19 +177,19 @@ def initialize(query)
155177
constraints << '%s %s ?' % [@@term_to_field_map[keyword], operator]
156178
where << value
157179
elsif @@numeric_keywords.include?(keyword)
158-
if !value.match?(/\A\d+\Z/)
180+
if !value.match?(/\A(\d+|x)\Z/i)
159181
@parse_error = 'Invalid value "%s" for integer field "%s"' % [value, keyword]
160182
return
161183
end
162184
operator = ''
163-
if @@numeric_operators.include?(match_type)
185+
if @@numeric_operators.include?(match_type)
164186
operator = @@numeric_operators[match_type]
165187
else
166188
@parse_error = 'Invalid numeric operator "%s"' % match_type
167189
return
168190
end
169191
constraints << '%s %s ?' % [@@term_to_field_map[keyword], operator]
170-
where << value
192+
where << (value.downcase == 'x' ? -1 : value)
171193
else
172194
# String fields only support : and !, resolving to to {,NOT} LIKE %value%.
173195
# TODO(plural): consider ~ for regex matches.
@@ -178,7 +200,7 @@ def initialize(query)
178200
@parse_error = 'Invalid string operator "%s"' % match_type
179201
return
180202
end
181-
constraints << 'lower(%s) %s ?' % [@@term_to_field_map[keyword], operator]
203+
constraints << 'lower(%s) %s ?' % [@@term_to_field_map[keyword], operator]
182204
where << '%%%s%%' % value
183205
end
184206
if @@term_to_left_join_map.include?(keyword)

lib/printing_search_parser.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ class PrintingSearchParser < Parslet::Parser
1818
# Note that while this list should generally be kept sorted, an entry that is a prefix of
1919
# a later entry will clobber the later entries and throw an error parsing text with the later entries.
2020
rule(:keyword) {
21+
str('additional_cost') |
22+
str('advanceable') |
2123
str('advancement_cost') |
2224
str('agenda_points') |
2325
str('base_link') |
@@ -31,21 +33,30 @@ class PrintingSearchParser < Parslet::Parser
3133
str('faction') |
3234
str('flavor') |
3335
str('format') |
36+
str('gains_subroutines') |
3437
str('global_penalty') |
3538
str('illustrator') |
3639
str('in_restriction') |
3740
str('influence_cost') |
41+
str('interrupt') |
3842
str('is_banned') |
3943
str('is_restricted') |
4044
str('is_unique') |
45+
str('link_provided') |
4146
str('memory_usage') |
47+
str('mu_provided') |
48+
str('num_printed_subroutines') |
49+
str('on_encounter_effect') |
50+
str('performs_trace') |
4251
str('quantity') |
52+
str('recurring_credits_provided') |
4353
str('release_date') |
4454
str('restriction_id') |
4555
str('side') |
4656
str('strength') |
4757
str('text') |
4858
str('title') |
59+
str('trash_ability') |
4960
str('trash_cost') |
5061
str('universal_faction_cost') |
5162
# Single letter 'short codes'

0 commit comments

Comments
 (0)