From 5be020fef230ac4532768310be480ea647e9c492 Mon Sep 17 00:00:00 2001 From: Jason Gessner Date: Mon, 30 Dec 2024 06:43:30 +0000 Subject: [PATCH 1/2] Add basic import and storage for card face info. --- app/models/card_face.rb | 7 + app/models/card_face_card_subtype.rb | 11 + .../20241230053539_add_layout_id_to_cards.rb | 5 + .../20241230055434_create_card_faces.rb | 15 + ...0055711_create_card_faces_card_subtypes.rb | 9 + db/schema.rb | 318 ++++++++++-------- lib/tasks/cards.rake | 79 ++++- 7 files changed, 292 insertions(+), 152 deletions(-) create mode 100644 app/models/card_face.rb create mode 100644 app/models/card_face_card_subtype.rb create mode 100644 db/migrate/20241230053539_add_layout_id_to_cards.rb create mode 100644 db/migrate/20241230055434_create_card_faces.rb create mode 100644 db/migrate/20241230055711_create_card_faces_card_subtypes.rb diff --git a/app/models/card_face.rb b/app/models/card_face.rb new file mode 100644 index 0000000..bbaa326 --- /dev/null +++ b/app/models/card_face.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class CardFace < ApplicationRecord + belongs_to :card + has_many :card_face_card_subtypes + has_many :card_subtypes, through: :card_face_card_subtypes +end diff --git a/app/models/card_face_card_subtype.rb b/app/models/card_face_card_subtype.rb new file mode 100644 index 0000000..912fda7 --- /dev/null +++ b/app/models/card_face_card_subtype.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class CardFaceCardSubtype < ApplicationRecord + self.table_name = 'card_faces_card_subtypes' + + belongs_to :card_face, + primary_key: %i[card_id face_index], + query_constraints: %i[card_id face_index] + belongs_to :card_subtype, + primary_key: :id +end diff --git a/db/migrate/20241230053539_add_layout_id_to_cards.rb b/db/migrate/20241230053539_add_layout_id_to_cards.rb new file mode 100644 index 0000000..de38031 --- /dev/null +++ b/db/migrate/20241230053539_add_layout_id_to_cards.rb @@ -0,0 +1,5 @@ +class AddLayoutIdToCards < ActiveRecord::Migration[7.1] + def change + add_column :cards, :layout_id, :string, default: 'normal', null: false + end +end diff --git a/db/migrate/20241230055434_create_card_faces.rb b/db/migrate/20241230055434_create_card_faces.rb new file mode 100644 index 0000000..f6ba1fe --- /dev/null +++ b/db/migrate/20241230055434_create_card_faces.rb @@ -0,0 +1,15 @@ +class CreateCardFaces < ActiveRecord::Migration[7.1] + def change + create_table :card_faces, primary_key: %i[card_id face_index] do |t| + t.string :card_id, null: false + t.integer :face_index, null: false + t.text :base_link + t.text :display_subtypes + t.text :stripped_text + t.text :stripped_title + t.text :text + t.text :title + t.timestamps + end + end +end diff --git a/db/migrate/20241230055711_create_card_faces_card_subtypes.rb b/db/migrate/20241230055711_create_card_faces_card_subtypes.rb new file mode 100644 index 0000000..b735c0d --- /dev/null +++ b/db/migrate/20241230055711_create_card_faces_card_subtypes.rb @@ -0,0 +1,9 @@ +class CreateCardFacesCardSubtypes < ActiveRecord::Migration[7.1] + def change + create_table :card_faces_card_subtypes, id: false do |t| + t.string :card_id, null: false + t.integer :face_index, null: false + t.string :card_subtype_id + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 757b384..bba6f4d 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2024_10_26_035831) do +ActiveRecord::Schema[7.1].define(version: 2024_12_30_055711) do # These are extensions that must be enabled in order to support this database enable_extension "pgcrypto" enable_extension "plpgsql" @@ -26,6 +26,25 @@ t.integer "position" end + create_table "card_faces", primary_key: ["card_id", "face_index"], force: :cascade do |t| + t.string "card_id", null: false + t.integer "face_index", null: false + t.text "base_link" + t.text "display_subtypes" + t.text "stripped_text" + t.text "stripped_title" + t.text "text" + t.text "title" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + create_table "card_faces_card_subtypes", id: false, force: :cascade do |t| + t.string "card_id", null: false + t.integer "face_index", null: false + t.string "card_subtype_id" + end + create_table "card_pools", id: :string, force: :cascade do |t| t.text "name", null: false t.text "format_id", null: false @@ -124,6 +143,7 @@ t.string "pronouns" t.string "pronunciation_approximation" t.string "pronunciation_ipa" + t.string "layout_id", default: "normal", null: false t.index ["card_type_id"], name: "index_cards_on_card_type_id" t.index ["faction_id"], name: "index_cards_on_faction_id" t.index ["side_id"], name: "index_cards_on_side_id" @@ -435,23 +455,28 @@ add_index "unified_restrictions", ["restriction_id"], name: "index_unified_restrictions_on_restriction_id" add_index "unified_restrictions", ["snapshot_id"], name: "index_unified_restrictions_on_snapshot_id" - create_view "unified_printings", materialized: true, sql_definition: <<-SQL + create_view "unified_cards", materialized: true, sql_definition: <<-SQL WITH card_cycles_summary AS ( SELECT c_1.id, - array_agg(cc_1.id ORDER BY cc_1.date_release DESC) AS card_cycle_ids, - array_agg(cc_1.name ORDER BY cc_1.date_release DESC) AS card_cycle_names + array_agg(cc.id ORDER BY cc.date_release DESC) AS card_cycle_ids, + array_agg(cc.name ORDER BY cc.date_release DESC) AS card_cycle_names FROM (((cards c_1 JOIN printings p_1 ON (((c_1.id)::text = p_1.card_id))) - JOIN card_sets cs_1 ON ((p_1.card_set_id = (cs_1.id)::text))) - JOIN card_cycles cc_1 ON (((cc_1.id)::text = cs_1.card_cycle_id))) + JOIN card_sets cs ON ((p_1.card_set_id = (cs.id)::text))) + JOIN card_cycles cc ON (((cc.id)::text = cs.card_cycle_id))) GROUP BY c_1.id + ), printing_releasers AS ( + SELECT printings.card_id, + array_agg(DISTINCT printings.released_by ORDER BY printings.released_by) AS releasers + FROM printings + GROUP BY printings.card_id ), card_sets_summary AS ( SELECT c_1.id, - array_agg(cs_1.id ORDER BY cs_1.date_release DESC) AS card_set_ids, - array_agg(cs_1.name ORDER BY cs_1.date_release DESC) AS card_set_names + array_agg(cs.id ORDER BY cs.date_release DESC) AS card_set_ids, + array_agg(cs.name ORDER BY cs.date_release DESC) AS card_set_names FROM ((cards c_1 JOIN printings p_1 ON (((c_1.id)::text = p_1.card_id))) - JOIN card_sets cs_1 ON ((p_1.card_set_id = (cs_1.id)::text))) + JOIN card_sets cs ON ((p_1.card_set_id = (cs.id)::text))) GROUP BY c_1.id ), card_subtype_ids AS ( SELECT cards_card_subtypes.card_id, @@ -460,28 +485,21 @@ GROUP BY cards_card_subtypes.card_id ), card_subtype_names AS ( SELECT ccs_1.card_id, - array_agg(lower(cs_1.name) ORDER BY (lower(cs_1.name))) AS lower_card_subtype_names, - array_agg(cs_1.name ORDER BY cs_1.name) AS card_subtype_names + array_agg(lower(cs.name) ORDER BY (lower(cs.name))) AS lower_card_subtype_names, + array_agg(cs.name ORDER BY cs.name) AS card_subtype_names FROM (cards_card_subtypes ccs_1 - JOIN card_subtypes cs_1 ON ((ccs_1.card_subtype_id = (cs_1.id)::text))) + JOIN card_subtypes cs ON ((ccs_1.card_subtype_id = (cs.id)::text))) GROUP BY ccs_1.card_id ), card_printing_ids AS ( SELECT printings.card_id, array_agg(printings.id ORDER BY printings.date_release DESC) AS printing_ids FROM printings GROUP BY printings.card_id - ), printing_releasers AS ( + ), card_release_dates AS ( SELECT printings.card_id, - array_agg(DISTINCT printings.released_by ORDER BY printings.released_by) AS releasers + min(printings.date_release) AS date_release FROM printings GROUP BY printings.card_id - ), illustrators AS ( - SELECT ip.printing_id, - array_agg(ip.illustrator_id ORDER BY ip.illustrator_id) AS illustrator_ids, - array_agg(i_1.name ORDER BY i_1.name) AS illustrator_names - FROM (illustrators_printings ip - JOIN public.illustrators i_1 ON (((ip.illustrator_id)::text = (i_1.id)::text))) - GROUP BY ip.printing_id ), card_restriction_ids AS ( SELECT unified_restrictions.card_id, array_agg(unified_restrictions.restriction_id ORDER BY unified_restrictions.restriction_id) AS restriction_ids @@ -532,60 +550,54 @@ JOIN snapshots s_1 ON ((cpc_1.card_pool_id = s_1.card_pool_id))) GROUP BY cpc_1.card_id ) - SELECT p.id, - p.card_id, - cc.id AS card_cycle_id, - cc.name AS card_cycle_name, - p.card_set_id, - cs.name AS card_set_name, - p.flavor, - p.display_illustrators, - p."position", - p.position_in_set, - p.quantity, - p.date_release, - p.created_at, - p.updated_at, - c.additional_cost, - c.advanceable, + SELECT 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.card_type_id, c.cost, - c.faction_id, - c.gains_subroutines, + c.deck_limit, c.influence_cost, - c.interrupt, + c.influence_limit, + c.memory_cost, + c.minimum_deck_size, + c.pronouns, + c.pronunciation_approximation, + c.pronunciation_ipa, + c.strength, + c.stripped_text, + c.text, + c.trash_cost, c.is_unique, + c.display_subtypes, + c.attribution, + c.created_at, + c.updated_at, + c.additional_cost, + c.advanceable, + c.gains_subroutines, + c.interrupt, c.link_provided, - c.memory_cost, c.mu_provided, c.num_printed_subroutines, c.on_encounter_effect, c.performs_trace, - c.pronouns, - c.pronunciation_approximation, - c.pronunciation_ipa, c.recurring_credits_provided, - c.side_id, - c.strength, - c.stripped_text, - c.stripped_title, + c.rez_effect, c.trash_ability, - c.trash_cost, COALESCE(csi.card_subtype_ids, ARRAY[]::text[]) AS card_subtype_ids, COALESCE(csn.lower_card_subtype_names, ARRAY[]::text[]) AS lower_card_subtype_names, COALESCE(csn.card_subtype_names, ARRAY[]::text[]) AS card_subtype_names, - cp.printing_ids, - ((p.id)::text = (cp.printing_ids[1])::text) AS is_latest_printing, - array_length(cp.printing_ids, 1) AS num_printings, - COALESCE(ccs.card_cycle_ids, (ARRAY[]::text[])::character varying[]) AS card_cycle_ids, - COALESCE(ccs.card_cycle_names, ARRAY[]::text[]) AS card_cycle_names, - COALESCE(css.card_set_ids, (ARRAY[]::text[])::character varying[]) AS card_set_ids, - COALESCE(css.card_set_names, ARRAY[]::text[]) AS card_set_names, - COALESCE(i.illustrator_ids, (ARRAY[]::text[])::character varying[]) AS illustrator_ids, - COALESCE(i.illustrator_names, (ARRAY[]::text[])::character varying[]) AS illustrator_names, + p.printing_ids, + array_length(p.printing_ids, 1) AS num_printings, + ccs.card_cycle_ids, + ccs.card_cycle_names, + css.card_set_ids, + css.card_set_names, COALESCE(r.restriction_ids, (ARRAY[]::text[])::character varying[]) AS restriction_ids, (r.restriction_ids IS NOT NULL) AS in_restriction, COALESCE(r_b.restrictions_banned, ARRAY[]::text[]) AS restrictions_banned, @@ -596,60 +608,45 @@ COALESCE(f.format_ids, ARRAY[]::text[]) AS format_ids, COALESCE(cpc.card_pool_ids, ARRAY[]::text[]) AS card_pool_ids, COALESCE(s.snapshot_ids, (ARRAY[]::text[])::character varying[]) AS snapshot_ids, - c.attribution, - c.deck_limit, - c.display_subtypes, - c.influence_limit, - c.minimum_deck_size, - c.rez_effect, - c.text, - c.title, + crd.date_release, c.designed_by, - p.released_by, pr.releasers AS printings_released_by - FROM (((((((((((((((((((printings p - JOIN cards c ON ((p.card_id = (c.id)::text))) + FROM ((((((((((((((((cards c + JOIN card_printing_ids p ON (((c.id)::text = p.card_id))) JOIN card_cycles_summary ccs ON (((c.id)::text = (ccs.id)::text))) JOIN card_sets_summary css ON (((c.id)::text = (css.id)::text))) - JOIN card_sets cs ON ((p.card_set_id = (cs.id)::text))) - JOIN card_cycles cc ON ((cs.card_cycle_id = (cc.id)::text))) + JOIN printing_releasers pr ON (((c.id)::text = pr.card_id))) LEFT JOIN card_subtype_ids csi ON (((c.id)::text = csi.card_id))) LEFT JOIN card_subtype_names csn ON (((c.id)::text = csn.card_id))) - JOIN card_printing_ids cp ON ((p.card_id = cp.card_id))) - JOIN printing_releasers pr ON ((p.card_id = pr.card_id))) - LEFT JOIN illustrators i ON (((p.id)::text = (i.printing_id)::text))) - LEFT JOIN card_restriction_ids r ON ((p.card_id = (r.card_id)::text))) - LEFT JOIN restrictions_banned_summary r_b ON ((p.card_id = r_b.card_id))) - LEFT JOIN restrictions_global_penalty_summary r_g_p ON ((p.card_id = r_g_p.card_id))) - LEFT JOIN restrictions_points_summary r_p ON ((p.card_id = r_p.card_id))) - LEFT JOIN restrictions_restricted_summary r_r ON ((p.card_id = r_r.card_id))) - LEFT JOIN restrictions_universal_faction_cost_summary r_u_f_c ON ((p.card_id = r_u_f_c.card_id))) - LEFT JOIN format_ids f ON ((p.card_id = f.card_id))) - LEFT JOIN card_pool_ids cpc ON ((p.card_id = cpc.card_id))) - LEFT JOIN snapshot_ids s ON ((p.card_id = s.card_id))); + LEFT JOIN card_restriction_ids r ON (((c.id)::text = (r.card_id)::text))) + LEFT JOIN restrictions_banned_summary r_b ON (((c.id)::text = r_b.card_id))) + LEFT JOIN restrictions_global_penalty_summary r_g_p ON (((c.id)::text = r_g_p.card_id))) + LEFT JOIN restrictions_points_summary r_p ON (((c.id)::text = r_p.card_id))) + LEFT JOIN restrictions_restricted_summary r_r ON (((c.id)::text = r_r.card_id))) + LEFT JOIN restrictions_universal_faction_cost_summary r_u_f_c ON (((c.id)::text = r_u_f_c.card_id))) + LEFT JOIN format_ids f ON (((c.id)::text = f.card_id))) + LEFT JOIN card_pool_ids cpc ON (((c.id)::text = cpc.card_id))) + LEFT JOIN snapshot_ids s ON (((c.id)::text = s.card_id))) + LEFT JOIN card_release_dates crd ON (((c.id)::text = crd.card_id))) + 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.attribution, 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, crd.date_release, pr.releasers; SQL - create_view "unified_cards", materialized: true, sql_definition: <<-SQL + create_view "unified_printings", materialized: true, sql_definition: <<-SQL WITH card_cycles_summary AS ( SELECT c_1.id, - array_agg(cc.id ORDER BY cc.date_release DESC) AS card_cycle_ids, - array_agg(cc.name ORDER BY cc.date_release DESC) AS card_cycle_names + array_agg(cc_1.id ORDER BY cc_1.date_release DESC) AS card_cycle_ids, + array_agg(cc_1.name ORDER BY cc_1.date_release DESC) AS card_cycle_names FROM (((cards c_1 JOIN printings p_1 ON (((c_1.id)::text = p_1.card_id))) - JOIN card_sets cs ON ((p_1.card_set_id = (cs.id)::text))) - JOIN card_cycles cc ON (((cc.id)::text = cs.card_cycle_id))) + JOIN card_sets cs_1 ON ((p_1.card_set_id = (cs_1.id)::text))) + JOIN card_cycles cc_1 ON (((cc_1.id)::text = cs_1.card_cycle_id))) GROUP BY c_1.id - ), printing_releasers AS ( - SELECT printings.card_id, - array_agg(DISTINCT printings.released_by ORDER BY printings.released_by) AS releasers - FROM printings - GROUP BY printings.card_id ), card_sets_summary AS ( SELECT c_1.id, - array_agg(cs.id ORDER BY cs.date_release DESC) AS card_set_ids, - array_agg(cs.name ORDER BY cs.date_release DESC) AS card_set_names + array_agg(cs_1.id ORDER BY cs_1.date_release DESC) AS card_set_ids, + array_agg(cs_1.name ORDER BY cs_1.date_release DESC) AS card_set_names FROM ((cards c_1 JOIN printings p_1 ON (((c_1.id)::text = p_1.card_id))) - JOIN card_sets cs ON ((p_1.card_set_id = (cs.id)::text))) + JOIN card_sets cs_1 ON ((p_1.card_set_id = (cs_1.id)::text))) GROUP BY c_1.id ), card_subtype_ids AS ( SELECT cards_card_subtypes.card_id, @@ -658,21 +655,28 @@ GROUP BY cards_card_subtypes.card_id ), card_subtype_names AS ( SELECT ccs_1.card_id, - array_agg(lower(cs.name) ORDER BY (lower(cs.name))) AS lower_card_subtype_names, - array_agg(cs.name ORDER BY cs.name) AS card_subtype_names + array_agg(lower(cs_1.name) ORDER BY (lower(cs_1.name))) AS lower_card_subtype_names, + array_agg(cs_1.name ORDER BY cs_1.name) AS card_subtype_names FROM (cards_card_subtypes ccs_1 - JOIN card_subtypes cs ON ((ccs_1.card_subtype_id = (cs.id)::text))) + JOIN card_subtypes cs_1 ON ((ccs_1.card_subtype_id = (cs_1.id)::text))) GROUP BY ccs_1.card_id ), card_printing_ids AS ( SELECT printings.card_id, array_agg(printings.id ORDER BY printings.date_release DESC) AS printing_ids FROM printings GROUP BY printings.card_id - ), card_release_dates AS ( + ), printing_releasers AS ( SELECT printings.card_id, - min(printings.date_release) AS date_release + array_agg(DISTINCT printings.released_by ORDER BY printings.released_by) AS releasers FROM printings GROUP BY printings.card_id + ), illustrators AS ( + SELECT ip.printing_id, + array_agg(ip.illustrator_id ORDER BY ip.illustrator_id) AS illustrator_ids, + array_agg(i_1.name ORDER BY i_1.name) AS illustrator_names + FROM (illustrators_printings ip + JOIN public.illustrators i_1 ON (((ip.illustrator_id)::text = (i_1.id)::text))) + GROUP BY ip.printing_id ), card_restriction_ids AS ( SELECT unified_restrictions.card_id, array_agg(unified_restrictions.restriction_id ORDER BY unified_restrictions.restriction_id) AS restriction_ids @@ -723,54 +727,60 @@ JOIN snapshots s_1 ON ((cpc_1.card_pool_id = s_1.card_pool_id))) GROUP BY cpc_1.card_id ) - SELECT c.id, - c.title, - c.stripped_title, - c.card_type_id, - c.side_id, - c.faction_id, + SELECT p.id, + p.card_id, + cc.id AS card_cycle_id, + cc.name AS card_cycle_name, + p.card_set_id, + cs.name AS card_set_name, + p.flavor, + p.display_illustrators, + p."position", + p.position_in_set, + p.quantity, + p.date_release, + p.created_at, + p.updated_at, + c.additional_cost, + c.advanceable, c.advancement_requirement, c.agenda_points, c.base_link, + c.card_type_id, c.cost, - c.deck_limit, - c.influence_cost, - c.influence_limit, - c.memory_cost, - c.minimum_deck_size, - c.pronouns, - c.pronunciation_approximation, - c.pronunciation_ipa, - c.strength, - c.stripped_text, - c.text, - c.trash_cost, - c.is_unique, - c.display_subtypes, - c.attribution, - c.created_at, - c.updated_at, - c.additional_cost, - c.advanceable, + c.faction_id, c.gains_subroutines, + c.influence_cost, c.interrupt, + c.is_unique, c.link_provided, + c.memory_cost, c.mu_provided, c.num_printed_subroutines, c.on_encounter_effect, c.performs_trace, + c.pronouns, + c.pronunciation_approximation, + c.pronunciation_ipa, c.recurring_credits_provided, - c.rez_effect, + c.side_id, + c.strength, + c.stripped_text, + c.stripped_title, c.trash_ability, + c.trash_cost, COALESCE(csi.card_subtype_ids, ARRAY[]::text[]) AS card_subtype_ids, COALESCE(csn.lower_card_subtype_names, ARRAY[]::text[]) AS lower_card_subtype_names, COALESCE(csn.card_subtype_names, ARRAY[]::text[]) AS card_subtype_names, - p.printing_ids, - array_length(p.printing_ids, 1) AS num_printings, - ccs.card_cycle_ids, - ccs.card_cycle_names, - css.card_set_ids, - css.card_set_names, + cp.printing_ids, + ((p.id)::text = (cp.printing_ids[1])::text) AS is_latest_printing, + array_length(cp.printing_ids, 1) AS num_printings, + COALESCE(ccs.card_cycle_ids, (ARRAY[]::text[])::character varying[]) AS card_cycle_ids, + COALESCE(ccs.card_cycle_names, ARRAY[]::text[]) AS card_cycle_names, + COALESCE(css.card_set_ids, (ARRAY[]::text[])::character varying[]) AS card_set_ids, + COALESCE(css.card_set_names, ARRAY[]::text[]) AS card_set_names, + COALESCE(i.illustrator_ids, (ARRAY[]::text[])::character varying[]) AS illustrator_ids, + COALESCE(i.illustrator_names, (ARRAY[]::text[])::character varying[]) AS illustrator_names, COALESCE(r.restriction_ids, (ARRAY[]::text[])::character varying[]) AS restriction_ids, (r.restriction_ids IS NOT NULL) AS in_restriction, COALESCE(r_b.restrictions_banned, ARRAY[]::text[]) AS restrictions_banned, @@ -781,26 +791,36 @@ COALESCE(f.format_ids, ARRAY[]::text[]) AS format_ids, COALESCE(cpc.card_pool_ids, ARRAY[]::text[]) AS card_pool_ids, COALESCE(s.snapshot_ids, (ARRAY[]::text[])::character varying[]) AS snapshot_ids, - crd.date_release, + c.attribution, + c.deck_limit, + c.display_subtypes, + c.influence_limit, + c.minimum_deck_size, + c.rez_effect, + c.text, + c.title, c.designed_by, + p.released_by, pr.releasers AS printings_released_by - FROM ((((((((((((((((cards c - JOIN card_printing_ids p ON (((c.id)::text = p.card_id))) + FROM (((((((((((((((((((printings p + JOIN cards c ON ((p.card_id = (c.id)::text))) JOIN card_cycles_summary ccs ON (((c.id)::text = (ccs.id)::text))) JOIN card_sets_summary css ON (((c.id)::text = (css.id)::text))) - JOIN printing_releasers pr ON (((c.id)::text = pr.card_id))) + JOIN card_sets cs ON ((p.card_set_id = (cs.id)::text))) + JOIN card_cycles cc ON ((cs.card_cycle_id = (cc.id)::text))) LEFT JOIN card_subtype_ids csi ON (((c.id)::text = csi.card_id))) LEFT JOIN card_subtype_names csn ON (((c.id)::text = csn.card_id))) - LEFT JOIN card_restriction_ids r ON (((c.id)::text = (r.card_id)::text))) - LEFT JOIN restrictions_banned_summary r_b ON (((c.id)::text = r_b.card_id))) - LEFT JOIN restrictions_global_penalty_summary r_g_p ON (((c.id)::text = r_g_p.card_id))) - LEFT JOIN restrictions_points_summary r_p ON (((c.id)::text = r_p.card_id))) - LEFT JOIN restrictions_restricted_summary r_r ON (((c.id)::text = r_r.card_id))) - LEFT JOIN restrictions_universal_faction_cost_summary r_u_f_c ON (((c.id)::text = r_u_f_c.card_id))) - LEFT JOIN format_ids f ON (((c.id)::text = f.card_id))) - LEFT JOIN card_pool_ids cpc ON (((c.id)::text = cpc.card_id))) - LEFT JOIN snapshot_ids s ON (((c.id)::text = s.card_id))) - LEFT JOIN card_release_dates crd ON (((c.id)::text = crd.card_id))) - 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.attribution, 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, crd.date_release, pr.releasers; + JOIN card_printing_ids cp ON ((p.card_id = cp.card_id))) + JOIN printing_releasers pr ON ((p.card_id = pr.card_id))) + LEFT JOIN illustrators i ON (((p.id)::text = (i.printing_id)::text))) + LEFT JOIN card_restriction_ids r ON ((p.card_id = (r.card_id)::text))) + LEFT JOIN restrictions_banned_summary r_b ON ((p.card_id = r_b.card_id))) + LEFT JOIN restrictions_global_penalty_summary r_g_p ON ((p.card_id = r_g_p.card_id))) + LEFT JOIN restrictions_points_summary r_p ON ((p.card_id = r_p.card_id))) + LEFT JOIN restrictions_restricted_summary r_r ON ((p.card_id = r_r.card_id))) + LEFT JOIN restrictions_universal_faction_cost_summary r_u_f_c ON ((p.card_id = r_u_f_c.card_id))) + LEFT JOIN format_ids f ON ((p.card_id = f.card_id))) + LEFT JOIN card_pool_ids cpc ON ((p.card_id = cpc.card_id))) + LEFT JOIN snapshot_ids s ON ((p.card_id = s.card_id))); SQL end diff --git a/lib/tasks/cards.rake b/lib/tasks/cards.rake index ff0b0d5..738abe9 100644 --- a/lib/tasks/cards.rake +++ b/lib/tasks/cards.rake @@ -113,7 +113,8 @@ namespace :cards do is_unique: card['is_unique'], display_subtypes: flatten_subtypes(subtypes, card['subtypes']), attribution: card['attribution'], - designed_by: card['designed_by'] + designed_by: card['designed_by'], + layout_id: card.key?('layout_id') ? card['layout_id'] : 'normal' ) if card.key?('cost') new_card.cost = (card['cost'].nil? ? -1 : card['cost']) @@ -209,6 +210,75 @@ namespace :cards do end end + def import_card_faces(cards) + # Use a transaction since we are deleting the card_faces and card_faces_card_subtypes tables completely. + ActiveRecord::Base.transaction do + puts ' Clear out existing card face -> card subtype mappings' + unless ActiveRecord::Base.connection.delete('DELETE FROM card_faces_card_subtypes') + puts 'Hit an error while deleting card face -> card subtype mappings. rolling back.' + raise ActiveRecord::Rollback + end + + puts ' Clear out existing card faces' + unless ActiveRecord::Base.connection.delete('DELETE FROM card_faces') + puts 'Hit an error while deleting card faces. rolling back.' + raise ActiveRecord::Rollback + end + + subtypes = CardSubtype.all.index_by(&:id) + + cards.each do |card| + # Only generate faces for cards with multiple faces + next if !card.key?('layout_id') || card['layout_id'].nil? || card['layout_id'] == 'normal' + + # The first face of a card is just the main Card object and we do not make a CardFace for it. + # The rest of the faces are generated from the explicitly-defined faces of the card. + # Missing attributes are assumed to be unchanged. + i = 0 + card['faces'].each do |face| + i += 1 + face_subtypes = face.key?('subtypes') ? face['subtypes'] : card['subtypes'] + # There aren't enough cards with multiple faces to worry about optimizing inserts for them. + new_face = CardFace.new( + card_id: card['id'], + face_index: i + ) + new_face.base_link = face['base_link'] if face.key?('base_link') + display_subtypes = [] + if face.key?('subtypes') + face['subtypes'].each do |s| + unless subtypes.key?(s) + puts "subtype #{s} is invalid for card face for #{new_face.card_id}" + raise ActiveRecord::Rollback + end + display_subtypes << subtypes[s].name + end + end + new_face.display_subtypes = display_subtypes.join(' - ') if face.key?('subtypes') + new_face.stripped_text = face['stripped_text'] if face.key?('stripped_text') + new_face.stripped_title = face['stripped_title'] if face.key?('stripped_title') + new_face.text = face['text'] if face.key?('text') + new_face.title = face['title'] if face.key?('title') + + new_face.save + + next if face_subtypes.nil? + + face_subtypes.each do |s| + puts "Adding subtype #{s} to face #{i} of card #{new_face.card_id}" + cfcs = CardFaceCardSubtype.new( + card_id: new_face.card_id, + face_index: i, + card_subtype_id: s + ) + puts cfcs.inspect + cfcs.save + end + end + end + end + end + # This assumes that cards and card subtypes have already been loaded. def import_printing_subtypes printing_id_to_card_subtype_id = [] @@ -381,13 +451,13 @@ namespace :cards do def import_illustrators # Use a transaction since we are deleting the illustrator and mapping tables. ActiveRecord::Base.transaction do - puts 'Clear out existing illustrator -> printing mappings' + puts ' Clear out existing illustrator -> printing mappings' unless ActiveRecord::Base.connection.delete('DELETE FROM illustrators_printings') puts 'Hit an error while deleting illustrator -> printing mappings. rolling back.' raise ActiveRecord::Rollback end - puts 'Clear out existing illustrators' + puts ' Clear out existing illustrators' unless ActiveRecord::Base.connection.delete('DELETE FROM illustrators') puts 'Hit an error while deleting illustrators. rolling back.' raise ActiveRecord::Rollback @@ -821,6 +891,9 @@ namespace :cards do puts 'Importing Subtypes for Cards...' import_card_subtypes(cards_json) + puts 'Importing Card Faces...' + import_card_faces(cards_json) + puts 'Importing Printings...' import_printings(printings_json) From 60bd5b630fe08ed1e2d6090b965b33464bcfac6b Mon Sep 17 00:00:00 2001 From: Jason Gessner Date: Mon, 30 Dec 2024 20:54:44 +0000 Subject: [PATCH 2/2] Fix lint errors. --- app/models/card_face.rb | 1 + app/models/card_face_card_subtype.rb | 1 + db/migrate/20241230053539_add_layout_id_to_cards.rb | 4 +++- db/migrate/20241230055434_create_card_faces.rb | 4 +++- db/migrate/20241230055711_create_card_faces_card_subtypes.rb | 4 +++- 5 files changed, 11 insertions(+), 3 deletions(-) diff --git a/app/models/card_face.rb b/app/models/card_face.rb index bbaa326..c125a3e 100644 --- a/app/models/card_face.rb +++ b/app/models/card_face.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true +# Model for Card Faces - flip cards, cards with multiple versions, etc. class CardFace < ApplicationRecord belongs_to :card has_many :card_face_card_subtypes diff --git a/app/models/card_face_card_subtype.rb b/app/models/card_face_card_subtype.rb index 912fda7..4b5c504 100644 --- a/app/models/card_face_card_subtype.rb +++ b/app/models/card_face_card_subtype.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true +# Join model connecting CardFace objects to CardSubtype objects. class CardFaceCardSubtype < ApplicationRecord self.table_name = 'card_faces_card_subtypes' diff --git a/db/migrate/20241230053539_add_layout_id_to_cards.rb b/db/migrate/20241230053539_add_layout_id_to_cards.rb index de38031..20b9914 100644 --- a/db/migrate/20241230053539_add_layout_id_to_cards.rb +++ b/db/migrate/20241230053539_add_layout_id_to_cards.rb @@ -1,4 +1,6 @@ -class AddLayoutIdToCards < ActiveRecord::Migration[7.1] +# frozen_string_literal: true + +class AddLayoutIdToCards < ActiveRecord::Migration[7.1] # rubocop:disable Style/Documentation def change add_column :cards, :layout_id, :string, default: 'normal', null: false end diff --git a/db/migrate/20241230055434_create_card_faces.rb b/db/migrate/20241230055434_create_card_faces.rb index f6ba1fe..6aa01b8 100644 --- a/db/migrate/20241230055434_create_card_faces.rb +++ b/db/migrate/20241230055434_create_card_faces.rb @@ -1,4 +1,6 @@ -class CreateCardFaces < ActiveRecord::Migration[7.1] +# frozen_string_literal: true + +class CreateCardFaces < ActiveRecord::Migration[7.1] # rubocop:disable Style/Documentation def change create_table :card_faces, primary_key: %i[card_id face_index] do |t| t.string :card_id, null: false diff --git a/db/migrate/20241230055711_create_card_faces_card_subtypes.rb b/db/migrate/20241230055711_create_card_faces_card_subtypes.rb index b735c0d..201704b 100644 --- a/db/migrate/20241230055711_create_card_faces_card_subtypes.rb +++ b/db/migrate/20241230055711_create_card_faces_card_subtypes.rb @@ -1,4 +1,6 @@ -class CreateCardFacesCardSubtypes < ActiveRecord::Migration[7.1] +# frozen_string_literal: true + +class CreateCardFacesCardSubtypes < ActiveRecord::Migration[7.1] # rubocop:disable Style/Documentation def change create_table :card_faces_card_subtypes, id: false do |t| t.string :card_id, null: false