arql 0.3.5 → 0.3.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 754f0123178d350470df65a3b627f3ae3890a3de7668d8422429d661e1d271cf
4
- data.tar.gz: 5d8241b6d7ba7fca92cd3a645138276fc2c3b0c8fb7658ba514f16794f63e26a
3
+ metadata.gz: 49ad54c58145e93df8e50ed2008831982b5b2274d78db75d22b074f54b807a5d
4
+ data.tar.gz: 9dae3245f6a5c16338cf894ecc08a44550e69b1fcef574a70b13d70016ee3a3a
5
5
  SHA512:
6
- metadata.gz: 85e3b47d182b593b9a34055141192073844d257d96fbd2319e83eb3b0444c3f747fcc460819a1f8d7b51110487f00afa27c61f8ef280d49724390123c8d759f1
7
- data.tar.gz: a5c8898c8384a7ed8685fe0ce758f797cbb530c627e116ad58610b854496d388063dfb0278a5c53586bd17a38740925d39ff9cc9942bda200436da597abaf644
6
+ metadata.gz: 486887bee40dc5fa2f5d4f857990a43026f98e73b2ede3d4a1ad9d0a7bf2c36ef46411ae102470c1545d259e11a3f4bc495998446432255be6e591bbeb89c2f6
7
+ data.tar.gz: be23a8df1e4a7f161a2363f467c107004e52203fe85a1c29af185d519d48bcd05a05f94017b5fe77f2dd9d981e68d441e3627da35eb84ddc869bcea790013d06
data/.gitignore CHANGED
@@ -6,3 +6,4 @@
6
6
  /pkg/
7
7
  /spec/reports/
8
8
  /tmp/
9
+ /.idea/
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- arql (0.3.5)
4
+ arql (0.3.8)
5
5
  activerecord (>= 6.0.3, < 6.2.0)
6
6
  activesupport (~> 6.0.3)
7
7
  caxlsx (~> 3.0.2)
@@ -53,7 +53,7 @@ GEM
53
53
  net-ssh (6.1.0)
54
54
  net-ssh-gateway (2.0.0)
55
55
  net-ssh (>= 4.0.0)
56
- nokogiri (1.13.0-x86_64-darwin)
56
+ nokogiri (1.13.6-x86_64-darwin)
57
57
  racc (~> 1.4)
58
58
  pry (0.13.1)
59
59
  coderay (~> 1.1)
@@ -82,7 +82,7 @@ GEM
82
82
  webrick (1.7.0)
83
83
  yard (0.9.27)
84
84
  webrick (~> 1.7.0)
85
- zeitwerk (2.5.3)
85
+ zeitwerk (2.5.4)
86
86
 
87
87
  PLATFORMS
88
88
  ruby
data/lib/arql/app.rb CHANGED
@@ -29,8 +29,14 @@ module Arql
29
29
  App.env = @options.env
30
30
  App.connect_options = connect_options
31
31
  Connection.open(App.connect_options)
32
+ print "Defining models..."
32
33
  @definition = Definition.new(effective_config)
34
+ print "\u001b[2K"
35
+ puts "\rModels defined"
36
+ print "Running initializers..."
33
37
  load_initializer!
38
+ print "\u001b[2K"
39
+ puts "\rInitializers loaded"
34
40
  App.instance = self
35
41
  end
36
42
 
@@ -0,0 +1,46 @@
1
+ require 'arql/vd'
2
+
3
+ module Arql::Commands
4
+ module VD
5
+ class << self
6
+ def get_table_name(name)
7
+ name = name.to_s
8
+ return name if name =~ /^[a-z]/
9
+ if Object.const_defined?(name)
10
+ klass = Object.const_get(name)
11
+ return klass.table_name if klass < ActiveRecord::Base
12
+ end
13
+ name
14
+ end
15
+
16
+ def table_info_vd(table_name)
17
+ Arql::VD.new do |vd|
18
+ table_info(table_name).each { |row| vd << row }
19
+ end
20
+ end
21
+
22
+ def table_info(table_name)
23
+ t = []
24
+ t << ['PK', 'Name', 'SQL Type', 'Ruby Type', 'Limit', 'Precision', 'Scale', 'Default', 'Nullable', 'Comment']
25
+ connection = ::ActiveRecord::Base.connection
26
+ connection.columns(table_name).each do |column|
27
+ pk = if [connection.primary_key(table_name)].flatten.include?(column.name)
28
+ 'Y'
29
+ else
30
+ ''
31
+ end
32
+ t << [pk, column.name, column.sql_type,
33
+ column.sql_type_metadata.type, column.sql_type_metadata.limit || '',
34
+ column.sql_type_metadata.precision || '', column.sql_type_metadata.scale || '', column.default || '',
35
+ column.null, column.comment || '']
36
+ end
37
+ t
38
+ end
39
+ end
40
+
41
+ Pry.commands.block_command 'vd' do |name|
42
+ table_name = VD::get_table_name(name)
43
+ VD::table_info_vd(table_name)
44
+ end
45
+ end
46
+ end
data/lib/arql/commands.rb CHANGED
@@ -5,6 +5,7 @@ require 'arql/commands/reconnect'
5
5
  require 'arql/commands/redefine'
6
6
  require 'arql/commands/show_sql'
7
7
  require 'arql/commands/sandbox'
8
+ require 'arql/commands/vd'
8
9
 
9
10
  module Arql::Commands
10
11
  end
@@ -2,7 +2,10 @@ module Arql
2
2
  class Connection
3
3
  class << self
4
4
  def open(options)
5
+ print "Establishing DB connection to #{options[:host]}:#{options[:port]}"
5
6
  ActiveRecord::Base.establish_connection(options)
7
+ print "\u001b[2K"
8
+ puts "\rDB connection to #{options[:host]}:#{options[:port]} established\n"
6
9
  $C = ActiveRecord::Base.connection
7
10
  $C.define_singleton_method(:dump) do |filename, no_create_db=false|
8
11
  Arql::Mysqldump.new.dump_database(filename, no_create_db)
@@ -1,4 +1,6 @@
1
1
  require 'arql/concerns'
2
+ require 'arql/vd'
3
+
2
4
  module Arql
3
5
  module Extension
4
6
  extend ActiveSupport::Concern
@@ -9,6 +11,15 @@ module Arql
9
11
  }
10
12
  end
11
13
 
14
+ def vd
15
+ VD.new do |vd|
16
+ vd << ['Attribute Name', 'Attribute Value', 'SQL Type', 'Comment']
17
+ self.class.connection.columns(self.class.table_name).each do |column|
18
+ vd << [column.name, read_attribute(column.name), column.sql_type, column.comment || '']
19
+ end
20
+ end
21
+ end
22
+
12
23
  def v
13
24
  t = []
14
25
  t << ['Attribute Name', 'Attribute Value', 'SQL Type', 'Comment']
@@ -49,6 +60,12 @@ module Arql
49
60
  puts Commands::Table::table_info_table(table_name)
50
61
  end
51
62
 
63
+ def vd
64
+ table_name = Commands::Table::get_table_name(name)
65
+ Commands::VD::table_info_vd(table_name)
66
+ nil
67
+ end
68
+
52
69
  def v
53
70
  table_name = Commands::Table::get_table_name(name)
54
71
  Commands::Table::table_info(table_name)
@@ -91,18 +108,21 @@ module Arql
91
108
  end
92
109
  @@models = []
93
110
  ActiveRecord::Base.connection.tap do |conn|
94
- conn.tables.each do |table_name|
95
- table_comment = conn.table_comment(table_name)
96
- conn.primary_key(table_name).tap do |pkey|
111
+ tables = conn.tables
112
+ comments = conn.table_comment_of_tables(tables)
113
+ primary_keys = conn.primary_keys_of_tables(tables)
114
+ tables.each do |table_name|
115
+ table_comment = comments[table_name]
116
+ primary_keys[table_name].tap do |pkey|
97
117
  table_name.camelize.tap do |const_name|
98
118
  const_name = 'Modul' if const_name == 'Module'
99
119
  const_name = 'Clazz' if const_name == 'Class'
100
120
  Class.new(::ArqlModel) do
101
121
  include Arql::Extension
102
- if pkey.is_a?(Array)
122
+ if pkey.is_a?(Array) && pkey.size > 1
103
123
  self.primary_keys = pkey
104
124
  else
105
- self.primary_key = pkey
125
+ self.primary_key = pkey&.first
106
126
  end
107
127
  self.table_name = table_name
108
128
  self.inheritance_column = nil
@@ -169,18 +189,29 @@ module Arql
169
189
  end.t
170
190
  end
171
191
  end)
172
- conn.tables.each do |table_name|
173
- table_comment = conn.table_comment(table_name)
174
- conn.primary_key(table_name).tap do |pkey|
192
+
193
+ tables = conn.tables
194
+ if conn.adapter_name == 'Mysql2'
195
+ require 'arql/ext/active_record/connection_adapters/abstract_mysql_adapter'
196
+ comments = conn.table_comment_of_tables(tables)
197
+ primary_keys = conn.primary_keys_of_tables(tables)
198
+ else
199
+ comments = tables.map { |t| [t, conn.table_comment(t)] }.to_h
200
+ primary_keys = tables.map { |t| [t, conn.primary_keys(t)] }.to_h
201
+ end
202
+
203
+ tables.each do |table_name|
204
+ table_comment = comments[table_name]
205
+ primary_keys[table_name].tap do |pkey|
175
206
  table_name.camelize.tap do |const_name|
176
207
  const_name = 'Modul' if const_name == 'Module'
177
208
  const_name = 'Clazz' if const_name == 'Class'
178
209
  Class.new(::ArqlModel) do
179
210
  include Arql::Extension
180
- if pkey.is_a?(Array)
211
+ if pkey.is_a?(Array) && pkey.size > 1
181
212
  self.primary_keys = pkey
182
213
  else
183
- self.primary_key = pkey
214
+ self.primary_key = pkey&.first
184
215
  end
185
216
  self.table_name = table_name
186
217
  self.inheritance_column = nil
@@ -229,6 +260,10 @@ module Arql
229
260
  records.t(*attrs, **options)
230
261
  end
231
262
 
263
+ def vd(*attrs, **options)
264
+ records.vd(*attrs, **options)
265
+ end
266
+
232
267
  def v
233
268
  records.v
234
269
  end
@@ -0,0 +1,53 @@
1
+ require 'active_record/connection_adapters/abstract_mysql_adapter'
2
+
3
+ module ActiveRecord
4
+ module ConnectionAdapters
5
+ class AbstractMysqlAdapter
6
+
7
+ def extract_schema_qualified_name_of_tables(table_names)
8
+ table_names.map do |string|
9
+ schema, name = string.to_s.scan(/[^`.\s]+|`[^`]*`/)
10
+ schema, name = nil, schema unless name
11
+ [schema, name]
12
+ end
13
+ end
14
+
15
+ def quoted_scope_of_tables(names = nil)
16
+ extract_schema_qualified_name_of_tables(names).map do |(schema, name)|
17
+ scope = {}
18
+ scope[:schema] = schema ? quote(schema) : "database()"
19
+ scope[:name] = quote(name) if name
20
+ scope
21
+ end
22
+ end
23
+
24
+ def primary_keys_of_tables(table_names) # :nodoc:
25
+ raise ArgumentError unless table_names.present?
26
+
27
+ scopes = quoted_scope_of_tables(table_names)
28
+
29
+ res = query(<<~SQL, "SCHEMA")
30
+ SELECT table_name, column_name
31
+ FROM information_schema.statistics
32
+ WHERE index_name = 'PRIMARY'
33
+ AND (table_schema, table_name) in
34
+ (#{scopes.map { |scope| "(#{scope[:schema]}, #{scope[:name]})" }.join(', ')})
35
+ ORDER BY seq_in_index
36
+ SQL
37
+
38
+ res.group_by(&:first).map { |table, vlaues| [table, vlaues.map(&:last)] }.to_h
39
+ end
40
+
41
+ def table_comment_of_tables(table_names) # :nodoc:
42
+ scopes = quoted_scope_of_tables(table_names)
43
+
44
+ query(<<~SQL, "SCHEMA").presence.try(&:to_h)
45
+ SELECT table_name, table_comment
46
+ FROM information_schema.tables
47
+ WHERE (table_schema, table_name) in
48
+ (#{scopes.map { |scope| "(#{scope[:schema]}, #{scope[:name]})" }.join(', ')})
49
+ SQL
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,8 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module PostgreSQL
4
+ module SchemaStatements
5
+ end
6
+ end
7
+ end
8
+ end
@@ -1,3 +1,5 @@
1
+ require 'arql/vd'
2
+
1
3
  class Array
2
4
  def to_insert_sql(batch_size=500)
3
5
  raise 'All element should be an ActiveRecord instance object' unless all? { |e| e.is_a?(ActiveRecord::Base) }
@@ -48,6 +50,33 @@ class Array
48
50
  end
49
51
  end
50
52
 
53
+ def vd(*attrs, **options)
54
+ if (attrs.present? || options.present? && options[:except]) && present? && first.is_a?(ActiveRecord::Base)
55
+ column_names = first.attribute_names.map(&:to_sym)
56
+ attrs = attrs.flat_map { |e| e.is_a?(Regexp) ? column_names.grep(e) : e }.uniq
57
+ if options.present? && options[:except]
58
+ attrs = column_names if attrs.empty?
59
+ if options[:except].is_a?(Regexp)
60
+ attrs.reject! { |e| e =~ options[:except] }
61
+ else
62
+ attrs -= [options[:except]].flatten
63
+ end
64
+ end
65
+
66
+ Arql::VD.new do |vd|
67
+ vd << attrs
68
+ each do |e|
69
+ vd << e.attributes.values_at(*attrs.map(&:to_s))
70
+ end
71
+ end
72
+ else
73
+ Arql::VD.new do |vd|
74
+ v.each { |row| vd << row if row }
75
+ end
76
+ end
77
+ nil
78
+ end
79
+
51
80
  def v
52
81
  return self unless present?
53
82
  t = []
@@ -8,9 +8,13 @@ module Arql
8
8
  attr_accessor :config, :ssh_gateway, :local_ssh_proxy_port
9
9
 
10
10
  def connect(config)
11
+ print "Establishing SSH connection to #{config[:host]}:#{config[:port]}"
11
12
  @config = config
12
13
  @ssh_gateway = Net::SSH::Gateway.new(config[:host], config[:user], config.slice(:port, :password).symbolize_keys.merge(keepalive: true, keepalive_interval: 30, loop_wait: 1))
13
14
  @local_ssh_proxy_port = @ssh_gateway.open(config[:forward_host], config[:forward_port], config[:local_port])
15
+ print "\u001b[2K"
16
+ puts "\rSSH connection to #{config[:host]}:#{config[:port]} established"
17
+ @local_ssh_proxy_port
14
18
  end
15
19
 
16
20
  def reconnect
data/lib/arql/vd.rb ADDED
@@ -0,0 +1,42 @@
1
+ require 'csv'
2
+
3
+ module Arql
4
+ class VD
5
+ COMMAND = 'vd'
6
+
7
+ attr_accessor :rows
8
+
9
+ def initialize
10
+ return unless check_command_installation
11
+ @rows = []
12
+ yield self
13
+ command = "#{COMMAND} -f csv"
14
+ IO.popen(command, 'w+') do |io|
15
+ io.puts(csv)
16
+ io.close_write
17
+ end
18
+ print "\033[5q"
19
+ end
20
+
21
+ def <<(row)
22
+ rows << row
23
+ end
24
+
25
+ def csv
26
+ CSV.generate do |csv|
27
+ rows.each do |row|
28
+ csv << row
29
+ end
30
+ end
31
+ end
32
+
33
+ def check_command_installation
34
+ `which #{COMMAND}`
35
+ if $?.exitstatus != 0
36
+ puts "Please install vd (visidata) command, see: https://www.visidata.org/"
37
+ else
38
+ true
39
+ end
40
+ end
41
+ end
42
+ end
data/lib/arql/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Arql
2
- VERSION = "0.3.5"
2
+ VERSION = "0.3.8"
3
3
  end
data/lib/arql.rb CHANGED
@@ -11,6 +11,7 @@ require "arql/ssh_proxy"
11
11
  require "arql/app"
12
12
  require "arql/cli"
13
13
  require "arql/mysqldump"
14
+ require "arql/vd"
14
15
 
15
16
  module Arql
16
17
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: arql
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.5
4
+ version: 0.3.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Liu Xiang
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-04-27 00:00:00.000000000 Z
11
+ date: 2022-05-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mysql2
@@ -245,12 +245,15 @@ files:
245
245
  - lib/arql/commands/sandbox.rb
246
246
  - lib/arql/commands/show_sql.rb
247
247
  - lib/arql/commands/table.rb
248
+ - lib/arql/commands/vd.rb
248
249
  - lib/arql/concerns.rb
249
250
  - lib/arql/concerns/global_data_definition.rb
250
251
  - lib/arql/concerns/table_data_definition.rb
251
252
  - lib/arql/connection.rb
252
253
  - lib/arql/definition.rb
253
254
  - lib/arql/ext.rb
255
+ - lib/arql/ext/active_record/connection_adapters/abstract_mysql_adapter.rb
256
+ - lib/arql/ext/active_record/connection_adapters/postgresql/schema_statements.rb
254
257
  - lib/arql/ext/array.rb
255
258
  - lib/arql/ext/hash.rb
256
259
  - lib/arql/ext/kernel.rb
@@ -263,6 +266,7 @@ files:
263
266
  - lib/arql/repl.rb
264
267
  - lib/arql/ssh_proxy.rb
265
268
  - lib/arql/ssh_proxy_patch.rb
269
+ - lib/arql/vd.rb
266
270
  - lib/arql/version.rb
267
271
  homepage: https://github.com/lululau/arql
268
272
  licenses: