mongodb_model 2.0.2 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -2,7 +2,7 @@ require 'rake_ext'
2
2
 
3
3
  project \
4
4
  name: "mongodb_model",
5
- # version: '2.0.0',
5
+ version: '2.1.0',
6
6
  gem: true,
7
7
  summary: "Object Model for MongoDB",
8
8
 
@@ -23,7 +23,8 @@ module Mongo::Model::Assignment
23
23
  v = type.cast(v) if type
24
24
  send "#{n}=", v
25
25
  else
26
- raise "mass assignment for :#{n} attribute not allowed!"
26
+ # Do nothing, just silently skip it.
27
+ # raise "mass assignment for :#{n} attribute not allowed!"
27
28
  end
28
29
  end
29
30
  else
@@ -1,10 +1,12 @@
1
+ require 'mongo/model/support/rson'
2
+
1
3
  module Mongo::Model::Conversion
2
4
  def model_to_json *args, &block
3
- to_hash(*args, &block).to_json
5
+ to_rson(*args, &block).to_json
4
6
  end
5
7
 
6
8
  def model_to_xml *args, &block
7
- to_hash(*args, &block).to_xml
9
+ to_rson(*args, &block).to_xml
8
10
  end
9
11
 
10
12
  alias_method :to_json, :model_to_json
@@ -19,13 +21,15 @@ module Mongo::Model::Conversion
19
21
  alias_method :as_xml, :model_to_xml
20
22
  end
21
23
 
22
- def to_hash options = {}
24
+ def to_rson options = {}
25
+ options = {profile: options} if options.is_a? Symbol
26
+
23
27
  if profile = options[:profile]
24
28
  raise "no other optins are allowed when using :profile option!" if options.size > 1
25
29
  profile_options = self.class.profiles[profile] || raise("profile :#{profile} not defined for #{self.class}!")
26
- to_hash profile_options.merge(_profile: profile)
30
+ to_rson profile_options.merge(_profile: profile)
27
31
  else
28
- options.validate_options! :only, :except, :methods, :errors, :_profile
32
+ options.validate_options! :only, :except, :methods, :errors, :id, :_profile
29
33
  child_options = options[:_profile] ? {profile: options[:_profile]} : {}
30
34
 
31
35
  instance_variables = self.persistent_instance_variable_names
@@ -39,15 +43,15 @@ module Mongo::Model::Conversion
39
43
  result = {}
40
44
  instance_variables.each do |iv_name|
41
45
  value = instance_variable_get iv_name
42
- value = convert_model value, :to_hash, child_options
43
- result[iv_name[1.. -1].to_sym] = value
46
+ # value = convert_object value, :to_rson, child_options
47
+ result[iv_name[1.. -1].to_sym] = value.to_rson child_options
44
48
  end
45
49
 
46
50
  methods = options[:methods] ? Array(options[:methods]) : []
47
51
  methods.each do |method|
48
52
  value = send method
49
- value = convert_model value, :to_hash, child_options
50
- result[method.to_sym] = value
53
+ # value = convert_object value, :to_rson, child_options
54
+ result[method.to_sym] = value.to_rson child_options
51
55
  end
52
56
 
53
57
  with_errors = options.include?(:errors) ? options[:errors] : true
@@ -57,24 +61,12 @@ module Mongo::Model::Conversion
57
61
  result[:errors] = errors
58
62
  end
59
63
 
64
+ result[:id] = _id if _id and (options[:id] != false)
65
+
60
66
  result
61
67
  end
62
68
  end
63
69
 
64
- protected
65
- def convert_model obj, method, options
66
- if obj.respond_to? :collect_with_value
67
- # Array or Hash.
68
- obj.collect_with_value{|v| convert_model v, method, options}
69
- elsif obj.respond_to? method
70
- # Model.
71
- obj.send method, options
72
- else
73
- # Simple object.
74
- obj
75
- end
76
- end
77
-
78
70
  module ClassMethods
79
71
  inheritable_accessor :profiles, {}
80
72
  def profile name, options = {}
@@ -22,7 +22,19 @@ module Mongo::Model::Db
22
22
  def default_collection_name
23
23
  first_ancestor_class = ancestors.find{|a| a.is_a? Class} ||
24
24
  raise("can't evaluate default collection name for #{self}!")
25
- first_ancestor_class.alias.pluralize.underscore.to_sym
25
+ als = first_ancestor_class.alias
26
+
27
+ unless als.respond_to? :pluralize
28
+ warn <<-TEXT
29
+ WARN: It seems that there's no `String.pluralize` method, Mongo::Model needs it to automatically infer
30
+ collection name from the model class name.
31
+ Please specify collection name explicitly (like `collection :users`) or provide the `pluralize`
32
+ method.
33
+ TEXT
34
+ raise "collection name for #{first_ancestor_class} not defined (add it, like `collection :users`)!"
35
+ end
36
+
37
+ als.pluralize.underscore.to_sym
26
38
  end
27
39
  end
28
40
  end
@@ -0,0 +1,38 @@
1
+ module Mongo::Model::IdentityMap
2
+ inherited do
3
+ Mongo::Model::IdentityMap.models.add self
4
+ end
5
+
6
+ def original
7
+ unless _cache[:original_cached]
8
+ _cache[:original_cached] = true
9
+ _cache[:original] = _id && self.class.get_from_identity_map(_id)
10
+ end
11
+ _cache[:original]
12
+ end
13
+
14
+ module ClassMethods
15
+ def identity_map
16
+ @identity_map ||= {}
17
+ end
18
+
19
+ def get_from_identity_map id
20
+ doc = identity_map[id]
21
+ from_mongo doc if doc
22
+ end
23
+
24
+ def from_mongo doc
25
+ model = super doc
26
+ model.class.identity_map[model._id] = doc if model._id
27
+ model
28
+ end
29
+ end
30
+
31
+ class << self
32
+ def models
33
+ @models ||= Set.new
34
+ end
35
+
36
+ def clear; models.collect(&:identity_map).every.clear end
37
+ end
38
+ end
@@ -0,0 +1,10 @@
1
+ require 'mongo/migration/tasks'
2
+
3
+ namespace :db do
4
+ desc "Internal task to prepare migration environment"
5
+ task migration_evnironment: :environment do
6
+ require 'mongo/migration'
7
+
8
+ Dir["#{rad.runtime_path}/db/**/*.rb"].each{|f| require f.sub(/\.rb$/, '')}
9
+ end
10
+ end
@@ -0,0 +1,41 @@
1
+ # Registering it as component.
2
+
3
+ class Mongo::Model::Component
4
+ attr_accessor :db
5
+ attr_required :db
6
+
7
+ attr_accessor :fs
8
+ attr_required :fs
9
+ end
10
+
11
+ rad.register :models do
12
+ Mongo::Model::Component.new
13
+ end
14
+
15
+ # Using DB connection setting defined in component's config file.
16
+ Mongo.metaclass_eval do
17
+ def db name
18
+ config = rad.models.db[name.to_s] || raise("no database config for #{name} alias!")
19
+ host, port, options = config['host'], config['port'], (config['options'] || {})
20
+ connection = self.connection host, port, options
21
+ db_name = config['name'] || raise("no database name for #{name} alias!")
22
+ connection.db db_name
23
+ end
24
+ cache_method_with_params :db
25
+
26
+ def connection host, port, options
27
+ options[:logger] = rad.logger unless options.include? :logger
28
+ Mongo::Connection.new host, port, options
29
+ end
30
+ cache_method_with_params :connection
31
+ end
32
+
33
+ # Localization
34
+
35
+ Mongo::Model::Misc.class_eval do
36
+ def t *args; rad.locale.t *args end
37
+ end
38
+
39
+ Mongo::Model::Misc::ClassMethods.class_eval do
40
+ def t *args; rad.locale.t *args end
41
+ end
@@ -20,6 +20,8 @@ module Mongo::Model::Rails
20
20
  persisted? ? [_id] : nil
21
21
  end
22
22
 
23
+ def new_record?; new? end
24
+
23
25
  module ClassMethods
24
26
  def model_name
25
27
  @_model_name ||= begin
@@ -1,17 +1,14 @@
1
- require 'mongo/object'
2
1
  require 'ruby_ext'
3
2
 
4
3
  module Mongo::Model; end
5
4
 
6
5
  %w(
7
- support
8
-
9
6
  db
10
7
  conversion
11
8
  assignment
12
9
  callbacks
13
- validation
14
10
  crud
11
+ validation
15
12
  query
16
13
  query_mixin
17
14
  scope
@@ -20,17 +17,18 @@ module Mongo::Model; end
20
17
  model
21
18
  ).each{|f| require "mongo/model/#{f}"}
22
19
 
20
+ # Assembling model.
23
21
  module Mongo
24
22
  module Model
25
- autoload :FileModel, 'mongo/model/integration/file_model'
23
+ autoload :IdentityMap, 'mongo/model/identity_map'
26
24
 
27
25
  inherit \
28
26
  Db,
29
27
  Conversion,
30
28
  Assignment,
31
29
  Callbacks,
32
- Validation,
33
30
  Crud,
31
+ Validation,
34
32
  QueryMixin,
35
33
  Scope,
36
34
  AttributeConvertors,
@@ -45,15 +43,19 @@ Mongo.defaults.merge! \
45
43
  safe: true,
46
44
  generate_id: true
47
45
 
48
- # Integration with Rails.
46
+ # Integrations.
47
+
49
48
  unless $dont_use_rails
50
49
  require 'mongo/model/integration/rails' if defined? Rails
51
50
  end
52
51
 
53
- # Integration with Validatable2
54
52
  unless $dont_use_validatable
55
53
  require 'validatable'
56
54
  require 'mongo/model/integration/validatable'
57
55
  require 'mongo/model/integration/validatable/uniqueness_validator'
58
56
  Mongo::Model.inherit Validatable::Model
57
+ end
58
+
59
+ unless $dont_use_file_model
60
+ Mongo::Model.autoload :FileModel, 'mongo/model/integration/file_model'
59
61
  end
@@ -8,7 +8,6 @@ module Mongo::Model::Misc
8
8
  self.updated_at = now
9
9
  end
10
10
 
11
-
12
11
  def _cache
13
12
  @_cache ||= {}
14
13
  end
@@ -32,7 +31,11 @@ module Mongo::Model::Misc
32
31
  end
33
32
 
34
33
  def original
35
- @_original ||= _id? ? self.class.by_id(self._id) : nil
34
+ unless _cache[:original_cached]
35
+ _cache[:original_cached] = true
36
+ _cache[:original] = _id && self.class.by_id(_id)
37
+ end
38
+ _cache[:original]
36
39
  end
37
40
 
38
41
  module ClassMethods
@@ -41,5 +44,9 @@ module Mongo::Model::Misc
41
44
  before_create :update_created_at
42
45
  before_save :update_updated_at
43
46
  end
47
+
48
+ def create_index *args
49
+ collection.create_index *args
50
+ end
44
51
  end
45
52
  end
@@ -70,5 +70,17 @@ module Mongo::Model
70
70
  list.collect!{|n| :"@#{n}"}
71
71
  if list.empty? then _embedded else _embedded.push(*list) end
72
72
  end
73
+
74
+ def from_mongo doc
75
+ model = ::Mongo::Object.from_mongo doc
76
+ model.run_after_callbacks :build, :build
77
+ model
78
+ end
79
+ end
80
+
81
+ class << self
82
+ def originals
83
+ @originals ||= {}
84
+ end
73
85
  end
74
86
  end
@@ -87,9 +87,21 @@ module Mongo::Model::Scope
87
87
  list = list.collect{|item| item.is_a?(Array) ? item : [item, 1]}
88
88
  query({}, sort: list)
89
89
  end
90
+ alias_method :sort_by, :sort
90
91
  def snapshot; query({}, snapshot: true) end
91
92
 
92
- def paginate page, per_page
93
+ PER_PAGE, MAX_PER_PAGE = 25, 100
94
+ def paginate *args
95
+ args.size.must.be_in 1..2
96
+ if args.size == 2
97
+ page, per_page = *args
98
+ else
99
+ options = args.first
100
+ page, per_page = options[:page], options[:per_page]
101
+ end
102
+ page ||= 1
103
+ per_page ||= PER_PAGE
104
+ per_page = MAX_PER_PAGE if per_page > MAX_PER_PAGE
93
105
  skip((page - 1) * per_page).limit(per_page)
94
106
  end
95
107
 
@@ -5,6 +5,12 @@ rspec do
5
5
  class << self
6
6
  def with_mongo_model
7
7
  with_mongo
8
+ before{Mongo::Model::IdentityMap.clear}
9
+ end
10
+
11
+ def with_models *args
12
+ ::Models
13
+ with_mongo_model *args
8
14
  end
9
15
  end
10
16
  end
@@ -0,0 +1,68 @@
1
+ class Object
2
+ def rson?
3
+ false
4
+ end
5
+ end
6
+
7
+ [
8
+ Time,
9
+ FalseClass,
10
+ TrueClass,
11
+ Numeric,
12
+ Symbol,
13
+ String,
14
+ NilClass,
15
+ ].each do |klass|
16
+ klass.class_eval do
17
+ def to_rson options = {}
18
+ self
19
+ end
20
+
21
+ def rson?
22
+ true
23
+ end
24
+ end
25
+ end
26
+
27
+ # [
28
+ # String
29
+ # ].each do |klass|
30
+ # klass.class_eval do
31
+ # def to_rson options = {}
32
+ # self.to_sym
33
+ # end
34
+ #
35
+ # def rson?
36
+ # false
37
+ # end
38
+ # end
39
+ # end
40
+
41
+ Array.class_eval do
42
+ def to_rson options = {}
43
+ collect{|v| v.to_rson(options)}
44
+ end
45
+
46
+ def rson?
47
+ all?{|v| v.rson?}
48
+ end
49
+ end
50
+
51
+ [Hash, OpenObject].each do |klass|
52
+ klass.class_eval do
53
+ def to_rson options = {}
54
+ r = self.class.new
55
+ each do |k, v|
56
+ r[k.to_sym] = v.to_rson(options)
57
+ end
58
+ r
59
+ end
60
+
61
+ def rson?
62
+ each do |k, v|
63
+ return false unless k.rson? and v.rson?
64
+ end
65
+ true
66
+ end
67
+ end
68
+ end
@@ -5,7 +5,38 @@ module Mongo::Model::Validation
5
5
  end
6
6
  def invalid?(options = {}); !valid?(options) end
7
7
 
8
+ # Catching erros during CRUD and adding it to errors, like unique index.
9
+
10
+ def create_object *args
11
+ with_exceptions_as_errors do
12
+ super
13
+ end
14
+ end
15
+
16
+ def update_object *args
17
+ with_exceptions_as_errors do
18
+ super
19
+ end
20
+ end
21
+
22
+ def delete_object *args
23
+ with_exceptions_as_errors do
24
+ super
25
+ end
26
+ end
27
+
8
28
  protected
29
+ def with_exceptions_as_errors &block
30
+ block.call
31
+ rescue Mongo::OperationFailure => e
32
+ if [11000, 11001].include? e.error_code
33
+ errors.add :base, "not unique value!"
34
+ false
35
+ else
36
+ raise e
37
+ end
38
+ end
39
+
9
40
  def run_validations options = {}
10
41
  with_model_callbacks [:validate], options, [self] do
11
42
  # Validating main model.
data/lib/mongo/model.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  require 'mongodb_model/gems'
2
2
 
3
+ require 'mongo/object'
4
+
3
5
  module Mongo
4
6
  autoload :Model, 'mongo/model/load'
5
7
  end
@@ -1,8 +1,5 @@
1
- # gem 'i18n', '~> 0.5'
2
-
3
1
  if respond_to? :fake_gem
4
2
  fake_gem 'mongodb'
5
- # fake_gem 'file_model'
6
3
  fake_gem 'validatable2'
7
4
  fake_gem 'ruby_ext'
8
5
  end
@@ -38,9 +38,12 @@ describe 'Attribute assignment' do
38
38
 
39
39
  u = User.new
40
40
  u.set name: 'Alex', has_mail: '1', age: '31', position: [11, 34]
41
- -> {u.set name: 'Alex', banned: false}.should raise_error(/not allowed/)
42
41
  [u.name, u.has_mail, u.age, u.position, u.banned].should == ['Alex', true, 31, [11, 34], nil]
43
42
 
43
+ # Should skip not allowed attributes.
44
+ u.set banned: false
45
+ u.banned.should be_nil
46
+
44
47
  # should allow to forcefully cast and update any attribute
45
48
  u.set! banned: '0'
46
49
  u.banned.should == false
@@ -67,6 +67,7 @@ describe "Attribute convertors" do
67
67
 
68
68
  # Protection.
69
69
  o.protected_tags = []
70
- -> {o.set protected_tags_as_string: 'Java, Ruby'}.should raise_error(/not allowed/)
70
+ o.set protected_tags_as_string: 'Java, Ruby'
71
+ o.protected_tags = []
71
72
  end
72
73
  end
@@ -155,7 +155,7 @@ describe 'Callbacks' do
155
155
  instance.should_receive(:after_build)
156
156
  end
157
157
  EmbeddedObject.after_instantiate do |instance|
158
- instance.should_receive(:after_build)
158
+ instance.should_not_receive(:after_build)
159
159
  end
160
160
  db.objects.first
161
161
  end
@@ -40,7 +40,7 @@ describe 'Conversion' do
40
40
 
41
41
  it "should work without arguments" do
42
42
  post = build_post_with_comment
43
- post.to_hash.should == {
43
+ post.to_rson.should == {
44
44
  text: 'StarCraft releasing soon!',
45
45
  token: 'secret',
46
46
  comments: [
@@ -51,14 +51,14 @@ describe 'Conversion' do
51
51
 
52
52
  it "should accept :only, :except and :methods options" do
53
53
  post = build_post_with_comment
54
- post.to_hash(only: :text).should == {text: 'StarCraft releasing soon!'}
55
- post.to_hash(except: :token).should == {
54
+ post.to_rson(only: :text).should == {text: 'StarCraft releasing soon!'}
55
+ post.to_rson(except: :token).should == {
56
56
  text: 'StarCraft releasing soon!',
57
57
  comments: [
58
58
  {text: 'Cool!'}
59
59
  ]
60
60
  }
61
- post.to_hash(only: [], methods: :teaser).should == {teaser: 'StarCraft r'}
61
+ post.to_rson(only: [], methods: :teaser).should == {teaser: 'StarCraft r'}
62
62
  end
63
63
 
64
64
  it "should use conversion profiles" do
@@ -68,13 +68,21 @@ describe 'Conversion' do
68
68
 
69
69
  post = build_post_with_comment
70
70
 
71
- -> {post.to_hash(profile: :public)}.should raise_error(/profile :public not defined for Comment/)
71
+ -> {post.to_rson(profile: :public)}.should raise_error(/profile :public not defined for Comment/)
72
72
 
73
73
  Comment.class_eval do
74
74
  profile :public
75
75
  end
76
76
 
77
- post.to_hash(profile: :public).should == {
77
+ post.to_rson(profile: :public).should == {
78
+ text: 'StarCraft releasing soon!',
79
+ teaser: 'StarCraft r',
80
+ comments: [
81
+ {text: 'Cool!'}
82
+ ]
83
+ }
84
+
85
+ post.to_rson(:public).should == {
78
86
  text: 'StarCraft releasing soon!',
79
87
  teaser: 'StarCraft r',
80
88
  comments: [
@@ -91,29 +99,29 @@ describe 'Conversion' do
91
99
  post = Post.new text: 'StarCraft releasing soon!'
92
100
  post.valid?.should be_false
93
101
 
94
- post.to_hash.should == {
102
+ post.to_rson.should == {
95
103
  text: 'StarCraft releasing soon!',
96
104
  errors: {token: ["can't be empty"]}
97
105
  }
98
106
 
99
- post.to_hash(errors: false).should == {
107
+ post.to_rson(errors: false).should == {
100
108
  text: 'StarCraft releasing soon!'
101
109
  }
102
110
  end
103
111
 
104
112
  it "should convert to to_json" do
105
113
  post = build_post_with_comment
106
- rson = mock
107
- rson.should_receive(:to_json).and_return(:ok)
108
- post.should_receive(:to_hash).with(only: :text).and_return(rson)
114
+ hash = mock
115
+ hash.should_receive(:to_json).and_return(:ok)
116
+ post.should_receive(:to_rson).with(only: :text).and_return(hash)
109
117
  post.to_json(only: :text).should == :ok
110
118
  end
111
119
 
112
120
  it "should convert to to_xml" do
113
121
  post = build_post_with_comment
114
- rson = mock
115
- rson.should_receive(:to_xml).and_return(:ok)
116
- post.should_receive(:to_hash).with(only: :text).and_return(rson)
122
+ hash = mock
123
+ hash.should_receive(:to_xml).and_return(:ok)
124
+ post.should_receive(:to_rson).with(only: :text).and_return(hash)
117
125
  post.to_xml(only: :text).should == :ok
118
126
  end
119
127
  end
data/spec/crud_spec.rb CHANGED
@@ -20,6 +20,25 @@ describe "Model CRUD" do
20
20
  end
21
21
  after{remove_constants :Unit}
22
22
 
23
+ it 'save should return true or false' do
24
+ # Successfull create and update.
25
+ unit = Unit.new
26
+ unit.save.class.should == TrueClass
27
+ unit.name = 'Another'
28
+ unit.save.class.should == TrueClass
29
+
30
+ # Invalid create.
31
+ unit = Unit.new
32
+ unit.stub!(:valid?).and_return false
33
+ unit.save.class.should == FalseClass
34
+
35
+ # Invalid update.
36
+ unit = Unit.new
37
+ unit.save.should be_true
38
+ unit.stub!(:valid?).and_return false
39
+ unit.save.class.should == FalseClass
40
+ end
41
+
23
42
  it 'should perform CRUD' do
24
43
  # Read.
25
44
  Unit.count.should == 0
@@ -77,10 +96,7 @@ describe "Model CRUD" do
77
96
 
78
97
  it 'should create model' do
79
98
  u = Unit.create(name: 'Zeratul')
80
- u.new_record?.should be_false
81
-
82
- u = Unit.create!(name: 'Zeratul')
83
- u.new_record?.should be_false
99
+ u.new?.should be_false
84
100
  end
85
101
 
86
102
  it 'should delete all models' do
data/spec/misc_spec.rb CHANGED
@@ -11,10 +11,10 @@ describe 'Miscellaneous' do
11
11
  attr_accessor :name
12
12
  end
13
13
  end
14
- after{remove_constants :Unit3, :User}
14
+ after{remove_constants :Unit, :User}
15
15
 
16
16
  it "should create timestamps" do
17
- class Unit3
17
+ class Unit
18
18
  inherit Mongo::Model
19
19
  collection :units
20
20
 
@@ -23,10 +23,10 @@ describe 'Miscellaneous' do
23
23
  timestamps!
24
24
  end
25
25
 
26
- unit = Unit3.build name: 'Zeratul'
26
+ unit = Unit.build name: 'Zeratul'
27
27
  unit.save!
28
28
 
29
- unit = Unit3.first
29
+ unit = Unit.first
30
30
  unit.created_at.should_not be_nil
31
31
  unit.updated_at.should_not be_nil
32
32
  created_at,updated_at = unit.created_at, unit.updated_at
@@ -37,10 +37,10 @@ describe 'Miscellaneous' do
37
37
  end
38
38
 
39
39
  it 'should have cache' do
40
- class Unit3
40
+ class Unit
41
41
  inherit Mongo::Model
42
42
  end
43
- u = Unit3.new
43
+ u = Unit.new
44
44
  u._cache.should == {}
45
45
  end
46
46
 
@@ -64,4 +64,45 @@ describe 'Miscellaneous' do
64
64
  u.reload
65
65
  u.name.should == 'Zeratul'
66
66
  end
67
+
68
+ describe 'original' do
69
+ before do
70
+ class Unit
71
+ inherit Mongo::Model
72
+ collection :units
73
+
74
+ attr_accessor :name
75
+ end
76
+
77
+ @unit = Unit.new.tap{|u| u.name = "Zeratul"}
78
+ end
79
+ after{remove_constants :Unit}
80
+
81
+ it "should query original from database" do
82
+ @unit.original.should be_nil
83
+ @unit.save!
84
+
85
+ unit = Unit.first
86
+ unit.name = "Tassadar"
87
+
88
+ Unit.should_receive(:first).with(_id: unit._id).and_return{db.units.first(_id: unit._id)}
89
+ unit.original.name.should == "Zeratul"
90
+ end
91
+
92
+ it "should use identity map if provided" do
93
+ Unit.inherit Mongo::Model::IdentityMap
94
+
95
+ @unit.original.should be_nil
96
+ @unit.save!
97
+
98
+ Unit.identity_map.size.should == 0
99
+ unit = Unit.first
100
+ Unit.identity_map.size.should == 1
101
+
102
+ unit.name = "Tassadar"
103
+
104
+ Unit.should_not_receive :first
105
+ unit.original.name.should == "Zeratul"
106
+ end
107
+ end
67
108
  end
data/spec/query_spec.rb CHANGED
@@ -74,7 +74,9 @@ describe "Query" do
74
74
  end
75
75
  end
76
76
 
77
- -> {SpecialUnit.query(name: 'Zeratul').build age: 500, status: 'active'}.should raise_error(/not allowed/)
77
+ u = SpecialUnit.query(name: 'Zeratul').build status: 'active'
78
+ u.status.should be_nil
79
+
78
80
  u = SpecialUnit.query(name: 'Zeratul', status: 'active').build age: 500
79
81
  u.status.should == 'active'
80
82
  end
@@ -142,4 +142,26 @@ describe "Validation" do
142
142
  unit.should be_valid
143
143
  end
144
144
  end
145
+
146
+ context "database exceptions" do
147
+ before do
148
+ class Unit
149
+ inherit Mongo::Model
150
+ collection :units
151
+
152
+ attr_accessor :name
153
+ end
154
+ end
155
+ after{remove_constants :Unit}
156
+
157
+ it "should convert unique index exception to errors" do
158
+ db.units.create_index [["name", 1]], unique: true
159
+
160
+ Unit.create name: 'Zeratul'
161
+
162
+ unit = Unit.new name: 'Zeratul'
163
+ unit.save.should be_false
164
+ unit.errors[:base].should == ["not unique value!"]
165
+ end
166
+ end
145
167
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongodb_model
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.2
4
+ version: 2.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-11-19 00:00:00.000000000Z
12
+ date: 2011-12-19 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: mongodb
16
- requirement: &2848930 !ruby/object:Gem::Requirement
16
+ requirement: &70169713604240 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *2848930
24
+ version_requirements: *70169713604240
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: validatable2
27
- requirement: &2848690 !ruby/object:Gem::Requirement
27
+ requirement: &70169713603760 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *2848690
35
+ version_requirements: *70169713603760
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: ruby_ext
38
- requirement: &2848450 !ruby/object:Gem::Requirement
38
+ requirement: &70169713603260 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,7 +43,7 @@ dependencies:
43
43
  version: '0'
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *2848450
46
+ version_requirements: *70169713603260
47
47
  description:
48
48
  email:
49
49
  executables: []
@@ -58,7 +58,10 @@ files:
58
58
  - lib/mongo/model/conversion.rb
59
59
  - lib/mongo/model/crud.rb
60
60
  - lib/mongo/model/db.rb
61
+ - lib/mongo/model/identity_map.rb
61
62
  - lib/mongo/model/integration/file_model.rb
63
+ - lib/mongo/model/integration/rad/tasks.rb
64
+ - lib/mongo/model/integration/rad.rb
62
65
  - lib/mongo/model/integration/rails.rb
63
66
  - lib/mongo/model/integration/validatable/uniqueness_validator.rb
64
67
  - lib/mongo/model/integration/validatable.rb
@@ -70,7 +73,7 @@ files:
70
73
  - lib/mongo/model/scope.rb
71
74
  - lib/mongo/model/spec.rb
72
75
  - lib/mongo/model/support/conversions.rb
73
- - lib/mongo/model/support.rb
76
+ - lib/mongo/model/support/rson.rb
74
77
  - lib/mongo/model/validation.rb
75
78
  - lib/mongo/model.rb
76
79
  - lib/mongodb_model/gems.rb
@@ -109,7 +112,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
109
112
  version: '0'
110
113
  requirements: []
111
114
  rubyforge_project:
112
- rubygems_version: 1.8.6
115
+ rubygems_version: 1.8.10
113
116
  signing_key:
114
117
  specification_version: 3
115
118
  summary: Object Model for MongoDB
@@ -1,10 +0,0 @@
1
- Array.class_eval do
2
- alias_method :each_value, :each
3
- alias_method :collect_with_value, :collect
4
- end
5
-
6
- Hash.class_eval do
7
- def collect_with_value &block
8
- {}.tap{|h| self.each{|k, v| h[k] = block.call v}}
9
- end
10
- end