db_admin 0.1.3 → 0.1.4
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/README.md +8 -8
- data/bin/db_admin +2 -0
- data/lib/db_admin.rb +215 -215
- data/lib/db_admin/run_web.rb +3 -0
- data/lib/views/index.erb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0a8f97746d7103044bbf1dc369ba58e71f3187cf56be65ff25bd4db59306d3d5
|
4
|
+
data.tar.gz: 8cfeffc151121b48db254645fcf35a3e0571a7140796d00b15f6ffb5e0b48830
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dae113ec5ed7439ce49e53a4454b9eac58877826d6562b31683febf3d1a9ba8a7c2178156f9a1f13b0f7c378b78e951b2ca428abcf644c16fbc4ad58fa646430
|
7
|
+
data.tar.gz: 35cab1a68129ed60709e938b13a6d7eae444ba857c21562a01f63343f20ac02313c5e2173bd03f7550dcf0feb348b011faf353fe803e1d3a9999083ac6a47462
|
data/README.md
CHANGED
@@ -11,15 +11,14 @@ Rails user can also use it because it is just a gem. Here are some demo pictures
|
|
11
11
|

|
12
12
|
|
13
13
|
## Installation
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
Or modify `Gemfile` as below, then `$ bundle install`.
|
14
|
+
**The best way** to use this gem is **`gem install db_admin`**.
|
15
|
+
|
16
|
+
If you prefer to use it in `Gemfile`:
|
18
17
|
~~~ruby
|
19
|
-
group :development do
|
18
|
+
group :development do
|
20
19
|
# A Web UI for database admin. Run `$ db_admin` and then
|
21
20
|
# visit http://localhost:4567
|
22
|
-
gem 'db_admin', require: false
|
21
|
+
gem 'db_admin', require: false # Don't require the code because you needn't it.
|
23
22
|
end
|
24
23
|
~~~
|
25
24
|
|
@@ -36,11 +35,12 @@ Visit [http://localhost:4567](http://localhost:4567/)
|
|
36
35
|
If you want to change some code for your own purpose, please
|
37
36
|
~~~bash
|
38
37
|
$ git clone git@github.com:gazeldx/db_admin.git
|
39
|
-
$
|
38
|
+
$ cd db_admin
|
39
|
+
$ ruby lib/db_admin/run_web.rb # Then visit http://localhost:4567
|
40
40
|
~~~
|
41
41
|
|
42
42
|
### Debugging
|
43
|
-
You need to restart Web
|
43
|
+
You need to restart Web when you made a change.
|
44
44
|
|
45
45
|
Uncomment the below line in `./lib/db_admin.rb` to auto-reload changed files.
|
46
46
|
~~~ruby
|
data/bin/db_admin
CHANGED
data/lib/db_admin.rb
CHANGED
@@ -2,291 +2,291 @@ require 'sinatra/base'
|
|
2
2
|
require 'sequel'
|
3
3
|
require 'json'
|
4
4
|
|
5
|
-
|
6
|
-
|
5
|
+
module DBAdmin
|
6
|
+
class Web < Sinatra::Base
|
7
|
+
# require 'sinatra/reloader' if development? # `$ gem install sinatra-reloader` first if you want to debug this project by auto-reloading changed files.
|
7
8
|
|
8
|
-
|
9
|
+
use Rack::MethodOverride
|
9
10
|
|
10
|
-
|
11
|
-
|
11
|
+
DBs = []
|
12
|
+
DB = nil
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
14
|
+
# Direct connect. 'adapter' can be 'postgres', 'mysql2', 'sqlite', 'oracle', etc.
|
15
|
+
# DB = Sequel.connect({ adapter: 'postgres',
|
16
|
+
# host: 'hostname_or_ip',
|
17
|
+
# database: 'database_name',
|
18
|
+
# user: 'user',
|
19
|
+
# password: '' })
|
19
20
|
|
20
|
-
|
21
|
+
DBs << DB unless DB.nil?
|
21
22
|
|
22
|
-
|
23
|
+
set :bind, '0.0.0.0'
|
23
24
|
|
24
|
-
|
25
|
+
enable :sessions
|
25
26
|
|
26
|
-
|
27
|
-
|
28
|
-
|
27
|
+
get '/' do
|
28
|
+
erb :index, layout: :layout_index
|
29
|
+
end
|
29
30
|
|
30
|
-
|
31
|
-
|
32
|
-
|
31
|
+
get '/home' do
|
32
|
+
erb :home
|
33
|
+
end
|
33
34
|
|
34
|
-
|
35
|
-
|
35
|
+
get '/tables/:table_name' do
|
36
|
+
@schema = DB.schema(params[:table_name].to_sym)
|
36
37
|
|
37
|
-
|
38
|
-
|
39
|
-
|
38
|
+
@dataset = DB[params[:table_name].to_sym]
|
39
|
+
.extension(:pagination)
|
40
|
+
.paginate((params[:page] || 1).to_i, 50, record_count = nil)
|
40
41
|
|
41
|
-
|
42
|
-
|
42
|
+
erb :table
|
43
|
+
end
|
43
44
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
45
|
+
post '/select_sql' do
|
46
|
+
@dataset = DB.fetch(params[:sql].gsub(';', ''))
|
47
|
+
.extension(:pagination)
|
48
|
+
.paginate((params[:page] || 1).to_i, 1000, record_count = nil)
|
48
49
|
|
49
|
-
|
50
|
-
|
50
|
+
erb :select_sql
|
51
|
+
end
|
51
52
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
53
|
+
post '/connect_another_db' do
|
54
|
+
begin
|
55
|
+
another_db = Sequel.connect(connect_hash)
|
56
|
+
if another_db.test_connection
|
57
|
+
DB = another_db
|
58
|
+
DBs << DB
|
59
|
+
end
|
60
|
+
rescue Sequel::AdapterNotFound => e
|
61
|
+
session[:error] = "#{e.message} \n You need to install the database driver gem first.\n Please uncomment the driver gem in 'Gemfile' and run `$ bundle install`."
|
62
|
+
rescue Exception => e
|
63
|
+
session[:error] = e.message
|
58
64
|
end
|
59
|
-
rescue Sequel::AdapterNotFound => e
|
60
|
-
session[:error] = "#{e.message} \n You need to install the database driver gem first.\n Please uncomment the driver gem in 'Gemfile' and run `$ bundle install`."
|
61
|
-
rescue Exception => e
|
62
|
-
session[:error] = e.message
|
63
|
-
end
|
64
65
|
|
65
|
-
|
66
|
-
|
66
|
+
redirect (session[:error] ? '/' : '/home')
|
67
|
+
end
|
67
68
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
69
|
+
get '/switch_db/:i' do
|
70
|
+
begin
|
71
|
+
if should_switch_db?(DBs[params[:i].to_i])
|
72
|
+
DB = DBs[params[:i].to_i]
|
73
|
+
end
|
74
|
+
rescue Exception => e
|
75
|
+
session[:error] = e.message
|
72
76
|
end
|
73
|
-
rescue Exception => e
|
74
|
-
session[:error] = e.message
|
75
|
-
end
|
76
77
|
|
77
|
-
|
78
|
-
|
78
|
+
redirect (session[:error] ? '/' : '/home')
|
79
|
+
end
|
79
80
|
|
80
81
|
|
81
|
-
|
82
|
-
|
82
|
+
post '/tables/:table_name/insert_one' do
|
83
|
+
content_type :json
|
83
84
|
|
84
|
-
|
85
|
-
|
86
|
-
|
85
|
+
begin
|
86
|
+
id = DB[params[:table_name].to_sym]
|
87
|
+
.insert(textarea_value_to_hash(params[:values]))
|
87
88
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
89
|
+
{ id: id }.to_json
|
90
|
+
rescue Exception => e
|
91
|
+
status 500
|
92
|
+
{ message: e.message }.to_json
|
93
|
+
end
|
92
94
|
end
|
93
|
-
end
|
94
|
-
|
95
|
-
delete '/tables/:table_name/delete_one/:id' do
|
96
|
-
DB[params[:table_name].to_sym].where(id: params[:id]).delete
|
97
|
-
|
98
|
-
content_type :json
|
99
|
-
{ id: params[:id] }.to_json
|
100
|
-
end
|
101
|
-
|
102
|
-
delete '/tables/:table_name/truncate' do
|
103
|
-
DB[params[:table_name].to_sym].truncate
|
104
95
|
|
105
|
-
|
106
|
-
|
107
|
-
end
|
96
|
+
delete '/tables/:table_name/delete_one/:id' do
|
97
|
+
DB[params[:table_name].to_sym].where(id: params[:id]).delete
|
108
98
|
|
109
|
-
|
110
|
-
|
99
|
+
content_type :json
|
100
|
+
{ id: params[:id] }.to_json
|
101
|
+
end
|
111
102
|
|
112
|
-
|
113
|
-
|
114
|
-
end
|
103
|
+
delete '/tables/:table_name/truncate' do
|
104
|
+
DB[params[:table_name].to_sym].truncate
|
115
105
|
|
116
|
-
|
117
|
-
|
106
|
+
session[:notice] = "#{params[:table_name].to_sym.inspect} truncated!"
|
107
|
+
redirect back
|
108
|
+
end
|
118
109
|
|
119
|
-
|
120
|
-
|
121
|
-
end
|
110
|
+
delete '/tables/:table_name/delete_all' do
|
111
|
+
DB[params[:table_name].to_sym].delete
|
122
112
|
|
123
|
-
|
124
|
-
|
113
|
+
session[:notice] = "All #{params[:table_name].to_sym.inspect} data deleted!"
|
114
|
+
redirect back
|
115
|
+
end
|
125
116
|
|
126
|
-
|
127
|
-
DB
|
128
|
-
.where(id: params[:id])
|
129
|
-
.update(params[:column_name].to_sym => params[:new_value])
|
117
|
+
delete '/tables/:table_name/drop' do
|
118
|
+
DB.drop_table(params[:table_name].to_sym)
|
130
119
|
|
131
|
-
|
132
|
-
|
133
|
-
}.to_json
|
134
|
-
rescue Exception => e
|
135
|
-
status 500
|
136
|
-
{ message: e.message }.to_json
|
120
|
+
session[:notice] = "Table #{params[:table_name].to_sym.inspect} dropped!"
|
121
|
+
redirect '/'
|
137
122
|
end
|
138
|
-
end
|
139
123
|
|
140
|
-
|
141
|
-
|
124
|
+
put '/tables/:table_name/:id/:column_name' do
|
125
|
+
content_type :json
|
142
126
|
|
143
|
-
|
144
|
-
|
127
|
+
begin
|
128
|
+
DB[params[:table_name].to_sym]
|
129
|
+
.where(id: params[:id])
|
130
|
+
.update(params[:column_name].to_sym => params[:new_value])
|
145
131
|
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
132
|
+
{ new_value: (params[:column_name] == 'id' ? params[:new_value] : DB[params[:table_name].to_sym].first(id: params[:id])[params[:column_name].to_sym]),
|
133
|
+
td_id: params[:td_id]
|
134
|
+
}.to_json
|
135
|
+
rescue Exception => e
|
136
|
+
status 500
|
137
|
+
{ message: e.message }.to_json
|
138
|
+
end
|
150
139
|
end
|
151
|
-
end
|
152
140
|
|
153
|
-
|
154
|
-
|
141
|
+
post '/execute_sql' do
|
142
|
+
content_type :json
|
155
143
|
|
156
|
-
begin
|
157
|
-
DB[params[:table_name].to_sym]
|
158
|
-
.first(id: params[:id])
|
159
|
-
.merge(table_name: ":#{params[:table_name]}", rand_id: params[:rand_id]).to_json
|
160
|
-
rescue
|
161
|
-
status 500
|
162
|
-
{ table_name: ":#{params[:table_name]}", rand_id: params[:rand_id], id: params[:id] }.to_json
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
|
-
helpers do
|
167
|
-
def database_name
|
168
144
|
begin
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
/.*\/(.*)">$/.match(DB.inspect)[1]
|
173
|
-
end
|
145
|
+
result = DB.run params[:sql]
|
146
|
+
|
147
|
+
{ result: result }.to_json
|
174
148
|
rescue Exception => e
|
175
|
-
|
149
|
+
status 500
|
150
|
+
{ message: e.message }.to_json
|
176
151
|
end
|
177
152
|
end
|
178
153
|
|
179
|
-
|
180
|
-
|
181
|
-
end
|
154
|
+
get '/belongs_to_table_find/:table_name/:id' do
|
155
|
+
content_type :json
|
182
156
|
|
183
|
-
|
184
|
-
|
157
|
+
begin
|
158
|
+
DB[params[:table_name].to_sym]
|
159
|
+
.first(id: params[:id])
|
160
|
+
.merge(table_name: ":#{params[:table_name]}", rand_id: params[:rand_id]).to_json
|
161
|
+
rescue
|
162
|
+
status 500
|
163
|
+
{ table_name: ":#{params[:table_name]}", rand_id: params[:rand_id], id: params[:id] }.to_json
|
164
|
+
end
|
185
165
|
end
|
186
166
|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
167
|
+
helpers do
|
168
|
+
def database_name
|
169
|
+
begin
|
170
|
+
if /{.*}/.match(DB.inspect)
|
171
|
+
db_hash[:database]
|
172
|
+
else
|
173
|
+
/.*\/(.*)">$/.match(DB.inspect)[1]
|
174
|
+
end
|
175
|
+
rescue Exception => e
|
176
|
+
puts e.message
|
177
|
+
end
|
192
178
|
end
|
193
|
-
end
|
194
179
|
|
195
|
-
|
196
|
-
|
197
|
-
if session[:notice]
|
198
|
-
result = "<div class='alert alert-success' role='alert'>#{session[:notice]}</div>"
|
199
|
-
session[:notice] = nil
|
180
|
+
def database_adapter
|
181
|
+
adapter_hash[DB.database_type]
|
200
182
|
end
|
201
183
|
|
202
|
-
|
203
|
-
|
204
|
-
session[:error] = nil
|
184
|
+
def database_host
|
185
|
+
database_hash(DB)[:host]
|
205
186
|
end
|
206
|
-
result
|
207
|
-
end
|
208
187
|
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
</a>
|
216
|
-
<ul id='ul_belongs_to_#{rand_id}' class='dropdown-menu' role='menu'>Searching...</ul>
|
217
|
-
</li>"
|
218
|
-
else
|
219
|
-
row[column].is_a?(String) ? long_string_become_short(row[column]) : column_text(row[column])
|
188
|
+
def column_name_with_belongs_to(column_name)
|
189
|
+
if belongs_to_table(column_name)
|
190
|
+
"<a href='/tables/#{belongs_to_table(column_name)}'>#{column_name[0..column_name.size - 4]}</a>_id"
|
191
|
+
else
|
192
|
+
column_name
|
193
|
+
end
|
220
194
|
end
|
221
|
-
end
|
222
195
|
|
223
|
-
|
196
|
+
def notice_error
|
197
|
+
result = ''
|
198
|
+
if session[:notice]
|
199
|
+
result = "<div class='alert alert-success' role='alert'>#{session[:notice]}</div>"
|
200
|
+
session[:notice] = nil
|
201
|
+
end
|
224
202
|
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
203
|
+
if session[:error]
|
204
|
+
result = "<div class='alert alert-danger' role='alert'>#{session[:error]}</div>"
|
205
|
+
session[:error] = nil
|
206
|
+
end
|
207
|
+
result
|
208
|
+
end
|
209
|
+
|
210
|
+
def show_column_text(row, column)
|
211
|
+
if row[column].is_a?(Integer) && belongs_to_table(column)
|
212
|
+
rand_id = rand(1000000000)
|
213
|
+
"<li class='dropdown' style='list-style: none'>
|
214
|
+
<a href='#' onclick='belongs_to_table_find.call(this)' data-rand-id=#{rand_id} data-url='/belongs_to_table_find/#{belongs_to_table(column)}/#{row[column]}' class='dropdown-toggle' data-toggle='dropdown' role='button' aria-expanded='false' title='Click to show relation data'>
|
215
|
+
#{row[column]}
|
216
|
+
</a>
|
217
|
+
<ul id='ul_belongs_to_#{rand_id}' class='dropdown-menu' role='menu'>Searching...</ul>
|
218
|
+
</li>"
|
219
|
+
else
|
220
|
+
row[column].is_a?(String) ? long_string_become_short(row[column]) : column_text(row[column])
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
private
|
225
|
+
|
226
|
+
def belongs_to_table(column_name)
|
227
|
+
match_data = column_name.to_s.match(/(.*)_id$/)
|
228
|
+
if match_data
|
229
|
+
table = match_data[1]
|
230
|
+
begin
|
231
|
+
if DB.table_exists?("#{table}es")
|
232
|
+
return "#{table}es"
|
233
|
+
elsif DB.table_exists?("#{table[0..table.size - 2]}ies")
|
234
|
+
return "#{table[0..(table.size - 2)]}ies"
|
235
|
+
elsif DB.table_exists?("#{table}s")
|
236
|
+
return "#{table}s"
|
237
|
+
elsif DB.table_exists?("#{table}")
|
238
|
+
return "#{table}"
|
239
|
+
end
|
240
|
+
rescue Exception => e
|
241
|
+
puts e.message
|
238
242
|
end
|
239
|
-
rescue Exception => e
|
240
|
-
puts e.message
|
241
243
|
end
|
244
|
+
nil
|
242
245
|
end
|
243
|
-
nil
|
244
|
-
end
|
245
246
|
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
247
|
+
def long_string_become_short(string_value)
|
248
|
+
if string_value.to_s.size > 33
|
249
|
+
"#{string_value[0..30]}<a href='#' onclick='show_full_content.call(this)' title='Click to show full content'>...</a>"
|
250
|
+
else
|
251
|
+
column_text(string_value)
|
252
|
+
end
|
251
253
|
end
|
252
|
-
end
|
253
254
|
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
255
|
+
def column_text(value)
|
256
|
+
if value.to_s.strip == ''
|
257
|
+
' '
|
258
|
+
else
|
259
|
+
value
|
260
|
+
end
|
259
261
|
end
|
260
|
-
end
|
261
262
|
|
262
|
-
|
263
|
-
|
264
|
-
|
263
|
+
def adapter_hash
|
264
|
+
{ :sqlite => 'SQLite', :postgres => 'PostgreSQL', :mysql => 'MySQL', :mysql2 => 'MySQL', :oracle => 'Oracle', :sqlanywhere => 'SQL Anywhere' }
|
265
|
+
end
|
265
266
|
|
266
|
-
|
267
|
-
|
267
|
+
def database_hash(db)
|
268
|
+
eval(/{.*}/.match(db.inspect)[0])
|
269
|
+
end
|
268
270
|
end
|
269
|
-
end
|
270
271
|
|
271
|
-
|
272
|
+
private
|
272
273
|
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
274
|
+
def textarea_value_to_hash(textarea_value)
|
275
|
+
hash = textarea_value.gsub(/(\r)+/, '').gsub(/(\n)+/, ',')
|
276
|
+
hash = hash[0..hash.size - 2] if hash[hash.size - 1] == ','
|
277
|
+
eval("{#{hash}}")
|
278
|
+
end
|
278
279
|
|
279
|
-
|
280
|
-
|
281
|
-
|
280
|
+
def connect_hash
|
281
|
+
textarea_value_to_hash(params[:connect_hash]).merge(adapter: params[:adapter])
|
282
|
+
end
|
282
283
|
|
283
|
-
|
284
|
-
|
285
|
-
|
284
|
+
def db_hash
|
285
|
+
eval(/{.*}/.match(DB.inspect)[0])
|
286
|
+
end
|
286
287
|
|
287
|
-
|
288
|
-
|
288
|
+
def should_switch_db?(new_db)
|
289
|
+
new_db.test_connection && new_db != DB
|
290
|
+
end
|
289
291
|
end
|
290
292
|
end
|
291
|
-
|
292
|
-
RubyDatabaseAdmin.run!
|
data/lib/views/index.erb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: db_admin
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lane Zhang
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-02-
|
11
|
+
date: 2019-02-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sinatra
|
@@ -49,6 +49,7 @@ files:
|
|
49
49
|
- README.md
|
50
50
|
- bin/db_admin
|
51
51
|
- lib/db_admin.rb
|
52
|
+
- lib/db_admin/run_web.rb
|
52
53
|
- lib/public/css/bootstrap.min.css
|
53
54
|
- lib/public/demo_home.png
|
54
55
|
- lib/public/demo_hover.png
|