mimi-db 0.2.7 → 0.3.0
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 +4 -4
- data/examples/my_app.rb +3 -12
- data/examples/my_app_2.rb +20 -0
- data/examples/my_model.rb +13 -0
- data/lib/mimi/db/dictate/dsl.rb +2 -2
- data/lib/mimi/db/dictate/explorer.rb +34 -20
- data/lib/mimi/db/dictate/migrator.rb +35 -21
- data/lib/mimi/db/dictate/schema_definition.rb +61 -28
- data/lib/mimi/db/dictate/schema_diff.rb +1 -6
- data/lib/mimi/db/dictate/type_defaults.rb +167 -0
- data/lib/mimi/db/dictate.rb +15 -53
- data/lib/mimi/db/extensions/sequel-cockroachdb.rb +39 -0
- data/lib/mimi/db/extensions/sequel-database.rb +23 -0
- data/lib/mimi/db/extensions/sequel-postgres.rb +3 -0
- data/lib/mimi/db/extensions/sequel-sqlite.rb +3 -0
- data/lib/mimi/db/extensions.rb +14 -10
- data/lib/mimi/db/foreign_key.rb +9 -7
- data/lib/mimi/db/helpers.rb +39 -41
- data/lib/mimi/db/lock.rb +4 -0
- data/lib/mimi/db/model.rb +64 -0
- data/lib/mimi/db/version.rb +1 -1
- data/lib/mimi/db.rb +50 -23
- data/lib/tasks/db.rake +9 -1
- data/mimi-db.gemspec +1 -1
- metadata +13 -5
data/lib/mimi/db/dictate.rb
CHANGED
@@ -3,65 +3,26 @@ require_relative 'dictate/schema_definition'
|
|
3
3
|
require_relative 'dictate/schema_diff'
|
4
4
|
require_relative 'dictate/explorer'
|
5
5
|
require_relative 'dictate/migrator'
|
6
|
+
require_relative 'dictate/type_defaults'
|
6
7
|
|
7
8
|
module Mimi
|
8
9
|
module DB
|
9
10
|
module Dictate
|
10
|
-
TYPE_DEFAULTS = {
|
11
|
-
# sqlite3: {
|
12
|
-
# string: { name: 'varchar', limit: 32 }
|
13
|
-
# }
|
14
|
-
}.freeze
|
15
|
-
|
16
11
|
def self.included(base)
|
17
12
|
base.extend Mimi::DB::Dictate::DSL
|
18
13
|
end
|
19
14
|
|
20
15
|
def self.start
|
21
|
-
ActiveRecord::Base.extend Mimi::DB::Dictate::DSL
|
22
16
|
end
|
23
17
|
|
18
|
+
# Returns all registered schema definitions
|
19
|
+
#
|
20
|
+
# @return [Hash] a map of <table_name> -> <schema_definition>
|
21
|
+
#
|
24
22
|
def self.schema_definitions
|
25
23
|
@schema_definitions ||= {}
|
26
24
|
end
|
27
25
|
|
28
|
-
def self.adapter_type
|
29
|
-
ca = ActiveRecord::ConnectionAdapters
|
30
|
-
c = ActiveRecord::Base.connection
|
31
|
-
|
32
|
-
# TODO: postgres???
|
33
|
-
return :cockroachdb if ca.const_defined?(:CockroachDBAdapter) && c.is_a?(ca::PostgreSQLAdapter)
|
34
|
-
|
35
|
-
return :postgresql if ca.const_defined?(:PostgreSQLAdapter) && c.is_a?(ca::PostgreSQLAdapter)
|
36
|
-
|
37
|
-
return :mysql if ca.const_defined?(:AbstractMysqlAdapter) && c.is_a?(ca::AbstractMysqlAdapter)
|
38
|
-
|
39
|
-
return :sqlite3 if ca.const_defined?(:SQLite3Adapter) && c.is_a?(ca::SQLite3Adapter)
|
40
|
-
|
41
|
-
raise 'Unrecognized database adapter type'
|
42
|
-
end
|
43
|
-
|
44
|
-
# Returns type defaults based on given type:
|
45
|
-
# :string
|
46
|
-
# :text
|
47
|
-
# :integer etc
|
48
|
-
#
|
49
|
-
def self.type_defaults(type)
|
50
|
-
type = type.to_sym
|
51
|
-
connection_defaults = ActiveRecord::Base.connection.native_database_types
|
52
|
-
adapter_defaults = TYPE_DEFAULTS[DB::Dictate.adapter_type]
|
53
|
-
d = (adapter_defaults && adapter_defaults[type]) || connection_defaults[type] || {}
|
54
|
-
d = {
|
55
|
-
sql_type: d.is_a?(String) ? d : d[:name],
|
56
|
-
limit: d.is_a?(String) ? nil : d[:limit]
|
57
|
-
}
|
58
|
-
if type == :primary_key
|
59
|
-
d[:primary_key] = true
|
60
|
-
d[:not_null] = true
|
61
|
-
end
|
62
|
-
d
|
63
|
-
end
|
64
|
-
|
65
26
|
# Updates the DB schema to the target schema defined in models
|
66
27
|
#
|
67
28
|
# Default options from Migrator::DEFAULTS:
|
@@ -71,18 +32,18 @@ module Mimi
|
|
71
32
|
# indexes: false
|
72
33
|
# },
|
73
34
|
# dry_run: false,
|
74
|
-
# logger: nil # will use
|
35
|
+
# logger: nil # will use Mimi::DB.logger
|
75
36
|
#
|
76
37
|
# @param opts [Hash]
|
77
38
|
#
|
78
39
|
def self.update_schema!(opts = {})
|
79
|
-
logger = opts[:logger] ||
|
80
|
-
logger.
|
40
|
+
logger = opts[:logger] || Mimi::DB.logger
|
41
|
+
logger.debug 'Mimi::DB::Dictate started updating DB schema'
|
81
42
|
t_start = Time.now
|
82
43
|
Mimi::DB.all_table_names.each { |t| Mimi::DB::Dictate::Migrator.new(t, opts).run! }
|
83
|
-
logger.
|
44
|
+
logger.debug 'Mimi::DB::Dictate finished updating DB schema (%.3fs)' % [Time.now - t_start]
|
84
45
|
rescue StandardError => e
|
85
|
-
logger.error "DB::Dictate failed to update DB schema: #{e}"
|
46
|
+
logger.error "Mimi::DB::Dictate failed to update DB schema: #{e}"
|
86
47
|
raise
|
87
48
|
end
|
88
49
|
|
@@ -92,22 +53,23 @@ module Mimi
|
|
92
53
|
# @return [Hash]
|
93
54
|
#
|
94
55
|
def self.diff_schema(opts = {})
|
95
|
-
logger = opts[:logger] ||
|
96
|
-
diff = { add_tables: [], change_tables: [], drop_tables: []}
|
56
|
+
logger = opts[:logger] || Mimi::DB.logger
|
57
|
+
diff = { add_tables: [], change_tables: [], drop_tables: [] }
|
97
58
|
Mimi::DB.all_table_names.each do |t|
|
98
59
|
m = Mimi::DB::Dictate::Migrator.new(t, opts)
|
99
60
|
if m.from_schema && m.to_schema.nil?
|
100
61
|
diff[:drop_tables] << t
|
101
62
|
elsif m.from_schema && m.to_schema
|
63
|
+
logger.debug "DB::Dictate comparing '#{t}'"
|
102
64
|
t_diff = Mimi::DB::Dictate::SchemaDiff.diff(m.from_schema, m.to_schema)
|
103
65
|
diff[:change_tables] << t_diff unless t_diff[:columns].empty? && t_diff[:indexes].empty?
|
104
|
-
elsif m.from_schema.nil? &&
|
66
|
+
elsif m.from_schema.nil? && m.to_schema
|
105
67
|
diff[:add_tables] << m.to_schema
|
106
68
|
end
|
107
69
|
end
|
108
70
|
diff
|
109
71
|
rescue StandardError => e
|
110
|
-
logger.error "DB::Dictate failed to
|
72
|
+
logger.error "DB::Dictate failed to compare schema: #{e}"
|
111
73
|
raise
|
112
74
|
end
|
113
75
|
end # module Dictate
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'sequel/adapters/postgres'
|
4
|
+
|
5
|
+
module Sequel
|
6
|
+
#
|
7
|
+
# A simplistic and not fully functional CockroachDB adapter
|
8
|
+
#
|
9
|
+
# TODO: to replace with a better alternative once available
|
10
|
+
#
|
11
|
+
module Cockroach
|
12
|
+
class Database < Sequel::Postgres::Database
|
13
|
+
set_adapter_scheme :cockroach
|
14
|
+
set_adapter_scheme :cockroachdb
|
15
|
+
|
16
|
+
# Cockroach DB only supports one savepoint
|
17
|
+
def supports_savepoints?
|
18
|
+
false
|
19
|
+
end
|
20
|
+
|
21
|
+
def server_version(*)
|
22
|
+
80000 # mimics Postgres v8
|
23
|
+
# 100000 # mimics Postgres v10
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def dataset_class_default
|
29
|
+
Dataset
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class Dataset < Sequel::Postgres::Dataset
|
34
|
+
def default_timestamp_format
|
35
|
+
"'%Y-%m-%d %H:%M:%S%N%:z'"
|
36
|
+
end
|
37
|
+
end # class Dataset
|
38
|
+
end # module Cockroach
|
39
|
+
end # module Sequel
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'sequel'
|
4
|
+
|
5
|
+
module Sequel
|
6
|
+
class Database
|
7
|
+
#
|
8
|
+
# Fixed behaviour for Sequel's log_exception()
|
9
|
+
#
|
10
|
+
# Reason:
|
11
|
+
# * handled exceptions should not be logged as errors
|
12
|
+
# * unhandled exceptions will be logged at the application level
|
13
|
+
#
|
14
|
+
def log_exception(exception, message, *)
|
15
|
+
text_message = "#{self.class}(#{exception.class}): #{exception.message}"
|
16
|
+
logger_message = { m: text_message, sql: message }
|
17
|
+
|
18
|
+
# In case logger does not support structured data, implement a #to_s method
|
19
|
+
logger_message.define_singleton_method(:to_s) { text_message }
|
20
|
+
log_each(:debug, logger_message)
|
21
|
+
end
|
22
|
+
end # class Database
|
23
|
+
end # module Sequel
|
data/lib/mimi/db/extensions.rb
CHANGED
@@ -2,16 +2,20 @@ module Mimi
|
|
2
2
|
module DB
|
3
3
|
module Extensions
|
4
4
|
def self.start
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
5
|
+
adapter_name = Mimi::DB.sequel_config[:adapter]
|
6
|
+
require_relative 'extensions/sequel-database'
|
7
|
+
case adapter_name
|
8
|
+
when 'sqlite'
|
9
|
+
require_relative 'extensions/sequel-sqlite'
|
10
|
+
when 'postgres'
|
11
|
+
require_relative 'extensions/sequel-postgres'
|
12
|
+
when 'cockroachdb'
|
13
|
+
require_relative 'extensions/sequel-postgres'
|
14
|
+
require_relative 'extensions/sequel-cockroachdb'
|
15
|
+
else
|
16
|
+
# load nothing
|
17
|
+
end
|
18
|
+
Sequel::Model.plugin :timestamps
|
15
19
|
end
|
16
20
|
end # module Extensions
|
17
21
|
end # module DB
|
data/lib/mimi/db/foreign_key.rb
CHANGED
@@ -1,20 +1,22 @@
|
|
1
1
|
module Mimi
|
2
2
|
module DB
|
3
3
|
module ForeignKey
|
4
|
-
|
4
|
+
# TODO: refactor and re-implement
|
5
5
|
|
6
|
-
|
6
|
+
# extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
# class_methods do
|
7
9
|
#
|
8
10
|
# Explicitly specify a (bigint) foreign key
|
9
11
|
#
|
10
|
-
def foreign_key(name, opts = {})
|
11
|
-
|
12
|
-
raise 'Not implemented'
|
12
|
+
# def foreign_key(name, opts = {})
|
13
|
+
|
14
|
+
# raise 'Not implemented'
|
13
15
|
|
14
16
|
# opts = { as: :integer, limit: 8 }.merge(opts)
|
15
17
|
# field(name, opts)
|
16
18
|
# index(name)
|
17
|
-
end
|
19
|
+
# end
|
18
20
|
|
19
21
|
# Redefines .belongs_to() with explicitly specified .foreign_key
|
20
22
|
#
|
@@ -25,7 +27,7 @@ module Mimi
|
|
25
27
|
# # orig_belongs_to(name, opts)
|
26
28
|
# super
|
27
29
|
# end
|
28
|
-
end
|
30
|
+
# end
|
29
31
|
end # module ForeignKey
|
30
32
|
end # module DB
|
31
33
|
end # module Mimi
|
data/lib/mimi/db/helpers.rb
CHANGED
@@ -7,7 +7,7 @@ module Mimi
|
|
7
7
|
# @return [Array<ActiveRecord::Base>]
|
8
8
|
#
|
9
9
|
def models
|
10
|
-
|
10
|
+
Mimi::DB::Model.descendants
|
11
11
|
end
|
12
12
|
|
13
13
|
# Returns a list of table names defined in models
|
@@ -23,7 +23,7 @@ module Mimi
|
|
23
23
|
# @return [Array<String>]
|
24
24
|
#
|
25
25
|
def db_table_names
|
26
|
-
|
26
|
+
Mimi::DB.connection.tables
|
27
27
|
end
|
28
28
|
|
29
29
|
# Returns a list of all discovered table names,
|
@@ -56,6 +56,7 @@ module Mimi
|
|
56
56
|
# Mimi::DB.update_schema!(destructive: true)
|
57
57
|
#
|
58
58
|
def update_schema!(opts = {})
|
59
|
+
Mimi::DB.start
|
59
60
|
opts[:logger] ||= Mimi::DB.logger
|
60
61
|
Mimi::DB::Dictate.update_schema!(opts)
|
61
62
|
end
|
@@ -84,6 +85,7 @@ module Mimi
|
|
84
85
|
# @return [Hash]
|
85
86
|
#
|
86
87
|
def diff_schema(opts = {})
|
88
|
+
Mimi::DB.start
|
87
89
|
opts[:logger] ||= Mimi::DB.logger
|
88
90
|
Mimi::DB::Dictate.diff_schema(opts)
|
89
91
|
end
|
@@ -91,29 +93,16 @@ module Mimi
|
|
91
93
|
# Creates the database specified in the current configuration.
|
92
94
|
#
|
93
95
|
def create!
|
94
|
-
|
95
|
-
db_database = Mimi::DB.active_record_config['database']
|
96
|
-
slim_url = "#{db_adapter}//<host>:<port>/#{db_database}"
|
97
|
-
Mimi::DB.logger.info "Mimi::DB.create! creating database: #{slim_url}"
|
98
|
-
original_stdout = $stdout
|
99
|
-
original_stderr = $stderr
|
100
|
-
$stdout = StringIO.new
|
101
|
-
$stderr = StringIO.new
|
102
|
-
ActiveRecord::Tasks::DatabaseTasks.root = Mimi.app_root_path
|
103
|
-
ActiveRecord::Tasks::DatabaseTasks.create(Mimi::DB.active_record_config)
|
104
|
-
Mimi::DB.logger.debug "Mimi::DB.create! out:#{$stdout.string}, err:#{$stderr.string}"
|
105
|
-
ensure
|
106
|
-
$stdout = original_stdout
|
107
|
-
$stderr = original_stderr
|
96
|
+
raise 'Not implemented'
|
108
97
|
end
|
109
98
|
|
110
99
|
# Tries to establish connection, returns true if the database exist
|
111
100
|
#
|
112
101
|
def database_exist?
|
113
|
-
|
114
|
-
ActiveRecord::Base.connection
|
102
|
+
Mimi::DB.connection.test_connection
|
115
103
|
true
|
116
|
-
rescue
|
104
|
+
rescue StandardError => e
|
105
|
+
Mimi::DB.logger.error "DB: database_exist? failed with: #{e}"
|
117
106
|
false
|
118
107
|
end
|
119
108
|
|
@@ -130,31 +119,17 @@ module Mimi
|
|
130
119
|
# Drops the database specified in the current configuration.
|
131
120
|
#
|
132
121
|
def drop!
|
133
|
-
|
134
|
-
original_stderr = $stderr
|
135
|
-
$stdout = StringIO.new
|
136
|
-
$stderr = StringIO.new
|
137
|
-
ActiveRecord::Tasks::DatabaseTasks.root = Mimi.app_root_path
|
138
|
-
ActiveRecord::Tasks::DatabaseTasks.drop(Mimi::DB.active_record_config)
|
139
|
-
Mimi::DB.logger.debug "Mimi::DB.drop! out:#{$stdout.string}, err:#{$stderr.string}"
|
140
|
-
ensure
|
141
|
-
$stdout = original_stdout
|
142
|
-
$stderr = original_stderr
|
122
|
+
raise 'Not implemented'
|
143
123
|
end
|
144
124
|
|
145
125
|
# Clears (but not drops) the database specified in the current configuration.
|
146
126
|
#
|
147
127
|
def clear!
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
ActiveRecord::Tasks::DatabaseTasks.purge(Mimi::DB.active_record_config)
|
154
|
-
Mimi::DB.logger.debug "Mimi::DB.clear! out:#{$stdout.string}, err:#{$stderr.string}"
|
155
|
-
ensure
|
156
|
-
$stdout = original_stdout
|
157
|
-
$stderr = original_stderr
|
128
|
+
Mimi::DB.start
|
129
|
+
db_table_names.each do |table_name|
|
130
|
+
Mimi::DB.logger.debug "Mimi::DB dropping table: #{table_name}"
|
131
|
+
Mimi::DB.connection.drop_table(table_name)
|
132
|
+
end
|
158
133
|
end
|
159
134
|
|
160
135
|
# Executes raw SQL, with variables interpolation.
|
@@ -163,8 +138,31 @@ module Mimi
|
|
163
138
|
# Mimi::DB.execute('insert into table1 values(?, ?, ?)', 'foo', :bar, 123)
|
164
139
|
#
|
165
140
|
def execute(statement, *args)
|
166
|
-
sql =
|
167
|
-
|
141
|
+
sql = Sequel.fetch(statement, *args).sql
|
142
|
+
Mimi::DB.connection.run(sql)
|
143
|
+
end
|
144
|
+
|
145
|
+
# Starts a transaction and executes a given block within the transaction
|
146
|
+
#
|
147
|
+
# @param params [Hash] parameters to Sequel #transaction() method
|
148
|
+
#
|
149
|
+
def transaction(params = {}, &_block)
|
150
|
+
unless Mimi::DB.connection
|
151
|
+
raise 'Failed to start transaction, Mimi::DB.connection not available'
|
152
|
+
end
|
153
|
+
Mimi::DB.connection.transaction(params) { yield }
|
154
|
+
end
|
155
|
+
|
156
|
+
# Executes a block with a given DB log level
|
157
|
+
#
|
158
|
+
# @param log_level [Symbol,nil] :debug, :info etc
|
159
|
+
#
|
160
|
+
def with_log_level(log_level, &_block)
|
161
|
+
current_log_level = Mimi::DB.connection.sql_log_level
|
162
|
+
Mimi::DB.connection.sql_log_level = log_level
|
163
|
+
yield
|
164
|
+
ensure
|
165
|
+
Mimi::DB.connection.sql_log_level = current_log_level
|
168
166
|
end
|
169
167
|
end # module Helpers
|
170
168
|
|
data/lib/mimi/db/lock.rb
CHANGED
@@ -49,6 +49,10 @@ module Mimi
|
|
49
49
|
end
|
50
50
|
|
51
51
|
def lock!(name, opts = {}, &block)
|
52
|
+
raise 'Not implemented'
|
53
|
+
|
54
|
+
# FIXME: migrate Mimi::DB::Lock to Sequel
|
55
|
+
|
52
56
|
opts = Mimi::DB::Lock.module_options[:default_lock_options].merge(opts.dup)
|
53
57
|
adapter_name = ActiveRecord::Base.connection.adapter_name.downcase.to_sym
|
54
58
|
case adapter_name
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# NOTE: this is the way to create an abstract class that inherits from Sequel::Model
|
4
|
+
Mimi::DB::Model = Class.new(Sequel::Model)
|
5
|
+
|
6
|
+
module Mimi
|
7
|
+
module DB
|
8
|
+
class Model
|
9
|
+
include Mimi::DB::Dictate
|
10
|
+
|
11
|
+
self.require_valid_table = false
|
12
|
+
plugin :timestamps, create: :created_at, update: :updated_at, update_on_create: true
|
13
|
+
plugin :validation_helpers
|
14
|
+
|
15
|
+
# Keeps messages as error types, not human readable strings
|
16
|
+
#
|
17
|
+
def default_validation_helpers_options(type)
|
18
|
+
{ message: type }
|
19
|
+
end
|
20
|
+
|
21
|
+
def before_validation
|
22
|
+
super
|
23
|
+
call_hooks(:before_validation)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Defines a hook the ActiveRecord way
|
27
|
+
#
|
28
|
+
# Example:
|
29
|
+
#
|
30
|
+
# class A < Mimi::DB::Model
|
31
|
+
# before_validation :set_detaults
|
32
|
+
#
|
33
|
+
# def set_defaults
|
34
|
+
# self.name = "John Doe"
|
35
|
+
# end
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
def self.before_validation(method = nil, &block)
|
39
|
+
if method && block
|
40
|
+
raise ArgumentError, '.before_validation() cannot accept both method and a block'
|
41
|
+
end
|
42
|
+
block = -> { send(method) } if method
|
43
|
+
register_hook(:before_validation, block)
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def self.registered_hooks(name)
|
49
|
+
@registered_hooks ||= {}
|
50
|
+
@registered_hooks[name] ||= []
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.register_hook(name, block)
|
54
|
+
registered_hooks(name) << block
|
55
|
+
end
|
56
|
+
|
57
|
+
def call_hooks(name)
|
58
|
+
self.class.registered_hooks(name).each do |block|
|
59
|
+
instance_eval(&block)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end # class Model
|
63
|
+
end # module DB
|
64
|
+
end # module Mimi
|
data/lib/mimi/db/version.rb
CHANGED
data/lib/mimi/db.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'mimi/core'
|
2
|
-
require '
|
2
|
+
require 'sequel'
|
3
3
|
|
4
4
|
module Mimi
|
5
5
|
module DB
|
@@ -13,12 +13,8 @@ module Mimi
|
|
13
13
|
db_port: nil,
|
14
14
|
db_username: nil,
|
15
15
|
db_password: nil,
|
16
|
-
db_log_level: :
|
17
|
-
db_pool: 15
|
18
|
-
db_primary_key_cockroachdb: nil,
|
19
|
-
db_primary_key_postgresql: nil,
|
20
|
-
db_primary_key_mysql: nil,
|
21
|
-
db_primary_key_sqlite3: nil
|
16
|
+
db_log_level: :debug,
|
17
|
+
db_pool: 15
|
22
18
|
# db_encoding:
|
23
19
|
)
|
24
20
|
|
@@ -58,45 +54,75 @@ module Mimi
|
|
58
54
|
},
|
59
55
|
db_log_level: {
|
60
56
|
desc: 'Logging level for database layer ("debug", "info" etc)',
|
61
|
-
default: '
|
57
|
+
default: 'debug'
|
62
58
|
}
|
63
59
|
}
|
64
60
|
end
|
65
61
|
|
66
62
|
def self.configure(*)
|
67
63
|
super
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
# TODO: test and remove deprectated ...
|
73
|
-
# ActiveRecord::Base.raise_in_transactional_callbacks = true
|
64
|
+
if Mimi.const_defined?(:Application)
|
65
|
+
@logger = Mimi::Application.logger
|
66
|
+
end
|
74
67
|
end
|
75
68
|
|
76
69
|
def self.logger
|
77
|
-
@logger ||= Mimi::Logger.new
|
70
|
+
@logger ||= Mimi::Logger.new
|
71
|
+
end
|
72
|
+
|
73
|
+
# Returns active DB connection
|
74
|
+
#
|
75
|
+
# @return [Sequel::<...>::Database]
|
76
|
+
#
|
77
|
+
def self.connection
|
78
|
+
@connection
|
78
79
|
end
|
79
80
|
|
80
81
|
def self.start
|
81
|
-
ActiveRecord::Base.establish_connection(:default)
|
82
82
|
Mimi::DB::Extensions.start
|
83
|
-
|
83
|
+
@connection = Sequel.connect(sequel_config)
|
84
84
|
Mimi.require_files(module_options[:require_files]) if module_options[:require_files]
|
85
85
|
super
|
86
86
|
end
|
87
87
|
|
88
|
-
|
88
|
+
# Returns a standard Sequel adapter name converted from any variation of adapter names.
|
89
|
+
#
|
90
|
+
# @example
|
91
|
+
# sequel_config_canonical_adapter_name(:sqlite3) # => 'sqlite'
|
92
|
+
#
|
93
|
+
# @param adapter_name [String,Symbol]
|
94
|
+
# @return [String]
|
95
|
+
#
|
96
|
+
def self.sequel_config_canonical_adapter_name(adapter_name)
|
97
|
+
case adapter_name.to_s.downcase
|
98
|
+
when 'sqlite', 'sqlite3'
|
99
|
+
'sqlite'
|
100
|
+
when 'postgres', 'postgresql'
|
101
|
+
'postgres'
|
102
|
+
when 'cockroach', 'cockroachdb'
|
103
|
+
'cockroachdb'
|
104
|
+
else
|
105
|
+
adapter_name.to_s.downcase
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# Returns Sequel connection parameters
|
110
|
+
#
|
111
|
+
# @return [Hash]
|
112
|
+
#
|
113
|
+
def self.sequel_config
|
89
114
|
{
|
90
|
-
adapter: module_options[:db_adapter],
|
115
|
+
adapter: sequel_config_canonical_adapter_name(module_options[:db_adapter]),
|
91
116
|
database: module_options[:db_database],
|
92
117
|
host: module_options[:db_host],
|
93
118
|
port: module_options[:db_port],
|
94
|
-
|
119
|
+
user: module_options[:db_username],
|
95
120
|
password: module_options[:db_password],
|
96
121
|
encoding: module_options[:db_encoding],
|
97
|
-
|
98
|
-
|
99
|
-
|
122
|
+
max_connections: module_options[:db_pool],
|
123
|
+
sql_log_level: module_options[:db_log_level],
|
124
|
+
logger: logger
|
125
|
+
}
|
100
126
|
end
|
101
127
|
end # module DB
|
102
128
|
end # module Mimi
|
@@ -106,3 +132,4 @@ require_relative 'db/extensions'
|
|
106
132
|
require_relative 'db/helpers'
|
107
133
|
require_relative 'db/foreign_key'
|
108
134
|
require_relative 'db/dictate'
|
135
|
+
require_relative 'db/model'
|
data/lib/tasks/db.rake
CHANGED
@@ -40,17 +40,22 @@ namespace :db do
|
|
40
40
|
namespace :migrate do
|
41
41
|
desc 'Migrate database (seeds only)'
|
42
42
|
task seeds: :"db:start" do
|
43
|
+
logger.info "* Processing database seeds: #{Mimi::DB.module_options[:db_database]}"
|
44
|
+
t_start = Time.now
|
43
45
|
seeds = Pathname.glob(Mimi.app_path_to('db', 'seeds', '**', '*.rb')).sort
|
44
46
|
seeds.each do |seed_filename|
|
45
|
-
logger.info "
|
47
|
+
logger.info "-- Processing seed: #{seed_filename}"
|
46
48
|
load seed_filename
|
47
49
|
end
|
50
|
+
logger.info '* Finished processing database seeds (%.3fs)' % (Time.now - t_start)
|
48
51
|
end
|
49
52
|
|
50
53
|
desc 'Migrate database (schema only)'
|
51
54
|
task schema: :"db:start" do
|
52
55
|
logger.info "* Updating database schema: #{Mimi::DB.module_options[:db_database]}"
|
56
|
+
t_start = Time.now
|
53
57
|
Mimi::DB.update_schema!(destructive: true)
|
58
|
+
logger.info '* Finished updating database schema (%.3fs)' % (Time.now - t_start)
|
54
59
|
end
|
55
60
|
|
56
61
|
namespace :schema do
|
@@ -88,6 +93,9 @@ namespace :db do
|
|
88
93
|
diff[:drop_tables].each do |t|
|
89
94
|
puts "-- DROP table: #{t}"
|
90
95
|
end
|
96
|
+
if diff[:add_tables].empty? && diff[:change_tables].empty? && diff[:drop_tables].empty?
|
97
|
+
logger.info '* Diff database schema: no changes detected'
|
98
|
+
end
|
91
99
|
end
|
92
100
|
end
|
93
101
|
end
|
data/mimi-db.gemspec
CHANGED
@@ -29,7 +29,7 @@ Gem::Specification.new do |spec|
|
|
29
29
|
|
30
30
|
spec.add_dependency 'mimi-core', '~> 0.2'
|
31
31
|
spec.add_dependency 'mimi-logger', '~> 0.2'
|
32
|
-
spec.add_dependency '
|
32
|
+
spec.add_dependency 'sequel', '~> 5.8'
|
33
33
|
|
34
34
|
spec.add_development_dependency 'bundler', '~> 1.11'
|
35
35
|
spec.add_development_dependency 'rake', '~> 10.0'
|