nobrainer 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
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