nobrainer 0.18.0 → 0.22.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 (79) hide show
  1. checksums.yaml +4 -4
  2. data/lib/no_brainer/autoload.rb +0 -5
  3. data/lib/no_brainer/config.rb +73 -39
  4. data/lib/no_brainer/connection.rb +2 -4
  5. data/lib/no_brainer/criteria/after_find.rb +3 -11
  6. data/lib/no_brainer/criteria/aggregate.rb +2 -2
  7. data/lib/no_brainer/criteria/cache.rb +15 -10
  8. data/lib/no_brainer/criteria/core.rb +46 -11
  9. data/lib/no_brainer/criteria/delete.rb +2 -2
  10. data/lib/no_brainer/criteria/eager_load.rb +51 -0
  11. data/lib/no_brainer/criteria/extend.rb +4 -16
  12. data/lib/no_brainer/criteria/find.rb +27 -0
  13. data/lib/no_brainer/criteria/index.rb +7 -13
  14. data/lib/no_brainer/criteria/limit.rb +5 -12
  15. data/lib/no_brainer/criteria/order_by.rb +20 -36
  16. data/lib/no_brainer/criteria/pluck.rb +16 -22
  17. data/lib/no_brainer/criteria/raw.rb +4 -10
  18. data/lib/no_brainer/criteria/scope.rb +6 -19
  19. data/lib/no_brainer/criteria/update.rb +8 -6
  20. data/lib/no_brainer/criteria/where.rb +252 -138
  21. data/lib/no_brainer/criteria.rb +3 -2
  22. data/lib/no_brainer/document/aliases.rb +3 -3
  23. data/lib/no_brainer/document/association/belongs_to.rb +9 -5
  24. data/lib/no_brainer/document/association/core.rb +6 -5
  25. data/lib/no_brainer/document/association/eager_loader.rb +9 -9
  26. data/lib/no_brainer/document/association/has_many.rb +23 -9
  27. data/lib/no_brainer/document/association/has_many_through.rb +12 -3
  28. data/lib/no_brainer/document/atomic_ops.rb +79 -78
  29. data/lib/no_brainer/document/attributes.rb +24 -20
  30. data/lib/no_brainer/document/callbacks.rb +1 -1
  31. data/lib/no_brainer/document/core.rb +5 -2
  32. data/lib/no_brainer/document/criteria.rb +14 -19
  33. data/lib/no_brainer/document/dirty.rb +11 -16
  34. data/lib/no_brainer/document/index/index.rb +2 -1
  35. data/lib/no_brainer/document/index/meta_store.rb +1 -1
  36. data/lib/no_brainer/document/index.rb +14 -10
  37. data/lib/no_brainer/document/persistance.rb +24 -13
  38. data/lib/no_brainer/document/primary_key/generator.rb +83 -0
  39. data/lib/no_brainer/document/{id.rb → primary_key.rb} +9 -36
  40. data/lib/no_brainer/document/store_in.rb +2 -2
  41. data/lib/no_brainer/document/timestamps.rb +4 -2
  42. data/lib/no_brainer/document/types/binary.rb +2 -7
  43. data/lib/no_brainer/document/types/boolean.rb +2 -4
  44. data/lib/no_brainer/document/types/date.rb +2 -2
  45. data/lib/no_brainer/document/types/float.rb +2 -2
  46. data/lib/no_brainer/document/types/geo.rb +1 -0
  47. data/lib/no_brainer/document/types/integer.rb +2 -2
  48. data/lib/no_brainer/document/types/set.rb +2 -2
  49. data/lib/no_brainer/document/types/string.rb +5 -2
  50. data/lib/no_brainer/document/types/symbol.rb +2 -2
  51. data/lib/no_brainer/document/types/text.rb +18 -0
  52. data/lib/no_brainer/document/types/time.rb +2 -2
  53. data/lib/no_brainer/document/types.rb +17 -18
  54. data/lib/no_brainer/document/validation/not_null.rb +15 -0
  55. data/lib/no_brainer/document/{uniqueness.rb → validation/uniqueness.rb} +11 -11
  56. data/lib/no_brainer/document/validation.rb +35 -6
  57. data/lib/no_brainer/document.rb +1 -1
  58. data/lib/no_brainer/error.rb +21 -19
  59. data/lib/no_brainer/geo/base.rb +16 -0
  60. data/lib/no_brainer/geo/circle.rb +25 -0
  61. data/lib/no_brainer/geo/line_string.rb +11 -0
  62. data/lib/no_brainer/geo/point.rb +49 -0
  63. data/lib/no_brainer/geo/polygon.rb +11 -0
  64. data/lib/no_brainer/geo.rb +4 -0
  65. data/lib/no_brainer/locale/en.yml +1 -0
  66. data/lib/no_brainer/lock.rb +114 -0
  67. data/lib/no_brainer/query_runner/connection_lock.rb +1 -1
  68. data/lib/no_brainer/query_runner/database_on_demand.rb +0 -1
  69. data/lib/no_brainer/query_runner/missing_index.rb +1 -1
  70. data/lib/no_brainer/query_runner/reconnect.rb +9 -11
  71. data/lib/no_brainer/query_runner/run_options.rb +0 -3
  72. data/lib/no_brainer/query_runner/table_on_demand.rb +3 -4
  73. data/lib/no_brainer/railtie/database.rake +2 -2
  74. data/lib/no_brainer/rql.rb +1 -5
  75. data/lib/nobrainer.rb +2 -6
  76. data/lib/rails/generators/nobrainer.rb +1 -1
  77. metadata +34 -9
  78. data/lib/no_brainer/criteria/preload.rb +0 -50
  79. data/lib/no_brainer/decorated_symbol.rb +0 -17
@@ -1,12 +1,8 @@
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)
@@ -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 || (model ? {model.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,17 @@ 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.model.has_index?(first_key)
68
+ return false unless first_key.is_a?(Symbol) || first_key.is_a?(String)
69
+ return false unless index = criteria.model.indexes[first_key.to_sym]
70
+ return !index.multi && !index.geo
87
71
  end
88
72
 
89
73
  def find_index
90
74
  return if criteria.without_index?
91
75
  return unless first_key_indexable?
92
76
 
93
- if criteria.with_index_name && criteria.with_index_name != true
94
- return unless first_key.to_s == criteria.with_index_name.to_s
77
+ if criteria.options[:use_index] && criteria.options[:use_index] != true
78
+ return unless first_key.to_s == criteria.options[:use_index].to_s
95
79
  end
96
80
 
97
81
  # We need make sure that the where index finder has been invoked, it has priority.
@@ -105,7 +89,7 @@ module NoBrainer::Criteria::OrderBy
105
89
 
106
90
  def order_by_index_finder
107
91
  return finalized_criteria.__send__(:order_by_index_finder) unless finalized?
108
- @order_by_index_finder ||= IndexFinder.new(self).tap { |index_finder| index_finder.find_index }
92
+ @order_by_index_finder ||= IndexFinder.new(self).tap(&:find_index)
109
93
  end
110
94
 
111
95
  def compile_rql_pass1
@@ -150,6 +134,6 @@ module NoBrainer::Criteria::OrderBy
150
134
  end
151
135
 
152
136
  def raise_bad_rule(rule)
153
- raise "Please pass something like ':field1 => :desc, :field2 => :asc', not #{rule}"
137
+ raise "order_by() takes arguments such as `:field1 => :desc, :field2 => :asc', not `#{rule}'"
154
138
  end
155
139
  end
@@ -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,9 +59,9 @@ 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
@@ -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
@@ -1,20 +1,14 @@
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)
@@ -30,21 +24,14 @@ module NoBrainer::Criteria::Scope
30
24
 
31
25
  private
32
26
 
33
- def should_apply_default_scope?
34
- model.default_scope_proc && use_default_scope != false
35
- end
36
-
37
27
  def _apply_default_scope
38
- return unless should_apply_default_scope?
39
- criteria = model.default_scope_proc.call
40
- raise "Mixing model issue. Contact developer." if [criteria.model, self.model].compact.uniq.size == 2
41
- criteria.merge(self)
28
+ return self if @options[:use_default_scope] == false
29
+ (model.default_scopes.map(&:call).compact + [self]).reduce(:merge)
42
30
  end
43
31
 
44
32
  module ClassMethods
45
33
  def _finalize_criteria(base)
46
- criteria = super
47
- criteria.__send__(:_apply_default_scope) || criteria
34
+ super.__send__(:_apply_default_scope)
48
35
  end
49
36
  end
50
37
  end
@@ -2,18 +2,20 @@ module NoBrainer::Criteria::Update
2
2
  extend ActiveSupport::Concern
3
3
 
4
4
  def update_all(*a, &b)
5
- prepare_args_for_update!(a)
6
- run { without_ordering.without_plucking.to_rql.update(*a, &b) }
5
+ perform_update(:update, a, b)
7
6
  end
8
7
 
9
8
  def replace_all(*a, &b)
10
- prepare_args_for_update!(a)
11
- run { without_ordering.without_plucking.to_rql.replace(*a, &b) }
9
+ perform_update(:replace, a, b)
12
10
  end
13
11
 
14
12
  private
15
13
 
16
- def prepare_args_for_update!(a)
17
- a[0] = model.persistable_attributes(a[0]) if !a.empty? && a.first.is_a?(Hash)
14
+ def perform_update(type, args, block)
15
+ args[0] = model.persistable_attributes(args[0]) if !args.empty? && args.first.is_a?(Hash)
16
+ # can't use without_distinct when passed a block as the operation may be
17
+ # performed many times, which might not be idempotent.
18
+ clause = block ? self : without_distinct
19
+ run { clause.without_plucking.to_rql.__send__(type, *args, &block) }
18
20
  end
19
21
  end