terrestrial 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.ruby-version +1 -1
- data/Gemfile.lock +44 -53
- data/README.md +3 -6
- data/bin/test +1 -1
- data/features/env.rb +12 -2
- data/features/example.feature +23 -26
- data/lib/terrestrial.rb +31 -0
- data/lib/terrestrial/adapters/abstract_adapter.rb +6 -0
- data/lib/terrestrial/adapters/memory_adapter.rb +82 -6
- data/lib/terrestrial/adapters/sequel_postgres_adapter.rb +191 -0
- data/lib/terrestrial/configurations/conventional_association_configuration.rb +65 -35
- data/lib/terrestrial/configurations/conventional_configuration.rb +280 -124
- data/lib/terrestrial/configurations/mapping_config_options_proxy.rb +97 -0
- data/lib/terrestrial/deleted_record.rb +12 -8
- data/lib/terrestrial/dirty_map.rb +17 -9
- data/lib/terrestrial/functional_pipeline.rb +64 -0
- data/lib/terrestrial/inspection_string.rb +6 -1
- data/lib/terrestrial/lazy_object_proxy.rb +1 -0
- data/lib/terrestrial/many_to_many_association.rb +34 -20
- data/lib/terrestrial/many_to_one_association.rb +11 -3
- data/lib/terrestrial/one_to_many_association.rb +9 -0
- data/lib/terrestrial/public_conveniencies.rb +65 -82
- data/lib/terrestrial/record.rb +106 -0
- data/lib/terrestrial/relation_mapping.rb +43 -12
- data/lib/terrestrial/relational_store.rb +33 -11
- data/lib/terrestrial/upsert_record.rb +54 -0
- data/lib/terrestrial/version.rb +1 -1
- data/spec/automatic_timestamps_spec.rb +339 -0
- data/spec/changes_api_spec.rb +81 -0
- data/spec/config_override_spec.rb +28 -19
- data/spec/custom_serializers_spec.rb +3 -2
- data/spec/database_default_fields_spec.rb +213 -0
- data/spec/database_generated_id_spec.rb +291 -0
- data/spec/database_owned_fields_and_timestamps_spec.rb +200 -0
- data/spec/deletion_spec.rb +1 -1
- data/spec/error_handling/factory_error_handling_spec.rb +1 -4
- data/spec/error_handling/serialization_error_spec.rb +1 -4
- data/spec/error_handling/upsert_error_spec.rb +7 -11
- data/spec/graph_persistence_spec.rb +52 -18
- data/spec/ordered_association_spec.rb +10 -12
- data/spec/predefined_queries_spec.rb +14 -12
- data/spec/readme_examples_spec.rb +1 -1
- data/spec/sequel_query_efficiency_spec.rb +19 -16
- data/spec/spec_helper.rb +6 -1
- data/spec/support/blog_schema.rb +7 -3
- data/spec/support/object_graph_setup.rb +30 -39
- data/spec/support/object_store_setup.rb +16 -196
- data/spec/support/seed_data_setup.rb +15 -149
- data/spec/support/seed_records.rb +141 -0
- data/spec/support/sequel_test_support.rb +46 -13
- data/spec/terrestrial/abstract_record_spec.rb +138 -106
- data/spec/terrestrial/adapters/sequel_postgres_adapter_spec.rb +138 -0
- data/spec/terrestrial/deleted_record_spec.rb +0 -27
- data/spec/terrestrial/dirty_map_spec.rb +52 -77
- data/spec/terrestrial/functional_pipeline_spec.rb +153 -0
- data/spec/terrestrial/inspection_string_spec.rb +61 -0
- data/spec/terrestrial/upsert_record_spec.rb +29 -0
- data/terrestrial.gemspec +7 -8
- metadata +43 -40
- data/MissingFeatures.md +0 -64
- data/lib/terrestrial/abstract_record.rb +0 -99
- data/lib/terrestrial/association_loaders.rb +0 -52
- data/lib/terrestrial/upserted_record.rb +0 -15
- data/spec/terrestrial/public_conveniencies_spec.rb +0 -63
- data/spec/terrestrial/upserted_record_spec.rb +0 -59
@@ -0,0 +1,138 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
require "terrestrial/adapters/sequel_postgres_adapter"
|
4
|
+
require "terrestrial/upsert_record"
|
5
|
+
|
6
|
+
RSpec.describe Terrestrial::Adapters::SequelPostgresAdapter, backend: "sequel" do
|
7
|
+
|
8
|
+
let(:adapter) { Terrestrial::Adapters::SequelPostgresAdapter.new(datastore) }
|
9
|
+
|
10
|
+
describe "#tables" do
|
11
|
+
it "returns all table names as symbols" do
|
12
|
+
expect(adapter.tables).to match_array(
|
13
|
+
[:users, :posts, :categories, :comments, :categories_to_posts]
|
14
|
+
)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "#primary_key" do
|
19
|
+
context "when the table has a regular primary key" do
|
20
|
+
let(:table_name) { :users }
|
21
|
+
it "returns the primary key field(s) for a table as an array of symbols" do
|
22
|
+
expect(adapter.primary_key(table_name)).to eq([:id])
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context "when the table has no primary key" do
|
27
|
+
let(:table_name) { :categories_to_posts }
|
28
|
+
|
29
|
+
it "returns an empty array" do
|
30
|
+
expect(adapter.primary_key(table_name)).to eq([])
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "#unique_indexes" do
|
36
|
+
before(:all) do
|
37
|
+
adapter_support.create_tables(schema_with_unique_index.fetch(:tables))
|
38
|
+
adapter_support.add_unique_indexes(schema_with_unique_index.fetch(:unique_indexes))
|
39
|
+
end
|
40
|
+
|
41
|
+
after(:all) do
|
42
|
+
adapter_support.drop_tables(schema_with_unique_index.fetch(:tables).keys)
|
43
|
+
end
|
44
|
+
|
45
|
+
before(:each) { adapter_support.clean_table(:unique_index_table) }
|
46
|
+
|
47
|
+
context "when the table has no primary key" do
|
48
|
+
let(:table_name) { :unique_index_table }
|
49
|
+
|
50
|
+
it "returns an array of the indexed fields" do
|
51
|
+
expect(adapter.unique_indexes(table_name)).to eq([
|
52
|
+
[:field_one, :field_two]
|
53
|
+
])
|
54
|
+
end
|
55
|
+
|
56
|
+
context "when there is no conflicting row" do
|
57
|
+
let(:record) {
|
58
|
+
create_record(field_one: "1", field_two: "2", text: "initial value")
|
59
|
+
}
|
60
|
+
|
61
|
+
it "upserts resulting in a new row" do
|
62
|
+
expect { adapter.upsert(record) }
|
63
|
+
.to change { datastore[:unique_index_table].count }
|
64
|
+
.by(1)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context "when a conflicting row" do
|
69
|
+
let(:updated_record) {
|
70
|
+
create_record(field_one: "1", field_two: "2", text: "new value")
|
71
|
+
}
|
72
|
+
|
73
|
+
before do
|
74
|
+
record = create_record(field_one: "1", field_two: "2", text: "initial value")
|
75
|
+
adapter.upsert(record)
|
76
|
+
end
|
77
|
+
|
78
|
+
it "upserts, updating the existing row" do
|
79
|
+
expect { adapter.upsert(updated_record) }
|
80
|
+
.to change { datastore[:unique_index_table].count }
|
81
|
+
.by(0)
|
82
|
+
|
83
|
+
expect(adapter[:unique_index_table].first.fetch(:text)).to eq("new value")
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def create_record(values)
|
89
|
+
Terrestrial::UpsertRecord.new(
|
90
|
+
mapping,
|
91
|
+
object,
|
92
|
+
values,
|
93
|
+
0,
|
94
|
+
)
|
95
|
+
end
|
96
|
+
|
97
|
+
let(:object) { double(:object)
|
98
|
+
}
|
99
|
+
|
100
|
+
let(:mapping) {
|
101
|
+
double(
|
102
|
+
:mapping,
|
103
|
+
namespace: :unique_index_table,
|
104
|
+
primary_key: [],
|
105
|
+
database_owned_fields: [],
|
106
|
+
database_default_fields: [],
|
107
|
+
post_save: nil,
|
108
|
+
)
|
109
|
+
}
|
110
|
+
|
111
|
+
context "when the has a primary key and no other indexes" do
|
112
|
+
let(:table_name) { :users }
|
113
|
+
|
114
|
+
it "returns an empty array" do
|
115
|
+
expect(adapter.unique_indexes(table_name)).to eq([])
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def adapter_support
|
120
|
+
Terrestrial::SequelTestSupport
|
121
|
+
end
|
122
|
+
|
123
|
+
def schema_with_unique_index
|
124
|
+
{
|
125
|
+
tables: {
|
126
|
+
unique_index_table: [
|
127
|
+
{ name: :field_one, type: String, options: { null: false } },
|
128
|
+
{ name: :field_two, type: String, options: { null: false } },
|
129
|
+
{ name: :text, type: String, options: { null: false } },
|
130
|
+
],
|
131
|
+
},
|
132
|
+
unique_indexes: [
|
133
|
+
[:unique_index_table, :field_one, :field_two]
|
134
|
+
],
|
135
|
+
}
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
@@ -29,31 +29,4 @@ RSpec.describe Terrestrial::DeletedRecord do
|
|
29
29
|
}.to yield_with_args(record)
|
30
30
|
end
|
31
31
|
end
|
32
|
-
|
33
|
-
describe "#==" do
|
34
|
-
context "with another record that deletes" do
|
35
|
-
let(:comparitor) {
|
36
|
-
record.merge({})
|
37
|
-
}
|
38
|
-
|
39
|
-
it "is equal" do
|
40
|
-
expect(record.==(comparitor)).to be(true)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
context "with another record that does not delete" do
|
45
|
-
let(:comparitor) {
|
46
|
-
Class.new(Terrestrial::AbstractRecord) do
|
47
|
-
protected
|
48
|
-
def operation
|
49
|
-
:something_else
|
50
|
-
end
|
51
|
-
end
|
52
|
-
}
|
53
|
-
|
54
|
-
it "is not equal" do
|
55
|
-
expect(record.==(comparitor)).to be(false)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
32
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
3
|
require "terrestrial/dirty_map"
|
4
|
-
require "terrestrial/
|
4
|
+
require "terrestrial/upsert_record"
|
5
5
|
require "terrestrial/deleted_record"
|
6
6
|
|
7
7
|
RSpec.describe Terrestrial::DirtyMap do
|
@@ -11,13 +11,24 @@ RSpec.describe Terrestrial::DirtyMap do
|
|
11
11
|
|
12
12
|
let(:storage) { {} }
|
13
13
|
|
14
|
-
let(:record) {
|
15
|
-
|
14
|
+
let(:record) { create_record(mapping, attributes) }
|
15
|
+
let(:dirty_record) {
|
16
|
+
create_record( mapping, attributes.merge(name: "record/dirty_name"))
|
17
|
+
}
|
18
|
+
|
19
|
+
let(:mapping) {
|
20
|
+
double(
|
21
|
+
:mapping,
|
22
|
+
namespace: namespace,
|
23
|
+
primary_key: identity_fields,
|
24
|
+
database_owned_fields: [],
|
25
|
+
database_default_fields: [],
|
26
|
+
)
|
16
27
|
}
|
17
28
|
|
18
29
|
let(:namespace) { :table_name }
|
19
30
|
let(:identity_fields) { [:id] }
|
20
|
-
let(:
|
31
|
+
let(:identity) { { id: "record/id" } }
|
21
32
|
|
22
33
|
let(:attributes) {
|
23
34
|
{
|
@@ -72,22 +83,9 @@ RSpec.describe Terrestrial::DirtyMap do
|
|
72
83
|
end
|
73
84
|
|
74
85
|
describe "#dirty" do
|
75
|
-
|
76
|
-
create_record(namespace, identity_fields, attributes, depth)
|
77
|
-
}
|
78
|
-
|
79
|
-
let(:dirty_record) {
|
80
|
-
create_record(
|
81
|
-
namespace,
|
82
|
-
identity_fields,
|
83
|
-
attributes.merge(name: "record/dirty_name"),
|
84
|
-
depth,
|
85
|
-
)
|
86
|
-
}
|
87
|
-
|
88
|
-
context "when the record has not been loaded (new record)" do
|
86
|
+
context "when the record has not been loaded (a new record)" do
|
89
87
|
it "return true" do
|
90
|
-
expect(dirty_map.dirty?(
|
88
|
+
expect(dirty_map.dirty?(record)).to be(true)
|
91
89
|
end
|
92
90
|
end
|
93
91
|
|
@@ -98,7 +96,7 @@ RSpec.describe Terrestrial::DirtyMap do
|
|
98
96
|
|
99
97
|
context "when the record is unchanged" do
|
100
98
|
it "returns false" do
|
101
|
-
expect(dirty_map.dirty?(
|
99
|
+
expect(dirty_map.dirty?(record)).to be(false)
|
102
100
|
end
|
103
101
|
end
|
104
102
|
|
@@ -110,12 +108,7 @@ RSpec.describe Terrestrial::DirtyMap do
|
|
110
108
|
|
111
109
|
context "when the record is deleted" do
|
112
110
|
let(:deleted_record) {
|
113
|
-
Terrestrial::DeletedRecord.new(
|
114
|
-
namespace,
|
115
|
-
identity_fields,
|
116
|
-
attributes,
|
117
|
-
depth,
|
118
|
-
)
|
111
|
+
Terrestrial::DeletedRecord.new(mapping, attributes, _depth = 0)
|
119
112
|
}
|
120
113
|
|
121
114
|
it "is always dirty" do
|
@@ -125,32 +118,27 @@ RSpec.describe Terrestrial::DirtyMap do
|
|
125
118
|
|
126
119
|
context "when the record's attributes hash is mutated" do
|
127
120
|
before do
|
128
|
-
attributes.merge!(name: "new_value")
|
121
|
+
record.attributes.merge!(name: "new_value")
|
129
122
|
end
|
130
123
|
|
131
124
|
it "returns true" do
|
132
|
-
expect(dirty_map.dirty?(
|
125
|
+
expect(dirty_map.dirty?(record)).to be(true)
|
133
126
|
end
|
134
127
|
end
|
135
128
|
|
136
129
|
context "when a record's string value is mutated" do
|
137
130
|
before do
|
138
|
-
attributes.fetch(:name) << "MUTANT"
|
131
|
+
record.attributes.fetch(:name) << "MUTANT"
|
139
132
|
end
|
140
133
|
|
141
134
|
it "returns true" do
|
142
|
-
expect(dirty_map.dirty?(
|
135
|
+
expect(dirty_map.dirty?(record)).to be(true)
|
143
136
|
end
|
144
137
|
end
|
145
138
|
|
146
139
|
context "when record contains an unchanged subset of the fields loaded" do
|
147
140
|
let(:partial_record) {
|
148
|
-
create_record(
|
149
|
-
namespace,
|
150
|
-
identity_fields,
|
151
|
-
partial_clean_attrbiutes,
|
152
|
-
depth,
|
153
|
-
)
|
141
|
+
create_record(mapping, partial_clean_attrbiutes)
|
154
142
|
}
|
155
143
|
|
156
144
|
let(:partial_clean_attrbiutes) {
|
@@ -164,12 +152,7 @@ RSpec.describe Terrestrial::DirtyMap do
|
|
164
152
|
|
165
153
|
context "when record contains a changed subset of the fields loaded" do
|
166
154
|
let(:partial_record) {
|
167
|
-
create_record(
|
168
|
-
namespace,
|
169
|
-
identity_fields,
|
170
|
-
partial_dirty_attrbiutes,
|
171
|
-
depth,
|
172
|
-
)
|
155
|
+
create_record(mapping, partial_dirty_attrbiutes)
|
173
156
|
}
|
174
157
|
|
175
158
|
let(:partial_dirty_attrbiutes) {
|
@@ -185,12 +168,7 @@ RSpec.describe Terrestrial::DirtyMap do
|
|
185
168
|
|
186
169
|
context "when record contains an unchanged superset of the fields loaded" do
|
187
170
|
let(:super_record) {
|
188
|
-
create_record(
|
189
|
-
namespace,
|
190
|
-
identity_fields,
|
191
|
-
super_clean_attributes,
|
192
|
-
depth,
|
193
|
-
)
|
171
|
+
create_record(mapping, super_clean_attributes)
|
194
172
|
}
|
195
173
|
|
196
174
|
let(:super_clean_attributes) {
|
@@ -202,45 +180,42 @@ RSpec.describe Terrestrial::DirtyMap do
|
|
202
180
|
end
|
203
181
|
end
|
204
182
|
end
|
183
|
+
end
|
205
184
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
end
|
185
|
+
describe "#reject_unchanged_fields" do
|
186
|
+
context "when the record has not been loaded (new record)" do
|
187
|
+
it "returns an eqiuivalent record" do
|
188
|
+
expect(dirty_map.reject_unchanged_fields(dirty_record))
|
189
|
+
.to eq(dirty_record)
|
212
190
|
end
|
191
|
+
end
|
213
192
|
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
193
|
+
context "when a record with same identity has been loaded (existing record)" do
|
194
|
+
before do
|
195
|
+
dirty_map.load(record)
|
196
|
+
end
|
197
|
+
|
198
|
+
let(:dup_record) { create_record(mapping, attributes) }
|
218
199
|
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
end
|
200
|
+
context "with a equivalent record" do
|
201
|
+
it "returns an empty record" do
|
202
|
+
expect(dirty_map.reject_unchanged_fields(dup_record)).to be_empty
|
223
203
|
end
|
204
|
+
end
|
224
205
|
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
end
|
206
|
+
context "a record with a changed field" do
|
207
|
+
it "returns a record containing just that field" do
|
208
|
+
expect(
|
209
|
+
dirty_map
|
210
|
+
.reject_unchanged_fields(dirty_record)
|
211
|
+
.updatable_attributes
|
212
|
+
).to eq( name: "record/dirty_name" )
|
233
213
|
end
|
234
214
|
end
|
235
215
|
end
|
236
216
|
end
|
237
217
|
|
238
|
-
def create_record(
|
239
|
-
Terrestrial::
|
240
|
-
namespace,
|
241
|
-
identity_fields,
|
242
|
-
attributes,
|
243
|
-
depth,
|
244
|
-
)
|
218
|
+
def create_record(mapping, attributes)
|
219
|
+
Terrestrial::Record.new(mapping, attributes)
|
245
220
|
end
|
246
221
|
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
require "terrestrial/functional_pipeline"
|
2
|
+
RSpec.describe Terrestrial::FunctionalPipeline do
|
3
|
+
subject(:pipeline) { Terrestrial::FunctionalPipeline.new }
|
4
|
+
|
5
|
+
let(:input) { double(:input) }
|
6
|
+
let(:step1) { double(:step1, call: "step1_result") }
|
7
|
+
let(:step2) { double(:step2, call: "step2_result") }
|
8
|
+
let(:step3) { double(:step3, call: "step3_result") }
|
9
|
+
|
10
|
+
describe "#append" do
|
11
|
+
it "returns a new pipeline" do
|
12
|
+
expect(pipeline.append(:step1, step1)).not_to be(pipeline)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "appends a step to the existing steps" do
|
16
|
+
p1 = pipeline.append(:step1, step1)
|
17
|
+
result, _ = p1.call(input)
|
18
|
+
|
19
|
+
expect(result).to eq("step1_result")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context "three step pipeline" do
|
24
|
+
let(:pipeline) do
|
25
|
+
Terrestrial::FunctionalPipeline.from_array(
|
26
|
+
[
|
27
|
+
[:step1, step1],
|
28
|
+
[:step2, step2],
|
29
|
+
[:step3, step3],
|
30
|
+
]
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "#call" do
|
35
|
+
it "calls the first step with the input" do
|
36
|
+
pipeline.call(input)
|
37
|
+
|
38
|
+
expect(step1).to have_received(:call).with(input)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "calls the second step with the result of the first" do
|
42
|
+
pipeline.call(input)
|
43
|
+
|
44
|
+
expect(step2).to have_received(:call).with("step1_result")
|
45
|
+
end
|
46
|
+
|
47
|
+
it "calls the thrid step with the result of the second" do
|
48
|
+
pipeline.call(input)
|
49
|
+
|
50
|
+
expect(step3).to have_received(:call).with("step2_result")
|
51
|
+
end
|
52
|
+
|
53
|
+
it "returns the result of the last step" do
|
54
|
+
result, _ = pipeline.call(input)
|
55
|
+
|
56
|
+
expect(result).to eq("step3_result")
|
57
|
+
end
|
58
|
+
|
59
|
+
it "returns the intermediate results of all steps" do
|
60
|
+
_, intermediates = pipeline.call(input)
|
61
|
+
|
62
|
+
expect(intermediates).to eq([
|
63
|
+
[:input, input],
|
64
|
+
[:step1, "step1_result"],
|
65
|
+
[:step2, "step2_result"],
|
66
|
+
[:step3, "step3_result"],
|
67
|
+
])
|
68
|
+
end
|
69
|
+
|
70
|
+
context "when called with a block" do
|
71
|
+
it "yields the result of each step to the block" do
|
72
|
+
yielded = []
|
73
|
+
|
74
|
+
pipeline.call(input) do |name, result|
|
75
|
+
yielded << [name, result]
|
76
|
+
end
|
77
|
+
|
78
|
+
expect(yielded).to eq([
|
79
|
+
[:step1, "step1_result"],
|
80
|
+
[:step2, "step2_result"],
|
81
|
+
[:step3, "step3_result"],
|
82
|
+
])
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe "#describe" do
|
88
|
+
it "returns the list of named steps" do
|
89
|
+
expect(pipeline.describe).to eq([:step1, :step2, :step3])
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "#take_until" do
|
94
|
+
it "returns a new a pipeline" do
|
95
|
+
expect(pipeline.take_until(:step2)).to be_a(Terrestrial::FunctionalPipeline)
|
96
|
+
end
|
97
|
+
|
98
|
+
describe "the new pipeline" do
|
99
|
+
subject(:new_pipeline) { pipeline.take_until(:step2) }
|
100
|
+
|
101
|
+
it "contains steps from the beginning up to specified step" do
|
102
|
+
expect(new_pipeline.describe).to eq([:step1, :step2])
|
103
|
+
end
|
104
|
+
|
105
|
+
context "when executed" do
|
106
|
+
it "returns the result of the steps" do
|
107
|
+
result, _ = new_pipeline.call(input)
|
108
|
+
|
109
|
+
expect(result).to eq("step2_result")
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe "#drop_until" do
|
116
|
+
it "returns a new a pipeline" do
|
117
|
+
expect(pipeline.drop_until(:step2)).to be_a(Terrestrial::FunctionalPipeline)
|
118
|
+
end
|
119
|
+
|
120
|
+
describe "the new pipeline" do
|
121
|
+
subject(:new_pipeline) { pipeline.drop_until(:step2) }
|
122
|
+
|
123
|
+
it "contains steps that appear before the specified step" do
|
124
|
+
expect(new_pipeline.describe).to eq([:step3])
|
125
|
+
end
|
126
|
+
|
127
|
+
context "when executed" do
|
128
|
+
it "starts execution with the step after the specified one" do
|
129
|
+
result, _ = new_pipeline.call(input)
|
130
|
+
|
131
|
+
expect(step3).to have_received(:call).with(input)
|
132
|
+
end
|
133
|
+
|
134
|
+
it "does not execute steps dropped from the original pipeline" do
|
135
|
+
result, _ = new_pipeline.call(input)
|
136
|
+
|
137
|
+
expect(step1).not_to have_received(:call)
|
138
|
+
expect(step2).not_to have_received(:call)
|
139
|
+
end
|
140
|
+
|
141
|
+
it "returns the result of the steps" do
|
142
|
+
result, _ = new_pipeline.call(input)
|
143
|
+
|
144
|
+
expect(result).to eq("step3_result")
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
describe "#each" do
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|