crnixon-mongomapper 0.2.0 → 0.3.4
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/History +48 -0
- data/README.rdoc +5 -3
- data/Rakefile +6 -4
- data/VERSION +1 -1
- data/bin/mmconsole +56 -0
- data/lib/mongomapper.rb +29 -18
- data/lib/mongomapper/associations.rb +53 -38
- data/lib/mongomapper/associations/base.rb +53 -20
- data/lib/mongomapper/associations/belongs_to_polymorphic_proxy.rb +34 -0
- data/lib/mongomapper/associations/belongs_to_proxy.rb +10 -14
- data/lib/mongomapper/associations/many_documents_as_proxy.rb +27 -0
- data/lib/mongomapper/associations/many_documents_proxy.rb +103 -0
- data/lib/mongomapper/associations/many_embedded_polymorphic_proxy.rb +33 -0
- data/lib/mongomapper/associations/{has_many_embedded_proxy.rb → many_embedded_proxy.rb} +6 -8
- data/lib/mongomapper/associations/many_polymorphic_proxy.rb +11 -0
- data/lib/mongomapper/associations/{array_proxy.rb → many_proxy.rb} +1 -1
- data/lib/mongomapper/associations/proxy.rb +24 -21
- data/lib/mongomapper/callbacks.rb +1 -1
- data/lib/mongomapper/document.rb +160 -74
- data/lib/mongomapper/dynamic_finder.rb +38 -0
- data/lib/mongomapper/embedded_document.rb +154 -105
- data/lib/mongomapper/finder_options.rb +11 -7
- data/lib/mongomapper/key.rb +15 -21
- data/lib/mongomapper/pagination.rb +52 -0
- data/lib/mongomapper/rails_compatibility/document.rb +15 -0
- data/lib/mongomapper/rails_compatibility/embedded_document.rb +25 -0
- data/lib/mongomapper/serialization.rb +1 -1
- data/lib/mongomapper/serializers/json_serializer.rb +15 -0
- data/lib/mongomapper/support.rb +30 -0
- data/mongomapper.gemspec +87 -46
- data/test/NOTE_ON_TESTING +1 -0
- data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +53 -0
- data/test/functional/associations/test_belongs_to_proxy.rb +45 -0
- data/test/functional/associations/test_many_documents_as_proxy.rb +253 -0
- data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +131 -0
- data/test/functional/associations/test_many_embedded_proxy.rb +106 -0
- data/test/functional/associations/test_many_polymorphic_proxy.rb +261 -0
- data/test/functional/associations/test_many_proxy.rb +295 -0
- data/test/functional/test_associations.rb +47 -0
- data/test/{test_callbacks.rb → functional/test_callbacks.rb} +2 -1
- data/test/functional/test_document.rb +952 -0
- data/test/functional/test_pagination.rb +81 -0
- data/test/functional/test_rails_compatibility.rb +30 -0
- data/test/functional/test_validations.rb +172 -0
- data/test/models.rb +169 -0
- data/test/test_helper.rb +7 -2
- data/test/unit/serializers/test_json_serializer.rb +189 -0
- data/test/unit/test_association_base.rb +144 -0
- data/test/unit/test_document.rb +123 -0
- data/test/unit/test_embedded_document.rb +526 -0
- data/test/{test_finder_options.rb → unit/test_finder_options.rb} +36 -1
- data/test/{test_key.rb → unit/test_key.rb} +59 -12
- data/test/{test_mongomapper.rb → unit/test_mongomapper.rb} +0 -0
- data/test/{test_observing.rb → unit/test_observing.rb} +0 -0
- data/test/unit/test_pagination.rb +113 -0
- data/test/unit/test_rails_compatibility.rb +34 -0
- data/test/{test_serializations.rb → unit/test_serializations.rb} +0 -2
- data/test/{test_validations.rb → unit/test_validations.rb} +0 -134
- metadata +81 -43
- data/lib/mongomapper/associations/has_many_proxy.rb +0 -28
- data/lib/mongomapper/associations/polymorphic_belongs_to_proxy.rb +0 -31
- data/lib/mongomapper/rails_compatibility.rb +0 -23
- data/test/serializers/test_json_serializer.rb +0 -104
- data/test/test_associations.rb +0 -174
- data/test/test_document.rb +0 -944
- data/test/test_embedded_document.rb +0 -253
- data/test/test_rails_compatibility.rb +0 -29
data/.gitignore
CHANGED
data/History
CHANGED
@@ -1,3 +1,51 @@
|
|
1
|
+
0.3.4 8/28/2009
|
2
|
+
* BACKWORDS COMPATIBILITY BREAK: Timestamps are now optional. To use them add timestamps! to your model.
|
3
|
+
* BACKWORDS COMPATIBILITY BREAK: Associations keys are no longer created automatically when you use belongs_to and many. Too much was hidden from the developer. You now have to declare them like key :creator_id, String and such.
|
4
|
+
* to_json now includes dynamic keys and embedded stuff by default
|
5
|
+
* added polymorphic many with :as option (dcu)
|
6
|
+
|
7
|
+
0.3.3 8/16/2009
|
8
|
+
* BACKWORDS COMPATIBILITY BREAK: _id is now once again a string rather than an object id and will stay that way.
|
9
|
+
* Custom id's can now be used because of the change to string id's
|
10
|
+
* Added dynamic finders to document. (dcu)
|
11
|
+
* Added destroy_all, delete_all and nullify for many document association
|
12
|
+
* Added :dependent option for many documents assocation (dcu)
|
13
|
+
* update_attributes now returns true or false instead of the document. (Durran Jordan and me)
|
14
|
+
* Keys no longer require a type
|
15
|
+
* Keys can now be added on the fly using []=
|
16
|
+
|
17
|
+
0.3.2 8/6/2009
|
18
|
+
* Added many polymorphic documents association
|
19
|
+
* Implemented build and create for many and many polymorphic documents
|
20
|
+
* <<, push and concat now work correctly for many and many polymorphic documents
|
21
|
+
* find(:first) now accepts order option
|
22
|
+
* id is now included by default with to_json
|
23
|
+
* _id is now always excluded from to_json
|
24
|
+
* Times are now always returned as UTC
|
25
|
+
* Default values are now a bit more intelligent for Array and Hash keys (djsun)
|
26
|
+
* Embedded documents now have _id as well so they can be identified more easily
|
27
|
+
|
28
|
+
0.3.1 7/28/2009
|
29
|
+
* 1 minor tweak
|
30
|
+
* Removed deep_merge gem as dependency as ActiveSupport has deep_merge that works good enough
|
31
|
+
|
32
|
+
0.3.0 7/28/2009
|
33
|
+
* 5 major additions, 3 minor additions, 3 bug fix, and other miscellany
|
34
|
+
* BACKWORDS COMPATIBILITY BREAK: _id is now stored in binary form (recommended by mongodb team) instead of string, api is the same everywhere as before but data stored with string id's previous to change will need to be updated
|
35
|
+
* Added Document#paginate which works just like find but adds pagination (dcu did basics and I pimped)
|
36
|
+
* Added a basic console for playing around with MongoMapper (dcu)
|
37
|
+
* Embedded associations can now be deeply nested (Keith Hanson)
|
38
|
+
* Added support for many polymorphic documents (Felipe Coury and Me)
|
39
|
+
* Fixed bug where conditions that disallowed using $in, $all and $any with an array
|
40
|
+
* Bumped version of validatable so :if validation option supports symbol/string to proc.
|
41
|
+
* Document#create with no attributes now creates a document as long as it is valid
|
42
|
+
* Now defining accessor methods when key is declared rather than using method missing and all that jazz
|
43
|
+
* Attributes now have boolean methods that return true or false based on whether they have value present
|
44
|
+
* Added scoped finds and pagination on many document association.
|
45
|
+
* find first and last now use natural order which is more reliable.
|
46
|
+
* Updated to latest ruby driver (0.10.1)
|
47
|
+
|
48
|
+
|
1
49
|
0.2.0 7/7/2009
|
2
50
|
* 2 major additions (observers, associations), several minor additions, and a few bug fixes
|
3
51
|
* Added observers
|
data/README.rdoc
CHANGED
@@ -2,16 +2,18 @@
|
|
2
2
|
|
3
3
|
Awesome gem for modeling your domain and storing it in mongo.
|
4
4
|
|
5
|
-
|
5
|
+
Releases are tagged on github and also released as gems on github and rubyforge. Master is pushed to whenever I add a patch or a new feature. To build from master, you can clone the code, generate the updated gemspec, build the gem and install.
|
6
6
|
|
7
|
-
|
7
|
+
* rake gemspec
|
8
|
+
* gem build mongomapper.gemspec
|
9
|
+
* gem install the gem that was built
|
8
10
|
|
9
11
|
== Note on Patches/Pull Requests
|
10
12
|
|
11
13
|
* Fork the project.
|
12
14
|
* Make your feature addition or bug fix.
|
13
15
|
* Add tests for it. This is important so I don't break it in a future version unintentionally.
|
14
|
-
* Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
16
|
+
* Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself in another branch so I can ignore when I pull)
|
15
17
|
* Send me a pull request. Bonus points for topic branches.
|
16
18
|
|
17
19
|
== Dependencies
|
data/Rakefile
CHANGED
@@ -12,14 +12,16 @@ begin
|
|
12
12
|
gem.rubyforge_project = "mongomapper"
|
13
13
|
|
14
14
|
gem.add_dependency('activesupport')
|
15
|
-
gem.add_dependency('mongodb-mongo', '0.
|
16
|
-
gem.add_dependency('jnunemaker-validatable', '1.7.
|
15
|
+
gem.add_dependency('mongodb-mongo', '0.11.1')
|
16
|
+
gem.add_dependency('jnunemaker-validatable', '1.7.2')
|
17
17
|
|
18
18
|
gem.add_development_dependency('mocha', '0.9.4')
|
19
19
|
gem.add_development_dependency('jnunemaker-matchy', '0.4.0')
|
20
20
|
end
|
21
|
-
|
22
|
-
Jeweler::RubyforgeTasks.new
|
21
|
+
|
22
|
+
Jeweler::RubyforgeTasks.new do |rubyforge|
|
23
|
+
rubyforge.doc_task = "rdoc"
|
24
|
+
end
|
23
25
|
rescue LoadError
|
24
26
|
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
25
27
|
end
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.4
|
data/bin/mmconsole
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$:.unshift File.dirname(__FILE__)+"/../lib"
|
3
|
+
|
4
|
+
require 'mongomapper'
|
5
|
+
require 'irb'
|
6
|
+
|
7
|
+
IRB.setup(nil)
|
8
|
+
irb = IRB::Irb.new
|
9
|
+
|
10
|
+
IRB.conf[:MAIN_CONTEXT] = irb.context
|
11
|
+
|
12
|
+
irb.context.evaluate("require 'irb/completion'", 0)
|
13
|
+
irb.context.evaluate(%@
|
14
|
+
include XGen::Mongo::Driver
|
15
|
+
include MongoMapper
|
16
|
+
|
17
|
+
MongoMapper.database = "mmtest"
|
18
|
+
$db = MongoMapper.database
|
19
|
+
|
20
|
+
@, 0)
|
21
|
+
|
22
|
+
puts %@
|
23
|
+
Welcome to the MongoMapper Console!
|
24
|
+
|
25
|
+
Example 1:
|
26
|
+
things = $db.collection("things")
|
27
|
+
things.insert("name" => "Raw Thing")
|
28
|
+
things.insert("name" => "Another Thing", "date" => Time.now)
|
29
|
+
|
30
|
+
cursor = things.find("name" => "Raw Thing")
|
31
|
+
puts cursor.next_object.inspect
|
32
|
+
|
33
|
+
Example 2:
|
34
|
+
class Thing
|
35
|
+
include MongoMapper::Document
|
36
|
+
key :name, String, :required => true
|
37
|
+
key :date, Time
|
38
|
+
end
|
39
|
+
|
40
|
+
thing = Thing.new
|
41
|
+
thing.name = "My thing"
|
42
|
+
thing.date = Time.now
|
43
|
+
thing.save
|
44
|
+
|
45
|
+
all_things = Thing.all
|
46
|
+
puts all_things.map { |object| object.name }.inspect
|
47
|
+
|
48
|
+
@
|
49
|
+
|
50
|
+
trap("SIGINT") do
|
51
|
+
irb.signal_handle
|
52
|
+
end
|
53
|
+
catch(:IRB_EXIT) do
|
54
|
+
irb.eval_input
|
55
|
+
end
|
56
|
+
|
data/lib/mongomapper.rb
CHANGED
@@ -2,8 +2,8 @@ require 'pathname'
|
|
2
2
|
require 'rubygems'
|
3
3
|
|
4
4
|
gem 'activesupport'
|
5
|
-
gem 'mongodb-mongo', '0.
|
6
|
-
gem 'jnunemaker-validatable', '1.7.
|
5
|
+
gem 'mongodb-mongo', '0.11.1'
|
6
|
+
gem 'jnunemaker-validatable', '1.7.2'
|
7
7
|
|
8
8
|
require 'activesupport'
|
9
9
|
require 'mongo'
|
@@ -11,37 +11,48 @@ require 'validatable'
|
|
11
11
|
|
12
12
|
dir = Pathname(__FILE__).dirname.expand_path + 'mongomapper'
|
13
13
|
|
14
|
-
require dir + '
|
14
|
+
require dir + 'support'
|
15
|
+
|
16
|
+
require dir + 'associations'
|
17
|
+
require dir + 'associations/base'
|
18
|
+
|
19
|
+
require dir + 'associations/proxy'
|
20
|
+
require dir + 'associations/many_documents_proxy'
|
21
|
+
|
22
|
+
require dir + 'associations/belongs_to_proxy'
|
23
|
+
require dir + 'associations/belongs_to_polymorphic_proxy'
|
24
|
+
require dir + 'associations/many_proxy'
|
25
|
+
require dir + 'associations/many_polymorphic_proxy'
|
26
|
+
require dir + 'associations/many_embedded_proxy'
|
27
|
+
require dir + 'associations/many_embedded_polymorphic_proxy'
|
28
|
+
require dir + 'associations/many_documents_as_proxy'
|
29
|
+
|
30
|
+
require dir + 'callbacks'
|
15
31
|
require dir + 'finder_options'
|
16
|
-
require dir + '
|
32
|
+
require dir + 'dynamic_finder'
|
33
|
+
require dir + 'key'
|
34
|
+
require dir + 'observing'
|
35
|
+
require dir + 'pagination'
|
17
36
|
require dir + 'save_with_validation'
|
18
37
|
require dir + 'serialization'
|
19
|
-
require dir + 'callbacks'
|
20
|
-
require dir + 'observing'
|
21
38
|
require dir + 'validations'
|
22
39
|
|
23
|
-
require dir + '
|
24
|
-
require dir + '
|
25
|
-
require dir + 'associations/base'
|
26
|
-
|
27
|
-
require dir + 'associations/has_many_proxy'
|
28
|
-
require dir + 'associations/has_many_embedded_proxy'
|
29
|
-
require dir + 'associations/belongs_to_proxy'
|
30
|
-
require dir + 'associations/polymorphic_belongs_to_proxy'
|
31
|
-
require dir + 'associations'
|
40
|
+
require dir + 'rails_compatibility/document'
|
41
|
+
require dir + 'rails_compatibility/embedded_document'
|
32
42
|
|
33
43
|
require dir + 'embedded_document'
|
34
44
|
require dir + 'document'
|
35
45
|
|
36
46
|
module MongoMapper
|
37
|
-
|
38
|
-
|
47
|
+
DocumentNotFound = Class.new(StandardError)
|
48
|
+
|
49
|
+
DocumentNotValid = Class.new(StandardError) do
|
39
50
|
def initialize(document)
|
40
51
|
@document = document
|
41
52
|
super("Validation failed: #{@document.errors.full_messages.join(", ")}")
|
42
53
|
end
|
43
54
|
end
|
44
|
-
|
55
|
+
|
45
56
|
def self.connection
|
46
57
|
@@connection ||= XGen::Mongo::Driver::Mongo.new
|
47
58
|
end
|
@@ -2,33 +2,12 @@ module MongoMapper
|
|
2
2
|
module Associations
|
3
3
|
module ClassMethods
|
4
4
|
def belongs_to(association_id, options = {})
|
5
|
-
|
6
|
-
|
7
|
-
ref_id = "#{association_id}_id"
|
8
|
-
key ref_id, String
|
9
|
-
|
10
|
-
define_method("#{ref_id}=") do |value|
|
11
|
-
write_attribute(ref_id, value)
|
12
|
-
end
|
13
|
-
|
14
|
-
if options[:polymorphic]
|
15
|
-
ref_type = "#{association_id}_type"
|
16
|
-
key ref_type, String
|
17
|
-
|
18
|
-
define_method("#{ref_type}=") do |value|
|
19
|
-
write_attribute(ref_type, value)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
define_association_methods(association)
|
24
|
-
|
5
|
+
create_association(:belongs_to, association_id, options)
|
25
6
|
self
|
26
7
|
end
|
27
8
|
|
28
9
|
def many(association_id, options = {})
|
29
|
-
|
30
|
-
define_association_methods(association)
|
31
|
-
|
10
|
+
create_association(:many, association_id, options)
|
32
11
|
self
|
33
12
|
end
|
34
13
|
|
@@ -37,31 +16,67 @@ module MongoMapper
|
|
37
16
|
end
|
38
17
|
|
39
18
|
private
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
19
|
+
def create_association(type, name, options)
|
20
|
+
association = Associations::Base.new(type, name, options)
|
21
|
+
associations[association.name] = association
|
22
|
+
define_association_methods(association)
|
23
|
+
define_dependent_callback(association)
|
24
|
+
association
|
25
|
+
end
|
45
26
|
|
46
|
-
|
47
|
-
|
48
|
-
|
27
|
+
def define_association_methods(association)
|
28
|
+
define_method(association.name) do
|
29
|
+
get_proxy(association)
|
30
|
+
end
|
31
|
+
|
32
|
+
define_method("#{association.name}=") do |value|
|
33
|
+
get_proxy(association).replace(value)
|
34
|
+
value
|
35
|
+
end
|
49
36
|
end
|
50
37
|
|
51
|
-
|
52
|
-
|
53
|
-
|
38
|
+
def define_dependent_callback(association)
|
39
|
+
if association.options[:dependent]
|
40
|
+
if association.many?
|
41
|
+
define_dependent_callback_for_many(association)
|
42
|
+
elsif association.belongs_to?
|
43
|
+
define_dependent_callback_for_belongs_to(association)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def define_dependent_callback_for_many(association)
|
49
|
+
return if association.embeddable?
|
50
|
+
|
51
|
+
after_destroy do |doc|
|
52
|
+
case association.options[:dependent]
|
53
|
+
when :destroy
|
54
|
+
doc.get_proxy(association).destroy_all
|
55
|
+
when :delete_all
|
56
|
+
doc.get_proxy(association).delete_all
|
57
|
+
when :nullify
|
58
|
+
doc.get_proxy(association).nullify
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def define_dependent_callback_for_belongs_to(association)
|
64
|
+
after_destroy do |doc|
|
65
|
+
case association.options[:dependent]
|
66
|
+
when :destroy
|
67
|
+
doc.get_proxy(association).destroy
|
68
|
+
end
|
69
|
+
end
|
54
70
|
end
|
55
|
-
end
|
56
71
|
end
|
57
72
|
|
58
73
|
module InstanceMethods
|
59
74
|
def get_proxy(association)
|
60
|
-
proxy = self.instance_variable_get(association.ivar)
|
61
|
-
if proxy.nil?
|
75
|
+
unless proxy = self.instance_variable_get(association.ivar)
|
62
76
|
proxy = association.proxy_class.new(self, association)
|
63
|
-
self.instance_variable_set(association.ivar, proxy)
|
77
|
+
self.instance_variable_set(association.ivar, proxy) if !frozen?
|
64
78
|
end
|
79
|
+
|
65
80
|
proxy
|
66
81
|
end
|
67
82
|
end
|
@@ -4,20 +4,14 @@ module MongoMapper
|
|
4
4
|
attr_reader :type, :name, :options
|
5
5
|
|
6
6
|
def initialize(type, name, options = {})
|
7
|
-
@options = options
|
8
|
-
@type = type
|
9
|
-
@name = name
|
10
|
-
end
|
11
|
-
|
12
|
-
def klass
|
13
|
-
class_name.constantize
|
7
|
+
@type, @name, @options = type, name, options
|
14
8
|
end
|
15
9
|
|
16
10
|
def class_name
|
17
11
|
@class_name ||= begin
|
18
12
|
if cn = options[:class_name]
|
19
13
|
cn
|
20
|
-
elsif
|
14
|
+
elsif many?
|
21
15
|
name.to_s.singularize.camelize
|
22
16
|
else
|
23
17
|
name.to_s.camelize
|
@@ -25,26 +19,65 @@ module MongoMapper
|
|
25
19
|
end
|
26
20
|
end
|
27
21
|
|
22
|
+
def klass
|
23
|
+
@klass ||= class_name.constantize
|
24
|
+
end
|
25
|
+
|
26
|
+
def many?
|
27
|
+
@many_type ||= @type == :many
|
28
|
+
end
|
29
|
+
|
30
|
+
def belongs_to?
|
31
|
+
@belongs_to_type ||= @type == :belongs_to
|
32
|
+
end
|
33
|
+
|
34
|
+
def polymorphic?
|
35
|
+
!!@options[:polymorphic]
|
36
|
+
end
|
37
|
+
|
38
|
+
def as?
|
39
|
+
!!@options[:as]
|
40
|
+
end
|
41
|
+
|
42
|
+
def type_key_name
|
43
|
+
@type_key_name ||= many? ? '_type' : "#{as}_type"
|
44
|
+
end
|
45
|
+
|
46
|
+
def as
|
47
|
+
@options[:as] || self.name
|
48
|
+
end
|
49
|
+
|
50
|
+
def foreign_key
|
51
|
+
@options[:foreign_key] || "#{name}_id"
|
52
|
+
end
|
53
|
+
|
28
54
|
def ivar
|
29
55
|
@ivar ||= "@_#{name}"
|
30
56
|
end
|
31
57
|
|
58
|
+
def embeddable?
|
59
|
+
many? && klass.embeddable?
|
60
|
+
end
|
61
|
+
|
32
62
|
def proxy_class
|
33
|
-
|
34
|
-
|
35
|
-
if @options[:polymorphic]
|
36
|
-
PolymorphicBelongsToProxy
|
37
|
-
else
|
38
|
-
BelongsToProxy
|
39
|
-
end
|
40
|
-
when :many
|
63
|
+
@proxy_class ||= begin
|
64
|
+
if many?
|
41
65
|
if self.klass.embeddable?
|
42
|
-
|
66
|
+
polymorphic? ? ManyEmbeddedPolymorphicProxy : ManyEmbeddedProxy
|
43
67
|
else
|
44
|
-
|
68
|
+
if polymorphic?
|
69
|
+
ManyPolymorphicProxy
|
70
|
+
elsif as?
|
71
|
+
ManyDocumentsAsProxy
|
72
|
+
else
|
73
|
+
ManyProxy
|
74
|
+
end
|
45
75
|
end
|
46
|
-
|
47
|
-
|
76
|
+
else
|
77
|
+
polymorphic? ? BelongsToPolymorphicProxy : BelongsToProxy
|
78
|
+
end
|
79
|
+
end # end begin
|
80
|
+
end # end proxy_class
|
48
81
|
end
|
49
82
|
end
|
50
83
|
end
|