mm_uses_uuid 0.0.16 → 0.0.18

Sign up to get free protection for your applications and to get access to all the features.
@@ -24,7 +24,7 @@ class MongoMapper::Plugins::Associations::InArrayProxy
24
24
  def find_target
25
25
  return [] if ids.blank?
26
26
  if klass == UuidModel
27
- UuidModel.find(*criteria[:_id])
27
+ out = *UuidModel.find(*criteria[:_id])
28
28
  else
29
29
  all
30
30
  end
@@ -32,93 +32,82 @@ class MongoMapper::Plugins::Associations::InArrayProxy
32
32
 
33
33
  end
34
34
 
35
- class UuidModel
36
-
37
- include MongoMapper::Document
38
-
39
- @@lsn_class_lookup ||= {}
40
-
41
- def self.add_lsn_mapping(ind, klass)
42
- @@lsn_class_lookup[ind] = klass
43
- @@class_lsn_lookup = @@lsn_class_lookup.invert
44
- end
45
-
46
- def self.lsn_class_lookup
47
- @@lsn_class_lookup
48
- end
49
-
50
- def self.class_lsn_lookup
51
- @@class_lsn_lookup
52
- end
53
-
54
- def self.find(*ids)
55
- ids = ids.flatten.uniq
56
- ids_by_class = ids.each_with_object(Hash.new { |hash, key| hash[key] = [] }) do |id, hsh|
57
- lsn = id.to_s[-1].hex
58
- klass = @@lsn_class_lookup[lsn]
59
- if klass.nil?
60
- raise "expected to find a class in @@lsn_class_lookup[#{lsn}] of the MongoMapper module but there was no entry. You need to set uuid_lsn in your class."
61
- end
62
- hsh[klass] << id
63
- end
64
- result = ids_by_class.map {|klass, ids| klass.find(ids)} .flatten
65
- ids.length == 1 ? result.first : result
66
- end
67
-
68
- def self.find!(*ids)
69
- ids = ids.flatten.uniq
70
- raise MongoMapper::DocumentNotFound, "Couldn't find without an ID" if ids.size == 0
71
- find(*ids).tap do |result|
72
- if result.nil? || ids.size != Array(result).size
73
- raise MongoMapper::DocumentNotFound, "Couldn't find all of the ids (#{ids.join(',')}). Found #{Array(result).size}, but was expecting #{ids.size}"
74
- end
75
- end
76
- end
77
-
78
- end
79
-
80
35
  module MmUsesUuid
81
36
  extend ActiveSupport::Concern
82
37
 
83
38
  included do
84
- key :_id, BsonUuid
39
+ key :_id, BsonUuid, :default => lambda { make_uuid }
85
40
  end
86
41
 
87
42
  module ClassMethods
88
43
 
89
- def find(*args)
90
- args = convert_ids_to_BSON(args)
91
- super(args)
44
+ def serialize_id(object)
45
+ case object
46
+ when MongoMapper::Document, MongoMapper::EmbeddedDocument
47
+ object.id.to_s
48
+ else
49
+ object.to_s
50
+ end
92
51
  end
93
52
 
94
- def find!(*args)
95
- args = convert_ids_to_BSON(args)
96
- super(args)
53
+ def deserialize_id(id)
54
+ BSON::Binary.new(id, BSON::Binary::SUBTYPE_UUID)
97
55
  end
98
56
 
99
- def convert_ids_to_BSON(args)
100
- args.flatten!
101
- if args.size > 1
102
- args.map! {|id| BsonUuid.to_mongo(id)}
57
+ def make_uuid
58
+ uuid = SecureRandom.uuid.gsub!('-', '')
59
+ if single_collection_inherited? and not embeddable?
60
+ lookup_class_name = collection_name.singularize.camelize
103
61
  else
104
- args = BsonUuid.to_mongo(args.first)
62
+ lookup_class_name = name
105
63
  end
106
- args
64
+ replacement_lsn = UuidModel.class_lsn_lookup[lookup_class_name] || 0x00
65
+ uuid[-2..-1] = replacement_lsn.to_s(16).rjust(2,'0')
66
+ BSON::Binary.new(uuid, BSON::Binary::SUBTYPE_UUID)
67
+
68
+ rescue => e
69
+ binding.pry
70
+ raise e
107
71
  end
108
72
 
109
- def new(params = {})
110
- passed_id = params.delete(:id) || params.delete(:_id) || params.delete('id') || params.delete('_id')
111
- new_object = super(params)
112
- if passed_id.is_a?(BSON::Binary) and passed_id.subtype == BSON::Binary::SUBTYPE_UUID
113
- new_object.id = passed_id
114
- else
115
- new_object.find_new_uuid
116
- end
117
- new_object
73
+ def find(*ids)
74
+ batch_mode = ids.first.is_a?(Array) || ids.length > 1
75
+ ids.flatten!
76
+ ids = convert_ids_to_BSON(ids)
77
+ results = super(ids)
78
+ batch_mode ? results : results.first
79
+ end
80
+
81
+ def find!(*ids)
82
+ batch_mode = ids.first.is_a?(Array) || ids.length > 1
83
+ ids.flatten!
84
+ ids = convert_ids_to_BSON(ids)
85
+ results = super(ids)
86
+ batch_mode ? results : results.first
118
87
  end
88
+
89
+ def convert_ids_to_BSON(ids)
90
+ ids.map {|id| BsonUuid.to_mongo(id)}
91
+ end
92
+
93
+ # def new(params = {})
94
+ # passed_id = params.delete(:id) || params.delete(:_id) || params.delete('id') || params.delete('_id')
95
+ # new_object = super(params)
96
+ # if passed_id
97
+ # if passed_id.is_a?(BSON::Binary) and passed_id.subtype == BSON::Binary::SUBTYPE_UUID
98
+ # new_object.id = passed_id
99
+ # else
100
+ # raise ArgumentError, "if you pass an explicit :id parameter it must be a valid BSON::Binary::SUBTYPE_UUID"
101
+ # end
102
+ # else
103
+ # new_object.find_new_uuid
104
+ # end
105
+ # new_object
106
+ # end
119
107
 
120
108
  def uuid_lsn(lsn_integer)
121
- UuidModel.add_lsn_mapping(lsn_integer, self)
109
+ raise "lsn_integer must be from 0-255" unless (0..255).cover?(lsn_integer)
110
+ UuidModel.add_lsn_mapping(lsn_integer, self.name)
122
111
  end
123
112
 
124
113
  end
@@ -129,8 +118,8 @@ module MmUsesUuid
129
118
  options = {force_safe: false}.merge(options)
130
119
 
131
120
  if not options[:ensure_unique_in]
132
- @_id, variant = make_uuid
133
- #puts "assuming #{variant} UUID #{@_id} is available"
121
+ @_id = make_uuid
122
+ #puts "assuming UUID #{@_id} is available"
134
123
  return
135
124
  else
136
125
  find_new_uuid_safely(options[:ensure_unique_in])
@@ -142,8 +131,8 @@ module MmUsesUuid
142
131
 
143
132
  @_id = nil
144
133
  begin
145
- trial_id, variant = make_uuid
146
- #puts "CHECKING #{coll} collection for availability of #{variant} UUID: #{trial_id}"
134
+ trial_id = make_uuid
135
+ #puts "CHECKING #{coll} collection for availability of UUID: #{trial_id}"
147
136
  if coll.where(:_id => trial_id).fields(:_id).first.nil?
148
137
  @_id = trial_id
149
138
  end
@@ -152,17 +141,7 @@ module MmUsesUuid
152
141
  end
153
142
 
154
143
  def make_uuid
155
- uuid = SecureRandom.uuid.gsub!('-', '')
156
- if self.class.single_collection_inherited?
157
- lookup_class = self.class.collection_name.singularize.camelize.constantize
158
- else
159
- lookup_class = self.class
160
- end
161
- if replacement_lsn = UuidModel.class_lsn_lookup[lookup_class]
162
- uuid[-1] = replacement_lsn.to_s(16)
163
- end
164
- bson_encoded_uuid = BSON::Binary.new(uuid, BSON::Binary::SUBTYPE_UUID)
165
- return bson_encoded_uuid, 'random'
144
+ self.class.make_uuid
166
145
  end
167
146
 
168
147
  def id_to_s!
@@ -177,3 +156,132 @@ module MmUsesUuid
177
156
  end
178
157
 
179
158
  end
159
+
160
+ class UuidModel
161
+
162
+ include MongoMapper::Document
163
+ plugin MmUsesUuid
164
+
165
+ @@lsn_class_lookup ||= {}
166
+
167
+ class << self
168
+
169
+ def add_lsn_mapping(ind, class_name)
170
+ class_name = class_name.to_s
171
+ if current_class_name = @@lsn_class_lookup[ind]
172
+ raise "cannont assign #{class_name} to #{ind} as #{current_class_name} is already assigned to that LSN"
173
+ end
174
+ @@lsn_class_lookup[ind] = class_name
175
+ @@class_lsn_lookup = @@lsn_class_lookup.invert
176
+ end
177
+
178
+ def lsn_class_lookup
179
+ @@lsn_class_lookup
180
+ end
181
+
182
+ def class_lsn_lookup
183
+ @@class_lsn_lookup
184
+ end
185
+
186
+ def class_name_from_id(id, options = {})
187
+ lsn = id.to_s[-2..-1].hex
188
+ class_name = @@lsn_class_lookup[lsn]
189
+ if class_name.nil? and options[:error_if_no_lsn_match]
190
+ raise "expected to find a class name in @@lsn_class_lookup[#{lsn}] of the MongoMapper module but there was no entry. You need to set uuid_lsn in your class."
191
+ end
192
+ class_name
193
+ end
194
+
195
+ def find_by_id(id)
196
+ find id
197
+ end
198
+
199
+ def find(*args)
200
+
201
+ # raise "foo"
202
+
203
+ options = args.last.is_a?(Hash) ? args.pop : {}
204
+ fields = *options[:fields]
205
+ fields = nil if fields.empty?
206
+ batch_mode = args.first.is_a?(Array) || args.length > 1
207
+ ids = args.flatten.uniq
208
+ ids.map! {|id| BsonUuid.to_mongo(id)}
209
+
210
+ ids_by_model = ids.each_with_object(Hash.new { |hash, key| hash[key] = [] }) do |id, hsh|
211
+ model_name = class_name_from_id(id, options)
212
+ hsh[model_name.constantize] << id if model_name
213
+ end
214
+
215
+ if defined? Celluloid
216
+
217
+ #NOTE: because IdentityMap is in the current thread only...
218
+ #we have to manage it ourselves if using Celluloid
219
+
220
+ im_results = []
221
+
222
+ unless fields
223
+ ids_by_model.clone.each do |model, model_ids|
224
+ model_ids.each do |model_id|
225
+ doc = model.get_from_identity_map(model_id)
226
+ if doc
227
+ im_results << doc
228
+ ids_by_model[model].delete model_id
229
+ end
230
+ end
231
+ ids_by_model.delete(model) if ids_by_model[model].empty?
232
+ end
233
+ end
234
+
235
+ future_db_results = ids_by_model.map do |model, model_ids|
236
+ query = model.where(:id => model_ids)
237
+ query = query.fields(fields) if fields
238
+ Celluloid::Future.new { query.all }
239
+ end
240
+
241
+ db_results = future_db_results.map(&:value).flatten
242
+
243
+ if fields
244
+ db_results.each(&:remove_from_identity_map)
245
+ else
246
+ db_results.each(&:add_to_identity_map)
247
+ end
248
+
249
+ results = im_results + db_results
250
+
251
+ else
252
+
253
+ #NOTE: as this is in the current thread, IdentityMap management is normal
254
+
255
+ results = ids_by_model.map do |model, model_ids|
256
+ if fields
257
+ model.where(:id => model_ids).fields(fields).all #models will be removed from the map
258
+ else
259
+ model.find model_ids #we use this so that we read and write to the identity map
260
+ end
261
+ end.flatten
262
+
263
+ end
264
+
265
+ batch_mode ? results : results.first
266
+
267
+ # rescue => e
268
+ # binding.pry
269
+ end
270
+ alias_method :find_with_fields, :find
271
+
272
+ def find!(*args)
273
+ options = args.last.is_a?(Hash) ? args.pop : {}
274
+ options.merge(:error_if_no_lsn_match => true)
275
+ ids = args.flatten.uniq
276
+ raise MongoMapper::DocumentNotFound, "Couldn't find without an ID" if ids.size == 0
277
+ find(*ids, options).tap do |result|
278
+ if result.nil? || ids.size != Array(result).size
279
+ raise MongoMapper::DocumentNotFound, "Couldn't find all of the ids (#{ids.join(',')}). Found #{Array(result).size}, but was expecting #{ids.size}"
280
+ end
281
+ end
282
+ end
283
+ alias_method :find_with_fields!, :find!
284
+
285
+ end
286
+
287
+ end
@@ -18,8 +18,12 @@ module BSON
18
18
  end
19
19
  end
20
20
 
21
+ def hash
22
+ [@str, @subtype].hash
23
+ end
24
+
21
25
  def eql?(value)
22
- self.to_s == value.to_s
26
+ @str.eql?(value.to_s) && @subtype.eql?(value.subtype)
23
27
  end
24
28
 
25
29
  end
@@ -1,3 +1,3 @@
1
1
  module MmUsesUuid
2
- VERSION = "0.0.16"
2
+ VERSION = "0.0.18"
3
3
  end
@@ -1,5 +1,6 @@
1
1
  require File.expand_path('../../lib/mm_uses_uuid', __FILE__)
2
2
  require 'ruby-debug'
3
+ require 'pry'
3
4
 
4
5
  describe MmUsesUuid do
5
6
 
@@ -10,7 +11,7 @@ describe MmUsesUuid do
10
11
 
11
12
  key :name, String
12
13
  belongs_to :owner, :class_name => 'UuidModel', :required => true
13
- many :people, :class_name => 'Person'
14
+ has_many :people, :class_name => 'Person'
14
15
 
15
16
  uuid_lsn 0
16
17
 
@@ -23,8 +24,8 @@ describe MmUsesUuid do
23
24
  key :name
24
25
  key :age
25
26
 
26
- key :interest_ids, Array
27
- many :interests, :in => :interest_ids, :class_name => 'UuidModel' # this allows many-to-many polymorphic interests without the need for groups and people to be stored in a single collection
27
+ key :interest_ids, Set
28
+ has_many :interests, :in => :interest_ids, :class_name => 'UuidModel' # this allows many-to-many polymorphic interests without the need for groups and people to be stored in a single collection
28
29
 
29
30
  belongs_to :group
30
31
 
@@ -79,6 +80,12 @@ describe MmUsesUuid do
79
80
  person = Person.find_by_name 'Jon'
80
81
  person.interests.map(&:name).should include(@person.name, @group.name)
81
82
  end
83
+
84
+ it "should return an array for many to many associations when there is only one associated item" do
85
+ person = Person.new
86
+ person.interests << @group
87
+ person.interests.should be_an_instance_of(Array)
88
+ end
82
89
 
83
90
  it "should not set a new uuid if one as passed as a param" do
84
91
  group_with_passed_id = Group.new(:id => BSON::Binary.new("3333333333334333y333333333333330", BSON::Binary::SUBTYPE_UUID))
metadata CHANGED
@@ -1,8 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mm_uses_uuid
3
3
  version: !ruby/object:Gem::Version
4
- prerelease:
5
- version: 0.0.16
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 18
9
+ version: 0.0.18
6
10
  platform: ruby
7
11
  authors:
8
12
  - Jonathan Chambers
@@ -10,7 +14,8 @@ autorequire:
10
14
  bindir: bin
11
15
  cert_chain: []
12
16
 
13
- date: 2012-07-23 00:00:00 Z
17
+ date: 2012-12-21 00:00:00 +00:00
18
+ default_executable:
14
19
  dependencies:
15
20
  - !ruby/object:Gem::Dependency
16
21
  name: rspec
@@ -20,6 +25,9 @@ dependencies:
20
25
  requirements:
21
26
  - - ">="
22
27
  - !ruby/object:Gem::Version
28
+ segments:
29
+ - 2
30
+ - 7
23
31
  version: "2.7"
24
32
  type: :development
25
33
  version_requirements: *id001
@@ -31,6 +39,10 @@ dependencies:
31
39
  requirements:
32
40
  - - ">="
33
41
  - !ruby/object:Gem::Version
42
+ segments:
43
+ - 1
44
+ - 5
45
+ - 0
34
46
  version: 1.5.0
35
47
  type: :development
36
48
  version_requirements: *id002
@@ -42,6 +54,10 @@ dependencies:
42
54
  requirements:
43
55
  - - ">="
44
56
  - !ruby/object:Gem::Version
57
+ segments:
58
+ - 0
59
+ - 10
60
+ - 1
45
61
  version: 0.10.1
46
62
  type: :runtime
47
63
  version_requirements: *id003
@@ -65,6 +81,7 @@ files:
65
81
  - lib/mm_uses_uuid/version.rb
66
82
  - mm_uses_uuid.gemspec
67
83
  - spec/mm_uses_uuid_spec.rb
84
+ has_rdoc: true
68
85
  homepage: https://github.com/jmchambers/mm_uses_uuid
69
86
  licenses:
70
87
  - MIT
@@ -78,20 +95,23 @@ required_ruby_version: !ruby/object:Gem::Requirement
78
95
  requirements:
79
96
  - - ">="
80
97
  - !ruby/object:Gem::Version
98
+ segments:
99
+ - 0
81
100
  version: "0"
82
101
  required_rubygems_version: !ruby/object:Gem::Requirement
83
102
  none: false
84
103
  requirements:
85
104
  - - ">="
86
105
  - !ruby/object:Gem::Version
106
+ segments:
107
+ - 0
87
108
  version: "0"
88
109
  requirements: []
89
110
 
90
111
  rubyforge_project:
91
- rubygems_version: 1.8.17
112
+ rubygems_version: 1.3.7
92
113
  signing_key:
93
114
  specification_version: 3
94
115
  summary: UUIDs for MM
95
116
  test_files: []
96
117
 
97
- has_rdoc: