itiel 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.autotest +17 -0
- data/.gitignore +13 -0
- data/.gitlab-ci.yml +36 -0
- data/.rspec +2 -0
- data/.ruby-version +1 -0
- data/.travis.yml +9 -0
- data/Gemfile +4 -0
- data/Gemfile.rails.4.0 +7 -0
- data/Gemfile.rails.4.1 +7 -0
- data/Gemfile.rails.4.2 +7 -0
- data/README.markdown +106 -0
- data/Rakefile +13 -0
- data/build.sh +10 -0
- data/features/extract/database_table.feature +16 -0
- data/features/extract/sql_script.feature +17 -0
- data/features/load/database_table_loader.feature +21 -0
- data/features/lookup/csv_file.feature +41 -0
- data/features/lookup/database_table.feature +43 -0
- data/features/script/ruby_script.feature +19 -0
- data/features/step_definitions/csv_steps.rb +15 -0
- data/features/step_definitions/extractor/csv_file_steps.rb +3 -0
- data/features/step_definitions/extractor/custom_sql_steps.rb +6 -0
- data/features/step_definitions/extractor/database_steps.rb +27 -0
- data/features/step_definitions/extractor/database_table_steps.rb +8 -0
- data/features/step_definitions/extractor/extraction_steps.rb +3 -0
- data/features/step_definitions/flow_steps.rb +9 -0
- data/features/step_definitions/loader/csv_file_steps.rb +4 -0
- data/features/step_definitions/loader/database_table_steps.rb +14 -0
- data/features/step_definitions/lookup/lookup_steps.rb +35 -0
- data/features/step_definitions/scripting/ruby_script_steps.rb +5 -0
- data/features/step_definitions/stream_steps.rb +8 -0
- data/features/step_definitions/transformation/calculated_column_steps.rb +5 -0
- data/features/step_definitions/transformation/calculated_columns_steps.rb +7 -0
- data/features/step_definitions/transformation/constant_column_steps.rb +3 -0
- data/features/step_definitions/transformation/map_values_step.rb +4 -0
- data/features/step_definitions/transformation/rename_column_steps.rb +3 -0
- data/features/step_definitions/transformation/select_column_steps.rb +3 -0
- data/features/step_definitions/transformation/single_column_sort_steps.rb +3 -0
- data/features/support/database.yml +1 -0
- data/features/support/env.rb +13 -0
- data/features/transform/transformations.feature +123 -0
- data/itiel.gemspec +34 -0
- data/lib/itiel.rb +45 -0
- data/lib/itiel/db/connection.rb +24 -0
- data/lib/itiel/db/sql_connectable.rb +33 -0
- data/lib/itiel/db/truncator.rb +30 -0
- data/lib/itiel/extract/chained_step.rb +22 -0
- data/lib/itiel/extract/csv_file.rb +31 -0
- data/lib/itiel/extract/custom_sql.rb +38 -0
- data/lib/itiel/extract/database_table.rb +23 -0
- data/lib/itiel/job.rb +116 -0
- data/lib/itiel/load/chained_step.rb +37 -0
- data/lib/itiel/load/csv_file.rb +45 -0
- data/lib/itiel/load/database_table.rb +34 -0
- data/lib/itiel/load/input_output_behavior.rb +36 -0
- data/lib/itiel/logger.rb +47 -0
- data/lib/itiel/lookup/chained_step.rb +35 -0
- data/lib/itiel/lookup/csv_file.rb +16 -0
- data/lib/itiel/lookup/database_table.rb +36 -0
- data/lib/itiel/lookup/hash_lookup.rb +35 -0
- data/lib/itiel/nameable.rb +6 -0
- data/lib/itiel/script/chained_step.rb +18 -0
- data/lib/itiel/script/ruby_script.rb +31 -0
- data/lib/itiel/script/sql_script.rb +29 -0
- data/lib/itiel/transform/calculated_columns.rb +47 -0
- data/lib/itiel/transform/chained_step.rb +27 -0
- data/lib/itiel/transform/constant_column.rb +35 -0
- data/lib/itiel/transform/input_output_behavior.rb +44 -0
- data/lib/itiel/transform/map_values.rb +43 -0
- data/lib/itiel/transform/remove_column.rb +33 -0
- data/lib/itiel/transform/rename_column.rb +43 -0
- data/lib/itiel/transform/select_column.rb +37 -0
- data/lib/itiel/version.rb +3 -0
- data/spec/db/sql_connectable_spec.rb +20 -0
- data/spec/extract/chained_step_spec.rb +31 -0
- data/spec/extract/csv_file_spec.rb +22 -0
- data/spec/extract/custom_sql_spec.rb +19 -0
- data/spec/extract/database_table_spec.rb +22 -0
- data/spec/job_spec.rb +80 -0
- data/spec/loader/chained_step_spec.rb +39 -0
- data/spec/loader/csv_file_spec.rb +69 -0
- data/spec/loader/database_table_spec.rb +29 -0
- data/spec/lookup/hash_lookup_spec.rb +108 -0
- data/spec/nameable_spec.rb +17 -0
- data/spec/script/chained_step_spec.rb +24 -0
- data/spec/script/ruby_script_spec.rb +18 -0
- data/spec/script/sql_script_spec.rb +41 -0
- data/spec/spec_helper.rb +24 -0
- data/spec/support/config/database.yml +1 -0
- data/spec/support/config/sources.yml +9 -0
- data/spec/transform/calculated_columns_spec.rb +36 -0
- data/spec/transform/chained_step_spec.rb +36 -0
- data/spec/transform/constant_column_spec.rb +22 -0
- data/spec/transform/map_values_spec.rb +26 -0
- data/spec/transform/rename_column_spec.rb +25 -0
- data/spec/transform/select_column_spec.rb +21 -0
- metadata +344 -0
@@ -0,0 +1,43 @@
|
|
1
|
+
module Itiel
|
2
|
+
module Transform
|
3
|
+
#
|
4
|
+
# Renames a column in the data stream
|
5
|
+
#
|
6
|
+
# Usage:
|
7
|
+
#
|
8
|
+
# @transformer = Itiel::Transform::RenameColumn.new("order_id" => "id")
|
9
|
+
#
|
10
|
+
# This would rename the order_id column in the input stream to id
|
11
|
+
#
|
12
|
+
class RenameColumn
|
13
|
+
include ChainedStep
|
14
|
+
include Itiel::Nameable
|
15
|
+
|
16
|
+
attr_accessor :mappings
|
17
|
+
|
18
|
+
def initialize(*args)
|
19
|
+
self.mappings = args
|
20
|
+
end
|
21
|
+
|
22
|
+
def transform!(input_stream)
|
23
|
+
old_keys = self.mappings.first.keys
|
24
|
+
all_keys = input_stream.first.keys
|
25
|
+
|
26
|
+
transformed_output = []
|
27
|
+
input_stream.each do |object|
|
28
|
+
element = {}
|
29
|
+
all_keys.each do |k|
|
30
|
+
if old_keys.include?(k)
|
31
|
+
element[self.mappings.first[k]] = object[k]
|
32
|
+
else
|
33
|
+
element[k] = object[k]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
transformed_output << element
|
37
|
+
end
|
38
|
+
|
39
|
+
transformed_output
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Itiel
|
2
|
+
module Transform
|
3
|
+
#
|
4
|
+
# This transformation only selects specific columns on the data stream
|
5
|
+
#
|
6
|
+
# Usage:
|
7
|
+
#
|
8
|
+
# @transformer = Itiel::Transform::SelectColumn.new("order_id", "name")
|
9
|
+
#
|
10
|
+
# In the example, the output stream would only have the order_id and the name column
|
11
|
+
# All other columns will be ignored
|
12
|
+
#
|
13
|
+
class SelectColumn
|
14
|
+
include ChainedStep
|
15
|
+
include Itiel::Nameable
|
16
|
+
|
17
|
+
attr_accessor :mappings
|
18
|
+
|
19
|
+
def input=(stream)
|
20
|
+
next_step.input = transform!(stream)
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize(*args)
|
24
|
+
self.mappings = args
|
25
|
+
end
|
26
|
+
|
27
|
+
def transform!(input_stream)
|
28
|
+
selected_output = []
|
29
|
+
input_stream.each do |object|
|
30
|
+
selected_output << object.select {|key, value| self.mappings.include? key }
|
31
|
+
end
|
32
|
+
|
33
|
+
selected_output
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Itiel::DB::SQLConnectable do
|
4
|
+
before :each do
|
5
|
+
class Step
|
6
|
+
include Itiel::DB::SQLConnectable
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
it "sets and gets connection_file_path" do
|
11
|
+
expect(Step).to respond_to :connection_file_path
|
12
|
+
expect(Step).to respond_to :connection_file_path=
|
13
|
+
end
|
14
|
+
|
15
|
+
it "returns a sequel_connection object based on the connection file" do
|
16
|
+
Step.connection_file_path = File.dirname(__FILE__) + '/../support/config/database.yml'
|
17
|
+
expect(Step.sequel_connection(:test)).to_not be_nil
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Itiel::Extract::ChainedStep do
|
4
|
+
before :each do
|
5
|
+
klass = Class.new
|
6
|
+
klass.send(:include, Itiel::Extract::ChainedStep)
|
7
|
+
@step = klass.new
|
8
|
+
|
9
|
+
@stream = double
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "#start" do
|
13
|
+
before :each do
|
14
|
+
@next_step = double
|
15
|
+
@step.next_step = @next_step
|
16
|
+
end
|
17
|
+
|
18
|
+
it "extracts and sends the stream to the next step" do
|
19
|
+
allow(@step).to receive(:extract).and_return(@stream)
|
20
|
+
allow(@next_step).to receive(:input=).and_return(@stream)
|
21
|
+
|
22
|
+
@step.start
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "#extract" do
|
27
|
+
it "raises an exception" do
|
28
|
+
expect { @step.extract }.to raise_error Itiel::MethodNotImplementedException
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Itiel::Extract::CSVFile do
|
4
|
+
before :each do
|
5
|
+
@step = Itiel::Extract::CSVFile.new 'FILENAME'
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "#extract" do
|
9
|
+
it "reads a csv file and returns it as a hash to the stream" do
|
10
|
+
row = double
|
11
|
+
allow(row).to receive(:to_hash).and_return({data: true})
|
12
|
+
|
13
|
+
@stream = [ row ]
|
14
|
+
allow(CSV).to receive(:read).
|
15
|
+
with('FILENAME', headers: true).
|
16
|
+
and_return(@stream)
|
17
|
+
|
18
|
+
expect(@step.extract).to eq [{ data: true }]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Itiel::Extract::CustomSQL do
|
4
|
+
describe "#extract" do
|
5
|
+
before :each do
|
6
|
+
@step = Itiel::Extract::CustomSQL.new 'SCRIPT'
|
7
|
+
@step.connection = :test
|
8
|
+
end
|
9
|
+
|
10
|
+
it "Runs a script on the database and returns its results to the stream" do
|
11
|
+
result = double
|
12
|
+
allow(result).to receive(:all).and_return double
|
13
|
+
db = { 'SCRIPT' => result }
|
14
|
+
allow(Itiel::Extract::CustomSQL).to receive(:sequel_connection).with(:test).and_return db
|
15
|
+
|
16
|
+
expect(@step.extract).to eq result.all
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Itiel::Extract::DatabaseTable do
|
4
|
+
before :each do
|
5
|
+
@step = Itiel::Extract::DatabaseTable.new
|
6
|
+
@step.connection = :test
|
7
|
+
@step.table_name = 'table_name'
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "#extract" do
|
11
|
+
it "returns all the rows in the specified database table" do
|
12
|
+
result = double
|
13
|
+
db = { table_name: result }
|
14
|
+
allow(result).to receive(:all).and_return double
|
15
|
+
expect(Itiel::Extract::DatabaseTable).
|
16
|
+
to receive(:sequel_connection).
|
17
|
+
with(:test).and_return db
|
18
|
+
|
19
|
+
expect(@step.extract).to eq result.all
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/spec/job_spec.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Itiel::Job do
|
4
|
+
describe "#run" do
|
5
|
+
it "yields a new instance of Itiel::Job" do
|
6
|
+
Itiel::Job.run { |object| expect(object).to be_instance_of(Itiel::Job) }
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "#define" do
|
11
|
+
it "returns an instance of Itiel::Job" do
|
12
|
+
expect(Itiel::Job.define).to be_instance_of(Itiel::Job)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "yields a new instance of Itiel::Job" do
|
16
|
+
Itiel::Job.define {|object| assert_instance_of(Itiel::Job, object)}
|
17
|
+
end
|
18
|
+
|
19
|
+
it "sets given block as the block attribute of the instance it returns" do
|
20
|
+
block = Proc.new {}
|
21
|
+
job = Itiel::Job.define(&block)
|
22
|
+
expect(block).to eq job.block
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "#run!" do
|
27
|
+
it "calls the block on self.block" do
|
28
|
+
block = Proc.new {}
|
29
|
+
expect(block).to receive(:call)
|
30
|
+
job = Itiel::Job.define(&block)
|
31
|
+
job.run!
|
32
|
+
end
|
33
|
+
|
34
|
+
it "responds to step inside the block" do
|
35
|
+
@object = double
|
36
|
+
instanced_job = Itiel::Job.define do |job|
|
37
|
+
job.step @object
|
38
|
+
end
|
39
|
+
|
40
|
+
expect(instanced_job).to receive(:step).with(@object)
|
41
|
+
instanced_job.run!
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "#step" do
|
46
|
+
before :each do
|
47
|
+
@job = Itiel::Job.new
|
48
|
+
@source = double
|
49
|
+
@destination = double
|
50
|
+
@stream = double
|
51
|
+
|
52
|
+
allow(@source).to receive(:output).and_return @stream
|
53
|
+
expect(@destination).to receive(:input=).and_return @stream
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "@source => @destination" do
|
57
|
+
it "hardwires the @destination's input with the @source output" do
|
58
|
+
@job.step @source => @destination
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "step @source; step @destination" do
|
63
|
+
it "hardwires the @destination's input with the @source output" do
|
64
|
+
expect(@destination).to receive(:output)
|
65
|
+
@job.step @source
|
66
|
+
@job.step @destination
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "step @source => [ @destination, @second_destination ]" do
|
71
|
+
it "hardwires both destination's inputs with the @source output" do
|
72
|
+
@second_destination = double
|
73
|
+
expect(@second_destination).to receive(:input=).and_return @stream
|
74
|
+
|
75
|
+
@job.step @source => [@destination, @second_destination]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Itiel::Load::ChainedStep do
|
4
|
+
before :each do
|
5
|
+
klass = Class.new
|
6
|
+
klass.send :include, Itiel::Load::ChainedStep
|
7
|
+
|
8
|
+
@step = klass.new
|
9
|
+
end
|
10
|
+
|
11
|
+
it "defines next_step" do
|
12
|
+
expect(@step).to respond_to(:next_step)
|
13
|
+
expect(@step).to respond_to(:next_step=)
|
14
|
+
end
|
15
|
+
|
16
|
+
describe :persist do
|
17
|
+
it "raises an error if undefined" do
|
18
|
+
expect { @step.persist([]) }.to raise_error Itiel::MethodNotImplementedException
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe :input= do
|
23
|
+
before :each do
|
24
|
+
@next_step = double
|
25
|
+
@input = [ double ]
|
26
|
+
@step.next_step = @next_step
|
27
|
+
|
28
|
+
expect(Itiel::Logger).to receive(:log_received).with(@step, @input.size)
|
29
|
+
expect(Itiel::Logger).to receive(:log_processed).with(@step, @input.size)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "calls persist with the stream received through input= and sends it to next_step" do
|
33
|
+
expect(@step).to receive(:persist).with @input
|
34
|
+
expect(@next_step).to receive(:input=).with @input
|
35
|
+
@step.input = @input
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Itiel::Load::CSVFile do
|
4
|
+
before :each do
|
5
|
+
@filename = File.expand_path("#{File.dirname(__FILE__)}/../../tmp/output.csv")
|
6
|
+
File.unlink(@filename) if File.exist?(@filename)
|
7
|
+
|
8
|
+
@input = [
|
9
|
+
{
|
10
|
+
"id" => 1,
|
11
|
+
"name" => "Subject Name"
|
12
|
+
},
|
13
|
+
{
|
14
|
+
"id" => 2,
|
15
|
+
"name" => "Subject Name"
|
16
|
+
}
|
17
|
+
]
|
18
|
+
|
19
|
+
@expected_result = [
|
20
|
+
[ "id" , "name" ] ,
|
21
|
+
[ "1" , "Subject Name" ] ,
|
22
|
+
[ "2" , "Subject Name" ]
|
23
|
+
]
|
24
|
+
|
25
|
+
@csv_output = Itiel::Load::CSVFile.new(@filename)
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "the file does not exist" do
|
29
|
+
before :each do
|
30
|
+
@csv_output.persist(@input)
|
31
|
+
@result = CSV.read(@filename, :headers => true)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "generates a CSV file with the input data" do
|
35
|
+
expect(@expected_result).to eq @result.to_a
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "the file already exists" do
|
40
|
+
before :each do
|
41
|
+
FileUtils.touch(@filename)
|
42
|
+
@csv_output.persist(@input)
|
43
|
+
@result = CSV.read(@filename)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "appends to the existing data" do
|
47
|
+
expect(@expected_result - [[ "id", "name" ]]).to eq @result
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "use append = false" do
|
52
|
+
before do
|
53
|
+
@csv_output = Itiel::Load::CSVFile.new(@filename, false)
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "the file already exists" do
|
57
|
+
before :each do
|
58
|
+
FileUtils.touch(@filename)
|
59
|
+
@csv_output.persist(@input)
|
60
|
+
@result = CSV.read(@filename)
|
61
|
+
end
|
62
|
+
|
63
|
+
it "replaces the existing file with the input data" do
|
64
|
+
expect(@expected_result).to eq @result
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Itiel::Load::DatabaseTable do
|
4
|
+
before(:each) do
|
5
|
+
@output = Itiel::Load::DatabaseTable.new :test, "users"
|
6
|
+
@input = [
|
7
|
+
{
|
8
|
+
"id" => "1",
|
9
|
+
"name" => "Some Name"
|
10
|
+
},
|
11
|
+
{
|
12
|
+
"id" => "2",
|
13
|
+
"name" => "Some Other Name"
|
14
|
+
},
|
15
|
+
]
|
16
|
+
end
|
17
|
+
|
18
|
+
it "inserts a record for each row" do
|
19
|
+
table = double
|
20
|
+
allow(@output).to receive(:table).and_return table
|
21
|
+
|
22
|
+
@input.each do |row|
|
23
|
+
expect(table).to receive(:insert).and_return row
|
24
|
+
end
|
25
|
+
|
26
|
+
@output.persist(@input)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Itiel::Lookup::HashLookup do
|
4
|
+
before(:each) do
|
5
|
+
@input = [
|
6
|
+
{
|
7
|
+
:id => 1,
|
8
|
+
:author => "Isaac"
|
9
|
+
},
|
10
|
+
{
|
11
|
+
:id => 2,
|
12
|
+
:author => "Carver"
|
13
|
+
}
|
14
|
+
]
|
15
|
+
|
16
|
+
@lookup_source = [
|
17
|
+
{
|
18
|
+
:id => 1,
|
19
|
+
:name => "Isaac",
|
20
|
+
:active => "t"
|
21
|
+
},
|
22
|
+
{
|
23
|
+
:id => 2,
|
24
|
+
:name => "Carver",
|
25
|
+
:active => "f"
|
26
|
+
}
|
27
|
+
]
|
28
|
+
|
29
|
+
@lookup_stream = {
|
30
|
+
"Isaac" => {
|
31
|
+
:author_id => 1,
|
32
|
+
:active => "t"
|
33
|
+
},
|
34
|
+
|
35
|
+
"Carver" => {
|
36
|
+
:author_id => 2,
|
37
|
+
:active => "f"
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
41
|
+
@expected_output = [
|
42
|
+
{
|
43
|
+
:id => 1,
|
44
|
+
:author => "Isaac",
|
45
|
+
:author_id => 1,
|
46
|
+
:active => "t"
|
47
|
+
},
|
48
|
+
{
|
49
|
+
:id => 2,
|
50
|
+
:author => "Carver",
|
51
|
+
:author_id => 2,
|
52
|
+
:active => "f"
|
53
|
+
}
|
54
|
+
]
|
55
|
+
|
56
|
+
class FooLookup
|
57
|
+
include Itiel::Lookup::HashLookup
|
58
|
+
end
|
59
|
+
|
60
|
+
@lookup = FooLookup.new
|
61
|
+
@lookup.lookup_columns = { "author" => "name" }
|
62
|
+
@lookup.joined_columns = { "id" => "author_id", "active" => "active" }
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "#lookup!" do
|
66
|
+
it "joins the data using the specified column" do
|
67
|
+
allow(@lookup).to receive(:lookup_stream).and_return @lookup_stream
|
68
|
+
expect(@expected_output).to eq @lookup.lookup!(@input)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "#lookup_stream" do
|
73
|
+
it do
|
74
|
+
allow(@lookup).to receive(:lookup_source).and_return @lookup_source
|
75
|
+
expect(@lookup_stream).to eq @lookup.lookup_stream
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe 'with nil values in the lookup column' do
|
80
|
+
before do
|
81
|
+
@input.append({ id: 3, author: nil })
|
82
|
+
@expected_output.append({ id: 3, author: nil, author_id: nil, active: nil })
|
83
|
+
end
|
84
|
+
|
85
|
+
describe "#lookup!" do
|
86
|
+
it 'joins the data setting the value to nil' do
|
87
|
+
allow(@lookup).to receive(:lookup_stream).and_return @lookup_stream
|
88
|
+
expect(@expected_output).to eq @lookup.lookup!(@input)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "When the lookup column doesn't exist in the input_stream" do
|
94
|
+
before do
|
95
|
+
@input.append({ id: 3 })
|
96
|
+
@expected_output.append({ id: 3, author_id: nil, active: nil })
|
97
|
+
end
|
98
|
+
|
99
|
+
describe "#lookup!" do
|
100
|
+
it 'joins the data setting the value to nil' do
|
101
|
+
allow(@lookup).to receive(:lookup_stream).and_return @lookup_stream
|
102
|
+
|
103
|
+
expect(@expected_output).to eq @lookup.lookup!(@input)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|