mongous 0.1.6 → 0.4.0

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 (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
+