nobrainer 0.8.0 → 0.9.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 +9 -16
- data/lib/no_brainer/connection.rb +32 -26
- data/lib/no_brainer/criteria/chainable/core.rb +17 -20
- data/lib/no_brainer/criteria/chainable/limit.rb +2 -2
- data/lib/no_brainer/criteria/chainable/order_by.rb +24 -7
- data/lib/no_brainer/criteria/chainable/raw.rb +11 -3
- data/lib/no_brainer/criteria/chainable/scope.rb +11 -7
- data/lib/no_brainer/criteria/chainable/where.rb +32 -15
- data/lib/no_brainer/criteria/termination/cache.rb +13 -9
- data/lib/no_brainer/criteria/termination/eager_loading.rb +12 -26
- data/lib/no_brainer/document.rb +2 -6
- data/lib/no_brainer/document/association.rb +8 -7
- data/lib/no_brainer/document/association/belongs_to.rb +27 -22
- data/lib/no_brainer/document/association/core.rb +8 -8
- data/lib/no_brainer/document/association/eager_loader.rb +57 -0
- data/lib/no_brainer/document/association/has_many.rb +49 -26
- data/lib/no_brainer/document/association/has_many_through.rb +31 -0
- data/lib/no_brainer/document/association/has_one.rb +13 -0
- data/lib/no_brainer/document/association/has_one_through.rb +10 -0
- data/lib/no_brainer/document/attributes.rb +4 -3
- data/lib/no_brainer/document/core.rb +1 -1
- data/lib/no_brainer/document/criteria.rb +2 -3
- data/lib/no_brainer/document/index.rb +3 -3
- data/lib/no_brainer/document/polymorphic.rb +1 -1
- data/lib/no_brainer/document/serialization.rb +1 -1
- data/lib/no_brainer/document/store_in.rb +5 -3
- data/lib/no_brainer/error.rb +1 -0
- data/lib/no_brainer/query_runner.rb +2 -1
- data/lib/no_brainer/query_runner/driver.rb +1 -4
- data/lib/no_brainer/query_runner/missing_index.rb +11 -0
- data/lib/no_brainer/query_runner/run_options.rb +2 -3
- data/lib/no_brainer/railtie.rb +0 -1
- data/lib/no_brainer/version.rb +1 -1
- data/lib/nobrainer.rb +5 -5
- metadata +28 -24
- data/lib/no_brainer/database.rb +0 -41
@@ -0,0 +1,31 @@
|
|
1
|
+
class NoBrainer::Document::Association::HasManyThrough
|
2
|
+
include NoBrainer::Document::Association::Core
|
3
|
+
|
4
|
+
class Metadata
|
5
|
+
VALID_OPTIONS = [:through]
|
6
|
+
include NoBrainer::Document::Association::Core::Metadata
|
7
|
+
|
8
|
+
def through_association_name
|
9
|
+
options[:through].to_sym
|
10
|
+
end
|
11
|
+
|
12
|
+
def through_association
|
13
|
+
owner_klass.association_metadata[through_association_name] or
|
14
|
+
raise "#{through_association_name} association not found"
|
15
|
+
end
|
16
|
+
|
17
|
+
def eager_load(docs, criteria=nil)
|
18
|
+
NoBrainer::Document::Association::EagerLoader.new
|
19
|
+
.eager_load_association(through_association.eager_load(docs), target_name, criteria)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def read
|
24
|
+
# TODO implement joins
|
25
|
+
@targets ||= metadata.eager_load([owner]).freeze
|
26
|
+
end
|
27
|
+
|
28
|
+
def write(new_children)
|
29
|
+
raise "You can't assign #{target_name}"
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class NoBrainer::Document::Association::HasOne < NoBrainer::Document::Association::HasMany
|
2
|
+
class Metadata < NoBrainer::Document::Association::HasMany::Metadata
|
3
|
+
def target_klass
|
4
|
+
(options[:class_name] || target_name.to_s.camelize).constantize
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
def read
|
9
|
+
targets = target_criteria.to_a # to load the cache
|
10
|
+
NoBrainer.logger.warn "#{owner} has more than one #{target_name}" if targets.size > 1
|
11
|
+
targets.first
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
class NoBrainer::Document::Association::HasOneThrough < NoBrainer::Document::Association::HasManyThrough
|
2
|
+
class Metadata < NoBrainer::Document::Association::HasManyThrough::Metadata
|
3
|
+
end
|
4
|
+
|
5
|
+
def read
|
6
|
+
targets = super
|
7
|
+
NoBrainer.logger.warn "#{owner} has more than one #{target_name}" if targets.size > 1
|
8
|
+
targets.first
|
9
|
+
end
|
10
|
+
end
|
@@ -1,11 +1,12 @@
|
|
1
1
|
module NoBrainer::Document::Attributes
|
2
2
|
VALID_FIELD_OPTIONS = [:index, :default]
|
3
|
+
RESERVED_FIELD_NAMES = [:index, :default, :and, :or, :selector, :associations] + NoBrainer::DecoratedSymbol::MODIFIERS.keys
|
3
4
|
extend ActiveSupport::Concern
|
4
5
|
|
5
6
|
included do
|
6
7
|
# Not using class_attribute because we want to
|
7
8
|
# use our custom logic
|
8
|
-
|
9
|
+
singleton_class.send(:attr_accessor, :fields)
|
9
10
|
self.fields = {}
|
10
11
|
end
|
11
12
|
|
@@ -82,8 +83,8 @@ module NoBrainer::Document::Attributes
|
|
82
83
|
def field(name, options={})
|
83
84
|
name = name.to_sym
|
84
85
|
|
85
|
-
options.assert_valid_keys(*
|
86
|
-
if name.in?
|
86
|
+
options.assert_valid_keys(*VALID_FIELD_OPTIONS)
|
87
|
+
if name.in?(RESERVED_FIELD_NAMES)
|
87
88
|
raise "Cannot use a reserved field name: #{name}"
|
88
89
|
end
|
89
90
|
|
@@ -5,9 +5,7 @@ module NoBrainer::Document::Criteria
|
|
5
5
|
self.class.selector_for(id)
|
6
6
|
end
|
7
7
|
|
8
|
-
included
|
9
|
-
class_attribute :default_scope_proc
|
10
|
-
end
|
8
|
+
included { cattr_accessor :default_scope_proc, :instance_accessor => false }
|
11
9
|
|
12
10
|
module ClassMethods
|
13
11
|
delegate :to_rql, # Core
|
@@ -39,6 +37,7 @@ module NoBrainer::Document::Criteria
|
|
39
37
|
|
40
38
|
def default_scope(criteria=nil, &block)
|
41
39
|
criteria ||= block
|
40
|
+
raise "store_in() must be called on the parent class" unless is_root_class?
|
42
41
|
self.default_scope_proc = criteria.is_a?(Proc) ? criteria : proc { criteria }
|
43
42
|
end
|
44
43
|
|
@@ -3,7 +3,7 @@ module NoBrainer::Document::Index
|
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
5
|
included do
|
6
|
-
|
6
|
+
cattr_accessor :indexes, :instance_accessor => false
|
7
7
|
self.indexes = {}
|
8
8
|
self.index :id
|
9
9
|
end
|
@@ -12,7 +12,7 @@ module NoBrainer::Document::Index
|
|
12
12
|
def index(name, *args)
|
13
13
|
name = name.to_sym
|
14
14
|
options = args.extract_options!
|
15
|
-
options.assert_valid_keys(*
|
15
|
+
options.assert_valid_keys(*VALID_INDEX_OPTIONS)
|
16
16
|
|
17
17
|
raise "Too many arguments: #{args}" if args.size > 1
|
18
18
|
|
@@ -24,7 +24,7 @@ module NoBrainer::Document::Index
|
|
24
24
|
end
|
25
25
|
|
26
26
|
# FIXME Primary key may not always be :id
|
27
|
-
if name.in?(NoBrainer::
|
27
|
+
if name.in?(NoBrainer::Document::Attributes::RESERVED_FIELD_NAMES)
|
28
28
|
raise "Cannot use a reserved field name: #{name}"
|
29
29
|
end
|
30
30
|
if has_field?(name) && kind != :single
|
@@ -1,14 +1,16 @@
|
|
1
|
+
require 'rethinkdb'
|
2
|
+
|
1
3
|
module NoBrainer::Document::StoreIn
|
2
4
|
extend ActiveSupport::Concern
|
3
5
|
|
4
6
|
included do
|
5
|
-
|
7
|
+
cattr_accessor :store_in_options, :instance_accessor => false
|
6
8
|
self.store_in_options = {}
|
7
9
|
end
|
8
10
|
|
9
11
|
module ClassMethods
|
10
12
|
def store_in(options)
|
11
|
-
raise "store_in() must be called on the parent class" unless
|
13
|
+
raise "store_in() must be called on the parent class" unless is_root_class?
|
12
14
|
self.store_in_options.merge!(options)
|
13
15
|
end
|
14
16
|
|
@@ -20,7 +22,7 @@ module NoBrainer::Document::StoreIn
|
|
20
22
|
def table_name
|
21
23
|
table = store_in_options[:table]
|
22
24
|
table_name = table.is_a?(Proc) ? table.call : table
|
23
|
-
table_name || root_class.name.
|
25
|
+
table_name || root_class.name.tableize.gsub('/', '__')
|
24
26
|
end
|
25
27
|
|
26
28
|
def rql_table
|
data/lib/no_brainer/error.rb
CHANGED
@@ -5,6 +5,7 @@ module NoBrainer::Error
|
|
5
5
|
class DocumentNotSaved < StandardError; end
|
6
6
|
class ChildrenExist < StandardError; end
|
7
7
|
class CannotUseIndex < StandardError; end
|
8
|
+
class MissingIndex < StandardError; end
|
8
9
|
class InvalidType < StandardError; end
|
9
10
|
class AssociationNotSaved < StandardError; end
|
10
11
|
end
|
@@ -11,7 +11,7 @@ module NoBrainer::QueryRunner
|
|
11
11
|
end
|
12
12
|
|
13
13
|
autoload :Driver, :DatabaseOnDemand, :TableOnDemand, :WriteError,
|
14
|
-
:Connection, :Selection, :RunOptions, :Logger
|
14
|
+
:Connection, :Selection, :RunOptions, :Logger, :MissingIndex
|
15
15
|
|
16
16
|
class << self
|
17
17
|
attr_accessor :stack
|
@@ -29,6 +29,7 @@ module NoBrainer::QueryRunner
|
|
29
29
|
use RunOptions
|
30
30
|
use Connection
|
31
31
|
use WriteError
|
32
|
+
use MissingIndex
|
32
33
|
use DatabaseOnDemand
|
33
34
|
use TableOnDemand
|
34
35
|
use Logger
|
@@ -1,8 +1,5 @@
|
|
1
1
|
class NoBrainer::QueryRunner::Driver < NoBrainer::QueryRunner::Middleware
|
2
2
|
def call(env)
|
3
|
-
env[:query].run(NoBrainer.connection, env[:options])
|
4
|
-
rescue NoMethodError => e
|
5
|
-
raise "NoBrainer is not connected to a RethinkDB instance" unless NoBrainer.connection
|
6
|
-
raise e
|
3
|
+
env[:query].run(NoBrainer.connection.raw, env[:options])
|
7
4
|
end
|
8
5
|
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class NoBrainer::QueryRunner::MissingIndex < NoBrainer::QueryRunner::Middleware
|
2
|
+
def call(env)
|
3
|
+
@runner.call(env)
|
4
|
+
rescue RethinkDB::RqlRuntimeError => e
|
5
|
+
if e.message =~ /^Index `(.+)` was not found\.$/
|
6
|
+
raise NoBrainer::Error::MissingIndex.new("Please run \"rake db:update_indexes\" to create index `#{$1}`\n" +
|
7
|
+
"--> Read http://nobrainer.io/docs/indexes for more information.")
|
8
|
+
end
|
9
|
+
raise
|
10
|
+
end
|
11
|
+
end
|
@@ -1,12 +1,11 @@
|
|
1
1
|
class NoBrainer::QueryRunner::RunOptions < NoBrainer::QueryRunner::Middleware
|
2
2
|
# XXX NoBrainer::Database#drop() uses Thread.current[:nobrainer_options]
|
3
|
-
# We should fix that hack.
|
4
3
|
|
5
4
|
def self.with_database(db_name, &block)
|
6
|
-
|
5
|
+
with(:db => db_name, &block)
|
7
6
|
end
|
8
7
|
|
9
|
-
def self.
|
8
|
+
def self.with(options={}, &block)
|
10
9
|
old_options = Thread.current[:nobrainer_options]
|
11
10
|
Thread.current[:nobrainer_options] = (old_options || {}).merge(options.symbolize_keys)
|
12
11
|
block.call if block
|
data/lib/no_brainer/railtie.rb
CHANGED
@@ -5,7 +5,6 @@ class NoBrainer::Railtie < Rails::Railtie
|
|
5
5
|
config.action_dispatch.rescue_responses.merge!(
|
6
6
|
"NoBrainer::Errors::DocumentNotFound" => :not_found,
|
7
7
|
"NoBrainer::Errors::DocumentInvalid" => :unprocessable_entity,
|
8
|
-
"NoBrainer::Errors::DocumentNotSaved" => :unprocessable_entity,
|
9
8
|
)
|
10
9
|
|
11
10
|
rake_tasks do
|
data/lib/no_brainer/version.rb
CHANGED
data/lib/nobrainer.rb
CHANGED
@@ -34,13 +34,13 @@ module NoBrainer
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
|
-
#
|
38
|
-
delegate :db_create, :db_drop, :db_list,
|
39
|
-
|
40
|
-
:drop!, :purge!, :to => :
|
37
|
+
# Not using modules to extend, it's nicer to see the NoBrainer module API here.
|
38
|
+
delegate :db_create, :db_drop, :db_list,
|
39
|
+
:table_create, :table_drop, :table_list,
|
40
|
+
:drop!, :purge!, :to => :connection
|
41
41
|
delegate :run, :to => 'NoBrainer::QueryRunner'
|
42
42
|
delegate :update_indexes, :to => 'NoBrainer::IndexManager'
|
43
|
-
delegate :
|
43
|
+
delegate :with, :with_database, :to => 'NoBrainer::QueryRunner::RunOptions'
|
44
44
|
delegate :configure, :logger, :to => 'NoBrainer::Config'
|
45
45
|
|
46
46
|
def jruby?
|
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.9.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:
|
11
|
+
date: 2014-01-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rethinkdb
|
@@ -65,61 +65,65 @@ executables: []
|
|
65
65
|
extensions: []
|
66
66
|
extra_rdoc_files: []
|
67
67
|
files:
|
68
|
-
- lib/no_brainer/document/polymorphic.rb
|
69
68
|
- lib/no_brainer/document/id.rb
|
70
69
|
- lib/no_brainer/document/injection_layer.rb
|
71
|
-
- lib/no_brainer/document/store_in.rb
|
72
70
|
- lib/no_brainer/document/timestamps.rb
|
73
|
-
- lib/no_brainer/document/association.rb
|
71
|
+
- lib/no_brainer/document/association/belongs_to.rb
|
74
72
|
- lib/no_brainer/document/association/core.rb
|
73
|
+
- lib/no_brainer/document/association/eager_loader.rb
|
74
|
+
- lib/no_brainer/document/association/has_many_through.rb
|
75
75
|
- lib/no_brainer/document/association/has_many.rb
|
76
|
-
- lib/no_brainer/document/association/
|
77
|
-
- lib/no_brainer/document/
|
78
|
-
- lib/no_brainer/document/criteria.rb
|
76
|
+
- lib/no_brainer/document/association/has_one.rb
|
77
|
+
- lib/no_brainer/document/association/has_one_through.rb
|
79
78
|
- lib/no_brainer/document/dirty.rb
|
80
79
|
- lib/no_brainer/document/dynamic_attributes.rb
|
81
80
|
- lib/no_brainer/document/persistance.rb
|
82
|
-
- lib/no_brainer/document/serialization.rb
|
83
81
|
- lib/no_brainer/document/validation.rb
|
84
|
-
- lib/no_brainer/document/
|
82
|
+
- lib/no_brainer/document/serialization.rb
|
83
|
+
- lib/no_brainer/document/criteria.rb
|
85
84
|
- lib/no_brainer/document/index.rb
|
85
|
+
- lib/no_brainer/document/polymorphic.rb
|
86
|
+
- lib/no_brainer/document/store_in.rb
|
87
|
+
- lib/no_brainer/document/attributes.rb
|
88
|
+
- lib/no_brainer/document/core.rb
|
89
|
+
- lib/no_brainer/document/association.rb
|
86
90
|
- lib/no_brainer/query_runner/connection.rb
|
87
|
-
- lib/no_brainer/query_runner/driver.rb
|
88
91
|
- lib/no_brainer/query_runner/database_on_demand.rb
|
89
92
|
- lib/no_brainer/query_runner/logger.rb
|
90
|
-
- lib/no_brainer/query_runner/run_options.rb
|
91
93
|
- lib/no_brainer/query_runner/table_on_demand.rb
|
92
94
|
- lib/no_brainer/query_runner/write_error.rb
|
95
|
+
- lib/no_brainer/query_runner/driver.rb
|
96
|
+
- lib/no_brainer/query_runner/missing_index.rb
|
97
|
+
- lib/no_brainer/query_runner/run_options.rb
|
93
98
|
- lib/no_brainer/railtie/database.rake
|
94
|
-
- lib/no_brainer/criteria/chainable/raw.rb
|
95
|
-
- lib/no_brainer/criteria/chainable/core.rb
|
96
99
|
- lib/no_brainer/criteria/chainable/limit.rb
|
97
100
|
- lib/no_brainer/criteria/chainable/order_by.rb
|
98
101
|
- lib/no_brainer/criteria/chainable/scope.rb
|
102
|
+
- lib/no_brainer/criteria/chainable/raw.rb
|
103
|
+
- lib/no_brainer/criteria/chainable/core.rb
|
99
104
|
- lib/no_brainer/criteria/chainable/where.rb
|
100
105
|
- lib/no_brainer/criteria/termination/inc.rb
|
101
106
|
- lib/no_brainer/criteria/termination/count.rb
|
102
107
|
- lib/no_brainer/criteria/termination/first.rb
|
103
108
|
- lib/no_brainer/criteria/termination/enumerable.rb
|
104
109
|
- lib/no_brainer/criteria/termination/update.rb
|
105
|
-
- lib/no_brainer/criteria/termination/cache.rb
|
106
110
|
- lib/no_brainer/criteria/termination/delete.rb
|
107
111
|
- lib/no_brainer/criteria/termination/eager_loading.rb
|
108
|
-
- lib/no_brainer/
|
109
|
-
- lib/no_brainer/railtie.rb
|
110
|
-
- lib/no_brainer/criteria.rb
|
111
|
-
- lib/no_brainer/database.rb
|
112
|
+
- lib/no_brainer/criteria/termination/cache.rb
|
112
113
|
- lib/no_brainer/decorated_symbol.rb
|
113
|
-
- lib/no_brainer/document.rb
|
114
|
-
- lib/no_brainer/error.rb
|
115
114
|
- lib/no_brainer/index_manager.rb
|
116
115
|
- lib/no_brainer/loader.rb
|
117
116
|
- lib/no_brainer/locale/en.yml
|
118
|
-
- lib/no_brainer/query_runner.rb
|
119
117
|
- lib/no_brainer/util.rb
|
120
|
-
- lib/no_brainer/config.rb
|
121
|
-
- lib/no_brainer/connection.rb
|
122
118
|
- lib/no_brainer/fork.rb
|
119
|
+
- lib/no_brainer/criteria.rb
|
120
|
+
- lib/no_brainer/connection.rb
|
121
|
+
- lib/no_brainer/query_runner.rb
|
122
|
+
- lib/no_brainer/error.rb
|
123
|
+
- lib/no_brainer/document.rb
|
124
|
+
- lib/no_brainer/config.rb
|
125
|
+
- lib/no_brainer/railtie.rb
|
126
|
+
- lib/no_brainer/autoload.rb
|
123
127
|
- lib/no_brainer/version.rb
|
124
128
|
- lib/nobrainer.rb
|
125
129
|
- README.md
|
data/lib/no_brainer/database.rb
DELETED
@@ -1,41 +0,0 @@
|
|
1
|
-
class NoBrainer::Database
|
2
|
-
attr_accessor :connection
|
3
|
-
|
4
|
-
# FIXME This class is a bit weird as we don't use it to represent the current
|
5
|
-
# database.
|
6
|
-
|
7
|
-
delegate :database_name, :to => :connection
|
8
|
-
|
9
|
-
def initialize(connection)
|
10
|
-
self.connection = connection
|
11
|
-
end
|
12
|
-
|
13
|
-
def raw
|
14
|
-
@raw ||= RethinkDB::RQL.new.db(database_name)
|
15
|
-
end
|
16
|
-
|
17
|
-
def drop!
|
18
|
-
# FIXME Sad hack.
|
19
|
-
db = (Thread.current[:nobrainer_options] || {})[:db] || database_name
|
20
|
-
connection.db_drop(db)['dropped'] == 1
|
21
|
-
end
|
22
|
-
|
23
|
-
# Note that truncating each table (purge) is much faster than dropping the
|
24
|
-
# database (drop)
|
25
|
-
def purge!(options={})
|
26
|
-
table_list.each do |table_name|
|
27
|
-
NoBrainer.run { |r| r.table(table_name).delete }
|
28
|
-
end
|
29
|
-
true
|
30
|
-
rescue RuntimeError => e
|
31
|
-
raise e unless e.message =~ /No entry with that name/
|
32
|
-
end
|
33
|
-
|
34
|
-
[:table_create, :table_drop, :table_list].each do |cmd|
|
35
|
-
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
36
|
-
def #{cmd}(*args)
|
37
|
-
NoBrainer.run { |r| r.#{cmd}(*args) }
|
38
|
-
end
|
39
|
-
RUBY
|
40
|
-
end
|
41
|
-
end
|