Verified Commit b7eb2160 authored by Alexis Reigel's avatar Alexis Reigel
Browse files

add transaction support

parent d04b051d
......@@ -5,11 +5,13 @@ require 'excelsior/source'
require 'excelsior/mapping'
require 'excelsior/error'
require 'excelsior/report'
require 'excelsior/transaction'
module Excelsior
class Import
include Source
include Mapping
include Transaction
attr_accessor :source, :fields, :errors, :report
attr_accessor :rows, :columns
......@@ -29,21 +31,15 @@ module Excelsior
valid?
end
def run # takes an optional block
@rows.map.with_index do |row, i|
attributes = map_row_values(row, @columns)
if block_given?
begin
result = yield attributes
report_insert
result
rescue
report_failure
end
else
record = model_class.create(attributes)
add_model_errors(record, i)
def run(&block)
if self.class.use_transaction
model_class.transaction do
insert_rows(&block)
raise ActiveRecord::Rollback if @report.failed > 0
end
else
insert_rows(&block)
end
end
......@@ -84,5 +80,23 @@ module Excelsior
def report_failure
@report.failed += 1
end
def insert_rows(&block)
@rows.map.with_index do |row, i|
attributes = map_row_values(row, @columns)
if block_given?
begin
result = block.call(attributes)
report_insert
result
rescue
report_failure
end
else
record = model_class.create(attributes)
add_model_errors(record, i)
end
end
end
end
end
module Excelsior
module Transaction
def self.included(host_class)
host_class.extend ClassMethods
end
module ClassMethods
attr_accessor :use_transaction
def transaction(use_transaction)
self.use_transaction = use_transaction
end
end
end
end
require "test_helper"
require "excelsior/import"
class UserImport < Excelsior::Import
source "test/files/complete.xlsx"
map "Vorname", to: :first_name
map "Nachname", to: :last_name
map "E-Mail", to: :email
end
class User < ActiveRecord::Base
validates :first_name, presence: true
end
describe Excelsior do
before do
Object.send(:remove_const, :UserImport) if Object.constants.include?(:UserImport)
class UserImport < Excelsior::Import
source "test/files/complete.xlsx"
map "Vorname", to: :first_name
map "Nachname", to: :last_name
map "E-Mail", to: :email
end
@import = UserImport.new
end
......@@ -34,6 +36,66 @@ describe Excelsior do
end
end
describe 'transaction' do
describe 'transaction is not set' do
it 'inserts only the valid rows' do
UserImport.new("test/files/missing-first-name.xlsx").run
assert_equal 2, User.count
end
end
describe 'transaction is set to true' do
before do
Object.send(:remove_const, :UserImport) if Object.constants.include?(:UserImport)
class UserImport < Excelsior::Import
source "test/files/complete.xlsx"
transaction true
map "Vorname", to: :first_name
map "Nachname", to: :last_name
map "E-Mail", to: :email
end
end
describe 'without a block' do
let(:import) { UserImport.new("test/files/missing-first-name.xlsx") }
before do
import.run
end
it 'rolls back if one record fails' do
assert_equal 0, User.count
end
it 'returns the report' do
assert_equal 2, import.report.inserted
assert_equal 1, import.report.failed
assert_equal 3, import.report.total
end
end
describe 'with a block' do
it 'rolls back if one record raises an error' do
UserImport.new("test/files/missing-first-name.xlsx").run do |v|
User.create!(v)
end
assert_equal 0, User.count
end
it 'does not roll back if the block does not raise an error' do
UserImport.new("test/files/missing-first-name.xlsx").run do |v|
User.create(v)
end
assert_equal 2, User.count
end
end
end
end
describe '#rows' do
it 'returns the correct number of rows' do
assert_equal 2, @import.rows.length
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment