nulldb 0.3.7.pre.alpha.1

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 (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