protobuf-activerecord 1.2.6 → 2.0.0.beta

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.
@@ -3,6 +3,60 @@ require 'spec_helper'
3
3
  describe Protoable::Serialization do
4
4
  let(:protobuf_message) { UserMessage }
5
5
 
6
+ describe "._protobuf_convert_attributes_to_fields" do
7
+ context "when the column type is :date" do
8
+ let(:date) { Date.current }
9
+ let(:integer) { date.to_time.to_i }
10
+
11
+ before { User.stub(:_protobuf_date_column?).and_return(true) }
12
+
13
+ it "converts the given value to an integer" do
14
+ User._protobuf_convert_attributes_to_fields(:foo_date, date).should eq integer
15
+ end
16
+ end
17
+
18
+ context "when the column type is :datetime" do
19
+ let(:datetime) { DateTime.current }
20
+ let(:integer) { datetime.to_time.to_i }
21
+
22
+ before { User.stub(:_protobuf_datetime_column?).and_return(true) }
23
+
24
+ it "converts the given value to an integer" do
25
+ User._protobuf_convert_attributes_to_fields(:foo_datetime, datetime).should eq integer
26
+ end
27
+ end
28
+
29
+ context "when the column type is :time" do
30
+ let(:time) { Time.current }
31
+ let(:integer) { time.to_time.to_i }
32
+
33
+ before { User.stub(:_protobuf_time_column?).and_return(true) }
34
+
35
+ it "converts the given value to an integer" do
36
+ User._protobuf_convert_attributes_to_fields(:foo_time, time).should eq integer
37
+ end
38
+ end
39
+
40
+ context "when the column type is :timestamp" do
41
+ let(:timestamp) { Time.current }
42
+ let(:integer) { timestamp.to_time.to_i }
43
+
44
+ before { User.stub(:_protobuf_timestamp_column?).and_return(true) }
45
+
46
+ it "converts the given value to an integer" do
47
+ User._protobuf_convert_attributes_to_fields(:foo_timestamp, timestamp).should eq integer
48
+ end
49
+ end
50
+
51
+ context "when no conversion is necessary" do
52
+ let(:value) { "Foo" }
53
+
54
+ it "returns the given value" do
55
+ User._protobuf_convert_attributes_to_fields(:foo, value).should eq value
56
+ end
57
+ end
58
+ end
59
+
6
60
  describe ".field_from_record" do
7
61
  context "when the given converter is a symbol" do
8
62
  let(:callable) { lambda { |value| User.__send__(:extract_first_name) } }
@@ -35,87 +89,117 @@ describe Protoable::Serialization do
35
89
  end
36
90
  end
37
91
 
38
- describe ".protoable_attribute" do
39
- context "when the given converter is a hash" do
40
- let(:method) { lambda { |value| User.__send__(:convert_base64_to_string, value) } }
92
+ describe ".protobuf_message" do
93
+ let(:options) { { :only => [] } }
41
94
 
42
- before { User.protoable_attribute :public_key, :from => :base64, :to => :string }
95
+ before { User.protobuf_message(protobuf_message, options) }
96
+ after { User.protobuf_message(protobuf_message, {}) }
43
97
 
44
- it "determines the method using the hash's :to and :from keys" do
45
- User.should_receive(:convert_base64_to_string)
46
- User._protobuf_attribute_converters[:public_key].call(1)
98
+ context "given a value" do
99
+ it "defines #to_proto" do
100
+ User.allocate.should respond_to :to_proto
47
101
  end
48
102
  end
49
103
 
50
- context "when the given converter is a symbol" do
51
- let(:callable) { lambda { |value| User.__send__(:convert_email_to_lowercase, value) } }
104
+ context "given options" do
105
+ it "merges them with protobuf field options" do
106
+ User._protobuf_field_options.should eq options
107
+ end
108
+ end
109
+
110
+ it "returns the protobuf message for this object" do
111
+ User.protobuf_message.should eq protobuf_message
112
+ end
113
+ end
52
114
 
53
- before { User.protoable_attribute :email, :convert_email_to_lowercase }
115
+ context "when protobuf_message is defined" do
116
+ let(:attributes) { Hash.new }
117
+ let(:user) { User.new(attributes) }
54
118
 
55
- it "creates a callable method object from the converter" do
56
- User.should_receive(:convert_email_to_lowercase)
57
- User._protobuf_attribute_converters[:email].call(1)
119
+ before { User.protobuf_message(protobuf_message) }
120
+
121
+ describe "#_filter_field_attributes" do
122
+ context "when options has :only" do
123
+ it "only returns the given field(s)" do
124
+ fields = user._filter_field_attributes(:only => :name).should
125
+ fields.should eq [ :name ]
126
+ end
58
127
  end
59
- end
60
128
 
61
- context "when the given converter is not callable" do
62
- it "raises an exception" do
63
- expect { User.protoable_attribute :email, nil }.to raise_exception(Protoable::AttributeConverterError)
129
+ context "when options has :except" do
130
+ it "returns all except the given field(s)" do
131
+ fields = user._filter_field_attributes(:except => :name).should
132
+ fields.should eq [ :guid, :email, :email_domain ]
133
+ end
64
134
  end
65
135
  end
66
136
 
67
- context "when the given converter is callable" do
68
- let(:callable) { lambda { |value| value } }
69
-
70
- before { User.protoable_attribute :email, callable }
137
+ describe "#_filtered_fields" do
138
+ it "returns protobuf fields" do
139
+ user._filtered_fields.should eq [ :guid, :name, :email, :email_domain ]
140
+ end
71
141
 
72
- it "adds the given converter to list of attribute converters" do
73
- User._protobuf_attribute_converters[:email].should eq callable
142
+ context "given :deprecated => false" do
143
+ it "filters all deprecated fields" do
144
+ fields = user._filtered_fields(:deprecated => false).should
145
+ fields.should eq [ :guid, :name, :email ]
146
+ end
74
147
  end
75
148
  end
76
- end
77
149
 
78
- describe ".protobuf_message" do
79
- before { User.protobuf_message(protobuf_message) }
150
+ describe "#_normalize_options" do
151
+ let(:options) { { :only => [ :name ] } }
80
152
 
81
- context "given a value" do
82
- let(:protobuf_fields) { [ :guid, :name, :email, :email_domain ] }
153
+ context "given empty options" do
154
+ before { User.protobuf_message(protobuf_message, options) }
83
155
 
84
- it "sets .protobuf_fields" do
85
- User.protobuf_fields.should =~ protobuf_fields
156
+ it "returns the class's protobuf field options" do
157
+ User.allocate._normalize_options({}).should eq options
158
+ end
86
159
  end
87
160
 
88
- it "defines #to_proto" do
89
- User.allocate.should respond_to :to_proto
161
+ context "given options" do
162
+ before { User.protobuf_message(protobuf_message, {}) }
163
+
164
+ it "merges them with the class's protobuf field options" do
165
+ normalized_options = User.allocate._normalize_options(options)
166
+ normalized_options[:only].should eq options[:only]
167
+ end
90
168
  end
91
169
 
92
- it "defines #to_proto_hash" do
93
- User.allocate.should respond_to :to_proto_hash
170
+ context "given options with :only" do
171
+ before { User.protobuf_message(protobuf_message, {}) }
172
+
173
+ it "ensures that :except exists" do
174
+ normalized_options = User.allocate._normalize_options(options)
175
+ normalized_options[:except].should eq []
176
+ end
94
177
  end
95
- end
96
178
 
97
- it "returns the protobuf message for this object" do
98
- User.protobuf_message.should eq protobuf_message
99
- end
100
- end
179
+ context "given options with :except" do
180
+ let(:options) { { :except => [ :name ] } }
101
181
 
102
- context "when protobuf_message is defined" do
103
- let(:attributes) { Hash.new }
104
- let(:user) { User.new(attributes) }
182
+ before { User.protobuf_message(protobuf_message, {}) }
105
183
 
106
- before { User.protobuf_message(protobuf_message) }
184
+ it "ensures that :only exists" do
185
+ normalized_options = User.allocate._normalize_options(options)
186
+ normalized_options[:only].should eq []
187
+ end
188
+ end
189
+ end
107
190
 
108
- describe "#protoable_attributes" do
109
- context "when a transformer is defined for the field" do
110
- let(:attributes) {
111
- {
112
- :guid => "foo",
113
- :first_name => "bar",
114
- :last_name => "baz",
115
- :email => "foo@test.co"
116
- }
191
+ describe "#fields_from_record" do
192
+ let(:attributes) {
193
+ {
194
+ :guid => "foo",
195
+ :first_name => "bar",
196
+ :last_name => "baz",
197
+ :email => "foo@test.co"
117
198
  }
118
- let(:protoable_attributes) { { :guid => user.guid, :name => user.name, :email => user.email, :email_domain => 'test.co' } }
199
+ }
200
+
201
+ context "when a transformer is defined for the field" do
202
+ let(:fields_from_record) { { :guid => user.guid, :name => user.name, :email => user.email, :email_domain => 'test.co' } }
119
203
  let(:transformer) { { :email_domain => lambda { |record| record.email.split('@').last } } }
120
204
 
121
205
  before {
@@ -123,28 +207,27 @@ describe Protoable::Serialization do
123
207
  }
124
208
 
125
209
  it "gets the field from the transformer" do
126
- user.protoable_attributes.should eq protoable_attributes
210
+ user.fields_from_record.should eq fields_from_record
127
211
  end
128
212
  end
129
213
 
130
214
  context "when a transformer is not defined for the field" do
131
- let(:attributes) {
132
- {
133
- :guid => "foo",
134
- :first_name => "bar",
135
- :last_name => "baz",
136
- :email => "foo@test.co"
137
- }
138
- }
139
- let(:protoable_attributes) { { :guid => user.guid, :name => user.name, :email => user.email, :email_domain => nil } }
215
+ let(:fields_from_record) { { :guid => user.guid, :name => user.name, :email => user.email, :email_domain => nil } }
140
216
 
141
217
  it "returns a hash of protobuf fields that this object has getters for" do
142
- user.protoable_attributes.should eq protoable_attributes
218
+ user.fields_from_record.should eq fields_from_record
143
219
  end
144
220
 
145
221
  it "converts attributes values for protobuf messages" do
146
222
  user.should_receive(:_protobuf_convert_attributes_to_fields).any_number_of_times
147
- user.protoable_attributes
223
+ user.fields_from_record
224
+ end
225
+ end
226
+
227
+ context "given options with :include" do
228
+ it "adds the given field to the list of serialized fields" do
229
+ fields = user.fields_from_record(:include => :token)
230
+ fields.include?(:token).should be_true
148
231
  end
149
232
  end
150
233
  end
@@ -153,21 +236,11 @@ describe Protoable::Serialization do
153
236
  let(:proto) { protobuf_message.new(proto_hash) }
154
237
  let(:proto_hash) { { :name => "foo" } }
155
238
 
156
- before { user.stub(:to_proto_hash).and_return(proto_hash) }
239
+ before { user.stub(:fields_from_record).and_return(proto_hash) }
157
240
 
158
241
  it "intializes a new protobuf message with attributes from #to_proto_hash" do
159
242
  user.to_proto.should eq proto
160
243
  end
161
244
  end
162
-
163
- describe "#to_proto_hash" do
164
- let(:proto_hash) { { :name => "foo" } }
165
-
166
- before { user.stub(:protoable_attributes).and_return(proto_hash) }
167
-
168
- it "returns #protoable_attributes" do
169
- user.to_proto_hash.should eq proto_hash
170
- end
171
- end
172
245
  end
173
246
  end
@@ -0,0 +1,214 @@
1
+ require 'spec_helper'
2
+
3
+ describe Protoable::Transformation do
4
+ let(:user) { User.new(user_attributes) }
5
+ let(:user_attributes) { { :first_name => 'foo', :last_name => 'bar', :email => 'foo@test.co' } }
6
+ let(:proto_hash) { { :name => 'foo bar', :email => 'foo@test.co' } }
7
+ let(:proto) { UserMessage.new(proto_hash) }
8
+
9
+ describe "._filter_attribute_fields" do
10
+ it "includes fields that have values" do
11
+ attribute_fields = User._filter_attribute_fields(proto)
12
+ attribute_fields[:email].should eq proto_hash[:email]
13
+ end
14
+
15
+ it "filters repeated fields" do
16
+ attribute_fields = User._filter_attribute_fields(proto)
17
+ attribute_fields.has_key?(:tags).should be_false
18
+ end
19
+
20
+ it "includes attributes that aren't fields, but have attribute transformers" do
21
+ User.stub(:_protobuf_attribute_transformers).and_return({ :account_id => :fetch_account_id })
22
+ attribute_fields = User._filter_attribute_fields(proto)
23
+ attribute_fields.has_key?(:account_id).should be_true
24
+ end
25
+ end
26
+
27
+ describe "._protobuf_convert_fields_to_columns" do
28
+ context "when the given field's corresponding column type is :date" do
29
+ let(:date) { Date.current }
30
+ let(:value) { date.to_time.to_i }
31
+
32
+ before { User.stub(:_protobuf_date_column?).and_return(true) }
33
+
34
+ it "converts the given value to a Date object" do
35
+ User._protobuf_convert_fields_to_columns(:foo_date, value).should eq date
36
+ end
37
+ end
38
+
39
+ context "when given field's corresponding the column type is :datetime" do
40
+ let(:datetime) { DateTime.current }
41
+ let(:value) { datetime.to_i }
42
+
43
+ before { User.stub(:_protobuf_datetime_column?).and_return(true) }
44
+
45
+ it "converts the given value to a DateTime object" do
46
+ User._protobuf_convert_fields_to_columns(:foo_datetime, value).should be_a(DateTime)
47
+ end
48
+
49
+ it "converts the given value to a DateTime object of the same value" do
50
+ User._protobuf_convert_fields_to_columns(:foo_datetime, value).should be_within(1).of(datetime)
51
+ end
52
+ end
53
+
54
+ context "when given field's corresponding the column type is :time" do
55
+ let(:time) { Time.current }
56
+ let(:value) { time.to_i }
57
+
58
+ before { User.stub(:_protobuf_time_column?).and_return(true) }
59
+
60
+ it "converts the given value to a Time object" do
61
+ User._protobuf_convert_fields_to_columns(:foo_time, value).should be_a(Time)
62
+ end
63
+
64
+ it "converts the given value to a Time object of the same value" do
65
+ User._protobuf_convert_fields_to_columns(:foo_time, value).should be_within(1).of(time)
66
+ end
67
+ end
68
+
69
+ context "when given field's corresponding the column type is :timestamp" do
70
+ let(:time) { Time.current }
71
+ let(:value) { time.to_i }
72
+
73
+ before { User.stub(:_protobuf_timestamp_column?).and_return(true) }
74
+
75
+ it "converts the given value to a Time object" do
76
+ User._protobuf_convert_fields_to_columns(:foo_time, value).should be_a(Time)
77
+ end
78
+
79
+ it "converts the given value to a Time object of the same value" do
80
+ User._protobuf_convert_fields_to_columns(:foo_timestamp, value).should be_within(1).of(time)
81
+ end
82
+ end
83
+
84
+ context "when no conversion is necessary" do
85
+ let(:value) { "Foo" }
86
+
87
+ it "returns the given value" do
88
+ User._protobuf_convert_fields_to_columns(:foo, value).should eq value
89
+ end
90
+ end
91
+ end
92
+
93
+ describe ".attributes_from_proto" do
94
+ context "when a transformer is defined for the attribute" do
95
+ it "transforms the field value" do
96
+ attribute_fields = User.attributes_from_proto(proto)
97
+ attribute_fields[:first_name].should eq user_attributes[:first_name]
98
+ end
99
+ end
100
+
101
+ context "when a transformer is a callable that returns nil" do
102
+ before do
103
+ transformers = User._protobuf_attribute_transformers
104
+ User.stub(:_protobuf_attribute_transformers).and_return(
105
+ {:account_id => lambda { |proto| nil }}.merge(transformers)
106
+ )
107
+ end
108
+
109
+ it "does not set the attribute" do
110
+ attribute_fields = User.attributes_from_proto(proto)
111
+ attribute_fields.should eq user_attributes
112
+ end
113
+ end
114
+
115
+ context "when a transformer is a callable that returns a value" do
116
+ before do
117
+ transformers = User._protobuf_attribute_transformers
118
+ User.stub(:_protobuf_attribute_transformers).and_return(
119
+ {:account_id => lambda { |proto| 1 }}.merge(transformers)
120
+ )
121
+ end
122
+
123
+ it "sets the attribute" do
124
+ attribute_fields = User.attributes_from_proto(proto)
125
+ attribute_fields.should eq user_attributes.merge(:account_id => 1)
126
+ end
127
+ end
128
+
129
+ context "when a transformer is not defined for the attribute" do
130
+ before {
131
+ User.stub(:_protobuf_convert_fields_to_columns) do |key, value|
132
+ value
133
+ end
134
+ }
135
+
136
+ it "converts the field value" do
137
+ attribute_fields = User.attributes_from_proto(proto)
138
+ attribute_fields.should eq user_attributes
139
+ end
140
+ end
141
+ end
142
+
143
+ describe ".attribute_from_proto" do
144
+ context "when the given transformer is a symbol" do
145
+ let(:callable) { lambda { |value| User.__send__(:extract_first_name) } }
146
+
147
+ before { User.attribute_from_proto :first_name, :extract_first_name }
148
+
149
+ it "creates a callable method object from the converter" do
150
+ User.should_receive(:extract_first_name)
151
+ User._protobuf_attribute_transformers[:first_name].call(1)
152
+ end
153
+ end
154
+
155
+ context "when the given transformer is not callable" do
156
+ it "raises an exception" do
157
+ expect { User.attribute_from_proto :name, nil }.to raise_exception(Protoable::AttributeTransformerError)
158
+ end
159
+ end
160
+
161
+ context "when the given transformer is callable" do
162
+ let(:callable) { lambda { |proto| nil } }
163
+
164
+ before {
165
+ User.stub(:_protobuf_attribute_transformers).and_return(Hash.new)
166
+ User.attribute_from_proto :account_id, callable
167
+ }
168
+
169
+ it "adds the given converter to the list of protobuf field transformers" do
170
+ User._protobuf_attribute_transformers[:account_id] = callable
171
+ end
172
+ end
173
+ end
174
+
175
+ describe ".convert_int64_to_date" do
176
+ let(:date) { Date.current }
177
+ let(:int64) { date.to_time.to_i }
178
+
179
+ it "initializes a new Date object from the value" do
180
+ Timecop.freeze(Date.current) do
181
+ User.convert_int64_to_date(int64).should eq date
182
+ end
183
+ end
184
+ end
185
+
186
+ describe ".convert_int64_to_datetime" do
187
+ let(:datetime) { DateTime.current }
188
+ let(:int64) { datetime.to_time.to_i }
189
+
190
+ it "initializes a new DateTime object from the value" do
191
+ Timecop.freeze(DateTime.current) do
192
+ User.convert_int64_to_datetime(int64).should eq datetime
193
+ end
194
+ end
195
+ end
196
+
197
+ describe ".convert_int64_to_time" do
198
+ let(:time) { Time.current }
199
+ let(:int64) { time.to_time.to_i }
200
+
201
+ it "initializes a new Time object from the value" do
202
+ Timecop.freeze(Time.current) do
203
+ User.convert_int64_to_time(int64).should be_within(1).of(time)
204
+ end
205
+ end
206
+ end
207
+
208
+ describe "#attributes_from_proto" do
209
+ it "gets attributes from the given protobuf message" do
210
+ User.should_receive(:attributes_from_proto).with(proto)
211
+ user.attributes_from_proto(proto)
212
+ end
213
+ end
214
+ end