nobrainer 0.16.0 → 0.18.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 (66) hide show
  1. checksums.yaml +4 -4
  2. data/lib/no_brainer/config.rb +53 -28
  3. data/lib/no_brainer/connection.rb +1 -0
  4. data/lib/no_brainer/connection_manager.rb +60 -0
  5. data/lib/no_brainer/criteria/after_find.rb +3 -11
  6. data/lib/no_brainer/criteria/aggregate.rb +8 -5
  7. data/lib/no_brainer/criteria/cache.rb +7 -7
  8. data/lib/no_brainer/criteria/core.rb +56 -16
  9. data/lib/no_brainer/criteria/count.rb +1 -1
  10. data/lib/no_brainer/criteria/delete.rb +1 -1
  11. data/lib/no_brainer/criteria/extend.rb +19 -0
  12. data/lib/no_brainer/criteria/first.rb +1 -1
  13. data/lib/no_brainer/criteria/index.rb +7 -13
  14. data/lib/no_brainer/criteria/limit.rb +5 -13
  15. data/lib/no_brainer/criteria/order_by.rb +22 -41
  16. data/lib/no_brainer/criteria/pluck.rb +17 -23
  17. data/lib/no_brainer/criteria/preload.rb +9 -15
  18. data/lib/no_brainer/criteria/raw.rb +5 -11
  19. data/lib/no_brainer/criteria/scope.rb +9 -15
  20. data/lib/no_brainer/criteria/update.rb +3 -3
  21. data/lib/no_brainer/criteria/where.rb +33 -56
  22. data/lib/no_brainer/criteria.rb +1 -1
  23. data/lib/no_brainer/document/aliases.rb +1 -1
  24. data/lib/no_brainer/document/association/belongs_to.rb +6 -6
  25. data/lib/no_brainer/document/association/core.rb +11 -11
  26. data/lib/no_brainer/document/association/eager_loader.rb +4 -3
  27. data/lib/no_brainer/document/association/has_many.rb +7 -7
  28. data/lib/no_brainer/document/association/has_many_through.rb +1 -1
  29. data/lib/no_brainer/document/association/has_one.rb +1 -1
  30. data/lib/no_brainer/document/association.rb +5 -5
  31. data/lib/no_brainer/document/atomic_ops.rb +213 -0
  32. data/lib/no_brainer/document/attributes.rb +19 -10
  33. data/lib/no_brainer/document/callbacks.rb +1 -1
  34. data/lib/no_brainer/document/core.rb +1 -1
  35. data/lib/no_brainer/document/criteria.rb +9 -2
  36. data/lib/no_brainer/document/dirty.rb +22 -22
  37. data/lib/no_brainer/document/dynamic_attributes.rb +2 -14
  38. data/lib/no_brainer/document/id.rb +1 -0
  39. data/lib/no_brainer/document/index/index.rb +83 -0
  40. data/lib/no_brainer/document/index/meta_store.rb +31 -0
  41. data/lib/no_brainer/document/index/synchronizer.rb +68 -0
  42. data/lib/no_brainer/document/index.rb +13 -72
  43. data/lib/no_brainer/document/lazy_fetch.rb +5 -5
  44. data/lib/no_brainer/document/missing_attributes.rb +6 -23
  45. data/lib/no_brainer/document/persistance.rb +38 -21
  46. data/lib/no_brainer/document/polymorphic.rb +1 -1
  47. data/lib/no_brainer/document/types/set.rb +23 -0
  48. data/lib/no_brainer/document/types.rb +8 -6
  49. data/lib/no_brainer/document/uniqueness.rb +3 -3
  50. data/lib/no_brainer/document/validation.rb +13 -4
  51. data/lib/no_brainer/document.rb +1 -1
  52. data/lib/no_brainer/error.rb +14 -0
  53. data/lib/no_brainer/fork.rb +1 -0
  54. data/lib/no_brainer/query_runner/connection_lock.rb +5 -1
  55. data/lib/no_brainer/query_runner/database_on_demand.rb +6 -5
  56. data/lib/no_brainer/query_runner/logger.rb +10 -6
  57. data/lib/no_brainer/query_runner/missing_index.rb +5 -4
  58. data/lib/no_brainer/query_runner/reconnect.rb +20 -17
  59. data/lib/no_brainer/query_runner/run_options.rb +3 -0
  60. data/lib/no_brainer/query_runner/table_on_demand.rb +11 -8
  61. data/lib/no_brainer/railtie/database.rake +12 -12
  62. data/lib/no_brainer/railtie.rb +5 -5
  63. data/lib/no_brainer/rql.rb +9 -0
  64. data/lib/nobrainer.rb +9 -23
  65. metadata +10 -4
  66. data/lib/no_brainer/index_manager.rb +0 -9
@@ -1,16 +1,12 @@
1
1
  module NoBrainer::Criteria::OrderBy
2
2
  extend ActiveSupport::Concern
3
3
 
4
- included { attr_accessor :order, :ordering_mode }
5
-
6
- def initialize(options={})
7
- super
8
- self.order = {}
9
- end
4
+ # The latest order_by() wins
5
+ included { criteria_option :order_by, :ordering_mode, :merge_with => :set_scalar }
10
6
 
11
7
  def order_by(*rules, &block)
12
8
  # Note: We are relying on the fact that Hashes are ordered (since 1.9)
13
- rules = [*rules, block].compact.map do |rule|
9
+ rules = [*rules, block].flatten.compact.map do |rule|
14
10
  case rule
15
11
  when Hash then
16
12
  bad_rule = rule.values.reject { |v| v.in? [:asc, :desc] }.first
@@ -21,34 +17,20 @@ module NoBrainer::Criteria::OrderBy
21
17
  end
22
18
  end.reduce({}, :merge)
23
19
 
24
- chain do |criteria|
25
- criteria.order = rules
26
- criteria.ordering_mode = :normal
27
- end
20
+ chain(:order_by => rules, :ordering_mode => :normal)
28
21
  end
29
22
 
30
23
  def without_ordering
31
- chain { |criteria| criteria.ordering_mode = :disabled }
32
- end
33
-
34
- def merge!(criteria, options={})
35
- super
36
- # The latest order_by() wins
37
- self.order = criteria.order if criteria.order.present?
38
- self.ordering_mode = criteria.ordering_mode unless criteria.ordering_mode.nil?
39
- self
24
+ chain(:ordering_mode => :disabled)
40
25
  end
41
26
 
42
27
  def reverse_order
43
- chain do |criteria|
44
- criteria.ordering_mode =
45
- case self.ordering_mode
46
- when nil then :reversed
47
- when :normal then :reversed
48
- when :reversed then :normal
49
- when :disabled then :disabled
50
- end
51
- end
28
+ chain(:ordering_mode => case @options[:ordering_mode]
29
+ when nil then :reversed
30
+ when :normal then :reversed
31
+ when :reversed then :normal
32
+ when :disabled then :disabled
33
+ end)
52
34
  end
53
35
 
54
36
  def order_by_indexed?
@@ -62,15 +44,15 @@ module NoBrainer::Criteria::OrderBy
62
44
  private
63
45
 
64
46
  def effective_order
65
- self.order.presence || (klass ? {klass.pk_name => :asc} : {})
47
+ @options[:order_by].presence || (model ? {model.pk_name => :asc} : {})
66
48
  end
67
49
 
68
50
  def reverse_order?
69
- self.ordering_mode == :reversed
51
+ @options[:ordering_mode] == :reversed
70
52
  end
71
53
 
72
54
  def should_order?
73
- self.ordering_mode != :disabled
55
+ @options[:ordering_mode] != :disabled
74
56
  end
75
57
 
76
58
  class IndexFinder < Struct.new(:criteria, :index_name, :rql_proc)
@@ -83,15 +65,15 @@ module NoBrainer::Criteria::OrderBy
83
65
  end
84
66
 
85
67
  def first_key_indexable?
86
- (first_key.is_a?(Symbol) || first_key.is_a?(String)) && criteria.klass.has_index?(first_key)
68
+ (first_key.is_a?(Symbol) || first_key.is_a?(String)) && criteria.model.has_index?(first_key)
87
69
  end
88
70
 
89
71
  def find_index
90
72
  return if criteria.without_index?
91
73
  return unless first_key_indexable?
92
74
 
93
- if criteria.with_index_name && criteria.with_index_name != true
94
- return unless first_key.to_s == criteria.with_index_name.to_s
75
+ if criteria.options[:use_index] && criteria.options[:use_index] != true
76
+ return unless first_key.to_s == criteria.options[:use_index].to_s
95
77
  end
96
78
 
97
79
  # We need make sure that the where index finder has been invoked, it has priority.
@@ -116,9 +98,9 @@ module NoBrainer::Criteria::OrderBy
116
98
 
117
99
  rql_rules = _effective_order.map do |k,v|
118
100
  if order_by_index_finder.index_name == k
119
- k = klass.lookup_index_alias(k)
101
+ k = model.lookup_index_alias(k)
120
102
  else
121
- k = klass.lookup_field_alias(k)
103
+ k = model.lookup_field_alias(k)
122
104
  end
123
105
 
124
106
  case v
@@ -127,14 +109,13 @@ module NoBrainer::Criteria::OrderBy
127
109
  end
128
110
  end
129
111
 
130
- # We can only apply an index order_by on a table() term.
131
- # We are going to try to go so and if we cannot, we'll simply apply
132
- # the ordering in pass2, which will happen after a potential filter().
112
+ # We can only apply an indexed order_by on a table() RQL term.
113
+ # If we can, great. Otherwise, the ordering is applied in pass2, which will
114
+ # happen after a potential filter(), which is better for perfs.
133
115
  if order_by_index_finder.could_find_index?
134
116
  options = { :index => rql_rules.shift }
135
117
  rql = rql.order_by(*rql_rules, options)
136
118
  else
137
- # Stashing @rql_rules for pass2
138
119
  @rql_rules_pass2 = rql_rules
139
120
  end
140
121
 
@@ -1,7 +1,8 @@
1
1
  module NoBrainer::Criteria::Pluck
2
2
  extend ActiveSupport::Concern
3
3
 
4
- included { attr_accessor :missing_attributes }
4
+ included { criteria_option :missing_attributes, :merge_with =>
5
+ NoBrainer::Criteria::Pluck.method(:merge_missing_attributes) }
5
6
 
6
7
  def pluck(*attrs)
7
8
  _missing_attributes_criteria(:pluck, attrs)
@@ -16,24 +17,19 @@ module NoBrainer::Criteria::Pluck
16
17
  end
17
18
 
18
19
  def without_plucking
19
- chain { |criteria| criteria.missing_attributes = :remove }
20
+ chain(:missing_attributes => :remove)
20
21
  end
21
22
 
22
- def merge!(criteria, options={})
23
- return super unless criteria.missing_attributes
23
+ def self.merge_missing_attributes(a, b)
24
+ return nil if b.nil? || b == :remove
24
25
 
25
- if criteria.missing_attributes == :remove
26
- self.missing_attributes = nil
27
- else
28
- self.missing_attributes ||= {}
29
- criteria.missing_attributes.each do |type, attrs|
30
- old_attrs = self.missing_attributes[type] || {}.with_indifferent_access
31
- new_attrs = old_attrs.deep_merge(attrs)
32
- self.missing_attributes[type] = new_attrs
33
- end
26
+ a = a ? a.dup : {}
27
+ b.each do |type, attrs|
28
+ old_attrs = a[type] || {}.with_indifferent_access
29
+ new_attrs = old_attrs.deep_merge(attrs)
30
+ a[type] = new_attrs
34
31
  end
35
-
36
- self
32
+ a
37
33
  end
38
34
 
39
35
  private
@@ -41,16 +37,14 @@ module NoBrainer::Criteria::Pluck
41
37
  def _missing_attributes_criteria(type, args)
42
38
  raise ArgumentError if args.size.zero?
43
39
  args = [Hash[args.flatten.map { |k| [k, true] }]] unless args.size == 1 && args.first.is_a?(Hash)
44
- chain { |criteria| criteria.missing_attributes = {type => args.first} }
45
-
40
+ chain(:missing_attributes => {type => args.first})
46
41
  end
47
42
 
48
43
  def effective_missing_attributes
49
- return nil if self.missing_attributes.nil?
44
+ return nil if @options[:missing_attributes].nil?
50
45
  @effective_missing_attributes ||= begin
51
46
  # pluck gets priority
52
-
53
- missing_attributes = Hash[self.missing_attributes.map do |type, attrs|
47
+ missing_attributes = Hash[@options[:missing_attributes].map do |type, attrs|
54
48
  attrs = attrs.select { |k,v| v } # TODO recursive
55
49
  attrs.empty? ? nil : [type, attrs]
56
50
  end.compact]
@@ -65,16 +59,16 @@ module NoBrainer::Criteria::Pluck
65
59
  end
66
60
 
67
61
  def _instantiate_model(attrs, options={})
68
- return super if missing_attributes.nil?
62
+ return super if @options[:missing_attributes].nil?
69
63
  super(attrs, options.merge(:missing_attributes => effective_missing_attributes,
70
- :lazy_fetch => missing_attributes[:lazy_fetch]))
64
+ :lazy_fetch => @options[:missing_attributes][:lazy_fetch]))
71
65
  end
72
66
 
73
67
  def compile_rql_pass2
74
68
  rql = super
75
69
  if effective_missing_attributes
76
70
  type, attrs = effective_missing_attributes.first
77
- rql = rql.__send__(type, klass.with_fields_aliased(attrs))
71
+ rql = rql.__send__(type, model.with_fields_aliased(attrs))
78
72
  end
79
73
  rql
80
74
  end
@@ -1,24 +1,18 @@
1
1
  module NoBrainer::Criteria::Preload
2
2
  extend ActiveSupport::Concern
3
3
 
4
- included { attr_accessor :_preloads }
5
-
6
- def initialize(options={})
7
- super
8
- self._preloads = []
9
- end
4
+ included { criteria_option :preload, :merge_with => :append_array }
10
5
 
11
6
  def preload(*values)
12
- chain(:keep_cache => true) { |criteria| criteria._preloads = values }
7
+ chain({:preload => values}, :copy_cache_from => self)
13
8
  end
14
9
 
15
10
  def merge!(criteria, options={})
16
- super
17
- self._preloads = self._preloads + criteria._preloads
18
-
19
- # XXX Not pretty hack
20
- if criteria._preloads.present? && cached?
21
- perform_preloads(@cache)
11
+ super.tap do
12
+ # XXX Not pretty hack
13
+ if criteria.options[:preload].present? && criteria.cached?
14
+ perform_preloads(@cache)
15
+ end
22
16
  end
23
17
  end
24
18
 
@@ -35,7 +29,7 @@ module NoBrainer::Criteria::Preload
35
29
  private
36
30
 
37
31
  def should_preloads?
38
- self._preloads.present? && !raw?
32
+ @options[:preload].present? && !raw?
39
33
  end
40
34
 
41
35
  def get_one(criteria)
@@ -44,7 +38,7 @@ module NoBrainer::Criteria::Preload
44
38
 
45
39
  def perform_preloads(docs)
46
40
  if should_preloads? && docs.present?
47
- NoBrainer::Document::Association::EagerLoader.new.eager_load(docs, self._preloads)
41
+ NoBrainer::Document::Association::EagerLoader.new.eager_load(docs, @options[:preload])
48
42
  end
49
43
  end
50
44
  end
@@ -1,20 +1,14 @@
1
1
  module NoBrainer::Criteria::Raw
2
2
  extend ActiveSupport::Concern
3
3
 
4
- included { attr_accessor :_raw }
4
+ included { criteria_option :raw, :merge_with => :set_scalar }
5
5
 
6
- def raw
7
- chain { |criteria| criteria._raw = true }
8
- end
9
-
10
- def merge!(criteria, options={})
11
- super
12
- self._raw = criteria._raw unless criteria._raw.nil?
13
- self
6
+ def raw(value = true)
7
+ chain(:raw => value)
14
8
  end
15
9
 
16
10
  def raw?
17
- !!finalized_criteria._raw
11
+ !!finalized_criteria.options[:raw]
18
12
  end
19
13
 
20
14
  private
@@ -28,6 +22,6 @@ module NoBrainer::Criteria::Raw
28
22
  end
29
23
 
30
24
  def _instantiate_model(attrs, options={})
31
- klass.new_from_db(attrs, options)
25
+ model.new_from_db(attrs, options)
32
26
  end
33
27
  end
@@ -1,29 +1,23 @@
1
1
  module NoBrainer::Criteria::Scope
2
2
  extend ActiveSupport::Concern
3
3
 
4
- included { attr_accessor :use_default_scope }
4
+ included { criteria_option :use_default_scope, :merge_with => :set_scalar }
5
5
 
6
6
  def scoped
7
- chain { |criteria| criteria.use_default_scope = true }
7
+ chain(:use_default_scope => true)
8
8
  end
9
9
 
10
10
  def unscoped
11
- chain { |criteria| criteria.use_default_scope = false }
12
- end
13
-
14
- def merge!(criteria, options={})
15
- super
16
- self.use_default_scope = criteria.use_default_scope unless criteria.use_default_scope.nil?
17
- self
11
+ chain(:use_default_scope => false)
18
12
  end
19
13
 
20
14
  def respond_to?(name, include_private = false)
21
- super || self.klass.respond_to?(name)
15
+ super || self.model.respond_to?(name)
22
16
  end
23
17
 
24
18
  def method_missing(name, *args, &block)
25
- return super unless self.klass.respond_to?(name)
26
- criteria = self.klass.method(name).call(*args, &block)
19
+ return super unless self.model.respond_to?(name)
20
+ criteria = self.model.method(name).call(*args, &block)
27
21
  raise "#{name} did not return a criteria" unless criteria.is_a?(NoBrainer::Criteria)
28
22
  merge(criteria)
29
23
  end
@@ -31,13 +25,13 @@ module NoBrainer::Criteria::Scope
31
25
  private
32
26
 
33
27
  def should_apply_default_scope?
34
- klass.default_scope_proc && use_default_scope != false
28
+ model.default_scope_proc && @options[:use_default_scope] != false
35
29
  end
36
30
 
37
31
  def _apply_default_scope
38
32
  return unless should_apply_default_scope?
39
- criteria = klass.default_scope_proc.call
40
- raise "Mixing model issue. Contact developer." if [criteria.klass, self.klass].compact.uniq.size == 2
33
+ criteria = model.default_scope_proc.call
34
+ raise "Mixing model issue. Contact developer." if [criteria.model, self.model].compact.uniq.size == 2
41
35
  criteria.merge(self)
42
36
  end
43
37
 
@@ -3,17 +3,17 @@ module NoBrainer::Criteria::Update
3
3
 
4
4
  def update_all(*a, &b)
5
5
  prepare_args_for_update!(a)
6
- run(without_ordering.without_plucking.to_rql.update(*a, &b))
6
+ run { without_ordering.without_plucking.to_rql.update(*a, &b) }
7
7
  end
8
8
 
9
9
  def replace_all(*a, &b)
10
10
  prepare_args_for_update!(a)
11
- run(without_ordering.without_plucking.to_rql.replace(*a, &b))
11
+ run { without_ordering.without_plucking.to_rql.replace(*a, &b) }
12
12
  end
13
13
 
14
14
  private
15
15
 
16
16
  def prepare_args_for_update!(a)
17
- a[0] = klass.persistable_attributes(a[0]) if !a.empty? && a.first.is_a?(Hash)
17
+ a[0] = model.persistable_attributes(a[0]) if !a.empty? && a.first.is_a?(Hash)
18
18
  end
19
19
  end
@@ -1,35 +1,20 @@
1
1
  module NoBrainer::Criteria::Where
2
2
  extend ActiveSupport::Concern
3
3
 
4
- included { attr_accessor :where_ast, :with_index_name }
5
-
6
- def initialize(options={})
7
- super
4
+ included do
5
+ criteria_option :where_ast, :merge_with => NoBrainer::Criteria::Where.method(:merge_where_ast)
8
6
  end
9
7
 
10
8
  def where(*args, &block)
11
- chain { |criteria| criteria.where_ast = parse_clause([*args, block].compact) }
9
+ chain(:where_ast => parse_clause([*args, block].compact))
12
10
  end
13
11
 
14
- def merge!(criteria, options={})
15
- super
16
-
17
- if criteria.where_ast
18
- if self.where_ast
19
- self.where_ast = MultiOperator.new(:and, [self.where_ast, criteria.where_ast])
20
- else
21
- self.where_ast = criteria.where_ast
22
- end
23
- self.where_ast = self.where_ast.simplify
24
- raise unless criteria.where_ast.is_a?(MultiOperator)
25
- end
26
-
27
- self.with_index_name = criteria.with_index_name unless criteria.with_index_name.nil?
28
- self
12
+ def self.merge_where_ast(a, b)
13
+ (a ? MultiOperator.new(:and, [a, b]) : b).simplify
29
14
  end
30
15
 
31
16
  def where_present?
32
- finalized_criteria.where_ast.try(:clauses).present?
17
+ finalized_criteria.options[:where_ast].try(:clauses).present?
33
18
  end
34
19
 
35
20
  def where_indexed?
@@ -134,9 +119,9 @@ module NoBrainer::Criteria::Where
134
119
 
135
120
  case association
136
121
  when NoBrainer::Document::Association::BelongsTo::Metadata
137
- target_klass = association.target_klass
138
- opts = { :attr_name => key, :value => value, :type => target_klass}
139
- raise NoBrainer::Error::InvalidType.new(opts) unless value.is_a?(target_klass)
122
+ target_model = association.target_model
123
+ opts = { :attr_name => key, :value => value, :type => target_model}
124
+ raise NoBrainer::Error::InvalidType.new(opts) unless value.is_a?(target_model)
140
125
  value.pk_value
141
126
  else
142
127
  model.cast_user_to_db_for(key, value)
@@ -200,7 +185,7 @@ module NoBrainer::Criteria::Where
200
185
  when :nin then parse_clause(:not => { key.symbol.in => value })
201
186
  when :ne then parse_clause(:not => { key.symbol.eq => value })
202
187
  when :eq then parse_clause_stub_eq(key.symbol, value)
203
- else BinaryOperator.new(key.symbol, key.modifier, value, self.klass)
188
+ else BinaryOperator.new(key.symbol, key.modifier, value, self.model)
204
189
  end
205
190
  else raise "Invalid key: #{key}"
206
191
  end
@@ -208,9 +193,9 @@ module NoBrainer::Criteria::Where
208
193
 
209
194
  def parse_clause_stub_eq(key, value)
210
195
  case value
211
- when Range then BinaryOperator.new(key, :between, value, self.klass)
212
- when Regexp then BinaryOperator.new(key, :match, value.inspect[1..-2], self.klass)
213
- else BinaryOperator.new(key, :eq, value, self.klass)
196
+ when Range then BinaryOperator.new(key, :between, value, self.model)
197
+ when Regexp then BinaryOperator.new(key, :match, value.inspect[1..-2], self.model)
198
+ else BinaryOperator.new(key, :eq, value, self.model)
214
199
  end
215
200
  end
216
201
 
@@ -230,10 +215,10 @@ module NoBrainer::Criteria::Where
230
215
  def get_usable_indexes(*types)
231
216
  @usable_indexes = {}
232
217
  @usable_indexes[types] ||= begin
233
- indexes = criteria.klass.indexes
234
- indexes = indexes.select { |k,v| types.include?(v[:kind]) } if types.present?
235
- if criteria.with_index_name && criteria.with_index_name != true
236
- indexes = indexes.select { |k,v| k == criteria.with_index_name.to_sym }
218
+ indexes = criteria.model.indexes.values
219
+ indexes = indexes.select { |i| types.include?(i.kind) } if types.present?
220
+ if criteria.options[:use_index] && criteria.options[:use_index] != true
221
+ indexes = indexes.select { |i| i.name == criteria.options[:use_index].to_sym }
237
222
  end
238
223
  indexes
239
224
  end
@@ -248,16 +233,15 @@ module NoBrainer::Criteria::Where
248
233
  clauses = Hash[get_candidate_clauses(:eq, :in, :between).map { |c| [c.key, c] }]
249
234
  return unless clauses.present?
250
235
 
251
- if index_name = (get_usable_indexes.keys & clauses.keys).first
252
- clause = clauses[index_name]
253
- aliased_index = criteria.klass.indexes[index_name][:as]
254
- self.index_name = index_name
236
+ if index = get_usable_indexes.select { |i| clauses[i.name] }.first
237
+ clause = clauses[index.name]
238
+ self.index_name = index.name
255
239
  self.ast = remove_from_ast([clause])
256
240
  self.index_type = clause.op == :between ? :between : :get_all
257
241
  self.rql_proc = case clause.op
258
- when :eq then ->(rql){ rql.get_all(clause.value, :index => aliased_index) }
259
- when :in then ->(rql){ rql.get_all(*clause.value, :index => aliased_index) }
260
- when :between then ->(rql){ rql.between(clause.value.min, clause.value.max, :index => aliased_index,
242
+ when :eq then ->(rql){ rql.get_all(clause.value, :index => index.aliased_name) }
243
+ when :in then ->(rql){ rql.get_all(*clause.value, :index => index.aliased_name) }
244
+ when :between then ->(rql){ rql.between(clause.value.min, clause.value.max, :index => index.aliased_name,
261
245
  :left_bound => :closed, :right_bound => :closed) }
262
246
  end
263
247
  end
@@ -267,18 +251,12 @@ module NoBrainer::Criteria::Where
267
251
  clauses = Hash[get_candidate_clauses(:eq).map { |c| [c.key, c] }]
268
252
  return unless clauses.present?
269
253
 
270
- index_name, index_values = get_usable_indexes(:compound)
271
- .map { |name, option| [name, option[:what]] }
272
- .select { |name, values| values & clauses.keys == values }
273
- .first
274
-
275
- if index_name
276
- indexed_clauses = index_values.map { |field| clauses[field] }
277
- aliased_index = criteria.klass.indexes[index_name][:as]
278
- self.index_name = index_name
254
+ if index = get_usable_indexes(:compound).select { |i| i.what & clauses.keys == i.what }.first
255
+ indexed_clauses = index.what.map { |field| clauses[field] }
256
+ self.index_name = index.name
279
257
  self.ast = remove_from_ast(indexed_clauses)
280
258
  self.index_type = :get_all
281
- self.rql_proc = ->(rql){ rql.get_all(indexed_clauses.map { |c| c.value }, :index => aliased_index) }
259
+ self.rql_proc = ->(rql){ rql.get_all(indexed_clauses.map { |c| c.value }, :index => index.aliased_name) }
282
260
  end
283
261
  end
284
262
 
@@ -286,17 +264,16 @@ module NoBrainer::Criteria::Where
286
264
  clauses = get_candidate_clauses(:gt, :ge, :lt, :le).group_by(&:key)
287
265
  return unless clauses.present?
288
266
 
289
- if index_name = (get_usable_indexes.keys & clauses.keys).first
290
- op_clauses = Hash[clauses[index_name].map { |c| [c.op, c] }]
267
+ if index = get_usable_indexes.select { |i| clauses[i.name] }.first
268
+ op_clauses = Hash[clauses[index.name].map { |c| [c.op, c] }]
291
269
  left_bound = op_clauses[:gt] || op_clauses[:ge]
292
270
  right_bound = op_clauses[:lt] || op_clauses[:le]
293
271
 
294
- aliased_index = criteria.klass.indexes[index_name][:as]
295
- self.index_name = index_name
272
+ self.index_name = index.name
296
273
  self.ast = remove_from_ast([left_bound, right_bound].compact)
297
274
 
298
275
  options = {}
299
- options[:index] = aliased_index
276
+ options[:index] = index.aliased_name
300
277
  options[:left_bound] = {:gt => :open, :ge => :closed}[left_bound.op] if left_bound
301
278
  options[:right_bound] = {:lt => :open, :le => :closed}[right_bound.op] if right_bound
302
279
  self.index_type = :between
@@ -335,7 +312,7 @@ module NoBrainer::Criteria::Where
335
312
 
336
313
  def where_index_finder
337
314
  return finalized_criteria.__send__(:where_index_finder) unless finalized?
338
- @where_index_finder ||= IndexFinder.new(self, where_ast).tap { |index_finder| index_finder.find_index }
315
+ @where_index_finder ||= IndexFinder.new(self, @options[:where_ast]).tap { |index_finder| index_finder.find_index }
339
316
  end
340
317
 
341
318
  def compile_rql_pass1
@@ -346,7 +323,7 @@ module NoBrainer::Criteria::Where
346
323
 
347
324
  def compile_rql_pass2
348
325
  rql = super
349
- ast = where_index_finder.could_find_index? ? where_index_finder.ast : self.where_ast
326
+ ast = where_index_finder.could_find_index? ? where_index_finder.ast : @options[:where_ast]
350
327
  rql = rql.filter { |doc| ast.to_rql(doc) } if ast.try(:clauses).present?
351
328
  rql
352
329
  end
@@ -4,5 +4,5 @@ class NoBrainer::Criteria
4
4
  extend NoBrainer::Autoload
5
5
  autoload_and_include :Core, :Raw, :AfterFind, :Where, :OrderBy, :Limit,
6
6
  :Pluck, :Count, :Delete, :Enumerable, :First, :Aggregate,
7
- :Preload, :Update, :Cache, :Index, :Scope
7
+ :Preload, :Update, :Cache, :Index, :Extend, :Scope
8
8
  end
@@ -48,7 +48,7 @@ module NoBrainer::Document::Aliases
48
48
  end
49
49
  end
50
50
 
51
- def persistable_key(k)
51
+ def persistable_key(k, options={})
52
52
  lookup_field_alias(super)
53
53
  end
54
54
  end
@@ -13,10 +13,10 @@ class NoBrainer::Document::Association::BelongsTo
13
13
 
14
14
  def primary_key
15
15
  # TODO test :primary_key
16
- options[:primary_key].try(:to_sym) || target_klass.pk_name
16
+ options[:primary_key].try(:to_sym) || target_model.pk_name
17
17
  end
18
18
 
19
- def target_klass
19
+ def target_model
20
20
  # TODO test :class_name
21
21
  (options[:class_name] || target_name.to_s.camelize).constantize
22
22
  end
@@ -29,9 +29,9 @@ class NoBrainer::Document::Association::BelongsTo
29
29
  # This would have the effect of loading all the models because they
30
30
  # are likely to be related to each other. So we don't know the type
31
31
  # of the primary key of the target.
32
- owner_klass.field(foreign_key, :as => options[:foreign_key_as], :index => options[:index])
33
- owner_klass.validates(target_name, { :presence => true }) if options[:required]
34
- owner_klass.validates(target_name, options[:validates]) if options[:validates]
32
+ owner_model.field(foreign_key, :as => options[:foreign_key_as], :index => options[:index])
33
+ owner_model.validates(target_name, { :presence => true }) if options[:required]
34
+ owner_model.validates(target_name, options[:validates]) if options[:validates]
35
35
 
36
36
  delegate("#{foreign_key}=", :assign_foreign_key, :call_super => true)
37
37
  add_callback_for(:after_validation)
@@ -54,7 +54,7 @@ class NoBrainer::Document::Association::BelongsTo
54
54
  return target if loaded?
55
55
 
56
56
  if fk = owner.read_attribute(foreign_key)
57
- preload(target_klass.unscoped.where(primary_key => fk).first)
57
+ preload(target_model.unscoped.where(primary_key => fk).first)
58
58
  end
59
59
  end
60
60
 
@@ -4,25 +4,25 @@ module NoBrainer::Document::Association::Core
4
4
  module Metadata
5
5
  extend ActiveSupport::Concern
6
6
 
7
- attr_accessor :owner_klass, :target_name, :options
7
+ attr_accessor :owner_model, :target_name, :options
8
8
 
9
- def initialize(owner_klass, target_name, options={})
10
- @owner_klass = owner_klass
9
+ def initialize(owner_model, target_name, options={})
10
+ @owner_model = owner_model
11
11
  @target_name = target_name
12
12
  @options = options
13
13
  end
14
14
 
15
- def association_klass
16
- @association_klass ||= self.class.name.deconstantize.constantize
15
+ def association_model
16
+ @association_model ||= self.class.name.deconstantize.constantize
17
17
  end
18
18
 
19
19
  def new(owner)
20
- association_klass.new(self, owner)
20
+ association_model.new(self, owner)
21
21
  end
22
22
 
23
23
  def delegate(method_name, target, options={})
24
24
  metadata = self
25
- owner_klass.inject_in_layer :associations do
25
+ owner_model.inject_in_layer :associations do
26
26
  define_method(method_name) do |*args, &block|
27
27
  super(*args, &block) if options[:call_super]
28
28
  associations[metadata].__send__(target, *args, &block)
@@ -40,7 +40,7 @@ module NoBrainer::Document::Association::Core
40
40
  instance_eval <<-RUBY, __FILE__, __LINE__+1
41
41
  if !@added_#{what}
42
42
  metadata = self
43
- owner_klass.#{what} { associations[metadata].#{what}_callback }
43
+ owner_model.#{what} { associations[metadata].#{what}_callback }
44
44
  @added_#{what} = true
45
45
  end
46
46
  RUBY
@@ -49,15 +49,15 @@ module NoBrainer::Document::Association::Core
49
49
 
50
50
  included { attr_accessor :metadata, :owner }
51
51
 
52
- delegate :primary_key, :foreign_key, :target_name, :target_klass, :to => :metadata
52
+ delegate :primary_key, :foreign_key, :target_name, :target_model, :to => :metadata
53
53
 
54
54
  def initialize(metadata, owner)
55
55
  @metadata, @owner = metadata, owner
56
56
  end
57
57
 
58
58
  def assert_target_type(value)
59
- unless value.is_a?(target_klass) || value.nil?
60
- options = { :attr_name => target_name, :value => value, :type => target_klass }
59
+ unless value.is_a?(target_model) || value.nil?
60
+ options = { :attr_name => target_name, :value => value, :type => target_model }
61
61
  raise NoBrainer::Error::InvalidType.new(options)
62
62
  end
63
63
  end