nobrainer 0.20.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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/lib/no_brainer/autoload.rb +0 -5
  3. data/lib/no_brainer/config.rb +14 -9
  4. data/lib/no_brainer/connection.rb +1 -3
  5. data/lib/no_brainer/criteria/aggregate.rb +2 -2
  6. data/lib/no_brainer/criteria/cache.rb +8 -3
  7. data/lib/no_brainer/criteria/core.rb +1 -5
  8. data/lib/no_brainer/criteria/delete.rb +1 -1
  9. data/lib/no_brainer/criteria/eager_load.rb +51 -0
  10. data/lib/no_brainer/criteria/find.rb +27 -0
  11. data/lib/no_brainer/criteria/order_by.rb +1 -1
  12. data/lib/no_brainer/criteria/scope.rb +3 -10
  13. data/lib/no_brainer/criteria/update.rb +8 -6
  14. data/lib/no_brainer/criteria/where.rb +50 -13
  15. data/lib/no_brainer/criteria.rb +3 -2
  16. data/lib/no_brainer/document/aliases.rb +0 -8
  17. data/lib/no_brainer/document/association/belongs_to.rb +6 -2
  18. data/lib/no_brainer/document/association/core.rb +5 -4
  19. data/lib/no_brainer/document/association/eager_loader.rb +7 -8
  20. data/lib/no_brainer/document/association/has_many.rb +22 -8
  21. data/lib/no_brainer/document/association/has_many_through.rb +12 -3
  22. data/lib/no_brainer/document/atomic_ops.rb +63 -61
  23. data/lib/no_brainer/document/attributes.rb +11 -3
  24. data/lib/no_brainer/document/core.rb +5 -2
  25. data/lib/no_brainer/document/criteria.rb +14 -17
  26. data/lib/no_brainer/document/dirty.rb +11 -16
  27. data/lib/no_brainer/document/index/meta_store.rb +1 -1
  28. data/lib/no_brainer/document/index.rb +0 -6
  29. data/lib/no_brainer/document/persistance.rb +13 -3
  30. data/lib/no_brainer/document/store_in.rb +2 -2
  31. data/lib/no_brainer/document/types/binary.rb +2 -6
  32. data/lib/no_brainer/document/types/boolean.rb +2 -3
  33. data/lib/no_brainer/document/types/date.rb +2 -2
  34. data/lib/no_brainer/document/types/float.rb +2 -2
  35. data/lib/no_brainer/document/types/geo.rb +1 -0
  36. data/lib/no_brainer/document/types/integer.rb +2 -2
  37. data/lib/no_brainer/document/types/set.rb +2 -2
  38. data/lib/no_brainer/document/types/string.rb +5 -2
  39. data/lib/no_brainer/document/types/symbol.rb +2 -2
  40. data/lib/no_brainer/document/types/text.rb +18 -0
  41. data/lib/no_brainer/document/types/time.rb +2 -2
  42. data/lib/no_brainer/document/types.rb +13 -12
  43. data/lib/no_brainer/document/validation/not_null.rb +15 -0
  44. data/lib/no_brainer/document/{uniqueness.rb → validation/uniqueness.rb} +11 -10
  45. data/lib/no_brainer/document/validation.rb +35 -6
  46. data/lib/no_brainer/document.rb +2 -2
  47. data/lib/no_brainer/error.rb +20 -23
  48. data/lib/no_brainer/locale/en.yml +1 -0
  49. data/lib/no_brainer/lock.rb +114 -0
  50. data/lib/no_brainer/query_runner/database_on_demand.rb +0 -1
  51. data/lib/no_brainer/query_runner/missing_index.rb +1 -1
  52. data/lib/no_brainer/query_runner/run_options.rb +0 -3
  53. data/lib/no_brainer/query_runner/table_on_demand.rb +2 -3
  54. data/lib/no_brainer/rql.rb +0 -4
  55. data/lib/nobrainer.rb +1 -1
  56. metadata +9 -4
  57. data/lib/no_brainer/criteria/preload.rb +0 -44
@@ -1,5 +1,5 @@
1
1
  class Symbol
2
- module NoBrainerExtentions
2
+ module NoBrainerExtensions
3
3
  InvalidType = NoBrainer::Error::InvalidType
4
4
 
5
5
  def nobrainer_cast_user_to_model(value)
@@ -17,5 +17,5 @@ class Symbol
17
17
  value.to_sym rescue (value.to_s.to_sym rescue value)
18
18
  end
19
19
  end
20
- extend NoBrainerExtentions
20
+ extend NoBrainerExtensions
21
21
  end
@@ -0,0 +1,18 @@
1
+ class NoBrainer::Text
2
+ def initialize; raise; end
3
+ def self.inspect; 'Text'; end
4
+ def self.to_s; inspect; end
5
+ def self.name; inspect; end
6
+
7
+ module NoBrainerExtensions
8
+ InvalidType = NoBrainer::Error::InvalidType
9
+
10
+ def nobrainer_cast_user_to_model(value)
11
+ case value
12
+ when String then value
13
+ else raise InvalidType
14
+ end
15
+ end
16
+ end
17
+ extend NoBrainerExtensions
18
+ end
@@ -1,7 +1,7 @@
1
1
  require 'time'
2
2
 
3
3
  class Time
4
- module NoBrainerExtentions
4
+ module NoBrainerExtensions
5
5
  InvalidType = NoBrainer::Error::InvalidType
6
6
 
7
7
  def nobrainer_cast_user_to_model(value)
@@ -37,5 +37,5 @@ class Time
37
37
  end
38
38
  end
39
39
  end
40
- extend NoBrainerExtentions
40
+ extend NoBrainerExtensions
41
41
  end
@@ -6,7 +6,7 @@ module NoBrainer::Document::Types
6
6
  def add_type_errors
7
7
  return unless @pending_type_errors
8
8
  @pending_type_errors.each do |name, error|
9
- errors.add(name, :invalid_type, :type => error.human_type_name)
9
+ errors.add(name, :invalid_type, error.error)
10
10
  end
11
11
  end
12
12
 
@@ -22,7 +22,10 @@ module NoBrainer::Document::Types
22
22
  module ClassMethods
23
23
  def cast_user_to_model_for(attr, value)
24
24
  type = fields[attr.to_sym].try(:[], :type)
25
- return value if type.nil? || value.nil? || value.is_a?(NoBrainer::Document::AtomicOps::PendingAtomic)
25
+ return value if type.nil? || value.nil? ||
26
+ value.is_a?(NoBrainer::Document::AtomicOps::PendingAtomic) ||
27
+ value.is_a?(RethinkDB::RQL)
28
+
26
29
  if type.respond_to?(:nobrainer_cast_user_to_model)
27
30
  type.nobrainer_cast_user_to_model(value)
28
31
  else
@@ -30,9 +33,7 @@ module NoBrainer::Document::Types
30
33
  value
31
34
  end
32
35
  rescue NoBrainer::Error::InvalidType => error
33
- error.type = type
34
- error.value = value
35
- error.attr_name = attr
36
+ error.update(:model => self, :value => value, :attr_name => attr, :type => type)
36
37
  raise error
37
38
  end
38
39
 
@@ -62,14 +63,15 @@ module NoBrainer::Document::Types
62
63
 
63
64
  return unless options[:type]
64
65
 
65
- NoBrainer::Document::Types.load_type_extensions(options[:type]) if options[:type]
66
-
66
+ raise "Please use a class for the type option" unless options[:type].is_a?(Class)
67
67
  case options[:type].to_s
68
68
  when "NoBrainer::Geo::Circle" then raise "Cannot store circles :("
69
69
  when "NoBrainer::Geo::Polygon", "NoBrainer::Geo::LineString"
70
70
  raise "Make a request on github if you'd like to store polygons/linestrings"
71
71
  end
72
72
 
73
+ NoBrainer::Document::Types.load_type_extensions(options[:type]) if options[:type]
74
+
73
75
  inject_in_layer :types do
74
76
  define_method("#{attr}=") do |value|
75
77
  begin
@@ -96,11 +98,10 @@ module NoBrainer::Document::Types
96
98
  end
97
99
  end
98
100
 
99
- require File.join(File.dirname(__FILE__), 'types', 'binary')
100
- require File.join(File.dirname(__FILE__), 'types', 'boolean')
101
- Binary = NoBrainer::Binary
102
- Boolean = NoBrainer::Boolean
103
- Geo = NoBrainer::Geo
101
+ %w(binary boolean text geo).each do |type|
102
+ require File.join(File.dirname(__FILE__), 'types', type)
103
+ const_set(type.camelize, NoBrainer.const_get(type.camelize))
104
+ end
104
105
 
105
106
  class << self
106
107
  mattr_accessor :loaded_extensions
@@ -0,0 +1,15 @@
1
+ module NoBrainer::Document::Validation::NotNull
2
+ extend ActiveSupport::Concern
3
+
4
+ module ClassMethods
5
+ def validates_not_null(*attr_names)
6
+ validates_with(NotNullValidator, _merge_attributes(attr_names))
7
+ end
8
+ end
9
+
10
+ class NotNullValidator < ActiveModel::EachValidator
11
+ def validate_each(doc, attr, value)
12
+ doc.errors.add(attr, :undefined, options) if value.nil?
13
+ end
14
+ end
15
+ end
@@ -1,4 +1,4 @@
1
- module NoBrainer::Document::Uniqueness
1
+ module NoBrainer::Document::Validation::Uniqueness
2
2
  extend ActiveSupport::Concern
3
3
 
4
4
  def _create(options={})
@@ -27,7 +27,7 @@ module NoBrainer::Document::Uniqueness
27
27
  self.class.unique_validators
28
28
  .map { |validator| validator.attributes.map { |attr| [attr, validator] } }
29
29
  .flatten(1)
30
- .select { |f, validator| validator.should_validate_uniquess_of?(self, f) }
30
+ .select { |f, validator| validator.should_validate_field?(self, f) }
31
31
  .map { |f, options| _lock_key_from_field(f) }
32
32
  .sort
33
33
  .uniq
@@ -51,7 +51,7 @@ module NoBrainer::Document::Uniqueness
51
51
 
52
52
  module ClassMethods
53
53
  def validates_uniqueness_of(*attr_names)
54
- validates_with UniquenessValidator, _merge_attributes(attr_names)
54
+ validates_with(UniquenessValidator, _merge_attributes(attr_names))
55
55
  end
56
56
 
57
57
  def inherited(subclass)
@@ -72,19 +72,20 @@ module NoBrainer::Document::Uniqueness
72
72
  end
73
73
  end
74
74
 
75
- def should_validate_uniquess_of?(doc, field)
76
- (scope + [field]).any? { |f| doc.__send__("#{f}_changed?") }
75
+ def should_validate_field?(doc, field)
76
+ doc.new_record? || (scope + [field]).any? { |f| doc.__send__("#{f}_changed?") }
77
77
  end
78
78
 
79
79
  def validate_each(doc, attr, value)
80
- return true unless should_validate_uniquess_of?(doc, attr)
81
-
82
80
  criteria = doc.root_class.unscoped.where(attr => value)
83
81
  criteria = apply_scopes(criteria, doc)
84
82
  criteria = exclude_doc(criteria, doc) if doc.persisted?
85
- is_unique = criteria.count == 0
86
- doc.errors.add(attr, :taken, options.except(:scope).merge(:value => value)) unless is_unique
87
- is_unique
83
+ doc.errors.add(attr, :taken, options.except(:scope).merge(:value => value)) unless criteria.empty?
84
+ rescue NoBrainer::Error::InvalidType
85
+ # We can't run the uniqueness validator: where() won't accept bad types
86
+ # and we have some values that don't have the right type.
87
+ # Note that it's fine to not add errors because the type validations will
88
+ # prevent the document from being saved.
88
89
  end
89
90
 
90
91
  def apply_scopes(criteria, doc)
@@ -1,8 +1,11 @@
1
1
  module NoBrainer::Document::Validation
2
+ extend NoBrainer::Autoload
2
3
  extend ActiveSupport::Concern
3
4
  include ActiveModel::Validations
4
5
  include ActiveModel::Validations::Callbacks
5
6
 
7
+ autoload_and_include :Uniqueness, :NotNull
8
+
6
9
  included do
7
10
  # We don't want before_validation returning false to halt the chain.
8
11
  define_callbacks :validation, :skip_after_callbacks_if_terminated => true,
@@ -12,7 +15,7 @@ module NoBrainer::Document::Validation
12
15
  def valid?(context=nil, options={})
13
16
  context ||= new_record? ? :create : :update
14
17
 
15
- # copy/pasted, because we need to have control on errors.clear
18
+ # XXX Monkey Patching, because we need to have control on errors.clear
16
19
  current_context, self.validation_context = validation_context, context
17
20
  errors.clear unless options[:clear_errors] == false
18
21
  run_validations!
@@ -20,15 +23,41 @@ module NoBrainer::Document::Validation
20
23
  self.validation_context = current_context
21
24
  end
22
25
 
26
+ SHORTHANDS = { :format => :format, :length => :length, :required => :presence,
27
+ :uniq => :uniqueness, :unique => :uniqueness, :in => :inclusion }
28
+
23
29
  module ClassMethods
24
30
  def _field(attr, options={})
25
31
  super
26
- validates(attr, :format => { :with => options[:format] }) if options.has_key?(:format)
27
- validates(attr, :presence => options[:required]) if options.has_key?(:required)
28
- validates(attr, :uniqueness => options[:unique]) if options.has_key?(:unique)
29
- validates(attr, :uniqueness => options[:uniq]) if options.has_key?(:uniq)
30
- validates(attr, :inclusion => {:in => options[:in]}) if options.has_key?(:in)
32
+
33
+ shorthands = SHORTHANDS
34
+ shorthands = shorthands.merge(:required => :not_null) if options[:type] == NoBrainer::Boolean
35
+ shorthands.each { |k,v| validates(attr, v => options[k]) if options.has_key?(k) }
36
+
31
37
  validates(attr, options[:validates]) if options[:validates]
38
+ validates(attr, :length => { :minimum => options[:min_length] }) if options[:min_length]
39
+ validates(attr, :length => { :maximum => options[:max_length] }) if options[:max_length]
40
+ end
41
+ end
42
+ end
43
+
44
+ class ActiveModel::EachValidator
45
+ def should_validate_field?(record, attribute)
46
+ return true unless record.is_a?(NoBrainer::Document)
47
+ return true if record.new_record?
48
+
49
+ attr_changed = "#{attribute}_changed?"
50
+ return record.respond_to?(attr_changed) ? record.__send__(attr_changed) : true
51
+ end
52
+
53
+ # XXX Monkey Patching :(
54
+ def validate(record)
55
+ attributes.each do |attribute|
56
+ next unless should_validate_field?(record, attribute) # <--- Added
57
+ value = record.read_attribute_for_validation(attribute)
58
+ next if value.is_a?(NoBrainer::Document::AtomicOps::PendingAtomic) # <--- Added
59
+ next if (value.nil? && options[:allow_nil]) || (value.blank? && options[:allow_blank])
60
+ validate_each(record, attribute, value)
32
61
  end
33
62
  end
34
63
  end
@@ -4,8 +4,8 @@ module NoBrainer::Document
4
4
  extend ActiveSupport::Concern
5
5
  extend NoBrainer::Autoload
6
6
 
7
- autoload_and_include :Core, :StoreIn, :InjectionLayer, :Attributes, :Readonly, :Validation,
8
- :Persistance, :Types, :Uniqueness, :Callbacks, :Dirty, :PrimaryKey,
7
+ autoload_and_include :Core, :StoreIn, :InjectionLayer, :Attributes, :Readonly,
8
+ :Persistance, :Validation, :Types, :Callbacks, :Dirty, :PrimaryKey,
9
9
  :Association, :Serialization, :Criteria, :Polymorphic, :Index, :Aliases,
10
10
  :MissingAttributes, :LazyFetch, :AtomicOps
11
11
 
@@ -5,25 +5,13 @@ module NoBrainer::Error
5
5
  class ChildrenExist < RuntimeError; end
6
6
  class CannotUseIndex < RuntimeError; end
7
7
  class MissingIndex < RuntimeError; end
8
- class InvalidType < RuntimeError; end
9
8
  class AssociationNotPersisted < RuntimeError; end
10
9
  class ReadonlyField < RuntimeError; end
11
10
  class MissingAttribute < RuntimeError; end
12
11
  class UnknownAttribute < RuntimeError; end
13
12
  class AtomicBlock < RuntimeError; end
14
-
15
- class CannotReadAtomic < RuntimeError
16
- attr_accessor :instance, :field, :value
17
- def initialize(instance, field, value)
18
- @instance = instance
19
- @field = field
20
- @value = value
21
- end
22
-
23
- def message
24
- "Cannot read #{field}, atomic operations are pending"
25
- end
26
- end
13
+ class LostLock < RuntimeError; end
14
+ class LockUnavailable < RuntimeError; end
27
15
 
28
16
  class DocumentInvalid < RuntimeError
29
17
  attr_accessor :instance
@@ -37,23 +25,32 @@ module NoBrainer::Error
37
25
  end
38
26
 
39
27
  class InvalidType < RuntimeError
40
- attr_accessor :attr_name, :value, :type
28
+ attr_accessor :model, :attr_name, :value, :type, :error
41
29
  def initialize(options={})
42
- @attr_name = options[:attr_name]
43
- @value = options[:value]
44
- @type = options[:type]
30
+ update(options)
31
+ end
32
+
33
+ def update(options={})
34
+ options.assert_valid_keys(:model, :attr_name, :type, :value, :error)
35
+ options.each { |k,v| instance_variable_set("@#{k}", v) }
45
36
  end
46
37
 
47
38
  def human_type_name
48
39
  type.to_s.underscore.humanize.downcase
49
40
  end
50
41
 
42
+ def error
43
+ # dup because errors.add eventually .delete() on our option.
44
+ @error.nil? ? (type && { :type => human_type_name }) : @error.dup
45
+ end
46
+
51
47
  def message
52
- if attr_name && type && value
53
- "#{attr_name} should be used with a #{human_type_name}. Got `#{value}` (#{value.class})"
54
- else
55
- super
56
- end
48
+ return super unless model && attr_name && error
49
+ value = self.value
50
+ mock = model.allocate
51
+ mock.singleton_class.send(:define_method, :read_attribute_for_validation) { |_| value }
52
+ mock.errors.add(attr_name, :invalid_type, error)
53
+ mock.errors.full_messages.first
57
54
  end
58
55
  end
59
56
 
@@ -3,3 +3,4 @@ en:
3
3
  messages:
4
4
  taken: "is already taken"
5
5
  invalid_type: "should be a %{type}"
6
+ undefined: "must be defined"
@@ -0,0 +1,114 @@
1
+ require 'digest/sha1'
2
+
3
+ class NoBrainer::Lock
4
+ include NoBrainer::Document
5
+
6
+ store_in :table => 'nobrainer_locks'
7
+
8
+ # Since PKs are limited to 127 characters, we can't use the user's key as a PK
9
+ # as it could be arbitrarily long.
10
+ field :key_hash, :type => String, :primary_key => true, :default => ->{ Digest::SHA1.base64digest(key) }
11
+ field :key, :type => String
12
+ field :token, :type => String
13
+ field :expires_at, :type => Time
14
+
15
+ # We always use a new token, even when reading from the DB, because that's
16
+ # what represent our instance.
17
+ after_initialize { self.token = NoBrainer::Document::PrimaryKey::Generator.generate }
18
+
19
+ scope :expired, where(:expires_at.lt(RethinkDB::RQL.new.now))
20
+
21
+ def initialize(key, options={})
22
+ return super if options[:from_db]
23
+
24
+ key = case key
25
+ when Symbol then key.to_s
26
+ when String then key
27
+ else raise ArgumentError
28
+ end
29
+
30
+ super(options.merge(:key => key))
31
+ end
32
+
33
+ def lock(options={}, &block)
34
+ if block
35
+ lock(options)
36
+ return block.call.tap { unlock }
37
+ end
38
+
39
+ options.assert_valid_keys(:expire, :timeout)
40
+ timeout = NoBrainer::Config.lock_options.merge(options)[:timeout]
41
+ sleep_amount = 0.1
42
+
43
+ start_at = Time.now
44
+ while Time.now - start_at < timeout
45
+ return if try_lock(options.select { |k,_| k == :expire })
46
+ sleep(sleep_amount)
47
+ sleep_amount = [1, sleep_amount * 2].min
48
+ end
49
+
50
+ raise NoBrainer::Error::LockUnavailable.new("Lock on `#{key}' unavailable")
51
+ end
52
+
53
+ def try_lock(options={})
54
+ options.assert_valid_keys(:expire)
55
+ raise "Lock instance `#{key}' already locked" if @locked
56
+
57
+ set_expiration(options)
58
+
59
+ result = NoBrainer.run do |r|
60
+ selector.replace do |doc|
61
+ r.branch(doc.eq(nil).or(doc[:expires_at] < r.now),
62
+ self.attributes, doc)
63
+ end
64
+ end
65
+
66
+ return @locked = (result['inserted'] + result['replaced']) == 1
67
+ end
68
+
69
+ def unlock
70
+ raise "Lock instance `#{key}' not locked" unless @locked
71
+
72
+ result = NoBrainer.run do |r|
73
+ selector.replace do |doc|
74
+ r.branch(doc[:token].eq(self.token),
75
+ nil, doc)
76
+ end
77
+ end
78
+
79
+ @locked = false
80
+ raise NoBrainer::Error::LostLock.new("Lost lock on `#{key}'") unless result['deleted'] == 1
81
+ end
82
+
83
+ def refresh(options={})
84
+ options.assert_valid_keys(:expire)
85
+ raise "Lock instance `#{key}' not locked" unless @locked
86
+
87
+ set_expiration(options)
88
+
89
+ result = NoBrainer.run do |r|
90
+ selector.update do |doc|
91
+ r.branch(doc[:token].eq(self.token),
92
+ { :expires_at => self.expires_at }, nil)
93
+ end
94
+ end
95
+
96
+ # Note: If we are too quick, expires_at may not change, and the returned
97
+ # 'replaced' won't be 1. We'll generate a spurious error. This is very
98
+ # unlikely to happen and should not harmful.
99
+ unless result['replaced'] == 1
100
+ @locked = false
101
+ raise NoBrainer::Error::LostLock.new("Lost lock on `#{key}'")
102
+ end
103
+ end
104
+
105
+ private
106
+
107
+ def set_expiration(options)
108
+ expire = NoBrainer::Config.lock_options.merge(options)[:expire]
109
+ self.expires_at = RethinkDB::RQL.new.now + expire
110
+ end
111
+
112
+ def save?; raise; end
113
+ def delete; raise; end
114
+ end
@@ -10,7 +10,6 @@ class NoBrainer::QueryRunner::DatabaseOnDemand < NoBrainer::QueryRunner::Middlew
10
10
  end
11
11
 
12
12
  def handle_database_on_demand_exception?(env, e)
13
- (NoBrainer::Config.auto_create_databases || env[:auto_create_databases]) &&
14
13
  e.message =~ /^Database `(.+)` does not exist\.$/ && $1
15
14
  end
16
15
 
@@ -11,7 +11,7 @@ class NoBrainer::QueryRunner::MissingIndex < NoBrainer::QueryRunner::Middleware
11
11
  index = model.indexes.values.select { |i| i.aliased_name == index_name.to_sym }.first if model
12
12
  index_name = index.name if index
13
13
 
14
- if model.try(:pk_name).try(:to_s) == index_name
14
+ if model.try(:pk_name).try(:to_s) == index_name.to_s
15
15
  err_msg = "Please update the primary key `#{index_name}` in the table `#{database_name}.#{table_name}`."
16
16
  else
17
17
  err_msg = "Please run `NoBrainer.sync_indexes' or `rake nobrainer:sync_indexes' to create the index `#{index_name}`"
@@ -30,9 +30,6 @@ class NoBrainer::QueryRunner::RunOptions < NoBrainer::QueryRunner::Middleware
30
30
 
31
31
  env[:criteria] = env[:options].delete(:criteria)
32
32
 
33
- env[:auto_create_tables] = env[:options].delete(:auto_create_tables)
34
- env[:auto_create_databases] = env[:options].delete(:auto_create_databases)
35
-
36
33
  @runner.call(env)
37
34
  end
38
35
  end
@@ -10,15 +10,14 @@ class NoBrainer::QueryRunner::TableOnDemand < NoBrainer::QueryRunner::Middleware
10
10
  end
11
11
 
12
12
  def handle_table_on_demand_exception?(env, e)
13
- (NoBrainer::Config.auto_create_tables || env[:auto_create_tables]) &&
14
13
  e.message =~ /^Table `(.+)\.(.+)` does not exist\.$/ && [$1, $2]
15
14
  end
16
15
 
17
16
  private
18
17
 
19
18
  def auto_create_table(env, database_name, table_name)
20
- model = NoBrainer::Document::Index::MetaStore if table_name == 'nobrainer_index_meta'
21
- model ||= NoBrainer::Document.all.select { |m| m.table_name == table_name }.first
19
+ model ||= NoBrainer::Document::Core._all.select { |m| m.table_name == table_name }.first
20
+ model ||= NoBrainer::Document::Core._all_nobrainer.select { |m| m.table_name == table_name }.first
22
21
 
23
22
  if model.nil?
24
23
  raise "Auto table creation is not working for `#{database_name}.#{table_name}` -- Can't find the corresponding model."
@@ -27,8 +27,4 @@ module NoBrainer::RQL
27
27
  :read
28
28
  end
29
29
  end
30
-
31
- def is_table?(rql)
32
- rql.body.first == TABLE
33
- end
34
30
  end
data/lib/nobrainer.rb CHANGED
@@ -13,7 +13,7 @@ module NoBrainer
13
13
 
14
14
  # We eager load things that could be loaded when handling the first web request.
15
15
  # Code that is loaded through the DSL of NoBrainer should not be eager loaded.
16
- autoload :Document, :IndexManager, :Loader, :Fork, :Geo
16
+ autoload :Document, :IndexManager, :Loader, :Fork, :Geo, :Lock
17
17
  eager_autoload :Config, :Connection, :ConnectionManager, :Error,
18
18
  :QueryRunner, :Criteria, :RQL
19
19
 
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.20.0
4
+ version: 0.22.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: 2014-12-03 00:00:00.000000000 Z
11
+ date: 2015-03-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rethinkdb
@@ -100,14 +100,15 @@ files:
100
100
  - lib/no_brainer/criteria/core.rb
101
101
  - lib/no_brainer/criteria/count.rb
102
102
  - lib/no_brainer/criteria/delete.rb
103
+ - lib/no_brainer/criteria/eager_load.rb
103
104
  - lib/no_brainer/criteria/enumerable.rb
104
105
  - lib/no_brainer/criteria/extend.rb
106
+ - lib/no_brainer/criteria/find.rb
105
107
  - lib/no_brainer/criteria/first.rb
106
108
  - lib/no_brainer/criteria/index.rb
107
109
  - lib/no_brainer/criteria/limit.rb
108
110
  - lib/no_brainer/criteria/order_by.rb
109
111
  - lib/no_brainer/criteria/pluck.rb
110
- - lib/no_brainer/criteria/preload.rb
111
112
  - lib/no_brainer/criteria/raw.rb
112
113
  - lib/no_brainer/criteria/scope.rb
113
114
  - lib/no_brainer/criteria/update.rb
@@ -149,13 +150,16 @@ files:
149
150
  - lib/no_brainer/document/types/boolean.rb
150
151
  - lib/no_brainer/document/types/date.rb
151
152
  - lib/no_brainer/document/types/float.rb
153
+ - lib/no_brainer/document/types/geo.rb
152
154
  - lib/no_brainer/document/types/integer.rb
153
155
  - lib/no_brainer/document/types/set.rb
154
156
  - lib/no_brainer/document/types/string.rb
155
157
  - lib/no_brainer/document/types/symbol.rb
158
+ - lib/no_brainer/document/types/text.rb
156
159
  - lib/no_brainer/document/types/time.rb
157
- - lib/no_brainer/document/uniqueness.rb
158
160
  - lib/no_brainer/document/validation.rb
161
+ - lib/no_brainer/document/validation/not_null.rb
162
+ - lib/no_brainer/document/validation/uniqueness.rb
159
163
  - lib/no_brainer/error.rb
160
164
  - lib/no_brainer/fork.rb
161
165
  - lib/no_brainer/geo.rb
@@ -166,6 +170,7 @@ files:
166
170
  - lib/no_brainer/geo/polygon.rb
167
171
  - lib/no_brainer/loader.rb
168
172
  - lib/no_brainer/locale/en.yml
173
+ - lib/no_brainer/lock.rb
169
174
  - lib/no_brainer/query_runner.rb
170
175
  - lib/no_brainer/query_runner/connection_lock.rb
171
176
  - lib/no_brainer/query_runner/database_on_demand.rb
@@ -1,44 +0,0 @@
1
- module NoBrainer::Criteria::Preload
2
- extend ActiveSupport::Concern
3
-
4
- included { criteria_option :preload, :merge_with => :append_array }
5
-
6
- def preload(*values)
7
- chain({:preload => values}, :copy_cache_from => self)
8
- end
9
-
10
- def merge!(criteria, options={})
11
- super.tap do
12
- # XXX Not pretty hack
13
- if criteria.options[:preload].present? && criteria.cached?
14
- perform_preloads(@cache)
15
- end
16
- end
17
- end
18
-
19
- def each(options={}, &block)
20
- return super unless should_preloads? && !options[:no_preloading] && block
21
-
22
- docs = []
23
- super(options.merge(:no_preloading => true)) { |doc| docs << doc }
24
- perform_preloads(docs)
25
- docs.each(&block)
26
- self
27
- end
28
-
29
- private
30
-
31
- def should_preloads?
32
- @options[:preload].present? && !raw?
33
- end
34
-
35
- def get_one(criteria)
36
- super.tap { |doc| perform_preloads([doc]) }
37
- end
38
-
39
- def perform_preloads(docs)
40
- if should_preloads? && docs.present?
41
- NoBrainer::Document::Association::EagerLoader.new.eager_load(docs, @options[:preload])
42
- end
43
- end
44
- end