diff options
Diffstat (limited to 'app/services/ci/update_instance_variables_service.rb')
-rw-r--r-- | app/services/ci/update_instance_variables_service.rb | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/app/services/ci/update_instance_variables_service.rb b/app/services/ci/update_instance_variables_service.rb new file mode 100644 index 00000000000..ee513647d08 --- /dev/null +++ b/app/services/ci/update_instance_variables_service.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +# This class is a simplified version of assign_nested_attributes_for_collection_association from ActiveRecord +# https://github.com/rails/rails/blob/v6.0.2.1/activerecord/lib/active_record/nested_attributes.rb#L466 + +module Ci + class UpdateInstanceVariablesService + UNASSIGNABLE_KEYS = %w(id _destroy).freeze + + def initialize(params) + @params = params[:variables_attributes] + end + + def execute + instantiate_records + persist_records + end + + def errors + @records.to_a.flat_map { |r| r.errors.full_messages } + end + + private + + attr_reader :params + + def existing_records_by_id + @existing_records_by_id ||= Ci::InstanceVariable + .all + .index_by { |var| var.id.to_s } + end + + def instantiate_records + @records = params.map do |attributes| + find_or_initialize_record(attributes).tap do |record| + record.assign_attributes(attributes.except(*UNASSIGNABLE_KEYS)) + record.mark_for_destruction if has_destroy_flag?(attributes) + end + end + end + + def find_or_initialize_record(attributes) + id = attributes[:id].to_s + + if id.blank? + Ci::InstanceVariable.new + else + existing_records_by_id.fetch(id) { raise ActiveRecord::RecordNotFound } + end + end + + def persist_records + Ci::InstanceVariable.transaction do + success = @records.map do |record| + if record.marked_for_destruction? + record.destroy + else + record.save + end + end.all? + + raise ActiveRecord::Rollback unless success + + success + end + end + + def has_destroy_flag?(hash) + Gitlab::Utils.to_boolean(hash['_destroy']) + end + end +end |