protobuf-activerecord 1.0.1 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +91 -1
- data/lib/protoable/fields.rb +3 -0
- data/lib/protoable/persistence.rb +39 -8
- data/lib/protoable/serialization.rb +2 -0
- data/lib/protobuf/activerecord/version.rb +1 -1
- data/spec/protoable/persistence_spec.rb +4 -4
- metadata +4 -4
data/README.md
CHANGED
@@ -18,7 +18,97 @@ Or install it yourself as:
|
|
18
18
|
|
19
19
|
## Usage
|
20
20
|
|
21
|
-
|
21
|
+
Protobuf Active Record's functionality is contained within the `Protoable` module. To endow your Active Record models with the protoable behaviour, simply include it into your model:
|
22
|
+
|
23
|
+
```Ruby
|
24
|
+
|
25
|
+
class User < ActiveRecord::Base
|
26
|
+
include Protoable
|
27
|
+
|
28
|
+
# Your awesome methods...
|
29
|
+
#
|
30
|
+
end
|
31
|
+
|
32
|
+
```
|
33
|
+
|
34
|
+
Now you can pass protobuf messages to your user model just like you would attributes. Protoable will take care of converting the protobuf message to attributes and continue on with Active Record's normal behavior.
|
35
|
+
|
36
|
+
### Field/Attribute mapping
|
37
|
+
|
38
|
+
Just like Active Record maps database columns to your model's attributes, Protoable maps protobuf fields to your model's attributes.
|
39
|
+
|
40
|
+
Given a table that looks like this:
|
41
|
+
|
42
|
+
```Ruby
|
43
|
+
|
44
|
+
create_table :users do |t|
|
45
|
+
t.string :first_name
|
46
|
+
t.string :last_name
|
47
|
+
t.string :email
|
48
|
+
t.integer :account_id
|
49
|
+
|
50
|
+
t.timestamps
|
51
|
+
end
|
52
|
+
|
53
|
+
```
|
54
|
+
|
55
|
+
and a protobuf message that looks like this:
|
56
|
+
|
57
|
+
```Ruby
|
58
|
+
|
59
|
+
class UserMessage < ::Protobuf::Message
|
60
|
+
optional ::Protobuf::Field::StringField, :first_name, 1
|
61
|
+
optional ::Protobuf::Field::StringField, :last_name, 2
|
62
|
+
optional ::Protobuf::Field::StringField, :email, 3
|
63
|
+
optional ::Protobuf::Field::IntegerField, :account_id, 4
|
64
|
+
end
|
65
|
+
|
66
|
+
```
|
67
|
+
|
68
|
+
Protoable will map the `first_name`, `last_name`, `email`, & `account_id` columns, skipping the timestamp columns. Repeated fields and fields that are nil will not be mapped.
|
69
|
+
|
70
|
+
**Dates**
|
71
|
+
|
72
|
+
Since Protocol Buffer messages don't support sending date, time, or datetime fields, Protoable expects date, time, and datetime fields to be sent as integers. Just like Active Record handles translating Ruby dates, times, and datetimes into the proper database column types, Protoable will handle converting dates, times, and dateimes to and from integers mapping protobuf message fields.
|
73
|
+
|
74
|
+
Picking up our users table example again, if you wanted to add a `created_at` field to your protobuf message, if you add it as an integer field, Protoable will handle the conversions for you:
|
75
|
+
|
76
|
+
```Ruby
|
77
|
+
|
78
|
+
class UserMessage < ::Protobuf::Message
|
79
|
+
optional ::Protobuf::Field::StringField, :first_name, 1
|
80
|
+
optional ::Protobuf::Field::StringField, :last_name, 2
|
81
|
+
optional ::Protobuf::Field::StringField, :email, 3
|
82
|
+
optional ::Protobuf::Field::IntegerField, :account_id, 4
|
83
|
+
|
84
|
+
# Add a datetime field as an integer and Protoable will map it for you
|
85
|
+
optional ::Protobuf::Field::IntegerField, :created_at, 5
|
86
|
+
end
|
87
|
+
|
88
|
+
```
|
89
|
+
|
90
|
+
**Mass-assignment**
|
91
|
+
|
92
|
+
If a model has protected attributes defined, Protoable will skip any fields that map to them. Likewise, if there are accessible attributes defined, only they will be mapped.
|
93
|
+
|
94
|
+
### Persistence
|
95
|
+
|
96
|
+
Protoable doesn't alter Active Record's normal persistence methods. It simply adds to ability to pass protobuf messages to them in place of an attributes hash.
|
97
|
+
|
98
|
+
### Serialization
|
99
|
+
|
100
|
+
In addition to mapping protobuf message fields to Active Record objects when creating or updating records, Protoable also provides the ability to serialize Active Record objects to protobuf messages. Simply tell Protoable the protobuf message that should be used and it will take care of the rest:
|
101
|
+
|
102
|
+
```Ruby
|
103
|
+
|
104
|
+
class User < ActiveRecord::Base
|
105
|
+
# Configures Protoable to use the UserMessage class and adds a :to_proto method.
|
106
|
+
protobuf_message :user_message
|
107
|
+
end
|
108
|
+
|
109
|
+
```
|
110
|
+
|
111
|
+
Once the desired protobuf message has been specified, Protoable adds a `to_proto` method to the model. Calling `to_proto` will automatically convert the model to the specified protobuf message using the same attribute to field mapping it uses to create and update objects from protobuf messages.
|
22
112
|
|
23
113
|
## Contributing
|
24
114
|
|
data/lib/protoable/fields.rb
CHANGED
@@ -10,6 +10,9 @@ module Protoable
|
|
10
10
|
class << self
|
11
11
|
attr_accessor :_protobuf_columns, :_protobuf_column_types,
|
12
12
|
:_protobuf_column_transformers, :_protobuf_field_converters
|
13
|
+
|
14
|
+
alias_method :convert_field_to_column, :convert_field
|
15
|
+
alias_method :transform_column_from_proto, :transform_column
|
13
16
|
end
|
14
17
|
|
15
18
|
@_protobuf_columns = {}
|
@@ -51,21 +51,39 @@ module Protoable
|
|
51
51
|
attributes
|
52
52
|
end
|
53
53
|
|
54
|
+
# :nodoc:
|
55
|
+
def create(attributes, options = {}, &block)
|
56
|
+
attributes = attributes_from_proto(proto) if attributes.is_a?(::Protobuf::Message)
|
57
|
+
|
58
|
+
super(attributes, options)
|
59
|
+
end
|
60
|
+
|
61
|
+
# :nodoc:
|
62
|
+
def create!(attributes, options = {}, &block)
|
63
|
+
attributes = attributes_from_proto(proto) if attributes.is_a?(::Protobuf::Message)
|
64
|
+
|
65
|
+
super(attributes, options)
|
66
|
+
end
|
67
|
+
|
54
68
|
# Creates an object from the given protobuf message, if it's valid. The
|
55
69
|
# newly created object is returned if it was successfully saved or not.
|
56
70
|
#
|
57
|
-
def create_from_proto(proto)
|
71
|
+
def create_from_proto(proto, options = {})
|
58
72
|
attributes = attributes_from_proto(proto)
|
59
73
|
|
60
74
|
yield(attributes) if block_given?
|
61
75
|
|
62
|
-
|
63
|
-
|
64
|
-
record.save! if record.valid?
|
65
|
-
return record
|
76
|
+
self.create(attributes, options)
|
66
77
|
end
|
67
78
|
end
|
68
79
|
|
80
|
+
# :nodoc:
|
81
|
+
def assign_attributes(attributes, options = {})
|
82
|
+
attributes = attributes_from_proto(proto) if attributes.is_a?(::Protobuf::Message)
|
83
|
+
|
84
|
+
super(attributes, options)
|
85
|
+
end
|
86
|
+
|
69
87
|
# Calls up to the class version of the method.
|
70
88
|
#
|
71
89
|
def attributes_from_proto(proto)
|
@@ -79,16 +97,29 @@ module Protoable
|
|
79
97
|
destroy
|
80
98
|
end
|
81
99
|
|
100
|
+
# :nodoc:
|
101
|
+
def update_attributes(attributes, options = {})
|
102
|
+
attributes = attributes_from_proto(proto) if attributes.is_a?(::Protobuf::Message)
|
103
|
+
|
104
|
+
super(attributes, options)
|
105
|
+
end
|
106
|
+
|
107
|
+
# :nodoc:
|
108
|
+
def update_attributes!(attributes, options = {})
|
109
|
+
attributes = attributes_from_proto(proto) if attributes.is_a?(::Protobuf::Message)
|
110
|
+
|
111
|
+
super(attributes, options)
|
112
|
+
end
|
113
|
+
|
82
114
|
# Update a record from a proto message. Accepts an optional block.
|
83
115
|
# If block is given, yields the attributes that would be updated.
|
84
116
|
#
|
85
|
-
def update_from_proto(proto)
|
117
|
+
def update_from_proto(proto, options = {})
|
86
118
|
attributes = attributes_from_proto(proto)
|
87
119
|
|
88
120
|
yield(attributes) if block_given?
|
89
121
|
|
90
|
-
|
91
|
-
return valid? ? save! : false
|
122
|
+
update_attributes(attributes, options)
|
92
123
|
end
|
93
124
|
end
|
94
125
|
end
|
@@ -78,7 +78,7 @@ describe Protoable::Persistence do
|
|
78
78
|
end
|
79
79
|
|
80
80
|
context "when an error occurs while saving" do
|
81
|
-
before { User.any_instance.stub(:
|
81
|
+
before { User.any_instance.stub(:create).and_raise(RuntimeError) }
|
82
82
|
|
83
83
|
it "raises an exception" do
|
84
84
|
expect { User.create_from_proto(proto) }.to raise_exception
|
@@ -112,7 +112,7 @@ describe Protoable::Persistence do
|
|
112
112
|
|
113
113
|
describe "#update_from_proto" do
|
114
114
|
it "updates the object with attributes from the given protobuf message" do
|
115
|
-
user.should_receive(:assign_attributes).with(user_attributes)
|
115
|
+
user.should_receive(:assign_attributes).with(user_attributes, {})
|
116
116
|
user.update_from_proto(proto)
|
117
117
|
end
|
118
118
|
|
@@ -133,13 +133,13 @@ describe Protoable::Persistence do
|
|
133
133
|
|
134
134
|
context "when saving is successful" do
|
135
135
|
it "returns true" do
|
136
|
-
user.stub(:
|
136
|
+
user.stub(:assign_attributes).and_return(true)
|
137
137
|
user.update_from_proto(proto).should be_true
|
138
138
|
end
|
139
139
|
end
|
140
140
|
|
141
141
|
context "when an error occurs while saving" do
|
142
|
-
before { user.stub(:
|
142
|
+
before { user.stub(:assign_attributes).and_raise(RuntimeError) }
|
143
143
|
|
144
144
|
it "raises an exception" do
|
145
145
|
expect { user.update_from_proto }.to raise_exception
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: protobuf-activerecord
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-10-
|
12
|
+
date: 2012-10-28 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
@@ -222,7 +222,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
222
222
|
version: '0'
|
223
223
|
segments:
|
224
224
|
- 0
|
225
|
-
hash: -
|
225
|
+
hash: -2932429429413082945
|
226
226
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
227
227
|
none: false
|
228
228
|
requirements:
|
@@ -231,7 +231,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
231
231
|
version: '0'
|
232
232
|
segments:
|
233
233
|
- 0
|
234
|
-
hash: -
|
234
|
+
hash: -2932429429413082945
|
235
235
|
requirements: []
|
236
236
|
rubyforge_project:
|
237
237
|
rubygems_version: 1.8.24
|