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.
- checksums.yaml +4 -4
- data/lib/no_brainer/autoload.rb +0 -5
- data/lib/no_brainer/config.rb +73 -39
- data/lib/no_brainer/connection.rb +2 -4
- data/lib/no_brainer/criteria/after_find.rb +3 -11
- data/lib/no_brainer/criteria/aggregate.rb +2 -2
- data/lib/no_brainer/criteria/cache.rb +15 -10
- data/lib/no_brainer/criteria/core.rb +46 -11
- data/lib/no_brainer/criteria/delete.rb +2 -2
- data/lib/no_brainer/criteria/eager_load.rb +51 -0
- data/lib/no_brainer/criteria/extend.rb +4 -16
- data/lib/no_brainer/criteria/find.rb +27 -0
- 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 +20 -36
- data/lib/no_brainer/criteria/pluck.rb +16 -22
- data/lib/no_brainer/criteria/raw.rb +4 -10
- data/lib/no_brainer/criteria/scope.rb +6 -19
- data/lib/no_brainer/criteria/update.rb +8 -6
- data/lib/no_brainer/criteria/where.rb +252 -138
- data/lib/no_brainer/criteria.rb +3 -2
- data/lib/no_brainer/document/aliases.rb +3 -3
- data/lib/no_brainer/document/association/belongs_to.rb +9 -5
- data/lib/no_brainer/document/association/core.rb +6 -5
- data/lib/no_brainer/document/association/eager_loader.rb +9 -9
- data/lib/no_brainer/document/association/has_many.rb +23 -9
- data/lib/no_brainer/document/association/has_many_through.rb +12 -3
- data/lib/no_brainer/document/atomic_ops.rb +79 -78
- data/lib/no_brainer/document/attributes.rb +24 -20
- data/lib/no_brainer/document/callbacks.rb +1 -1
- data/lib/no_brainer/document/core.rb +5 -2
- data/lib/no_brainer/document/criteria.rb +14 -19
- data/lib/no_brainer/document/dirty.rb +11 -16
- data/lib/no_brainer/document/index/index.rb +2 -1
- data/lib/no_brainer/document/index/meta_store.rb +1 -1
- data/lib/no_brainer/document/index.rb +14 -10
- data/lib/no_brainer/document/persistance.rb +24 -13
- data/lib/no_brainer/document/primary_key/generator.rb +83 -0
- data/lib/no_brainer/document/{id.rb → primary_key.rb} +9 -36
- data/lib/no_brainer/document/store_in.rb +2 -2
- data/lib/no_brainer/document/timestamps.rb +4 -2
- data/lib/no_brainer/document/types/binary.rb +2 -7
- data/lib/no_brainer/document/types/boolean.rb +2 -4
- data/lib/no_brainer/document/types/date.rb +2 -2
- data/lib/no_brainer/document/types/float.rb +2 -2
- data/lib/no_brainer/document/types/geo.rb +1 -0
- data/lib/no_brainer/document/types/integer.rb +2 -2
- data/lib/no_brainer/document/types/set.rb +2 -2
- data/lib/no_brainer/document/types/string.rb +5 -2
- data/lib/no_brainer/document/types/symbol.rb +2 -2
- data/lib/no_brainer/document/types/text.rb +18 -0
- data/lib/no_brainer/document/types/time.rb +2 -2
- data/lib/no_brainer/document/types.rb +17 -18
- data/lib/no_brainer/document/validation/not_null.rb +15 -0
- data/lib/no_brainer/document/{uniqueness.rb → validation/uniqueness.rb} +11 -11
- data/lib/no_brainer/document/validation.rb +35 -6
- data/lib/no_brainer/document.rb +1 -1
- data/lib/no_brainer/error.rb +21 -19
- data/lib/no_brainer/geo/base.rb +16 -0
- data/lib/no_brainer/geo/circle.rb +25 -0
- data/lib/no_brainer/geo/line_string.rb +11 -0
- data/lib/no_brainer/geo/point.rb +49 -0
- data/lib/no_brainer/geo/polygon.rb +11 -0
- data/lib/no_brainer/geo.rb +4 -0
- data/lib/no_brainer/locale/en.yml +1 -0
- data/lib/no_brainer/lock.rb +114 -0
- data/lib/no_brainer/query_runner/connection_lock.rb +1 -1
- data/lib/no_brainer/query_runner/database_on_demand.rb +0 -1
- data/lib/no_brainer/query_runner/missing_index.rb +1 -1
- data/lib/no_brainer/query_runner/reconnect.rb +9 -11
- data/lib/no_brainer/query_runner/run_options.rb +0 -3
- data/lib/no_brainer/query_runner/table_on_demand.rb +3 -4
- data/lib/no_brainer/railtie/database.rake +2 -2
- data/lib/no_brainer/rql.rb +1 -5
- data/lib/nobrainer.rb +2 -6
- data/lib/rails/generators/nobrainer.rb +1 -1
- metadata +34 -9
- data/lib/no_brainer/criteria/preload.rb +0 -50
- 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: c53755e5f9ec902612c417fcf053404cf114ca0b
|
|
4
|
+
data.tar.gz: 529fe4b627d366ba4813fd6ff750192caf0df316
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 920d6b1c7bec9acd28b4a0e7f54a9967d068a01d31174396ca961eaf8cbfec31e3b8397ab2242ac87c73b9ca3789e80b47c8ca4b809d7a71b5fa80aeedb81f4b
|
|
7
|
+
data.tar.gz: 92144b91eb03ac14d2a01ea5244480b215286228691e5406a9f7bcf218499853ecfb0d1313f1380f62d509d97dc2bb1dac65ae8e97c0c2c3cc2b7b4c3835e1c2
|
data/lib/no_brainer/autoload.rb
CHANGED
|
@@ -17,9 +17,4 @@ module NoBrainer::Autoload
|
|
|
17
17
|
constants.each { |constant| autoload constant }
|
|
18
18
|
constants.each { |constant| include const_get(constant) }
|
|
19
19
|
end
|
|
20
|
-
|
|
21
|
-
def eager_autoload_and_include(*constants)
|
|
22
|
-
eager_autoload(*constants)
|
|
23
|
-
constants.each { |constant| include const_get(constant) }
|
|
24
|
-
end
|
|
25
20
|
end
|
data/lib/no_brainer/config.rb
CHANGED
|
@@ -1,46 +1,61 @@
|
|
|
1
1
|
require 'logger'
|
|
2
2
|
|
|
3
3
|
module NoBrainer::Config
|
|
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
|
+
:colorize_logger => { :default => ->{ true }, :valid_values => [true, false] },
|
|
10
|
+
:warn_on_active_record => { :default => ->{ true }, :valid_values => [true, false] },
|
|
11
|
+
:max_retries_on_connection_failure => { :default => ->{ default_max_retries_on_connection_failure } },
|
|
12
|
+
:durability => { :default => ->{ default_durability }, :valid_values => [:hard, :soft] },
|
|
13
|
+
:max_string_length => { :default => -> { 255 } },
|
|
14
|
+
:user_timezone => { :default => ->{ :local }, :valid_values => [:unchanged, :utc, :local] },
|
|
15
|
+
:db_timezone => { :default => ->{ :utc }, :valid_values => [:unchanged, :utc, :local] },
|
|
16
|
+
:geo_options => { :default => ->{ {:geo_system => 'WGS84', :unit => 'm'} } },
|
|
17
|
+
:distributed_lock_class => { :default => ->{ NoBrainer::Lock } },
|
|
18
|
+
:lock_options => { :default => ->{ { :expire => 60, :timeout => 10 } } },
|
|
19
|
+
:per_thread_connection => { :default => ->{ false }, :valid_values => [true, false] },
|
|
20
|
+
:machine_id => { :default => ->{ default_machine_id } },
|
|
21
|
+
:criteria_cache_max_entries => { :default => -> { 10_000 } },
|
|
22
|
+
}
|
|
23
|
+
|
|
4
24
|
class << self
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
25
|
+
attr_accessor(*SETTINGS.keys)
|
|
26
|
+
|
|
27
|
+
def auto_create_databases=(value)
|
|
28
|
+
STDERR.puts "[NoBrainer] config.auto_create_databases is no longer active."
|
|
29
|
+
STDERR.puts "[NoBrainer] The current behavior is now to always auto create databases"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def auto_create_tables=(value)
|
|
33
|
+
STDERR.puts "[NoBrainer] config.auto_create_tables is no longer active."
|
|
34
|
+
STDERR.puts "[NoBrainer] The current behavior is now to always auto create tables"
|
|
35
|
+
end
|
|
11
36
|
|
|
12
37
|
def apply_defaults
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
self.db_timezone = :utc
|
|
24
|
-
self.colorize_logger = true
|
|
25
|
-
self.distributed_lock_class = nil
|
|
26
|
-
self.per_thread_connection = false
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def max_reconnection_tries=(value)
|
|
30
|
-
STDERR.puts "[NoBrainer] config.max_reconnection_tries is deprecated and will be removed"
|
|
31
|
-
STDERR.puts "[NoBrainer] use config.max_retries_on_connection_failure instead."
|
|
32
|
-
self.max_retries_on_connection_failure = value
|
|
38
|
+
@applied_defaults_for = SETTINGS.keys.reject { |k| instance_variable_defined?("@#{k}") }
|
|
39
|
+
@applied_defaults_for.each { |k| __send__("#{k}=", SETTINGS[k][:default].call) }
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def geo_options=(value)
|
|
43
|
+
@geo_options = value.try(:symbolize_keys)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def assert_valid_options
|
|
47
|
+
SETTINGS.each { |k,v| assert_array_in(k, v[:valid_values]) if v[:valid_values] }
|
|
33
48
|
end
|
|
34
49
|
|
|
35
50
|
def reset!
|
|
36
|
-
|
|
37
|
-
apply_defaults
|
|
51
|
+
instance_variables.each { |ivar| remove_instance_variable(ivar) }
|
|
38
52
|
end
|
|
39
53
|
|
|
40
54
|
def configure(&block)
|
|
41
|
-
|
|
55
|
+
@applied_defaults_for.to_a.each { |k| remove_instance_variable("@#{k}") }
|
|
42
56
|
block.call(self) if block
|
|
43
|
-
|
|
57
|
+
apply_defaults
|
|
58
|
+
assert_valid_options
|
|
44
59
|
@configured = true
|
|
45
60
|
|
|
46
61
|
NoBrainer::ConnectionManager.disconnect_if_url_changed
|
|
@@ -50,20 +65,18 @@ module NoBrainer::Config
|
|
|
50
65
|
!!@configured
|
|
51
66
|
end
|
|
52
67
|
|
|
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
68
|
def assert_array_in(name, values)
|
|
60
69
|
unless __send__(name).in?(values)
|
|
61
70
|
raise ArgumentError.new("Unknown configuration for #{name}: #{__send__(name)}. Valid values are: #{values.inspect}")
|
|
62
71
|
end
|
|
63
72
|
end
|
|
64
73
|
|
|
74
|
+
def dev_mode?
|
|
75
|
+
self.environment.to_s.in? %w(development test)
|
|
76
|
+
end
|
|
77
|
+
|
|
65
78
|
def default_app_name
|
|
66
|
-
defined?(Rails) ? Rails.application.class.parent_name.underscore : nil
|
|
79
|
+
defined?(Rails) ? Rails.application.class.parent_name.underscore.presence : nil rescue nil
|
|
67
80
|
end
|
|
68
81
|
|
|
69
82
|
def default_environment
|
|
@@ -94,8 +107,29 @@ module NoBrainer::Config
|
|
|
94
107
|
dev_mode? ? 1 : 15
|
|
95
108
|
end
|
|
96
109
|
|
|
97
|
-
def
|
|
98
|
-
|
|
110
|
+
def default_machine_id
|
|
111
|
+
require 'socket'
|
|
112
|
+
require 'digest/md5'
|
|
113
|
+
|
|
114
|
+
return ENV['MACHINE_ID'] if ENV['MACHINE_ID']
|
|
115
|
+
|
|
116
|
+
host = Socket.gethostname
|
|
117
|
+
if host.in? %w(127.0.0.1 localhost)
|
|
118
|
+
raise "Please configure NoBrainer::Config.machine_id due to lack of appropriate hostname (Socket.gethostname = #{host})"
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
Digest::MD5.digest(host).unpack("N")[0] & NoBrainer::Document::PrimaryKey::Generator::MACHINE_ID_MASK
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def machine_id=(machine_id)
|
|
125
|
+
machine_id = case machine_id
|
|
126
|
+
when Integer then machine_id
|
|
127
|
+
when /^[0-9]+$/ then machine_id.to_i
|
|
128
|
+
else raise "Invalid machine_id"
|
|
129
|
+
end
|
|
130
|
+
max_id = NoBrainer::Document::PrimaryKey::Generator::MACHINE_ID_MASK
|
|
131
|
+
raise "Invalid machine_id (must be between 0 and #{max_id})" unless machine_id.in?(0..max_id)
|
|
132
|
+
@machine_id = machine_id
|
|
99
133
|
end
|
|
100
134
|
end
|
|
101
135
|
end
|
|
@@ -50,13 +50,11 @@ 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
|
-
next if table_name
|
|
55
|
+
next if table_name == 'nobrainer_index_meta' # keeping because indexes are not going away
|
|
56
56
|
NoBrainer.run { |r| r.table(table_name).delete }
|
|
57
57
|
end
|
|
58
58
|
true
|
|
59
|
-
rescue RuntimeError => e
|
|
60
|
-
raise e unless e.message =~ /No entry with that name/
|
|
61
59
|
end
|
|
62
60
|
end
|
|
@@ -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
|
|
@@ -2,11 +2,11 @@ module NoBrainer::Criteria::Aggregate
|
|
|
2
2
|
extend ActiveSupport::Concern
|
|
3
3
|
|
|
4
4
|
def min(*a, &b)
|
|
5
|
-
|
|
5
|
+
order_by(a, &b).first
|
|
6
6
|
end
|
|
7
7
|
|
|
8
8
|
def max(*a, &b)
|
|
9
|
-
|
|
9
|
+
order_by(a, &b).last
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def sum(*a, &b)
|
|
@@ -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
|
|
@@ -37,15 +37,20 @@ module NoBrainer::Criteria::Cache
|
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
def each(options={}, &block)
|
|
40
|
-
return super unless with_cache? && !options[:no_cache] && block
|
|
40
|
+
return super unless with_cache? && !options[:no_cache] && block && !@cache_too_small
|
|
41
41
|
return @cache.each(&block) if @cache
|
|
42
42
|
|
|
43
43
|
cache = []
|
|
44
44
|
super(options.merge(:no_cache => true)) do |instance|
|
|
45
45
|
block.call(instance)
|
|
46
|
-
cache << instance
|
|
46
|
+
cache << instance unless @cache_too_small
|
|
47
|
+
|
|
48
|
+
if cache.size > NoBrainer::Config.criteria_cache_max_entries
|
|
49
|
+
cache = []
|
|
50
|
+
@cache_too_small = true
|
|
51
|
+
end
|
|
47
52
|
end
|
|
48
|
-
@cache = cache
|
|
53
|
+
@cache = cache unless @cache_too_small
|
|
49
54
|
self
|
|
50
55
|
end
|
|
51
56
|
|
|
@@ -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,12 +38,16 @@ 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
|
|
|
33
49
|
def merge(criteria, options={})
|
|
34
|
-
dup.
|
|
50
|
+
dup.merge!(criteria, options)
|
|
35
51
|
end
|
|
36
52
|
|
|
37
53
|
def ==(other)
|
|
@@ -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,29 @@ 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 append_array(a, b)
|
|
106
|
+
a ? a+b : b
|
|
72
107
|
end
|
|
73
108
|
end
|
|
74
109
|
end
|
|
@@ -2,10 +2,10 @@ module NoBrainer::Criteria::Delete
|
|
|
2
2
|
extend ActiveSupport::Concern
|
|
3
3
|
|
|
4
4
|
def delete_all
|
|
5
|
-
run { without_ordering.without_plucking.to_rql.delete }
|
|
5
|
+
run { without_distinct.without_ordering.without_plucking.to_rql.delete }
|
|
6
6
|
end
|
|
7
7
|
|
|
8
8
|
def destroy_all
|
|
9
|
-
to_a.each
|
|
9
|
+
to_a.each(&:destroy)
|
|
10
10
|
end
|
|
11
11
|
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
module NoBrainer::Criteria::EagerLoad
|
|
2
|
+
extend ActiveSupport::Concern
|
|
3
|
+
|
|
4
|
+
included { criteria_option :eager_load, :merge_with => :append_array }
|
|
5
|
+
|
|
6
|
+
def eager_load(*values)
|
|
7
|
+
chain({:eager_load => values}, :copy_cache_from => self)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def preload(*values)
|
|
11
|
+
STDERR.puts "[NoBrainer] `preload' is deprecated and will be removed, please use `eager_load' instead"
|
|
12
|
+
eager_load(*values)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def merge!(criteria, options={})
|
|
16
|
+
super.tap do
|
|
17
|
+
# If we already have some cached documents, and we need to so some eager
|
|
18
|
+
# loading, then we it now. It's easier than doing it lazily.
|
|
19
|
+
if self.cached? && criteria.options[:eager_load].present?
|
|
20
|
+
perform_eager_load(@cache)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def each(options={}, &block)
|
|
26
|
+
return super unless should_eager_load? && !options[:no_eager_loading] && block
|
|
27
|
+
|
|
28
|
+
docs = []
|
|
29
|
+
super(options.merge(:no_eager_loading => true)) { |doc| docs << doc }
|
|
30
|
+
# TODO batch the eager loading with NoBrainer::Config.criteria_cache_max_entries
|
|
31
|
+
perform_eager_load(docs)
|
|
32
|
+
docs.each(&block)
|
|
33
|
+
self
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def should_eager_load?
|
|
39
|
+
@options[:eager_load].present? && !raw?
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def get_one(criteria)
|
|
43
|
+
super.tap { |doc| perform_eager_load([doc]) }
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def perform_eager_load(docs)
|
|
47
|
+
if should_eager_load? && docs.present?
|
|
48
|
+
NoBrainer::Document::Association::EagerLoader.new.eager_load(docs, @options[:eager_load])
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
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
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module NoBrainer::Criteria::Find
|
|
2
|
+
extend ActiveSupport::Concern
|
|
3
|
+
|
|
4
|
+
def find_by?(*args, &block)
|
|
5
|
+
where(*args, &block).first
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def find_by(*args, &block)
|
|
9
|
+
find_by?(*args, &block).tap { |doc| raise_not_found(args) unless doc }
|
|
10
|
+
end
|
|
11
|
+
alias_method :find_by!, :find_by
|
|
12
|
+
|
|
13
|
+
def find?(pk)
|
|
14
|
+
without_ordering.find_by?(model.pk_name => pk)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def find(pk)
|
|
18
|
+
without_ordering.find_by(model.pk_name => pk)
|
|
19
|
+
end
|
|
20
|
+
alias_method :find!, :find
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def raise_not_found(args)
|
|
25
|
+
raise NoBrainer::Error::DocumentNotFound, "#{model} #{args.inspect.gsub(/\[{(.*)}\]/, '\1')} not found"
|
|
26
|
+
end
|
|
27
|
+
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
|