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
@@ -0,0 +1,26 @@
1
+ require 'mongodb/object'
2
+ require 'ruby_ext'
3
+ require 'i18n'
4
+
5
+ module Mongo::Model; end
6
+
7
+ %w(
8
+ support/types
9
+
10
+ db
11
+ assignment
12
+ callbacks
13
+ validation
14
+ crud
15
+ query
16
+ scope
17
+ attribute_convertors
18
+ misc
19
+ model
20
+ ).each{|f| require "mongodb/model/#{f}"}
21
+
22
+ module Mongo
23
+ module Model
24
+ inherit Db, Assignment, Callbacks, Validation, Crud, Query, Scope, AttributeConvertors, Misc
25
+ end
26
+ end
@@ -0,0 +1,65 @@
1
+ module Mongo::Model::Assignment
2
+ class Dsl < BasicObject
3
+ def initialize
4
+ @attributes = {}
5
+ end
6
+
7
+ def self.const_missing name
8
+ # BasicObject doesn't have access to any constants like String, Symbol, ...
9
+ ::Object.const_get name
10
+ end
11
+
12
+ def to_h; attributes end
13
+
14
+ protected
15
+ attr_reader :attributes
16
+
17
+ def method_missing attribute_name, *args
18
+ attribute_name.must_be.a Symbol
19
+
20
+ args.size.must_be.in 1..2
21
+ if args.first.is_a? Class
22
+ type, mass_assignment = args
23
+ mass_assignment ||= false
24
+ type.must.respond_to :cast
25
+ else
26
+ type, mass_assignment = nil, args.first
27
+ end
28
+
29
+ attributes[attribute_name] = [type, mass_assignment]
30
+ end
31
+ end
32
+
33
+ def set attributes, options = {}
34
+ if rules = self.class._assign
35
+ force = options[:force]
36
+ attributes.each do |n, v|
37
+ n = n.to_sym
38
+ if rule = rules[n]
39
+ type, mass_assignment = rule
40
+ if mass_assignment or force
41
+ v = type.cast(v) if type
42
+ send "#{n}=", v
43
+ end
44
+ end
45
+ end
46
+ else
47
+ attributes.each{|n, v| send "#{n}=", v}
48
+ end
49
+ self
50
+ end
51
+
52
+ def set! attributes, options = {}
53
+ set attributes, options.merge(force: true)
54
+ end
55
+
56
+ module ClassMethods
57
+ inheritable_accessor :_assign, nil
58
+
59
+ def assign &block
60
+ dsl = ::Mongo::Model::Assignment::Dsl.new
61
+ dsl.instance_eval &block
62
+ self._assign = (_assign || {}).merge dsl.to_h
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,54 @@
1
+ require 'json'
2
+ require 'yaml'
3
+
4
+ module Mongo::Model::AttributeConvertors
5
+ CONVERTORS = {
6
+ line: {
7
+ from_string: -> s {(s || "").split(',').collect{|s| s.strip}},
8
+ to_string: -> v {v.join(', ')}
9
+ },
10
+ column: {
11
+ from_string: -> s {(s || "").split("\n").collect{|s| s.strip}},
12
+ to_string: -> v {v.join("\n")}
13
+ },
14
+ yaml: {
15
+ from_string: -> s {YAML.load s rescue {}},
16
+ to_string: -> v {v.to_yaml.strip}
17
+ },
18
+ json: {
19
+ from_string: -> s {JSON.parse s rescue {}},
20
+ to_string: -> v {v.to_json.strip}
21
+ }
22
+ }
23
+
24
+ module ClassMethods
25
+ def available_as_string name, converter_name
26
+ converter = CONVERTORS[converter_name]
27
+ raise "unknown converter name :#{converter_name} for :#{name} field!" unless converter
28
+
29
+ from_string, to_string = converter[:from_string], converter[:to_string]
30
+ name_as_string = "#{name}_as_string".to_sym
31
+ define_method name_as_string do
32
+ _cache[name_as_string] ||= to_string.call(send(name))
33
+ end
34
+
35
+ define_method "#{name_as_string}=" do |value|
36
+ _cache.delete name_as_string
37
+ self.send "#{name}=", from_string.call(value)
38
+ end
39
+ end
40
+
41
+ def available_as_yaml name
42
+ raise "delimiter not specified for :#{name} field!" unless delimiter
43
+ method = "#{name}_as_string"
44
+ define_method method do
45
+ self.send(name).join(delimiter)
46
+ end
47
+ define_method "#{method}=" do |value|
48
+ value = (value || "").split(delimiter.strip).collect{|s| s.strip}
49
+ self.send "#{name}=", value
50
+ end
51
+ end
52
+ end
53
+
54
+ end
@@ -0,0 +1,36 @@
1
+ module Mongo::Model::Callbacks
2
+ inherit RubyExt::Callbacks
3
+
4
+ def _run_callbacks type, method_name
5
+ if type == :before
6
+ run_before_callbacks method_name, method: method_name
7
+ elsif type == :after
8
+ run_after_callbacks method_name, method: method_name
9
+ else
10
+ raise "invalid callback type (#{type})!"
11
+ end
12
+ end
13
+
14
+ module ClassMethods
15
+ [:validate, :update, :save, :destroy].each do |method_name|
16
+ define_method "before_#{method_name}" do |*args, &block|
17
+ opt = args.extract_options!
18
+ if block
19
+ set_callback method_name, :before, opt, &block
20
+ else
21
+ opt[:terminator] = false unless opt.include? :terminator
22
+ args.each{|executor| set_callback method_name, :before, executor, opt}
23
+ end
24
+ end
25
+
26
+ define_method "after_#{method_name}" do |*args, &block|
27
+ opt = args.extract_options!
28
+ if block
29
+ set_callback method_name, :after, opt, &block
30
+ else
31
+ args.each{|executor| set_callback method_name, :after, executor, opt}
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,57 @@
1
+ module Mongo::Model::Crud
2
+ def save opts = {}
3
+ with_collection opts do |collection, opts|
4
+ collection.save self, opts
5
+ end
6
+ end
7
+
8
+ def save! *args
9
+ save(*args) || raise(Mongo::Error, "can't save #{self.inspect}!")
10
+ end
11
+
12
+ def destroy opts = {}
13
+ with_collection opts do |collection, opts|
14
+ collection.destroy self, opts
15
+ end
16
+ end
17
+
18
+ def destroy! *args
19
+ destroy(*args) || raise(Mongo::Error, "can't destroy #{self.inspect}!")
20
+ end
21
+
22
+ module ClassMethods
23
+ def build attributes, opts = {}
24
+ self.new.set attributes, opts
25
+ end
26
+
27
+ def create attributes, opts = {}
28
+ o = build attributes, opts
29
+ o.save
30
+ o
31
+ end
32
+
33
+ def create! attributes, opts = {}
34
+ o = create attributes
35
+ raise(Mongo::Error, "can't create #{attributes.inspect}!") if o.new_record?
36
+ o
37
+ end
38
+
39
+ def destroy_all selector = {}, opts = {}
40
+ success = true
41
+ collection = opts[:collection] || self.collection
42
+ each(selector){|o| success = false unless o.destroy}
43
+ success
44
+ end
45
+
46
+ def destroy_all! selector = {}, opts = {}
47
+ destroy_all(selector, opts) || raise(Mongo::Error, "can't destroy #{selector.inspect}!")
48
+ end
49
+ end
50
+
51
+ protected
52
+ def with_collection opts, &block
53
+ opts = opts.clone
54
+ collection = opts.delete(:collection) || self.class.collection
55
+ block.call collection, opts
56
+ end
57
+ end
@@ -0,0 +1,53 @@
1
+ module Mongo::Model::Db
2
+ module ClassMethods
3
+ inheritable_accessor :_db, nil
4
+ def db= v
5
+ self._db = if v.is_a? ::Proc
6
+ v
7
+ elsif v.is_a? ::Symbol
8
+ -> {::Mongo::Model.connection.db v.to_s}
9
+ else
10
+ -> {v}
11
+ end
12
+ end
13
+
14
+ def db *args, &block
15
+ if block
16
+ self.db = block
17
+ elsif !args.empty?
18
+ args.size.must == 1
19
+ self.db = args.first
20
+ else
21
+ (_db && _db.call) || ::Mongo::Model.db
22
+ end
23
+ end
24
+
25
+ inheritable_accessor :_collection, nil
26
+ def collection= v
27
+ self._collection = if v.is_a? ::Proc
28
+ v
29
+ elsif v.is_a? ::Symbol
30
+ -> {db.collection v}
31
+ else
32
+ -> {v}
33
+ end
34
+ end
35
+
36
+ def collection *args, &block
37
+ if block
38
+ self.collection = block
39
+ elsif !args.empty?
40
+ args.size.must == 1
41
+ self.collection = args.first
42
+ else
43
+ (_collection && _collection.call) || db.collection(default_collection_name)
44
+ end
45
+ end
46
+
47
+ def default_collection_name
48
+ first_ancestor_class = ancestors.find{|a| a.is_a? Class} ||
49
+ raise("can't evaluate default collection name for #{self}!")
50
+ first_ancestor_class.alias.pluralize.underscore.to_sym
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,33 @@
1
+ module Mongo::Model::Misc
2
+ def update_timestamps
3
+ now = Time.now.utc
4
+ self.created_at ||= now
5
+ self.updated_at = now
6
+ end
7
+
8
+
9
+ def _cache
10
+ @_cache ||= {}
11
+ end
12
+ def _clear_cache
13
+ @_cache = {}
14
+ end
15
+
16
+
17
+ def dom_id
18
+ # new_record? ? "new_#{self.class.name.underscore}" : to_param
19
+ to_param
20
+ end
21
+
22
+ def to_param
23
+ (_id || '').to_s
24
+ end
25
+
26
+
27
+ module ClassMethods
28
+ def timestamps!
29
+ attr_accessor :created_at, :updated_at
30
+ before_save :update_timestamps
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,11 @@
1
+ module Mongo::Model
2
+ attr_accessor :_id, :_class
3
+
4
+ def _id?; !!_id end
5
+ def new_record?; !_id end
6
+
7
+ class << self
8
+ attr_accessor :db, :connection
9
+ attr_required :db, :connection
10
+ end
11
+ end
@@ -0,0 +1,36 @@
1
+ module Mongo::Model::Query
2
+ module ClassMethods
3
+ include Mongo::DynamicFinders
4
+
5
+ def count selector = {}, opts = {}
6
+ collection.count selector, opts
7
+ end
8
+
9
+ def first selector = {}, opts = {}
10
+ collection.first selector, opts
11
+ end
12
+
13
+ def each selector = {}, opts = {}, &block
14
+ collection.each selector, opts, &block
15
+ end
16
+
17
+ def all selector = {}, opts = {}, &block
18
+ if block
19
+ each selector, opts, &block
20
+ else
21
+ list = []
22
+ each(selector, opts){|doc| list << doc}
23
+ list
24
+ end
25
+ end
26
+
27
+ def first! selector = {}, opts = {}
28
+ first(selector, opts) || raise(Mongo::NotFound, "document with selector #{selector} not found!")
29
+ end
30
+
31
+ def exists? selector = {}, opts = {}
32
+ count(selector, opts) > 0
33
+ end
34
+ alias :exist? :exists?
35
+ end
36
+ end
@@ -0,0 +1,99 @@
1
+ module Mongo::Model::Scope
2
+ class ScopeProxy < BasicObject
3
+ def initialize model, scope
4
+ @model, @scope = model, scope
5
+ end
6
+
7
+ def class
8
+ ::Mongo::Model::Scope::ScopeProxy
9
+ end
10
+
11
+ def reverse_merge! scope
12
+ @scope = scope.merge @scope
13
+ end
14
+
15
+ def inspect
16
+ "#<ScopeProxy:{#{scope.inspect}}>"
17
+ end
18
+ alias_method :to_s, :inspect
19
+
20
+ protected
21
+ attr_reader :model, :scope
22
+
23
+ def method_missing method, *args, &block
24
+ model.with_scope scope do
25
+ result = model.send method, *args, &block
26
+ result.reverse_merge! scope if result.class == ::Mongo::Model::Scope::ScopeProxy
27
+ result
28
+ end
29
+ end
30
+ end
31
+
32
+ module ClassMethods
33
+ def current_scope
34
+ scope, exclusive = Thread.current[:mongo_model_scope]
35
+ if exclusive
36
+ scope
37
+ elsif scope
38
+ default_scope.merge scope
39
+ else
40
+ default_scope
41
+ end
42
+ end
43
+
44
+ def with_exclusive_scope options = {}, &block
45
+ with_scope options, true, &block
46
+ end
47
+
48
+ def with_scope options = {}, exclusive = false, &block
49
+ previous_options, previous_exclusive = Thread.current[:mongo_model_scope]
50
+ raise "exclusive scope already applied!" if previous_exclusive
51
+
52
+ begin
53
+ options = previous_options.merge options if previous_options and !exclusive
54
+ Thread.current[:mongo_model_scope] = [options, exclusive]
55
+ return block.call
56
+ ensure
57
+ Thread.current[:mongo_model_scope] = [previous_options, false]
58
+ end
59
+ end
60
+
61
+ inheritable_accessor :_default_scope, -> {{}}
62
+ def default_scope *args, &block
63
+ if block
64
+ self._default_scope = block
65
+ elsif !args.empty?
66
+ args.size.must == 1
67
+ args.first.must_be.a Hash
68
+ scope = args.first
69
+ self._default_scope = -> {args.first}
70
+ else
71
+ _default_scope.call
72
+ end
73
+ end
74
+
75
+ def scope name, options = nil, &block
76
+ model = self
77
+ metaclass.define_method name do
78
+ scope = (block && block.call) || options
79
+ ScopeProxy.new model, scope
80
+ end
81
+ end
82
+
83
+
84
+ #
85
+ # finders
86
+ #
87
+ def count selector = {}, opts = {}
88
+ super current_scope.merge(selector), opts
89
+ end
90
+
91
+ def first selector = {}, opts = {}
92
+ super current_scope.merge(selector), opts
93
+ end
94
+
95
+ def each selector = {}, opts = {}, &block
96
+ super current_scope.merge(selector), opts, &block
97
+ end
98
+ end
99
+ end