From 5d2eed1f666c78757d0f6e29ecdf9ff600050536 Mon Sep 17 00:00:00 2001 From: Jason Gessner Date: Sat, 25 Jun 2022 12:27:29 -0500 Subject: [PATCH 1/3] Add illustrator model, resource, and API. Update importer to support it. --- .../api/v3/public/illustrators_controller.rb | 8 ++ app/models/illustrator.rb | 6 + app/models/illustrator_printing.rb | 12 ++ app/models/printing.rb | 2 + .../api/v3/public/illustrator_resource.rb | 16 +++ .../api/v3/public/printing_resource.rb | 9 +- config/routes.rb | 1 + ...0220625035145_create_illustrator_tables.rb | 14 ++ ...20625170812_rename_printing_illustrator.rb | 5 + db/schema.rb | 16 ++- lib/tasks/cards.rake | 132 +++++++++++++----- 11 files changed, 178 insertions(+), 43 deletions(-) create mode 100644 app/controllers/api/v3/public/illustrators_controller.rb create mode 100644 app/models/illustrator.rb create mode 100644 app/models/illustrator_printing.rb create mode 100644 app/resources/api/v3/public/illustrator_resource.rb create mode 100644 db/migrate/20220625035145_create_illustrator_tables.rb create mode 100644 db/migrate/20220625170812_rename_printing_illustrator.rb diff --git a/app/controllers/api/v3/public/illustrators_controller.rb b/app/controllers/api/v3/public/illustrators_controller.rb new file mode 100644 index 00000000..715ac3ee --- /dev/null +++ b/app/controllers/api/v3/public/illustrators_controller.rb @@ -0,0 +1,8 @@ +module API + module V3 + module Public + class Api::V3::Public::IllustratorsController < JSONAPI::ResourceController + end + end + end +end diff --git a/app/models/illustrator.rb b/app/models/illustrator.rb new file mode 100644 index 00000000..9b807ecf --- /dev/null +++ b/app/models/illustrator.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +class Illustrator < ApplicationRecord + has_many :illustrator_printings + has_many :printings, :through => :illustrator_printings +end diff --git a/app/models/illustrator_printing.rb b/app/models/illustrator_printing.rb new file mode 100644 index 00000000..9eaede19 --- /dev/null +++ b/app/models/illustrator_printing.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +class IllustratorPrinting < ApplicationRecord + self.table_name = "illustrators_printings" + + belongs_to :illustrator, + :primary_key => :id, + :foreign_key => :illustrator_id + belongs_to :printing, + :primary_key => :id, + :foreign_key => :printing_id +end diff --git a/app/models/printing.rb b/app/models/printing.rb index 732b48a5..1a0bb56b 100644 --- a/app/models/printing.rb +++ b/app/models/printing.rb @@ -6,4 +6,6 @@ class Printing < ApplicationRecord has_one :faction, :through => :card has_one :card_cycle, :through => :card_set has_one :side, :through => :card + has_many :illustrator_printings + has_many :illustrators, :through => :illustrator_printings end diff --git a/app/resources/api/v3/public/illustrator_resource.rb b/app/resources/api/v3/public/illustrator_resource.rb new file mode 100644 index 00000000..d5457d1b --- /dev/null +++ b/app/resources/api/v3/public/illustrator_resource.rb @@ -0,0 +1,16 @@ +module API + module V3 + module Public + class Api::V3::Public::IllustratorResource < JSONAPI::Resource + immutable + + attributes :name, :updated_at + key_type :string + + paginator :none + + has_many :printings + end + end + end +end diff --git a/app/resources/api/v3/public/printing_resource.rb b/app/resources/api/v3/public/printing_resource.rb index 5ab584a9..4a201071 100644 --- a/app/resources/api/v3/public/printing_resource.rb +++ b/app/resources/api/v3/public/printing_resource.rb @@ -6,7 +6,7 @@ class Api::V3::Public::PrintingResource < JSONAPI::Resource # Direct printing attributes attributes :card_id, :card_set_id, :printed_text, :stripped_printed_text - attributes :printed_is_unique, :flavor, :illustrator, :position + attributes :printed_is_unique, :flavor, :display_illustrators, :position attributes :quantity, :date_release, :updated_at # Parent Card attributes, included inline to make printings a bit more useful. @@ -21,14 +21,15 @@ class Api::V3::Public::PrintingResource < JSONAPI::Resource key_type :string + has_one :card has_one :card_cycle has_one :card_set - has_one :side has_one :faction - has_one :card + has_many :illustrators + has_one :side # Printing direct attribute filters - filters :card_id, :card_set_id, :printed_is_unique, :illustrator, :position + filters :card_id, :card_set_id, :printed_is_unique, :display_illustrators, :position filters :quantity, :date_release # Card attribute filters diff --git a/config/routes.rb b/config/routes.rb index 3d04a5b6..bba8a22b 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -9,6 +9,7 @@ jsonapi_resources :card_types, only: [:index, :show] jsonapi_resources :cards, only: [:index, :show] jsonapi_resources :factions, only: [:index, :show] + jsonapi_resources :illustrators, only: [:index, :show] jsonapi_resources :printings, only: [:index, :show] jsonapi_resources :sides, only: [:index, :show] end diff --git a/db/migrate/20220625035145_create_illustrator_tables.rb b/db/migrate/20220625035145_create_illustrator_tables.rb new file mode 100644 index 00000000..8b466fe3 --- /dev/null +++ b/db/migrate/20220625035145_create_illustrator_tables.rb @@ -0,0 +1,14 @@ +class CreateIllustratorTables < ActiveRecord::Migration[7.0] + def change + create_table :illustrators, id: :string do |t| + t.string :name + t.timestamps + end + + create_table :illustrators_printings, id: false, force: :cascade do |t| + t.string :illustrator_id, null: false + t.string :printing_id, null: false + t.index [:illustrator_id, :printing_id], name: "index_illustrators_printings_on_illustrator_id_and_printing_id", unique: true + end + end +end diff --git a/db/migrate/20220625170812_rename_printing_illustrator.rb b/db/migrate/20220625170812_rename_printing_illustrator.rb new file mode 100644 index 00000000..ecacfc3b --- /dev/null +++ b/db/migrate/20220625170812_rename_printing_illustrator.rb @@ -0,0 +1,5 @@ +class RenamePrintingIllustrator < ActiveRecord::Migration[7.0] + def change + rename_column :printings, :illustrator, :display_illustrators + end +end diff --git a/db/schema.rb b/db/schema.rb index 67553bef..43f70d25 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.0].define(version: 2022_06_18_233411) do +ActiveRecord::Schema[7.0].define(version: 2022_06_25_170812) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -97,6 +97,18 @@ t.string "description" end + create_table "illustrators", id: :string, force: :cascade do |t| + t.string "name" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + create_table "illustrators_printings", id: false, force: :cascade do |t| + t.string "illustrator_id", null: false + t.string "printing_id", null: false + t.index ["illustrator_id", "printing_id"], name: "index_illustrators_printings_on_illustrator_id_and_printing_id", unique: true + end + create_table "printings", id: :string, force: :cascade do |t| t.text "card_id" t.text "card_set_id" @@ -104,7 +116,7 @@ t.text "stripped_printed_text" t.boolean "printed_is_unique" t.text "flavor" - t.text "illustrator" + t.text "display_illustrators" t.integer "position" t.integer "quantity" t.date "date_release" diff --git a/lib/tasks/cards.rake b/lib/tasks/cards.rake index c9580325..236bb750 100644 --- a/lib/tasks/cards.rake +++ b/lib/tasks/cards.rake @@ -1,6 +1,16 @@ namespace :cards do desc 'import card data - json_dir defaults to /netrunner-cards-json/ if not specified.' + def text_to_id(t) + t.downcase + .unicode_normalize(:nfd) + .gsub(/\P{ASCII}/, '') + .gsub(/'s(\p{Space}|\z)/, 's\1') + .split(/[\p{Space}\p{Punct}]+/) + .reject { |s| s&.strip&.empty? } + .join("_") + end + def load_multiple_json_files(path) cards = [] Dir.glob(path) do |f| @@ -124,7 +134,7 @@ namespace :cards do ActiveRecord::Base.transaction do puts 'Clear out existing card -> subtype mappings' unless ActiveRecord::Base.connection.delete("DELETE FROM cards_card_subtypes") - puts 'Hit an error while delete card -> subtype mappings. rolling back.' + puts 'Hit an error while deleting card -> subtype mappings. rolling back.' raise ActiveRecord::Rollback end @@ -205,7 +215,7 @@ namespace :cards do printed_is_unique: printing["printed_is_unique"], id: printing["id"], flavor: printing["flavor"], - illustrator: printing["illustrator"], + display_illustrators: printing["illustrator"], position: printing["position"], quantity: printing["quantity"], card_id: printing["card_id"], @@ -222,45 +232,93 @@ namespace :cards do } end + 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' + 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' + unless ActiveRecord::Base.connection.delete("DELETE FROM illustrators") + puts 'Hit an error while deleting illustrators. rolling back.' + raise ActiveRecord::Rollback + end + + illustrators = Set[] + illustrators_to_printings = [] + num_its = 0 + printings = Printing.all + printings.each { |printing| + if printing.display_illustrators then + printing.display_illustrators.split(', ').each { |i| + illustrators.add(i) + num_its += 1 + illustrators_to_printings << { + "illustrator_id": text_to_id(i), + "printing_id": printing.id + } + } + end + } + + ill = [] + illustrators.each { |i| + ill << { + "id": text_to_id(i), + "name": i + } + } + + Illustrator.import ill, on_duplicate_key_update: { conflict_target: [ :id ], columns: :all } + IllustratorPrinting.import illustrators_to_printings, on_duplicate_key_update: { conflict_target: [ :illustrator_id, :printing_id ], columns: :all } + end + end + task :import, [:json_dir] => [:environment] do |t, args| args.with_defaults(:json_dir => '/netrunner-cards-json/') puts 'Import card data...' - # The JSON from the files in packs/ are used by multiple methods. - pack_cards_json = load_multiple_json_files(args[:json_dir] + '/pack/*.json') - - puts 'Importing Sides...' - import_sides(args[:json_dir] + '/v2/sides.json') - - puts 'Import Factions...' - import_factions(args[:json_dir] + '/v2/factions.json') - - puts 'Importing Cycles...' - import_cycles(args[:json_dir] + '/v2/cycles.json') - - puts 'Importing Card Set Types...' - import_set_types(args[:json_dir] + '/v2/set_types.json') - - puts 'Importing Sets...' - import_sets(args[:json_dir] + '/v2/printings.json') - - puts 'Updating date_release for Cycles' - update_date_release_for_cycles() - - puts 'Importing Types...' - import_types(args[:json_dir] + '/v2/types.json') - - puts 'Importing Subtypes...' - import_subtypes(args[:json_dir] + '/v2/subtypes.json') - - puts 'Importing Cards...' - import_cards(load_multiple_json_files(args[:json_dir] + '/v2/cards/*.json')) - - puts 'Importing Subtypes for Cards...' - import_card_subtypes(load_multiple_json_files(args[:json_dir] + '/v2/cards/*.json')) - - puts 'Importing Printings...' - import_printings(load_multiple_json_files(args[:json_dir] + '/v2/printings/*.json')) +# # The JSON from the files in packs/ are used by multiple methods. +# pack_cards_json = load_multiple_json_files(args[:json_dir] + '/pack/*.json') +# +# puts 'Importing Sides...' +# import_sides(args[:json_dir] + '/v2/sides.json') +# +# puts 'Import Factions...' +# import_factions(args[:json_dir] + '/v2/factions.json') +# +# puts 'Importing Cycles...' +# import_cycles(args[:json_dir] + '/v2/cycles.json') +# +# puts 'Importing Card Set Types...' +# import_set_types(args[:json_dir] + '/v2/set_types.json') +# +# puts 'Importing Sets...' +# import_sets(args[:json_dir] + '/v2/printings.json') +# +# puts 'Updating date_release for Cycles' +# update_date_release_for_cycles() +# +# puts 'Importing Types...' +# import_types(args[:json_dir] + '/v2/types.json') +# +# puts 'Importing Subtypes...' +# import_subtypes(args[:json_dir] + '/v2/subtypes.json') +# +# puts 'Importing Cards...' +# import_cards(load_multiple_json_files(args[:json_dir] + '/v2/cards/*.json')) +# +# puts 'Importing Subtypes for Cards...' +# import_card_subtypes(load_multiple_json_files(args[:json_dir] + '/v2/cards/*.json')) +# +# puts 'Importing Printings...' +# import_printings(load_multiple_json_files(args[:json_dir] + '/v2/printings/*.json')) + + puts 'Importing Illustrators...' + import_illustrators() puts 'Done!' end From a8dda85d45c5f2f25cba6bf8e538473b9f97c3dc Mon Sep 17 00:00:00 2001 From: Jason Gessner Date: Sun, 26 Jun 2022 12:19:38 -0500 Subject: [PATCH 2/3] Remove temporary importer commenting. --- lib/tasks/cards.rake | 70 ++++++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/lib/tasks/cards.rake b/lib/tasks/cards.rake index 236bb750..0d2395e8 100644 --- a/lib/tasks/cards.rake +++ b/lib/tasks/cards.rake @@ -281,41 +281,41 @@ namespace :cards do args.with_defaults(:json_dir => '/netrunner-cards-json/') puts 'Import card data...' -# # The JSON from the files in packs/ are used by multiple methods. -# pack_cards_json = load_multiple_json_files(args[:json_dir] + '/pack/*.json') -# -# puts 'Importing Sides...' -# import_sides(args[:json_dir] + '/v2/sides.json') -# -# puts 'Import Factions...' -# import_factions(args[:json_dir] + '/v2/factions.json') -# -# puts 'Importing Cycles...' -# import_cycles(args[:json_dir] + '/v2/cycles.json') -# -# puts 'Importing Card Set Types...' -# import_set_types(args[:json_dir] + '/v2/set_types.json') -# -# puts 'Importing Sets...' -# import_sets(args[:json_dir] + '/v2/printings.json') -# -# puts 'Updating date_release for Cycles' -# update_date_release_for_cycles() -# -# puts 'Importing Types...' -# import_types(args[:json_dir] + '/v2/types.json') -# -# puts 'Importing Subtypes...' -# import_subtypes(args[:json_dir] + '/v2/subtypes.json') -# -# puts 'Importing Cards...' -# import_cards(load_multiple_json_files(args[:json_dir] + '/v2/cards/*.json')) -# -# puts 'Importing Subtypes for Cards...' -# import_card_subtypes(load_multiple_json_files(args[:json_dir] + '/v2/cards/*.json')) -# -# puts 'Importing Printings...' -# import_printings(load_multiple_json_files(args[:json_dir] + '/v2/printings/*.json')) + # The JSON from the files in packs/ are used by multiple methods. + pack_cards_json = load_multiple_json_files(args[:json_dir] + '/pack/*.json') + + puts 'Importing Sides...' + import_sides(args[:json_dir] + '/v2/sides.json') + + puts 'Import Factions...' + import_factions(args[:json_dir] + '/v2/factions.json') + + puts 'Importing Cycles...' + import_cycles(args[:json_dir] + '/v2/cycles.json') + + puts 'Importing Card Set Types...' + import_set_types(args[:json_dir] + '/v2/set_types.json') + + puts 'Importing Sets...' + import_sets(args[:json_dir] + '/v2/printings.json') + + puts 'Updating date_release for Cycles' + update_date_release_for_cycles() + + puts 'Importing Types...' + import_types(args[:json_dir] + '/v2/types.json') + + puts 'Importing Subtypes...' + import_subtypes(args[:json_dir] + '/v2/subtypes.json') + + puts 'Importing Cards...' + import_cards(load_multiple_json_files(args[:json_dir] + '/v2/cards/*.json')) + + puts 'Importing Subtypes for Cards...' + import_card_subtypes(load_multiple_json_files(args[:json_dir] + '/v2/cards/*.json')) + + puts 'Importing Printings...' + import_printings(load_multiple_json_files(args[:json_dir] + '/v2/printings/*.json')) puts 'Importing Illustrators...' import_illustrators() From 8a8835af43df6163b9e1210c2012be3b7cd599c8 Mon Sep 17 00:00:00 2001 From: Jason Gessner Date: Sat, 2 Jul 2022 21:38:38 -0500 Subject: [PATCH 3/3] Use ruby 1.9 hash syntax for IllustratorPrinting. --- app/models/illustrator_printing.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/models/illustrator_printing.rb b/app/models/illustrator_printing.rb index 9eaede19..ccf69a60 100644 --- a/app/models/illustrator_printing.rb +++ b/app/models/illustrator_printing.rb @@ -4,9 +4,9 @@ class IllustratorPrinting < ApplicationRecord self.table_name = "illustrators_printings" belongs_to :illustrator, - :primary_key => :id, - :foreign_key => :illustrator_id + primary_key: :id, + foreign_key: :illustrator_id belongs_to :printing, - :primary_key => :id, - :foreign_key => :printing_id + primary_key: :id, + foreign_key: :printing_id end