mongo_mapper-unstable 2010.1.27 → 2010.1.28

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -12,7 +12,7 @@ Jeweler::Tasks.new do |gem|
12
12
  gem.authors = ["John Nunemaker"]
13
13
 
14
14
  gem.add_dependency('activesupport', '>= 2.3')
15
- gem.add_dependency('mongo', '0.18.2')
15
+ gem.add_dependency('mongo', '0.18.3')
16
16
  gem.add_dependency('jnunemaker-validatable', '1.8.1')
17
17
 
18
18
  gem.add_development_dependency('jnunemaker-matchy', '0.4.0')
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2010.01.27
1
+ 2010.01.28
@@ -7,8 +7,8 @@ module MongoMapper
7
7
  include InstanceMethods
8
8
  extend ClassMethods
9
9
  extend Finders
10
-
11
10
  extend Plugins
11
+
12
12
  plugin Plugins::Associations
13
13
  plugin Plugins::Clone
14
14
  plugin Plugins::Descendants
@@ -18,6 +18,7 @@ module MongoMapper
18
18
  plugin Plugins::Dirty # for now dirty needs to be after keys
19
19
  plugin Plugins::Logger
20
20
  plugin Plugins::Pagination
21
+ plugin Plugins::Protected
21
22
  plugin Plugins::Rails
22
23
  plugin Plugins::Serialization
23
24
  plugin Plugins::Validations
@@ -69,6 +70,21 @@ module MongoMapper
69
70
  end
70
71
  end
71
72
 
73
+ def find_or_create(arg)
74
+ first(arg) || create(arg)
75
+ end
76
+
77
+ def find_each(options={})
78
+ criteria, options = to_finder_options(options)
79
+ collection.find(criteria, options).each do |doc|
80
+ yield load(doc)
81
+ end
82
+ end
83
+
84
+ def find_by_id(id)
85
+ find(id)
86
+ end
87
+
72
88
  def first(options={})
73
89
  find_one(options)
74
90
  end
@@ -82,21 +98,10 @@ module MongoMapper
82
98
  find_many(options)
83
99
  end
84
100
 
85
- def find_by_id(id)
86
- find(id)
87
- end
88
-
89
101
  def count(options={})
90
102
  collection.find(to_criteria(options)).count
91
103
  end
92
104
 
93
- def find_each(options={})
94
- criteria, options = to_finder_options(options)
95
- collection.find(criteria, options).each do |doc|
96
- yield load(doc)
97
- end
98
- end
99
-
100
105
  def exists?(options={})
101
106
  !count(options).zero?
102
107
  end
@@ -1,13 +1,13 @@
1
1
  module MongoMapper
2
2
  module EmbeddedDocument
3
3
  extend DescendantAppends
4
-
4
+
5
5
  def self.included(model)
6
6
  model.class_eval do
7
7
  include InstanceMethods
8
8
  extend ClassMethods
9
-
10
9
  extend Plugins
10
+
11
11
  plugin Plugins::Associations
12
12
  plugin Plugins::Clone
13
13
  plugin Plugins::Descendants
@@ -15,13 +15,14 @@ module MongoMapper
15
15
  plugin Plugins::Inspect
16
16
  plugin Plugins::Keys
17
17
  plugin Plugins::Logger
18
+ plugin Plugins::Protected
18
19
  plugin Plugins::Rails
19
20
  plugin Plugins::Serialization
20
21
  plugin Plugins::Validations
21
22
 
22
- attr_accessor :_root_document
23
+ attr_accessor :_root_document, :_parent_document
23
24
  end
24
-
25
+
25
26
  super
26
27
  end
27
28
 
@@ -29,6 +30,12 @@ module MongoMapper
29
30
  def embeddable?
30
31
  true
31
32
  end
33
+
34
+ def embedded_in(owner_name)
35
+ define_method(owner_name) do
36
+ self._parent_document
37
+ end
38
+ end
32
39
  end
33
40
 
34
41
  module InstanceMethods
@@ -38,7 +45,7 @@ module MongoMapper
38
45
  end
39
46
  result
40
47
  end
41
-
48
+
42
49
  def save!(options={})
43
50
  if result = _root_document.try(:save!, options)
44
51
  @new = false
@@ -41,6 +41,7 @@ module MongoMapper
41
41
  def assign_root_document(*docs)
42
42
  docs.each do |doc|
43
43
  doc._root_document = _root_document
44
+ doc._parent_document = owner
44
45
  end
45
46
  end
46
47
  end
@@ -122,6 +122,14 @@ module MongoMapper
122
122
  validates_format_of(attribute, :with => key.options[:format])
123
123
  end
124
124
 
125
+ if key.options[:in]
126
+ validates_inclusion_of(attribute, :within => key.options[:in])
127
+ end
128
+
129
+ if key.options[:not_in]
130
+ validates_exclusion_of(attribute, :within => key.options[:not_in])
131
+ end
132
+
125
133
  if key.options[:length]
126
134
  length_options = case key.options[:length]
127
135
  when Integer
@@ -289,4 +297,4 @@ module MongoMapper
289
297
  end
290
298
  end
291
299
  end
292
- end
300
+ end
@@ -0,0 +1,41 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module Protected
4
+ module ClassMethods
5
+ def attr_protected(*attrs)
6
+ self.write_inheritable_attribute(:attr_protected, Set.new(attrs) + (protected_attributes || []))
7
+ end
8
+
9
+ def protected_attributes
10
+ self.read_inheritable_attribute(:attr_protected)
11
+ end
12
+
13
+ def key(*args)
14
+ key = super
15
+ attr_protected key.name.to_sym if key.options[:protected]
16
+ key
17
+ end
18
+ end
19
+
20
+ module InstanceMethods
21
+ def update_attributes(attrs={})
22
+ super(filter_protected_attrs(attrs))
23
+ end
24
+
25
+ def update_attributes!(attrs={})
26
+ super(filter_protected_attrs(attrs))
27
+ end
28
+
29
+ def protected_attributes
30
+ self.class.protected_attributes
31
+ end
32
+
33
+ protected
34
+ def filter_protected_attrs(attrs)
35
+ return attrs if protected_attributes.blank?
36
+ attrs.dup.delete_if { |key, val| protected_attributes.include?(key) }
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -205,8 +205,9 @@ class Time
205
205
  end
206
206
  end
207
207
 
208
- # TODO: Remove when patch accepted into driver
209
208
  class Mongo::ObjectID
209
+ alias_method :original_to_json, :to_json
210
+
210
211
  def to_json(options = nil)
211
212
  %Q("#{to_s}")
212
213
  end
data/lib/mongo_mapper.rb CHANGED
@@ -6,7 +6,7 @@ require 'set'
6
6
  # if there is a better way to do this, please enlighten me!
7
7
  if self.class.const_defined?(:Gem)
8
8
  gem 'activesupport', '>= 2.3'
9
- gem 'mongo', '0.18.2'
9
+ gem 'mongo', '0.18.3'
10
10
  gem 'jnunemaker-validatable', '1.8.1'
11
11
  end
12
12
 
@@ -117,6 +117,7 @@ require 'mongo_mapper/plugins/inspect'
117
117
  require 'mongo_mapper/plugins/keys'
118
118
  require 'mongo_mapper/plugins/logger'
119
119
  require 'mongo_mapper/plugins/pagination'
120
+ require 'mongo_mapper/plugins/protected'
120
121
  require 'mongo_mapper/plugins/rails'
121
122
  require 'mongo_mapper/plugins/serialization'
122
123
  require 'mongo_mapper/plugins/validations'
@@ -15,6 +15,7 @@ class ManyEmbeddedProxyTest < Test::Unit::TestCase
15
15
  @pet_class = EDoc do
16
16
  key :name, String
17
17
  end
18
+ @pet_class.embedded_in :person
18
19
  @person_class = EDoc do
19
20
  key :name, String
20
21
  end
@@ -133,6 +134,17 @@ class ManyEmbeddedProxyTest < Test::Unit::TestCase
133
134
  doc.people.first._root_document.should == doc
134
135
  doc.people.first.pets.first._root_document.should == doc
135
136
  end
137
+ should "create a reference to the owning document for all embedded documents before save" do
138
+ doc = @klass.new
139
+ meg = @person_class.new(:name => 'Meg')
140
+ pet = @pet_class.new(:name => 'Sparky', :species => 'Dog')
141
+
142
+ doc.people << meg
143
+ meg.pets << pet
144
+
145
+ doc.people.first._parent_document.should == doc
146
+ doc.people.first.pets.first._parent_document.should == doc.people.first
147
+ end
136
148
 
137
149
  should "create a reference to the root document for all embedded documents" do
138
150
  sparky = @pet_class.new(:name => 'Sparky', :species => 'Dog')
@@ -145,6 +157,32 @@ class ManyEmbeddedProxyTest < Test::Unit::TestCase
145
157
  doc.people.first._root_document.should == doc
146
158
  doc.people.first.pets.first._root_document.should == doc
147
159
  end
160
+ should "create a reference to the owning document for all embedded documents" do
161
+ doc = @klass.new
162
+ meg = @person_class.new(:name => 'Meg')
163
+ pet = @pet_class.new(:name => 'Sparky', :species => 'Dog')
164
+
165
+ doc.people << meg
166
+ meg.pets << pet
167
+ doc.save
168
+
169
+ doc.reload
170
+ doc.people.first._parent_document.should == doc
171
+ doc.people.first.pets.first._parent_document.should == doc.people.first
172
+ end
173
+
174
+ should "create embedded_in relationship for embedded docs" do
175
+ doc = @klass.new
176
+ meg = @person_class.new(:name => 'Meg')
177
+ pet = @pet_class.new(:name => 'Sparky', :species => 'Dog')
178
+
179
+ doc.people << meg
180
+ meg.pets << pet
181
+ doc.save
182
+
183
+ doc.reload
184
+ doc.people.first.pets.first.person.should == doc.people.first
185
+ end
148
186
  end
149
187
 
150
188
  should "allow finding by id" do
@@ -13,7 +13,7 @@ class DocumentTest < Test::Unit::TestCase
13
13
  end
14
14
  end
15
15
 
16
- context "Using key with type Array" do
16
+ context "array key" do
17
17
  setup do
18
18
  @document.key :tags, Array
19
19
  end
@@ -60,7 +60,7 @@ class DocumentTest < Test::Unit::TestCase
60
60
  end
61
61
  end
62
62
 
63
- context "Using key with type Hash" do
63
+ context "hash key" do
64
64
  setup do
65
65
  @document.key :foo, Hash
66
66
  end
@@ -95,7 +95,7 @@ class DocumentTest < Test::Unit::TestCase
95
95
  end
96
96
  end
97
97
 
98
- context "Using key with custom type with default" do
98
+ context "custom type key with default" do
99
99
  setup do
100
100
  @document.key :window, WindowSize, :default => WindowSize.new(600, 480)
101
101
  end
@@ -407,6 +407,24 @@ class DocumentTest < Test::Unit::TestCase
407
407
  end
408
408
  end
409
409
 
410
+ context "find_or_create" do
411
+ should "find if exists" do
412
+ created = @document.create(:first_name => 'John', :last_name => 'Nunemaker')
413
+ lambda {
414
+ found = @document.find_or_create(:first_name => 'John', :last_name => 'Nunemaker')
415
+ found.should == created
416
+ }.should_not change { @document.count }
417
+ end
418
+
419
+ should "create if not found" do
420
+ lambda {
421
+ created = @document.find_or_create(:first_name => 'John', :last_name => 'Nunemaker')
422
+ created.first_name.should == 'John'
423
+ created.last_name.should == 'Nunemaker'
424
+ }.should change { @document.count }.by(1)
425
+ end
426
+ end
427
+
410
428
  context "ClassMethods#delete (single document)" do
411
429
  setup do
412
430
  @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
@@ -568,10 +586,10 @@ class DocumentTest < Test::Unit::TestCase
568
586
  @document.new.database.should == @document.database
569
587
  end
570
588
 
571
- context "#save (new document)" do
589
+ context "#update_attributes (new document)" do
572
590
  setup do
573
591
  @doc = @document.new(:first_name => 'John', :age => '27')
574
- @doc.save
592
+ @doc.update_attributes(:first_name => 'Johnny', :age => 30)
575
593
  end
576
594
 
577
595
  should "insert document into the collection" do
@@ -583,54 +601,27 @@ class DocumentTest < Test::Unit::TestCase
583
601
  end
584
602
 
585
603
  should "save attributes" do
586
- @doc.first_name.should == 'John'
587
- @doc.age.should == 27
604
+ @doc.first_name.should == 'Johnny'
605
+ @doc.age.should == 30
588
606
  end
589
607
 
590
608
  should "update attributes in the database" do
591
609
  doc = @doc.reload
592
610
  doc.should == @doc
593
- doc.first_name.should == 'John'
594
- doc.age.should == 27
595
- end
596
-
597
- should "allow to add custom attributes to the document" do
598
- @doc = @document.new(:first_name => 'David', :age => '26', :gender => 'male', :tags => [1, "2"])
599
- @doc.save
600
- doc = @doc.reload
601
- doc.gender.should == 'male'
602
- doc.tags.should == [1, "2"]
603
- end
604
-
605
- should "allow to use custom methods to assign properties" do
606
- klass = Doc do
607
- key :name, String
608
-
609
- def realname=(value)
610
- self.name = value
611
- end
612
- end
613
-
614
- person = klass.new(:realname => 'David')
615
- person.save
616
- person.reload.name.should == 'David'
611
+ doc.first_name.should == 'Johnny'
612
+ doc.age.should == 30
617
613
  end
618
614
 
619
- context "with key of type date" do
620
- should "save the date value as a Time object" do
621
- doc = @document.new(:first_name => 'John', :age => '27', :date => "12/01/2009")
622
- doc.save
623
- doc.date.should == Date.new(2009, 12, 1)
624
- end
615
+ should "allow updating custom attributes" do
616
+ @doc.update_attributes(:gender => 'mALe')
617
+ @doc.reload.gender.should == 'mALe'
625
618
  end
626
619
  end
627
620
 
628
- context "#save (existing document)" do
621
+ context "#update_attributes (existing document)" do
629
622
  setup do
630
623
  @doc = @document.create(:first_name => 'John', :age => '27')
631
- @doc.first_name = 'Johnny'
632
- @doc.age = 30
633
- @doc.save
624
+ @doc.update_attributes(:first_name => 'Johnny', :age => 30)
634
625
  end
635
626
 
636
627
  should "not insert document into collection" do
@@ -647,19 +638,26 @@ class DocumentTest < Test::Unit::TestCase
647
638
  doc.first_name.should == 'Johnny'
648
639
  doc.age.should == 30
649
640
  end
641
+ end
650
642
 
651
- should "allow updating custom attributes" do
652
- @doc = @document.new(:first_name => 'David', :age => '26', :gender => 'male')
653
- @doc.gender = 'Male'
654
- @doc.save
655
- @doc.reload.gender.should == 'Male'
643
+ context "#update_attributes (return value)" do
644
+ setup do
645
+ @document.key :foo, String, :required => true
656
646
  end
657
- end
658
647
 
659
- context "#update_attributes (new document)" do
648
+ should "be true if document valid" do
649
+ @document.new.update_attributes(:foo => 'bar').should be_true
650
+ end
651
+
652
+ should "be false if document not valid" do
653
+ @document.new.update_attributes({}).should be_false
654
+ end
655
+ end
656
+
657
+ context "#save (new document)" do
660
658
  setup do
661
659
  @doc = @document.new(:first_name => 'John', :age => '27')
662
- @doc.update_attributes(:first_name => 'Johnny', :age => 30)
660
+ @doc.save
663
661
  end
664
662
 
665
663
  should "insert document into the collection" do
@@ -671,27 +669,54 @@ class DocumentTest < Test::Unit::TestCase
671
669
  end
672
670
 
673
671
  should "save attributes" do
674
- @doc.first_name.should == 'Johnny'
675
- @doc.age.should == 30
672
+ @doc.first_name.should == 'John'
673
+ @doc.age.should == 27
676
674
  end
677
675
 
678
676
  should "update attributes in the database" do
679
677
  doc = @doc.reload
680
678
  doc.should == @doc
681
- doc.first_name.should == 'Johnny'
682
- doc.age.should == 30
679
+ doc.first_name.should == 'John'
680
+ doc.age.should == 27
683
681
  end
684
682
 
685
- should "allow updating custom attributes" do
686
- @doc.update_attributes(:gender => 'mALe')
687
- @doc.reload.gender.should == 'mALe'
683
+ should "allow to add custom attributes to the document" do
684
+ @doc = @document.new(:first_name => 'David', :age => '26', :gender => 'male', :tags => [1, "2"])
685
+ @doc.save
686
+ doc = @doc.reload
687
+ doc.gender.should == 'male'
688
+ doc.tags.should == [1, "2"]
689
+ end
690
+
691
+ should "allow to use custom methods to assign properties" do
692
+ klass = Doc do
693
+ key :name, String
694
+
695
+ def realname=(value)
696
+ self.name = value
697
+ end
698
+ end
699
+
700
+ person = klass.new(:realname => 'David')
701
+ person.save
702
+ person.reload.name.should == 'David'
703
+ end
704
+
705
+ context "with key of type date" do
706
+ should "save the date value as a Time object" do
707
+ doc = @document.new(:first_name => 'John', :age => '27', :date => "12/01/2009")
708
+ doc.save
709
+ doc.date.should == Date.new(2009, 12, 1)
710
+ end
688
711
  end
689
712
  end
690
713
 
691
- context "#update_attributes (existing document)" do
714
+ context "#save (existing document)" do
692
715
  setup do
693
716
  @doc = @document.create(:first_name => 'John', :age => '27')
694
- @doc.update_attributes(:first_name => 'Johnny', :age => 30)
717
+ @doc.first_name = 'Johnny'
718
+ @doc.age = 30
719
+ @doc.save
695
720
  end
696
721
 
697
722
  should "not insert document into collection" do
@@ -708,22 +733,15 @@ class DocumentTest < Test::Unit::TestCase
708
733
  doc.first_name.should == 'Johnny'
709
734
  doc.age.should == 30
710
735
  end
711
- end
712
-
713
- context "#update_attributes" do
714
- setup do
715
- @document.key :foo, String, :required => true
716
- end
717
-
718
- should "return true if document valid" do
719
- @document.new.update_attributes(:foo => 'bar').should be_true
720
- end
721
736
 
722
- should "return false if document not valid" do
723
- @document.new.update_attributes({}).should be_false
737
+ should "allow updating custom attributes" do
738
+ @doc = @document.new(:first_name => 'David', :age => '26', :gender => 'male')
739
+ @doc.gender = 'Male'
740
+ @doc.save
741
+ @doc.reload.gender.should == 'Male'
724
742
  end
725
743
  end
726
-
744
+
727
745
  context "#save (with validations off)" do
728
746
  setup do
729
747
  @document = Doc do
@@ -1091,7 +1109,7 @@ class DocumentTest < Test::Unit::TestCase
1091
1109
  end
1092
1110
  end
1093
1111
 
1094
- context "#exist?" do
1112
+ context "#exists?" do
1095
1113
  setup do
1096
1114
  @doc = @document.create(:first_name => "James", :age => 27)
1097
1115
  end
@@ -1162,7 +1180,7 @@ class DocumentTest < Test::Unit::TestCase
1162
1180
  end
1163
1181
  end
1164
1182
 
1165
- context "Loading a document from the database with keys that are not defined" do
1183
+ context "database has keys not defined in model" do
1166
1184
  setup do
1167
1185
  @id = Mongo::ObjectID.new
1168
1186
  @document.collection.insert({