diff --git a/app/services/repository_rows/update_repository_row_service.rb b/app/services/repository_rows/update_repository_row_service.rb new file mode 100644 index 000000000..507f31ca4 --- /dev/null +++ b/app/services/repository_rows/update_repository_row_service.rb @@ -0,0 +1,76 @@ +# frozen_string_literal: true + +module RepositoryRows + class UpdateRepositoryRowService + extend Service + + attr_reader :repository_row, :params, :errors, :record_updated + + def initialize(repository_row:, user:, params:) + @repository_row = repository_row + @user = user + @params = params + @record_updated = false + @errors = {} + end + + def call + return self unless valid? + + ActiveRecord::Base.transaction do + # Update invetory row's cells + params[:repository_cells]&.each do |column_id, value| + column = @repository_row.repository.repository_columns.find_by(id: column_id) + next unless column + + cell = @repository_row.repository_cells.find_by(repository_column_id: column.id) + unless cell + RepositoryCell.create_with_value!(@repository_row, column, value, @user) + @record_updated = true + next + end + + if cell.value.data_changed?(value) + cell.value.update_data!(value, @user) + @record_updated = true + end + end + + # Update invetory rows + @repository_row.attributes = params[:repository_row] + + if @repository_row.changed? + @repository_row.last_modified_by = @user + @repository_row.save! + @record_updated = true + end + rescue ActiveRecord::RecordInvalid => e + @errors[e.record.class.name.underscore] = e.record.errors.full_messages + @record_updated = false + raise ActiveRecord::Rollback + end + + self + end + + def succeed? + @errors.none? + end + + private + + def valid? + unless @user && @repository_row && @params + @errors[:invalid_arguments] = + { 'repository_row': @repository_row, + 'params': @params, + 'user': @user } + .map do |key, value| + I18n.t('repositories.multiple_share_service.invalid_arguments', key: key.capitalize) if value.nil? + end.compact + return false + end + true + end + end +end diff --git a/spec/services/repository_rows/update_repository_row_service_spec.rb b/spec/services/repository_rows/update_repository_row_service_spec.rb new file mode 100644 index 000000000..0da0bd768 --- /dev/null +++ b/spec/services/repository_rows/update_repository_row_service_spec.rb @@ -0,0 +1,156 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe RepositoryRows::UpdateRepositoryRowService do + let(:user) { create :user } + let(:repository) { create :repository } + let(:row) { create :repository_row, repository: repository } + let!(:column) { create :repository_column, :text_type, repository: repository } + let(:service_call) do + RepositoryRows::UpdateRepositoryRowService + .call(repository_row: row, user: user, params: params) + end + + context 'when service succeed' do + context 'when repository cell does not exists' do + let(:params) do + { + repository_cells: Hash[column.id, 'some value'], + repository_row: {} + } + end + + it 'creates new cell' do + expect { service_call }.to change(RepositoryCell, :count).by(1) + end + + it 'returns true for record_updated' do + expect(service_call.record_updated).to be_truthy + end + + it 'returns true for succeeded' do + expect(service_call.succeed?).to be_truthy + end + end + + context 'when repository cell needs to be deleted' do + let(:params) do + { + repository_cells: Hash[column.id, ''], + repository_row: {} + } + end + + before do + RepositoryCell.create_with_value!(row, column, 'some data', user) + end + + it 'deletes cell' do + expect { service_call }.to change(RepositoryCell, :count).by(-1) + end + + it 'returns true for record_updated' do + expect(service_call.record_updated).to be_truthy + end + + it 'returns true for succeed' do + expect(service_call.succeed?).to be_truthy + end + end + + context 'when there is no repository_cells' do + let(:params) do + { + repository_cells: {}, + repository_row: {} + } + end + + it 'returns false for record_updated' do + expect(service_call.record_updated).to be_falsey + end + + it 'returns true for succeeded' do + expect(service_call.succeed?).to be_truthy + end + end + + context 'when has repository_row name param' do + let(:params) do + { + repository_row: { name: 'new name' } + } + end + + it 'updates repository name' do + expect { service_call }.to change(row, :name) + end + + it 'returns true for record_updated' do + expect(service_call.record_updated).to be_truthy + end + + it 'returns true for succeed' do + expect(service_call.succeed?).to be_truthy + end + end + + context 'when have cells for update' do + let(:params) do + { + repository_cells: Hash[column.id, 'New value'], + repository_row: {} + } + end + + it 'updates cell value data' do + cell = RepositoryCell.create_with_value!(row, column, 'some data', user) + + expect { service_call }.to(change { cell.reload.value.data }) + end + + it 'returns true for succeed' do + RepositoryCell.create_with_value!(row, column, 'some data', user) + + expect(service_call.succeed?).to be_truthy + end + end + end + + context 'when service does not succeed' do + context 'when cell value update fails' do + end + + context 'when updates repository_row and cell, but fails' do + let(:params) do + { + repository_cells: Hash[column.id, 'New value'], + repository_row: { name: '' } + } + end + + it 'reverts cells update' do + cell = RepositoryCell.create_with_value!(row, column, 'some data', user) + + expect { service_call }.not_to(change { cell.reload.value.data }) + end + end + + context 'when repository_row update fails' do + let(:params) do + { + repository_row: { name: '' } + } + end + + it 'returns false for succeed' do + expect(service_call.succeed?).to be_falsey + end + + it 'returns errors' do + expect(service_call.errors.count).to eq(1) + end + end + end +end