nobrainer 0.25.1 → 0.26.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 71e9e6216a8508d483d0c0769b6d8f5137b5f2c2
4
- data.tar.gz: 91cc415c1d35b3120fc94edfc322bdc30652aa30
3
+ metadata.gz: 22202d66d5f511c228b92b0a93df97628dd2ad6d
4
+ data.tar.gz: 28b596c4b83b83300add95b5f9971e4a3c9ceaf8
5
5
  SHA512:
6
- metadata.gz: b4a4656ab19c63e12e194b3c90dd7f25ffc806cfefee029a352e22deccca5908029bf06f14af097d8ebd069ef5eb0a923550d7411dc520fdb2fa8ef2e34378d6
7
- data.tar.gz: 37f77aef1ca56aeda705659162bab344f4c1e6495ea0c9fe5682ac7a3276eaee642b9313153ecbb80caf839054a499db19c3dd20eb144820ea0a9a97cf1e7f50
6
+ metadata.gz: df558fdce2a60deee0e500766a7963769ea6514fb1f97d6129c7d49eb66579f3b45990d9dca0b2506e0e8bb55940a826d1acf33e97233b8162cd4b53ec377862
7
+ data.tar.gz: 59ef60554676a4eff6919a3168d91803a6c11897cfa7073d52da262c4047640d7de6879a062c086994ea0a6f7fec4e56804ce6b46f444a86777c8151bbc667f5
@@ -11,9 +11,29 @@ module NoBrainer::ConnectionManager
11
11
  end
12
12
  end
13
13
 
14
+ def warn_for_other_orms
15
+ if defined?(ActiveRecord) && NoBrainer::Config.warn_on_active_record
16
+ STDERR.puts "[NoBrainer] ActiveRecord is loaded which is probably not what you want."
17
+ STDERR.puts "[NoBrainer] Follow the instructions on http://nobrainer.io/docs/configuration/#removing_activerecord"
18
+ STDERR.puts "[NoBrainer] Configure NoBrainer with 'config.warn_on_active_record = false' to disable with warning."
19
+ end
20
+
21
+ if defined?(Mongoid)
22
+ STDERR.puts "[NoBrainer] WARNING: Mongoid is loaded, and we conflict on the symbol decorations"
23
+ STDERR.puts "[NoBrainer] They are used in queries such as Model.where(:tags.in => ['fun', 'stuff'])"
24
+ STDERR.puts "[NoBrainer] This is a problem!"
25
+ end
26
+ end
27
+
14
28
  def get_new_connection
15
29
  url = NoBrainer::Config.rethinkdb_url
16
30
  raise "Please specify a database connection to RethinkDB" unless url
31
+
32
+ # We don't want to warn on "rails g nobrainer:install", but because it's
33
+ # hard to check when the generator is running because of spring as it wipes
34
+ # ARGV. So we check for other ORMs during the connection instantiation.
35
+ warn_for_other_orms
36
+
17
37
  NoBrainer::Connection.new(url)
18
38
  end
19
39
 
@@ -56,14 +56,20 @@ module NoBrainer::Document::AtomicOps
56
56
 
57
57
  def compile_rql_value(rql_doc)
58
58
  field = @instance.class.lookup_field_alias(@field)
59
- value = @is_user_value ? RethinkDB::RQL.new.expr(@value) : rql_doc[field]
59
+ if @is_user_value
60
+ casted_value = @instance.class.cast_model_to_db_for(@field, @value)
61
+ value = RethinkDB::RQL.new.expr(casted_value)
62
+ else
63
+ value = rql_doc[field]
64
+ end
60
65
  value = value.default(default_value) if default_value
61
66
  @ops.reduce(value) { |v, (method, a, b)| v.__send__(method, *a, &b) }
62
67
  end
63
68
 
64
69
  def modify_source!
65
- unless @instance._is_attribute_touched?(@field)
66
- @instance.write_attribute(@field, self)
70
+ if (@is_user_value && @instance.instance_eval { @_attributes[@field].equal?(@value) }) ||
71
+ !@instance._is_attribute_touched?(@field)
72
+ @instance._write_attribute(@field, self)
67
73
  end
68
74
  end
69
75
  end
@@ -1,10 +1,11 @@
1
1
  module NoBrainer::Document::Dirty
2
2
  extend ActiveSupport::Concern
3
- # We need to save the changes as seen through read_attribute because
4
- # the user sees attributes through the read_attribute getters.
5
- # But we want to detect changes based on @_attributes to track
6
- # things like undefined -> nil. Going through the getters will
7
- # not give us that.
3
+ # 1) We should save the changes as seen through read_attribute, because the
4
+ # user sees attributes through the read_attribute getters, but it's near
5
+ # impossible because we would need to wrap the user defined getters, so we'll
6
+ # go through _read_attribute.
7
+ # 2) We want to detect changes based on @_attributes to track things like
8
+ # undefined -> nil. Going through the getters will not give us that.
8
9
 
9
10
  def _create(*args)
10
11
  super.tap { clear_dirtiness }
@@ -36,7 +37,7 @@ module NoBrainer::Document::Dirty
36
37
  def changes
37
38
  result = {}.with_indifferent_access
38
39
  @_old_attributes.each do |attr, old_value|
39
- current_value = read_attribute(attr)
40
+ current_value = _read_attribute(attr)
40
41
  if current_value != old_value || !@_old_attributes_keys.include?(attr)
41
42
  result[attr] = [old_value, current_value]
42
43
  end
@@ -49,7 +50,7 @@ module NoBrainer::Document::Dirty
49
50
  if current_value == None
50
51
  current_value = begin
51
52
  assert_access_field(attr)
52
- read_attribute(attr)
53
+ _read_attribute(attr)
53
54
  rescue NoBrainer::Error::MissingAttribute => e
54
55
  e
55
56
  end
@@ -81,7 +82,7 @@ module NoBrainer::Document::Dirty
81
82
  inject_in_layer :dirty_tracking do
82
83
  define_method("#{attr}_change") do
83
84
  if @_old_attributes.has_key?(attr)
84
- result = [@_old_attributes[attr], read_attribute(attr)]
85
+ result = [@_old_attributes[attr], _read_attribute(attr)]
85
86
  result if result.first != result.last || !@_old_attributes_keys.include?(attr)
86
87
  end
87
88
  end
@@ -91,7 +92,7 @@ module NoBrainer::Document::Dirty
91
92
  end
92
93
 
93
94
  define_method("#{attr}_was") do
94
- @_old_attributes.has_key?(attr) ? @_old_attributes[attr] : read_attribute(attr)
95
+ @_old_attributes.has_key?(attr) ? @_old_attributes[attr] : _read_attribute(attr)
95
96
  end
96
97
  end
97
98
  end
@@ -48,12 +48,22 @@ class NoBrainer::Document::Index::Synchronizer
48
48
  end
49
49
 
50
50
  def sync_indexes(options={})
51
- plan = generate_plan
52
- plan.each { |op| op.run(options) }
51
+ lock = NoBrainer::Lock.new('nobrainer:sync_indexes')
52
+
53
+ lock.synchronize do
54
+ plan = generate_plan
55
+ plan.each { |op| lock.refresh; op.run(options) }
56
+ end
57
+
53
58
  unless options[:wait] == false
54
- models = plan.map(&:index).map(&:model).uniq
55
- models.each { |model| NoBrainer.run(model.rql_table.index_wait()) }
59
+ # Waiting on all models due to possible races when performing concurrent
60
+ # sync_indexes()
61
+ @models_indexes_map.each_key do |model|
62
+ NoBrainer.run(model.rql_table.index_wait())
63
+ end
56
64
  end
65
+
66
+ true
57
67
  end
58
68
 
59
69
  class << self
@@ -1,6 +1,9 @@
1
1
  module NoBrainer::Document::Validation::Uniqueness
2
2
  extend ActiveSupport::Concern
3
3
 
4
+ # XXX we don't use read_attribute_for_validation, which goes through the user
5
+ # getters, but read internal attributes instead. It makes more sense.
6
+
4
7
  def save?(options={})
5
8
  lock_unique_fields
6
9
  super
@@ -22,7 +25,7 @@ module NoBrainer::Document::Validation::Uniqueness
22
25
  self.class.unique_validators
23
26
  .flat_map { |validator| validator.attributes.map { |attr| [attr, validator] } }
24
27
  .select { |f, validator| validator.should_validate_field?(self, f) }
25
- .map { |f, validator| [f, *validator.scope].map { |k| [k, read_attribute(k)] } }
28
+ .map { |f, validator| [f, *validator.scope].map { |k| [k, _read_attribute(k)] } }
26
29
  .map { |params| self.class._uniqueness_key_name_from_params(params) }
27
30
  .sort.each { |key| _lock_for_uniqueness_once(key) }
28
31
  end
@@ -79,7 +82,7 @@ module NoBrainer::Document::Validation::Uniqueness
79
82
  end
80
83
 
81
84
  def apply_scopes(criteria, doc)
82
- criteria.where(scope.map { |k| {k => doc.read_attribute(k)} })
85
+ criteria.where(scope.map { |k| {k => doc._read_attribute(k)} })
83
86
  end
84
87
 
85
88
  def exclude_doc(criteria, doc)
@@ -35,7 +35,7 @@ class NoBrainer::Lock
35
35
  begin
36
36
  block.call
37
37
  ensure
38
- unlock
38
+ unlock if @locked
39
39
  end
40
40
  end
41
41
 
@@ -36,9 +36,8 @@ class NoBrainer::QueryRunner::Reconnect < NoBrainer::QueryRunner::Middleware
36
36
  Errno::ECONNRESET, Errno::ETIMEDOUT, IOError
37
37
  true
38
38
  when RethinkDB::RqlRuntimeError
39
- e.message =~ /No master available/ ||
40
- e.message =~ /Master .* not available/ ||
41
- e.message =~ /Error: Connection Closed/
39
+ e.message =~ /Primary .* not available/ ||
40
+ e.message =~ /Connection.*closed/
42
41
  else
43
42
  false
44
43
  end
@@ -26,18 +26,6 @@ class NoBrainer::Railtie < Rails::Railtie
26
26
  config.after_initialize do
27
27
  NoBrainer::Config.configure unless NoBrainer::Config.configured?
28
28
 
29
- if defined?(ActiveRecord) && NoBrainer::Config.warn_on_active_record
30
- STDERR.puts "[NoBrainer] ActiveRecord is loaded which is probably not what you want."
31
- STDERR.puts "[NoBrainer] Follow the instructions on http://nobrainer.io/docs/configuration/#removing_activerecord"
32
- STDERR.puts "[NoBrainer] Configure NoBrainer with 'config.warn_on_active_record = false' to disable with warning."
33
- end
34
-
35
- if defined?(Mongoid)
36
- STDERR.puts "[NoBrainer] WARNING: Mongoid is loaded, and we conflict on the symbol decorations"
37
- STDERR.puts "[NoBrainer] They are used in queries such as Model.where(:tags.in => ['fun', 'stuff'])"
38
- STDERR.puts "[NoBrainer] This is a problem!"
39
- end
40
-
41
29
  ActionDispatch::Reloader.to_prepare do
42
30
  NoBrainer::Loader.cleanup
43
31
  end
@@ -13,19 +13,19 @@ module NoBrainer::RQL
13
13
  RethinkDB::RQL.new.new_func(&block)))
14
14
  end
15
15
 
16
- def is_write_query?(rql_query)
17
- type_of(rql_query) == :write
16
+ def is_write_query?(rql)
17
+ type_of(rql) == :write
18
18
  end
19
19
 
20
- def type_of(rql_query)
21
- case rql_query.body.first
20
+ def type_of(rql)
21
+ case rql.is_a?(RethinkDB::RQL) && rql.body.is_a?(Array) && rql.body.first
22
22
  when UPDATE, DELETE, REPLACE, INSERT
23
23
  :write
24
24
  when DB_CREATE, DB_DROP, DB_LIST, TABLE_CREATE, TABLE_DROP, TABLE_LIST, SYNC,
25
25
  INDEX_CREATE, INDEX_DROP, INDEX_LIST, INDEX_STATUS, INDEX_WAIT
26
26
  :management
27
27
  else
28
- # XXX Not sure if that's correct, but we'll be happy for logging colors.
28
+ # XXX Not necessarily correct, but we'll be happy for logging colors.
29
29
  :read
30
30
  end
31
31
  end
@@ -0,0 +1,48 @@
1
+ require "rails/generators/nobrainer/namespace_fix"
2
+ require 'rails/generators/base'
3
+
4
+ module NoBrainer::Generators
5
+ class InstallGenerator < Rails::Generators::Base
6
+ extend NoBrainer::Generators::NamespaceFix
7
+ source_root File.expand_path("../../templates", __FILE__)
8
+
9
+ desc "Disable ActiveRecord and generates ./config/initializer/nobrainer.rb"
10
+
11
+ class RequireProxy
12
+ attr_accessor :required_paths
13
+ def initialize
14
+ self.required_paths = []
15
+ end
16
+
17
+ def require(path)
18
+ self.required_paths << path
19
+ end
20
+
21
+ def resolve_require_path(path)
22
+ $:.map { |dir| File.join(dir, path) }.detect { |f| File.exists?(f) }
23
+ end
24
+ end
25
+
26
+ def expand_require_rails_all
27
+ require_proxy = RequireProxy.new
28
+ rails_all_file = require_proxy.resolve_require_path('rails/all.rb')
29
+ require_proxy.instance_eval(File.read(rails_all_file))
30
+
31
+ gsub_file('config/application.rb', %r(^require 'rails/all'$)) do
32
+ require_proxy.required_paths.map { |f| "require '#{f}'" }.join("\n")
33
+ end
34
+ end
35
+
36
+ def remove_active_record
37
+ (Dir['config/environments/*'] + ['config/application.rb']).each do |config_file|
38
+ comment_lines(config_file, /active_record/)
39
+ end
40
+ remove_file('config/database.yml')
41
+ end
42
+
43
+
44
+ def copy_initializer
45
+ template('nobrainer.rb', 'config/initializer/nobrainer.rb')
46
+ end
47
+ end
48
+ end
@@ -1,7 +1,11 @@
1
- require "rails/generators/nobrainer"
1
+ require "rails/generators/nobrainer/namespace_fix"
2
+ require 'rails/generators/named_base'
2
3
 
3
4
  module NoBrainer::Generators
4
- class ModelGenerator < Base
5
+ class ModelGenerator < Rails::Generators::NamedBase
6
+ extend NoBrainer::Generators::NamespaceFix
7
+ source_root File.expand_path("../../templates", __FILE__)
8
+
5
9
  argument(:attributes, :type => :array, default: [],
6
10
  banner: "field[:type][:index] ... field[:type][:index]")
7
11
 
@@ -10,7 +14,7 @@ module NoBrainer::Generators
10
14
  class_option :parent, :type => :string, :desc => "The parent class for the generated model"
11
15
 
12
16
  def create_model_file
13
- template "model.rb.tt", File.join("app/models", class_path, "#{file_name}.rb")
17
+ template "model.rb", File.join("app", "models", class_path, "#{file_name}.rb")
14
18
  end
15
19
 
16
20
  hook_for :test_framework
@@ -0,0 +1,15 @@
1
+ module NoBrainer::Generators
2
+ module NamespaceFix
3
+ def base_name
4
+ 'nobrainer'
5
+ end
6
+
7
+ def base_root
8
+ File.dirname(__FILE__)
9
+ end
10
+
11
+ def namespace
12
+ super.gsub(/no_brainer/, 'nobrainer')
13
+ end
14
+ end
15
+ end
@@ -7,7 +7,7 @@ class <%= class_name %><%= " < #{options[:parent].classify}" if options[:parent]
7
7
  <% end -%>
8
8
  <% attributes.reject(&:reference?).each do |attribute| -%>
9
9
  field :<%= attribute.name -%>
10
- <%= puts attribute; ", :type => #{attribute.type.to_s.classify}" if attribute.type != :object -%>
10
+ <%= ", :type => #{attribute.type.to_s.classify}" if attribute.type != :object -%>
11
11
  <%= ", :index => true" if attribute.has_index? %>
12
12
  <% end -%>
13
13
  <% attributes.select(&:reference?).each do |attribute| -%>
@@ -0,0 +1,92 @@
1
+ NoBrainer.configure do |config|
2
+ # app_name is the name of your application in lowercase.
3
+ # When using Rails, the application name is automatically inferred.
4
+ # config.app_name = config.default_app_name
5
+
6
+ # environment defaults to Rails.env for Rails apps or to the environment
7
+ # variables RUBY_ENV, RAILS_ENV, RACK_ENV, or :production.
8
+ # config.environment = config.default_environment
9
+
10
+ # The rethinkdb_url specifies the RethinkDB database connection url.
11
+ # When left unspecified, NoBrainer picks a database connection by default.
12
+ # The default is to use localhost, with a database name matching the
13
+ # application name and the environment.
14
+ # NoBrainer also reads environment variables when defined:
15
+ # * RETHINKDB_URL, RDB_URL
16
+ # * RETHINKDB_HOST, RETHINKDB_PORT, RETHINKDB_DB, RETHINKDB_AUTH
17
+ # * RDB_HOST, RDB_PORT, RDB_DB, RDB_AUTH
18
+ # config.rethinkdb_url = config.default_rethinkdb_url
19
+
20
+ # NoBrainer uses logger to emit debugging information.
21
+ # The default logger is the Rails logger if run with Rails,
22
+ # otherwise Logger.new(STDERR) with a WARN level.
23
+ # If the logger is configured with a DEBUG level,
24
+ # then each database query is emitted.
25
+ # config.logger = config.default_logger
26
+
27
+ # NoBrainer will colorize the queries if colorize_logger is true.
28
+ # Specifically, NoBrainer will colorize management RQL queries in yellow,
29
+ # write queries in red and read queries in green.
30
+ # config.colorize_logger = true
31
+
32
+ # You probably do not want to use both NoBrainer and ActiveRecord in your
33
+ # application. NoBrainer will emit a warning if you do so.
34
+ # You can turn off the warning if you want to use both.
35
+ # config.warn_on_active_record = true
36
+
37
+ # When the network connection is lost, NoBrainer can retry running a given
38
+ # query a few times before giving up. Note that this can be a problem with
39
+ # non idempotent write queries such as increments.
40
+ # Setting it to 0 disable retries during reconnections.
41
+ # The default is 1 for development or test environment, otherwise 15.
42
+ # config.max_retries_on_connection_failure = \
43
+ # config.default_max_retries_on_connection_failure
44
+
45
+ # Configures the durability for database writes.
46
+ # The default is :soft for development or test environment, otherwise :hard.
47
+ # config.durability = config.default_durability
48
+
49
+ # Persisted Strings have a configurable maximum length. To get rid of the
50
+ # length validation, you may use the Text type instead.
51
+ # config.max_string_length = 255
52
+
53
+ # user_timezone can be configured with :utc, :local, or :unchanged.
54
+ # When reading an attribute from a model which type is Time, the timezone
55
+ # of that time is translated according to this setting.
56
+ # config.user_timezone = :local
57
+
58
+ # db_timezone can be configured with :utc, :local, or :unchanged.
59
+ # When writting to the database, the timezone of Time attributes are
60
+ # translated according to this setting.
61
+ # config.db_timezone = :utc
62
+
63
+ # Default options used when compiling geo queries.
64
+ # config.geo_options => { :geo_system => 'WGS84', :unit => 'm' }
65
+
66
+ # Configures which mechanism to use in order to perform non-racy uniqueness
67
+ # validations. More about this behavior in the Distributed Locks section.
68
+ # config.distributed_lock_class = NoBrainer::Lock
69
+
70
+ # Configures the default timing lock options.
71
+ # config.lock_options = { :expire => 60, :timeout => 10 }
72
+
73
+ # Instead of using a single connection to the database, You can tell
74
+ # NoBrainer to spin up a new connection for each thread. This is
75
+ # useful for multi-threading usage such as Sidekiq.
76
+ # Call NoBrainer.disconnect before a thread exits, otherwise you will have
77
+ # a resource leak, and you will run out of connections.
78
+ # Note that this is solution is temporary, until we get a connection pool.
79
+ # config.per_thread_connection = false
80
+
81
+ # The machine id is used to generate primary keys. The default one is seeded
82
+ # with the machine IP with Socket.gethostname.
83
+ # The env variable MACHINE_ID can also be used to set the machine id.
84
+ # When using distinct machine_id, then primary keys are guaranteed to be
85
+ # generated without conflicts.
86
+ # config.machine_id = config.default_machine_id
87
+
88
+ # Criteria cache elements. For example, the result of a has_many association
89
+ # is cached. The per criteria cache is disabled if it grows too big to avoid
90
+ # out of memory issues.
91
+ # config.criteria_cache_max_entries = 10_000
92
+ end
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.25.1
4
+ version: 0.26.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-06-01 00:00:00.000000000 Z
11
+ date: 2015-06-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rethinkdb
@@ -192,9 +192,11 @@ files:
192
192
  - lib/no_brainer/railtie/database.rake
193
193
  - lib/no_brainer/rql.rb
194
194
  - lib/nobrainer.rb
195
- - lib/rails/generators/nobrainer.rb
196
- - lib/rails/generators/nobrainer/model/model_generator.rb
197
- - lib/rails/generators/nobrainer/model/templates/model.rb.tt
195
+ - lib/rails/generators/nobrainer/install_generator.rb
196
+ - lib/rails/generators/nobrainer/model_generator.rb
197
+ - lib/rails/generators/nobrainer/namespace_fix.rb
198
+ - lib/rails/generators/templates/model.rb
199
+ - lib/rails/generators/templates/nobrainer.rb
198
200
  homepage: http://nobrainer.io
199
201
  licenses:
200
202
  - LGPLv3
@@ -1,18 +0,0 @@
1
- require 'rails/generators/named_base'
2
- require 'nobrainer'
3
-
4
- module NoBrainer::Generators
5
- class Base < Rails::Generators::NamedBase
6
- def self.base_name
7
- 'nobrainer'
8
- end
9
-
10
- def self.base_root
11
- File.dirname(__FILE__)
12
- end
13
-
14
- def self.namespace
15
- super.gsub(/no_brainer/, 'nobrainer')
16
- end
17
- end
18
- end