arql 0.3.5 → 0.3.8

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.
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: