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.
- checksums.yaml +7 -0
- data/.gitignore +28 -0
- data/.travis.yml +49 -0
- data/Appraisals +36 -0
- data/CHANGES.md +75 -0
- data/Gemfile +14 -0
- data/LICENSE +21 -0
- data/README.rdoc +147 -0
- data/Rakefile +14 -0
- data/VERSION +1 -0
- data/gemfiles/activerecord_2.3.gemfile +17 -0
- data/gemfiles/activerecord_3.0.gemfile +16 -0
- data/gemfiles/activerecord_3.1.gemfile +16 -0
- data/gemfiles/activerecord_3.2.gemfile +16 -0
- data/gemfiles/activerecord_4.0.gemfile +16 -0
- data/gemfiles/activerecord_4.1.gemfile +16 -0
- data/gemfiles/activerecord_4.2.gemfile +16 -0
- data/gemfiles/activerecord_5.0.gemfile +16 -0
- data/gemfiles/activerecord_5.1.gemfile +16 -0
- data/gemfiles/activerecord_master.gemfile +18 -0
- data/lib/active_record/connection_adapters/nulldb_adapter.rb +21 -0
- data/lib/active_record/connection_adapters/nulldb_adapter/checkpoint.rb +13 -0
- data/lib/active_record/connection_adapters/nulldb_adapter/column.rb +20 -0
- data/lib/active_record/connection_adapters/nulldb_adapter/configuration.rb +5 -0
- data/lib/active_record/connection_adapters/nulldb_adapter/core.rb +324 -0
- data/lib/active_record/connection_adapters/nulldb_adapter/empty_result.rb +26 -0
- data/lib/active_record/connection_adapters/nulldb_adapter/index_definition.rb +5 -0
- data/lib/active_record/connection_adapters/nulldb_adapter/null_object.rb +13 -0
- data/lib/active_record/connection_adapters/nulldb_adapter/statement.rb +15 -0
- data/lib/active_record/connection_adapters/nulldb_adapter/table_definition.rb +5 -0
- data/lib/activerecord-nulldb-adapter.rb +1 -0
- data/lib/nulldb.rb +2 -0
- data/lib/nulldb/arel_compiler.rb +6 -0
- data/lib/nulldb/core.rb +39 -0
- data/lib/nulldb/extensions.rb +42 -0
- data/lib/nulldb/rails.rb +4 -0
- data/lib/nulldb_rspec.rb +104 -0
- data/lib/tasks/database.rake +32 -0
- data/nulldb.gemspec +27 -0
- data/spec/nulldb_spec.rb +345 -0
- data/spec/spec.opts +1 -0
- 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,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,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
|