arql 0.3.31 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.vscode/launch.json +1 -1
- data/Gemfile.lock +1 -1
- data/README-zh_CN.org +616 -491
- data/README.org +803 -628
- data/auto-set-id-before-save-zh_CN.org +1 -1
- data/auto-set-id-before-save.org +1 -1
- data/custom-configurations-zh_CN.org +40 -3
- data/custom-configurations.org +71 -32
- data/define-associations-zh_CN.org +31 -17
- data/define-associations.org +52 -29
- data/initializer-structure-zh_CN.org +23 -5
- data/initializer-structure.org +46 -18
- data/lib/arql/app.rb +98 -71
- data/lib/arql/cli.rb +37 -15
- data/lib/arql/commands/info.rb +41 -28
- data/lib/arql/commands/models.rb +106 -61
- data/lib/arql/commands/reconnect.rb +8 -4
- data/lib/arql/commands/redefine.rb +3 -1
- data/lib/arql/commands/sandbox.rb +6 -4
- data/lib/arql/commands.rb +0 -2
- data/lib/arql/concerns/global_data_definition.rb +40 -6
- data/lib/arql/concerns/model_extension.rb +168 -0
- data/lib/arql/concerns/table_data_definition.rb +20 -20
- data/lib/arql/concerns.rb +1 -0
- data/lib/arql/definition.rb +169 -317
- data/lib/arql/ext/active_record/relation.rb +29 -0
- data/lib/arql/ext/active_record/result.rb +29 -0
- data/lib/arql/ext/array.rb +40 -1
- data/lib/arql/ext/kernel.rb +70 -61
- data/lib/arql/ext/object.rb +14 -0
- data/lib/arql/ext/ransack/search.rb +29 -0
- data/lib/arql/mysqldump.rb +0 -1
- data/lib/arql/repl.rb +1 -1
- data/lib/arql/ssh_proxy.rb +25 -22
- data/lib/arql/version.rb +1 -1
- data/lib/arql.rb +11 -7
- data/oss-files-zh_CN.org +2 -2
- data/oss-files.org +2 -2
- data/sql-log-zh_CN.org +8 -3
- data/sql-log.org +8 -3
- metadata +6 -5
- data/lib/arql/commands/table.rb +0 -55
- data/lib/arql/commands/vd.rb +0 -46
- data/lib/arql/connection.rb +0 -16
data/lib/arql/app.rb
CHANGED
@@ -1,114 +1,141 @@
|
|
1
1
|
module Arql
|
2
2
|
class App
|
3
|
+
attr_accessor :log_io, :environments, :definitions, :options, :config
|
3
4
|
|
4
5
|
class << self
|
5
|
-
attr_accessor :
|
6
|
+
attr_accessor :instance
|
6
7
|
|
7
|
-
def
|
8
|
-
|
8
|
+
def log_io
|
9
|
+
instance.log_io
|
10
|
+
end
|
11
|
+
|
12
|
+
def log_io=(io)
|
13
|
+
instance.log_io = io
|
14
|
+
end
|
15
|
+
|
16
|
+
# environment names
|
17
|
+
def environments
|
18
|
+
instance.environments
|
9
19
|
end
|
10
20
|
|
11
21
|
def prompt
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
22
|
+
instance.prompt
|
23
|
+
end
|
24
|
+
|
25
|
+
def config
|
26
|
+
instance.config
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def prompt
|
31
|
+
if environments.present?
|
32
|
+
environments.join('+')
|
33
|
+
else
|
34
|
+
File.basename(@options.database)
|
17
35
|
end
|
18
36
|
end
|
19
37
|
|
20
38
|
def initialize(options)
|
21
|
-
require "arql/connection"
|
22
39
|
require "arql/definition"
|
40
|
+
|
41
|
+
App.instance = self
|
42
|
+
|
43
|
+
# command line options
|
23
44
|
@options = options
|
24
|
-
|
25
|
-
|
26
|
-
|
45
|
+
|
46
|
+
# env names
|
47
|
+
@environments = @options.environments
|
48
|
+
@environments ||= ['default']
|
49
|
+
|
27
50
|
print "Defining models..."
|
28
|
-
@
|
51
|
+
@definitions = config[:environments].each_with_object({}) do |(env_name, env_conf), h|
|
52
|
+
h[env_name] = Definition.new(env_conf)
|
53
|
+
end.with_indifferent_access
|
54
|
+
|
29
55
|
print "\u001b[2K"
|
30
56
|
puts "\rModels defined"
|
31
57
|
print "Running initializers..."
|
32
58
|
load_initializer!
|
33
59
|
print "\u001b[2K"
|
34
60
|
puts "\rInitializers loaded"
|
35
|
-
App.instance = self
|
36
|
-
end
|
37
|
-
|
38
|
-
def connect_options
|
39
|
-
connect_conf = effective_config.slice(:adapter, :host, :username,
|
40
|
-
:password, :database, :encoding,
|
41
|
-
:pool, :port, :socket)
|
42
|
-
if effective_config[:ssh].present?
|
43
|
-
connect_conf.merge!(start_ssh_proxy!)
|
44
|
-
end
|
45
|
-
|
46
|
-
connect_conf
|
47
61
|
end
|
48
62
|
|
49
63
|
def load_initializer!
|
50
|
-
return unless
|
51
|
-
|
64
|
+
return unless config[:options][:initializer]
|
65
|
+
|
66
|
+
initializer_file = File.expand_path(config[:options][:initializer])
|
52
67
|
unless File.exist?(initializer_file)
|
53
|
-
|
68
|
+
warn "Specified initializer file not found, #{config[:options][:initializer]}"
|
54
69
|
exit(1)
|
55
70
|
end
|
56
71
|
load(initializer_file)
|
57
72
|
end
|
58
73
|
|
59
|
-
def
|
60
|
-
|
61
|
-
local_ssh_proxy_port = Arql::SSHProxy.connect(ssh_config.slice(:host, :user, :port, :password).merge(
|
62
|
-
forward_host: effective_config[:host],
|
63
|
-
forward_port: effective_config[:port],
|
64
|
-
local_port: ssh_config[:local_port]))
|
65
|
-
{
|
66
|
-
host: '127.0.0.1',
|
67
|
-
port: local_ssh_proxy_port
|
68
|
-
}
|
69
|
-
end
|
70
|
-
|
71
|
-
def config
|
72
|
-
@config ||= YAML.load(IO.read(File.expand_path(@options.config_file)), aliases: true).with_indifferent_access
|
74
|
+
def config_from_file
|
75
|
+
@config_from_file ||= YAML.safe_load(IO.read(File.expand_path(@options.config_file)), aliases: true).with_indifferent_access
|
73
76
|
rescue ArgumentError
|
74
|
-
@
|
77
|
+
@config_from_file ||= YAML.safe_load(IO.read(File.expand_path(@options.config_file))).with_indifferent_access
|
75
78
|
end
|
76
79
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
+
# Returns the configuration for config file.
|
81
|
+
# or default configuration (built from CLI options) if no environment specified
|
82
|
+
def environ_config_from_file
|
83
|
+
if @options.enviroments.present? || @options.environments&.any? { |env_names| !config_from_file.key?(env_names) }
|
84
|
+
warn "Specified ENV `#{@options.env}' not exists in config file"
|
85
|
+
exit(1)
|
80
86
|
end
|
81
|
-
|
82
|
-
|
87
|
+
conf = if @options.environments.present?
|
88
|
+
@config_from_file.slice(*@options.environments)
|
83
89
|
else
|
84
|
-
{}
|
90
|
+
{ default: @options.to_h }.with_indifferent_access
|
85
91
|
end
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
@@effective_config ||= nil
|
90
|
-
unless @@effective_config
|
91
|
-
@@effective_config = selected_config.deep_merge(@options.to_h)
|
92
|
-
if @@effective_config[:adapter].blank?
|
93
|
-
@@effective_config[:adapter] = 'sqlite3'
|
92
|
+
conf.each do |env_name, env_conf|
|
93
|
+
unless env_conf.key?(:namespace)
|
94
|
+
env_conf[:namespace] = env_name.to_s.gsub(/[^a-zA-Z0-9]/, '_').camelize
|
94
95
|
end
|
95
|
-
@@effective_config[:database] = File.expand_path(@@effective_config[:database]) if @@effective_config[:adapter] == 'sqlite3'
|
96
96
|
end
|
97
|
-
|
97
|
+
end
|
98
|
+
|
99
|
+
# Returns the effective configuration for the application.
|
100
|
+
# structure like:
|
101
|
+
# {
|
102
|
+
# options: {show_sql: true,
|
103
|
+
# write_sql: 'output.sql',
|
104
|
+
# },
|
105
|
+
# environments: {
|
106
|
+
# development: {adapter: 'mysql2',
|
107
|
+
# host: 'localhost',
|
108
|
+
# port: 3306},
|
109
|
+
# test: {adapter: 'mysql2',
|
110
|
+
# host: 'localhost',
|
111
|
+
# port: 3306},
|
112
|
+
# }
|
113
|
+
# }
|
114
|
+
def config
|
115
|
+
@config ||= {
|
116
|
+
options: @options,
|
117
|
+
environments: environ_config_from_file.each_with_object({}) { |(env_name, env_conf), h|
|
118
|
+
conf = env_conf.deep_merge(@options.to_h)
|
119
|
+
conf[:adapter] = 'sqlite3' if conf[:adapter].blank?
|
120
|
+
conf[:database] = File.expand_path(conf[:database]) if conf[:adapter] == 'sqlite3'
|
121
|
+
h[env_name] = conf
|
122
|
+
h
|
123
|
+
}.with_indifferent_access
|
124
|
+
}
|
98
125
|
end
|
99
126
|
|
100
127
|
def run!
|
101
128
|
show_sql if should_show_sql?
|
102
129
|
write_sql if should_write_sql?
|
103
130
|
append_sql if should_append_sql?
|
104
|
-
if
|
105
|
-
eval(
|
106
|
-
elsif
|
107
|
-
|
108
|
-
elsif
|
131
|
+
if @options.code&.present?
|
132
|
+
eval(@options.code)
|
133
|
+
elsif @options.args.present?
|
134
|
+
@options.args.first.tap { |file| load(file) }
|
135
|
+
elsif $stdin.isatty
|
109
136
|
run_repl!
|
110
137
|
else
|
111
|
-
eval(
|
138
|
+
eval($stdin.read)
|
112
139
|
end
|
113
140
|
end
|
114
141
|
|
@@ -117,32 +144,32 @@ module Arql
|
|
117
144
|
end
|
118
145
|
|
119
146
|
def should_show_sql?
|
120
|
-
|
147
|
+
@options.show_sql
|
121
148
|
end
|
122
149
|
|
123
150
|
def should_write_sql?
|
124
|
-
|
151
|
+
@options.write_sql
|
125
152
|
end
|
126
153
|
|
127
154
|
def should_append_sql?
|
128
|
-
|
155
|
+
@options.append_sql
|
129
156
|
end
|
130
157
|
|
131
158
|
def show_sql
|
132
159
|
App.log_io ||= MultiIO.new
|
133
160
|
ActiveRecord::Base.logger = Logger.new(App.log_io)
|
134
|
-
App.log_io <<
|
161
|
+
App.log_io << $stdout
|
135
162
|
end
|
136
163
|
|
137
164
|
def write_sql
|
138
|
-
write_sql_file =
|
165
|
+
write_sql_file = @options.write_sql
|
139
166
|
App.log_io ||= MultiIO.new
|
140
167
|
ActiveRecord::Base.logger = Logger.new(App.log_io)
|
141
168
|
App.log_io << File.new(write_sql_file, 'w')
|
142
169
|
end
|
143
170
|
|
144
171
|
def append_sql
|
145
|
-
write_sql_file =
|
172
|
+
write_sql_file = @options.append_sql
|
146
173
|
App.log_io ||= MultiIO.new
|
147
174
|
ActiveRecord::Base.logger = Logger.new(App.log_io)
|
148
175
|
App.log_io << File.new(write_sql_file, 'a')
|
data/lib/arql/cli.rb
CHANGED
@@ -12,6 +12,7 @@ module Arql
|
|
12
12
|
def parse_options!
|
13
13
|
@options = OpenStruct.new(config_file: default_config_file,
|
14
14
|
initializer: default_initializer,
|
15
|
+
babel_compatable: false,
|
15
16
|
ssh: {})
|
16
17
|
|
17
18
|
|
@@ -19,7 +20,7 @@ module Arql
|
|
19
20
|
opts.banner = <<~EOF
|
20
21
|
Usage: arql [options] [ruby file]
|
21
22
|
|
22
|
-
If neither [ruby file] nor -e option specified, and STDIN is
|
23
|
+
If neither [ruby file] nor -e option specified, and STDIN is a tty, a Pry REPL will be launched,
|
23
24
|
otherwise the specified ruby file or -e option value or ruby code read from STDIN will be run, and no REPL launched
|
24
25
|
|
25
26
|
EOF
|
@@ -32,8 +33,12 @@ module Arql
|
|
32
33
|
@options.initializer = initializer
|
33
34
|
end
|
34
35
|
|
35
|
-
opts.on('-eENVIRON', '--env=ENVIRON', 'Specify config environment
|
36
|
-
@options.
|
36
|
+
opts.on('-eENVIRON', '--env=ENVIRON', 'Specify config environment, multiple environments allowed, separated by comma') do |env_names|
|
37
|
+
@options.environments = env_names.split(/[,\+:]/)
|
38
|
+
if @options.environments.any? { |e| e =~ /^default|arql$/i }
|
39
|
+
warn '[default, arql] are reserved environment names, please use another name'
|
40
|
+
exit(1)
|
41
|
+
end
|
37
42
|
end
|
38
43
|
|
39
44
|
opts.on('-aDB_ADAPTER', '--db-adapter=DB_ADAPTER', 'Specify database Adapter, default is sqlite3') do |db_adapter|
|
@@ -92,6 +97,11 @@ module Arql
|
|
92
97
|
@options.code = code
|
93
98
|
end
|
94
99
|
|
100
|
+
opts.on('-b', '--babel', 'Enable compatibility for Org-Mode Babel') do
|
101
|
+
@options.babel_compatable = true
|
102
|
+
end
|
103
|
+
|
104
|
+
|
95
105
|
opts.on('-S', '--show-sql', 'Show SQL on STDOUT') do
|
96
106
|
@options.show_sql = true
|
97
107
|
end
|
@@ -117,24 +127,36 @@ module Arql
|
|
117
127
|
end.parse!
|
118
128
|
|
119
129
|
@options.args = ARGV
|
130
|
+
|
131
|
+
if @options.environments&.size&.positive? && any_database_options?
|
132
|
+
$stderr.puts "Following options are not allowed when using multiple environments specified: #{database_options.join(', ')}"
|
133
|
+
$stderr.puts " #{database_options.join(', ')}"
|
134
|
+
exit(1)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def any_database_options?
|
139
|
+
%i[adapter host port database username
|
140
|
+
password encoding pool ssh].reduce(false) do |acc, opt|
|
141
|
+
acc || @options.send(opt).present?
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def database_options
|
146
|
+
['--db-adapter', '--db-host', '--db-port', '--db-name', '--db-user', '--db-password',
|
147
|
+
'--db-encoding', '--db-pool', '--ssh-host', '--ssh-port', '--ssh-user', '--ssh-password', '--ssh-local-port']
|
120
148
|
end
|
121
149
|
|
122
150
|
def default_config_file
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
return conf if File.file?(conf)
|
127
|
-
conf = File.expand_path('~/.arql.d/init.yml')
|
128
|
-
return conf if File.file?(conf)
|
129
|
-
conf = File.expand_path('~/.arql.d/init.yaml')
|
130
|
-
return conf if File.file?(conf)
|
151
|
+
['~/.arql.yml', '~/.arql.yaml', '~/.arql.d/init.yml', '~/.arql.d/init.yaml'].find { |f|
|
152
|
+
File.file?(File.expand_path(f))
|
153
|
+
}.try { |f| File.expand_path(f) }
|
131
154
|
end
|
132
155
|
|
133
156
|
def default_initializer
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
return conf if File.file?(conf)
|
157
|
+
['~/.arql.rb', '~/.arql.d/init.rb',].find { |f|
|
158
|
+
File.file?(File.expand_path(f))
|
159
|
+
}.try { |f| File.expand_path(f) }
|
138
160
|
end
|
139
161
|
end
|
140
162
|
end
|
data/lib/arql/commands/info.rb
CHANGED
@@ -3,38 +3,49 @@ require 'rainbow'
|
|
3
3
|
module Arql::Commands
|
4
4
|
module Info
|
5
5
|
class << self
|
6
|
-
def db_info
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
6
|
+
def db_info(env_name_regexp)
|
7
|
+
|
8
|
+
Arql::App.instance.definitions.map do |env_name, definition|
|
9
|
+
next unless env_name =~ env_name_regexp
|
10
|
+
config = Arql::App.config[:environments][env_name]
|
11
|
+
<<~DB_INFO
|
12
|
+
|
13
|
+
#{env_name} Database Connection Information:
|
14
|
+
|
15
|
+
Active: #{color_boolean(definition.connection.active?)}
|
16
|
+
Host: #{config[:host]}
|
17
|
+
Port: #{config[:port]}
|
18
|
+
Username: #{config[:username]}
|
19
|
+
Password: #{(config[:password] || '').gsub(/./, '*')}
|
20
|
+
Database: #{config[:database]}
|
21
|
+
Adapter: #{config[:adapter]}
|
22
|
+
Encoding: #{config[:encoding]}
|
23
|
+
Pool Size: #{config[:pool]}
|
24
|
+
DB_INFO
|
25
|
+
end
|
21
26
|
end
|
22
27
|
|
23
|
-
def ssh_info
|
24
|
-
|
28
|
+
def ssh_info(env_name_regexp)
|
29
|
+
Arql::App.instance.definitions.map do |env_name, definition|
|
30
|
+
next unless env_name =~ env_name_regexp
|
31
|
+
config = Arql::App.config[:environments][env_name]
|
32
|
+
next unless config[:ssh].present?
|
33
|
+
<<~SSH_INFO
|
25
34
|
|
26
|
-
|
35
|
+
#{env_name} SSH Connection Information:
|
27
36
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
37
|
+
Active: #{color_boolean(definition.ssh_proxy.active?)}
|
38
|
+
Host: #{config[:ssh][:host]}
|
39
|
+
Port: #{config[:ssh][:port]}
|
40
|
+
Username: #{config[:ssh][:user]}
|
41
|
+
Password: #{(config[:ssh][:password] || '').gsub(/./, '*')}
|
42
|
+
Local Port: #{definition.ssh_proxy.local_ssh_proxy_port}
|
43
|
+
SSH_INFO
|
44
|
+
end
|
35
45
|
end
|
36
46
|
|
37
47
|
private
|
48
|
+
|
38
49
|
def color_boolean(bool)
|
39
50
|
if bool
|
40
51
|
Rainbow('TRUE').green
|
@@ -44,9 +55,11 @@ module Arql::Commands
|
|
44
55
|
end
|
45
56
|
end
|
46
57
|
|
47
|
-
Pry.commands.block_command 'info' do
|
48
|
-
|
49
|
-
|
58
|
+
Pry.commands.block_command 'info' do |env_name_regexp|
|
59
|
+
env_name_regexp ||= '.*'
|
60
|
+
env_name_regexp = Regexp.new(env_name_regexp, Regexp::IGNORECASE)
|
61
|
+
output.puts Info::db_info(env_name_regexp)
|
62
|
+
output.puts Info::ssh_info(env_name_regexp)
|
50
63
|
end
|
51
64
|
end
|
52
65
|
end
|
data/lib/arql/commands/models.rb
CHANGED
@@ -3,84 +3,129 @@ require 'terminal-table'
|
|
3
3
|
module Arql::Commands
|
4
4
|
module Models
|
5
5
|
class << self
|
6
|
-
def
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
if column_regexp.nil?
|
18
|
-
Terminal::Table.new do |t|
|
19
|
-
models.each_with_index { |row, idx| t << (row || :separator) if row.nil? ||
|
20
|
-
table_regexp.nil? ||
|
21
|
-
idx.zero? ||
|
22
|
-
row.any? { |e| e =~ table_regexp }
|
23
|
-
}
|
6
|
+
def filter_tables(env_name, definition, format, table_regexp=nil)
|
7
|
+
result = ''
|
8
|
+
result << '-- ' if format == 'sql'
|
9
|
+
result << "Environment: #{env_name}\n"
|
10
|
+
result << "------------------------------\n\n"
|
11
|
+
if format == 'sql'
|
12
|
+
definition.models.each do |model|
|
13
|
+
if table_regexp? || ( model[:table] =~ table_regexp || model[:comment] =~ table_regexp )
|
14
|
+
result << "-- Table: #{table_name}\n\n"
|
15
|
+
result << definition.connection.exec_query("show create table `#{table_name}`").rows.last.last + ';'
|
16
|
+
end
|
24
17
|
end
|
25
18
|
else
|
26
|
-
|
27
|
-
|
28
|
-
t << ['
|
19
|
+
Terminal::Table.new do |t|
|
20
|
+
t.style = table_style_for_format(format)
|
21
|
+
t << ['Table Name', 'Model Class', 'Abbr', 'Comment']
|
29
22
|
t << :separator
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
next if matched_columns.empty?
|
34
|
-
matched_columns.each do |column|
|
35
|
-
pk = if [connection.primary_key(definition[:table])].flatten.include?(column.name)
|
36
|
-
'Y'
|
37
|
-
else
|
38
|
-
''
|
39
|
-
end
|
40
|
-
t << [pk, definition[:table], model_class.name, column.name, column.sql_type,
|
41
|
-
column.sql_type_metadata.type, column.sql_type_metadata.limit || '',
|
42
|
-
column.sql_type_metadata.precision || '', column.sql_type_metadata.scale || '', column.default || '',
|
43
|
-
column.null, "#{definition[:comment]} - #{column.comment}"]
|
23
|
+
definition.models.each do |model|
|
24
|
+
if table_regexp.nil? || ( model[:table] =~ table_regexp || model[:comment] =~ table_regexp )
|
25
|
+
t << [model[:table], model[:model].name, model[:abbr] || '', model[:comment] || '']
|
44
26
|
end
|
45
27
|
end
|
28
|
+
end.try { |e|
|
29
|
+
case format
|
30
|
+
when 'md'
|
31
|
+
result << e.to_s.lines.map { |l| ' ' + l }.join
|
32
|
+
when 'org'
|
33
|
+
result << e.to_s.lines.map { |l| ' ' + l.gsub(/^\+|\+$/, '|') }.join
|
34
|
+
else
|
35
|
+
result << e.to_s
|
36
|
+
end
|
37
|
+
}
|
38
|
+
end
|
39
|
+
result
|
40
|
+
end
|
41
|
+
|
42
|
+
def filter_columns(env_name, definition, format, column_regexp=nil)
|
43
|
+
result = ''
|
44
|
+
result << '-- ' if format == 'sql'
|
45
|
+
result << "Environment: #{env_name}\n"
|
46
|
+
result << "------------------------------\n\n"
|
47
|
+
Terminal::Table.new do |t|
|
48
|
+
t.style = table_style_for_format(format)
|
49
|
+
t << ['Table', 'Model', 'Name', 'SQL Type', 'Ruby Type', 'Limit', 'Precision', 'Scale', 'Default', 'Nullable', 'Comment']
|
50
|
+
t << :separator
|
51
|
+
definition.models.each do |model_def|
|
52
|
+
model_class = model_def[:model]
|
53
|
+
matched_columns = model_class.columns.select { |column| column.name =~ column_regexp || column.comment =~ column_regexp }
|
54
|
+
next if matched_columns.empty?
|
55
|
+
matched_columns.each do |column|
|
56
|
+
t << [model_def[:table], model_class.name, column.name, column.sql_type,
|
57
|
+
column.sql_type_metadata.type, column.sql_type_metadata.limit || '',
|
58
|
+
column.sql_type_metadata.precision || '', column.sql_type_metadata.scale || '', column.default || '',
|
59
|
+
column.null, "#{model_def[:comment]} - #{column.comment}"]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end.try { |e|
|
63
|
+
case format
|
64
|
+
when 'md'
|
65
|
+
result << e.to_s.lines.map { |l| ' ' + l }.join
|
66
|
+
when 'org'
|
67
|
+
result << e.to_s.lines.map { |l| ' ' + l.gsub(/^\+|\+$/, '|') }.join
|
68
|
+
else
|
69
|
+
result << e.to_s
|
46
70
|
end
|
47
|
-
|
71
|
+
}
|
72
|
+
result
|
73
|
+
end
|
74
|
+
|
75
|
+
def table_style_for_format(format)
|
76
|
+
case format
|
77
|
+
when 'md'
|
78
|
+
{
|
79
|
+
border_top: false,
|
80
|
+
border_bottom: false,
|
81
|
+
border_i: '|'
|
82
|
+
}
|
83
|
+
when 'org'
|
84
|
+
{
|
85
|
+
border_top: false,
|
86
|
+
border_bottom: false,
|
87
|
+
}
|
88
|
+
else
|
89
|
+
{}
|
48
90
|
end
|
49
91
|
end
|
50
92
|
end
|
51
93
|
end
|
52
94
|
|
53
|
-
Pry.commands.
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
95
|
+
Pry.commands.create_command 'm' do
|
96
|
+
description 'List models or columns (specified by `-c`): m [-e env_name_regexp] -c [column_regexp] [table_regexp]'
|
97
|
+
|
98
|
+
def options(opt)
|
99
|
+
opt.on '-e', '--env', 'Environment name regexp', argument: true, as: String, required: false, default: nil
|
100
|
+
opt.on '-f', '--format', 'Table format, available: terminal(default), md, org, sql', argument: true, as: String, required: false, default: 'terminal'
|
101
|
+
opt.on '-c', '--column', 'Column name regexp', argument: true, as: String, required: false, default: nil
|
60
102
|
end
|
61
|
-
end
|
62
103
|
|
63
|
-
|
64
|
-
end
|
104
|
+
def process
|
65
105
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
106
|
+
if opts[:format] == 'sql' && opts[:column]
|
107
|
+
output.puts 'SQL format is not supported for column listing'
|
108
|
+
return
|
109
|
+
end
|
70
110
|
|
71
|
-
|
72
|
-
|
73
|
-
end
|
111
|
+
env_names = opts[:env].try {|e| [e]}.presence || Arql::App.environments
|
112
|
+
env_names = env_names.map { |e| e.start_with?('/') ? eval(e) : Regexp.new(e) }
|
74
113
|
|
75
|
-
|
76
|
-
|
77
|
-
end
|
114
|
+
Arql::App.instance.definitions.each do |env_name, definition|
|
115
|
+
next unless env_names.any? { |e| env_name =~ e }
|
78
116
|
|
79
|
-
|
80
|
-
|
81
|
-
|
117
|
+
output.puts
|
118
|
+
if opts[:column]
|
119
|
+
column_regexp = opts[:column]
|
120
|
+
output.puts Models::filter_columns(env_name, definition, opts[:format], column_regexp.try { |e| e.start_with?('/') ? eval(e) : Regexp.new(e) })
|
121
|
+
else
|
122
|
+
table_regexp = args&.first
|
123
|
+
output.puts Models::filter_tables(env_name, definition, opts[:format], table_regexp.try { |e| e.start_with?('/') ? eval(e) : Regexp.new(e) })
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
82
127
|
|
83
|
-
def model_names
|
84
|
-
models[2..-1].map(&:second)
|
85
128
|
end
|
129
|
+
|
130
|
+
Pry.commands.alias_command 'l', 'm'
|
86
131
|
end
|
@@ -2,13 +2,17 @@ module Arql::Commands
|
|
2
2
|
module Reconnect
|
3
3
|
class << self
|
4
4
|
def reconnect
|
5
|
-
Arql::
|
6
|
-
|
5
|
+
Arql::App.instance.definitions.each do |_, definition|
|
6
|
+
definition.ssh_proxy.reconnect if definition.options[:ssh].present?
|
7
|
+
definition.connection.reconnect! unless definition.connection.active?
|
8
|
+
end
|
7
9
|
end
|
8
10
|
|
9
11
|
def reconnect!
|
10
|
-
Arql::
|
11
|
-
|
12
|
+
Arql::App.instance.definitions.each do |_, definition|
|
13
|
+
definition.ssh_proxy.reconnect if definition.options[:ssh].present?
|
14
|
+
definition.connection.reconnect!
|
15
|
+
end
|
12
16
|
end
|
13
17
|
end
|
14
18
|
|