active_remote 5.1.1 → 5.2.0.alpha
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/active_remote.gemspec +2 -2
- data/bin/benchmark +12 -5
- data/lib/active_remote/association.rb +7 -9
- data/lib/active_remote/attribute_methods.rb +51 -0
- data/lib/active_remote/base.rb +64 -14
- data/lib/active_remote/dirty.rb +4 -7
- data/lib/active_remote/integration.rb +112 -26
- data/lib/active_remote/persistence.rb +1 -1
- data/lib/active_remote/primary_key.rb +18 -0
- data/lib/active_remote/rpc.rb +3 -4
- data/lib/active_remote/search.rb +2 -1
- data/lib/active_remote/version.rb +1 -1
- data/spec/lib/active_remote/association_spec.rb +0 -16
- data/spec/lib/active_remote/dirty_spec.rb +14 -29
- data/spec/lib/active_remote/integration_spec.rb +80 -12
- data/spec/lib/active_remote/query_attribute_spec.rb +8 -17
- data/spec/lib/active_remote/rpc_spec.rb +5 -1
- data/spec/lib/active_remote/search_spec.rb +4 -3
- data/spec/support/models.rb +0 -1
- data/spec/support/models/author.rb +10 -6
- data/spec/support/models/category.rb +3 -3
- data/spec/support/models/default_author.rb +2 -2
- data/spec/support/models/post.rb +5 -5
- data/spec/support/models/tag.rb +4 -4
- metadata +10 -16
- data/lib/active_remote/attribute_definition.rb +0 -114
- data/lib/active_remote/attributes.rb +0 -204
- data/spec/lib/active_remote/attributes_spec.rb +0 -223
- data/spec/support/models/typecasted_author.rb +0 -8
@@ -48,7 +48,7 @@ module ActiveRemote
|
|
48
48
|
# Instantiate a record with the given remote attributes. Generally used
|
49
49
|
# when retrieving records that already exist, so @new_record is set to false.
|
50
50
|
#
|
51
|
-
def instantiate(new_attributes, options = {})
|
51
|
+
def instantiate(new_attributes = {}, options = {})
|
52
52
|
attributes = self.build_from_rpc(new_attributes)
|
53
53
|
new_object = self.allocate.init_with(attributes)
|
54
54
|
new_object.readonly! if options[:readonly]
|
@@ -32,5 +32,23 @@ module ActiveRemote
|
|
32
32
|
def primary_key
|
33
33
|
self.class.primary_key
|
34
34
|
end
|
35
|
+
|
36
|
+
# Returns an Array of all key attributes if any of the attributes is set, whether or not
|
37
|
+
# the object is persisted. Returns +nil+ if there are no key attributes.
|
38
|
+
#
|
39
|
+
# class Person
|
40
|
+
# include ActiveModel::Conversion
|
41
|
+
# attr_accessor :id
|
42
|
+
#
|
43
|
+
# def initialize(id)
|
44
|
+
# @id = id
|
45
|
+
# end
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# person = Person.new(1)
|
49
|
+
# person.to_key # => [1]
|
50
|
+
def to_key
|
51
|
+
send(primary_key) ? [send(primary_key)] : nil
|
52
|
+
end
|
35
53
|
end
|
36
54
|
end
|
data/lib/active_remote/rpc.rb
CHANGED
@@ -15,8 +15,8 @@ module ActiveRemote
|
|
15
15
|
def build_from_rpc(values)
|
16
16
|
values = values.stringify_keys
|
17
17
|
|
18
|
-
|
19
|
-
attributes
|
18
|
+
attribute_names.inject(_default_attributes.deep_dup) do |attributes, name|
|
19
|
+
attributes.write_from_database(name, values[name])
|
20
20
|
attributes
|
21
21
|
end
|
22
22
|
end
|
@@ -53,8 +53,7 @@ module ActiveRemote
|
|
53
53
|
end
|
54
54
|
|
55
55
|
def assign_attributes_from_rpc(response)
|
56
|
-
|
57
|
-
@attributes.update(new_attributes)
|
56
|
+
@attributes = self.class.build_from_rpc(response.to_hash)
|
58
57
|
add_errors(response.errors) if response.respond_to?(:errors)
|
59
58
|
end
|
60
59
|
|
data/lib/active_remote/search.rb
CHANGED
@@ -117,7 +117,8 @@ module ActiveRemote
|
|
117
117
|
#
|
118
118
|
def reload
|
119
119
|
fresh_object = self.class.find(scope_key_hash)
|
120
|
-
@attributes
|
120
|
+
@attributes = fresh_object.instance_variable_get("@attributes")
|
121
|
+
self
|
121
122
|
end
|
122
123
|
end
|
123
124
|
end
|
@@ -155,14 +155,6 @@ describe ActiveRemote::Association do
|
|
155
155
|
expect(subject.user_posts).to eq(records)
|
156
156
|
end
|
157
157
|
|
158
|
-
context "when user_guid doesnt exist on model " do
|
159
|
-
before { allow(subject).to receive(:respond_to?).with("user_guid").and_return(false) }
|
160
|
-
|
161
|
-
it "raises an error" do
|
162
|
-
expect { subject.user_posts }.to raise_error(::ActiveRemote::UnknownAttributeError)
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
158
|
context "when user_guid doesnt exist on associated model " do
|
167
159
|
before { allow(Post).to receive_message_chain(:public_instance_methods, :include?).with(:user_guid).and_return(false) }
|
168
160
|
|
@@ -251,14 +243,6 @@ describe ActiveRemote::Association do
|
|
251
243
|
expect(subject.chief_editor).to eq(record)
|
252
244
|
end
|
253
245
|
|
254
|
-
context "when user_guid doesnt exist on model " do
|
255
|
-
before { allow(subject).to receive(:respond_to?).with("user_guid").and_return(false) }
|
256
|
-
|
257
|
-
it "raises an error" do
|
258
|
-
expect { subject.chief_editor }.to raise_error(::ActiveRemote::UnknownAttributeError)
|
259
|
-
end
|
260
|
-
end
|
261
|
-
|
262
246
|
context "when user_guid doesnt exist on associated model " do
|
263
247
|
before { allow(Author).to receive_message_chain(:public_instance_methods, :include?).with(:user_guid).and_return(false) }
|
264
248
|
|
@@ -4,10 +4,10 @@ describe ActiveRemote::Dirty do
|
|
4
4
|
context "when writing attributes through the setter" do
|
5
5
|
subject { Post.new(:name => "foo") }
|
6
6
|
|
7
|
-
before
|
8
|
-
subject.
|
9
|
-
subject.
|
10
|
-
|
7
|
+
before do
|
8
|
+
subject.changes_applied
|
9
|
+
subject.clear_changes_information
|
10
|
+
end
|
11
11
|
|
12
12
|
context "when the value changes" do
|
13
13
|
before { subject.name = "bar" }
|
@@ -25,10 +25,10 @@ describe ActiveRemote::Dirty do
|
|
25
25
|
context "when writing attributes directly" do
|
26
26
|
subject { Post.new(:name => "foo") }
|
27
27
|
|
28
|
-
before
|
29
|
-
subject.
|
30
|
-
subject.
|
31
|
-
|
28
|
+
before do
|
29
|
+
subject.changes_applied
|
30
|
+
subject.clear_changes_information
|
31
|
+
end
|
32
32
|
|
33
33
|
context "when the value changes" do
|
34
34
|
before { subject[:name] = "bar" }
|
@@ -46,10 +46,10 @@ describe ActiveRemote::Dirty do
|
|
46
46
|
describe "#reload" do
|
47
47
|
subject { Post.new(:name => "foo") }
|
48
48
|
|
49
|
-
before
|
49
|
+
before do
|
50
50
|
allow(Post).to receive(:find).and_return(Post.new(:name => "foo"))
|
51
51
|
subject.reload
|
52
|
-
|
52
|
+
end
|
53
53
|
|
54
54
|
its(:changes) { should be_empty }
|
55
55
|
end
|
@@ -68,10 +68,10 @@ describe ActiveRemote::Dirty do
|
|
68
68
|
|
69
69
|
subject { Post.new(:name => "foo") }
|
70
70
|
|
71
|
-
before
|
71
|
+
before do
|
72
72
|
allow(subject).to receive(:create_or_update).and_return(true)
|
73
73
|
subject.save
|
74
|
-
|
74
|
+
end
|
75
75
|
|
76
76
|
its(:previous_changes) { should eq changes }
|
77
77
|
its(:changes) { should be_empty }
|
@@ -82,27 +82,12 @@ describe ActiveRemote::Dirty do
|
|
82
82
|
|
83
83
|
subject { Post.new(:name => "foo") }
|
84
84
|
|
85
|
-
before
|
85
|
+
before do
|
86
86
|
allow(subject).to receive(:save).and_return(true)
|
87
87
|
subject.save!
|
88
|
-
|
88
|
+
end
|
89
89
|
|
90
90
|
its(:previous_changes) { should eq changes }
|
91
91
|
its(:changes) { should be_empty }
|
92
92
|
end
|
93
|
-
|
94
|
-
describe "#instantiate" do
|
95
|
-
let(:post) { Post.new }
|
96
|
-
let(:record) { ::Generic::Remote::Post.new(:name => "foo") }
|
97
|
-
|
98
|
-
it "clears previous changes" do
|
99
|
-
new_record = post.instantiate(record.to_hash)
|
100
|
-
expect(new_record.previous_changes).to eq({})
|
101
|
-
end
|
102
|
-
|
103
|
-
it "clears changes" do
|
104
|
-
new_record = post.instantiate(record.to_hash)
|
105
|
-
expect(new_record.changes).to be_empty
|
106
|
-
end
|
107
|
-
end
|
108
93
|
end
|
@@ -2,37 +2,41 @@ require "spec_helper"
|
|
2
2
|
|
3
3
|
describe ::ActiveRemote::Integration do
|
4
4
|
let(:guid) { "GUID-derp" }
|
5
|
-
|
5
|
+
let(:tag) { ::Tag.new(:guid => guid) }
|
6
|
+
|
7
|
+
subject { tag }
|
8
|
+
|
9
|
+
context ".to_param" do
|
10
|
+
specify { expect(::Tag).to respond_to(:to_param) }
|
11
|
+
end
|
6
12
|
|
7
13
|
context "#to_param" do
|
8
|
-
# API
|
9
14
|
specify { expect(subject).to respond_to(:to_param) }
|
10
15
|
|
11
16
|
it "returns the guid if the guid is present (by default)" do
|
12
|
-
expect(
|
17
|
+
expect(tag.to_param).to eq(guid)
|
13
18
|
end
|
14
19
|
end
|
15
20
|
|
16
21
|
context "#cache_key" do
|
17
|
-
# API
|
18
22
|
specify { expect(subject).to respond_to(:cache_key) }
|
19
23
|
|
20
24
|
it "sets 'new' as the identifier when the record has not been persisted" do
|
21
|
-
expect(
|
22
|
-
expect(
|
25
|
+
expect(tag).to receive(:new_record?).and_return(true)
|
26
|
+
expect(tag.cache_key).to match(/tags\/new/)
|
23
27
|
end
|
24
28
|
|
25
29
|
it "sets the cache_key to the class/guid as a default" do
|
26
|
-
expect(
|
27
|
-
expect(
|
30
|
+
expect(tag).to receive(:new_record?).and_return(false)
|
31
|
+
expect(tag.cache_key).to eq("tags/#{guid}")
|
28
32
|
end
|
29
33
|
|
30
34
|
it "adds the 'updated_at' attribute to the cache_key if updated_at is present" do
|
31
35
|
::ActiveRemote.config.default_cache_key_updated_at = true
|
32
|
-
twenty_o_one_one =
|
33
|
-
expect(
|
34
|
-
expect(
|
35
|
-
|
36
|
+
twenty_o_one_one = tag.updated_at = DateTime.new(2001, 0o1, 0o1)
|
37
|
+
expect(tag).to receive(:new_record?).and_return(false)
|
38
|
+
expect(tag.cache_key).to eq("tags/#{guid}-#{twenty_o_one_one.to_s(:usec)}")
|
39
|
+
tag.updated_at = nil
|
36
40
|
::ActiveRemote.config.default_cache_key_updated_at = false
|
37
41
|
end
|
38
42
|
|
@@ -40,4 +44,68 @@ describe ::ActiveRemote::Integration do
|
|
40
44
|
expect(::ActiveRemote.config.default_cache_key_updated_at?).to be_falsey
|
41
45
|
end
|
42
46
|
end
|
47
|
+
|
48
|
+
describe "#cache_key_with_version" do
|
49
|
+
let(:tag) { ::Tag.new(:guid => guid, :updated_at => ::DateTime.current) }
|
50
|
+
|
51
|
+
specify { expect(subject).to respond_to(:cache_key_with_version) }
|
52
|
+
|
53
|
+
context "when cache versioning is enabled" do
|
54
|
+
around do |example|
|
55
|
+
cache_versioning_value = ::Tag.cache_versioning
|
56
|
+
::Tag.cache_versioning = true
|
57
|
+
example.run
|
58
|
+
::Tag.cache_versioning = cache_versioning_value
|
59
|
+
end
|
60
|
+
|
61
|
+
it "returns a cache key with the version" do
|
62
|
+
expect(tag.cache_version).to be_present
|
63
|
+
expect(tag.cache_key_with_version).to eq("#{tag.cache_key}-#{tag.cache_version}")
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context "when cache versioning is not enabled" do
|
68
|
+
around do |example|
|
69
|
+
cache_versioning_value = ::Tag.cache_versioning
|
70
|
+
::Tag.cache_versioning = false
|
71
|
+
example.run
|
72
|
+
::Tag.cache_versioning = cache_versioning_value
|
73
|
+
end
|
74
|
+
|
75
|
+
it "returns a cache key without the version" do
|
76
|
+
expect(tag.cache_key_with_version).to eq(tag.cache_key)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe "#cache_version" do
|
82
|
+
specify { expect(subject).to respond_to(:cache_version) }
|
83
|
+
|
84
|
+
context "when cache versioning is enabled" do
|
85
|
+
around do |example|
|
86
|
+
cache_versioning_value = ::Tag.cache_versioning
|
87
|
+
::Tag.cache_versioning = true
|
88
|
+
example.run
|
89
|
+
::Tag.cache_versioning = cache_versioning_value
|
90
|
+
end
|
91
|
+
|
92
|
+
it "returns a cache version" do
|
93
|
+
tag.updated_at = DateTime.new(2001, 0o1, 0o1)
|
94
|
+
expect(tag.cache_version).to eq(tag.updated_at.utc.to_s(:usec))
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
context "when cache versioning is not enabled" do
|
99
|
+
around do |example|
|
100
|
+
cache_versioning_value = ::Tag.cache_versioning
|
101
|
+
::Tag.cache_versioning = false
|
102
|
+
example.run
|
103
|
+
::Tag.cache_versioning = cache_versioning_value
|
104
|
+
end
|
105
|
+
|
106
|
+
it "returns nil" do
|
107
|
+
expect(tag.cache_version).to be_nil
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
43
111
|
end
|
@@ -4,18 +4,14 @@ describe ::ActiveRemote::QueryAttributes do
|
|
4
4
|
subject { ::Author.new }
|
5
5
|
|
6
6
|
describe "#query_attribute" do
|
7
|
-
it "raises when getting an undefined attribute" do
|
8
|
-
expect { subject.query_attribute(:foobar) }.to raise_error(::ActiveRemote::UnknownAttributeError)
|
9
|
-
end
|
10
|
-
|
11
7
|
it "is false when the attribute is false" do
|
12
|
-
subject.
|
13
|
-
expect(subject.
|
8
|
+
subject.writes_fiction = false
|
9
|
+
expect(subject.writes_fiction?).to eq false
|
14
10
|
end
|
15
11
|
|
16
12
|
it "is true when the attribute is true" do
|
17
|
-
subject.
|
18
|
-
expect(subject.
|
13
|
+
subject.writes_fiction = true
|
14
|
+
expect(subject.writes_fiction?).to eq true
|
19
15
|
end
|
20
16
|
|
21
17
|
it "is false when the attribute is nil" do
|
@@ -23,11 +19,6 @@ describe ::ActiveRemote::QueryAttributes do
|
|
23
19
|
expect(subject.name?).to eq false
|
24
20
|
end
|
25
21
|
|
26
|
-
it "is true when the attribute is an Object" do
|
27
|
-
subject.name = Object.new
|
28
|
-
expect(subject.name?).to eq true
|
29
|
-
end
|
30
|
-
|
31
22
|
it "is false when the attribute is an empty string" do
|
32
23
|
subject.name = ""
|
33
24
|
expect(subject.name?).to eq false
|
@@ -40,13 +31,13 @@ describe ::ActiveRemote::QueryAttributes do
|
|
40
31
|
|
41
32
|
# This behavior varies from ActiveRecord, so we test it explicitly
|
42
33
|
it "is true when the attribute is 0" do
|
43
|
-
subject.
|
44
|
-
expect(subject.
|
34
|
+
subject.age = 0
|
35
|
+
expect(subject.age?).to eq true
|
45
36
|
end
|
46
37
|
|
47
38
|
it "is true when the attribute is 1" do
|
48
|
-
subject.
|
49
|
-
expect(subject.
|
39
|
+
subject.age = 1
|
40
|
+
expect(subject.age?).to eq true
|
50
41
|
end
|
51
42
|
end
|
52
43
|
end
|
@@ -6,6 +6,10 @@ describe ::ActiveRemote::RPC do
|
|
6
6
|
describe ".build_from_rpc" do
|
7
7
|
let(:new_attributes) { { :name => "test" } }
|
8
8
|
|
9
|
+
it "dups the default attributes" do
|
10
|
+
expect { ::Tag.build_from_rpc(new_attributes) }.to_not change { ::Tag._default_attributes["name"] }
|
11
|
+
end
|
12
|
+
|
9
13
|
context "missing attributes from rpc" do
|
10
14
|
it "initializes to nil" do
|
11
15
|
expect(::Tag.build_from_rpc(new_attributes)).to include("guid" => nil)
|
@@ -25,7 +29,7 @@ describe ::ActiveRemote::RPC do
|
|
25
29
|
|
26
30
|
it "calls the typecasters" do
|
27
31
|
expect(
|
28
|
-
::
|
32
|
+
::Author.build_from_rpc(new_attributes)
|
29
33
|
).to include("birthday" => "2017-01-01".to_datetime)
|
30
34
|
end
|
31
35
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
3
|
describe ActiveRemote::Search do
|
4
|
-
let(:records) { [Generic::Remote::Tag.new] }
|
4
|
+
let(:records) { [Generic::Remote::Tag.new(:guid => "123")] }
|
5
5
|
let(:response) { Generic::Remote::Tags.new(:records => records) }
|
6
6
|
let(:rpc) { double(:rpc) }
|
7
7
|
|
@@ -37,7 +37,7 @@ describe ActiveRemote::Search do
|
|
37
37
|
end
|
38
38
|
|
39
39
|
describe ".search" do
|
40
|
-
let(:serialized_records) { [Tag.
|
40
|
+
let(:serialized_records) { [Tag.instantiate(:guid => "123")] }
|
41
41
|
|
42
42
|
context "given args that respond to :to_hash" do
|
43
43
|
let(:args) { {} }
|
@@ -52,7 +52,8 @@ describe ActiveRemote::Search do
|
|
52
52
|
end
|
53
53
|
|
54
54
|
it "returns records" do
|
55
|
-
|
55
|
+
records = Tag.search(args)
|
56
|
+
expect(records).to eq serialized_records
|
56
57
|
end
|
57
58
|
end
|
58
59
|
|
data/spec/support/models.rb
CHANGED
@@ -6,12 +6,16 @@ require "support/protobuf/author.pb"
|
|
6
6
|
class Author < ::ActiveRemote::Base
|
7
7
|
service_class ::Generic::Remote::AuthorService
|
8
8
|
|
9
|
-
attribute :guid
|
10
|
-
attribute :name
|
11
|
-
attribute :user_guid
|
12
|
-
attribute :chief_editor_guid
|
13
|
-
attribute :editor_guid
|
14
|
-
attribute :category_guid
|
9
|
+
attribute :guid, :string
|
10
|
+
attribute :name, :string
|
11
|
+
attribute :user_guid, :string
|
12
|
+
attribute :chief_editor_guid, :string
|
13
|
+
attribute :editor_guid, :string
|
14
|
+
attribute :category_guid, :string
|
15
|
+
attribute :age, :integer
|
16
|
+
attribute :birthday, :datetime
|
17
|
+
attribute :writes_fiction, :boolean
|
18
|
+
attribute :net_sales, :float
|
15
19
|
|
16
20
|
has_many :posts
|
17
21
|
has_many :user_posts, :class_name => "::Post", :scope => :user_guid
|
@@ -6,9 +6,9 @@ require "support/protobuf/category.pb"
|
|
6
6
|
class Category < ::ActiveRemote::Base
|
7
7
|
service_class ::Generic::Remote::CategoryService
|
8
8
|
|
9
|
-
attribute :guid
|
10
|
-
attribute :user_guid
|
11
|
-
attribute :chief_editor_guid
|
9
|
+
attribute :guid, :string
|
10
|
+
attribute :user_guid, :string
|
11
|
+
attribute :chief_editor_guid, :string
|
12
12
|
|
13
13
|
has_many :posts
|
14
14
|
|