protobuf-activerecord 3.4.4 → 3.5.0
Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6ebddfb7f1a2b6a894d213d63cec1a179e69c88c
|
4
|
+
data.tar.gz: 2ddf9cc3994a46fb2ec4c3118121be657faf7e2a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4a5386b5374b38a42c3b507ff848c2afef0bea3d93ac3e8435e6c9863c87ff6fe1ef6bdf2c3d9ff7de7931b9735d92e0b673e268744140b28e23a733d7617ff9
|
7
|
+
data.tar.gz: f17ccbe9174babd312ebb75d35ffb65f8aff1c31886e20420d5f314029a3febf258eb377bc995b12e7cdf9e9256286938994d63bf801b0b83676d1b666581b45
|
data/README.md
CHANGED
@@ -255,6 +255,53 @@ User.limit(10).search_scope(request)
|
|
255
255
|
|
256
256
|
Protobuf Active Record also provides some aliases for the `search_scope` method in the event that you'd like something a little more descriptive: `by_fields` and `scope_from_proto` are all aliases of `search_scope`.
|
257
257
|
|
258
|
+
#### Upsert
|
259
|
+
|
260
|
+
Protobuf Active Record provides the ability to create a new record, or update an existing record if an existing record is found. This is implemented using Active Record's `first_or_initialize` method.
|
261
|
+
|
262
|
+
```Ruby
|
263
|
+
class User < ActiveRecord::Base
|
264
|
+
scope :by_guid, lambda { |*values| where(:guid => values) }
|
265
|
+
scope :by_first_name, lambda { |*values| where(:first_name => values) }
|
266
|
+
scope :by_last_name, lambda { |*values| where(:last_name => values) }
|
267
|
+
|
268
|
+
field_scope :guid
|
269
|
+
field_scope :first_name
|
270
|
+
field_scope :last_name
|
271
|
+
|
272
|
+
upsert_key :guid
|
273
|
+
upsert_key :first_name, :last_name
|
274
|
+
end
|
275
|
+
|
276
|
+
@user = User.for_upsert(request)
|
277
|
+
```
|
278
|
+
|
279
|
+
Note: An upsert_key should only be defined on a field or set of fields that have a unique constraint
|
280
|
+
|
281
|
+
Note: All fields used in an upsert key must also have a field_scope defined
|
282
|
+
|
283
|
+
If multiple upsert_keys match the request, the first matching upsert key will be used, in order of declaration. In the typical use-case where upsert keys have corresponding unique constraints the results should be equivalent regardless of order.
|
284
|
+
|
285
|
+
Protobuf Active Record provides several methods for invoking an upsert.
|
286
|
+
|
287
|
+
The first approach is to use the `for_upsert` method to look up a record.
|
288
|
+
|
289
|
+
```Ruby
|
290
|
+
@user = User.for_upsert(proto)
|
291
|
+
```
|
292
|
+
|
293
|
+
Alternatively, you can use `upsert` to look up the record and perform the persistence in the same call.
|
294
|
+
|
295
|
+
```Ruby
|
296
|
+
# Example
|
297
|
+
User.upsert(proto)
|
298
|
+
|
299
|
+
# This is equivalent to
|
300
|
+
user = User.for_upsert(proto)
|
301
|
+
user.assign_attributes(proto)
|
302
|
+
user.save
|
303
|
+
```
|
304
|
+
|
258
305
|
## Contributing
|
259
306
|
|
260
307
|
1. Fork it
|
@@ -38,5 +38,13 @@ module Protobuf
|
|
38
38
|
# Raised by `field_scope` when given scope is not defined.
|
39
39
|
class SearchScopeError < ProtobufActiveRecordError
|
40
40
|
end
|
41
|
+
|
42
|
+
# Raised by `upsert_scope` when a given scope is not defined
|
43
|
+
class UpsertScopeError < ProtobufActiveRecordError
|
44
|
+
end
|
45
|
+
|
46
|
+
# Raised by `for_upsert` when no valid upsert_scopes are found
|
47
|
+
class UpsertNotFoundError < ProtobufActiveRecordError
|
48
|
+
end
|
41
49
|
end
|
42
50
|
end
|
@@ -111,6 +111,80 @@ module Protobuf
|
|
111
111
|
def searchable_field_parsers
|
112
112
|
@_searchable_field_parsers ||= {}
|
113
113
|
end
|
114
|
+
|
115
|
+
# Defines a scope that is eligible for upsert. The scope will be
|
116
|
+
# used to initialize a record with first_or_initialize. An upsert scope
|
117
|
+
# declariation must specify one or more fields that are required to
|
118
|
+
# be present on the request and also must have a field_scope defined.
|
119
|
+
#
|
120
|
+
# If multiple upsert scopes are specified, they will be searched in
|
121
|
+
# the order they are declared for the first valid scope.
|
122
|
+
#
|
123
|
+
# Examples:
|
124
|
+
#
|
125
|
+
# class User < ActiveRecord::Base
|
126
|
+
# scope :by_guid, lambda { |*guids| where(:guid => guids) }
|
127
|
+
# scope :by_external_guid, lambda { |*external_guids|
|
128
|
+
# where(:external_guid => exteranl_guids)
|
129
|
+
# }
|
130
|
+
# scope :by_client_guid, lambda { |*client_guids|
|
131
|
+
# joins(:client).where(
|
132
|
+
# :clients => { :guid => client_guids }
|
133
|
+
# )
|
134
|
+
# }
|
135
|
+
#
|
136
|
+
# field_scope :guid
|
137
|
+
# field_scope :client_guid
|
138
|
+
# field_scope :external_guid
|
139
|
+
#
|
140
|
+
# upsert_scope :external_guid, :client_guid
|
141
|
+
# upsert_scope :guid
|
142
|
+
#
|
143
|
+
# end
|
144
|
+
#
|
145
|
+
def upsert_key(*fields)
|
146
|
+
fields = fields.flatten
|
147
|
+
|
148
|
+
fields.each do |field|
|
149
|
+
fail UpsertScopeError unless searchable_fields[field].present?
|
150
|
+
end
|
151
|
+
|
152
|
+
upsert_keys << fields
|
153
|
+
end
|
154
|
+
|
155
|
+
def upsert_keys
|
156
|
+
@_upsert_keys ||= []
|
157
|
+
end
|
158
|
+
|
159
|
+
def for_upsert(proto)
|
160
|
+
valid_upsert = upsert_keys.find do |upsert_key|
|
161
|
+
upsert_key.all? do |field|
|
162
|
+
proto.respond_to_and_has_and_present?(field)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
fail UpsertNotFoundError unless valid_upsert.present?
|
167
|
+
|
168
|
+
upsert_scope = model_scope
|
169
|
+
valid_upsert.each do |field|
|
170
|
+
value = proto.__send__(field)
|
171
|
+
upsert_scope = upsert_scope.__send__(searchable_fields[field], value)
|
172
|
+
end
|
173
|
+
|
174
|
+
upsert_scope.first_or_initialize
|
175
|
+
end
|
176
|
+
|
177
|
+
def upsert(proto)
|
178
|
+
record = for_upsert(proto)
|
179
|
+
record.assign_attributes(proto)
|
180
|
+
record.save
|
181
|
+
end
|
182
|
+
|
183
|
+
def upsert!(proto)
|
184
|
+
record = for_upsert(proto)
|
185
|
+
record.assign_attributes(proto)
|
186
|
+
record.save!
|
187
|
+
end
|
114
188
|
end
|
115
189
|
end
|
116
190
|
end
|
@@ -9,6 +9,7 @@ describe Protobuf::ActiveRecord::Scope do
|
|
9
9
|
after do
|
10
10
|
User.instance_variable_set("@_searchable_field_parsers", @field_parsers)
|
11
11
|
User.instance_variable_set("@_searchable_fields", @fields)
|
12
|
+
User.instance_variable_set("@_upsert_keys", [])
|
12
13
|
end
|
13
14
|
|
14
15
|
|
@@ -78,7 +79,6 @@ describe Protobuf::ActiveRecord::Scope do
|
|
78
79
|
end
|
79
80
|
|
80
81
|
describe ".parse_search_values" do
|
81
|
-
|
82
82
|
it "converts single values to collections" do
|
83
83
|
proto = UserMessage.new(:email => "the.email@test.in")
|
84
84
|
|
@@ -116,4 +116,87 @@ describe Protobuf::ActiveRecord::Scope do
|
|
116
116
|
end
|
117
117
|
end
|
118
118
|
end
|
119
|
+
|
120
|
+
describe ".upsert_key" do
|
121
|
+
it "adds the fields to the upsert_keys" do
|
122
|
+
::User.field_scope(:guid)
|
123
|
+
::User.upsert_key(:guid)
|
124
|
+
expect(::User.upsert_keys).to eq([[:guid]])
|
125
|
+
end
|
126
|
+
|
127
|
+
context "no field_scope defined" do
|
128
|
+
it "raises an error" do
|
129
|
+
expect { ::User.upsert_key(:foobar) }.to raise_error(::Protobuf::ActiveRecord::UpsertScopeError)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
describe ".for_upsert" do
|
135
|
+
let(:guid) { "USR-1" }
|
136
|
+
let(:proto) { ::UserMessage.new(:guid => guid) }
|
137
|
+
|
138
|
+
before do
|
139
|
+
::User.delete_all
|
140
|
+
::User.field_scope(:guid)
|
141
|
+
::User.upsert_key(:guid)
|
142
|
+
end
|
143
|
+
|
144
|
+
context "no matching upsert keys" do
|
145
|
+
let(:proto) { ::UserMessage.new }
|
146
|
+
|
147
|
+
it "raises an error" do
|
148
|
+
expect { ::User.for_upsert(proto) }.to raise_error(::Protobuf::ActiveRecord::UpsertNotFoundError)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
context "no existing records" do
|
153
|
+
it "returns a new record" do
|
154
|
+
record = ::User.for_upsert(proto)
|
155
|
+
expect(record.new_record?).to be true
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
context "existing record" do
|
160
|
+
before { ::User.create(:guid => guid) }
|
161
|
+
after { ::User.delete_all }
|
162
|
+
|
163
|
+
it "returns the existing record" do
|
164
|
+
record = ::User.for_upsert(proto)
|
165
|
+
expect(record.new_record?).to be false
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
describe ".upsert" do
|
171
|
+
let(:guid) { "USR-1" }
|
172
|
+
let(:proto) { ::UserMessage.new(:guid => guid, :email => "bar") }
|
173
|
+
|
174
|
+
before do
|
175
|
+
::User.delete_all
|
176
|
+
::User.field_scope(:guid)
|
177
|
+
::User.upsert_key(:guid)
|
178
|
+
end
|
179
|
+
|
180
|
+
context "no existing records" do
|
181
|
+
it "creates a new record" do
|
182
|
+
::User.upsert(proto)
|
183
|
+
expect(::User.count).to eq(1)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
context "existing record" do
|
188
|
+
before { ::User.create(:guid => guid, :email => "foo") }
|
189
|
+
after { ::User.delete_all }
|
190
|
+
|
191
|
+
it "updates the existing record" do
|
192
|
+
::User.upsert(proto)
|
193
|
+
expect(::User.first.email).to eq("bar")
|
194
|
+
end
|
195
|
+
|
196
|
+
it "returns true when valid" do
|
197
|
+
result = ::User.upsert(proto)
|
198
|
+
expect(result).to be true
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
119
202
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: protobuf-activerecord
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Adam Hutchison
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-01-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -250,7 +250,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
250
250
|
version: '0'
|
251
251
|
requirements: []
|
252
252
|
rubyforge_project:
|
253
|
-
rubygems_version: 2.6.
|
253
|
+
rubygems_version: 2.6.10
|
254
254
|
signing_key:
|
255
255
|
specification_version: 4
|
256
256
|
summary: Google Protocol Buffers integration for Active Record
|