Skip to content

Commit 6118d67

Browse files
committed
2 parents 23e1c5f + b437e4a commit 6118d67

File tree

8 files changed

+149
-26
lines changed

8 files changed

+149
-26
lines changed

app/models/card.rb

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,30 @@ class Card < ApplicationRecord
1010
has_many :card_pool_cards
1111
has_many :card_pools, :through => :card_pool_cards
1212
has_many :restriction_card_banned
13-
has_many :restrictions, :through => :restriction_card_banned
14-
13+
has_many :restriction_card_global_penalty
14+
has_many :restriction_card_points, class_name: 'RestrictionCardPoints'
15+
has_many :restriction_card_restricted
16+
has_many :restriction_card_universal_faction_cost
17+
# This is here to support restrictions, but isn't usable on it's own.
1518
has_many :unified_restrictions
19+
# Will be all restrictions that directly reference this card in any way.
20+
has_many :restrictions, -> { where('unified_restrictions.in_restriction': true) }, :through => :unified_restrictions
1621

1722
validates :name, uniqueness: true
23+
24+
def advancement_requirement
25+
self[:advancement_requirement] == -1 ? 'X' : self[:advancement_requirement]
26+
end
27+
def link_provided
28+
self[:link_provided] == -1 ? 'X' : self[:link_provided]
29+
end
30+
def mu_provided
31+
self[:mu_provided] == -1 ? 'X' : self[:mu_provided]
32+
end
33+
def num_printed_subroutines
34+
self[:num_printed_subroutines] == -1 ? 'X' : self[:num_printed_subroutines]
35+
end
36+
def recurring_credits_provided
37+
self[:recurring_credits_provided] == -1 ? 'X' : self[:recurring_credits_provided]
38+
end
1839
end

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

Lines changed: 18 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
@@ -32,6 +48,7 @@ def latest_printing_id
3248
if query_builder.parse_error.nil?
3349
records.left_joins(query_builder.left_joins)
3450
.where(query_builder.where, *query_builder.where_values)
51+
.distinct
3552
else
3653
raise JSONAPI::Exceptions::BadRequest.new(
3754
'Invalid search query: [%s] / %s' % [value[0], query_builder.parse_error])

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

Lines changed: 19 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

@@ -88,6 +88,7 @@ class Api::V3::Public::PrintingResource < JSONAPI::Resource
8888
if query_builder.parse_error.nil?
8989
records.left_joins(query_builder.left_joins)
9090
.where(query_builder.where, *query_builder.where_values)
91+
.distinct
9192
else
9293
raise JSONAPI::Exceptions::BadRequest.new(
9394
'Invalid search query: [%s] / %s' % [value[0], query_builder.parse_error])
@@ -122,6 +123,21 @@ def agenda_points
122123
def base_link
123124
@model.card.base_link
124125
end
126+
def card_abilities
127+
{
128+
additional_cost: @model.card.additional_cost,
129+
advanceable: @model.card.advanceable,
130+
gains_subroutines: @model.card.gains_subroutines,
131+
interrupt: @model.card.interrupt,
132+
link_provided: @model.card.link_provided,
133+
mu_provided: @model.card.mu_provided,
134+
num_printed_subroutines: @model.card.num_printed_subroutines,
135+
on_encounter_effect: @model.card.on_encounter_effect,
136+
performs_trace: @model.card.performs_trace,
137+
recurring_credits_provided: @model.card.recurring_credits_provided,
138+
trash_ability: @model.card.trash_ability,
139+
}
140+
end
125141
def card_type_id
126142
@model.card.card_type_id
127143
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('has_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: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
11
class CardSearchQueryBuilder
22
@@parser = CardSearchParser.new
33
@@boolean_keywords = [
4+
'additional_cost',
5+
'advanceable',
46
'b',
57
'banlist',
8+
'gains_subroutines',
69
'has_global_penalty',
710
'in_restriction',
11+
'interrupt',
812
'is_banned',
913
'is_restricted',
1014
'is_unique',
15+
'on_encounter_effect',
16+
'performs_trace',
17+
'trash_ability',
1118
'u',
1219
]
1320
@@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',
78-
'has_global_penalty' => 'unified_restrictions.has_global_penalty',
91+
'gains_subroutines' => 'cards.gains_subroutines',
7992
'h' => 'cards.trash_cost',
93+
'has_global_penalty' => 'unified_restrictions.has_global_penalty',
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('has_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)