mongous 0.1.8 → 0.4.1

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