Skip to content

Commit fa4f774

Browse files
authored
Merge pull request #107 from plural/card_view
Replace Card Resource & API with a Unified Card backing view.
2 parents 3bfcd3d + d418f8b commit fa4f774

28 files changed

+909
-84
lines changed

app/models/card_card_subtype.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,7 @@ class CardCardSubtype < ApplicationRecord
99
belongs_to :card_subtype,
1010
:primary_key => :id,
1111
:foreign_key => :card_subtype_id
12-
end
12+
belongs_to :unified_card,
13+
:primary_key => :id,
14+
:foreign_key => :card_id
15+
end

app/models/card_cycle.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ class CardCycle < ApplicationRecord
44
has_many :card_sets
55
has_many :printings, :through => :card_sets
66
has_many :cards, :through => :printings
7+
has_many :unified_cards, :through => :printings
78
has_many :card_pool_card_cycles
89
has_many :card_pools, :through => :card_pool_card_cycles
910
end

app/models/card_pool.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ class CardPool < ApplicationRecord
77
has_many :card_sets, :through => :card_pool_card_sets
88
has_many :card_pool_cards
99
has_many :cards, :through => :card_pool_cards
10+
has_many :unified_cards, :through => :card_pool_cards, primary_key: :card_id, foreign_key: :id
1011
has_many :snapshots
1112

1213
belongs_to :format,

app/models/card_pool_card.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,7 @@ class CardPoolCard < ApplicationRecord
99
belongs_to :card_pool,
1010
:primary_key => :id,
1111
:foreign_key => :card_pool_id
12-
end
12+
belongs_to :unified_card,
13+
:primary_key => :id,
14+
:foreign_key => :card_id
15+
end

app/models/card_set.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ class CardSet < ApplicationRecord
66

77
has_many :printings
88
has_many :cards, :through => :printings
9+
has_many :unified_cards, :through => :printings
910
end

app/models/card_subtype.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ class CardSubtype < ApplicationRecord
44
has_many :card_card_subtypes
55
has_many :cards, :through => :card_card_subtypes
66
has_many :printings, :through => :cards
7+
has_many :unified_cards, :through => :card_card_subtypes, primary_key: :card_id, foreign_key: :id
78
end

app/models/card_type.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@
33
class CardType < ApplicationRecord
44
belongs_to :side
55
has_many :cards
6+
has_many :unified_cards
67
end

app/models/faction.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ class Faction < ApplicationRecord
44
belongs_to :side
55
has_many :cards
66
has_many :printings, :through => :cards
7+
has_many :unified_cards
78
end

app/models/printing.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
class Printing < ApplicationRecord
44
belongs_to :card
55
belongs_to :card_set
6+
belongs_to :unified_card, primary_key: :id, foreign_key: :card_id
67
has_one :faction, :through => :card
78
has_one :card_cycle, :through => :card_set
89
has_one :side, :through => :card

app/models/side.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@ class Side < ApplicationRecord
44
has_many :factions
55
has_many :card_types
66
has_many :cards
7+
has_many :unified_cards
78
has_many :printings, :through => :cards
89
end

app/models/snapshot.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ class Snapshot < ApplicationRecord
55
belongs_to :card_pool
66
belongs_to :restriction, optional: :true
77
has_many :cards, through: :card_pool
8+
has_many :unified_cards, through: :card_pool, primary_key: :card_id, foreign_key: :id
89
end

app/models/unified_card.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
class UnifiedCard < ApplicationRecord
2+
self.primary_key = :id
3+
end

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ class Api::V3::Public::CardCycleResource < JSONAPI::Resource
99

1010
has_many :card_sets
1111
has_many :printings
12-
has_many :cards
12+
13+
has_many :cards, relation_name: :unified_cards
1314

1415
paginator :none
1516
end

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class Api::V3::Public::CardPoolResource < JSONAPI::Resource
1414
has_one :format
1515
has_many :card_cycles
1616
has_many :card_sets
17-
has_many :cards
17+
has_many :cards, relation_name: :unified_cards
1818
has_many :snapshots
1919

2020
def num_cards

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

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@ module Public
44
class Api::V3::Public::CardResource < JSONAPI::Resource
55
immutable
66

7+
model_name 'UnifiedCard'
8+
79
attributes :stripped_title, :title, :card_type_id, :side_id, :faction_id
810
attributes :advancement_requirement, :agenda_points, :base_link, :cost
9-
attributes :deck_limit, :influence_cost, :influence_limit, :memory_cost
10-
attributes :minimum_deck_size, :strength, :stripped_text, :text, :trash_cost
11-
attributes :is_unique, :display_subtypes, :updated_at
12-
attributes :card_abilities, :latest_printing_id
11+
attributes :deck_limit, :in_restriction, :influence_cost, :influence_limit, :memory_cost
12+
attributes :minimum_deck_size, :latest_printing_id, :num_printings, :printing_ids, :restriction_ids, :restrictions, :strength, :stripped_text, :text, :trash_cost
13+
attributes :is_unique, :card_subtype_ids, :display_subtypes, :updated_at
14+
attributes :card_abilities, :format_ids, :card_pool_ids, :snapshot_ids
1315

1416
key_type :string
1517

@@ -20,7 +22,7 @@ class Api::V3::Public::CardResource < JSONAPI::Resource
2022
has_many :printings
2123

2224
def latest_printing_id
23-
@model.printings.max_by { |p| p.date_release } ['id']
25+
@model.printing_ids[0]
2426
end
2527

2628
def card_abilities
@@ -39,6 +41,25 @@ def card_abilities
3941
}
4042
end
4143

44+
def packed_restriction_to_map(packed)
45+
m = {}
46+
packed.each do |p|
47+
x = p.split('=')
48+
m[x[0]] = x[1].to_i
49+
end
50+
return m
51+
end
52+
53+
def restrictions
54+
{
55+
banned: @model.restrictions_banned,
56+
global_penalty: @model.restrictions_global_penalty,
57+
points: packed_restriction_to_map(@model.restrictions_points),
58+
restricted: @model.restrictions_restricted,
59+
universal_faction_cost: packed_restriction_to_map(@model.restrictions_universal_faction_cost)
60+
}
61+
end
62+
4263
filters :title, :card_type_id, :side_id, :faction_id, :advancement_requirement
4364
filters :agenda_points, :base_link, :cost, :deck_limit, :influence_cost
4465
filters :influence_limit, :memory_cost, :minimum_deck_size, :strength, :trash_cost, :is_unique

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class Api::V3::Public::CardSetResource < JSONAPI::Resource
1212
has_one :card_cycle
1313
has_one :card_set_type
1414
has_many :printings
15-
has_many :cards
15+
has_many :cards, relation_name: :unified_cards
1616

1717
filters :card_cycle_id, :card_set_type_id
1818
end

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ class Api::V3::Public::CardSubtypeResource < JSONAPI::Resource
99

1010
paginator :none
1111

12-
has_many :cards
12+
has_many :cards, relation_name: :unified_cards
1313
has_many :printings
1414
end
1515
end

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ class Api::V3::Public::CardTypeResource < JSONAPI::Resource
88
key_type :string
99

1010
has_one :side
11-
has_many :cards
11+
has_many :cards, relation_name: :unified_cards
1212
paginator :none
1313

1414
filter :side_id

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ class Api::V3::Public::FactionResource < JSONAPI::Resource
1010
paginator :none
1111

1212
has_one :side
13-
has_many :cards
13+
has_many :cards, relation_name: :unified_cards
1414
has_many :printings
1515

1616
filters :side_id, :is_mini

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ class Api::V3::Public::SideResource < JSONAPI::Resource
1111

1212
has_many :factions
1313
has_many :card_types
14-
has_many :cards
14+
has_many :cards, relation_name: :unified_cards
1515
has_many :printings
1616
end
1717
end

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class Api::V3::Public::SnapshotResource < JSONAPI::Resource
1515
has_one :card_pool
1616
has_one :restriction
1717

18-
has_many :cards
18+
has_many :cards, relation_name: :unified_cards
1919

2020
filters :active, :format_id
2121

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
class CreateUnifiedCards < ActiveRecord::Migration[7.0]
2+
def change
3+
create_view :unified_cards, materialized: true
4+
end
5+
end

db/schema.rb

Lines changed: 157 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#
1111
# It's strongly recommended that you check this file into your version control system.
1212

13-
ActiveRecord::Schema[7.0].define(version: 2022_09_25_225117) do
13+
ActiveRecord::Schema[7.0].define(version: 2022_09_26_010740) do
1414
# These are extensions that must be enabled in order to support this database
1515
enable_extension "plpgsql"
1616

@@ -320,4 +320,160 @@
320320
add_index "unified_restrictions", ["restriction_id"], name: "index_unified_restrictions_on_restriction_id"
321321
add_index "unified_restrictions", ["snapshot_id"], name: "index_unified_restrictions_on_snapshot_id"
322322

323+
create_view "unified_cards", materialized: true, sql_definition: <<-SQL
324+
WITH card_cycles_summary AS (
325+
SELECT c_1.id,
326+
array_agg(cc.id ORDER BY cc.id) AS card_cycle_ids,
327+
array_agg(lower(cc.name) ORDER BY (lower(cc.name))) AS card_cycle_names
328+
FROM (((cards c_1
329+
JOIN printings p_1 ON (((c_1.id)::text = p_1.card_id)))
330+
JOIN card_sets cs ON ((p_1.card_set_id = (cs.id)::text)))
331+
JOIN card_cycles cc ON (((cc.id)::text = cs.card_cycle_id)))
332+
GROUP BY c_1.id
333+
), card_sets_summary AS (
334+
SELECT c_1.id,
335+
array_agg(cs.id ORDER BY cs.id) AS card_set_ids,
336+
array_agg(lower(cs.name) ORDER BY (lower(cs.name))) AS card_set_names
337+
FROM ((cards c_1
338+
JOIN printings p_1 ON (((c_1.id)::text = p_1.card_id)))
339+
JOIN card_sets cs ON ((p_1.card_set_id = (cs.id)::text)))
340+
GROUP BY c_1.id
341+
), card_subtype_ids AS (
342+
SELECT cards_card_subtypes.card_id,
343+
array_agg(cards_card_subtypes.card_subtype_id ORDER BY 1::integer) AS card_subtype_ids
344+
FROM cards_card_subtypes
345+
GROUP BY cards_card_subtypes.card_id
346+
), card_subtype_names AS (
347+
SELECT ccs_1.card_id,
348+
array_agg(lower(cs.name) ORDER BY (lower(cs.name))) AS lower_card_subtype_names,
349+
array_agg(cs.name ORDER BY cs.name) AS card_subtype_names
350+
FROM (cards_card_subtypes ccs_1
351+
JOIN card_subtypes cs ON ((ccs_1.card_subtype_id = (cs.id)::text)))
352+
GROUP BY ccs_1.card_id
353+
), card_printing_ids AS (
354+
SELECT printings.card_id,
355+
array_agg(printings.id ORDER BY printings.date_release DESC) AS printing_ids
356+
FROM printings
357+
GROUP BY printings.card_id
358+
), card_restriction_ids AS (
359+
SELECT unified_restrictions.card_id,
360+
array_agg(unified_restrictions.restriction_id ORDER BY unified_restrictions.restriction_id) AS restriction_ids
361+
FROM unified_restrictions
362+
WHERE unified_restrictions.in_restriction
363+
GROUP BY unified_restrictions.card_id
364+
), restrictions_banned_summary AS (
365+
SELECT restrictions_cards_banned.card_id,
366+
array_agg(restrictions_cards_banned.restriction_id ORDER BY restrictions_cards_banned.restriction_id) AS restrictions_banned
367+
FROM restrictions_cards_banned
368+
GROUP BY restrictions_cards_banned.card_id
369+
), restrictions_global_penalty_summary AS (
370+
SELECT restrictions_cards_global_penalty.card_id,
371+
array_agg(restrictions_cards_global_penalty.restriction_id ORDER BY restrictions_cards_global_penalty.restriction_id) AS restrictions_global_penalty
372+
FROM restrictions_cards_global_penalty
373+
GROUP BY restrictions_cards_global_penalty.card_id
374+
), restrictions_points_summary AS (
375+
SELECT restrictions_cards_points.card_id,
376+
array_agg(concat(restrictions_cards_points.restriction_id, '=', (restrictions_cards_points.value)::text) ORDER BY (concat(restrictions_cards_points.restriction_id, '=', (restrictions_cards_points.value)::text))) AS restrictions_points
377+
FROM restrictions_cards_points
378+
GROUP BY restrictions_cards_points.card_id
379+
), restrictions_restricted_summary AS (
380+
SELECT restrictions_cards_restricted.card_id,
381+
array_agg(restrictions_cards_restricted.restriction_id ORDER BY restrictions_cards_restricted.restriction_id) AS restrictions_restricted
382+
FROM restrictions_cards_restricted
383+
GROUP BY restrictions_cards_restricted.card_id
384+
), restrictions_universal_faction_cost_summary AS (
385+
SELECT restrictions_cards_universal_faction_cost.card_id,
386+
array_agg(concat(restrictions_cards_universal_faction_cost.restriction_id, '=', (restrictions_cards_universal_faction_cost.value)::text) ORDER BY (concat(restrictions_cards_universal_faction_cost.restriction_id, '=', (restrictions_cards_universal_faction_cost.value)::text))) AS restrictions_universal_faction_cost
387+
FROM restrictions_cards_universal_faction_cost
388+
GROUP BY restrictions_cards_universal_faction_cost.card_id
389+
), format_ids AS (
390+
SELECT cpc_1.card_id,
391+
array_agg(DISTINCT s_1.format_id ORDER BY s_1.format_id) AS format_ids
392+
FROM (card_pools_cards cpc_1
393+
JOIN snapshots s_1 ON ((cpc_1.card_pool_id = s_1.card_pool_id)))
394+
GROUP BY cpc_1.card_id
395+
), card_pool_ids AS (
396+
SELECT cpc_1.card_id,
397+
array_agg(DISTINCT s_1.card_pool_id ORDER BY s_1.card_pool_id) AS card_pool_ids
398+
FROM (card_pools_cards cpc_1
399+
JOIN snapshots s_1 ON ((cpc_1.card_pool_id = s_1.card_pool_id)))
400+
GROUP BY cpc_1.card_id
401+
), snapshot_ids AS (
402+
SELECT cpc_1.card_id,
403+
array_agg(DISTINCT s_1.id ORDER BY s_1.id) AS snapshot_ids
404+
FROM (card_pools_cards cpc_1
405+
JOIN snapshots s_1 ON ((cpc_1.card_pool_id = s_1.card_pool_id)))
406+
GROUP BY cpc_1.card_id
407+
)
408+
SELECT c.id,
409+
c.title,
410+
c.stripped_title,
411+
c.card_type_id,
412+
c.side_id,
413+
c.faction_id,
414+
c.advancement_requirement,
415+
c.agenda_points,
416+
c.base_link,
417+
c.cost,
418+
c.deck_limit,
419+
c.influence_cost,
420+
c.influence_limit,
421+
c.memory_cost,
422+
c.minimum_deck_size,
423+
c.strength,
424+
c.stripped_text,
425+
c.text,
426+
c.trash_cost,
427+
c.is_unique,
428+
c.display_subtypes,
429+
c.created_at,
430+
c.updated_at,
431+
c.additional_cost,
432+
c.advanceable,
433+
c.gains_subroutines,
434+
c.interrupt,
435+
c.link_provided,
436+
c.mu_provided,
437+
c.num_printed_subroutines,
438+
c.on_encounter_effect,
439+
c.performs_trace,
440+
c.recurring_credits_provided,
441+
c.rez_effect,
442+
c.trash_ability,
443+
COALESCE(csi.card_subtype_ids, ARRAY[]::text[]) AS card_subtype_ids,
444+
COALESCE(csn.lower_card_subtype_names, ARRAY[]::text[]) AS lower_card_subtype_names,
445+
COALESCE(csn.card_subtype_names, ARRAY[]::text[]) AS card_subtype_names,
446+
p.printing_ids,
447+
array_length(p.printing_ids, 1) AS num_printings,
448+
ccs.card_cycle_ids,
449+
ccs.card_cycle_names,
450+
css.card_set_ids,
451+
css.card_set_names,
452+
COALESCE(r.restriction_ids, (ARRAY[]::text[])::character varying[]) AS restriction_ids,
453+
(r.restriction_ids IS NOT NULL) AS in_restriction,
454+
COALESCE(r_b.restrictions_banned, ARRAY[]::text[]) AS restrictions_banned,
455+
COALESCE(r_g_p.restrictions_global_penalty, ARRAY[]::text[]) AS restrictions_global_penalty,
456+
COALESCE(r_p.restrictions_points, ARRAY[]::text[]) AS restrictions_points,
457+
COALESCE(r_r.restrictions_restricted, ARRAY[]::text[]) AS restrictions_restricted,
458+
COALESCE(r_u_f_c.restrictions_universal_faction_cost, ARRAY[]::text[]) AS restrictions_universal_faction_cost,
459+
COALESCE(f.format_ids, ARRAY[]::text[]) AS format_ids,
460+
COALESCE(cpc.card_pool_ids, ARRAY[]::text[]) AS card_pool_ids,
461+
COALESCE(s.snapshot_ids, (ARRAY[]::text[])::character varying[]) AS snapshot_ids
462+
FROM ((((((((((((((cards c
463+
JOIN card_printing_ids p ON (((c.id)::text = p.card_id)))
464+
JOIN card_cycles_summary ccs ON (((c.id)::text = (ccs.id)::text)))
465+
JOIN card_sets_summary css ON (((c.id)::text = (css.id)::text)))
466+
LEFT JOIN card_subtype_ids csi ON (((c.id)::text = csi.card_id)))
467+
LEFT JOIN card_subtype_names csn ON (((c.id)::text = csn.card_id)))
468+
LEFT JOIN card_restriction_ids r ON (((c.id)::text = (r.card_id)::text)))
469+
LEFT JOIN restrictions_banned_summary r_b ON (((c.id)::text = r_b.card_id)))
470+
LEFT JOIN restrictions_global_penalty_summary r_g_p ON (((c.id)::text = r_g_p.card_id)))
471+
LEFT JOIN restrictions_points_summary r_p ON (((c.id)::text = r_p.card_id)))
472+
LEFT JOIN restrictions_restricted_summary r_r ON (((c.id)::text = r_r.card_id)))
473+
LEFT JOIN restrictions_universal_faction_cost_summary r_u_f_c ON (((c.id)::text = r_u_f_c.card_id)))
474+
LEFT JOIN format_ids f ON (((c.id)::text = f.card_id)))
475+
LEFT JOIN card_pool_ids cpc ON (((c.id)::text = cpc.card_id)))
476+
LEFT JOIN snapshot_ids s ON (((c.id)::text = s.card_id)))
477+
GROUP BY c.id, c.title, c.stripped_title, c.card_type_id, c.side_id, c.faction_id, c.advancement_requirement, c.agenda_points, c.base_link, c.cost, c.deck_limit, c.influence_cost, c.influence_limit, c.memory_cost, c.minimum_deck_size, c.strength, c.stripped_text, c.text, c.trash_cost, c.is_unique, c.display_subtypes, c.created_at, c.updated_at, c.additional_cost, c.advanceable, c.gains_subroutines, c.interrupt, c.link_provided, c.mu_provided, c.num_printed_subroutines, c.on_encounter_effect, c.performs_trace, c.recurring_credits_provided, c.rez_effect, c.trash_ability, csi.card_subtype_ids, csn.lower_card_subtype_names, csn.card_subtype_names, p.printing_ids, ccs.card_cycle_ids, ccs.card_cycle_names, css.card_set_ids, css.card_set_names, r.restriction_ids, r_b.restrictions_banned, r_g_p.restrictions_global_penalty, r_p.restrictions_points, r_r.restrictions_restricted, r_u_f_c.restrictions_universal_faction_cost, f.format_ids, cpc.card_pool_ids, s.snapshot_ids;
478+
SQL
323479
end

0 commit comments

Comments
 (0)