mongous 0.1.8 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/README.adoc +286 -48
  3. data/README.ja.adoc +288 -50
  4. data/lib/mongous/base.rb +45 -2
  5. data/lib/mongous/document.rb +75 -32
  6. data/lib/mongous/extention.rb +74 -55
  7. data/lib/mongous/filter.rb +316 -233
  8. data/lib/mongous/version.rb +1 -1
  9. data/mongous.gemspec +1 -1
  10. data/sample/connect_auto_0.rb +9 -0
  11. data/sample/declare_compact_1.rb +7 -9
  12. data/sample/declare_compact_2.rb +38 -0
  13. data/sample/declare_label_1.rb +10 -8
  14. data/sample/declare_ndex_1.rb +9 -7
  15. data/sample/declare_ndex_2.rb +10 -8
  16. data/sample/declare_strict_1.rb +14 -12
  17. data/sample/declare_strict_2.rb +5 -5
  18. data/sample/{multi_docs_1.rb → multi_collection_1.rb} +0 -2
  19. data/sample/multi_collection_2.rb +61 -0
  20. data/sample/multi_collection_3.rb +24 -0
  21. data/sample/query_basic_1.rb +8 -3
  22. data/sample/query_basic_2.rb +11 -6
  23. data/sample/query_basic_3.rb +2 -5
  24. data/sample/query_basic_4.rb +3 -6
  25. data/sample/query_basic_5.rb +2 -5
  26. data/sample/query_basic_6.rb +35 -22
  27. data/sample/query_detail_1.rb +3 -3
  28. data/sample/query_detail_2.rb +3 -3
  29. data/sample/query_detail_3.rb +5 -5
  30. data/sample/query_filter_1.rb +44 -0
  31. data/sample/query_filter_2.rb +48 -0
  32. data/sample/{query_super_1.rb → query_find_1.rb} +6 -6
  33. data/sample/query_select_1.rb +54 -0
  34. data/sample/query_skip_limit_1.rb +48 -0
  35. data/sample/query_skip_limit_2.rb +58 -0
  36. data/sample/query_sort_1.rb +43 -0
  37. data/sample/save_basic_1.rb +2 -7
  38. data/sample/save_basic_2.rb +2 -7
  39. data/sample/save_basic_3.rb +2 -7
  40. data/sample/save_detail_1.rb +7 -6
  41. data/sample/save_detail_2.rb +7 -6
  42. data/sample/save_detail_3.rb +11 -10
  43. data/sample/save_verify_1.rb +7 -6
  44. data/sample/save_verify_2.rb +0 -2
  45. data/sample/save_verify_3.rb +1 -3
  46. data/sample/save_verify_4.rb +0 -2
  47. data/sample/save_verify_5.rb +3 -5
  48. data/sample/save_verify_6.rb +3 -5
  49. data/sample/save_verify_7.rb +21 -0
  50. data/sample/update_basic_1.rb +9 -0
  51. data/sample/zap_basic_1.rb +1 -5
  52. data/sample/zap_basic_2.rb +2 -6
  53. data/sample/zap_basic_3.rb +2 -6
  54. data/sample/zbenchmark_search_1.rb +114 -0
  55. data/sample/zbenchmark_search_2.rb +114 -0
  56. data/sample/zbenchmark_search_3.rb +88 -0
  57. metadata +20 -12
  58. data/sample/multi_docs_2.rb +0 -58
  59. data/sample/query_basic_7.rb +0 -38
  60. data/sample/query_limit_1.rb +0 -44
  61. data/sample/query_order_1.rb +0 -49
  62. data/sample/query_projection_1.rb +0 -44
  63. data/sample/template_article.rb +0 -5
  64. data/sample/template_person.rb +0 -12
@@ -50,12 +50,55 @@ module Mongous
50
50
  self.class_variable_set( :@@client, _client )
51
51
  end
52
52
 
53
+ def document!( *names, **opts )
54
+ raise Mongous::Error, "missing argument." if names.empty?
55
+
56
+ names.each do |name|
57
+ case name
58
+ when String
59
+ when Symbol
60
+ name = name.to_s
61
+ else
62
+ raise Mongous::Error, "type invalid. : #{ name }"
63
+ end
64
+
65
+ raise Mongous::Error, "missing argument." unless /^[A-Z]/.match(name)
66
+
67
+ if Object.const_defined?( name )
68
+ if Object.const_get( name ).include?( Mongous::Document )
69
+ Object.class_eval{ remove_const( name ) }
70
+ else
71
+ raise Mongous::Error, "type invalid. : #{ Object.class_eval(name) }"
72
+ end
73
+ end
74
+
75
+ klass = Object.class_eval <<-CLASS
76
+ class #{name}
77
+ include Mongous::Document
78
+ end
79
+ CLASS
80
+
81
+ if opts[:timestamp]
82
+ klass.class_eval do
83
+ field :created_at, Time, create: proc{ Time.now }
84
+ field :updated_at, Time, update: proc{ Time.now }
85
+ index :created_at
86
+ index :updated_at
87
+ end
88
+ end
89
+ end
90
+ end
91
+ alias :attach! :document!
92
+
53
93
  def client
54
- self.class_variable_get( :@@client ) rescue nil
94
+ if not self.class_variable_defined?( :@@client )
95
+ connect!
96
+ end
97
+ self.class_variable_get( :@@client )
55
98
  end
56
99
 
57
100
  def client=( _client )
58
- if !_client.is_a?( ::Mongo::Client )
101
+ if not _client.is_a?( ::Mongo::Client )
59
102
  raise Mongous::Error, "type invalid. : #{ _client }"
60
103
  end
61
104
  self.class_variable_set( :@@client, _client )
@@ -26,33 +26,66 @@ module Mongous
26
26
  end
27
27
  end
28
28
 
29
- def having?( value )
30
- case value
29
+ def having?( label )
30
+ case label
31
31
  when NilClass
32
32
  false
33
33
  when String
34
- !value.strip.empty?
34
+ !label.strip.empty?
35
35
  else
36
36
  true
37
37
  end
38
38
  end
39
39
 
40
+ def getvalue_or_callproc( value_or_proc )
41
+ case value_or_proc
42
+ when Proc
43
+ value_or_proc.call
44
+ else
45
+ value_or_proc
46
+ end
47
+ end
48
+
40
49
  def save
50
+ if @doc["_id"].nil? || self.class.collection.find( { "_id"=> @doc["_id"] } ).count == 0
51
+ savemode = :create
52
+ else
53
+ savemode = :update
54
+ end
55
+
41
56
  self.class.fields.each do |label, field|
42
- _must = field[:_args].include?(:must)
57
+ default_value = getvalue_or_callproc( field[:default] )
58
+ _must = field[:_attrs].include?(:must)
43
59
  if @doc.has_key?(label)
44
- if _must && !having?( @doc[label] )
45
- raise Mongous::Error, "must and not having field. : #{ label }"
60
+ if !having?( @doc[label] )
61
+ if default_value
62
+ self[label] = default_value
63
+ elsif _must
64
+ raise Mongous::Error, "must but unassigned field. : #{ label }"
65
+ elsif self.class.symbols[:strict]
66
+ self[label] = nil
67
+ end
46
68
  end
47
69
  else
48
- if block = field[:_block]
49
- self[label] = block.call
70
+ if default_value
71
+ self[label] = default_value
50
72
  elsif _must
51
- raise Mongous::Error, "must and unassigned field. : #{ label }"
73
+ raise Mongous::Error, "must but unassigned field. : #{ label }"
52
74
  elsif self.class.symbols[:strict]
53
75
  self[label] = nil
54
76
  end
55
77
  end
78
+
79
+ case savemode
80
+ when :create
81
+ if create_value = getvalue_or_callproc( field[:create] )
82
+ self[label] = create_value
83
+ end
84
+ when :update
85
+ if update_value = getvalue_or_callproc( field[:update] )
86
+ self[label] = update_value
87
+ end
88
+ end
56
89
  end
57
90
 
58
91
  self.class.blocks.each do |call_from, block|
@@ -61,23 +94,29 @@ module Mongous
61
94
  end
62
95
  end
63
96
 
64
- if @doc["_id"]
65
- _filter = { "_id"=> @doc["_id"] }
66
- if self.class.collection.find( _filter ).first
67
- self.class.collection.update_one( _filter, { '$set' => @doc } )
68
- return self
69
- end
97
+ case savemode
98
+ when :create
99
+ self.class.collection.insert_one( @doc )
100
+ when :update
101
+ self.class.collection.update_one( { "_id"=> @doc["_id"] }, { '$set' => @doc } )
70
102
  end
71
-
72
- self.class.collection.insert_one( @doc )
73
103
  self
74
104
  end
75
105
 
106
+ def to_hash
107
+ @doc.dup
108
+ end
109
+
110
+ def to_json
111
+ @doc.to_json
112
+ end
113
+
76
114
  def []( label )
77
115
  label = label.to_s
78
116
 
79
117
  if self.class.symbols[:strict]
80
- if !self.class.fields.keys.include?(label)
118
+ labels = ["_id"] + self.class.fields.keys
119
+ if !labels.include?( label )
81
120
  raise Mongous::Error, "undefined field. : #{ label }"
82
121
  end
83
122
  end
@@ -108,18 +147,18 @@ module Mongous
108
147
  return @doc[label] = value if field.nil?
109
148
 
110
149
  types = []
111
- if args = field[:_args] || []
112
- args.each do |arg|
113
- if arg.class == Class
114
- types << arg
115
- args -= [arg]
150
+ if attrs = field[:_attrs] || []
151
+ attrs.each do |attr|
152
+ if attr.class == Class
153
+ types << attr
154
+ attrs -= [attr]
116
155
  break
117
156
  end
118
157
  end
119
158
  end
120
159
 
121
160
  if !types.empty?
122
- if !(args & [:must, :not_null]).empty?
161
+ if !(attrs & [:must, :not_null]).empty?
123
162
  if !types.include?( value.class )
124
163
  raise Mongous::Error, "invalid type. : #{ label } : #{ value.class }"
125
164
  end
@@ -129,7 +168,7 @@ module Mongous
129
168
  end
130
169
  end
131
170
  else
132
- if !(args & [:must, :not_null]).empty?
171
+ if !(attrs & [:must, :not_null]).empty?
133
172
  if [NilClass].include?( value.class )
134
173
  raise Mongous::Error, "invalid type. : #{ label } : #{ value.class }"
135
174
  end
@@ -138,19 +177,23 @@ module Mongous
138
177
 
139
178
  @doc[label] = value
140
179
 
141
- args.each do |arg|
142
- case arg
180
+ attrs.each do |attr|
181
+ case attr
143
182
  when Proc
144
- if !self.instance_eval( &arg )
183
+ if !self.instance_eval( &attr )
145
184
  raise Mongous::Error, "violation detected. : #{ label } : #{ value }"
146
185
  end
147
186
  when Array
148
- if !arg.include?( value )
149
- raise Mongous::Error, "not include. : #{ label } :#{ value }"
187
+ if !attr.include?( value )
188
+ raise Mongous::Error, "not include. : #{ label } : #{ value }"
150
189
  end
151
190
  when Range
152
- if !arg.cover?( value )
153
- raise Mongous::Error, "out of range. : #{ label } :#{ value }"
191
+ if !attr.cover?( value )
192
+ raise Mongous::Error, "out of range. : #{ label } : #{ value }"
193
+ end
194
+ when Regexp
195
+ if !attr.match( value )
196
+ raise Mongous::Error, "unmatch regexp. : #{ label } : #{ value }"
154
197
  end
155
198
  end
156
199
  end
@@ -21,11 +21,11 @@ module Mongous
21
21
 
22
22
  def collection_name
23
23
  if self.class_variable_defined?( :@@collection_name )
24
- self.class_variable_get( :@@collection_name )
25
- else
26
- _client_name = self.name
27
- self.class_variable_set( :@@collection_name, _client_name )
24
+ value = self.class_variable_get( :@@collection_name )
25
+ return value if value
28
26
  end
27
+
28
+ self.class_variable_set( :@@collection_name, self.name )
29
29
  end
30
30
 
31
31
  def collection_name=( _collection_name )
@@ -35,14 +35,17 @@ module Mongous
35
35
  end
36
36
  end
37
37
 
38
- def collection
39
- if self.class_variable_defined?( :@@collection )
40
- if _collection = self.class_variable_get( :@@collection )
41
- return _collection
38
+ def collection( temp_collection_name = nil )
39
+ if temp_collection_name.nil?
40
+ if self.class_variable_defined?( :@@collection )
41
+ if _collection = self.class_variable_get( :@@collection )
42
+ return _collection
43
+ end
42
44
  end
45
+ _collection_name = collection_name
46
+ else
47
+ _collection_name = temp_collection_name
43
48
  end
44
-
45
- _collection_name = collection_name
46
49
  _client = client
47
50
 
48
51
  if _client.database.collection_names.include?( _collection_name )
@@ -56,38 +59,41 @@ module Mongous
56
59
  _collection.indexes.create_one( keys, opts ) rescue nil
57
60
  end
58
61
 
59
- self.class_variable_set( :@@collection, _collection )
62
+ self.class_variable_set( :@@collection, _collection ) if temp_collection_name.nil?
63
+ _collection
60
64
  end
61
65
 
62
66
  def fields
63
- if self.class_variable_defined?( :@@fields )
64
- self.class_variable_get( :@@fields )
65
- else
66
- self.class_variable_set( :@@fields, {} )
67
- end
67
+ setup_class_variable( :@@fields, {} )
68
68
  end
69
69
 
70
70
  def symbols
71
- if self.class_variable_defined?( :@@symbols )
72
- self.class_variable_get( :@@symbols )
73
- else
74
- self.class_variable_set( :@@symbols, {} )
75
- end
71
+ setup_class_variable( :@@symbols, {} )
76
72
  end
77
73
 
78
74
  def blocks
79
- if self.class_variable_defined?( :@@blocks )
80
- self.class_variable_get( :@@blocks )
81
- else
82
- self.class_variable_set( :@@blocks, {} )
83
- end
75
+ setup_class_variable( :@@blocks, {} )
84
76
  end
85
77
 
86
78
  def indexes
87
- if self.class_variable_defined?( :@@indexes )
88
- self.class_variable_get( :@@indexes )
79
+ setup_class_variable( :@@indexes, [] )
80
+ end
81
+
82
+ def filters
83
+ setup_class_variable( :@@filters, {} )
84
+ end
85
+
86
+ def defaults
87
+ setup_class_variable( :@@defaults, {} )
88
+ end
89
+
90
+ def setup_class_variable( symbol, default = {}, &block )
91
+ if self.class_variable_defined?( symbol )
92
+ self.class_variable_get( symbol )
93
+ elsif block_given?
94
+ self.class_variable_set( symbol, block.call )
89
95
  else
90
- self.class_variable_set( :@@indexes, [] )
96
+ self.class_variable_set( symbol, default )
91
97
  end
92
98
  end
93
99
 
@@ -95,57 +101,70 @@ module Mongous
95
101
  self.new( **doc ).save
96
102
  end
97
103
 
104
+ def drop
105
+ self.collection.drop
106
+ end
107
+
98
108
  def find( conditios = {}, options = {} )
99
109
  self.collection.find( conditios, options )
100
110
  end
101
111
 
102
- def field( label, *args, **opts, &block )
112
+ def field( symbol, *attrs, **items )
103
113
  m = /(.*?):(\d+)/.match( caller()[0] )
104
114
  call_from = [ m[1], m[2] ].join(":")
105
115
 
106
- args.each do |arg|
107
- if klass = arg.class
108
- if ![Class, Range, Array, Proc, Symbol].include?(klass)
109
- raise Mongous::Error, "field error. : #{arg} on #{ label } at #{ call_from }"
116
+ attrs.each do |attr|
117
+ if klass = attr.class
118
+ if ![Class, Range, Array, Regexp, Proc, Symbol].include?(klass)
119
+ raise Mongous::Error, "'field' arguments error. : #{ attr } on #{ symbol } at #{ call_from }"
110
120
  end
111
121
  end
112
122
  end
113
123
 
114
- opts.each do |key, value|
115
- case key
116
- when :default
117
- case value
118
- when Proc, String, Numeric
119
- else
120
- raise Mongous::Error, "field error. : #{key} on #{ label } at #{ call_from }"
121
- end
122
- end
124
+ items.each do |key, value|
125
+ next if [:default, :create, :update].include?(key) && [Proc, String, Numeric].include?(value.class)
126
+
127
+ raise Mongous::Error, "'field' options error. : #{key} on #{ symbol } at #{ call_from }"
123
128
  end
124
129
 
125
- opts[:_args] = args
126
- opts[:_block] = block
127
- fields[label.to_s] = opts
130
+ items[:_attrs] = attrs
131
+ fields[symbol.to_s] = items
128
132
  end
129
133
 
130
- def verify( *syms, &block )
131
- if !syms.empty?
132
- syms.each do |sym|
133
- symbols[sym] = true
134
+ def verify( *directives, &block )
135
+ if !directives.empty?
136
+ directives.each do |directive|
137
+ symbols[directive] = true
134
138
  end
135
139
  elsif block
136
140
  m = /(.*?):(\d+)/.match( caller()[0] )
137
141
  call_from = [ m[1], m[2] ].join(":")
138
142
  blocks[call_from] = block
143
+ else
144
+ raise Mongous::Error, "'verify' arguments error. need directives or block."
139
145
  end
140
146
  end
141
147
 
142
- def index( *syms, **opts )
143
- opts[:background] = true unless opts.has_key?(:background)
148
+ def index( *symbols, **options )
149
+ options[:background] = true unless options.has_key?(:background)
144
150
  keys = {}
145
- syms.each do |sym|
146
- keys[sym] = 1
151
+ symbols.each do |symbol|
152
+ keys[symbol] = 1
153
+ end
154
+ indexes.push << [keys, options]
155
+ end
156
+
157
+ def filter( symbol, filter_or_condition )
158
+ case filter_or_condition
159
+ when Filter
160
+ filters[symbol] = filter_or_condition.to_condition
161
+ when Hash
162
+ filters[symbol] = filter_or_condition
163
+ else
164
+ m = /(.*?):(\d+)/.match( caller()[0] )
165
+ call_from = [ m[1], m[2] ].join(":")
166
+ raise Mongous::Error, "'filter' arguments error. : #{symbol}, #{filter_or_condition} at #{ call_from }"
147
167
  end
148
- indexes.push << [keys, opts]
149
168
  end
150
169
  end
151
170
  end
@@ -1,233 +1,316 @@
1
-
2
- module Mongous
3
- module Extention
4
- def count
5
- self.collection.find.count
6
- end
7
-
8
- def first
9
- doc = self.collection.find.first
10
- self.new( **doc ) if doc
11
- end
12
-
13
- def all
14
- self.collection.find.map do |doc|
15
- self.new( **doc )
16
- end
17
- end
18
-
19
- def each( &block )
20
- all.each( &block )
21
- end
22
-
23
- def delete
24
- self.collection.delete_many({})
25
- end
26
-
27
- def filter( **conditions )
28
- Filter.new( self ).filter( conditions )
29
- end
30
-
31
- def not( filter = nil, **conditions )
32
- raise Mongous::Error, "Unset args for #{self}.not." if filter.nil? && conditions.empty?
33
-
34
- filter ||= conditions
35
- condition = case filter
36
- when Hash
37
- Filter.new( self ).filter( filter ).to_condition
38
- when Filter
39
- filter.to_condition
40
- else
41
- raise Mongous::Error, "Invalid args for #{self}.not. : #{filter}"
42
- end
43
- Filter.new( self ).filter({"$nor" => [condition]})
44
- end
45
-
46
- def and( *filters )
47
- raise Mongous::Error, "Unset args for #{self}.and." if filters.empty?
48
-
49
- conditions = filters.map do |filter|
50
- case filter
51
- when Hash
52
- filter
53
- when Filter
54
- filter.to_condition
55
- else
56
- raise Mongous::Error, "Invalid args for #{self}.and. : #{filter}"
57
- end
58
- end
59
- Filter.new( self ).filter({"$and" => conditions})
60
- end
61
-
62
- def or( *filters )
63
- raise Mongous::Error, "Unset args for #{self}.or." if filters.empty?
64
-
65
- conditions = filters.map do |filter|
66
- case filter
67
- when Hash
68
- filter
69
- when Filter
70
- filter.to_condition
71
- else
72
- raise Mongous::Error, "Invalid args for #{self}.or. : #{filter}"
73
- end
74
- end
75
- Filter.new( self ).filter({"$or" => conditions})
76
- end
77
- end
78
- end
79
-
80
- module Mongous
81
- class Filter
82
- def initialize( klass )
83
- @klass = klass
84
- @filter = {}
85
- @option = {}
86
- end
87
-
88
- def filter( conditions )
89
- hash = {}
90
- conditions.each do |key, item|
91
- case key
92
- when /\$(and|or|nor)/
93
- hash[key] = item
94
-
95
- else
96
- case item
97
- when Array
98
- hash[key] = {"$in"=>item}
99
-
100
- when Range
101
- _begin_oper = "$gte"
102
- _end_oper = item.exclude_end? ? "$lt" : "$lte"
103
-
104
- if item.begin && item.end
105
- hash[key] = { _begin_oper => item.begin, _end_oper => item.end }
106
-
107
- elsif !item.begin && item.end
108
- hash[key] = { _end_oper => item.end }
109
-
110
- elsif item.begin && !item.end
111
- hash[key] = { _begin_oper => item.begin }
112
-
113
- else
114
- raise Mongous::Error, "invalid range. : #{ item }"
115
-
116
- end
117
-
118
- else
119
- hash[key] = item
120
-
121
- end
122
- end
123
- end
124
- @filter.merge!( hash )
125
- self.dup
126
- end
127
-
128
- def to_condition
129
- @filter.dup
130
- end
131
-
132
- def option( _option )
133
- @option.merge!( _option )
134
- self.dup
135
- end
136
-
137
- def projection( _projection )
138
- @projection = _projection
139
- self.dup
140
- end
141
- alias :select :projection
142
-
143
- def sort( _sort )
144
- @sort = _sort
145
- self.dup
146
- end
147
- alias :order :sort
148
-
149
- def skip( _skip )
150
- @skip = _skip
151
- self.dup
152
- end
153
- alias :offset :skip
154
-
155
- def limit( _limit )
156
- @limit = _limit
157
- self.dup
158
- end
159
-
160
- def []( nth_or_range, len = 1 )
161
- case nth_or_range
162
- when Integer
163
- raise Mongous::Error, "invalid nth. : #{ nth_or_range }" if len < 0
164
- @skip = nth_or_range
165
-
166
- raise Mongous::Error, "invalid len. : #{ len }" if !len.is_a? Integer || len <= 0
167
- @limit = len
168
-
169
- when Range
170
- from = nth_or_range.begin
171
- raise Mongous::Error, "invalid range. : #{ nth_or_range }" unless from.is_a? Integer
172
-
173
- to = nth_or_range.end
174
- raise Mongous::Error, "invalid range. : #{ nth_or_range }" unless to.is_a? Integer
175
-
176
- to -= 1 if nth_or_range.exclude_end?
177
- @skip = from
178
- @limit = to - from + 1
179
-
180
- else
181
- raise Mongous::Error, "invalid class. : #{ nth_or_range }"
182
-
183
- end
184
-
185
- self.dup
186
- end
187
-
188
- def do_find
189
- _filter = @filter
190
- _option = @option
191
- _option[:projection] = @projection if @projection
192
- found = @klass.collection.find( _filter, _option )
193
- found = found.sort( @sort ) if @sort
194
- found = found.skip( @skip ) if @skip
195
- found = found.limit( @limit ) if @limit
196
- found
197
- end
198
-
199
- def count
200
- _count = do_find.count
201
- if @skip && @limit
202
- [_count - @skip, @limit].min
203
- elsif @skip.nil? && @limit
204
- [_count, @limit].min
205
- elsif @skip && @limit.nil?
206
- [_count - @skip, 0].max
207
- else
208
- _count
209
- end
210
- end
211
-
212
- def first
213
- doc = do_find.first
214
- @klass.new( **doc ) if doc
215
- end
216
-
217
- def all
218
- do_find.map do |doc|
219
- @klass.new( **doc )
220
- end
221
- end
222
-
223
- def each( &block )
224
- all.each( &block )
225
- end
226
-
227
- def delete
228
- _filter = @filter
229
- @klass.collection.delete_many( _filter )
230
- end
231
- end
232
- end
233
-
1
+
2
+ module Mongous
3
+ module Extention
4
+ def count
5
+ self.collection.estimated_document_count
6
+ end
7
+
8
+ def all
9
+ self.collection.find.map do |doc|
10
+ self.new( **doc )
11
+ end
12
+ end
13
+
14
+ def each( &block )
15
+ all.each( &block )
16
+ end
17
+
18
+ def map( &block )
19
+ all.map( &block )
20
+ end
21
+
22
+ def delete
23
+ self.collection.delete_many({})
24
+ end
25
+
26
+ def attach( collection_name )
27
+ Filter.new( self ).attach( collection_name )
28
+ end
29
+
30
+ def []( nth_or_range, len = nil )
31
+ Filter.new( self )[ nth_or_range, len ]
32
+ end
33
+
34
+ def first
35
+ Filter.new( self ).first
36
+ end
37
+
38
+ def last
39
+ Filter.new( self ).last
40
+ end
41
+
42
+ def sort( *keys, **hash )
43
+ Filter.new( self ).sort( *keys, **hash )
44
+ end
45
+
46
+ def select( *keys, **hash )
47
+ Filter.new( self ).select( *keys, **hash )
48
+ end
49
+
50
+ def where( filter = nil, **conditions )
51
+ condition = normalize( filter, conditions )
52
+ Filter.new( self ).where( condition )
53
+ end
54
+
55
+ def not( filter = nil, **conditions )
56
+ raise Mongous::Error, "Unset args for #{self}.not." if filter.nil? && conditions.empty?
57
+
58
+ condition = normalize( filter, conditions )
59
+ Filter.new( self ).not( condition )
60
+ end
61
+
62
+ def and( *filters )
63
+ raise Mongous::Error, "Unset args for #{self}.and." if filters.empty?
64
+
65
+ conditions = filters.map do |filter|
66
+ normalize( filter, {} )
67
+ end
68
+ Filter.new( self ).where({"$and" => conditions})
69
+ end
70
+
71
+ def or( *filters )
72
+ raise Mongous::Error, "Unset args for #{self}.or." if filters.empty?
73
+
74
+ conditions = filters.map do |filter|
75
+ normalize( filter, {} )
76
+ end
77
+ Filter.new( self ).where({"$or" => conditions})
78
+ end
79
+
80
+ def normalize( filter, conditions )
81
+ condition = case filter
82
+ when Filter
83
+ filter.to_condition
84
+ when Symbol
85
+ case _filter = filters[filter]
86
+ when Filter
87
+ _filter.to_condition
88
+ when Hash
89
+ _filter
90
+ end
91
+ when NilClass
92
+ Filter.new( self ).where( **conditions ).to_condition
93
+ else
94
+ caller_method = /`(.*?)'/.match( caller()[0] )[1]
95
+ raise Mongous::Error, "Invalid args for #{self}.#{ caller_method }. : #{filter}, #{conditions}"
96
+ end
97
+ end
98
+ end
99
+ end
100
+
101
+ module Mongous
102
+ class Filter
103
+ def initialize( klass )
104
+ @klass = klass
105
+ @filter = {}
106
+ @option = {}
107
+ end
108
+
109
+ def attach( collection_name )
110
+ w = self.dup
111
+ w.instance_variable_set( :@collection_name, collection_name.to_s )
112
+ w
113
+ end
114
+
115
+ def build_condition( conditions )
116
+ hash = {}
117
+ conditions.each do |key, item|
118
+ case key
119
+ when /\$(and|or|nor)/
120
+ hash[key] = item
121
+
122
+ else
123
+ case item
124
+ when Array
125
+ hash[key] = {"$in"=>item}
126
+
127
+ when Range
128
+ _begin_oper = "$gte"
129
+ _end_oper = item.exclude_end? ? "$lt" : "$lte"
130
+
131
+ if item.begin && item.end
132
+ hash[key] = { _begin_oper => item.begin, _end_oper => item.end }
133
+
134
+ elsif !item.begin && item.end
135
+ hash[key] = { _end_oper => item.end }
136
+
137
+ elsif item.begin && !item.end
138
+ hash[key] = { _begin_oper => item.begin }
139
+
140
+ else
141
+ raise Mongous::Error, "invalid range. : #{ item }"
142
+
143
+ end
144
+
145
+ else
146
+ hash[key] = item
147
+
148
+ end
149
+ end
150
+ end
151
+ hash
152
+ end
153
+
154
+ def where( conditions )
155
+ hash = build_condition( conditions )
156
+ w = self.dup
157
+ w.instance_variable_set( :@filter, @filter.merge( hash ) )
158
+ w
159
+ end
160
+
161
+ def not( conditions )
162
+ hash = build_condition( conditions )
163
+ w = self.dup
164
+ w.instance_variable_set( :@filter, @filter.merge( {"$nor" => [hash]} ) )
165
+ w
166
+ end
167
+
168
+ def to_condition
169
+ @filter.dup
170
+ end
171
+
172
+ def option( _option )
173
+ w = self.dup
174
+ w.instance_variable_set( :@option, @option.merge( _option ) )
175
+ w
176
+ end
177
+
178
+ def select( *keys, **hash )
179
+ if not keys.empty?
180
+ _projection = Hash[ keys.zip( Array.new(keys.length, 1) ) ]
181
+ elsif not hash.empty?
182
+ _projection = hash
183
+ else
184
+ _projection = nil
185
+ end
186
+ w = self.dup
187
+ w.instance_variable_set( :@projection, _projection )
188
+ w
189
+ end
190
+
191
+ def sort( *keys, **hash )
192
+ if not keys.empty?
193
+ _sort = Hash[ keys.zip( Array.new( keys.length, 1 ) ) ]
194
+ elsif not hash.empty?
195
+ _sort = hash
196
+ else
197
+ _sort = nil
198
+ end
199
+ w = self.dup
200
+ w.instance_variable_set( :@sort, _sort )
201
+ w
202
+ end
203
+
204
+ def []( nth_or_range, len = nil )
205
+ case nth_or_range
206
+ when Integer
207
+ _skip = nth_or_range
208
+
209
+ if len.is_a?(NilClass)
210
+ _limit = 1
211
+ elsif len.is_a?(Integer) && len == 0
212
+ _limit = nil
213
+ elsif len.is_a?(Integer) && len > 0
214
+ _limit = len
215
+ else
216
+ raise Mongous::Error, "invalid len. : #{ len }"
217
+ end
218
+
219
+ when Range
220
+ from = nth_or_range.begin
221
+ raise Mongous::Error, "invalid range. : #{ nth_or_range }" unless from.is_a? Integer
222
+
223
+ to = nth_or_range.end
224
+ raise Mongous::Error, "invalid range. : #{ nth_or_range }" unless to.is_a? Integer
225
+
226
+ to -= 1 if nth_or_range.exclude_end?
227
+ _skip = from
228
+ _limit = to - from + 1
229
+
230
+ else
231
+ raise Mongous::Error, "invalid class. : #{ nth_or_range }"
232
+
233
+ end
234
+
235
+ w = self.dup
236
+ w.instance_variable_set( :@skip, _skip )
237
+ w.instance_variable_set( :@limit, _limit )
238
+ w
239
+ end
240
+
241
+ def exec_query
242
+ _filter = @filter
243
+ _option = @option.dup
244
+ _option[:projection] = @projection if @projection
245
+ found = @klass.collection( @collection_name ).find( _filter, _option )
246
+ found = found.sort( @sort ) if @sort
247
+ found = found.skip( @skip ) if @skip
248
+ found = found.limit( @limit ) if @limit
249
+ found
250
+ end
251
+
252
+ def count
253
+ found = @klass.collection.find( @filter )
254
+ found = found.skip( @skip ) if @skip
255
+ found = found.limit( @limit ) if @limit
256
+ _count = found.count_documents
257
+ if @skip
258
+ if @skip > _count
259
+ 0
260
+ elsif @limit
261
+ [_count - @skip, @limit].min
262
+ else
263
+ _count - @skip
264
+ end
265
+ else
266
+ if @limit
267
+ [_count, @limit].min
268
+ else
269
+ _count
270
+ end
271
+ end
272
+ end
273
+
274
+ def first
275
+ _filter = @filter
276
+ _option = @option.dup
277
+ _option[:projection] = @projection if @projection
278
+ found = @klass.collection( @collection_name ).find( _filter, _option )
279
+ _order = @sort || { _id: 1 }
280
+ doc = found.sort( _order ).first
281
+ @klass.new( **doc ) if doc
282
+ end
283
+
284
+ def last
285
+ _filter = @filter
286
+ _option = @option.dup
287
+ _option[:projection] = @projection if @projection
288
+ found = @klass.collection( @collection_name ).find( _filter, _option )
289
+ _order = {}
290
+ ( @sort || {_id: 1} ).each do |k,v|
291
+ _order[k] = - v
292
+ end
293
+ doc = found.sort( _order ).first
294
+ @klass.new( **doc ) if doc
295
+ end
296
+
297
+ def all
298
+ exec_query.map do |doc|
299
+ @klass.new( **doc )
300
+ end
301
+ end
302
+
303
+ def each( &block )
304
+ all.each( &block )
305
+ end
306
+
307
+ def map( &block )
308
+ all.map( &block )
309
+ end
310
+
311
+ def delete
312
+ @klass.collection.delete_many( @filter )
313
+ end
314
+ end
315
+ end
316
+