nobrainer 0.8.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 (61) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.md +7 -0
  3. data/README.md +6 -0
  4. data/lib/no_brainer/autoload.rb +14 -0
  5. data/lib/no_brainer/config.rb +61 -0
  6. data/lib/no_brainer/connection.rb +53 -0
  7. data/lib/no_brainer/criteria.rb +20 -0
  8. data/lib/no_brainer/criteria/chainable/core.rb +67 -0
  9. data/lib/no_brainer/criteria/chainable/limit.rb +31 -0
  10. data/lib/no_brainer/criteria/chainable/order_by.rb +76 -0
  11. data/lib/no_brainer/criteria/chainable/raw.rb +25 -0
  12. data/lib/no_brainer/criteria/chainable/scope.rb +41 -0
  13. data/lib/no_brainer/criteria/chainable/where.rb +198 -0
  14. data/lib/no_brainer/criteria/termination/cache.rb +71 -0
  15. data/lib/no_brainer/criteria/termination/count.rb +19 -0
  16. data/lib/no_brainer/criteria/termination/delete.rb +11 -0
  17. data/lib/no_brainer/criteria/termination/eager_loading.rb +64 -0
  18. data/lib/no_brainer/criteria/termination/enumerable.rb +24 -0
  19. data/lib/no_brainer/criteria/termination/first.rb +25 -0
  20. data/lib/no_brainer/criteria/termination/inc.rb +14 -0
  21. data/lib/no_brainer/criteria/termination/update.rb +13 -0
  22. data/lib/no_brainer/database.rb +41 -0
  23. data/lib/no_brainer/decorated_symbol.rb +15 -0
  24. data/lib/no_brainer/document.rb +18 -0
  25. data/lib/no_brainer/document/association.rb +41 -0
  26. data/lib/no_brainer/document/association/belongs_to.rb +64 -0
  27. data/lib/no_brainer/document/association/core.rb +64 -0
  28. data/lib/no_brainer/document/association/has_many.rb +68 -0
  29. data/lib/no_brainer/document/attributes.rb +124 -0
  30. data/lib/no_brainer/document/core.rb +20 -0
  31. data/lib/no_brainer/document/criteria.rb +62 -0
  32. data/lib/no_brainer/document/dirty.rb +88 -0
  33. data/lib/no_brainer/document/dynamic_attributes.rb +12 -0
  34. data/lib/no_brainer/document/id.rb +49 -0
  35. data/lib/no_brainer/document/index.rb +102 -0
  36. data/lib/no_brainer/document/injection_layer.rb +12 -0
  37. data/lib/no_brainer/document/persistance.rb +124 -0
  38. data/lib/no_brainer/document/polymorphic.rb +43 -0
  39. data/lib/no_brainer/document/serialization.rb +9 -0
  40. data/lib/no_brainer/document/store_in.rb +33 -0
  41. data/lib/no_brainer/document/timestamps.rb +18 -0
  42. data/lib/no_brainer/document/validation.rb +35 -0
  43. data/lib/no_brainer/error.rb +10 -0
  44. data/lib/no_brainer/fork.rb +14 -0
  45. data/lib/no_brainer/index_manager.rb +6 -0
  46. data/lib/no_brainer/loader.rb +5 -0
  47. data/lib/no_brainer/locale/en.yml +4 -0
  48. data/lib/no_brainer/query_runner.rb +37 -0
  49. data/lib/no_brainer/query_runner/connection.rb +17 -0
  50. data/lib/no_brainer/query_runner/database_on_demand.rb +26 -0
  51. data/lib/no_brainer/query_runner/driver.rb +8 -0
  52. data/lib/no_brainer/query_runner/logger.rb +29 -0
  53. data/lib/no_brainer/query_runner/run_options.rb +34 -0
  54. data/lib/no_brainer/query_runner/table_on_demand.rb +44 -0
  55. data/lib/no_brainer/query_runner/write_error.rb +28 -0
  56. data/lib/no_brainer/railtie.rb +36 -0
  57. data/lib/no_brainer/railtie/database.rake +34 -0
  58. data/lib/no_brainer/util.rb +23 -0
  59. data/lib/no_brainer/version.rb +3 -0
  60. data/lib/nobrainer.rb +59 -0
  61. metadata +152 -0
@@ -0,0 +1,34 @@
1
+ class NoBrainer::QueryRunner::RunOptions < NoBrainer::QueryRunner::Middleware
2
+ # XXX NoBrainer::Database#drop() uses Thread.current[:nobrainer_options]
3
+ # We should fix that hack.
4
+
5
+ def self.with_database(db_name, &block)
6
+ with_options(:db => db_name, &block)
7
+ end
8
+
9
+ def self.with_options(options={}, &block)
10
+ old_options = Thread.current[:nobrainer_options]
11
+ Thread.current[:nobrainer_options] = (old_options || {}).merge(options.symbolize_keys)
12
+ block.call if block
13
+ ensure
14
+ Thread.current[:nobrainer_options] = old_options
15
+ end
16
+
17
+ def call(env)
18
+ env[:options].symbolize_keys!
19
+ if Thread.current[:nobrainer_options]
20
+ env[:options] = env[:options].reverse_merge(Thread.current[:nobrainer_options])
21
+ end
22
+
23
+ if NoBrainer::Config.durability.to_s != 'hard'
24
+ env[:options] = env[:options].reverse_merge(:durability => NoBrainer::Config.durability)
25
+ end
26
+
27
+ if env[:options][:db] && !env[:options][:db].is_a?(RethinkDB::RQL)
28
+ env[:db_name] = env[:options][:db].to_s
29
+ env[:options][:db] = RethinkDB::RQL.new.db(env[:db_name])
30
+ end
31
+
32
+ @runner.call(env)
33
+ end
34
+ end
@@ -0,0 +1,44 @@
1
+ class NoBrainer::QueryRunner::TableOnDemand < NoBrainer::QueryRunner::Middleware
2
+ def call(env)
3
+ @runner.call(env)
4
+ rescue RuntimeError => e
5
+ if NoBrainer::Config.auto_create_tables &&
6
+ e.message =~ /^Table `(.+)` does not exist\.$/
7
+ auto_create_table(env, $1)
8
+ retry
9
+ end
10
+ raise
11
+ end
12
+
13
+ private
14
+
15
+ def auto_create_table(env, table_name)
16
+ if env[:auto_create_table] == table_name
17
+ raise "Auto table creation is not working with #{table_name}"
18
+ end
19
+ env[:auto_create_table] = table_name
20
+
21
+ # FIXME This stinks.
22
+ database_names = find_db_names(env[:query])
23
+ case database_names.size
24
+ when 0 then NoBrainer.table_create(table_name)
25
+ when 1 then NoBrainer.with_database(database_names.first) { NoBrainer.table_create(table_name) }
26
+ else raise "Ambiguous database name for creation on demand: #{database_names}"
27
+ end
28
+ rescue RuntimeError => e
29
+ # We might have raced with another table create
30
+ raise unless e.message =~ /Table `#{table_name}` already exists/
31
+ end
32
+
33
+ def find_db_names(terms)
34
+ terms = terms.body.args if terms.is_a?(RethinkDB::RQL)
35
+ terms.map do |term|
36
+ next unless term.is_a?(Term)
37
+ if term.type == Term::TermType::DB
38
+ term.args.first.datum.r_str
39
+ else
40
+ find_db_names(term.args)
41
+ end
42
+ end.flatten.uniq
43
+ end
44
+ end
@@ -0,0 +1,28 @@
1
+ class NoBrainer::QueryRunner::WriteError < NoBrainer::QueryRunner::Middleware
2
+ def call(env)
3
+ write_query = NoBrainer::Util.is_write_query?(env[:query])
4
+ @runner.call(env).tap do |result|
5
+ # TODO Fix rethinkdb driver: Their classes Term, Query, Response are
6
+ # not scoped to the RethinkDB module! (that would prevent a user from
7
+ # creating a Response model for example).
8
+
9
+ if write_query && (result['errors'].to_i != 0 || result['skipped'].to_i != 0)
10
+ raise_write_error(env, result['first_error'])
11
+ end
12
+ end
13
+ rescue RethinkDB::RqlRuntimeError => e
14
+ raise unless write_query
15
+
16
+ error_msg = e.message.split("\nBacktrace").first
17
+ error_msg = "Non existent document" if e.message =~ /Expected type OBJECT but found NULL/
18
+ raise_write_error(env, error_msg)
19
+ end
20
+
21
+ private
22
+
23
+ def raise_write_error(env, error_msg)
24
+ error_msg ||= "Unknown error"
25
+ error_msg += "\nQuery was: #{env[:query].inspect[0..1000]}"
26
+ raise NoBrainer::Error::DocumentNotSaved, error_msg
27
+ end
28
+ end
@@ -0,0 +1,36 @@
1
+ require "nobrainer"
2
+ require "rails"
3
+
4
+ class NoBrainer::Railtie < Rails::Railtie
5
+ config.action_dispatch.rescue_responses.merge!(
6
+ "NoBrainer::Errors::DocumentNotFound" => :not_found,
7
+ "NoBrainer::Errors::DocumentInvalid" => :unprocessable_entity,
8
+ "NoBrainer::Errors::DocumentNotSaved" => :unprocessable_entity,
9
+ )
10
+
11
+ rake_tasks do
12
+ load "no_brainer/railtie/database.rake"
13
+ end
14
+
15
+ config.after_initialize do
16
+ NoBrainer::Config.configure unless NoBrainer::Config.configured?
17
+
18
+ if defined?(ActiveRecord) && NoBrainer::Config.warn_on_active_record
19
+ STDERR.puts "[NoBrainer] WARNING: ActiveRecord is loaded which is probably not what you want."
20
+ STDERR.puts "[NoBrainer] Follow the instructions on http://todo/ to learn how to remove ActiveRecord."
21
+ STDERR.puts "[NoBrainer] Configure NoBrainer with 'config.warn_on_active_record = false' to disable with warning."
22
+ end
23
+
24
+ if defined?(Mongoid)
25
+ STDERR.puts "[NoBrainer] WARNING: Mongoid is loaded, and we conflict on the symbol decorations"
26
+ STDERR.puts "[NoBrainer] They are used in queries like Model.where(:tags.in => ['fun', 'stuff'])"
27
+ STDERR.puts "[NoBrainer] This is a problem!"
28
+ end
29
+
30
+ ActionDispatch::Reloader.to_cleanup do
31
+ NoBrainer::Loader.cleanup
32
+ end
33
+ end
34
+
35
+ #config.eager_load_namespaces << NoBrainer
36
+ end
@@ -0,0 +1,34 @@
1
+ namespace :db do
2
+ desc 'Drop the database'
3
+ task :drop => :environment do
4
+ NoBrainer.drop!
5
+ end
6
+
7
+ desc 'Load seed data from db/seeds.rb'
8
+ task :seed => :environment do
9
+ Rails.application.load_seed
10
+ end
11
+
12
+ desc 'Create and drop indexes on the database'
13
+ task :update_indexes => :environment do
14
+ NoBrainer.update_indexes(:verbose => true)
15
+ end
16
+
17
+ task :update_indexes_quiet => :environment do
18
+ NoBrainer.update_indexes
19
+ end
20
+
21
+ desc 'Equivalent to db:update_indexes + db:seed'
22
+ task :setup => [ :update_indexes_quiet, :seed ]
23
+
24
+ desc 'Equivalent to db:drop + db:setup'
25
+ task :reset => [ :drop, :setup ]
26
+
27
+ task :create => :environment do
28
+ # noop
29
+ end
30
+
31
+ task :migrate => :environment do
32
+ # noop
33
+ end
34
+ end
@@ -0,0 +1,23 @@
1
+ module NoBrainer::Util
2
+ def self.is_write_query?(rql_query)
3
+ rql_type(rql_query) == :write
4
+ end
5
+
6
+ def self.rql_type(rql_query)
7
+ case rql_query.body.type
8
+ when Term::TermType::UPDATE, Term::TermType::DELETE,
9
+ Term::TermType::REPLACE, Term::TermType::INSERT
10
+ :write
11
+ when Term::TermType::DB_CREATE, Term::TermType::DB_DROP,
12
+ Term::TermType::DB_LIST, Term::TermType::TABLE_CREATE,
13
+ Term::TermType::TABLE_DROP, Term::TermType::TABLE_LIST,
14
+ Term::TermType::SYNC, Term::TermType::INDEX_CREATE,
15
+ Term::TermType::INDEX_DROP, Term::TermType::INDEX_LIST,
16
+ Term::TermType::INDEX_STATUS, Term::TermType::INDEX_WAIT
17
+ :management
18
+ else
19
+ # XXX Not sure if that's correct, but we'll be happy for logging colors.
20
+ :read
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,3 @@
1
+ module NoBrainer
2
+ VERSION = '0.8.0'
3
+ end
data/lib/nobrainer.rb ADDED
@@ -0,0 +1,59 @@
1
+ require 'active_support/core_ext'
2
+
3
+ if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('1.9')
4
+ raise 'Please use Ruby 1.9 or later'
5
+ end
6
+
7
+ module NoBrainer
8
+ require 'no_brainer/autoload'
9
+ extend NoBrainer::Autoload
10
+
11
+ autoload :Config, :Document, :Connection, :Database, :Error, :QueryRunner,
12
+ :Criteria, :DecoratedSymbol, :IndexManager, :Loader, :Logging, :Util, :Fork
13
+
14
+ class << self
15
+ # Note: we always access the connection explicitly, so that in the future,
16
+ # we can refactor to return a connection depending on the context.
17
+ # Note that a connection is tied to a database in NoBrainer.
18
+ def connection
19
+ @connection ||= begin
20
+ url = NoBrainer::Config.rethinkdb_url
21
+ raise "Please specify a database connection to RethinkDB" unless url
22
+ Connection.new(url).tap { |c| c.connect }
23
+ end
24
+ end
25
+
26
+ def disconnect
27
+ @connection.try(:disconnect)
28
+ @connection = nil
29
+ end
30
+
31
+ def disconnect_if_url_changed
32
+ if @connection && @connection.uri != NoBrainer::Config.rethinkdb_url
33
+ disconnect
34
+ end
35
+ end
36
+
37
+ # No not use modules to extend, it's nice to see the NoBrainer module API here.
38
+ delegate :db_create, :db_drop, :db_list, :database, :to => :connection
39
+ delegate :table_create, :table_drop, :table_list,
40
+ :drop!, :purge!, :to => :database
41
+ delegate :run, :to => 'NoBrainer::QueryRunner'
42
+ delegate :update_indexes, :to => 'NoBrainer::IndexManager'
43
+ delegate :with_options, :with_database, :to => 'NoBrainer::QueryRunner::RunOptions'
44
+ delegate :configure, :logger, :to => 'NoBrainer::Config'
45
+
46
+ def jruby?
47
+ RUBY_PLATFORM == 'java'
48
+ end
49
+ end
50
+
51
+ DecoratedSymbol.hook
52
+ Fork.hook unless jruby?
53
+ end
54
+
55
+ ActiveSupport.on_load(:i18n) do
56
+ I18n.load_path << File.dirname(__FILE__) + '/no_brainer/locale/en.yml'
57
+ end
58
+
59
+ require 'no_brainer/railtie' if defined?(Rails)
metadata ADDED
@@ -0,0 +1,152 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nobrainer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.8.0
5
+ platform: ruby
6
+ authors:
7
+ - Nicolas Viennot
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-12-31 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rethinkdb
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: 1.11.0.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: 1.11.0.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: activemodel
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: 3.2.0
34
+ - - <
35
+ - !ruby/object:Gem::Version
36
+ version: '5'
37
+ type: :runtime
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - '>='
42
+ - !ruby/object:Gem::Version
43
+ version: 3.2.0
44
+ - - <
45
+ - !ruby/object:Gem::Version
46
+ version: '5'
47
+ - !ruby/object:Gem::Dependency
48
+ name: middleware
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: 0.1.0
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ~>
59
+ - !ruby/object:Gem::Version
60
+ version: 0.1.0
61
+ description: ORM for RethinkDB
62
+ email:
63
+ - nicolas@viennot.biz
64
+ executables: []
65
+ extensions: []
66
+ extra_rdoc_files: []
67
+ files:
68
+ - lib/no_brainer/document/polymorphic.rb
69
+ - lib/no_brainer/document/id.rb
70
+ - lib/no_brainer/document/injection_layer.rb
71
+ - lib/no_brainer/document/store_in.rb
72
+ - lib/no_brainer/document/timestamps.rb
73
+ - lib/no_brainer/document/association.rb
74
+ - lib/no_brainer/document/association/core.rb
75
+ - lib/no_brainer/document/association/has_many.rb
76
+ - lib/no_brainer/document/association/belongs_to.rb
77
+ - lib/no_brainer/document/core.rb
78
+ - lib/no_brainer/document/criteria.rb
79
+ - lib/no_brainer/document/dirty.rb
80
+ - lib/no_brainer/document/dynamic_attributes.rb
81
+ - lib/no_brainer/document/persistance.rb
82
+ - lib/no_brainer/document/serialization.rb
83
+ - lib/no_brainer/document/validation.rb
84
+ - lib/no_brainer/document/attributes.rb
85
+ - lib/no_brainer/document/index.rb
86
+ - lib/no_brainer/query_runner/connection.rb
87
+ - lib/no_brainer/query_runner/driver.rb
88
+ - lib/no_brainer/query_runner/database_on_demand.rb
89
+ - lib/no_brainer/query_runner/logger.rb
90
+ - lib/no_brainer/query_runner/run_options.rb
91
+ - lib/no_brainer/query_runner/table_on_demand.rb
92
+ - lib/no_brainer/query_runner/write_error.rb
93
+ - lib/no_brainer/railtie/database.rake
94
+ - lib/no_brainer/criteria/chainable/raw.rb
95
+ - lib/no_brainer/criteria/chainable/core.rb
96
+ - lib/no_brainer/criteria/chainable/limit.rb
97
+ - lib/no_brainer/criteria/chainable/order_by.rb
98
+ - lib/no_brainer/criteria/chainable/scope.rb
99
+ - lib/no_brainer/criteria/chainable/where.rb
100
+ - lib/no_brainer/criteria/termination/inc.rb
101
+ - lib/no_brainer/criteria/termination/count.rb
102
+ - lib/no_brainer/criteria/termination/first.rb
103
+ - lib/no_brainer/criteria/termination/enumerable.rb
104
+ - lib/no_brainer/criteria/termination/update.rb
105
+ - lib/no_brainer/criteria/termination/cache.rb
106
+ - lib/no_brainer/criteria/termination/delete.rb
107
+ - lib/no_brainer/criteria/termination/eager_loading.rb
108
+ - lib/no_brainer/autoload.rb
109
+ - lib/no_brainer/railtie.rb
110
+ - lib/no_brainer/criteria.rb
111
+ - lib/no_brainer/database.rb
112
+ - lib/no_brainer/decorated_symbol.rb
113
+ - lib/no_brainer/document.rb
114
+ - lib/no_brainer/error.rb
115
+ - lib/no_brainer/index_manager.rb
116
+ - lib/no_brainer/loader.rb
117
+ - lib/no_brainer/locale/en.yml
118
+ - lib/no_brainer/query_runner.rb
119
+ - lib/no_brainer/util.rb
120
+ - lib/no_brainer/config.rb
121
+ - lib/no_brainer/connection.rb
122
+ - lib/no_brainer/fork.rb
123
+ - lib/no_brainer/version.rb
124
+ - lib/nobrainer.rb
125
+ - README.md
126
+ - LICENSE.md
127
+ homepage: http://github.com/nviennot/nobrainer
128
+ licenses:
129
+ - MIT
130
+ metadata: {}
131
+ post_install_message:
132
+ rdoc_options: []
133
+ require_paths:
134
+ - lib
135
+ required_ruby_version: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - '>='
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ required_rubygems_version: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - '>='
143
+ - !ruby/object:Gem::Version
144
+ version: '0'
145
+ requirements: []
146
+ rubyforge_project:
147
+ rubygems_version: 2.0.8
148
+ signing_key:
149
+ specification_version: 4
150
+ summary: ORM for RethinkDB
151
+ test_files: []
152
+ has_rdoc: false