db-gui 0.1.0 → 0.2.1
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 +4 -4
- data/CHANGELOG.md +16 -1
- data/README.md +12 -2
- data/VERSION +1 -1
- data/app/db_gui/model/db.rb +79 -19
- data/app/db_gui/view/db_command_form.rb +1 -1
- data/app/db_gui/view/db_command_result_table.rb +9 -1
- data/app/db_gui/view/db_gui_application.rb +43 -33
- metadata +19 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 38eb8b2669f281d3dddb78945f259d5fe8dea12eb31b51f5761ce4ced71381e9
|
4
|
+
data.tar.gz: a0cb8959b31975f176302f20404011e3a8115d5e597461de0f90fe57a5305cf3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b664e4ed31d076e644451b58bd809dc9e9f58b8526d96d052d41eef238c4f293413f886eb0b4fe7f0d9fe19b66eba563d7d98f936fad43d0032b0e4f590ed9ec
|
7
|
+
data.tar.gz: 43696e4a6cb8ecd26363a5dc9f33588b1b88895aa5c16a63a88caa6fce393c9d2907f05e52b9ce66ecc3e35d6de8549e85e29f34af1191b81a1fda5b03e8cf5e
|
data/CHANGELOG.md
CHANGED
@@ -1,8 +1,23 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
## 0.2.1
|
4
|
+
|
5
|
+
- Fix bug in 0.2.0 with crashing whenever running a DB query for the second time.
|
6
|
+
|
7
|
+
## 0.2.0
|
8
|
+
|
9
|
+
- Edit -> Copy Table menu item to copy table data as a formatted string to the clipboard
|
10
|
+
- Edit -> Copy Selected Row menu item to copy selected row data as a formatted string to the clipboard
|
11
|
+
|
12
|
+
## 0.1.1
|
13
|
+
|
14
|
+
- Automatically extend DB command timeout after timing out by retrying 6 times (7 times total) with exponential timeout increases
|
15
|
+
- Avoid DB command timeout if DB result row count is received
|
16
|
+
- Show error when DB command fails
|
17
|
+
|
3
18
|
## 0.1.0
|
4
19
|
|
5
|
-
-
|
20
|
+
- Remember last DB command
|
6
21
|
- Move saved configuration from ~/.db_gui as a file to ~/.db_gui as a directory with multiple files underneath: ~/.db_gui/.db_configs & ~/.db_gui/.db_commands
|
7
22
|
|
8
23
|
## 0.0.4
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# DB GUI (Database Graphical User Interface) 0.1
|
1
|
+
# DB GUI (Database Graphical User Interface) 0.2.1
|
2
2
|
## [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=40 /> Glimmer DSL for LibUI Application](https://github.com/AndyObtiva/glimmer-dsl-libui)
|
3
3
|
[](http://badge.fury.io/rb/db-gui)
|
4
4
|
|
@@ -12,7 +12,7 @@ It currently supports PostgreSQL as a start, with the potential of supporting ma
|
|
12
12
|
|
13
13
|
Run:
|
14
14
|
```
|
15
|
-
gem install db-gui -v0.1
|
15
|
+
gem install db-gui -v0.2.1
|
16
16
|
```
|
17
17
|
|
18
18
|
## Usage
|
@@ -26,6 +26,16 @@ Or, run one of the aliases: `db-ui` / `dbgui` / `db-gui`
|
|
26
26
|
|
27
27
|
Note that it stores the last connection details under `~/.db_gui`, and will auto-connect using that configuration on startup for extra convenience (in the future, there is the potential to support multiple connection configurations).
|
28
28
|
|
29
|
+
### Menu Items
|
30
|
+
|
31
|
+
**Edit -> Copy Table**
|
32
|
+
|
33
|
+
Click on this menu item to copy the table data as a formatted string to the clipboard.
|
34
|
+
|
35
|
+
**Edit -> Copy Selected Row**
|
36
|
+
|
37
|
+
Click on this menu item to copy the selected row data as a formatted string to the clipboard.
|
38
|
+
|
29
39
|
## Change Log
|
30
40
|
|
31
41
|
[CHANGELOG.md](/CHANGELOG.md)
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1
|
1
|
+
0.2.1
|
data/app/db_gui/model/db.rb
CHANGED
@@ -1,27 +1,33 @@
|
|
1
1
|
require 'fileutils'
|
2
2
|
require 'timeout'
|
3
|
+
require 'clipboard'
|
3
4
|
|
4
5
|
class DbGui
|
5
6
|
module Model
|
6
|
-
Db = Struct.new(:host, :port, :dbname, :username, :password, keyword_init: true) do
|
7
|
+
Db = Struct.new(:host, :port, :dbname, :username, :password, :db_command_timeout, keyword_init: true) do
|
7
8
|
DIR_DB_GUI = File.expand_path(File.join('~', '.db_gui'))
|
8
9
|
FileUtils.rm(DIR_DB_GUI) if File.file?(DIR_DB_GUI)
|
9
10
|
FileUtils.mkdir_p(DIR_DB_GUI)
|
10
11
|
FILE_DB_CONFIGS = File.expand_path(File.join(DIR_DB_GUI, '.db_configs'))
|
11
12
|
FILE_DB_COMMANDS = File.expand_path(File.join(DIR_DB_GUI, '.db_commands'))
|
13
|
+
COUNT_RETRIES = ENV.fetch('DB_COMMAND_COUNT_RETRIES', 7)
|
14
|
+
REGEX_ROW_COUNT = /^\((\d+) row/
|
15
|
+
ERROR_PREFIX = 'ERROR:'
|
16
|
+
NEW_LINE = OS.windows? ? "\r\n" : "\n"
|
12
17
|
|
13
18
|
attr_accessor :connected
|
14
19
|
alias connected? connected
|
15
20
|
attr_accessor :db_command_result
|
16
21
|
attr_accessor :db_command
|
17
|
-
attr_accessor :
|
22
|
+
attr_accessor :db_command_result_selection
|
18
23
|
|
19
24
|
def initialize
|
20
|
-
self.port = 5432 # PostgreSQL default port
|
21
|
-
self.db_command_result = ''
|
22
|
-
self.db_command_timeout = (ENV['DB_COMMAND_TIMEOUT_IN_MILLISECONDS'] || 300).to_i
|
23
25
|
load_db_config
|
24
26
|
load_db_command
|
27
|
+
self.port ||= 5432 # PostgreSQL default port
|
28
|
+
self.db_command_result = ''
|
29
|
+
self.db_command_timeout ||= ENV.fetch('DB_COMMAND_TIMEOUT_IN_MILLISECONDS', 300).to_i
|
30
|
+
self.db_command_result_selection = 0
|
25
31
|
connect if to_h.except(:password).none? {|value| value.nil? || (value.respond_to?(:empty?) && value.empty?) }
|
26
32
|
end
|
27
33
|
|
@@ -46,7 +52,8 @@ class DbGui
|
|
46
52
|
end
|
47
53
|
|
48
54
|
def io
|
49
|
-
|
55
|
+
db_connection_command = "PGPASSWORD=\"#{password}\" psql --host=#{host} --port=#{port} --username=#{username} --dbname=#{dbname}"
|
56
|
+
@io ||= IO.popen(db_connection_command, 'r+', err: [:child, :out])
|
50
57
|
end
|
51
58
|
|
52
59
|
def run_io_command(command)
|
@@ -56,13 +63,22 @@ class DbGui
|
|
56
63
|
@io_command_try += 1
|
57
64
|
io.puts(command)
|
58
65
|
read_io_into_db_command_result
|
59
|
-
|
66
|
+
@io_command_try = nil
|
67
|
+
rescue Timeout::Error, Errno::EPIPE => e
|
68
|
+
puts e.message
|
60
69
|
@io = nil
|
61
|
-
|
70
|
+
if @io_command_try > COUNT_RETRIES
|
71
|
+
@io_command_try = nil
|
72
|
+
else
|
73
|
+
self.db_command_timeout *= 2
|
74
|
+
puts "Retrying DB Command... {try: #{@io_command_try + 1}, db_command_timeout: #{db_command_timeout}}"
|
75
|
+
run_io_command(command) unless db_command_result_error?
|
76
|
+
end
|
62
77
|
end
|
63
78
|
|
64
79
|
def run_db_command
|
65
80
|
run_io_command(db_command)
|
81
|
+
save_db_config
|
66
82
|
save_db_command
|
67
83
|
end
|
68
84
|
|
@@ -78,16 +94,50 @@ class DbGui
|
|
78
94
|
db_command_result_count_headers_rows[2]
|
79
95
|
end
|
80
96
|
|
97
|
+
def db_command_result_error?
|
98
|
+
db_command_result.to_s.strip.start_with?(ERROR_PREFIX)
|
99
|
+
end
|
100
|
+
|
101
|
+
def copy_table
|
102
|
+
return if db_command_result_rows.empty?
|
103
|
+
Clipboard.copy(formatted_table_string)
|
104
|
+
end
|
105
|
+
|
106
|
+
def copy_selected_row
|
107
|
+
return if db_command_result_rows.empty?
|
108
|
+
Clipboard.copy(formatted_selected_row_string)
|
109
|
+
end
|
110
|
+
|
111
|
+
def formatted_table_string
|
112
|
+
column_max_lengths = db_command_result_column_max_lengths
|
113
|
+
db_command_result_rows.map do |row|
|
114
|
+
row.each_with_index.map do |data, column_index|
|
115
|
+
data.ljust(column_max_lengths[column_index])
|
116
|
+
end.join(" | ")
|
117
|
+
end.join(NEW_LINE)
|
118
|
+
end
|
119
|
+
|
120
|
+
def formatted_selected_row_string
|
121
|
+
selected_row = db_command_result_rows[db_command_result_selection]
|
122
|
+
selected_row.join(' | ')
|
123
|
+
end
|
124
|
+
|
81
125
|
private
|
82
126
|
|
83
127
|
def read_io_into_db_command_result
|
84
|
-
self.db_command_result = ''
|
85
|
-
while (line = io_gets)
|
86
|
-
|
87
|
-
self.db_command_result += result
|
128
|
+
self.db_command_result = read_db_command_result = ''
|
129
|
+
while (!(@line.to_s.match(REGEX_ROW_COUNT) || @line.to_s.strip == "^") && (@line = io_gets))
|
130
|
+
read_db_command_result += @line.to_s
|
88
131
|
end
|
89
|
-
|
90
|
-
|
132
|
+
self.db_command_result = read_db_command_result
|
133
|
+
rescue
|
134
|
+
if read_db_command_result.to_s.strip.start_with?(ERROR_PREFIX)
|
135
|
+
self.db_command_result = read_db_command_result
|
136
|
+
else
|
137
|
+
raise
|
138
|
+
end
|
139
|
+
ensure
|
140
|
+
@line = nil
|
91
141
|
end
|
92
142
|
|
93
143
|
def save_db_config
|
@@ -123,11 +173,10 @@ class DbGui
|
|
123
173
|
end
|
124
174
|
|
125
175
|
def io_gets
|
126
|
-
# TODO figure out a way of knowing the end of input without timing out
|
127
176
|
Timeout.timeout(db_command_timeout/1000.0) { io.gets }
|
128
177
|
rescue
|
129
178
|
@io = nil
|
130
|
-
|
179
|
+
raise
|
131
180
|
end
|
132
181
|
|
133
182
|
def db_command_result_count_headers_rows
|
@@ -141,12 +190,11 @@ class DbGui
|
|
141
190
|
def compute_db_command_result_count_headers_rows
|
142
191
|
count = 0
|
143
192
|
headers = rows = []
|
144
|
-
db_command_result_lines = db_command_result.lines
|
145
|
-
db_command_result_lines.pop if db_command_result_lines.last == "\n"
|
193
|
+
db_command_result_lines = db_command_result.lines.reject { |line| line == "\n" }
|
146
194
|
if db_command_result_lines.any?
|
147
195
|
headers = db_command_result_lines.first.split('|').map(&:strip)
|
148
196
|
count_footer = db_command_result_lines.last
|
149
|
-
count_match = count_footer.match(
|
197
|
+
count_match = count_footer.match(REGEX_ROW_COUNT)
|
150
198
|
if count_match
|
151
199
|
count = count_match[1].to_i
|
152
200
|
rows = db_command_result_lines[2..-2].map {|row| row.split('|').map(&:strip) }
|
@@ -154,6 +202,18 @@ class DbGui
|
|
154
202
|
end
|
155
203
|
[count, headers, rows]
|
156
204
|
end
|
205
|
+
|
206
|
+
def db_command_result_column_max_lengths
|
207
|
+
column_count = db_command_result_rows.first.size
|
208
|
+
column_max_lengths = []
|
209
|
+
db_command_result_rows.each do |row|
|
210
|
+
row.each_with_index do |value, column_index|
|
211
|
+
column_max_lengths[column_index] ||= 0
|
212
|
+
column_max_lengths[column_index] = [column_max_lengths[column_index], value.size].max
|
213
|
+
end
|
214
|
+
end
|
215
|
+
column_max_lengths
|
216
|
+
end
|
157
217
|
end
|
158
218
|
end
|
159
219
|
end
|
@@ -10,13 +10,21 @@ class DbGui
|
|
10
10
|
body {
|
11
11
|
vertical_box {
|
12
12
|
content(db, :db_command_result) {
|
13
|
-
if db.
|
13
|
+
if db.db_command_result_error?
|
14
|
+
label(db.db_command_result)
|
15
|
+
elsif db.db_command_result_count > 0
|
14
16
|
table {
|
15
17
|
db.db_command_result_headers.each do |header|
|
16
18
|
text_column(header)
|
17
19
|
end
|
18
20
|
|
19
21
|
cell_rows db.db_command_result_rows
|
22
|
+
selection_mode :one
|
23
|
+
selection db.db_command_result_selection
|
24
|
+
|
25
|
+
on_selection_changed do |t, selection, added_selection, removed_selection|
|
26
|
+
db.db_command_result_selection = selection
|
27
|
+
end
|
20
28
|
}
|
21
29
|
else
|
22
30
|
label('No data')
|
@@ -13,7 +13,7 @@ class DbGui
|
|
13
13
|
|
14
14
|
before_body do
|
15
15
|
@db = Model::Db.new
|
16
|
-
|
16
|
+
menu_bar
|
17
17
|
end
|
18
18
|
|
19
19
|
body {
|
@@ -35,38 +35,48 @@ class DbGui
|
|
35
35
|
}
|
36
36
|
}
|
37
37
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
38
|
+
def menu_bar
|
39
|
+
menu('Edit') {
|
40
|
+
menu_item('Copy Table') {
|
41
|
+
enabled <= [db, :db_command_result_rows, computed_by: :db_command_result, on_read: -> (data) { !data.empty? }]
|
42
|
+
|
43
|
+
on_clicked do
|
44
|
+
db.copy_table
|
45
|
+
end
|
46
|
+
}
|
47
|
+
|
48
|
+
menu_item('Copy Selected Row') {
|
49
|
+
enabled <= [db, :db_command_result_rows, computed_by: :db_command_result, on_read: -> (data) { !data.empty? }]
|
50
|
+
|
51
|
+
on_clicked do
|
52
|
+
db.copy_selected_row
|
53
|
+
end
|
54
|
+
}
|
55
|
+
|
56
|
+
quit_menu_item if OS.mac?
|
57
|
+
}
|
58
|
+
menu('Help') {
|
59
|
+
if OS.mac?
|
60
|
+
about_menu_item {
|
61
|
+
on_clicked do
|
62
|
+
display_about_dialog
|
63
|
+
end
|
64
|
+
}
|
65
|
+
end
|
66
|
+
|
67
|
+
menu_item('About') {
|
68
|
+
on_clicked do
|
69
|
+
display_about_dialog
|
70
|
+
end
|
71
|
+
}
|
72
|
+
}
|
73
|
+
end
|
74
|
+
|
75
|
+
def display_about_dialog
|
76
|
+
message = "DB GUI #{VERSION}\n\n#{LICENSE}"
|
77
|
+
msg_box('About', message)
|
78
|
+
end
|
79
|
+
|
70
80
|
# def display_preferences_dialog
|
71
81
|
# window {
|
72
82
|
# title 'Preferences'
|
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: db-gui
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andy Maleh
|
8
|
-
autorequire:
|
9
8
|
bindir: bin
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: glimmer-dsl-libui
|
@@ -24,6 +23,20 @@ dependencies:
|
|
24
23
|
- - "~>"
|
25
24
|
- !ruby/object:Gem::Version
|
26
25
|
version: 0.12.7
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: clipboard
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - "~>"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 2.0.0
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: 2.0.0
|
27
40
|
- !ruby/object:Gem::Dependency
|
28
41
|
name: rspec
|
29
42
|
requirement: !ruby/object:Gem::Requirement
|
@@ -67,12 +80,12 @@ dependencies:
|
|
67
80
|
- !ruby/object:Gem::Version
|
68
81
|
version: '0'
|
69
82
|
description: DB GUI (Database Graphical User Interface) - Enables Interaction with
|
70
|
-
Relational SQL Databases
|
83
|
+
Relational SQL Databases. This alpha version only supports PostgreSQL at the moment.
|
71
84
|
email: andy.am@gmail.com
|
72
85
|
executables:
|
73
86
|
- db-gui
|
74
|
-
- dbgui
|
75
87
|
- db-ui
|
88
|
+
- dbgui
|
76
89
|
- dbui
|
77
90
|
extensions: []
|
78
91
|
extra_rdoc_files:
|
@@ -102,7 +115,6 @@ homepage: http://github.com/AndyObtiva/db-gui
|
|
102
115
|
licenses:
|
103
116
|
- MIT
|
104
117
|
metadata: {}
|
105
|
-
post_install_message:
|
106
118
|
rdoc_options: []
|
107
119
|
require_paths:
|
108
120
|
- lib
|
@@ -118,8 +130,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
118
130
|
- !ruby/object:Gem::Version
|
119
131
|
version: '0'
|
120
132
|
requirements: []
|
121
|
-
rubygems_version: 3.
|
122
|
-
signing_key:
|
133
|
+
rubygems_version: 3.6.7
|
123
134
|
specification_version: 4
|
124
135
|
summary: DB GUI
|
125
136
|
test_files: []
|