mongomodel 0.5.3 → 0.5.4

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 730ec72969141979066d7a38f450b9622485bb55
4
- data.tar.gz: b72b388e3b6b6d041dd4f6431233d25c0aeddd8c
3
+ metadata.gz: 3d006082bc3f5bf2357182fecea49893a06e5994
4
+ data.tar.gz: d53384261c1968e770c65c4eb4e8faa32ade2c22
5
5
  SHA512:
6
- metadata.gz: b954cd2ce4ed17b3dc9406572d8523092db0d249dfe9c1c61418b96b15702a91df7e740e4ed9af3581d41e5f37c8497447fceb794f7c01f661aa935007999f39
7
- data.tar.gz: 0a92c9c4215cea8d312d9ecd13684c8bf9d54cfada4410e6587902506edc6093314672a39e448ce07659bf1991b82eb24e77879227f15eebce938e8f6f0dbc3c
6
+ metadata.gz: e97ed321bde11ad2f30311b4e80a8ea853894e720673d2634142b3e29e1f5088286185169d95fa9bd233aab9637a1d28f69c1b3bd9ef726f69d3b5f6f089a2ff
7
+ data.tar.gz: b787c2bdaa482398da09028b9093ac4514bc596a446a115d58879ab103fd8c116a078415ba0c85022bd9ca14638421a5dfd4ac4844a42d65b1e4bd59d5e9b1c1
@@ -59,6 +59,8 @@ module MongoModel
59
59
  end
60
60
 
61
61
  collection = send(property)
62
+ collection.clear if options[:clear]
63
+
62
64
  attributes_collection.each_with_index do |attributes, index|
63
65
  if collection[index]
64
66
  collection[index].attributes = attributes
@@ -85,6 +87,8 @@ module MongoModel
85
87
  end
86
88
 
87
89
  association = send(association)
90
+ association.clear if options[:clear]
91
+
88
92
  attributes_collection.each do |attributes|
89
93
  association.build(attributes)
90
94
  end
@@ -55,6 +55,7 @@ module MongoModel
55
55
  def initialize(*keys)
56
56
  options = keys.extract_options!
57
57
 
58
+ @name = options.delete(:name)
58
59
  @unique = options.delete(:unique)
59
60
  @min = options.delete(:min)
60
61
  @max = options.delete(:max)
@@ -82,6 +83,7 @@ module MongoModel
82
83
 
83
84
  def to_args
84
85
  args = []
86
+ options = {}
85
87
 
86
88
  if geo2d?
87
89
  args << [[keys.keys.first, Mongo::GEO2D]]
@@ -92,11 +94,14 @@ module MongoModel
92
94
  end
93
95
 
94
96
  if geo2d? && @min && @max
95
- args << { :min => @min, :max => @max }
96
- elsif unique?
97
- args << { :unique => true }
97
+ options[:min] = @min
98
+ options[:max] = @max
98
99
  end
99
100
 
101
+ options[:unique] = true if unique?
102
+ options[:name] = @name if @name
103
+
104
+ args << options if options.any?
100
105
  args
101
106
  end
102
107
 
@@ -102,14 +102,11 @@ module MongoModel
102
102
  end
103
103
 
104
104
  def collection_name
105
- if superclass.abstract_class?
106
- @_collection_name || name.tableize.gsub(/\//, '.')
107
- else
108
- superclass.collection_name
109
- end
105
+ @_collection_name || inferred_collection_name
110
106
  end
111
107
 
112
108
  def collection_name=(name)
109
+ @_collection = nil
113
110
  @_collection_name = name
114
111
  end
115
112
 
@@ -130,12 +127,21 @@ module MongoModel
130
127
  end
131
128
 
132
129
  def save_safely?
133
- @_save_safely
130
+ defined?(@_save_safely) ? @_save_safely : true
134
131
  end
135
132
 
136
133
  def save_safely=(val)
137
134
  @_save_safely = val
138
135
  end
136
+
137
+ protected
138
+ def inferred_collection_name
139
+ if superclass.abstract_class?
140
+ name.tableize.gsub(/\//, '.')
141
+ else
142
+ superclass.collection_name
143
+ end
144
+ end
139
145
  end
140
146
 
141
147
  private
@@ -40,17 +40,16 @@ module MongoModel
40
40
  def setup!(klass)
41
41
  @klass = klass
42
42
 
43
- # Enable safety checks on save
44
- klass.save_safely = true
45
-
46
- # Create unique indexes to deal with race condition
47
- attributes.each do |attr_name|
48
- if options[:case_sensitive]
49
- klass.index *[attr_name] + Array.wrap(options[:scope]) << { :unique => true }
50
- else
51
- lowercase_key = "_lowercase_#{attr_name}"
52
- klass.before_save { attributes[lowercase_key] = send(attr_name).downcase }
53
- klass.index *[lowercase_key] + Array.wrap(options[:scope]) << { :unique => true }
43
+ unless options[:index] == false
44
+ # Create unique indexes to deal with race condition
45
+ attributes.each do |attr_name|
46
+ if options[:case_sensitive]
47
+ klass.index *[attr_name] + Array.wrap(options[:scope]) << { :unique => true }
48
+ else
49
+ lowercase_key = "_lowercase_#{attr_name}"
50
+ klass.before_save { attributes[lowercase_key] = send(attr_name).downcase }
51
+ klass.index *[lowercase_key] + Array.wrap(options[:scope]) << { :unique => true }
52
+ end
54
53
  end
55
54
  end
56
55
  end
@@ -93,6 +92,7 @@ module MongoModel
93
92
  # * <tt>:message</tt> - Specifies a custom error message (default is: "has already been taken").
94
93
  # * <tt>:scope</tt> - One or more properties by which to limit the scope of the uniqueness constraint.
95
94
  # * <tt>:case_sensitive</tt> - Looks for an exact match. Ignored by non-text columns (+true+ by default).
95
+ # * <tt>:index</tt> - If set to false, disables the unique index constraint (default is +true+).
96
96
  # * <tt>:allow_nil</tt> - If set to true, skips this validation if the attribute is +nil+ (default is +false+).
97
97
  # * <tt>:allow_blank</tt> - If set to true, skips this validation if the attribute is blank (default is +false+).
98
98
  # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
@@ -27,9 +27,12 @@ module MongoModel
27
27
  options['password']
28
28
  end
29
29
 
30
+ def replicas
31
+ options['replicas'] || []
32
+ end
33
+
30
34
  def establish_connection
31
- @connection ||= Mongo::Connection.new(host, port, connection_options)
32
- @database = @connection.db(database)
35
+ @database = connection.db(database)
33
36
  @database.authenticate(username, password) if username.present?
34
37
  @database
35
38
  end
@@ -39,8 +42,16 @@ module MongoModel
39
42
  establish_connection
40
43
  end
41
44
 
45
+ def connection
46
+ if replicas.any?
47
+ @connection ||= Mongo::MongoReplicaSetClient.new(replicas, connection_options)
48
+ else
49
+ @connection ||= Mongo::MongoClient.new(host, port, connection_options)
50
+ end
51
+ end
52
+
42
53
  def connection_options
43
- options.except('host', 'port', 'database', 'username', 'password').symbolize_keys
54
+ options.except('host', 'port', 'database', 'username', 'password', 'replicas').symbolize_keys
44
55
  end
45
56
 
46
57
  def options
@@ -80,9 +80,13 @@ module MongoModel
80
80
  end
81
81
 
82
82
  def update_all(updates)
83
- selector = MongoOptions.new(klass, :conditions => finder_conditions).selector
84
- collection.update(selector, { "$set" => updates }, { :multi => true })
85
- reset
83
+ if updates.any?
84
+ selector = MongoOptions.new(klass, :conditions => finder_conditions).selector
85
+ collection.update(selector, { "$set" => updates }, { :multi => true })
86
+ reset
87
+ else
88
+ self
89
+ end
86
90
  end
87
91
 
88
92
  def update(ids, updates)
@@ -1,3 +1,3 @@
1
1
  module MongoModel
2
- VERSION = "0.5.3"
2
+ VERSION = "0.5.4"
3
3
  end
@@ -22,7 +22,7 @@ module MongoModel
22
22
  end
23
23
  define_class(:IllustratedChapter, :Chapter)
24
24
  define_class(:Book, Document) do
25
- has_many :chapters, :by => :foreign_key, :limit => 5
25
+ has_many :chapters, :by => :foreign_key, :limit => 5, :order => :id.asc
26
26
  end
27
27
  define_class(:NonChapter, Document)
28
28
 
@@ -96,6 +96,21 @@ module MongoModel
96
96
  end
97
97
  end
98
98
 
99
+ describe "embedded collection with :clear => true" do
100
+ define_user(EmbeddedDocument)
101
+ define_class(:Account, described_class) do
102
+ property :owners, Collection[User]
103
+ accepts_nested_attributes_for :owners, :clear => true
104
+ end
105
+
106
+ subject { Account.new(:owners => [User.new, User.new]) }
107
+
108
+ it "clears the collection first when assigning attributes" do
109
+ subject.owners_attributes = [{ :age => 18 }]
110
+ subject.owners.size.should == 1
111
+ end
112
+ end
113
+
99
114
  describe "belongs_to association" do
100
115
  define_user(Document)
101
116
  define_class(:Account, described_class) do
@@ -175,6 +190,20 @@ module MongoModel
175
190
  }.should raise_error(MongoModel::TooManyDocuments, "Maximum 2 documents are allowed. Got 3 documents instead.")
176
191
  end
177
192
  end
193
+
194
+ describe "has_many association with :clear => true" do
195
+ define_class(:Account, described_class) do
196
+ has_many :owners, :class => User
197
+ accepts_nested_attributes_for :owners, :clear => true
198
+ end
199
+
200
+ subject { Account.new(:owners => [User.new, User.new]) }
201
+
202
+ it "clears the collection first when assigning attributes" do
203
+ subject.owners_attributes = [{ :age => 18 }]
204
+ subject.owners.size.should == 1
205
+ end
206
+ end
178
207
  end
179
208
  end
180
209
  end
@@ -87,46 +87,58 @@ module MongoModel
87
87
  end
88
88
 
89
89
  describe Index do
90
- it "converts index with single key to arguments for Mongo::Collection#create_index" do
91
- Index.new(:title).to_args.should == [:title]
92
- end
90
+ describe "#to_args" do
91
+ it "converts index with single key" do
92
+ Index.new(:title).to_args.should == [:title]
93
+ end
93
94
 
94
- it "converts nested index with single key to arguments for Mongo::Collection#create_index" do
95
- Index.new('page.title').to_args.should == [:'page.title']
96
- end
95
+ it "converts nested index with single key" do
96
+ Index.new('page.title').to_args.should == [:'page.title']
97
+ end
97
98
 
98
- it "converts index with unique option to arguments for Mongo::Collection#create_index" do
99
- Index.new(:title, :unique => true).to_args.should == [:title, { :unique => true }]
100
- end
99
+ it "converts index with unique option" do
100
+ Index.new(:title, :unique => true).to_args.should == [:title, { :unique => true }]
101
+ end
102
+
103
+ it "converts index with name option" do
104
+ Index.new(:title, :name => "my_name").to_args.should == [:title, { :name => "my_name" }]
105
+ end
106
+
107
+ it "converts index with multiple options" do
108
+ Index.new(:title, :name => "my_name", :unique => true).to_args.should == [:title, { :name => "my_name", :unique => true }]
109
+ end
101
110
 
102
- it "converts index with descending key to arguments for Mongo::Collection#create_index" do
103
- Index.new(:title => :descending).to_args.should == [[[:title, Mongo::DESCENDING]]]
104
- end
111
+ it "converts index with descending key" do
112
+ Index.new(:title => :descending).to_args.should == [[[:title, Mongo::DESCENDING]]]
113
+ end
105
114
 
106
- it "converts index with multiple keys to arguments for Mongo::Collection#create_index" do
107
- Index.new(:title, :age).to_args.should == [[[:age, Mongo::ASCENDING], [:title, Mongo::ASCENDING]]]
108
- end
115
+ it "converts index with multiple keys" do
116
+ Index.new(:title, :age).to_args.should == [[[:age, Mongo::ASCENDING], [:title, Mongo::ASCENDING]]]
117
+ end
109
118
 
110
- it "converts index with multiple keys (ascending and descending) to arguments for Mongo::Collection#create_index" do
111
- Index.new(:title => :ascending, :age => :descending).to_args.should == [[[:age, Mongo::DESCENDING], [:title, Mongo::ASCENDING]]]
112
- end
119
+ it "converts index with multiple keys (ascending and descending)" do
120
+ Index.new(:title => :ascending, :age => :descending).to_args.should == [[[:age, Mongo::DESCENDING], [:title, Mongo::ASCENDING]]]
121
+ end
113
122
 
114
- it "converts geospatial index with no options" do
115
- Index.new(:position => :geo2d).to_args.should == [[[:position, Mongo::GEO2D]]]
116
- end
123
+ it "converts geospatial index with no options" do
124
+ Index.new(:position => :geo2d).to_args.should == [[[:position, Mongo::GEO2D]]]
125
+ end
117
126
 
118
- it "converts geospatial index with min/max options" do
119
- Index.new(:position => :geo2d, :min => -50, :max => 50).to_args.should == [[[:position, Mongo::GEO2D]], { :min => -50, :max => 50 }]
127
+ it "converts geospatial index with min/max options" do
128
+ Index.new(:position => :geo2d, :min => -50, :max => 50).to_args.should == [[[:position, Mongo::GEO2D]], { :min => -50, :max => 50 }]
129
+ end
120
130
  end
121
131
 
122
- it "is equal to an equivalent index" do
123
- Index.new(:title).should == Index.new(:title)
124
- Index.new(:title, :age).should == Index.new(:title => :ascending, :age => :ascending)
125
- end
132
+ describe "equality" do
133
+ it "is equal to an equivalent index" do
134
+ Index.new(:title).should == Index.new(:title)
135
+ Index.new(:title, :age).should == Index.new(:title => :ascending, :age => :ascending)
136
+ end
126
137
 
127
- it "is not equal to an non-equivalent index" do
128
- Index.new(:title).should_not == Index.new(:age)
129
- Index.new(:title, :age).should_not == Index.new(:title => :ascending, :age => :descending)
138
+ it "is not equal to an non-equivalent index" do
139
+ Index.new(:title).should_not == Index.new(:age)
140
+ Index.new(:title, :age).should_not == Index.new(:title => :ascending, :age => :descending)
141
+ end
130
142
  end
131
143
  end
132
144
  end
@@ -94,6 +94,15 @@ module MongoModel
94
94
 
95
95
  ::CustomCollectionNameSubclass.collection_name.should == 'foobar'
96
96
  end
97
+
98
+ it "allows subclasses to set a custom collection name" do
99
+ class ::CustomCollectionName < Document; end
100
+ class ::CustomCollectionNameSubclass < ::CustomCollectionName
101
+ self.collection_name = 'custom'
102
+ end
103
+
104
+ ::CustomCollectionNameSubclass.collection_name.should == 'custom'
105
+ end
97
106
  end
98
107
 
99
108
  describe "#collection" do
@@ -104,6 +113,12 @@ module MongoModel
104
113
  it "uses the correct collection name" do
105
114
  User.collection.name.should == 'users'
106
115
  end
116
+
117
+ it "is updated when the collection name changes" do
118
+ collection = User.collection
119
+ User.collection_name = "custom"
120
+ User.collection.name.should == "custom"
121
+ end
107
122
  end
108
123
 
109
124
  describe "#database" do
@@ -31,6 +31,32 @@ module MongoModel
31
31
  end
32
32
  end
33
33
 
34
+ describe "indexes" do
35
+ define_class(:Article, Document) do
36
+ property :title, String
37
+ end
38
+
39
+ it "creates an index on the attribute" do
40
+ Article.should_receive(:index).with(:title, :unique => true)
41
+ Article.validates_uniqueness_of :title
42
+ end
43
+
44
+ it "creates an index on the lowercase attribute if :case_sensitive => false" do
45
+ Article.should_receive(:index).with("_lowercase_title", :unique => true)
46
+ Article.validates_uniqueness_of :title, :case_sensitive => false
47
+ end
48
+
49
+ it "creates a compound index when a scope is passed" do
50
+ Article.should_receive(:index).with(:title, :author_id, :unique => true)
51
+ Article.validates_uniqueness_of :title, :scope => :author_id
52
+ end
53
+
54
+ it "does not create an index if :index => false" do
55
+ Article.should_not_receive(:index)
56
+ Article.validates_uniqueness_of :title, :index => false
57
+ end
58
+ end
59
+
34
60
  describe "basic case" do
35
61
  define_class(:Article, Document) do
36
62
  property :title, String
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ module MongoModel
4
+ describe Configuration do
5
+ it "uses a standard connection (Mongo::MongoClient) if no replicas are specified" do
6
+ Configuration.new({}).connection.should be_an_instance_of(Mongo::MongoClient)
7
+ end
8
+
9
+ it "uses a replica set connection (Mongo::MongoReplicaSetClient) if replicas are specified" do
10
+ Configuration.new({ :replicas => ['127.0.0.1:27017'], :connect => false }).connection.should be_an_instance_of(Mongo::MongoReplicaSetClient)
11
+ end
12
+ end
13
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongomodel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.3
4
+ version: 0.5.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Pohlenz
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-04-13 00:00:00.000000000 Z
11
+ date: 2014-07-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -259,6 +259,7 @@ files:
259
259
  - spec/mongomodel/embedded_document_spec.rb
260
260
  - spec/mongomodel/mongomodel_spec.rb
261
261
  - spec/mongomodel/support/collection_spec.rb
262
+ - spec/mongomodel/support/configuration_spec.rb
262
263
  - spec/mongomodel/support/map_spec.rb
263
264
  - spec/mongomodel/support/mongo_operator_spec.rb
264
265
  - spec/mongomodel/support/mongo_options_spec.rb