arql 0.3.31 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/.vscode/launch.json +1 -1
  3. data/Gemfile.lock +1 -1
  4. data/README-zh_CN.org +616 -491
  5. data/README.org +803 -628
  6. data/auto-set-id-before-save-zh_CN.org +1 -1
  7. data/auto-set-id-before-save.org +1 -1
  8. data/custom-configurations-zh_CN.org +40 -3
  9. data/custom-configurations.org +71 -32
  10. data/define-associations-zh_CN.org +31 -17
  11. data/define-associations.org +52 -29
  12. data/initializer-structure-zh_CN.org +23 -5
  13. data/initializer-structure.org +46 -18
  14. data/lib/arql/app.rb +98 -71
  15. data/lib/arql/cli.rb +37 -15
  16. data/lib/arql/commands/info.rb +41 -28
  17. data/lib/arql/commands/models.rb +106 -61
  18. data/lib/arql/commands/reconnect.rb +8 -4
  19. data/lib/arql/commands/redefine.rb +3 -1
  20. data/lib/arql/commands/sandbox.rb +6 -4
  21. data/lib/arql/commands.rb +0 -2
  22. data/lib/arql/concerns/global_data_definition.rb +40 -6
  23. data/lib/arql/concerns/model_extension.rb +168 -0
  24. data/lib/arql/concerns/table_data_definition.rb +20 -20
  25. data/lib/arql/concerns.rb +1 -0
  26. data/lib/arql/definition.rb +169 -317
  27. data/lib/arql/ext/active_record/relation.rb +29 -0
  28. data/lib/arql/ext/active_record/result.rb +29 -0
  29. data/lib/arql/ext/array.rb +40 -1
  30. data/lib/arql/ext/kernel.rb +70 -61
  31. data/lib/arql/ext/object.rb +14 -0
  32. data/lib/arql/ext/ransack/search.rb +29 -0
  33. data/lib/arql/mysqldump.rb +0 -1
  34. data/lib/arql/repl.rb +1 -1
  35. data/lib/arql/ssh_proxy.rb +25 -22
  36. data/lib/arql/version.rb +1 -1
  37. data/lib/arql.rb +11 -7
  38. data/oss-files-zh_CN.org +2 -2
  39. data/oss-files.org +2 -2
  40. data/sql-log-zh_CN.org +8 -3
  41. data/sql-log.org +8 -3
  42. metadata +6 -5
  43. data/lib/arql/commands/table.rb +0 -55
  44. data/lib/arql/commands/vd.rb +0 -46
  45. 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 :log_io, :env, :prompt, :instance, :connect_options
6
+ attr_accessor :instance
6
7
 
7
- def config
8
- @@effective_config
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
- if env
13
- env
14
- else
15
- File.basename(@@effective_config[:database])
16
- end
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
- App.env = @options.env
25
- App.connect_options = connect_options
26
- Connection.open(App.connect_options)
45
+
46
+ # env names
47
+ @environments = @options.environments
48
+ @environments ||= ['default']
49
+
27
50
  print "Defining models..."
28
- @definition = Definition.new(effective_config)
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 effective_config[:initializer]
51
- initializer_file = File.expand_path(effective_config[:initializer])
64
+ return unless config[:options][:initializer]
65
+
66
+ initializer_file = File.expand_path(config[:options][:initializer])
52
67
  unless File.exist?(initializer_file)
53
- STDERR.puts "Specified initializer file not found, #{effective_config[:initializer]}"
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 start_ssh_proxy!
60
- ssh_config = effective_config[:ssh]
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
- @config ||= YAML.load(IO.read(File.expand_path(@options.config_file))).with_indifferent_access
77
+ @config_from_file ||= YAML.safe_load(IO.read(File.expand_path(@options.config_file))).with_indifferent_access
75
78
  end
76
79
 
77
- def selected_config
78
- if @options.env.present? && !config[@options.env].present?
79
- STDERR.puts "Specified ENV `#{@options.env}' not exists"
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
- if env = @options.env
82
- config[env]
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
- end
87
-
88
- def effective_config
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
- @@effective_config
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 effective_config[:code].present?
105
- eval(effective_config[:code])
106
- elsif effective_config[:args].present?
107
- effective_config[:args].first.tap { |file| load(file) }
108
- elsif STDIN.isatty
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(STDIN.read)
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
- effective_config[:show_sql]
147
+ @options.show_sql
121
148
  end
122
149
 
123
150
  def should_write_sql?
124
- effective_config[:write_sql]
151
+ @options.write_sql
125
152
  end
126
153
 
127
154
  def should_append_sql?
128
- effective_config[:append_sql]
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 << STDOUT
161
+ App.log_io << $stdout
135
162
  end
136
163
 
137
164
  def write_sql
138
- write_sql_file = effective_config[:write_sql]
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 = effective_config[:append_sql]
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 not a tty, a Pry REPL will be launched,
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.') do |env|
36
- @options.env = env
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
- conf = File.expand_path('~/.arql.yml')
124
- return conf if File.file?(conf)
125
- conf = File.expand_path('~/.arql.yaml')
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
- conf = File.expand_path('~/.arql.rb')
135
- return conf if File.file?(conf)
136
- conf = File.expand_path('~/.arql.d/init.rb')
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
@@ -3,38 +3,49 @@ require 'rainbow'
3
3
  module Arql::Commands
4
4
  module Info
5
5
  class << self
6
- def db_info
7
- <<~EOF
8
-
9
- Database Connection Information:
10
-
11
- Active: #{color_boolean(ActiveRecord::Base.connection.active?)}
12
- Host: #{Arql::App.config[:host]}
13
- Port: #{Arql::App.config[:port]}
14
- Username: #{Arql::App.config[:username]}
15
- Password: #{(Arql::App.config[:password] || '').gsub(/./, '*')}
16
- Database: #{Arql::App.config[:database]}
17
- Adapter: #{Arql::App.config[:adapter]}
18
- Encoding: #{Arql::App.config[:encoding]}
19
- Pool Size: #{Arql::App.config[:pool]}
20
- EOF
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
- <<~EOF
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
- SSH Connection Information:
35
+ #{env_name} SSH Connection Information:
27
36
 
28
- Active: #{color_boolean(Arql::SSHProxy.active?)}
29
- Host: #{Arql::App.config[:ssh][:host]}
30
- Port: #{Arql::App.config[:ssh][:port]}
31
- Username: #{Arql::App.config[:ssh][:user]}
32
- Password: #{(Arql::App.config[:ssh][:password] || '').gsub(/./, '*')}
33
- Local Port: #{Arql::SSHProxy.local_ssh_proxy_port}
34
- EOF
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
- puts Info::db_info
49
- puts Info::ssh_info if Arql::App.config[:ssh].present?
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
@@ -3,84 +3,129 @@ require 'terminal-table'
3
3
  module Arql::Commands
4
4
  module Models
5
5
  class << self
6
- def models
7
- t = []
8
- t << ['Table Name', 'Model Class', 'Abbr', 'Comment']
9
- t << nil
10
- Arql::Definition.models.each do |definition|
11
- t << [definition[:table], definition[:model].name, definition[:abbr] || '', definition[:comment] || '']
12
- end
13
- t
14
- end
15
-
16
- def models_table(table_regexp=nil, column_regexp=nil)
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
- connection = ::ActiveRecord::Base.connection
27
- table = Terminal::Table.new do |t|
28
- t << ['PK', 'Table', 'Model', 'Name', 'SQL Type', 'Ruby Type', 'Limit', 'Precision', 'Scale', 'Default', 'Nullable', 'Comment']
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
- Arql::Definition.models.each do |definition|
31
- model_class = definition[:model]
32
- matched_columns = model_class.columns.select { |column| column.name =~ column_regexp || column.comment =~ column_regexp }
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
- puts table
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.block_command 'm' do |arg|
54
- puts
55
- if arg.start_with?('c=') or arg.start_with?('column=')
56
- column_regexp = arg.sub(/^c(olumn)?=/, '')
57
- Models::models_table(nil, column_regexp.try { |e| e.start_with?('/') ? eval(e) : Regexp.new(e) })
58
- else
59
- puts Models::models_table(arg.try { |e| e.start_with?('/') ? eval(e) : Regexp.new(e) }, nil)
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
- Pry.commands.alias_command 'l', 'm'
64
- end
104
+ def process
65
105
 
66
- module Kernel
67
- def models
68
- Arql::Commands::Models::models
69
- end
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
- def tables
72
- models
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
- def model_classes
76
- ::ArqlModel.subclasses
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
- def table_names
80
- models[2..-1].map(&:first)
81
- end
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::SSHProxy.reconnect if Arql::App.config[:ssh].present?
6
- ActiveRecord::Base.connection.reconnect! unless ActiveRecord::Base.connection.active?
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::SSHProxy.reconnect! if Arql::App.config[:ssh].present?
11
- ActiveRecord::Base.connection.reconnect!
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
 
@@ -2,7 +2,9 @@ module Arql::Commands
2
2
  module Redefine
3
3
  class << self
4
4
  def redefine
5
- Arql::Definition.redefine
5
+ Arql::App.instance.definitions.each do |_, definition|
6
+ definition.redefine
7
+ end
6
8
  end
7
9
  end
8
10