refactor(repetition): add row_id to champs
This commit is contained in:
parent
5a7b2f76ee
commit
dfe65136be
44 changed files with 106 additions and 7 deletions
1
Gemfile
1
Gemfile
|
@ -84,6 +84,7 @@ gem 'spreadsheet_architect'
|
|||
gem 'strong_migrations' # lint database migrations
|
||||
gem 'turbo-rails'
|
||||
gem 'typhoeus'
|
||||
gem 'ulid-ruby', require: 'ulid'
|
||||
gem 'view_component'
|
||||
gem 'vite_rails'
|
||||
gem 'warden'
|
||||
|
|
|
@ -726,6 +726,7 @@ GEM
|
|||
ethon (>= 0.9.0)
|
||||
tzinfo (2.0.5)
|
||||
concurrent-ruby (~> 1.0)
|
||||
ulid-ruby (1.0.2)
|
||||
unf (0.1.4)
|
||||
unf_ext
|
||||
unf_ext (0.0.7.7)
|
||||
|
@ -915,6 +916,7 @@ DEPENDENCIES
|
|||
timecop
|
||||
turbo-rails
|
||||
typhoeus
|
||||
ulid-ruby
|
||||
vcr
|
||||
view_component
|
||||
vite_rails
|
||||
|
|
7
app/jobs/migrations/backfill_row_id_job.rb
Normal file
7
app/jobs/migrations/backfill_row_id_job.rb
Normal file
|
@ -0,0 +1,7 @@
|
|||
class Migrations::BackfillRowIdJob < ApplicationJob
|
||||
def perform(batch)
|
||||
batch.each do |(row_id, champ_ids)|
|
||||
Champ.where(id: champ_ids).update_all(row_id:)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -18,6 +18,7 @@
|
|||
# etablissement_id :integer
|
||||
# external_id :string
|
||||
# parent_id :bigint
|
||||
# row_id :string
|
||||
# type_de_champ_id :integer
|
||||
#
|
||||
class Champ < ApplicationRecord
|
||||
|
@ -221,7 +222,7 @@ class Champ < ApplicationRecord
|
|||
end
|
||||
|
||||
def clone
|
||||
champ_attributes = [:parent_id, :private, :row, :type, :type_de_champ_id]
|
||||
champ_attributes = [:parent_id, :private, :row, :row_id, :type, :type_de_champ_id]
|
||||
value_attributes = private? ? [] : [:value, :value_json, :data, :external_id]
|
||||
relationships = private? ? [] : [:etablissement, :geo_areas]
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
# etablissement_id :integer
|
||||
# external_id :string
|
||||
# parent_id :bigint
|
||||
# row_id :string
|
||||
# type_de_champ_id :integer
|
||||
#
|
||||
class Champs::AddressChamp < Champs::TextChamp
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
# etablissement_id :integer
|
||||
# external_id :string
|
||||
# parent_id :bigint
|
||||
# row_id :string
|
||||
# type_de_champ_id :integer
|
||||
#
|
||||
class Champs::AnnuaireEducationChamp < Champs::TextChamp
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
# etablissement_id :integer
|
||||
# external_id :string
|
||||
# parent_id :bigint
|
||||
# row_id :string
|
||||
# type_de_champ_id :integer
|
||||
#
|
||||
class Champs::CarteChamp < Champ
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
# etablissement_id :integer
|
||||
# external_id :string
|
||||
# parent_id :bigint
|
||||
# row_id :string
|
||||
# type_de_champ_id :integer
|
||||
#
|
||||
class Champs::CheckboxChamp < Champs::BooleanChamp
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
# etablissement_id :integer
|
||||
# external_id :string
|
||||
# parent_id :bigint
|
||||
# row_id :string
|
||||
# type_de_champ_id :integer
|
||||
#
|
||||
class Champs::CiviliteChamp < Champ
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
# etablissement_id :integer
|
||||
# external_id :string
|
||||
# parent_id :bigint
|
||||
# row_id :string
|
||||
# type_de_champ_id :integer
|
||||
#
|
||||
class Champs::CnafChamp < Champs::TextChamp
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
# etablissement_id :integer
|
||||
# external_id :string
|
||||
# parent_id :bigint
|
||||
# row_id :string
|
||||
# type_de_champ_id :integer
|
||||
#
|
||||
class Champs::CommuneChamp < Champs::TextChamp
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
# etablissement_id :integer
|
||||
# external_id :string
|
||||
# parent_id :bigint
|
||||
# row_id :string
|
||||
# type_de_champ_id :integer
|
||||
#
|
||||
class Champs::DateChamp < Champ
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
# etablissement_id :integer
|
||||
# external_id :string
|
||||
# parent_id :bigint
|
||||
# row_id :string
|
||||
# type_de_champ_id :integer
|
||||
#
|
||||
class Champs::DatetimeChamp < Champ
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
# etablissement_id :integer
|
||||
# external_id :string
|
||||
# parent_id :bigint
|
||||
# row_id :string
|
||||
# type_de_champ_id :integer
|
||||
#
|
||||
class Champs::DecimalNumberChamp < Champ
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
# etablissement_id :integer
|
||||
# external_id :string
|
||||
# parent_id :bigint
|
||||
# row_id :string
|
||||
# type_de_champ_id :integer
|
||||
#
|
||||
class Champs::DepartementChamp < Champs::TextChamp
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
# etablissement_id :integer
|
||||
# external_id :string
|
||||
# parent_id :bigint
|
||||
# row_id :string
|
||||
# type_de_champ_id :integer
|
||||
#
|
||||
class Champs::DgfipChamp < Champs::TextChamp
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
# etablissement_id :integer
|
||||
# external_id :string
|
||||
# parent_id :bigint
|
||||
# row_id :string
|
||||
# type_de_champ_id :integer
|
||||
#
|
||||
class Champs::DossierLinkChamp < Champ
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
# etablissement_id :integer
|
||||
# external_id :string
|
||||
# parent_id :bigint
|
||||
# row_id :string
|
||||
# type_de_champ_id :integer
|
||||
#
|
||||
class Champs::DropDownListChamp < Champ
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
# etablissement_id :integer
|
||||
# external_id :string
|
||||
# parent_id :bigint
|
||||
# row_id :string
|
||||
# type_de_champ_id :integer
|
||||
#
|
||||
class Champs::EmailChamp < Champs::TextChamp
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
# etablissement_id :integer
|
||||
# external_id :string
|
||||
# parent_id :bigint
|
||||
# row_id :string
|
||||
# type_de_champ_id :integer
|
||||
#
|
||||
class Champs::ExplicationChamp < Champs::TextChamp
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
# etablissement_id :integer
|
||||
# external_id :string
|
||||
# parent_id :bigint
|
||||
# row_id :string
|
||||
# type_de_champ_id :integer
|
||||
#
|
||||
class Champs::HeaderSectionChamp < Champ
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
# etablissement_id :integer
|
||||
# external_id :string
|
||||
# parent_id :bigint
|
||||
# row_id :string
|
||||
# type_de_champ_id :integer
|
||||
#
|
||||
class Champs::IbanChamp < Champ
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
# etablissement_id :integer
|
||||
# external_id :string
|
||||
# parent_id :bigint
|
||||
# row_id :string
|
||||
# type_de_champ_id :integer
|
||||
#
|
||||
class Champs::IntegerNumberChamp < Champ
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
# etablissement_id :integer
|
||||
# external_id :string
|
||||
# parent_id :bigint
|
||||
# row_id :string
|
||||
# type_de_champ_id :integer
|
||||
#
|
||||
class Champs::LinkedDropDownListChamp < Champ
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
# etablissement_id :integer
|
||||
# external_id :string
|
||||
# parent_id :bigint
|
||||
# row_id :string
|
||||
# type_de_champ_id :integer
|
||||
#
|
||||
class Champs::MesriChamp < Champs::TextChamp
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
# etablissement_id :integer
|
||||
# external_id :string
|
||||
# parent_id :bigint
|
||||
# row_id :string
|
||||
# type_de_champ_id :integer
|
||||
#
|
||||
class Champs::MultipleDropDownListChamp < Champ
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
# etablissement_id :integer
|
||||
# external_id :string
|
||||
# parent_id :bigint
|
||||
# row_id :string
|
||||
# type_de_champ_id :integer
|
||||
#
|
||||
class Champs::NumberChamp < Champ
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
# etablissement_id :integer
|
||||
# external_id :string
|
||||
# parent_id :bigint
|
||||
# row_id :string
|
||||
# type_de_champ_id :integer
|
||||
#
|
||||
class Champs::PaysChamp < Champs::TextChamp
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
# etablissement_id :integer
|
||||
# external_id :string
|
||||
# parent_id :bigint
|
||||
# row_id :string
|
||||
# type_de_champ_id :integer
|
||||
#
|
||||
class Champs::PhoneChamp < Champs::TextChamp
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
# etablissement_id :integer
|
||||
# external_id :string
|
||||
# parent_id :bigint
|
||||
# row_id :string
|
||||
# type_de_champ_id :integer
|
||||
#
|
||||
class Champs::PieceJustificativeChamp < Champ
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
# etablissement_id :integer
|
||||
# external_id :string
|
||||
# parent_id :bigint
|
||||
# row_id :string
|
||||
# type_de_champ_id :integer
|
||||
#
|
||||
class Champs::PoleEmploiChamp < Champs::TextChamp
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
# etablissement_id :integer
|
||||
# external_id :string
|
||||
# parent_id :bigint
|
||||
# row_id :string
|
||||
# type_de_champ_id :integer
|
||||
#
|
||||
class Champs::RegionChamp < Champs::TextChamp
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
# etablissement_id :integer
|
||||
# external_id :string
|
||||
# parent_id :bigint
|
||||
# row_id :string
|
||||
# type_de_champ_id :integer
|
||||
#
|
||||
class Champs::RepetitionChamp < Champ
|
||||
|
@ -32,8 +33,9 @@ class Champs::RepetitionChamp < Champ
|
|||
added_champs = []
|
||||
transaction do
|
||||
row = (blank? ? -1 : champs.last.row) + 1
|
||||
row_id = ULID.generate
|
||||
revision.children_of(type_de_champ).each do |type_de_champ|
|
||||
added_champs << type_de_champ.champ.build(row: row)
|
||||
added_champs << type_de_champ.champ.build(row:, row_id:)
|
||||
end
|
||||
self.champs << added_champs
|
||||
end
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
# external_id :string
|
||||
# parent_id :bigint
|
||||
# type_de_champ_id :integer not null
|
||||
# row_id :string
|
||||
#
|
||||
class Champs::RNAChamp < Champ
|
||||
validates :value, allow_blank: true, format: {
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
# etablissement_id :integer
|
||||
# external_id :string
|
||||
# parent_id :bigint
|
||||
# row_id :string
|
||||
# type_de_champ_id :integer
|
||||
#
|
||||
class Champs::SiretChamp < Champ
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
# etablissement_id :integer
|
||||
# external_id :string
|
||||
# parent_id :bigint
|
||||
# row_id :string
|
||||
# type_de_champ_id :integer
|
||||
#
|
||||
class Champs::TextChamp < Champ
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
# etablissement_id :integer
|
||||
# external_id :string
|
||||
# parent_id :bigint
|
||||
# row_id :string
|
||||
# type_de_champ_id :integer
|
||||
#
|
||||
class Champs::TextareaChamp < Champs::TextChamp
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
# etablissement_id :integer
|
||||
# external_id :string
|
||||
# parent_id :bigint
|
||||
# row_id :string
|
||||
# type_de_champ_id :integer
|
||||
#
|
||||
class Champs::TitreIdentiteChamp < Champ
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
# etablissement_id :integer
|
||||
# external_id :string
|
||||
# parent_id :bigint
|
||||
# row_id :string
|
||||
# type_de_champ_id :integer
|
||||
#
|
||||
class Champs::YesNoChamp < Champs::BooleanChamp
|
||||
|
|
|
@ -112,8 +112,8 @@ module DossierRebaseConcern
|
|||
.where(type_de_champ: { stable_id: parent_stable_id })
|
||||
|
||||
champs_repetition.each do |champ_repetition|
|
||||
champ_repetition.champs.map(&:row).uniq.each do |row|
|
||||
create_champ(target_coordinate, champ_repetition, row: row)
|
||||
champ_repetition.champs.index_by(&:row).each do |(row, champ)|
|
||||
create_champ(target_coordinate, champ_repetition, row:, row_id: champ.row_id)
|
||||
end
|
||||
end
|
||||
else
|
||||
|
@ -121,9 +121,8 @@ module DossierRebaseConcern
|
|||
end
|
||||
end
|
||||
|
||||
def create_champ(target_coordinate, parent, row: nil)
|
||||
params = { revision: target_coordinate.revision }
|
||||
params[:row] = row if row
|
||||
def create_champ(target_coordinate, parent, row: nil, row_id: nil)
|
||||
params = { revision: target_coordinate.revision, row:, row_id: }.compact
|
||||
champ = target_coordinate
|
||||
.type_de_champ
|
||||
.build_champ(params)
|
||||
|
|
5
db/migrate/20221215131001_add_row_id_to_champs.rb
Normal file
5
db/migrate/20221215131001_add_row_id_to_champs.rb
Normal file
|
@ -0,0 +1,5 @@
|
|||
class AddRowIdToChamps < ActiveRecord::Migration[6.1]
|
||||
def change
|
||||
add_column :champs, :row_id, :string
|
||||
end
|
||||
end
|
7
db/migrate/20221215131122_add_row_id_index_to_champs.rb
Normal file
7
db/migrate/20221215131122_add_row_id_index_to_champs.rb
Normal file
|
@ -0,0 +1,7 @@
|
|||
class AddRowIdIndexToChamps < ActiveRecord::Migration[6.1]
|
||||
disable_ddl_transaction!
|
||||
|
||||
def change
|
||||
add_index :champs, :row_id, algorithm: :concurrently
|
||||
end
|
||||
end
|
|
@ -227,6 +227,7 @@ ActiveRecord::Schema.define(version: 2022_12_27_084442) do
|
|||
t.boolean "private", default: false, null: false
|
||||
t.datetime "rebased_at"
|
||||
t.integer "row"
|
||||
t.string "row_id"
|
||||
t.string "type"
|
||||
t.integer "type_de_champ_id", null: false
|
||||
t.datetime "updated_at"
|
||||
|
@ -237,6 +238,7 @@ ActiveRecord::Schema.define(version: 2022_12_27_084442) do
|
|||
t.index ["parent_id"], name: "index_champs_on_parent_id"
|
||||
t.index ["private"], name: "index_champs_on_private"
|
||||
t.index ["row"], name: "index_champs_on_row"
|
||||
t.index ["row_id"], name: "index_champs_on_row_id"
|
||||
t.index ["type"], name: "index_champs_on_type"
|
||||
t.index ["type_de_champ_id", "dossier_id", "row"], name: "index_champs_on_type_de_champ_id_and_dossier_id_and_row", unique: true
|
||||
t.index ["type_de_champ_id"], name: "index_champs_on_type_de_champ_id"
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
namespace :after_party do
|
||||
desc 'Deployment task: backfill_row_id_on_champs'
|
||||
task backfill_row_id_on_champs: :environment do
|
||||
puts "Running deploy task 'backfill_row_id_on_champs'"
|
||||
|
||||
champs_to_fill = Champ.where(row_id: nil).where.not(parent_id: nil)
|
||||
progress = ProgressReport.new(champs_to_fill.count)
|
||||
|
||||
champs = champs_to_fill.pluck(:parent_id, :row, :id)
|
||||
pp "found #{champs.size} champs to fill"
|
||||
|
||||
row_ids = Champ.where.not(row_id: nil)
|
||||
.distinct(:row_id)
|
||||
.pluck(:parent_id, :row, :row_id)
|
||||
.map { [[_1.first, _1.second], _1.last] }.to_h
|
||||
pp "found #{row_ids.size} existing row ids"
|
||||
|
||||
champs_by_row = champs.group_by { [_1.first, _1.second] }.transform_values { _1.map(&:last) }
|
||||
pp "found #{champs_by_row.size} rows to fill"
|
||||
|
||||
champs_by_row.to_a.sort_by(&:first).in_groups_of(5_000) do |batch|
|
||||
batch = batch.lazy.compact.flat_map do |(key, champs)|
|
||||
row_ids[key] ||= ULID.generate
|
||||
champs&.map { [row_ids[key], _1] } || []
|
||||
end.group_by(&:first).transform_values { _1.map(&:last) }
|
||||
|
||||
Migrations::BackfillRowIdJob.perform_later(batch)
|
||||
|
||||
progress.inc(batch.size)
|
||||
end
|
||||
|
||||
progress.finish
|
||||
|
||||
# Update task as completed. If you remove the line below, the task will
|
||||
# run with every deploy (or every time you call after_party:run).
|
||||
AfterParty::TaskRecord
|
||||
.create version: AfterParty::TaskRecorder.new(__FILE__).timestamp
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue