mm_uses_uuid 0.0.16 → 0.0.18

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.
@@ -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: