mongous 0.1.6 → 0.4.0

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