nobrainer 0.18.0 → 0.19.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.
- checksums.yaml +4 -4
- data/lib/no_brainer/config.rb +35 -37
- data/lib/no_brainer/connection.rb +1 -1
- data/lib/no_brainer/criteria/after_find.rb +3 -11
- data/lib/no_brainer/criteria/cache.rb +7 -7
- data/lib/no_brainer/criteria/core.rb +49 -10
- data/lib/no_brainer/criteria/delete.rb +1 -1
- data/lib/no_brainer/criteria/extend.rb +4 -16
- data/lib/no_brainer/criteria/index.rb +7 -13
- data/lib/no_brainer/criteria/limit.rb +5 -12
- data/lib/no_brainer/criteria/order_by.rb +19 -35
- data/lib/no_brainer/criteria/pluck.rb +16 -22
- data/lib/no_brainer/criteria/preload.rb +9 -15
- data/lib/no_brainer/criteria/raw.rb +4 -10
- data/lib/no_brainer/criteria/scope.rb +4 -10
- data/lib/no_brainer/criteria/where.rb +172 -130
- data/lib/no_brainer/document/aliases.rb +10 -2
- data/lib/no_brainer/document/association/belongs_to.rb +3 -3
- data/lib/no_brainer/document/association/core.rb +1 -1
- data/lib/no_brainer/document/association/eager_loader.rb +4 -3
- data/lib/no_brainer/document/association/has_many.rb +2 -2
- data/lib/no_brainer/document/atomic_ops.rb +29 -30
- data/lib/no_brainer/document/attributes.rb +15 -19
- data/lib/no_brainer/document/callbacks.rb +1 -1
- data/lib/no_brainer/document/id.rb +7 -3
- data/lib/no_brainer/document/index.rb +20 -10
- data/lib/no_brainer/document/persistance.rb +11 -10
- data/lib/no_brainer/document/timestamps.rb +4 -2
- data/lib/no_brainer/document/types/binary.rb +0 -1
- data/lib/no_brainer/document/types/boolean.rb +0 -1
- data/lib/no_brainer/document/types.rb +0 -9
- data/lib/no_brainer/document/uniqueness.rb +0 -1
- data/lib/no_brainer/document/validation.rb +5 -5
- data/lib/no_brainer/error.rb +1 -0
- data/lib/no_brainer/query_runner/connection_lock.rb +1 -1
- data/lib/no_brainer/query_runner/reconnect.rb +9 -11
- data/lib/no_brainer/query_runner/table_on_demand.rb +1 -1
- data/lib/no_brainer/railtie/database.rake +2 -2
- data/lib/no_brainer/rql.rb +1 -1
- data/lib/nobrainer.rb +1 -6
- data/lib/rails/generators/nobrainer.rb +1 -1
- metadata +18 -5
- data/lib/no_brainer/decorated_symbol.rb +0 -17
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5dc33c00dc3aa418ae3bd36b0ccb2618a8c0e47f
|
|
4
|
+
data.tar.gz: 3a4c171e4c41341d14a3c4b6103b463be1b12701
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 70af56ece8a93103f310a729c338631e0bc56b52d4725ea2a304dfdb389e04fb530fda2b3d8039ec36e4f175ae9d510f3eb765fdf2d7a6f155ea37b822f0f464
|
|
7
|
+
data.tar.gz: 58371614f47e835c11b183fd2b004271b7c0031f27de8b17a9f8b0d3d2c4ee185a4e32efb5e495f5f6cf0b53fa9f64e4510150cfff3305d237431ec195733b13
|
data/lib/no_brainer/config.rb
CHANGED
|
@@ -1,30 +1,25 @@
|
|
|
1
1
|
require 'logger'
|
|
2
2
|
|
|
3
3
|
module NoBrainer::Config
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
4
|
+
SETTINGS = {
|
|
5
|
+
:app_name => { :default => ->{ default_app_name } },
|
|
6
|
+
:environment => { :default => ->{ default_environment } },
|
|
7
|
+
:rethinkdb_url => { :default => ->{ default_rethinkdb_url } },
|
|
8
|
+
:logger => { :default => ->{ default_logger } },
|
|
9
|
+
:warn_on_active_record => { :default => ->{ true }, :valid_values => [true, false] },
|
|
10
|
+
:auto_create_databases => { :default => ->{ true }, :valid_values => [true, false] },
|
|
11
|
+
:auto_create_tables => { :default => ->{ true }, :valid_values => [true, false] },
|
|
12
|
+
:max_retries_on_connection_failure => { :default => ->{ default_max_retries_on_connection_failure } },
|
|
13
|
+
:durability => { :default => ->{ default_durability }, :valid_values => [:hard, :soft] },
|
|
14
|
+
:user_timezone => { :default => ->{ :local }, :valid_values => [:unchanged, :utc, :local] },
|
|
15
|
+
:db_timezone => { :default => ->{ :utc }, :valid_values => [:unchanged, :utc, :local] },
|
|
16
|
+
:colorize_logger => { :default => ->{ true }, :valid_values => [true, false] },
|
|
17
|
+
:distributed_lock_class => { :default => ->{ nil } },
|
|
18
|
+
:per_thread_connection => { :default => ->{ false }, :valid_values => [true, false] },
|
|
19
|
+
}
|
|
11
20
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
self.environment = default_environment
|
|
15
|
-
self.rethinkdb_url = default_rethinkdb_url
|
|
16
|
-
self.logger = default_logger
|
|
17
|
-
self.warn_on_active_record = true
|
|
18
|
-
self.auto_create_databases = true
|
|
19
|
-
self.auto_create_tables = true
|
|
20
|
-
self.max_retries_on_connection_failure = default_max_retries_on_connection_failure
|
|
21
|
-
self.durability = default_durability
|
|
22
|
-
self.user_timezone = :local
|
|
23
|
-
self.db_timezone = :utc
|
|
24
|
-
self.colorize_logger = true
|
|
25
|
-
self.distributed_lock_class = nil
|
|
26
|
-
self.per_thread_connection = false
|
|
27
|
-
end
|
|
21
|
+
class << self
|
|
22
|
+
attr_accessor(*SETTINGS.keys)
|
|
28
23
|
|
|
29
24
|
def max_reconnection_tries=(value)
|
|
30
25
|
STDERR.puts "[NoBrainer] config.max_reconnection_tries is deprecated and will be removed"
|
|
@@ -32,14 +27,23 @@ module NoBrainer::Config
|
|
|
32
27
|
self.max_retries_on_connection_failure = value
|
|
33
28
|
end
|
|
34
29
|
|
|
30
|
+
def apply_defaults
|
|
31
|
+
@applied_defaults_for = SETTINGS.keys.reject { |k| instance_variable_defined?("@#{k}") }
|
|
32
|
+
@applied_defaults_for.each { |k| __send__("#{k}=", SETTINGS[k][:default].call) }
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def assert_valid_options!
|
|
36
|
+
SETTINGS.each { |k,v| assert_array_in(k, v[:valid_values]) if v[:valid_values] }
|
|
37
|
+
end
|
|
38
|
+
|
|
35
39
|
def reset!
|
|
36
|
-
|
|
37
|
-
apply_defaults
|
|
40
|
+
instance_variables.each { |ivar| remove_instance_variable(ivar) }
|
|
38
41
|
end
|
|
39
42
|
|
|
40
43
|
def configure(&block)
|
|
41
|
-
|
|
44
|
+
@applied_defaults_for.to_a.each { |k| remove_instance_variable("@#{k}") }
|
|
42
45
|
block.call(self) if block
|
|
46
|
+
apply_defaults
|
|
43
47
|
assert_valid_options!
|
|
44
48
|
@configured = true
|
|
45
49
|
|
|
@@ -50,20 +54,18 @@ module NoBrainer::Config
|
|
|
50
54
|
!!@configured
|
|
51
55
|
end
|
|
52
56
|
|
|
53
|
-
def assert_valid_options!
|
|
54
|
-
assert_array_in :durability, [:hard, :soft]
|
|
55
|
-
assert_array_in :user_timezone, [:unchanged, :utc, :local]
|
|
56
|
-
assert_array_in :db_timezone, [:unchanged, :utc, :local]
|
|
57
|
-
end
|
|
58
|
-
|
|
59
57
|
def assert_array_in(name, values)
|
|
60
58
|
unless __send__(name).in?(values)
|
|
61
59
|
raise ArgumentError.new("Unknown configuration for #{name}: #{__send__(name)}. Valid values are: #{values.inspect}")
|
|
62
60
|
end
|
|
63
61
|
end
|
|
64
62
|
|
|
63
|
+
def dev_mode?
|
|
64
|
+
self.environment.to_s.in? %w(development test)
|
|
65
|
+
end
|
|
66
|
+
|
|
65
67
|
def default_app_name
|
|
66
|
-
defined?(Rails) ? Rails.application.class.parent_name.underscore : nil
|
|
68
|
+
defined?(Rails) ? Rails.application.class.parent_name.underscore.presence : nil rescue nil
|
|
67
69
|
end
|
|
68
70
|
|
|
69
71
|
def default_environment
|
|
@@ -93,9 +95,5 @@ module NoBrainer::Config
|
|
|
93
95
|
def default_max_retries_on_connection_failure
|
|
94
96
|
dev_mode? ? 1 : 15
|
|
95
97
|
end
|
|
96
|
-
|
|
97
|
-
def dev_mode?
|
|
98
|
-
self.environment.to_sym.in?([:development, :test])
|
|
99
|
-
end
|
|
100
98
|
end
|
|
101
99
|
end
|
|
@@ -50,7 +50,7 @@ class NoBrainer::Connection
|
|
|
50
50
|
|
|
51
51
|
# Note that truncating each table (purge) is much faster than dropping the
|
|
52
52
|
# database (drop)
|
|
53
|
-
def purge!
|
|
53
|
+
def purge!
|
|
54
54
|
table_list.each do |table_name|
|
|
55
55
|
next if table_name =~ /^nobrainer_/
|
|
56
56
|
NoBrainer.run { |r| r.table(table_name).delete }
|
|
@@ -1,23 +1,15 @@
|
|
|
1
1
|
module NoBrainer::Criteria::AfterFind
|
|
2
2
|
extend ActiveSupport::Concern
|
|
3
3
|
|
|
4
|
-
included {
|
|
4
|
+
included { criteria_option :after_find, :merge_with => :append_array }
|
|
5
5
|
|
|
6
6
|
def after_find(b=nil, &block)
|
|
7
|
-
chain
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def merge!(criteria, options={})
|
|
11
|
-
super
|
|
12
|
-
if criteria._after_find.present?
|
|
13
|
-
self._after_find = (self._after_find || []) + criteria._after_find
|
|
14
|
-
end
|
|
15
|
-
self
|
|
7
|
+
chain(:after_find => [b, block].compact)
|
|
16
8
|
end
|
|
17
9
|
|
|
18
10
|
def _instantiate_doc(attrs)
|
|
19
11
|
super.tap do |doc|
|
|
20
|
-
|
|
12
|
+
@options[:after_find].to_a.each { |block| block.call(doc) }
|
|
21
13
|
doc.run_callbacks(:find) if doc.is_a?(NoBrainer::Document)
|
|
22
14
|
end
|
|
23
15
|
end
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
module NoBrainer::Criteria::Cache
|
|
2
2
|
extend ActiveSupport::Concern
|
|
3
3
|
|
|
4
|
-
included {
|
|
4
|
+
included { criteria_option :with_cache, :merge_with => :set_scalar }
|
|
5
5
|
|
|
6
6
|
def with_cache
|
|
7
|
-
chain
|
|
7
|
+
chain(:with_cache => true)
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
def without_cache
|
|
11
|
-
chain
|
|
11
|
+
chain(:with_cache => false)
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
def inspect
|
|
@@ -18,14 +18,14 @@ module NoBrainer::Criteria::Cache
|
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
def merge!(criteria, options={})
|
|
21
|
+
if options[:copy_cache_from] && options[:copy_cache_from].cached?
|
|
22
|
+
@cache = options[:copy_cache_from].instance_variable_get(:@cache)
|
|
23
|
+
end
|
|
21
24
|
super
|
|
22
|
-
self._with_cache = criteria._with_cache unless criteria._with_cache.nil?
|
|
23
|
-
self.reload unless options[:keep_cache]
|
|
24
|
-
self
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
def with_cache?
|
|
28
|
-
|
|
28
|
+
finalized_criteria.options[:with_cache] != false
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
def reload
|
|
@@ -1,14 +1,26 @@
|
|
|
1
1
|
module NoBrainer::Criteria::Core
|
|
2
2
|
extend ActiveSupport::Concern
|
|
3
3
|
|
|
4
|
-
included
|
|
4
|
+
included do
|
|
5
|
+
singleton_class.send(:attr_accessor, :options_definitions)
|
|
6
|
+
self.options_definitions = {}
|
|
7
|
+
attr_accessor :options
|
|
8
|
+
|
|
9
|
+
criteria_option :model, :merge_with => :set_scalar
|
|
10
|
+
criteria_option :finalized, :merge_with => :set_scalar
|
|
11
|
+
end
|
|
5
12
|
|
|
6
13
|
def initialize(options={})
|
|
7
|
-
|
|
14
|
+
@options = options
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def dup
|
|
18
|
+
# We don't keep any of the instance variables except options.
|
|
19
|
+
self.class.new(@options.dup)
|
|
8
20
|
end
|
|
9
21
|
|
|
10
22
|
def model
|
|
11
|
-
|
|
23
|
+
@options[:model]
|
|
12
24
|
end
|
|
13
25
|
|
|
14
26
|
def to_rql
|
|
@@ -26,7 +38,11 @@ module NoBrainer::Criteria::Core
|
|
|
26
38
|
end
|
|
27
39
|
|
|
28
40
|
def merge!(criteria, options={})
|
|
29
|
-
|
|
41
|
+
criteria.options.each do |k,v|
|
|
42
|
+
merge_proc = self.class.options_definitions[k]
|
|
43
|
+
raise "Non declared option: #{k}" unless merge_proc
|
|
44
|
+
@options[k] = merge_proc.call(@options[k], v)
|
|
45
|
+
end
|
|
30
46
|
self
|
|
31
47
|
end
|
|
32
48
|
|
|
@@ -41,10 +57,8 @@ module NoBrainer::Criteria::Core
|
|
|
41
57
|
|
|
42
58
|
private
|
|
43
59
|
|
|
44
|
-
def chain(options={},
|
|
45
|
-
|
|
46
|
-
block.call(tmp)
|
|
47
|
-
merge(tmp, options)
|
|
60
|
+
def chain(options={}, merge_options={})
|
|
61
|
+
merge(self.class.new(options), merge_options)
|
|
48
62
|
end
|
|
49
63
|
|
|
50
64
|
def compile_rql_pass1
|
|
@@ -59,7 +73,7 @@ module NoBrainer::Criteria::Core
|
|
|
59
73
|
end
|
|
60
74
|
|
|
61
75
|
def finalized?
|
|
62
|
-
|
|
76
|
+
!!@options[:finalized]
|
|
63
77
|
end
|
|
64
78
|
|
|
65
79
|
def finalized_criteria
|
|
@@ -67,8 +81,33 @@ module NoBrainer::Criteria::Core
|
|
|
67
81
|
end
|
|
68
82
|
|
|
69
83
|
module ClassMethods
|
|
84
|
+
def criteria_option(*names)
|
|
85
|
+
options = names.extract_options!
|
|
86
|
+
|
|
87
|
+
names.map(&:to_sym).each do |name|
|
|
88
|
+
merge_proc = options[:merge_with]
|
|
89
|
+
merge_proc = MergeStrategies.method(merge_proc) if merge_proc.is_a?(Symbol)
|
|
90
|
+
self.options_definitions[name] = merge_proc
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
70
94
|
def _finalize_criteria(base)
|
|
71
|
-
base.
|
|
95
|
+
base.__send__(:chain, :finalized => true)
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
module MergeStrategies
|
|
100
|
+
extend self
|
|
101
|
+
def set_scalar(a, b)
|
|
102
|
+
b
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def merge_hash(a, b)
|
|
106
|
+
a ? a.merge(b) : b
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def append_array(a, b)
|
|
110
|
+
a ? a+b : b
|
|
72
111
|
end
|
|
73
112
|
end
|
|
74
113
|
end
|
|
@@ -1,31 +1,19 @@
|
|
|
1
1
|
module NoBrainer::Criteria::Extend
|
|
2
2
|
extend ActiveSupport::Concern
|
|
3
3
|
|
|
4
|
-
included {
|
|
4
|
+
included { criteria_option :extend, :merge_with => :append_array }
|
|
5
5
|
|
|
6
6
|
def extend(*modules, &block)
|
|
7
7
|
options = modules.extract_options!
|
|
8
8
|
modules << Module.new(&block) if block
|
|
9
9
|
|
|
10
10
|
return super(*modules) if options[:original_behavior]
|
|
11
|
-
|
|
12
|
-
chain do |criteria|
|
|
13
|
-
criteria.extend_modules ||= []
|
|
14
|
-
criteria.extend_modules += [modules]
|
|
15
|
-
end
|
|
11
|
+
chain(:extend => [modules])
|
|
16
12
|
end
|
|
17
13
|
|
|
18
14
|
def merge!(criteria, options={})
|
|
19
|
-
super
|
|
20
|
-
|
|
21
|
-
if criteria.extend_modules.present?
|
|
22
|
-
self.extend_modules = self.extend_modules.to_a + criteria.extend_modules
|
|
15
|
+
super.tap do
|
|
16
|
+
@options[:extend].to_a.each { |modules| extend(*modules, :original_behavior => true) }
|
|
23
17
|
end
|
|
24
|
-
|
|
25
|
-
if self.extend_modules.present?
|
|
26
|
-
self.extend_modules.each { |modules| extend(*modules, :original_behavior => true) }
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
self
|
|
30
18
|
end
|
|
31
19
|
end
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
module NoBrainer::Criteria::Index
|
|
2
2
|
extend ActiveSupport::Concern
|
|
3
3
|
|
|
4
|
-
included {
|
|
4
|
+
included { criteria_option :use_index, :merge_with => :set_scalar }
|
|
5
5
|
|
|
6
6
|
def with_index(index_name=true)
|
|
7
|
-
chain
|
|
7
|
+
chain(:use_index => index_name)
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
def without_index
|
|
@@ -12,25 +12,19 @@ module NoBrainer::Criteria::Index
|
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
def without_index?
|
|
15
|
-
finalized_criteria.
|
|
15
|
+
finalized_criteria.options[:use_index] == false
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
def used_index
|
|
19
|
-
#
|
|
19
|
+
# Only one of them will be active.
|
|
20
20
|
where_index_name || order_by_index_name
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
-
def merge!(criteria, options={})
|
|
24
|
-
super
|
|
25
|
-
self.with_index_name = criteria.with_index_name unless criteria.with_index_name.nil?
|
|
26
|
-
self
|
|
27
|
-
end
|
|
28
|
-
|
|
29
23
|
def compile_rql_pass2
|
|
30
24
|
super.tap do
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
raise NoBrainer::Error::CannotUseIndex.new(
|
|
25
|
+
# The implicit ordering on the indexed pk does not count.
|
|
26
|
+
if @options[:use_index] && (!used_index || order_by_index_name.to_s == model.pk_name.to_s)
|
|
27
|
+
raise NoBrainer::Error::CannotUseIndex.new(@options[:use_index])
|
|
34
28
|
end
|
|
35
29
|
end
|
|
36
30
|
end
|
|
@@ -1,30 +1,23 @@
|
|
|
1
1
|
module NoBrainer::Criteria::Limit
|
|
2
2
|
extend ActiveSupport::Concern
|
|
3
3
|
|
|
4
|
-
included {
|
|
4
|
+
included { criteria_option :skip, :limit, :merge_with => :set_scalar }
|
|
5
5
|
|
|
6
6
|
def limit(value)
|
|
7
|
-
chain
|
|
7
|
+
chain(:limit => value)
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
def skip(value)
|
|
11
|
-
chain
|
|
11
|
+
chain(:skip => value)
|
|
12
12
|
end
|
|
13
13
|
alias_method :offset, :skip
|
|
14
14
|
|
|
15
|
-
def merge!(criteria, options={})
|
|
16
|
-
super
|
|
17
|
-
self._skip = criteria._skip if criteria._skip
|
|
18
|
-
self._limit = criteria._limit if criteria._limit
|
|
19
|
-
self
|
|
20
|
-
end
|
|
21
|
-
|
|
22
15
|
private
|
|
23
16
|
|
|
24
17
|
def compile_rql_pass2
|
|
25
18
|
rql = super
|
|
26
|
-
rql = rql.skip(
|
|
27
|
-
rql = rql.limit(
|
|
19
|
+
rql = rql.skip(@options[:skip]) if @options[:skip]
|
|
20
|
+
rql = rql.limit(@options[:limit]) if @options[:limit]
|
|
28
21
|
rql
|
|
29
22
|
end
|
|
30
23
|
end
|
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
module NoBrainer::Criteria::OrderBy
|
|
2
2
|
extend ActiveSupport::Concern
|
|
3
3
|
|
|
4
|
-
|
|
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
|
|
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
|
|
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
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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
|
-
|
|
47
|
+
@options[:order_by].presence || (model ? {model.pk_name => :asc} : {})
|
|
66
48
|
end
|
|
67
49
|
|
|
68
50
|
def reverse_order?
|
|
69
|
-
|
|
51
|
+
@options[:ordering_mode] == :reversed
|
|
70
52
|
end
|
|
71
53
|
|
|
72
54
|
def should_order?
|
|
73
|
-
|
|
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
|
-
|
|
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.
|
|
94
|
-
return unless first_key.to_s == criteria.
|
|
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
|
|
92
|
+
@order_by_index_finder ||= IndexFinder.new(self).tap(&:find_index)
|
|
109
93
|
end
|
|
110
94
|
|
|
111
95
|
def compile_rql_pass1
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
module NoBrainer::Criteria::Pluck
|
|
2
2
|
extend ActiveSupport::Concern
|
|
3
3
|
|
|
4
|
-
included {
|
|
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
|
|
20
|
+
chain(:missing_attributes => :remove)
|
|
20
21
|
end
|
|
21
22
|
|
|
22
|
-
def
|
|
23
|
-
return
|
|
23
|
+
def self.merge_missing_attributes(a, b)
|
|
24
|
+
return nil if b.nil? || b == :remove
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
|
45
|
-
|
|
40
|
+
chain(:missing_attributes => {type => args.first})
|
|
46
41
|
end
|
|
47
42
|
|
|
48
43
|
def effective_missing_attributes
|
|
49
|
-
return nil if
|
|
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,24 +1,18 @@
|
|
|
1
1
|
module NoBrainer::Criteria::Preload
|
|
2
2
|
extend ActiveSupport::Concern
|
|
3
3
|
|
|
4
|
-
included {
|
|
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(:
|
|
7
|
+
chain({:preload => values}, :copy_cache_from => self)
|
|
13
8
|
end
|
|
14
9
|
|
|
15
10
|
def merge!(criteria, options={})
|
|
16
|
-
super
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
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,
|
|
41
|
+
NoBrainer::Document::Association::EagerLoader.new.eager_load(docs, @options[:preload])
|
|
48
42
|
end
|
|
49
43
|
end
|
|
50
44
|
end
|