arql 0.1.30

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.
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+ task :default => :spec
@@ -0,0 +1,40 @@
1
+ require_relative 'lib/arql/version'
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "arql"
5
+ spec.version = Arql::VERSION
6
+ spec.authors = ["Liu Xiang"]
7
+ spec.email = ["liuxiang921@gmail.com"]
8
+
9
+ spec.summary = %{Rails ActiveRecord + Pry is the best SQL query editor}
10
+ spec.description = %{Use ActiveRecord and Pry as your favorite SQL query editor.}
11
+ spec.homepage = "https://github.com/lululau/arql"
12
+ spec.license = "MIT"
13
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
14
+
15
+
16
+
17
+ # Specify which files should be added to the gem when it is released.
18
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
19
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
20
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
21
+ end
22
+ spec.bindir = "exe"
23
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
+ spec.require_paths = ["lib"]
25
+
26
+ spec.add_dependency 'mysql2', '~> 0.5.3'
27
+ # spec.add_dependency 'pg', '>= 0.18', '< 2.0'
28
+ spec.add_dependency 'sqlite3', '~> 1.4'
29
+ # spec.add_dependency 'activerecord-sqlserver-adapter'
30
+ # spec.add_dependency 'activerecord-oracle_enhanced-adapter'
31
+ spec.add_dependency 'activerecord', '~> 6.0.3'
32
+ spec.add_dependency 'activesupport', '~> 6.0.3'
33
+ spec.add_dependency 'net-ssh-gateway', '~> 2.0.0'
34
+ spec.add_dependency 'pry', '~> 0.13.1'
35
+ spec.add_dependency 'pry-byebug', '~> 3.9.0'
36
+ spec.add_dependency 'pry-doc', '~> 1.1.0'
37
+ spec.add_dependency 'rainbow', '~> 3.0.0'
38
+ spec.add_dependency 'terminal-table', '~> 1.8.0'
39
+ spec.add_dependency 'table_print', '~> 1.5.6'
40
+ end
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "arql"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ ArqlSetsidWrrapper = File.dirname(File.absolute_path(__FILE__)) + '/arql_setsid_wrapper'
4
+
5
+ require "arql"
6
+
7
+ Arql::Cli.start
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ Process.setsid
4
+
5
+ exec(*ARGV)
@@ -0,0 +1,12 @@
1
+ require 'table_print'
2
+ require "arql/version"
3
+ require 'arql/id'
4
+ require 'arql/multi_io'
5
+ require 'arql/ext'
6
+ require "arql/repl"
7
+ require "arql/ssh_proxy"
8
+ require "arql/app"
9
+ require "arql/cli"
10
+
11
+ module Arql
12
+ end
@@ -0,0 +1,137 @@
1
+ require 'net/ssh/gateway'
2
+
3
+ module Arql
4
+ class App
5
+
6
+ class << self
7
+ attr_accessor :log_io, :env
8
+
9
+ def config
10
+ @@effective_config
11
+ end
12
+ end
13
+
14
+ def initialize(options)
15
+ require 'active_support/all'
16
+ require 'active_record'
17
+ require "arql/connection"
18
+ require "arql/definition"
19
+ @options = options
20
+ App.env = @options.env
21
+ Connection.open(connect_options)
22
+ @definition = Definition.new(effective_config)
23
+ load_initializer!
24
+ end
25
+
26
+ def connect_options
27
+ connect_conf = effective_config.slice(:adapter, :host, :username,
28
+ :password, :database, :encoding,
29
+ :pool, :port, :socket)
30
+ if effective_config[:ssh].present?
31
+ connect_conf.merge!(start_ssh_proxy!)
32
+ end
33
+
34
+ connect_conf
35
+ end
36
+
37
+ def load_initializer!
38
+ return unless effective_config[:initializer]
39
+ initializer_file = File.expand_path(effective_config[:initializer])
40
+ unless File.exists?(initializer_file)
41
+ STDERR.puts "Specified initializer file not found, #{effective_config[:initializer]}"
42
+ exit(1)
43
+ end
44
+ load(initializer_file)
45
+ end
46
+
47
+ def start_ssh_proxy!
48
+ ssh_config = effective_config[:ssh]
49
+ local_ssh_proxy_port = Arql::SSHProxy.connect(ssh_config.slice(:host, :user, :port, :password).merge(
50
+ forward_host: effective_config[:host],
51
+ forward_port: effective_config[:port],
52
+ local_port: ssh_config[:local_port]))
53
+ {
54
+ host: '127.0.0.1',
55
+ port: local_ssh_proxy_port
56
+ }
57
+ end
58
+
59
+ def config
60
+ @config ||= YAML.load(IO.read(File.expand_path(@options.config_file))).with_indifferent_access
61
+ end
62
+
63
+ def selected_config
64
+ if @options.env.present? && !config[@options.env].present?
65
+ STDERR.puts "Specified ENV `#{@options.env}' not exists"
66
+ end
67
+ if env = @options.env
68
+ config[env]
69
+ else
70
+ {}
71
+ end
72
+ end
73
+
74
+ def effective_config
75
+ @@effective_config ||= nil
76
+ unless @@effective_config
77
+ @@effective_config = selected_config.deep_merge(@options.to_h)
78
+ if @@effective_config[:adapter].blank?
79
+ @@effective_config[:adapter] = 'sqlite3'
80
+ end
81
+ @@effective_config[:database] = File.expand_path(@@effective_config[:database]) if @@effective_config[:adapter] == 'sqlite3'
82
+ end
83
+ @@effective_config
84
+ end
85
+
86
+ def run!
87
+ show_sql if should_show_sql?
88
+ write_sql if should_write_sql?
89
+ append_sql if should_append_sql?
90
+ if effective_config[:code].present?
91
+ eval(effective_config[:code])
92
+ elsif effective_config[:args].present?
93
+ effective_config[:args].each { |rb| load(rb) }
94
+ elsif STDIN.isatty
95
+ run_repl!
96
+ else
97
+ eval(STDIN.read)
98
+ end
99
+ end
100
+
101
+ def run_repl!
102
+ Repl.new
103
+ end
104
+
105
+ def should_show_sql?
106
+ effective_config[:show_sql]
107
+ end
108
+
109
+ def should_write_sql?
110
+ effective_config[:write_sql]
111
+ end
112
+
113
+ def should_append_sql?
114
+ effective_config[:append_sql]
115
+ end
116
+
117
+ def show_sql
118
+ App.log_io ||= MultiIO.new
119
+ ActiveRecord::Base.logger = Logger.new(App.log_io)
120
+ App.log_io << STDOUT
121
+ end
122
+
123
+ def write_sql
124
+ write_sql_file = effective_config[:write_sql]
125
+ App.log_io ||= MultiIO.new
126
+ ActiveRecord::Base.logger = Logger.new(App.log_io)
127
+ App.log_io << File.new(write_sql_file, 'w')
128
+ end
129
+
130
+ def append_sql
131
+ write_sql_file = effective_config[:append_sql]
132
+ App.log_io ||= MultiIO.new
133
+ ActiveRecord::Base.logger = Logger.new(App.log_io)
134
+ App.log_io << File.new(write_sql_file, 'a')
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,141 @@
1
+ require 'optparse'
2
+ require 'ostruct'
3
+
4
+ module Arql
5
+ class Cli
6
+ class << self
7
+ def start
8
+ parse_options!
9
+ App.new(@options).run!
10
+ end
11
+
12
+ def parse_options!
13
+ @options = OpenStruct.new(config_file: default_config_file,
14
+ initializer: default_initializer,
15
+ ssh: {})
16
+
17
+
18
+ OptionParser.new do |opts|
19
+ opts.banner = <<~EOF
20
+ Usage: arql [options] [ruby file]
21
+
22
+ If neither [ruby file] nor -e option specified, and STDIN is not a tty, a Pry REPL will be launched,
23
+ otherwise the specified ruby file or -e option value or ruby code read from STDIN will be run, and no REPL launched
24
+
25
+ EOF
26
+
27
+ opts.on('-cCONFIG_FILE', '--conf=CONFIG_FILE', 'Specify config file, default is $HOME/.arql.yml, or $HOME/.arql.d/init.yml.') do |config_file|
28
+ @options.config_file = config_file
29
+ end
30
+
31
+ opts.on('-iINITIALIZER', '--initializer=INITIALIZER', 'Specify initializer ruby file, default is $HOME/.arql.rb, or $HOME/.arql.d/init.rb.') do |initializer|
32
+ @options.initializer = initializer
33
+ end
34
+
35
+ opts.on('-eENVIRON', '--env=ENVIRON', 'Specify config environment.') do |env|
36
+ @options.env = env
37
+ end
38
+
39
+ opts.on('-aDB_ADAPTER', '--db-adapter=DB_ADAPTER', 'Specify database Adapter, default is mysql2') do |db_adapter|
40
+ @options.dapter = db_adapter
41
+ end
42
+
43
+ opts.on('-hDB_HOST', '--db-host=DB_HOST', 'Specify database host') do |db_host|
44
+ @options.host = db_host
45
+ end
46
+
47
+ opts.on('-pDB_PORT', '--db-port=DB_PORT', 'Specify database port') do |db_port|
48
+ @options.port = db_port.to_i
49
+ end
50
+
51
+ opts.on('-dDB_NAME', '--db-name=DB_NAME', 'Specify database name') do |db_name|
52
+ @options.database = db_name
53
+ end
54
+
55
+ opts.on('-uDB_USER', '--db-user=DB_USER', 'Specify database user') do |db_user|
56
+ @options.username = db_user
57
+ end
58
+
59
+ opts.on('-PDB_PASSWORD', '--db-password=DB_PASSWORD', 'Specify database password') do |db_password|
60
+ @options.password = db_password
61
+ end
62
+
63
+ opts.on('-n', '--db-encoding=DB_ENCODING', 'Specify database encoding, default is utf8') do |db_encoding|
64
+ @options.encoding = db_encoding
65
+ end
66
+
67
+ opts.on('-o', '--db-pool=DB_POOL', 'Specify database pool size, default is 5') do |db_pool|
68
+ @options.pool = db_pool
69
+ end
70
+
71
+ opts.on('-HSSH_HOST', '--ssh-host=SSH_HOST', 'Specify SSH host') do |ssh_host|
72
+ @options.ssh[:host] = ssh_host
73
+ end
74
+
75
+ opts.on('-OSSH_PORT', '--ssh-port=SSH_PORT', 'Specify SSH port') do |ssh_port|
76
+ @options.ssh[:port] = ssh_port.to_i
77
+ end
78
+
79
+ opts.on('-USSH_USER', '--ssh-user=SSH_USER', 'Specify SSH user') do |ssh_user|
80
+ @options.ssh[:user] = ssh_user
81
+ end
82
+
83
+ opts.on('-WSSH_PASSWORD', '--ssh-password=SSH_PASSWORD', 'Specify SSH password') do |ssh_password|
84
+ @options.ssh[:password] = ssh_password
85
+ end
86
+
87
+ opts.on('-LSSH_LOCAL_PORT', '--ssh-local-port=SSH_LOCAL_PORT', 'Specify local SSH proxy port') do |local_port|
88
+ @options.ssh[:local_port] = local_port.to_i
89
+ end
90
+
91
+ opts.on('-ECODE', '--eval=CODE', 'evaluate CODE') do |code|
92
+ @options.code = code
93
+ end
94
+
95
+ opts.on('-S', '--show-sql', 'Show SQL on STDOUT') do
96
+ @options.show_sql = true
97
+ end
98
+
99
+ opts.on('-wOUTOUT', '--write-sql=OUTPUT', 'Write SQL to OUTPUT file') do |file|
100
+ @options.write_sql = file
101
+ end
102
+
103
+ opts.on('-AOUTPUT', '--append-sql=OUTPUT', 'Append SQL to OUTPUT file') do |file|
104
+ @options.append_sql = file
105
+ end
106
+
107
+ opts.on('-V', '--version', 'Prints version') do
108
+ puts "ARQL #{Arql::VERSION}"
109
+ exit
110
+ end
111
+
112
+ opts.on('', '--help', 'Prints this help') do
113
+ puts opts
114
+ exit
115
+ end
116
+
117
+ end.parse!
118
+
119
+ @options.args = ARGV
120
+ end
121
+
122
+ 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)
131
+ end
132
+
133
+ 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)
138
+ end
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,9 @@
1
+ require 'arql/commands/info'
2
+ require 'arql/commands/models'
3
+ require 'arql/commands/table'
4
+ require 'arql/commands/reconnect'
5
+ require 'arql/commands/redefine'
6
+ require 'arql/commands/show_sql'
7
+
8
+ module Arql::Commands
9
+ end
@@ -0,0 +1,52 @@
1
+ require 'rainbow'
2
+
3
+ module Arql::Commands
4
+ module Info
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
21
+ end
22
+
23
+ def ssh_info
24
+ <<~EOF
25
+
26
+ SSH Connection Information:
27
+
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
35
+ end
36
+
37
+ private
38
+ def color_boolean(bool)
39
+ if bool
40
+ Rainbow('TRUE').green
41
+ else
42
+ Rainbow('FALSE').red
43
+ end
44
+ end
45
+ end
46
+
47
+ Pry.commands.block_command 'info' do
48
+ puts Info::db_info
49
+ puts Info::ssh_info if Arql::App.config[:ssh].present?
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,40 @@
1
+ require 'terminal-table'
2
+
3
+ module Arql::Commands
4
+ module Models
5
+ class << self
6
+ def models
7
+ t = []
8
+ t << ['Table Name', 'Model Class', 'Abbr']
9
+ t << nil
10
+ Arql::Definition.models.each do |definition|
11
+ t << [definition[:table], definition[:model].name, definition[:abbr] || '']
12
+ end
13
+ t
14
+ end
15
+
16
+ def models_table
17
+ Terminal::Table.new do |t|
18
+ models.each { |row| t << (row || :separator) }
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ Pry.commands.block_command 'm' do
25
+ puts
26
+ puts Models::models_table
27
+ end
28
+
29
+ Pry.commands.alias_command 'l', 'm'
30
+ end
31
+
32
+ module Kernel
33
+ def models
34
+ Arql::Commands::Models::models
35
+ end
36
+
37
+ def tables
38
+ models
39
+ end
40
+ end