mongodb 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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