nobrainer 0.26.0 → 0.27.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 +1 -1
- data/lib/no_brainer/config.rb +18 -6
- data/lib/no_brainer/connection_manager.rb +1 -1
- data/lib/no_brainer/criteria/where.rb +0 -8
- data/lib/no_brainer/document/association.rb +5 -5
- data/lib/no_brainer/document/association/belongs_to.rb +17 -7
- data/lib/no_brainer/document/association/eager_loader.rb +0 -1
- data/lib/no_brainer/document/attributes.rb +8 -7
- data/lib/no_brainer/document/criteria.rb +2 -2
- data/lib/no_brainer/document/lazy_fetch.rb +3 -3
- data/lib/no_brainer/document/polymorphic.rb +3 -3
- data/lib/no_brainer/document/primary_key.rb +12 -3
- data/lib/no_brainer/document/primary_key/generator.rb +6 -1
- data/lib/no_brainer/document/serialization.rb +0 -2
- data/lib/no_brainer/document/timestamps.rb +4 -0
- data/lib/no_brainer/document/validation/uniqueness.rb +2 -1
- data/lib/no_brainer/query_runner/profiler.rb +2 -0
- data/lib/no_brainer/symbol_decoration.rb +11 -0
- data/lib/nobrainer.rb +4 -4
- data/lib/rails/generators/nobrainer/install_generator.rb +2 -2
- data/lib/rails/generators/templates/nobrainer.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cc50cb3ae605543bb7ed3df448d0ff32d3b984d4
|
4
|
+
data.tar.gz: b8ae438c48a0d64408f4966f92002be17f6cdff0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 118724ce72e1c29432aa208b062f9e107b56dc0401d921f5194708a2c3f2b7a95160572cf2cd83cb22f322cad0fb7cfe3939fdccf8eb6ef401da99f975df275b
|
7
|
+
data.tar.gz: 2d5737b1035583abd7f888f61341b0922d85e654b919aee2c282be2fcd07bb144f3654ef76ad2d016289b5692766d72d7d0e7620f8d13a6923d054acab49de91
|
data/lib/no_brainer/autoload.rb
CHANGED
data/lib/no_brainer/config.rb
CHANGED
@@ -14,7 +14,7 @@ module NoBrainer::Config
|
|
14
14
|
:user_timezone => { :default => ->{ :local }, :valid_values => [:unchanged, :utc, :local] },
|
15
15
|
:db_timezone => { :default => ->{ :utc }, :valid_values => [:unchanged, :utc, :local] },
|
16
16
|
:geo_options => { :default => ->{ {:geo_system => 'WGS84', :unit => 'm'} } },
|
17
|
-
:distributed_lock_class => { :default => ->{ NoBrainer::Lock } },
|
17
|
+
:distributed_lock_class => { :default => ->{ "NoBrainer::Lock" } },
|
18
18
|
:lock_options => { :default => ->{ { :expire => 60, :timeout => 10 } } },
|
19
19
|
:per_thread_connection => { :default => ->{ false }, :valid_values => [true, false] },
|
20
20
|
:machine_id => { :default => ->{ default_machine_id } },
|
@@ -58,7 +58,7 @@ module NoBrainer::Config
|
|
58
58
|
assert_valid_options
|
59
59
|
@configured = true
|
60
60
|
|
61
|
-
NoBrainer::ConnectionManager.
|
61
|
+
NoBrainer::ConnectionManager.notify_url_change
|
62
62
|
end
|
63
63
|
|
64
64
|
def configured?
|
@@ -107,18 +107,23 @@ module NoBrainer::Config
|
|
107
107
|
dev_mode? ? 1 : 15
|
108
108
|
end
|
109
109
|
|
110
|
+
# XXX Not referencing NoBrainer::Document::PrimaryKey::Generator::MACHINE_ID_MASK
|
111
|
+
# because we don't want to load all the document code to speedup boot time.
|
112
|
+
MACHINE_ID_BITS = 24
|
113
|
+
MACHINE_ID_MASK = (1 << MACHINE_ID_BITS)-1
|
114
|
+
|
110
115
|
def default_machine_id
|
116
|
+
return ENV['MACHINE_ID'] if ENV['MACHINE_ID']
|
117
|
+
|
111
118
|
require 'socket'
|
112
119
|
require 'digest/md5'
|
113
120
|
|
114
|
-
return ENV['MACHINE_ID'] if ENV['MACHINE_ID']
|
115
|
-
|
116
121
|
host = Socket.gethostname
|
117
122
|
if host.in? %w(127.0.0.1 localhost)
|
118
123
|
raise "Please configure NoBrainer::Config.machine_id due to lack of appropriate hostname (Socket.gethostname = #{host})"
|
119
124
|
end
|
120
125
|
|
121
|
-
Digest::MD5.digest(host).unpack("N")[0] &
|
126
|
+
Digest::MD5.digest(host).unpack("N")[0] & MACHINE_ID_MASK
|
122
127
|
end
|
123
128
|
|
124
129
|
def machine_id=(machine_id)
|
@@ -127,9 +132,16 @@ module NoBrainer::Config
|
|
127
132
|
when /^[0-9]+$/ then machine_id.to_i
|
128
133
|
else raise "Invalid machine_id"
|
129
134
|
end
|
130
|
-
max_id =
|
135
|
+
max_id = MACHINE_ID_MASK
|
131
136
|
raise "Invalid machine_id (must be between 0 and #{max_id})" unless machine_id.in?(0..max_id)
|
132
137
|
@machine_id = machine_id
|
133
138
|
end
|
139
|
+
|
140
|
+
def distributed_lock_class
|
141
|
+
if @distributed_lock_class.is_a?(String)
|
142
|
+
@distributed_lock_class = @distributed_lock_class.constantize
|
143
|
+
end
|
144
|
+
@distributed_lock_class
|
145
|
+
end
|
134
146
|
end
|
135
147
|
end
|
@@ -1,12 +1,4 @@
|
|
1
1
|
module NoBrainer::Criteria::Where
|
2
|
-
NON_CHAINABLE_OPERATORS = %w(in eq gt ge gte lt le lte defined near intersects).map(&:to_sym)
|
3
|
-
CHAINABLE_OPERATORS = %w(not any all).map(&:to_sym)
|
4
|
-
OPERATORS = CHAINABLE_OPERATORS + NON_CHAINABLE_OPERATORS
|
5
|
-
|
6
|
-
require 'symbol_decoration'
|
7
|
-
Symbol::Decoration.register(*NON_CHAINABLE_OPERATORS)
|
8
|
-
Symbol::Decoration.register(*CHAINABLE_OPERATORS, :chainable => true)
|
9
|
-
|
10
2
|
extend ActiveSupport::Concern
|
11
3
|
include ActiveModel::ForbiddenAttributesProtection
|
12
4
|
|
@@ -28,11 +28,11 @@ module NoBrainer::Document::Association
|
|
28
28
|
raise "Cannot change the :through option" unless r.options[:through] == options[:through]
|
29
29
|
r.options.merge!(options)
|
30
30
|
else
|
31
|
-
|
32
|
-
|
33
|
-
r =
|
34
|
-
|
35
|
-
|
31
|
+
class_name = (options[:through] ? "#{association}_through" : association.to_s).camelize
|
32
|
+
metadata_class = NoBrainer::Document::Association.const_get(class_name).const_get(:Metadata)
|
33
|
+
r = metadata_class.new(self, target, options)
|
34
|
+
subclass_tree.each do |subclass|
|
35
|
+
subclass.association_metadata[target] = r
|
36
36
|
end
|
37
37
|
end
|
38
38
|
r.hook
|
@@ -11,7 +11,22 @@ class NoBrainer::Document::Association::BelongsTo
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def primary_key
|
14
|
-
|
14
|
+
# We default the primary_key to `:id' and not `target_model.pk_name',
|
15
|
+
# because we don't want to require the target_model to be already loaded.
|
16
|
+
# (We want the ability to load models in any order).
|
17
|
+
# Using target_model.pk_name and allowing lazy loading of models is
|
18
|
+
# difficult due to the inexistant API to remove validations if the
|
19
|
+
# foreign_key name was to be changed as the pk_name gets renamed.
|
20
|
+
return options[:primary_key].to_sym if options[:primary_key]
|
21
|
+
|
22
|
+
NoBrainer::Document::PrimaryKey::DEFAULT_PK_NAME.tap do |default_pk_name|
|
23
|
+
# We'll try to give a warning when we see a different target pk name (best effort).
|
24
|
+
real_pk_name = target_model.pk_name rescue nil
|
25
|
+
if real_pk_name && real_pk_name != default_pk_name
|
26
|
+
raise "Please specify the primary_key name on the following belongs_to association as such:\n" +
|
27
|
+
" belongs_to :#{target_name}, :primary_key => :#{real_pk_name}"
|
28
|
+
end
|
29
|
+
end
|
15
30
|
end
|
16
31
|
|
17
32
|
def target_model
|
@@ -24,11 +39,6 @@ class NoBrainer::Document::Association::BelongsTo
|
|
24
39
|
|
25
40
|
def hook
|
26
41
|
super
|
27
|
-
# XXX We are loading the target_model unless the primary_key is specified.
|
28
|
-
# This may eager load a part of the application Oh well.
|
29
|
-
|
30
|
-
# TODO if the primary key of the target_model changes, we need to revisit
|
31
|
-
# our default foreign_key/primary_key value
|
32
42
|
|
33
43
|
# TODO set the type of the foreign key to be the same as the target's primary key
|
34
44
|
if owner_model.association_metadata.values.any? { |assoc|
|
@@ -74,7 +84,7 @@ class NoBrainer::Document::Association::BelongsTo
|
|
74
84
|
return target if loaded?
|
75
85
|
|
76
86
|
if fk = owner.read_attribute(foreign_key)
|
77
|
-
preload(
|
87
|
+
preload(base_criteria.where(primary_key => fk).first)
|
78
88
|
end
|
79
89
|
end
|
80
90
|
|
@@ -33,7 +33,6 @@ class NoBrainer::Document::Association::EagerLoader
|
|
33
33
|
docs = docs.compact
|
34
34
|
return [] if docs.empty?
|
35
35
|
meta = docs.first.root_class.association_metadata
|
36
|
-
# TODO test the singularize thingy.
|
37
36
|
association = meta[association_name.to_sym] || meta[association_name.to_s.singularize.to_sym]
|
38
37
|
raise "Unknown association #{association_name}" unless association
|
39
38
|
association.eager_load(docs, criteria)
|
@@ -1,8 +1,9 @@
|
|
1
1
|
module NoBrainer::Document::Attributes
|
2
2
|
VALID_FIELD_OPTIONS = [:index, :default, :type, :readonly, :primary_key, :lazy_fetch, :store_as,
|
3
3
|
:validates, :required, :unique, :uniq, :format, :in, :length, :min_length, :max_length]
|
4
|
-
RESERVED_FIELD_NAMES = [:index, :default, :and, :or, :selector, :associations, :pk_value]
|
5
|
-
|
4
|
+
RESERVED_FIELD_NAMES = [:index, :default, :and, :or, :selector, :associations, :pk_value] +
|
5
|
+
NoBrainer::SymbolDecoration::OPERATORS
|
6
|
+
|
6
7
|
extend ActiveSupport::Concern
|
7
8
|
include ActiveModel::ForbiddenAttributesProtection
|
8
9
|
|
@@ -129,9 +130,9 @@ module NoBrainer::Document::Attributes
|
|
129
130
|
raise "Cannot use a reserved field attr: #{attr}"
|
130
131
|
end
|
131
132
|
|
132
|
-
|
133
|
-
|
134
|
-
|
133
|
+
subclass_tree.each do |subclass|
|
134
|
+
subclass.fields[attr] ||= {}
|
135
|
+
subclass.fields[attr].deep_merge!(options)
|
135
136
|
end
|
136
137
|
|
137
138
|
_field(attr, self.fields[attr])
|
@@ -149,8 +150,8 @@ module NoBrainer::Document::Attributes
|
|
149
150
|
|
150
151
|
_remove_field(attr, options)
|
151
152
|
|
152
|
-
|
153
|
-
|
153
|
+
subclass_tree.each do |subclass|
|
154
|
+
subclass.fields.delete(attr)
|
154
155
|
end
|
155
156
|
end
|
156
157
|
|
@@ -51,8 +51,8 @@ module NoBrainer::Document::Criteria
|
|
51
51
|
criteria_proc = block || (criteria.is_a?(Proc) ? criteria : proc { criteria })
|
52
52
|
raise "default_scope only accepts a criteria or a proc that returns criteria" unless criteria_proc.is_a?(Proc)
|
53
53
|
|
54
|
-
|
55
|
-
|
54
|
+
subclass_tree.each do |subclass|
|
55
|
+
subclass.default_scopes << criteria_proc
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
@@ -34,9 +34,9 @@ module NoBrainer::Document::LazyFetch
|
|
34
34
|
model = self
|
35
35
|
inject_in_layer :lazy_fetch do
|
36
36
|
if options[:lazy_fetch]
|
37
|
-
model.
|
37
|
+
model.subclass_tree.each { |subclass| subclass.fields_to_lazy_fetch << attr }
|
38
38
|
else
|
39
|
-
model.
|
39
|
+
model.subclass_tree.each { |subclass| subclass.fields_to_lazy_fetch.delete(attr) }
|
40
40
|
end
|
41
41
|
|
42
42
|
# Lazy loading can also specified through criteria.
|
@@ -57,7 +57,7 @@ module NoBrainer::Document::LazyFetch
|
|
57
57
|
|
58
58
|
def _remove_field(attr, options={})
|
59
59
|
super
|
60
|
-
|
60
|
+
subclass_tree.each { |subclass| subclass.fields_to_lazy_fetch.delete(attr) }
|
61
61
|
inject_in_layer :lazy_fetch do
|
62
62
|
remove_method("#{attr}") if method_defined?("#{attr}")
|
63
63
|
end
|
@@ -28,12 +28,12 @@ module NoBrainer::Document::Polymorphic
|
|
28
28
|
self == root_class
|
29
29
|
end
|
30
30
|
|
31
|
-
def
|
32
|
-
|
31
|
+
def subclass_tree
|
32
|
+
[self] + self.descendants
|
33
33
|
end
|
34
34
|
|
35
35
|
def descendants_type_values
|
36
|
-
|
36
|
+
subclass_tree.map(&:type_value)
|
37
37
|
end
|
38
38
|
|
39
39
|
def model_from_attrs(attrs)
|
@@ -23,6 +23,10 @@ module NoBrainer::Document::PrimaryKey
|
|
23
23
|
|
24
24
|
delegate :hash, :to => :pk_value
|
25
25
|
|
26
|
+
def cache_key
|
27
|
+
"#{self.class.table_name}/#{pk_value}"
|
28
|
+
end
|
29
|
+
|
26
30
|
module ClassMethods
|
27
31
|
def define_default_pk
|
28
32
|
class_variable_set(:@@pk_name, nil)
|
@@ -30,6 +34,7 @@ module NoBrainer::Document::PrimaryKey
|
|
30
34
|
end
|
31
35
|
|
32
36
|
def define_pk(attr)
|
37
|
+
return if pk_name == attr
|
33
38
|
if fields[pk_name].try(:[], :primary_key) == :default
|
34
39
|
remove_field(pk_name, :set_default_pk => false)
|
35
40
|
end
|
@@ -50,9 +55,13 @@ module NoBrainer::Document::PrimaryKey
|
|
50
55
|
options = options.merge(:readonly => true) if options[:readonly].nil?
|
51
56
|
options = options.merge(:index => true)
|
52
57
|
|
53
|
-
if options[:
|
54
|
-
|
55
|
-
|
58
|
+
if options[:default].nil?
|
59
|
+
# TODO Maybe we should let the user configure the pk generator
|
60
|
+
default_pk_generator = NoBrainer::Document::PrimaryKey::Generator
|
61
|
+
if options[:type].in?([default_pk_generator.field_type, nil])
|
62
|
+
options[:type] = default_pk_generator.field_type
|
63
|
+
options[:default] = ->{ default_pk_generator.generate }
|
64
|
+
end
|
56
65
|
end
|
57
66
|
end
|
58
67
|
super
|
@@ -20,6 +20,7 @@ module NoBrainer::Document::PrimaryKey::Generator
|
|
20
20
|
# 1% of chance to have a collision with ~580 servers.
|
21
21
|
# When using more than 500 machines, it's therefore a good
|
22
22
|
# idea to set the machine_id manually to avoid collisions.
|
23
|
+
# XXX This is referenced in nobrainer/config.rb#default_machine_id
|
23
24
|
MACHINE_ID_BITS = 24
|
24
25
|
|
25
26
|
# 15 bits for the current pid. We wouldn't need it if the sequence number was
|
@@ -27,7 +28,7 @@ module NoBrainer::Document::PrimaryKey::Generator
|
|
27
28
|
PID_BITS = 15
|
28
29
|
|
29
30
|
# Total: 83 bits
|
30
|
-
#
|
31
|
+
# With 14 digits in [A-Za-z0-9], we can represent 83 bits:
|
31
32
|
# Math.log(62**14)/Math.log(2) = 83.35
|
32
33
|
ID_STR_LENGTH = 14
|
33
34
|
|
@@ -80,4 +81,8 @@ module NoBrainer::Document::PrimaryKey::Generator
|
|
80
81
|
def self.generate
|
81
82
|
convert_to_alphanum(@lock.synchronize { _generate })
|
82
83
|
end
|
84
|
+
|
85
|
+
def self.field_type
|
86
|
+
String
|
87
|
+
end
|
83
88
|
end
|
@@ -60,7 +60,8 @@ module NoBrainer::Document::Validation::Uniqueness
|
|
60
60
|
super
|
61
61
|
self.model = options[:class]
|
62
62
|
self.scope = [*options[:scope]].map(&:to_sym)
|
63
|
-
|
63
|
+
|
64
|
+
model.subclass_tree.each do |subclass|
|
64
65
|
subclass.unique_validators << self
|
65
66
|
end
|
66
67
|
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module NoBrainer::SymbolDecoration
|
2
|
+
NON_CHAINABLE_OPERATORS = %w(in eq gt ge gte lt le lte defined near intersects).map(&:to_sym)
|
3
|
+
CHAINABLE_OPERATORS = %w(not any all).map(&:to_sym)
|
4
|
+
OPERATORS = CHAINABLE_OPERATORS + NON_CHAINABLE_OPERATORS
|
5
|
+
|
6
|
+
def self.hook
|
7
|
+
require 'symbol_decoration'
|
8
|
+
Symbol::Decoration.register(*NON_CHAINABLE_OPERATORS)
|
9
|
+
Symbol::Decoration.register(*CHAINABLE_OPERATORS, :chainable => true)
|
10
|
+
end
|
11
|
+
end
|
data/lib/nobrainer.rb
CHANGED
@@ -14,9 +14,9 @@ module NoBrainer
|
|
14
14
|
|
15
15
|
# We eager load things that could be loaded when handling the first web request.
|
16
16
|
# Code that is loaded through the DSL of NoBrainer should not be eager loaded.
|
17
|
-
autoload :Document, :IndexManager, :Loader, :Fork, :Geo, :
|
18
|
-
eager_autoload :Config, :Connection, :ConnectionManager,
|
19
|
-
:QueryRunner, :Criteria, :RQL
|
17
|
+
autoload :Document, :IndexManager, :Loader, :Fork, :Geo, :SymbolDecoration
|
18
|
+
eager_autoload :Config, :Connection, :ConnectionManager, :Error,
|
19
|
+
:QueryRunner, :Criteria, :RQL, :Lock, :Profiler
|
20
20
|
|
21
21
|
class << self
|
22
22
|
delegate :connection, :disconnect, :to => 'NoBrainer::ConnectionManager'
|
@@ -38,11 +38,11 @@ module NoBrainer
|
|
38
38
|
end
|
39
39
|
|
40
40
|
Fork.hook unless jruby?
|
41
|
+
SymbolDecoration.hook
|
41
42
|
end
|
42
43
|
|
43
44
|
ActiveSupport.on_load(:i18n) do
|
44
45
|
I18n.load_path << File.dirname(__FILE__) + '/no_brainer/locale/en.yml'
|
45
46
|
end
|
46
47
|
|
47
|
-
require 'no_brainer/profiler/logger'
|
48
48
|
require 'no_brainer/railtie' if defined?(Rails)
|
@@ -6,7 +6,7 @@ module NoBrainer::Generators
|
|
6
6
|
extend NoBrainer::Generators::NamespaceFix
|
7
7
|
source_root File.expand_path("../../templates", __FILE__)
|
8
8
|
|
9
|
-
desc "Disable ActiveRecord and generates ./config/
|
9
|
+
desc "Disable ActiveRecord and generates ./config/initializers/nobrainer.rb"
|
10
10
|
|
11
11
|
class RequireProxy
|
12
12
|
attr_accessor :required_paths
|
@@ -42,7 +42,7 @@ module NoBrainer::Generators
|
|
42
42
|
|
43
43
|
|
44
44
|
def copy_initializer
|
45
|
-
template('nobrainer.rb', 'config/
|
45
|
+
template('nobrainer.rb', 'config/initializers/nobrainer.rb')
|
46
46
|
end
|
47
47
|
end
|
48
48
|
end
|
@@ -65,7 +65,7 @@ NoBrainer.configure do |config|
|
|
65
65
|
|
66
66
|
# Configures which mechanism to use in order to perform non-racy uniqueness
|
67
67
|
# validations. More about this behavior in the Distributed Locks section.
|
68
|
-
# config.distributed_lock_class = NoBrainer::Lock
|
68
|
+
# config.distributed_lock_class = "NoBrainer::Lock"
|
69
69
|
|
70
70
|
# Configures the default timing lock options.
|
71
71
|
# config.lock_options = { :expire => 60, :timeout => 10 }
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nobrainer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.27.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nicolas Viennot
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-07-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rethinkdb
|
@@ -191,6 +191,7 @@ files:
|
|
191
191
|
- lib/no_brainer/railtie.rb
|
192
192
|
- lib/no_brainer/railtie/database.rake
|
193
193
|
- lib/no_brainer/rql.rb
|
194
|
+
- lib/no_brainer/symbol_decoration.rb
|
194
195
|
- lib/nobrainer.rb
|
195
196
|
- lib/rails/generators/nobrainer/install_generator.rb
|
196
197
|
- lib/rails/generators/nobrainer/model_generator.rb
|