nulldb 0.3.7.pre.alpha.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +28 -0
  3. data/.travis.yml +49 -0
  4. data/Appraisals +36 -0
  5. data/CHANGES.md +75 -0
  6. data/Gemfile +14 -0
  7. data/LICENSE +21 -0
  8. data/README.rdoc +147 -0
  9. data/Rakefile +14 -0
  10. data/VERSION +1 -0
  11. data/gemfiles/activerecord_2.3.gemfile +17 -0
  12. data/gemfiles/activerecord_3.0.gemfile +16 -0
  13. data/gemfiles/activerecord_3.1.gemfile +16 -0
  14. data/gemfiles/activerecord_3.2.gemfile +16 -0
  15. data/gemfiles/activerecord_4.0.gemfile +16 -0
  16. data/gemfiles/activerecord_4.1.gemfile +16 -0
  17. data/gemfiles/activerecord_4.2.gemfile +16 -0
  18. data/gemfiles/activerecord_5.0.gemfile +16 -0
  19. data/gemfiles/activerecord_5.1.gemfile +16 -0
  20. data/gemfiles/activerecord_master.gemfile +18 -0
  21. data/lib/active_record/connection_adapters/nulldb_adapter.rb +21 -0
  22. data/lib/active_record/connection_adapters/nulldb_adapter/checkpoint.rb +13 -0
  23. data/lib/active_record/connection_adapters/nulldb_adapter/column.rb +20 -0
  24. data/lib/active_record/connection_adapters/nulldb_adapter/configuration.rb +5 -0
  25. data/lib/active_record/connection_adapters/nulldb_adapter/core.rb +324 -0
  26. data/lib/active_record/connection_adapters/nulldb_adapter/empty_result.rb +26 -0
  27. data/lib/active_record/connection_adapters/nulldb_adapter/index_definition.rb +5 -0
  28. data/lib/active_record/connection_adapters/nulldb_adapter/null_object.rb +13 -0
  29. data/lib/active_record/connection_adapters/nulldb_adapter/statement.rb +15 -0
  30. data/lib/active_record/connection_adapters/nulldb_adapter/table_definition.rb +5 -0
  31. data/lib/activerecord-nulldb-adapter.rb +1 -0
  32. data/lib/nulldb.rb +2 -0
  33. data/lib/nulldb/arel_compiler.rb +6 -0
  34. data/lib/nulldb/core.rb +39 -0
  35. data/lib/nulldb/extensions.rb +42 -0
  36. data/lib/nulldb/rails.rb +4 -0
  37. data/lib/nulldb_rspec.rb +104 -0
  38. data/lib/tasks/database.rake +32 -0
  39. data/nulldb.gemspec +27 -0
  40. data/spec/nulldb_spec.rb +345 -0
  41. data/spec/spec.opts +1 -0
  42. metadata +172 -0
@@ -0,0 +1,16 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 3.2.0"
6
+
7
+ group :development, :test do
8
+ gem "spec"
9
+ gem "rspec", ">= 1.2.9"
10
+ gem "rake"
11
+ end
12
+
13
+ group :development do
14
+ gem "appraisal"
15
+ gem "simplecov", :require => false
16
+ end
@@ -0,0 +1,16 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 4.0.0"
6
+
7
+ group :development, :test do
8
+ gem "spec"
9
+ gem "rspec", ">= 1.2.9"
10
+ gem "rake"
11
+ end
12
+
13
+ group :development do
14
+ gem "appraisal"
15
+ gem "simplecov", :require => false
16
+ end
@@ -0,0 +1,16 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 4.1.0"
6
+
7
+ group :development, :test do
8
+ gem "spec"
9
+ gem "rspec", ">= 1.2.9"
10
+ gem "rake"
11
+ end
12
+
13
+ group :development do
14
+ gem "appraisal"
15
+ gem "simplecov", :require => false
16
+ end
@@ -0,0 +1,16 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 4.2.0"
6
+
7
+ group :development, :test do
8
+ gem "spec"
9
+ gem "rspec", ">= 1.2.9"
10
+ gem "rake"
11
+ end
12
+
13
+ group :development do
14
+ gem "appraisal"
15
+ gem "simplecov", :require => false
16
+ end
@@ -0,0 +1,16 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 5.0.0"
6
+
7
+ group :development, :test do
8
+ gem "spec"
9
+ gem "rspec", ">= 1.2.9"
10
+ gem "rake"
11
+ end
12
+
13
+ group :development do
14
+ gem "appraisal"
15
+ gem "simplecov", :require => false
16
+ end
@@ -0,0 +1,16 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 5.1.0"
6
+
7
+ group :development, :test do
8
+ gem "spec"
9
+ gem "rspec", ">= 1.2.9"
10
+ gem "rake"
11
+ end
12
+
13
+ group :development do
14
+ gem "appraisal"
15
+ gem "simplecov", :require => false
16
+ end
@@ -0,0 +1,18 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ git 'https://github.com/rails/rails.git' do
6
+ gem 'activerecord'
7
+ end
8
+
9
+ group :development, :test do
10
+ gem "spec"
11
+ gem "rspec", ">= 1.2.9"
12
+ gem "rake"
13
+ end
14
+
15
+ group :development do
16
+ gem "appraisal"
17
+ gem "simplecov", :require => false
18
+ end
@@ -0,0 +1,21 @@
1
+ require 'logger'
2
+ require 'stringio'
3
+ require 'singleton'
4
+ require 'pathname'
5
+
6
+ require 'active_support'
7
+ require 'active_record/connection_adapters/abstract_adapter'
8
+
9
+ require 'nulldb/core'
10
+ require 'nulldb/extensions'
11
+
12
+ require 'active_record/connection_adapters/nulldb_adapter/core'
13
+ require 'active_record/connection_adapters/nulldb_adapter/statement'
14
+ require 'active_record/connection_adapters/nulldb_adapter/checkpoint'
15
+ require 'active_record/connection_adapters/nulldb_adapter/column'
16
+ require 'active_record/connection_adapters/nulldb_adapter/configuration'
17
+ require 'active_record/connection_adapters/nulldb_adapter/empty_result'
18
+ require 'active_record/connection_adapters/nulldb_adapter/index_definition'
19
+ require 'active_record/connection_adapters/nulldb_adapter/null_object'
20
+ require 'active_record/connection_adapters/nulldb_adapter/table_definition'
21
+
@@ -0,0 +1,13 @@
1
+ class ActiveRecord::ConnectionAdapters::NullDBAdapter
2
+
3
+ class Checkpoint < Statement
4
+ def initialize
5
+ super(:checkpoint, "")
6
+ end
7
+
8
+ def ==(other)
9
+ self.class == other.class
10
+ end
11
+ end
12
+
13
+ end
@@ -0,0 +1,20 @@
1
+ class ActiveRecord::ConnectionAdapters::NullDBAdapter
2
+ class Column < ::ActiveRecord::ConnectionAdapters::Column
3
+
4
+ private
5
+
6
+ def simplified_type(field_type)
7
+ super || simplified_type_from_sql_type
8
+ end
9
+
10
+ def simplified_type_from_sql_type
11
+ case sql_type
12
+ when :primary_key
13
+ :integer
14
+ when :string
15
+ :string
16
+ end
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,5 @@
1
+ class ActiveRecord::ConnectionAdapters::NullDBAdapter
2
+
3
+ class Configuration < Struct.new(:project_root); end
4
+
5
+ end
@@ -0,0 +1,324 @@
1
+ class ActiveRecord::ConnectionAdapters::NullDBAdapter < ActiveRecord::ConnectionAdapters::AbstractAdapter
2
+
3
+ # A convenience method for integratinginto RSpec. See README for example of
4
+ # use.
5
+ def self.insinuate_into_spec(config)
6
+ config.before :all do
7
+ ActiveRecord::Base.establish_connection(:adapter => :nulldb)
8
+ end
9
+
10
+ config.after :all do
11
+ ActiveRecord::Base.establish_connection(:test)
12
+ end
13
+ end
14
+
15
+ # Recognized options:
16
+ #
17
+ # [+:schema+] path to the schema file, relative to Rails.root
18
+ def initialize(config={})
19
+ @log = StringIO.new
20
+ @logger = Logger.new(@log)
21
+ @last_unique_id = 0
22
+ @tables = {'schema_info' => new_table_definition(nil)}
23
+ @indexes = Hash.new { |hash, key| hash[key] = [] }
24
+ @schema_path = config.fetch(:schema){ "db/schema.rb" }
25
+ @config = config.merge(:adapter => :nulldb)
26
+ super *initialize_args
27
+ @visitor ||= Arel::Visitors::ToSql.new self if defined?(Arel::Visitors::ToSql)
28
+ end
29
+
30
+ # A log of every statement that has been "executed" by this connection adapter
31
+ # instance.
32
+ def execution_log
33
+ (@execution_log ||= [])
34
+ end
35
+
36
+ # A log of every statement that has been "executed" since the last time
37
+ # #checkpoint! was called, or since the connection was created.
38
+ def execution_log_since_checkpoint
39
+ checkpoint_index = @execution_log.rindex(Checkpoint.new)
40
+ checkpoint_index = checkpoint_index ? checkpoint_index + 1 : 0
41
+ @execution_log[(checkpoint_index..-1)]
42
+ end
43
+
44
+ # Inserts a checkpoint in the log. See also #execution_log_since_checkpoint.
45
+ def checkpoint!
46
+ self.execution_log << Checkpoint.new
47
+ end
48
+
49
+ def adapter_name
50
+ "NullDB"
51
+ end
52
+
53
+ def supports_migrations?
54
+ true
55
+ end
56
+
57
+ def create_table(table_name, options = {})
58
+ table_definition = new_table_definition(self, table_name, options.delete(:temporary), options)
59
+
60
+ unless options[:id] == false
61
+ table_definition.primary_key(options[:primary_key] || "id")
62
+ end
63
+
64
+ yield table_definition if block_given?
65
+
66
+ @tables[table_name] = table_definition
67
+ end
68
+
69
+ def add_index(table_name, column_names, options = {})
70
+ column_names = Array.wrap(column_names).map(&:to_s)
71
+ index_name, index_type, ignore = add_index_options(table_name, column_names, options)
72
+ @indexes[table_name] << IndexDefinition.new(table_name, index_name, (index_type == 'UNIQUE'), column_names, [], [])
73
+ end
74
+
75
+ unless instance_methods.include? :add_index_options
76
+ def add_index_options(table_name, column_name, options = {})
77
+ column_names = Array.wrap(column_name)
78
+ index_name = index_name(table_name, :column => column_names)
79
+
80
+ if Hash === options # legacy support, since this param was a string
81
+ index_type = options[:unique] ? "UNIQUE" : ""
82
+ index_name = options[:name].to_s if options.key?(:name)
83
+ else
84
+ index_type = options
85
+ end
86
+
87
+ if index_name.length > index_name_length
88
+ raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' is too long; the limit is #{index_name_length} characters"
89
+ end
90
+ if index_name_exists?(table_name, index_name, false)
91
+ raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' already exists"
92
+ end
93
+ index_columns = quoted_columns_for_index(column_names, options).join(", ")
94
+
95
+ [index_name, index_type, index_columns]
96
+ end
97
+ end
98
+
99
+ unless instance_methods.include? :index_name_exists?
100
+ def index_name_exists?(table_name, index_name, default)
101
+ return default unless respond_to?(:indexes)
102
+ index_name = index_name.to_s
103
+ indexes(table_name).detect { |i| i.name == index_name }
104
+ end
105
+ end
106
+
107
+ def add_fk_constraint(*args)
108
+ # NOOP
109
+ end
110
+
111
+ def add_pk_constraint(*args)
112
+ # NOOP
113
+ end
114
+
115
+ def enable_extension(*)
116
+ # NOOP
117
+ end
118
+
119
+ # Retrieve the table names defined by the schema
120
+ def tables
121
+ @tables.keys.map(&:to_s)
122
+ end
123
+
124
+ def views
125
+ [] # TODO: Implement properly if needed - This is new method in rails
126
+ end
127
+
128
+ # Retrieve table columns as defined by the schema
129
+ def columns(table_name, name = nil)
130
+ if @tables.size <= 1
131
+ ActiveRecord::Migration.verbose = false
132
+ schema_path = if Pathname(@schema_path).absolute?
133
+ @schema_path
134
+ else
135
+ File.join(NullDB.configuration.project_root, @schema_path)
136
+ end
137
+ Kernel.load(schema_path)
138
+ end
139
+
140
+ if table = @tables[table_name]
141
+ table.columns.map do |col_def|
142
+ ActiveRecord::ConnectionAdapters::NullDBAdapter::Column.new(*new_column_arguments(col_def))
143
+ end
144
+ else
145
+ []
146
+ end
147
+ end
148
+
149
+ # Retrieve table indexes as defined by the schema
150
+ def indexes(table_name, name = nil)
151
+ @indexes[table_name]
152
+ end
153
+
154
+ def execute(statement, name = nil)
155
+ self.execution_log << Statement.new(entry_point, statement)
156
+ NullObject.new
157
+ end
158
+
159
+ def exec_query(statement, name = 'SQL', binds = [], options = {})
160
+ self.execution_log << Statement.new(entry_point, statement)
161
+ EmptyResult.new
162
+ end
163
+
164
+ def select_rows(statement, name = nil, binds = [])
165
+ [].tap do
166
+ self.execution_log << Statement.new(entry_point, statement)
167
+ end
168
+ end
169
+
170
+ def insert(statement, name = nil, primary_key = nil, object_id = nil, sequence_name = nil, binds = [])
171
+ (object_id || next_unique_id).tap do
172
+ with_entry_point(:insert) do
173
+ super(statement, name, primary_key, object_id, sequence_name)
174
+ end
175
+ end
176
+ end
177
+ alias :create :insert
178
+
179
+ def update(statement, name=nil, binds = [])
180
+ with_entry_point(:update) do
181
+ super(statement, name)
182
+ end
183
+ end
184
+
185
+ def delete(statement, name=nil, binds = [])
186
+ with_entry_point(:delete) do
187
+ super(statement, name).size
188
+ end
189
+ end
190
+
191
+ def select_all(statement, name=nil, binds = [], options = {})
192
+ with_entry_point(:select_all) do
193
+ super(statement, name)
194
+ end
195
+ end
196
+
197
+ def select_one(statement, name=nil, binds = [])
198
+ with_entry_point(:select_one) do
199
+ super(statement, name)
200
+ end
201
+ end
202
+
203
+ def select_value(statement, name=nil, binds = [])
204
+ with_entry_point(:select_value) do
205
+ super(statement, name)
206
+ end
207
+ end
208
+
209
+ def select_values(statement, name=nil)
210
+ with_entry_point(:select_values) do
211
+ super(statement, name)
212
+ end
213
+ end
214
+
215
+ def primary_key(table_name)
216
+ columns(table_name).detect { |col| col.sql_type == :primary_key }.try(:name)
217
+ end
218
+
219
+ protected
220
+
221
+ def select(statement, name = nil, binds = [])
222
+ EmptyResult.new.tap do |r|
223
+ r.columns = columns_for(name)
224
+ self.execution_log << Statement.new(entry_point, statement)
225
+ end
226
+ end
227
+
228
+ private
229
+
230
+ def columns_for(table_name)
231
+ table_def = @tables[table_name]
232
+ table_def ? table_def.columns : []
233
+ end
234
+
235
+ def next_unique_id
236
+ @last_unique_id += 1
237
+ end
238
+
239
+ def with_entry_point(method)
240
+ if entry_point.nil?
241
+ with_thread_local_variable(:entry_point, method) do
242
+ yield
243
+ end
244
+ else
245
+ yield
246
+ end
247
+ end
248
+
249
+ def entry_point
250
+ Thread.current[:entry_point]
251
+ end
252
+
253
+ def with_thread_local_variable(name, value)
254
+ old_value = Thread.current[name]
255
+ Thread.current[name] = value
256
+ begin
257
+ yield
258
+ ensure
259
+ Thread.current[name] = old_value
260
+ end
261
+ end
262
+
263
+ def new_table_definition(adapter = nil, table_name = nil, is_temporary = nil, options = {})
264
+ case ::ActiveRecord::VERSION::MAJOR
265
+ when 5
266
+ TableDefinition.new(table_name, is_temporary, options.except(:id), nil)
267
+ when 4
268
+ TableDefinition.new(native_database_types, table_name, is_temporary, options)
269
+ when 2,3
270
+ TableDefinition.new(adapter)
271
+ else
272
+ raise "Unsupported ActiveRecord version #{::ActiveRecord::VERSION::STRING}"
273
+ end
274
+ end
275
+
276
+ def new_column_arguments(col_def)
277
+ args_with_optional_cast_type(col_def)
278
+ end
279
+
280
+ def args_with_optional_cast_type(col_def)
281
+ default_column_arguments(col_def).tap do |args|
282
+ if defined?(ActiveRecord::ConnectionAdapters::SqlTypeMetadata)
283
+ meta = ActiveRecord::ConnectionAdapters::SqlTypeMetadata.new(sql_type: col_def.type)
284
+ args.insert(2, meta_with_limit!(meta, col_def))
285
+ elsif initialize_column_with_cast_type?
286
+ args.insert(2, meta_with_limit!(lookup_cast_type(col_def.type), col_def))
287
+ else
288
+ args[2] = args[2].to_s + "(#{col_def.limit})" if col_def.limit
289
+ end
290
+ end
291
+ end
292
+
293
+ def meta_with_limit!(meta, col_def)
294
+ meta.instance_variable_set('@limit', col_def.limit)
295
+ meta
296
+ end
297
+
298
+ def default_column_arguments(col_def)
299
+ if ActiveRecord::VERSION::MAJOR == 5
300
+ [
301
+ col_def.name.to_s,
302
+ col_def.default,
303
+ col_def.null.nil? || col_def.null # cast [false, nil, true] => [false, true, true], other adapters default to null=true
304
+ ]
305
+ else
306
+ [
307
+ col_def.name.to_s,
308
+ col_def.default,
309
+ col_def.type,
310
+ col_def.null.nil? || col_def.null # cast [false, nil, true] => [false, true, true], other adapters default to null=true
311
+ ]
312
+ end
313
+ end
314
+
315
+ def initialize_column_with_cast_type?
316
+ ::ActiveRecord::VERSION::MAJOR == 4 && ::ActiveRecord::VERSION::MINOR >= 2
317
+ end
318
+
319
+ def initialize_args
320
+ return [nil, @logger, @config] if ActiveRecord::VERSION::MAJOR > 3
321
+ [nil, @logger]
322
+ end
323
+
324
+ end