Skip to content

Commit

Permalink
Added system table models and table configuration settings
Browse files Browse the repository at this point in the history
store_in was renamed to table_config
  • Loading branch information
nviennot committed Jul 22, 2015
1 parent bbb452a commit 9815a2d
Show file tree
Hide file tree
Showing 37 changed files with 430 additions and 156 deletions.
24 changes: 18 additions & 6 deletions lib/no_brainer/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ module NoBrainer::Config
:warn_on_active_record => { :default => ->{ true }, :valid_values => [true, false] },
:max_retries_on_connection_failure => { :default => ->{ default_max_retries_on_connection_failure } },
:durability => { :default => ->{ default_durability }, :valid_values => [:hard, :soft] },
:max_string_length => { :default => -> { 255 } },
:table_options => { :default => ->{ {:shards => 1, :replicas => 1, :write_acks => :majority} },
:valid_keys => [:shards, :replicas, :primary_replica_tag, :write_acks, :durability] },
:max_string_length => { :default => ->{ 255 } },
:user_timezone => { :default => ->{ :local }, :valid_values => [:unchanged, :utc, :local] },
:db_timezone => { :default => ->{ :utc }, :valid_values => [:unchanged, :utc, :local] },
:geo_options => { :default => ->{ {:geo_system => 'WGS84', :unit => 'm'} } },
:distributed_lock_class => { :default => ->{ "NoBrainer::Lock" } },
:lock_options => { :default => ->{ { :expire => 60, :timeout => 10 } } },
:lock_options => { :default => ->{ { :expire => 60, :timeout => 10 } }, :valid_keys => [:expire, :timeout] },
:per_thread_connection => { :default => ->{ false }, :valid_values => [true, false] },
:machine_id => { :default => ->{ default_machine_id } },
:criteria_cache_max_entries => { :default => -> { 10_000 } },
Expand Down Expand Up @@ -44,7 +46,10 @@ def geo_options=(value)
end

def assert_valid_options
SETTINGS.each { |k,v| assert_array_in(k, v[:valid_values]) if v[:valid_values] }
SETTINGS.each do |k,v|
assert_value_in(k, v[:valid_values]) if v[:valid_values]
assert_hash_keys_in(k, v[:valid_keys]) if v[:valid_keys]
end
end

def reset!
Expand All @@ -65,9 +70,16 @@ def configured?
!!@configured
end

def assert_array_in(name, values)
unless __send__(name).in?(values)
raise ArgumentError.new("Unknown configuration for #{name}: #{__send__(name)}. Valid values are: #{values.inspect}")
def assert_value_in(name, valid_values)
unless __send__(name).in?(valid_values)
raise ArgumentError.new("Invalid configuration for #{name}: #{__send__(name)}. Valid values are: #{valid_values.inspect}")
end
end

def assert_hash_keys_in(name, valid_keys)
extra_keys = __send__(name).keys - valid_keys
unless extra_keys.empty?
raise ArgumentError.new("Invalid configuration for #{name}: #{__send__(name)}. Valid keys are: #{valid_keys.inspect}")
end
end

Expand Down
14 changes: 3 additions & 11 deletions lib/no_brainer/connection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,6 @@ def raw
alias_method :connect, :raw
alias_method :disconnect, :close

[:db_create, :db_drop, :db_list, :table_create, :table_drop, :table_list].each do |cmd|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
def #{cmd}(*args)
NoBrainer.run { |r| r.#{cmd}(*args) }
end
RUBY
end

def default_db
parsed_uri[:db]
end
Expand All @@ -51,13 +43,13 @@ def current_db
end

def drop!
db_drop(current_db)['dropped'] == 1
NoBrainer.run { |r| r.db_drop(current_db) }
end

# Note that truncating each table (purge!) is much faster than dropping the database (drop!)
def purge!
table_list.each do |table_name|
# keeping the index meta store because indexes are not going away
NoBrainer.run { |r| r.table_list }.each do |table_name|
# keeping the index meta store because indexes are not going away when purging
next if table_name == NoBrainer::Document::Index::MetaStore.table_name
NoBrainer.run { |r| r.table(table_name).delete }
end
Expand Down
2 changes: 1 addition & 1 deletion lib/no_brainer/document.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ module NoBrainer::Document
extend ActiveSupport::Concern
extend NoBrainer::Autoload

autoload_and_include :Core, :StoreIn, :InjectionLayer, :Attributes, :Readonly,
autoload_and_include :Core, :TableConfig, :InjectionLayer, :Attributes, :Readonly,
:Persistance, :Callbacks, :Validation, :Types, :Dirty, :PrimaryKey,
:Association, :Serialization, :Criteria, :Polymorphic, :Index, :Aliases,
:MissingAttributes, :LazyFetch, :AtomicOps
Expand Down
19 changes: 11 additions & 8 deletions lib/no_brainer/document/attributes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,10 @@ def []=(*args); write_attribute(*args); end

def assign_defaults(options)
self.class.fields.each do |name, field_options|
next unless field_options.has_key?(:default) &&
!@_attributes.has_key?(name)
# :default => nil will not set the value to nil, but :default => ->{ nil } will.
# This is useful to unset a default value.

next if field_options[:default].nil? || @_attributes.key?(name)

if opt = options[:missing_attributes]
if (opt[:pluck] && !opt[:pluck][name]) ||
Expand Down Expand Up @@ -113,8 +115,14 @@ def inherited(subclass)
super
end

# The different between _field and field is that field can set other options
# (c.f. primary key module). _field always receive an immutable options list.
def _field(attr, options={})
# Using a layer so the user can use super when overriding these methods
options.assert_valid_keys(*VALID_FIELD_OPTIONS)
if attr.in?(RESERVED_FIELD_NAMES)
raise "The field name `:#{attr}' is reserved. Please use another one."
end

attr = attr.to_s
inject_in_layer :attributes do
define_method("#{attr}=") { |value| _write_attribute(attr, value) }
Expand All @@ -125,11 +133,6 @@ def _field(attr, options={})
def field(attr, options={})
attr = attr.to_sym

options.assert_valid_keys(*VALID_FIELD_OPTIONS)
if attr.in?(RESERVED_FIELD_NAMES)
raise "The field name `:#{attr}' is reserved. Please use another one."
end

subclass_tree.each do |subclass|
subclass.fields[attr] ||= {}
subclass.fields[attr].deep_merge!(options)
Expand Down
36 changes: 18 additions & 18 deletions lib/no_brainer/document/core.rb
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
module NoBrainer::Document::Core
extend ActiveSupport::Concern

singleton_class.class_eval do
attr_accessor :_all, :_all_nobrainer

def all
Rails.application.eager_load! if defined?(Rails.application.eager_load!)
@_all
end
end
singleton_class.class_eval { attr_accessor :_all }
self._all = []
self._all_nobrainer = []

include ActiveModel::Conversion

def to_key
# ActiveModel::Conversion stuff
[pk_value]
end

included do
# TODO test these includes
extend ActiveModel::Naming
extend ActiveModel::Translation

list_name = self.name =~ /^NoBrainer::/ ? :_all_nobrainer : :_all
NoBrainer::Document::Core.__send__(list_name) << self
NoBrainer::Document::Core._all << self unless name =~ /^NoBrainer::/
end

def self.all(options={})
(options[:types] || [:user]).map do |type|
case type
when :user
Rails.application.eager_load! if defined?(Rails.application.eager_load!)
_all
when :nobrainer
[NoBrainer::Document::Index::MetaStore, NoBrainer::Lock]
when :system
NoBrainer::System.constants
.map { |c| NoBrainer::System.const_get(c) }
.select { |m| m < NoBrainer::Document }
end
end.reduce([], &:+)
end
end
6 changes: 3 additions & 3 deletions lib/no_brainer/document/dirty.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def attribute_may_change(attr, current_value = None)
end
end

unless @_old_attributes.has_key?(attr)
unless @_old_attributes.key?(attr)
@_old_attributes[attr] = current_value.deep_dup
end
end
Expand All @@ -81,7 +81,7 @@ def _field(attr, options={})

inject_in_layer :dirty_tracking do
define_method("#{attr}_change") do
if @_old_attributes.has_key?(attr)
if @_old_attributes.key?(attr)
result = [@_old_attributes[attr], _read_attribute(attr)]
result if result.first != result.last || !@_old_attributes_keys.include?(attr)
end
Expand All @@ -92,7 +92,7 @@ def _field(attr, options={})
end

define_method("#{attr}_was") do
@_old_attributes.has_key?(attr) ? @_old_attributes[attr] : _read_attribute(attr)
@_old_attributes.key?(attr) ? @_old_attributes[attr] : _read_attribute(attr)
end
end
end
Expand Down
10 changes: 5 additions & 5 deletions lib/no_brainer/document/index/index.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
class NoBrainer::Document::Index::Index < Struct.new(
:model, :name, :aliased_name, :kind, :what, :external, :geo, :multi, :meta)

MetaStore = NoBrainer::Document::Index::MetaStore

def initialize(*args)
super

Expand Down Expand Up @@ -59,16 +57,18 @@ def create(options={})
NoBrainer::RQL.reset_lambda_var_counter
NoBrainer.run(model.rql_table.index_create(aliased_name, opt, &rql_proc))

MetaStore.create(:table_name => model.table_name, :index_name => aliased_name,
:rql_function => serialized_rql_proc)
NoBrainer::Document::Index::MetaStore.create(
:table_name => model.table_name, :index_name => aliased_name,
:rql_function => serialized_rql_proc)
end

def delete(options={})
show_op(:delete, options)

NoBrainer.run(model.rql_table.index_drop(aliased_name))

MetaStore.where(:table_name => model.table_name, :index_name => aliased_name).delete_all
NoBrainer::Document::Index::MetaStore.where(
:table_name => model.table_name, :index_name => aliased_name).delete_all
end

def update(wanted_index, options={})
Expand Down
2 changes: 1 addition & 1 deletion lib/no_brainer/document/index/meta_store.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class NoBrainer::Document::Index::MetaStore

default_scope ->{ order_by(:created_at) }

store_in :table => 'nobrainer_index_meta'
table_config :name => 'nobrainer_index_meta'

field :table_name, :type => String, :required => true
field :index_name, :type => String, :required => true
Expand Down
22 changes: 5 additions & 17 deletions lib/no_brainer/document/index/synchronizer.rb
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
class NoBrainer::Document::Index::Synchronizer
Index = NoBrainer::Document::Index::Index
MetaStore = NoBrainer::Document::Index::MetaStore

def initialize(models)
@models_indexes_map = Hash[models.map do |model|
[model, model.indexes.values.reject { |index| index.name == model.pk_name }]
end]
end

def meta_store
@meta_store ||= MetaStore.to_a
@meta_store ||= NoBrainer::Document::Index::MetaStore.to_a
end

class Op < Struct.new(:index, :op, :args)
Expand All @@ -21,7 +18,8 @@ def run(options={})
def _generate_plan_for(model, wanted_indexes)
current_indexes = NoBrainer.run(model.rql_table.index_status).map do |s|
meta = meta_store.select { |i| i.table_name == model.table_name && i.index_name == s['index'] }.last
Index.new(model, s['index'], s['index'], nil, nil, nil, s['geo'], s['multi'], meta)
NoBrainer::Document::Index::Index.new(
model, s['index'], s['index'], nil, nil, nil, s['geo'], s['multi'], meta)
end

all_aliased_names = (wanted_indexes + current_indexes).map(&:aliased_name).uniq
Expand Down Expand Up @@ -51,26 +49,16 @@ def sync_indexes(options={})
lock = NoBrainer::Lock.new('nobrainer:sync_indexes')

lock.synchronize do
plan = generate_plan
plan.each { |op| lock.refresh; op.run(options) }
generate_plan.each { |op| op.run(options) }
end

unless options[:wait] == false
# Waiting on all models due to possible races when performing concurrent
# sync_indexes()
# Waiting on all models due to possible races
@models_indexes_map.each_key do |model|
NoBrainer.run(model.rql_table.index_wait())
end
end

true
end

class << self
def instance
new(NoBrainer::Document.all)
end

delegate :sync_indexes, :to => :instance
end
end
22 changes: 14 additions & 8 deletions lib/no_brainer/document/primary_key.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module NoBrainer::Document::PrimaryKey
autoload :Generator

extend ActiveSupport::Concern
include ActiveModel::Conversion

DEFAULT_PK_NAME = :id

Expand All @@ -27,6 +28,11 @@ def cache_key
"#{self.class.table_name}/#{pk_value}"
end

def to_key
# ActiveModel::Conversion
[pk_value]
end

module ClassMethods
def define_default_pk
class_variable_set(:@@pk_name, nil)
Expand All @@ -51,19 +57,19 @@ def _field(attr, options={})
end

def field(attr, options={})
if options[:primary_key]
if attr.to_sym == pk_name || options[:primary_key]
options = options.merge(:readonly => true) if options[:readonly].nil?
options = options.merge(:index => true)

if options[:default].nil?
# TODO Maybe we should let the user configure the pk generator
default_pk_generator = NoBrainer::Document::PrimaryKey::Generator
if options[:type].in?([default_pk_generator.field_type, nil])
options[:type] = default_pk_generator.field_type
options[:default] = ->{ default_pk_generator.generate }
end
# TODO Maybe we should let the user configure the pk generator
pk_generator = NoBrainer::Document::PrimaryKey::Generator

if options[:type].in?([pk_generator.field_type, nil]) && !options.key?(:default)
options[:type] = pk_generator.field_type
options[:default] = ->{ pk_generator.generate }
end
end

super
end

Expand Down
33 changes: 0 additions & 33 deletions lib/no_brainer/document/store_in.rb

This file was deleted.

Loading

0 comments on commit 9815a2d

Please sign in to comment.