active_record_mysql_repl 0.1.0 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +3 -0
- data/.standard.yml +3 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/LICENSE.txt +21 -0
- data/README.md +43 -0
- data/Rakefile +10 -0
- data/exe/army +5 -0
- data/json_schemas/army_schema.json +34 -0
- data/json_schemas/association_schema.json +80 -0
- data/json_schemas/databases_schema.json +61 -0
- data/lib/active_record_mysql_repl/cli/erd.rb +11 -0
- data/lib/active_record_mysql_repl/cli/main.rb +60 -0
- data/lib/active_record_mysql_repl/cli/options.rb +13 -0
- data/lib/active_record_mysql_repl/cli/zsh_completion.rb +37 -0
- data/lib/active_record_mysql_repl/cli.rb +10 -0
- data/lib/active_record_mysql_repl/config.rb +38 -0
- data/lib/active_record_mysql_repl/database/association/analysis.rb +17 -0
- data/lib/active_record_mysql_repl/database/association/definition.rb +0 -0
- data/lib/active_record_mysql_repl/database/association.rb +83 -0
- data/lib/active_record_mysql_repl/database/configs.rb +53 -0
- data/lib/active_record_mysql_repl/database/connection.rb +42 -0
- data/lib/active_record_mysql_repl/database/loader.rb +63 -0
- data/lib/active_record_mysql_repl/database.rb +10 -0
- data/lib/active_record_mysql_repl/extensions/active_record.rb +32 -0
- data/lib/active_record_mysql_repl/extensions/global.rb +29 -0
- data/lib/active_record_mysql_repl/extensions/hash.rb +20 -0
- data/lib/active_record_mysql_repl/extensions/object.rb +138 -0
- data/lib/active_record_mysql_repl/extensions/tabler.rb +32 -0
- data/lib/active_record_mysql_repl/extensions.rb +18 -0
- data/lib/active_record_mysql_repl/ssh_tunnel.rb +21 -0
- data/lib/active_record_mysql_repl/version.rb +5 -0
- data/lib/active_record_mysql_repl.rb +12 -0
- data/sample_config/.army.sample.yml +6 -0
- data/sample_config/.pryrc.sample +9 -0
- data/sample_config/associations.sample.yml +13 -0
- data/sample_config/databases.sample.yml +9 -0
- data/sample_config/sample_db.sql +153 -0
- metadata +75 -36
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecordMysqlRepl
|
4
|
+
module Database
|
5
|
+
class Associations
|
6
|
+
class AnalyzedTable
|
7
|
+
attr_accessor :name, :has_many, :has_one, :belongs_to
|
8
|
+
def initialize(name)
|
9
|
+
@name = name
|
10
|
+
@has_many = []
|
11
|
+
@has_one = []
|
12
|
+
@belongs_to = []
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.load(path)
|
17
|
+
new(YAML.load_file(path, aliases: true))
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize(associations)
|
21
|
+
@associations = associations.map { |key, association| [key, Association.new(association)] }.to_h
|
22
|
+
end
|
23
|
+
|
24
|
+
def [](key)
|
25
|
+
@associations[key]
|
26
|
+
end
|
27
|
+
|
28
|
+
# Analyze the relationship between tables based on the information of *_id columns
|
29
|
+
# For example, if users.company_id exists, users belongs_to companies and companies has_many users
|
30
|
+
def self.analyze(tables, association_settings)
|
31
|
+
analyzed_tables = tables.map { |table| [table, AnalyzedTable.new(table)] }.to_h
|
32
|
+
|
33
|
+
analyzed_tables.each do |table_name, table|
|
34
|
+
association_setting = association_settings[table_name]
|
35
|
+
columns = ActiveRecord::Base.connection.columns(table_name)
|
36
|
+
columns.each do |column|
|
37
|
+
next if association_setting.present? && association_settings.ignore_columns(table_name).include?(column.name)
|
38
|
+
|
39
|
+
associatable = column.name.gsub(/_id$/, '') if column.name.end_with?('_id')
|
40
|
+
next if associatable.blank? || associatable == 'class' # reserved word
|
41
|
+
|
42
|
+
if analyzed_tables.keys.include?(associatable.pluralize)
|
43
|
+
table.belongs_to << associatable.singularize if associatable
|
44
|
+
analyzed_tables[associatable.pluralize].has_many << table_name.pluralize
|
45
|
+
else
|
46
|
+
associatable_table_name = associatable.split('_').last
|
47
|
+
if analyzed_tables.keys.include?(associatable_table_name.pluralize)
|
48
|
+
table.belongs_to << { name: associatable, class_name: associatable_table_name.classify, foreign_key: :id }
|
49
|
+
else
|
50
|
+
table.belongs_to << { name: associatable, class_name: table_name.singularize.classify, foreign_key: :id }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
next if association_setting.blank?
|
56
|
+
|
57
|
+
# merge yaml settings
|
58
|
+
[:has_many, :belongs_to].each do |type|
|
59
|
+
ass = association_setting.fetch(type.to_s, []).map(&:symbolize_keys)
|
60
|
+
table.send(type).concat(ass) unless ass.blank?
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
analyzed_tables.values
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class Association
|
69
|
+
def initialize(association)
|
70
|
+
@association = association
|
71
|
+
end
|
72
|
+
|
73
|
+
def [](table)
|
74
|
+
table = (@association.keys - ['ignore_columns']) & [table]
|
75
|
+
@association[table.first] if table.present?
|
76
|
+
end
|
77
|
+
|
78
|
+
def ignore_columns(table)
|
79
|
+
@association.fetch('ignore_columns', {}).fetch(table, [])
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecordMysqlRepl
|
4
|
+
module Database
|
5
|
+
class Configs
|
6
|
+
attr_reader :configs
|
7
|
+
|
8
|
+
def self.load(path)
|
9
|
+
new(YAML.load_file(path))
|
10
|
+
end
|
11
|
+
|
12
|
+
def [](key)
|
13
|
+
configs[key]
|
14
|
+
end
|
15
|
+
|
16
|
+
def keys
|
17
|
+
configs.keys
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def initialize(configs)
|
23
|
+
@configs = configs.map { |key, config| [key, Config.new(config)] }.to_h
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
class Config
|
30
|
+
attr_reader *%i[
|
31
|
+
bastion
|
32
|
+
ssh_user
|
33
|
+
remote_host
|
34
|
+
database
|
35
|
+
port
|
36
|
+
user
|
37
|
+
password
|
38
|
+
prompt_color
|
39
|
+
]
|
40
|
+
|
41
|
+
def initialize(config)
|
42
|
+
@bastion = config["bastion"]
|
43
|
+
@ssh_user = config["ssh_user"]
|
44
|
+
@remote_host = config["remote_host"]
|
45
|
+
@database = config["database"]
|
46
|
+
@port = config["port"]
|
47
|
+
@user = config["user"]
|
48
|
+
@password = config["password"]
|
49
|
+
@prompt_color = config["prompt_color"]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecordMysqlRepl
|
4
|
+
module Database
|
5
|
+
module Connection
|
6
|
+
MAX_RETRY = 3
|
7
|
+
|
8
|
+
def self.connect(db_config, port)
|
9
|
+
conn = {
|
10
|
+
adapter: 'mysql2',
|
11
|
+
host: '127.0.0.1',
|
12
|
+
port: port,
|
13
|
+
username: db_config.user,
|
14
|
+
password: db_config.password,
|
15
|
+
database: db_config.database,
|
16
|
+
}
|
17
|
+
|
18
|
+
ActiveRecord::Base.logger = Logger.new(STDOUT)
|
19
|
+
conn = ActiveRecord::Base.establish_connection(conn)
|
20
|
+
|
21
|
+
puts "Ensureing connection to #{db_config.database} on port 127.0.0.1:#{port}".gray
|
22
|
+
|
23
|
+
tables = nil
|
24
|
+
(1..MAX_RETRY-1).to_a.each do |time|
|
25
|
+
begin
|
26
|
+
tables = ActiveRecord::Base.connection.tables
|
27
|
+
rescue => e
|
28
|
+
puts "#{e}, Retry #{time}/#{MAX_RETRY}".red
|
29
|
+
sleep time*time
|
30
|
+
next
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
if tables.blank?
|
35
|
+
raise "Retred #{MAX_RETRY} times, but failed to connect to database."
|
36
|
+
end
|
37
|
+
|
38
|
+
yield if block_given?
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'active_record'
|
5
|
+
require 'active_support/all'
|
6
|
+
|
7
|
+
module ActiveRecordMysqlRepl
|
8
|
+
module Database
|
9
|
+
module Loader
|
10
|
+
def self.load_tables(db_config_key, army_config, port)
|
11
|
+
puts "Loading tables".gray
|
12
|
+
|
13
|
+
tables = ActiveRecord::Base.connection.tables
|
14
|
+
association_settings = Associations.load(army_config.associations)
|
15
|
+
|
16
|
+
analyzed_tables = Associations.analyze(tables, association_settings[db_config_key])
|
17
|
+
skipped = []
|
18
|
+
analyzed_tables.each do |analyzed_table|
|
19
|
+
# defer model definition for tables with `has_many: :xxx, through: xxx` associations
|
20
|
+
if analyzed_table.has_many.any? { |hm| hm.is_a?(Hash) && hm.key?(:through) }
|
21
|
+
skipped << analyzed_table
|
22
|
+
next
|
23
|
+
end
|
24
|
+
define_model(analyzed_table)
|
25
|
+
end
|
26
|
+
|
27
|
+
skipped.each do |analyzed_table|
|
28
|
+
define_model(analyzed_table)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.define_model(analyzed_table)
|
33
|
+
klass = Class.new(ActiveRecord::Base)
|
34
|
+
|
35
|
+
analyzed_table.has_many.each do |has_many|
|
36
|
+
if has_many.is_a?(String)
|
37
|
+
klass.has_many has_many.to_sym
|
38
|
+
elsif has_many.is_a?(Hash)
|
39
|
+
klass.has_many has_many[:name].to_sym, **has_many.except(:name)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
analyzed_table.has_one.each do |has_one|
|
44
|
+
klass.has_one has_one[:name].to_sym, class_name: has_one[:class_name], foreign_key: has_one[:foreign_key]
|
45
|
+
end
|
46
|
+
|
47
|
+
analyzed_table.belongs_to.each do |belongs_to|
|
48
|
+
if belongs_to.is_a?(String)
|
49
|
+
klass.belongs_to belongs_to.to_sym
|
50
|
+
elsif belongs_to.is_a?(Hash)
|
51
|
+
klass.belongs_to belongs_to[:name].to_sym, class_name: belongs_to[:class_name].to_sym
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# allow type column
|
56
|
+
klass.inheritance_column = :_type_disabled
|
57
|
+
klass.table_name = analyzed_table.name
|
58
|
+
|
59
|
+
Object.const_set(analyzed_table.name.classify, klass)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiverecordMysqlRepl
|
4
|
+
module Extensions
|
5
|
+
module ActiveRecord
|
6
|
+
module Base
|
7
|
+
def as(name = nil)
|
8
|
+
self.reflect_on_all_associations(name).map(&:name)
|
9
|
+
end
|
10
|
+
|
11
|
+
def describe
|
12
|
+
[
|
13
|
+
exec_sql("DESCRIBE #{self.table_name}").tab(:h),
|
14
|
+
exec_sql("SHOW INDEX FROM #{self.table_name}").tab(:h)
|
15
|
+
].join("\n")
|
16
|
+
end
|
17
|
+
|
18
|
+
alias desc describe
|
19
|
+
alias d describe
|
20
|
+
|
21
|
+
def show_ddl
|
22
|
+
exec_sql("SHOW CREATE TABLE #{self.table_name}")[0]['Create Table']
|
23
|
+
end
|
24
|
+
|
25
|
+
alias ddl show_ddl
|
26
|
+
end
|
27
|
+
|
28
|
+
::ActiveRecord::Base.extend(Base)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiverecordMysqlRepl
|
4
|
+
module Extensions
|
5
|
+
module Global
|
6
|
+
def tables
|
7
|
+
::ActiveRecord::Base.connection.tables.map(&:singularize).map(&:classify)
|
8
|
+
end
|
9
|
+
|
10
|
+
def models
|
11
|
+
::ActiveRecord::Base.subclasses
|
12
|
+
end
|
13
|
+
|
14
|
+
def transaction
|
15
|
+
::ActiveRecord::Base.transaction { yield }
|
16
|
+
end
|
17
|
+
|
18
|
+
def exec_sql(sql)
|
19
|
+
res = ::ActiveRecord::Base.connection.select_all(sql)
|
20
|
+
res.rows.map do |row|
|
21
|
+
res.columns.zip(row).to_h
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
Kernel.include(Global)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiverecordMysqlRepl
|
4
|
+
module Extensions
|
5
|
+
module Hash
|
6
|
+
def method_missing(name, *args)
|
7
|
+
if (self.keys & [name, name.to_s]).present?
|
8
|
+
self[name] || self[name.to_s]
|
9
|
+
elsif name.to_s.end_with?('=') && self.keys.include?(name.to_s[0..-2])
|
10
|
+
name = name[0..-2]
|
11
|
+
self[name] = args.first if self.key?(name)
|
12
|
+
self[name.to_sym] = args.first if self.key?(name.to_sym)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
::Hash.include(Hash)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
@@ -0,0 +1,138 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'terminal-table'
|
4
|
+
require 'csv'
|
5
|
+
require 'clipboard'
|
6
|
+
require 'json'
|
7
|
+
|
8
|
+
module ActiverecordMysqlRepl
|
9
|
+
module Extensions
|
10
|
+
module Object
|
11
|
+
def tabulate(orientation = nil)
|
12
|
+
arr = if self.is_a?(Array)
|
13
|
+
self
|
14
|
+
elsif self.is_a?(::ActiveRecord::Relation)
|
15
|
+
self.to_a
|
16
|
+
else
|
17
|
+
[self]
|
18
|
+
end
|
19
|
+
|
20
|
+
arr = arr.map do |e|
|
21
|
+
if e.is_a?(::ActiveRecord::Base)
|
22
|
+
values = e.attributes.transform_values do |v|
|
23
|
+
next JSON.pretty_generate(v) if v.is_a?(Enumerable) && v.size > 0
|
24
|
+
next 'NULL' if v.nil?
|
25
|
+
next '""' if v == ''
|
26
|
+
v.to_s
|
27
|
+
end
|
28
|
+
next values
|
29
|
+
end
|
30
|
+
e
|
31
|
+
end
|
32
|
+
|
33
|
+
raise "#{arr} is not an array of hash".red unless arr.all? { |e| e.is_a?(Hash) }
|
34
|
+
raise "#{arr} contains Hashes with different keys".red unless arr.map(&:keys).uniq.size == 1
|
35
|
+
|
36
|
+
orientation = case orientation
|
37
|
+
when :vertical, :v
|
38
|
+
:vertical
|
39
|
+
when :horizontal, :h
|
40
|
+
:horizontal
|
41
|
+
else
|
42
|
+
if arr.first.keys.size > 5
|
43
|
+
:vertical
|
44
|
+
else
|
45
|
+
:horizontal
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
t = Terminal::Table.new
|
50
|
+
|
51
|
+
case orientation
|
52
|
+
when :horizontal
|
53
|
+
t.headings = arr.first.keys
|
54
|
+
t.rows = arr.map(&:values)
|
55
|
+
|
56
|
+
when :vertical
|
57
|
+
t.headings = ['Name', 'Value']
|
58
|
+
arr.each.with_index do |row, i|
|
59
|
+
row.each { |col, val| t.add_row [col, val] }
|
60
|
+
t.add_separator if i < arr.size - 1
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
t.to_s
|
65
|
+
end
|
66
|
+
|
67
|
+
alias tab tabulate
|
68
|
+
alias table tabulate
|
69
|
+
alias to_table tabulate
|
70
|
+
|
71
|
+
def csv(orientation = nil)
|
72
|
+
arr = if self.is_a?(Array)
|
73
|
+
self
|
74
|
+
elsif self.is_a?(ActiveRecord::Relation)
|
75
|
+
self.to_a
|
76
|
+
else
|
77
|
+
[self]
|
78
|
+
end
|
79
|
+
|
80
|
+
arr = arr.map do |e|
|
81
|
+
if e.is_a?(ActiveRecord::Base)
|
82
|
+
values = e.attributes.transform_values do |v|
|
83
|
+
next JSON.pretty_generate(v) if v.is_a?(Enumerable) && v.size > 0
|
84
|
+
next 'NULL' if v.nil?
|
85
|
+
next '""' if v == ''
|
86
|
+
v.to_s
|
87
|
+
end
|
88
|
+
next values
|
89
|
+
end
|
90
|
+
e
|
91
|
+
end
|
92
|
+
|
93
|
+
raise "#{arr} is not an array of hash".red unless arr.all? { |e| e.is_a?(Hash) }
|
94
|
+
raise "#{arr} contains Hashes with different keys".red unless arr.map(&:keys).uniq.size == 1
|
95
|
+
|
96
|
+
orientation = case orientation
|
97
|
+
when :vertical, :v
|
98
|
+
:vertical
|
99
|
+
when :horizontal, :h
|
100
|
+
:horizontal
|
101
|
+
else
|
102
|
+
if arr.first.keys.size > 5
|
103
|
+
:vertical
|
104
|
+
else
|
105
|
+
:horizontal
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
CSV.generate do |csv|
|
110
|
+
case orientation
|
111
|
+
when :horizontal
|
112
|
+
csv << arr.first.keys
|
113
|
+
arr.each { |row| csv << row.values }
|
114
|
+
when :vertical
|
115
|
+
arr.each do |row|
|
116
|
+
row.each { |col, val| csv << [col, val] }
|
117
|
+
csv << []
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def copy
|
124
|
+
Clipboard.copy(self.to_s)
|
125
|
+
end
|
126
|
+
alias cp copy
|
127
|
+
|
128
|
+
alias j to_json
|
129
|
+
|
130
|
+
def jp
|
131
|
+
JSON.pretty_generate(JSON.parse(to_json))
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
::Object.include(Extensions::Object)
|
137
|
+
end
|
138
|
+
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiverecordMysqlRepl
|
4
|
+
module Extensions
|
5
|
+
module Tabler
|
6
|
+
::ActiveRecord::Base.subclasses.each do |model|
|
7
|
+
define_method(model.table_name) do
|
8
|
+
model.find(self)
|
9
|
+
end
|
10
|
+
|
11
|
+
define_method(model.table_name.singularize) do
|
12
|
+
model.find(self)
|
13
|
+
end
|
14
|
+
|
15
|
+
model.column_names.each do |column|
|
16
|
+
define_method("#{model.table_name.singularize}_by_#{column}") do
|
17
|
+
model.where(column => self)
|
18
|
+
end
|
19
|
+
|
20
|
+
define_method("#{model.table_name.singularize}_#{column}_like") do
|
21
|
+
model.where("#{column} like ?", "%#{self}%")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
String.include Tabler
|
28
|
+
Symbol.include Tabler
|
29
|
+
Enumerable.include Tabler
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'extensions/object'
|
4
|
+
require_relative 'extensions/global'
|
5
|
+
require_relative 'extensions/active_record'
|
6
|
+
require_relative 'extensions/hash'
|
7
|
+
require_relative 'extensions/tabler'
|
8
|
+
|
9
|
+
module ActiveRecordMysqlRepl
|
10
|
+
module Extensions
|
11
|
+
def self.load_external(dir)
|
12
|
+
Dir.glob("#{dir}/*.rb").each do |file|
|
13
|
+
require file
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'net/ssh'
|
4
|
+
require 'net/ssh/gateway'
|
5
|
+
|
6
|
+
module ActiveRecordMysqlRepl
|
7
|
+
module SSHTunnel
|
8
|
+
EPHEMERAL_PORT = 0
|
9
|
+
|
10
|
+
def self.tunnel(db_config)
|
11
|
+
return yield(db_config.port) if block_given? unless db_config.bastion
|
12
|
+
|
13
|
+
puts "Establishing ssh tunnel to #{db_config.remote_host}:#{db_config.port} via #{db_config.ssh_user}#{db_config.bastion}".gray
|
14
|
+
|
15
|
+
gateway = Net::SSH::Gateway.new(db_config.bastion, db_config.ssh_user)
|
16
|
+
gateway.open(db_config.remote_host, db_config.port) do |port|
|
17
|
+
yield(port) if block_given?
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "active_record_mysql_repl/version"
|
4
|
+
require_relative 'active_record_mysql_repl/config'
|
5
|
+
require_relative 'active_record_mysql_repl/cli'
|
6
|
+
require_relative 'active_record_mysql_repl/database'
|
7
|
+
require_relative 'active_record_mysql_repl/ssh_tunnel'
|
8
|
+
require_relative 'active_record_mysql_repl/version'
|
9
|
+
# extensions should be loaded after database connection is established
|
10
|
+
# require_relative 'active_record_mysql_repl/extensions'
|
11
|
+
|
12
|
+
module ActiveRecordMysqlRepl; end
|
@@ -0,0 +1,6 @@
|
|
1
|
+
# yaml-language-server: $schema=https://raw.githubusercontent.com/nogahighland/active_record_mysql_repl/refs/heads/main/json_schemas/army_schema.json
|
2
|
+
|
3
|
+
database_config: ./databases.sample.yml
|
4
|
+
associations: ./associations.sample.yml
|
5
|
+
extensions_dir:
|
6
|
+
pryrc: ./.pryrc.sample
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# yaml-language-server: $schema=https://raw.githubusercontent.com/nogahighland/active_record_mysql_repl/refs/heads/main/json_schemas/association_schema.json
|
2
|
+
|
3
|
+
test:
|
4
|
+
users:
|
5
|
+
belongs_to:
|
6
|
+
- name: profile
|
7
|
+
foreign_key: id
|
8
|
+
class_name: UserProfile
|
9
|
+
|
10
|
+
ignore_columns:
|
11
|
+
user:
|
12
|
+
- login_id
|
13
|
+
|
@@ -0,0 +1,9 @@
|
|
1
|
+
# yaml-language-server: $schema=https://raw.githubusercontent.com/nogahighland/active_record_mysql_repl/refs/heads/main/json_schema/databases_schema.json
|
2
|
+
|
3
|
+
test:
|
4
|
+
remote_host: 127.0.0.1
|
5
|
+
database: test
|
6
|
+
port: 3306
|
7
|
+
user: root
|
8
|
+
password: root
|
9
|
+
prompt_color: cyan
|