Skip to content

Commit a990bc5

Browse files
fidelpjurewicz
andcommitted
Reimplement DatabaseAdapter as a class hierarchy
Same features, less verbose implementation. Introducing new adapter type should be easier now. Co-authored-by: Piotr Jurewicz <[email protected]>
1 parent becf4a1 commit a990bc5

File tree

8 files changed

+82
-122
lines changed

8 files changed

+82
-122
lines changed

ruby_event_store-active_record/lib/ruby_event_store/active_record/generators/database_adapter.rb

Lines changed: 39 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -6,102 +6,57 @@ module ActiveRecord
66
InvalidDataTypeForAdapter = Class.new(StandardError)
77

88
class DatabaseAdapter
9-
BIG_NUM = 169_614_201_293_062_129
10-
119
NOT_SET = Object.new.freeze
12-
private_constant :NOT_SET
1310

14-
class PostgreSQL
11+
class PostgreSQL < self
1512
SUPPORTED_DATA_TYPES = %w[binary json jsonb].freeze
16-
private_constant :SUPPORTED_DATA_TYPES
1713

1814
def initialize(data_type = NOT_SET)
19-
if !data_type.eql?(NOT_SET) && !supported_data_types.include?(data_type)
20-
raise InvalidDataTypeForAdapter,
21-
"PostgreSQL doesn't support #{data_type.inspect}. Supported types are: #{supported_data_types.join(", ")}."
22-
end
23-
24-
@data_type = data_type
25-
end
26-
27-
attr_reader :data_type
28-
29-
def supported_data_types
30-
SUPPORTED_DATA_TYPES
31-
end
32-
33-
def eql?(other)
34-
other.instance_of?(PostgreSQL)
35-
end
36-
37-
alias == eql?
38-
39-
def hash
40-
PostgreSQL.hash ^ BIG_NUM
15+
super("postgresql", data_type)
4116
end
4217
end
4318

44-
class MySQL2
19+
class MySQL2 < self
4520
SUPPORTED_DATA_TYPES = %w[binary json].freeze
46-
private_constant :SUPPORTED_DATA_TYPES
4721

4822
def initialize(data_type = NOT_SET)
49-
if !data_type.eql?(NOT_SET) && !supported_data_types.include?(data_type)
50-
raise InvalidDataTypeForAdapter,
51-
"MySQL2 doesn't support #{data_type.inspect}. Supported types are: #{supported_data_types.join(", ")}."
52-
end
53-
54-
@data_type = data_type
55-
end
56-
57-
attr_reader :data_type
58-
59-
def supported_data_types
60-
SUPPORTED_DATA_TYPES
61-
end
62-
63-
def eql?(other)
64-
other.instance_of?(MySQL2)
65-
end
66-
67-
alias == eql?
68-
69-
def hash
70-
MySQL2.hash ^ BIG_NUM
23+
super("mysql2", data_type)
7124
end
7225
end
7326

74-
class SQLite
27+
class SQLite < self
7528
SUPPORTED_DATA_TYPES = %w[binary].freeze
76-
private_constant :SUPPORTED_DATA_TYPES
7729

7830
def initialize(data_type = NOT_SET)
79-
if !data_type.eql?(NOT_SET) && !supported_data_types.include?(data_type)
80-
raise InvalidDataTypeForAdapter,
81-
"SQLite doesn't support #{data_type.inspect}. Supported types are: #{supported_data_types.join}."
82-
end
83-
84-
@data_type = data_type
31+
super("sqlite", data_type)
8532
end
33+
end
8634

87-
attr_reader :data_type
35+
def initialize(adapter_name, data_type)
36+
validate_data_type!(data_type)
8837

89-
def supported_data_types
90-
SUPPORTED_DATA_TYPES
91-
end
38+
@adapter_name = adapter_name
39+
@data_type = data_type
40+
end
9241

93-
def eql?(other)
94-
other.instance_of?(SQLite)
95-
end
42+
attr_reader :adapter_name, :data_type
9643

97-
alias == eql?
44+
def supported_data_types
45+
self.class::SUPPORTED_DATA_TYPES
46+
end
9847

99-
def hash
100-
SQLite.hash ^ BIG_NUM
101-
end
48+
def eql?(other)
49+
other.is_a?(DatabaseAdapter) && adapter_name.eql?(other.adapter_name)
10250
end
10351

104-
def self.new(adapter_name, data_type = NOT_SET)
52+
alias == eql?
53+
54+
def hash
55+
DatabaseAdapter.hash ^ adapter_name.hash
56+
end
57+
58+
def self.from_string(adapter_name, data_type = NOT_SET)
59+
raise NoMethodError unless eql?(DatabaseAdapter)
10560
case adapter_name.to_s.downcase
10661
when "postgresql", "postgis"
10762
PostgreSQL.new(data_type)
@@ -113,6 +68,19 @@ def self.new(adapter_name, data_type = NOT_SET)
11368
raise UnsupportedAdapter, "Unsupported adapter: #{adapter_name.inspect}"
11469
end
11570
end
71+
72+
private
73+
74+
def validate_data_type!(data_type)
75+
if !data_type.eql?(NOT_SET) && !supported_data_types.include?(data_type)
76+
raise InvalidDataTypeForAdapter,
77+
"#{class_name} doesn't support #{data_type.inspect}. Supported types are: #{supported_data_types.join(", ")}."
78+
end
79+
end
80+
81+
def class_name
82+
self.class.name.split("::").last
83+
end
11684
end
11785
end
11886
end

ruby_event_store-active_record/lib/ruby_event_store/active_record/generators/foreign_key_on_event_id_migration_generator.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ module RubyEventStore
44
module ActiveRecord
55
class ForeignKeyOnEventIdMigrationGenerator
66
def call(database_adapter_name, migration_path)
7-
database_adapter = DatabaseAdapter.new(database_adapter_name)
7+
database_adapter = DatabaseAdapter.from_string(database_adapter_name)
88
each_migration(database_adapter) do |migration_name|
99
path = build_path(migration_path, migration_name)
1010
write_to_file(path, migration_code(database_adapter, migration_name))

ruby_event_store-active_record/lib/ruby_event_store/active_record/generators/rails_foreign_key_on_event_id_migration_generator.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class Error < Thor::Error
1919
def initialize(*args)
2020
super
2121

22-
@database_adapter = DatabaseAdapter.new(adapter_name)
22+
@database_adapter = DatabaseAdapter.from_string(adapter_name)
2323
rescue UnsupportedAdapter => e
2424
raise Error, e.message
2525
end

ruby_event_store-active_record/lib/ruby_event_store/active_record/generators/rails_migration_generator.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,12 @@ class Error < Thor::Error
2525
def initialize(*args)
2626
super
2727

28-
@database_adapter = DatabaseAdapter.new(adapter_name, data_type)
28+
@database_adapter = DatabaseAdapter.from_string(adapter_name, data_type)
2929
rescue UnsupportedAdapter => e
3030
raise Error, e.message
3131
rescue InvalidDataTypeForAdapter
3232
raise Error,
33-
"Invalid value for --data-type option. Supported for options are: #{DatabaseAdapter.new(adapter_name).supported_data_types.join(", ")}."
33+
"Invalid value for --data-type option. Supported for options are: #{DatabaseAdapter.from_string(adapter_name).supported_data_types.join(", ")}."
3434
end
3535

3636
def create_migration

ruby_event_store-active_record/lib/ruby_event_store/active_record/tasks/migration_tasks.rake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ task "db:migrations:copy" do
66
ENV["DATA_TYPE"] || raise("Specify data type (binary, json, jsonb): rake db:migrations:copy DATA_TYPE=json")
77
::ActiveRecord::Base.establish_connection(ENV["DATABASE_URL"])
88
database_adapter =
9-
RubyEventStore::ActiveRecord::DatabaseAdapter.new(::ActiveRecord::Base.connection.adapter_name, data_type)
9+
RubyEventStore::ActiveRecord::DatabaseAdapter.from_string(::ActiveRecord::Base.connection.adapter_name, data_type)
1010

1111
path =
1212
RubyEventStore::ActiveRecord::MigrationGenerator.new.call(database_adapter, ENV["MIGRATION_PATH"] || "db/migrate")

ruby_event_store-active_record/spec/database_adapter_spec.rb

Lines changed: 33 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -5,57 +5,49 @@
55
module RubyEventStore
66
module ActiveRecord
77
::RSpec.describe DatabaseAdapter do
8-
specify "equality" do
9-
expect(DatabaseAdapter.new("postgresql")).to eql(DatabaseAdapter::PostgreSQL.new)
10-
expect(DatabaseAdapter.new("mysql2")).to eql(DatabaseAdapter::MySQL2.new)
11-
expect(DatabaseAdapter.new("sqlite")).to eql(DatabaseAdapter::SQLite.new)
12-
13-
expect(DatabaseAdapter.new("postgresql")).to eq(DatabaseAdapter::PostgreSQL.new)
14-
expect(DatabaseAdapter.new("mysql2")).to eq(DatabaseAdapter::MySQL2.new)
15-
expect(DatabaseAdapter.new("sqlite")).to eq(DatabaseAdapter::SQLite.new)
16-
end
17-
18-
specify "does not equal different type" do
19-
expect(DatabaseAdapter.new("postgresql")).not_to eql("postgresql")
20-
expect(DatabaseAdapter.new("mysql2")).not_to eql("mysql2")
21-
expect(DatabaseAdapter.new("sqlite")).not_to eql("sqlite")
22-
end
23-
24-
specify "hash" do
25-
expect(DatabaseAdapter::PostgreSQL.new.hash).to eql(DatabaseAdapter::PostgreSQL.hash ^ DatabaseAdapter::BIG_NUM)
26-
expect(DatabaseAdapter::MySQL2.new.hash).to eql(DatabaseAdapter::MySQL2.hash ^ DatabaseAdapter::BIG_NUM)
27-
expect(DatabaseAdapter::SQLite.new.hash).to eql(DatabaseAdapter::SQLite.hash ^ DatabaseAdapter::BIG_NUM)
28-
29-
expect(DatabaseAdapter::PostgreSQL.new.hash).to eql(DatabaseAdapter::PostgreSQL.new.hash)
30-
expect(DatabaseAdapter::MySQL2.new.hash).to eql(DatabaseAdapter::MySQL2.new.hash)
31-
expect(DatabaseAdapter::SQLite.new.hash).to eql(DatabaseAdapter::SQLite.new.hash)
8+
specify "from_string" do
9+
expect(DatabaseAdapter.from_string("PostgreSQL")).to eql(DatabaseAdapter::PostgreSQL.new)
10+
expect(DatabaseAdapter.from_string("PostGIS")).to eql(DatabaseAdapter::PostgreSQL.new)
11+
expect(DatabaseAdapter.from_string("MySQL2")).to eql(DatabaseAdapter::MySQL2.new)
12+
expect(DatabaseAdapter.from_string("SQLite")).to eql(DatabaseAdapter::SQLite.new)
3213
end
3314

34-
specify "different adapters does not compare" do
35-
expect(DatabaseAdapter.new("postgresql")).not_to eql(DatabaseAdapter.new("mysql2"))
15+
specify "equality" do
16+
expect(DatabaseAdapter::PostgreSQL.new).not_to eql(DatabaseAdapter::MySQL2.new)
17+
expect(DatabaseAdapter::PostgreSQL.new).not_to eql("postgresql")
3618
end
3719

38-
specify "postgis is postgresql flavor" do
39-
expect(DatabaseAdapter.new("postgis")).to eq(DatabaseAdapter.new("postgresql"))
20+
specify "adapter_name" do
21+
expect(DatabaseAdapter::PostgreSQL.new.adapter_name).to eql("postgresql")
22+
expect(DatabaseAdapter::MySQL2.new.adapter_name).to eql("mysql2")
23+
expect(DatabaseAdapter::SQLite.new.adapter_name).to eql("sqlite")
4024
end
4125

42-
specify "raises exception on unsupported adapter" do
43-
expect { DatabaseAdapter.new("foo") }.to raise_error(UnsupportedAdapter, "Unsupported adapter: \"foo\"")
26+
specify "raise on unknown adapter" do
27+
expect { DatabaseAdapter.from_string("kakadudu") }.to raise_error(
28+
UnsupportedAdapter,
29+
"Unsupported adapter: \"kakadudu\""
30+
)
31+
expect { DatabaseAdapter.from_string(nil) }.to raise_error(UnsupportedAdapter, "Unsupported adapter: nil")
32+
expect { DatabaseAdapter.from_string(123) }.to raise_error(UnsupportedAdapter, "Unsupported adapter: 123")
4433
end
4534

46-
specify "case insensitive adapter name" do
47-
expect(DatabaseAdapter.new("PostgreSQL")).to eq(DatabaseAdapter.new("postgresql"))
35+
specify "unsupported data type passed to #from_string" do
36+
expect { DatabaseAdapter.from_string("postgresql", "foo") }.to raise_error(InvalidDataTypeForAdapter)
37+
expect { DatabaseAdapter.from_string("mysql2", "foo") }.to raise_error(InvalidDataTypeForAdapter)
38+
expect { DatabaseAdapter.from_string("sqlite", "foo") }.to raise_error(InvalidDataTypeForAdapter)
4839
end
4940

50-
specify "junk adapter name" do
51-
expect { DatabaseAdapter.new(nil) }.to raise_error(UnsupportedAdapter, "Unsupported adapter: nil")
52-
expect { DatabaseAdapter.new(123) }.to raise_error(UnsupportedAdapter, "Unsupported adapter: 123")
41+
specify "hash" do
42+
expect(DatabaseAdapter::PostgreSQL.new.hash).to eql(DatabaseAdapter.hash ^ "postgresql".hash)
43+
expect(DatabaseAdapter::MySQL2.new.hash).to eql(DatabaseAdapter.hash ^ "mysql2".hash)
44+
expect(DatabaseAdapter::SQLite.new.hash).to eql(DatabaseAdapter.hash ^ "sqlite".hash)
5345
end
5446

55-
specify "unsupported data type" do
56-
expect { DatabaseAdapter.new("postgresql", "foo") }.to raise_error(InvalidDataTypeForAdapter)
57-
expect { DatabaseAdapter.new("mysql2", "foo") }.to raise_error(InvalidDataTypeForAdapter)
58-
expect { DatabaseAdapter.new("sqlite", "foo") }.to raise_error(InvalidDataTypeForAdapter)
47+
specify "child classes don't implement #from_string" do
48+
expect { DatabaseAdapter::PostgreSQL.from_string("postgresql") }.to raise_error(NoMethodError)
49+
expect { DatabaseAdapter::MySQL2.from_string("mysql2") }.to raise_error(NoMethodError)
50+
expect { DatabaseAdapter::SQLite.from_string("sqlite") }.to raise_error(NoMethodError)
5951
end
6052

6153
context "data type verification" do
@@ -85,8 +77,8 @@ module ActiveRecord
8577
end
8678

8779
specify "PostgreSQL doesn't support bla" do
88-
expect { DatabaseAdapter::PostgreSQL.new("bla") }.to raise_error InvalidDataTypeForAdapter,
89-
"PostgreSQL doesn't support \"bla\". Supported types are: binary, json, jsonb."
80+
expect { DatabaseAdapter::PostgreSQL.new("kakadudu") }.to raise_error InvalidDataTypeForAdapter,
81+
"PostgreSQL doesn't support \"kakadudu\". Supported types are: binary, json, jsonb."
9082
end
9183

9284
specify "sqlite supports binary" do

ruby_event_store-active_record/spec/migration_generator_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ module ActiveRecord
125125
private
126126

127127
def migration_generator(dir, data_type = "binary", database_adapter = "sqlite")
128-
ActiveRecord::MigrationGenerator.new.call(DatabaseAdapter.new(database_adapter, data_type), dir)
128+
ActiveRecord::MigrationGenerator.new.call(DatabaseAdapter.from_string(database_adapter, data_type), dir)
129129
end
130130

131131
def migration_exists?(dir)

ruby_event_store-active_record/spec/template_directory_spec.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,16 @@ module RubyEventStore
66
module ActiveRecord
77
::RSpec.describe TemplateDirectory do
88
specify "returns template directory for postgresql adapter" do
9-
expect(TemplateDirectory.for_adapter(DatabaseAdapter.new("PostgreSQL"))).to eq("postgres/")
10-
expect(TemplateDirectory.for_adapter(DatabaseAdapter.new("PostGIS"))).to eq("postgres/")
9+
expect(TemplateDirectory.for_adapter(DatabaseAdapter.from_string("PostgreSQL"))).to eq("postgres/")
10+
expect(TemplateDirectory.for_adapter(DatabaseAdapter.from_string("PostGIS"))).to eq("postgres/")
1111
end
1212

1313
specify "returns template directory for mysql2 adapter" do
14-
expect(TemplateDirectory.for_adapter(DatabaseAdapter.new("MySQL2"))).to eq("mysql/")
14+
expect(TemplateDirectory.for_adapter(DatabaseAdapter.from_string("MySQL2"))).to eq("mysql/")
1515
end
1616

1717
specify "returns template directory for sqlite adapter" do
18-
expect(TemplateDirectory.for_adapter(DatabaseAdapter.new("sqlite"))).to eq(nil)
18+
expect(TemplateDirectory.for_adapter(DatabaseAdapter.from_string("sqlite"))).to eq(nil)
1919
end
2020
end
2121
end

0 commit comments

Comments
 (0)