mongodb 0.0.1 → 0.0.2

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.
Files changed (74) hide show
  1. data/Rakefile +3 -5
  2. data/lib/mongodb/driver.rb +33 -0
  3. data/lib/mongodb/driver/collection.rb +156 -0
  4. data/lib/mongodb/driver/database.rb +6 -0
  5. data/lib/mongodb/driver/dynamic_finders.rb +41 -0
  6. data/lib/{mongo_db → mongodb}/driver/spec.rb +12 -12
  7. data/lib/mongodb/gems.rb +6 -0
  8. data/lib/mongodb/integration/locales.rb +4 -0
  9. data/lib/mongodb/integration/locales/activemodel/ru.yml +27 -0
  10. data/lib/mongodb/migration.rb +8 -0
  11. data/lib/mongodb/migration/definition.rb +19 -0
  12. data/lib/mongodb/migration/migration.rb +68 -0
  13. data/lib/mongodb/migration/tasks.rb +19 -0
  14. data/lib/mongodb/model.rb +26 -0
  15. data/lib/mongodb/model/assignment.rb +65 -0
  16. data/lib/mongodb/model/attribute_convertors.rb +54 -0
  17. data/lib/mongodb/model/callbacks.rb +36 -0
  18. data/lib/mongodb/model/crud.rb +57 -0
  19. data/lib/mongodb/model/db.rb +53 -0
  20. data/lib/mongodb/model/misc.rb +33 -0
  21. data/lib/mongodb/model/model.rb +11 -0
  22. data/lib/mongodb/model/query.rb +36 -0
  23. data/lib/mongodb/model/scope.rb +99 -0
  24. data/lib/mongodb/model/spec.rb +12 -0
  25. data/lib/mongodb/model/support/types.rb +110 -0
  26. data/lib/mongodb/model/validation.rb +5 -0
  27. data/lib/mongodb/object.rb +18 -0
  28. data/lib/mongodb/object/object_helper.rb +62 -0
  29. data/lib/mongodb/object/object_serializer.rb +273 -0
  30. data/readme.md +261 -6
  31. data/spec/driver/collection_spec.rb +83 -0
  32. data/spec/{mongo_model/hash → driver}/crud_spec.rb +30 -29
  33. data/spec/driver/database_spec.rb +9 -0
  34. data/spec/driver/dynamic_finders_spec.rb +50 -0
  35. data/spec/driver/fixes_spec.rb +12 -0
  36. data/spec/driver/hash_helper_spec.rb +24 -0
  37. data/spec/driver/spec_helper.rb +28 -0
  38. data/spec/integration/am_conversion_spec.rb +1 -0
  39. data/spec/integration/am_validation_spec.rb +34 -0
  40. data/spec/integration/validatable2_spec.rb +40 -0
  41. data/spec/migration/migration_spec.rb +60 -0
  42. data/spec/model/assignment_spec.rb +80 -0
  43. data/spec/model/attribute_convertors_spec.rb +73 -0
  44. data/spec/model/callbacks_spec.rb +47 -0
  45. data/spec/model/crud_spec.rb +151 -0
  46. data/spec/model/db_spec.rb +63 -0
  47. data/spec/model/misc_spec.rb +58 -0
  48. data/spec/model/query_spec.rb +47 -0
  49. data/spec/model/scope_spec.rb +149 -0
  50. data/spec/model/spec_helper.rb +4 -0
  51. data/spec/model/validation_spec.rb +37 -0
  52. data/spec/object/callbacks_spec.rb +97 -0
  53. data/spec/object/crud_shared.rb +53 -0
  54. data/spec/object/crud_spec.rb +55 -0
  55. data/spec/object/spec_helper.rb +14 -0
  56. data/spec/{mongo_model/object → object}/validation_spec.rb +38 -36
  57. metadata +92 -25
  58. data/lib/mongo_db.rb +0 -3
  59. data/lib/mongo_db/driver.rb +0 -5
  60. data/lib/mongo_db/driver/connection.rb +0 -0
  61. data/lib/mongo_db/driver/database.rb +0 -5
  62. data/lib/mongo_db/gems.rb +0 -2
  63. data/lib/mongo_db/model.rb +0 -0
  64. data/spec/mongo_ext/migration_spec.rb +0 -0
  65. data/spec/mongo_ext/misc_spec.rb +0 -10
  66. data/spec/mongo_ext/spec_helper.rb +0 -4
  67. data/spec/mongo_model/model/crud_spec.rb +0 -123
  68. data/spec/mongo_model/model/query_spec.rb +0 -0
  69. data/spec/mongo_model/object/callbacks_spec.rb +0 -100
  70. data/spec/mongo_model/object/crud_shared.rb +0 -53
  71. data/spec/mongo_model/object/crud_spec.rb +0 -45
  72. data/spec/mongo_model/spec_helper.rb +0 -1
  73. data/spec/query_spec.rb +0 -0
  74. data/spec/test_spec.rb +0 -5
data/Rakefile CHANGED
@@ -2,12 +2,10 @@ require 'rake_ext'
2
2
 
3
3
  project(
4
4
  name: "mongodb",
5
- # official_name: "mongo_db",
6
- version: '0.0.1',
5
+ # version: '0.1.0',
7
6
  gem: true,
8
- summary: "MongDB ODM. In development, don't use it, come back at 11/8/25",
9
- # Very small, schema-less, config-less Ruby ODM for MongoDB",
7
+ summary: "Object Model & Ruby driver enhancements for MongoDB",
10
8
 
11
9
  author: "Alexey Petrushin",
12
- homepage: "http://github.com/alexeypetrushin/mongo_db"
10
+ homepage: "http://github.com/alexeypetrushin/mongodb"
13
11
  )
@@ -0,0 +1,33 @@
1
+ require 'mongodb/gems'
2
+
3
+ require 'mongo'
4
+
5
+ class Mongo::Error < StandardError; end
6
+ class Mongo::NotFound < Mongo::Error; end
7
+
8
+ %w(
9
+ database
10
+ collection
11
+ dynamic_finders
12
+ ).each{|f| require "mongodb/driver/#{f}"}
13
+
14
+ # defaults
15
+ Mongo.class_eval do
16
+ class << self
17
+ def defaults; @defaults ||= {} end
18
+ attr_writer :defaults
19
+ end
20
+ end
21
+
22
+ # database
23
+ Mongo::DB.send :include, Mongo::DBExt
24
+
25
+ # collection
26
+ Mongo::Collection.class_eval do
27
+ include Mongo::CollectionExt, Mongo::DynamicFinders
28
+
29
+ %w(insert update remove save count).each do |method|
30
+ alias_method "#{method}_without_ext", method
31
+ alias_method method, "#{method}_with_ext"
32
+ end
33
+ end
@@ -0,0 +1,156 @@
1
+ require 'set'
2
+ require 'date'
3
+
4
+ module Mongo::CollectionExt
5
+ #
6
+ # CRUD
7
+ #
8
+ def save_with_ext doc, opts = {}
9
+ save_without_ext doc, reverse_merge_defaults(opts, :safe)
10
+ end
11
+
12
+ def insert_with_ext args, opts = {}
13
+ result = insert_without_ext args, reverse_merge_defaults(opts, :safe)
14
+
15
+ # fix for mongodriver, it will return single result if we supply [doc] as args
16
+ (args.is_a?(Array) and !result.is_a?(Array)) ? [result] : result
17
+ end
18
+
19
+ def update_with_ext selector, doc, opts = {}
20
+ selector = convert_underscore_to_dollar_in_selector selector
21
+ doc = convert_underscore_to_dollar_in_update doc
22
+
23
+ # because :multi works only with $ operators, we need to check if it's applicable
24
+ opts = if doc.keys.any?{|k| k =~ /^\$/}
25
+ reverse_merge_defaults(opts, :safe, :multi)
26
+ else
27
+ reverse_merge_defaults(opts, :safe)
28
+ end
29
+
30
+ update_without_ext selector, doc, opts
31
+ end
32
+
33
+ def remove_with_ext selector = {}, opts = {}
34
+ selector = convert_underscore_to_dollar_in_selector selector
35
+ remove_without_ext selector, reverse_merge_defaults(opts, :safe, :multi)
36
+ end
37
+
38
+ def destroy *args
39
+ remove *args
40
+ end
41
+
42
+ def create *args
43
+ insert *args
44
+ end
45
+
46
+ #
47
+ # Querying
48
+ #
49
+ def first selector = {}, opts = {}
50
+ selector = convert_underscore_to_dollar_in_selector selector if selector.is_a? Hash
51
+
52
+ h = find_one selector, opts
53
+ symbolize_doc h
54
+ end
55
+
56
+ def first! selector = {}, opts = {}
57
+ first(selector, opts) || raise(Mongo::NotFound, "document with selector #{selector} not found!")
58
+ end
59
+
60
+ def all selector = {}, opts = {}, &block
61
+ if block
62
+ each selector, opts, &block
63
+ else
64
+ list = []
65
+ each(selector, opts){|doc| list << doc}
66
+ list
67
+ end
68
+ end
69
+
70
+ def each selector = {}, opts = {}, &block
71
+ selector = convert_underscore_to_dollar_in_selector selector
72
+
73
+ cursor = nil
74
+ begin
75
+ cursor = find selector, reverse_merge_defaults(opts, :batch_size)
76
+ cursor.each do |doc|
77
+ doc = symbolize_doc doc
78
+ block.call doc
79
+ end
80
+ nil
81
+ ensure
82
+ cursor.close if cursor
83
+ end
84
+ nil
85
+ end
86
+
87
+ def count_with_ext selector = {}, opts = {}
88
+ find(selector, opts).count()
89
+ end
90
+
91
+ protected
92
+ QUERY_KEYWORDS = [
93
+ :_lt, :_lte, :_gt, :_gte,
94
+ :_all, :_exists, :_mod, :_ne, :_in, :_nin,
95
+ :_nor, :_or, :_and,
96
+ :_size, :_type
97
+ ].to_set
98
+
99
+ UPDATE_KEYWORDS = [
100
+ :_inc, :_set, :_unset, :_push, :_pushAll, :_addToSet, :_pop, :_pull, :_pullAll, :_rename, :_bit
101
+ ].to_set
102
+
103
+ def reverse_merge_defaults opts, *keys
104
+ h = opts.clone
105
+ keys.each do |k|
106
+ h[k] = Mongo.defaults[k] if Mongo.defaults.include?(k) and !h.include?(k)
107
+ end
108
+ h
109
+ end
110
+
111
+ # symbolizing hashes
112
+ def symbolize_doc doc
113
+ return doc unless Mongo.defaults[:symbolize]
114
+
115
+ Mongo::CollectionExt.convert_doc doc do |k, v, result|
116
+ k = k.to_sym if k.is_a? String
117
+ result[k] = v
118
+ end
119
+ end
120
+
121
+ # replaces :_lt to :$lt in query
122
+ def convert_underscore_to_dollar_in_selector selector
123
+ return selector unless Mongo.defaults[:convert_underscore_to_dollar]
124
+
125
+ Mongo::CollectionExt.convert_doc selector do |k, v, result|
126
+ k = "$#{k.to_s[1..-1]}".to_sym if QUERY_KEYWORDS.include?(k)
127
+ result[k] = v
128
+ end
129
+ end
130
+
131
+ # replaces :_set to :$set in query
132
+ def convert_underscore_to_dollar_in_update update
133
+ return update unless Mongo.defaults[:convert_underscore_to_dollar]
134
+
135
+ Mongo::CollectionExt.convert_doc update do |k, v, result|
136
+ k = "$#{k.to_s[1..-1]}".to_sym if UPDATE_KEYWORDS.include?(k)
137
+ result[k] = v
138
+ end
139
+ end
140
+
141
+ # walks on hash and creates another (also works with nested & arrays)
142
+ def self.convert_doc doc, &block
143
+ if doc.is_a? Hash
144
+ result = {}
145
+ doc.each do |k, v|
146
+ v = convert_doc v, &block
147
+ block.call k, v, result
148
+ end
149
+ result
150
+ elsif doc.is_a? Array
151
+ doc.collect{|v| convert_doc v, &block}
152
+ else
153
+ doc
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,6 @@
1
+ module Mongo::DBExt
2
+ protected
3
+ def method_missing collection_name
4
+ self.collection collection_name
5
+ end
6
+ end
@@ -0,0 +1,41 @@
1
+ module Mongo::DynamicFinders
2
+ protected
3
+ #
4
+ # first_by_field, all_by_field, each_by_field, first_by_field
5
+ #
6
+ def method_missing clause, *args, &block
7
+ if clause =~ /^([a-z]_by_[a-z_])|(by_[a-z_])/
8
+ clause = clause.to_s
9
+
10
+ bang = clause =~ /!$/
11
+ clause = clause[0..-2] if bang
12
+
13
+ finder, field = if clause =~ /^by_/
14
+ ['first', clause.sub(/by_/, '')]
15
+ else
16
+ clause.split(/_by_/, 2)
17
+ end
18
+
19
+ finder = 'first' if finder == 'find'
20
+ field = '_id' if field == 'id'
21
+
22
+ if bang
23
+ raise "You can't use bang version with :#{finder}!" unless finder == 'first'
24
+ finder = "#{finder}!"
25
+ end
26
+
27
+ raise "invalid arguments for finder (#{args})!" unless args.size == 1
28
+ field_value = args.first
29
+
30
+ finder, field = finder.to_sym, field.to_sym
31
+
32
+ if respond_to? finder
33
+ send finder, {field => field_value}, &block
34
+ else
35
+ super
36
+ end
37
+ else
38
+ super
39
+ end
40
+ end
41
+ end
@@ -1,31 +1,31 @@
1
- MONGO_TEST_DATABASE = 'default_test'
1
+ MONGO_TEST_DATABASE_NAME = 'default_test'
2
2
 
3
- rspec do
3
+ rspec do
4
4
  def mongo
5
5
  $mongo || raise('Mongo not defined (use :with_mongo helper)!')
6
6
  end
7
-
8
- def clear_mongo name = MONGO_TEST_DATABASE
7
+
8
+ def clear_mongo name = MONGO_TEST_DATABASE_NAME
9
9
  mongo.db.collection_names.each do |name|
10
10
  next if name =~ /^system\./
11
11
  mongo.db.collection(name).drop
12
12
  end
13
13
  end
14
-
14
+
15
15
  class << self
16
16
  def with_mongo
17
- require 'ostruct'
18
-
19
17
  before :all do
18
+ require 'ostruct'
19
+
20
20
  $mongo = OpenStruct.new.tap do |m|
21
21
  m.connection = Mongo::Connection.new
22
- m.db = m.connection.db MONGO_TEST_DATABASE
22
+ m.db = m.connection.db MONGO_TEST_DATABASE_NAME
23
23
  end
24
- end
24
+ end
25
25
  after(:all){$mongo = nil}
26
-
27
- before do
28
- clear_mongo
26
+
27
+ before do
28
+ clear_mongo
29
29
  end
30
30
  end
31
31
  end
@@ -0,0 +1,6 @@
1
+ gem 'mongo', '~> 1.3'
2
+ gem 'i18n', '>= 0.5'
3
+
4
+ if respond_to? :fake_gem
5
+ fake_gem 'ruby_ext'
6
+ end
@@ -0,0 +1,4 @@
1
+ require 'i18n'
2
+
3
+ dir = File.dirname __FILE__
4
+ I18n.load_path += Dir["#{dir}/locales/**/*.{rb,yml}"]
@@ -0,0 +1,27 @@
1
+ ru:
2
+ errors:
3
+ # The default format to use in full error messages.
4
+ format: "%{attribute} %{message}"
5
+
6
+ # The values :model, :attribute and :value are always available for interpolation
7
+ # The value :count is available when applicable. Can be used for pluralization.
8
+ messages:
9
+ inclusion: "недопустимое значение"
10
+ exclusion: "недопустимо"
11
+ invalid: "неверно"
12
+ confirmation: "не совпадает с подтверждением"
13
+ accepted: "долно быть принято"
14
+ empty: "не может быть пустым"
15
+ blank: "не может быть пустым"
16
+ too_long: "слишком длинно (максимально допустимо %{count})"
17
+ too_short: "слищком коротко (минимально допустимо %{count})"
18
+ wrong_length: "неверная длинна (должно быть %{count})"
19
+ not_a_number: "не номер"
20
+ not_an_integer: "долно быть целочисленно"
21
+ greater_than: "должно быть больше чем %{count}"
22
+ greater_than_or_equal_to: "должно быть больше чем или равно %{count}"
23
+ equal_to: "должно быть равно %{count}"
24
+ less_than: "должно быть меньше чем %{count}"
25
+ less_than_or_equal_to: "должно быть меньше чем или равно %{count}"
26
+ odd: "должно быть не четно"
27
+ even: "должно быть четно"
@@ -0,0 +1,8 @@
1
+ require 'mongodb/driver'
2
+
3
+ class Mongo::Migration; end
4
+
5
+ %w(
6
+ definition
7
+ migration
8
+ ).each{|f| require "mongodb/migration/#{f}"}
@@ -0,0 +1,19 @@
1
+ class Mongo::Migration::Definition
2
+ def upgrade &block
3
+ if block
4
+ @upgrade = block
5
+ else
6
+ @upgrade
7
+ end
8
+ end
9
+ alias_method :up, :upgrade
10
+
11
+ def downgrade &block
12
+ if block
13
+ @downgrade = block
14
+ else
15
+ @downgrade
16
+ end
17
+ end
18
+ alias_method :down, :downgrade
19
+ end
@@ -0,0 +1,68 @@
1
+ class Mongo::Migration
2
+ def initialize db
3
+ @db, @definitions = db, {}
4
+ end
5
+
6
+ def add version, &block
7
+ raise "version should be an Integer! (but you provided '#{version}' instad)!" unless version.is_a? Integer
8
+ definition = Definition.new
9
+ block.call definition
10
+ definitions[version] = definition
11
+ end
12
+
13
+ def update version = nil
14
+ version ||= definitions.keys.max
15
+
16
+ if current_version == version
17
+ info "database '#{db.name}' already is of #{version} version, no migration needed"
18
+ return false
19
+ else
20
+ info "updating '#{db.name}' to #{version}"
21
+ end
22
+
23
+ increase_db_version while current_version < version
24
+ decrease_db_version while current_version > version
25
+ true
26
+ end
27
+
28
+ def current_version
29
+ if doc = db.db_metadata.first(name: 'migration')
30
+ doc[:version] || doc['version']
31
+ else
32
+ 0
33
+ end
34
+ end
35
+
36
+ protected
37
+ attr_accessor :db, :definitions
38
+
39
+ def info msg
40
+ db.connection.logger and db.connection.logger.info(msg)
41
+ end
42
+
43
+ def update_version new_version
44
+ db.db_metadata.update({name: 'migration'}, {name: 'migration', version: new_version}, {upsert: true, safe: true})
45
+ end
46
+
47
+ def increase_db_version
48
+ new_version = current_version + 1
49
+ migration = definitions[new_version]
50
+ raise "no upgrade of #{db.name} database to #{new_version} version!" unless migration and migration.up
51
+
52
+ migration.up.call db
53
+ update_version new_version
54
+
55
+ info "database '#{db.name}' upgraded to #{new_version} version."
56
+ end
57
+
58
+ def decrease_db_version
59
+ new_version = current_version - 1
60
+ migration = definitions[new_version + 1]
61
+ raise "no downgrade of #{db.name} database to #{new_version} version!" unless migration and migration.down
62
+
63
+ migration.down.call db
64
+ update_version new_version
65
+
66
+ info "database '#{db.name}' downgraded to #{new_version} version."
67
+ end
68
+ end
@@ -0,0 +1,19 @@
1
+ # namespace :db do
2
+ # desc "Migrate Database"
3
+ # task migrate: :migration_evnironment do
4
+ # require 'mongo_migration'
5
+ #
6
+ # database_name = (ENV['d'] || ENV['database'] || :default).to_sym
7
+ # version = ENV['v'] || ENV['version']
8
+ #
9
+ # if version.blank?
10
+ # size = Mongo.migration.definitions[database_name].size
11
+ # highest_defined_version = size == 0 ? 0 : size - 1
12
+ # version = highest_defined_version
13
+ # else
14
+ # version = version.to_i
15
+ # end
16
+ #
17
+ # Mongo.migration.update version, database_name
18
+ # end
19
+ # end