sqlui 0.1.14 → 0.1.16

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: 66115c1e705ecfeed1b2984ad0132ced622cfe53aab9170619dc247cac63f1c6
4
- data.tar.gz: b75a3856ad3ec0195b12dbe552d5aed89b925442646c83953717ac61c94c2d66
3
+ metadata.gz: d7c438724dd4d58432da2908650a10bb82c3452a2faf4f0560c5dd23a8fd6d66
4
+ data.tar.gz: 949a64296520f3e7fcfec48ae1a4cc8b4a4056184d88a88ca52b5813b1ad8064
5
5
  SHA512:
6
- metadata.gz: 51cefeed6b4c4a52641c4538412f9b4a5b3a467d9eb9fe1e49def4652f9443c11c6f92f94dc319ee813644c426cdf3aad61e8b719078f3a6b2edaf3824b2bca8
7
- data.tar.gz: 10c58b5566acf86680e0d5dd0fbffe3d72bc263cdc24aa7248b13fdf9bbad86bdf13ed7ff5cde08573c2b06d21e144d4e9de10c45035763a15eab227e202c551
6
+ metadata.gz: ab6348bdcbeb1b2dfd7e38c206b7d72bf388f28ae992e15c40823b00db1bc3bdfb705cc3764373ca0f1de053b32ea546f84bdacf99328b5b6def0f9aea40954e
7
+ data.tar.gz: a55564765cd9c90fe47ef06d521aefde3bc78f903527cd4a49b6817267364ff6cd609d47b645a9508c382fcc1798b355b414b12ea861782038b538dbaa90a861
data/.version CHANGED
@@ -1 +1 @@
1
- 0.1.14
1
+ 0.1.16
@@ -0,0 +1,20 @@
1
+ class Environment
2
+ SERVER_ENV = ENV.fetch('SERVER_ENV', 'development').to_sym
3
+ SERVER_PORT = ENV.fetch('SERVER_PORT', 8080)
4
+
5
+ def self.server_env
6
+ SERVER_ENV
7
+ end
8
+
9
+ def self.development?
10
+ SERVER_ENV == :development
11
+ end
12
+
13
+ def self.production?
14
+ SERVER_ENV == :production
15
+ end
16
+
17
+ def self.server_port
18
+ SERVER_PORT
19
+ end
20
+ end
data/app/server.rb CHANGED
@@ -4,6 +4,7 @@ require 'mysql2'
4
4
  require 'sinatra/base'
5
5
  require_relative 'sqlui'
6
6
  require 'yaml'
7
+ require_relative 'environment'
7
8
 
8
9
  if ARGV.include?('-v') || ARGV.include?('--version')
9
10
  puts File.read('.version')
@@ -16,7 +17,8 @@ raise "configuration file does not exist" unless File.exist?(ARGV[0])
16
17
  class Server < Sinatra::Base
17
18
  set :logging, true
18
19
  set :bind, '0.0.0.0'
19
- set :port, Integer(ENV['PORT'])
20
+ set :port, Environment.server_port
21
+ set :env, Environment.server_env
20
22
 
21
23
  class Client
22
24
  def initialize(params)
data/app/sqlui.rb CHANGED
@@ -11,7 +11,7 @@ class SQLUI
11
11
  @name = name
12
12
  @saved_path = saved_path
13
13
  @max_rows = max_rows
14
- @resources_dir = File.join(File.expand_path('..', File.dirname(__FILE__)), 'resources')
14
+ @resources_dir = File.join(File.expand_path('..', File.dirname(__FILE__)), 'client', 'resources')
15
15
  end
16
16
 
17
17
  def get(params)
@@ -78,25 +78,6 @@ class SQLUI
78
78
  end
79
79
 
80
80
  def load_metadata
81
- if @table_schema
82
- where_clause = "where table_schema = '#{@table_schema}'"
83
- else
84
- where_clause = "where table_schema not in('mysql', 'sys')"
85
- end
86
- stats_result = @client.query(
87
- <<~SQL
88
- select
89
- table_schema,
90
- table_name,
91
- index_name,
92
- seq_in_index,
93
- non_unique,
94
- column_name
95
- from information_schema.statistics
96
- #{where_clause}
97
- order by table_schema, table_name, if(index_name = "PRIMARY", 0, index_name), seq_in_index;
98
- SQL
99
- )
100
81
  result = {
101
82
  server: @name,
102
83
  schemas: {},
@@ -107,40 +88,11 @@ class SQLUI
107
88
  }
108
89
  end
109
90
  }
110
- stats_result.each do |row|
111
- table_schema = row['table_schema']
112
- unless result[:schemas][table_schema]
113
- result[:schemas][table_schema] = {
114
- tables: {}
115
- }
116
- end
117
- tables = result[:schemas][table_schema][:tables]
118
- table_name = row['table_name']
119
- unless tables[table_name]
120
- tables[table_name] = {
121
- indexes: {},
122
- columns: {}
123
- }
124
- end
125
- indexes = tables[table_name][:indexes]
126
- index_name = row['index_name']
127
- unless indexes[index_name]
128
- indexes[index_name] = {}
129
- end
130
- index = indexes[index_name]
131
- column_name = row['column_name']
132
- index[column_name] = {}
133
- column = index[column_name]
134
- column[:name] = index_name
135
- column[:seq_in_index] = row['seq_in_index']
136
- column[:non_unique] = row['non_unique']
137
- column[:column_name] = row['column_name']
138
- end
139
91
 
140
92
  if @table_schema
141
93
  where_clause = "where table_schema = '#{@table_schema}'"
142
94
  else
143
- where_clause = "where table_schema not in('information_schema' 'mysql', 'performance_schema', 'sys')"
95
+ where_clause = "where table_schema not in('mysql', 'sys', 'information_schema', 'performance_schema')"
144
96
  end
145
97
  column_result = @client.query(
146
98
  <<~SQL
@@ -155,29 +107,78 @@ class SQLUI
155
107
  column_default,
156
108
  extra
157
109
  from information_schema.columns
158
- where table_schema not in('information_schema' 'mysql', 'performance_schema', 'sys')
110
+ #{where_clause}
159
111
  order by table_schema, table_name, column_name, ordinal_position;
160
- SQL
112
+ SQL
161
113
  )
162
114
  column_result.each do |row|
163
- table_schema = row['table_schema']
164
- table_name = row['table_name']
165
- column_name = row['column_name']
166
- next unless result[:schemas][table_schema]
167
- next unless result[:schemas][table_schema][:tables][table_name]
168
-
115
+ row = row.transform_keys(&:downcase).transform_keys(&:to_sym)
116
+ table_schema = row[:table_schema]
117
+ unless result[:schemas][table_schema]
118
+ result[:schemas][table_schema] = {
119
+ tables: {}
120
+ }
121
+ end
122
+ table_name = row[:table_name]
123
+ tables = result[:schemas][table_schema][:tables]
124
+ unless tables[table_name]
125
+ tables[table_name] = {
126
+ indexes: {},
127
+ columns: {}
128
+ }
129
+ end
169
130
  columns = result[:schemas][table_schema][:tables][table_name][:columns]
131
+ column_name = row[:column_name]
170
132
  unless columns[column_name]
171
133
  columns[column_name] = {}
172
134
  end
173
135
  column = columns[column_name]
174
136
  column[:name] = column_name
175
- column[:data_type] = row['data_type']
176
- column[:length] = row['character_maximum_length']
177
- column[:allow_null] = row['is_nullable']
178
- column[:key] = row['column_key']
179
- column[:default] = row['column_default']
180
- column[:extra] = row['extra']
137
+ column[:data_type] = row[:data_type]
138
+ column[:length] = row[:character_maximum_length]
139
+ column[:allow_null] = row[:is_nullable]
140
+ column[:key] = row[:column_key]
141
+ column[:default] = row[:column_default]
142
+ column[:extra] = row[:extra]
143
+ end
144
+
145
+ if @table_schema
146
+ where_clause = "where table_schema = '#{@table_schema}'"
147
+ else
148
+ where_clause = "where table_schema not in('mysql', 'sys', 'information_schema', 'performance_schema')"
149
+ end
150
+ stats_result = @client.query(
151
+ <<~SQL
152
+ select
153
+ table_schema,
154
+ table_name,
155
+ index_name,
156
+ seq_in_index,
157
+ non_unique,
158
+ column_name
159
+ from information_schema.statistics
160
+ #{where_clause}
161
+ order by table_schema, table_name, if(index_name = "PRIMARY", 0, index_name), seq_in_index;
162
+ SQL
163
+ )
164
+ stats_result.each do |row|
165
+ row = row.transform_keys(&:downcase).transform_keys(&:to_sym)
166
+ table_schema = row[:table_schema]
167
+ tables = result[:schemas][table_schema][:tables]
168
+ table_name = row[:table_name]
169
+ indexes = tables[table_name][:indexes]
170
+ index_name = row[:index_name]
171
+ unless indexes[index_name]
172
+ indexes[index_name] = {}
173
+ end
174
+ index = indexes[index_name]
175
+ column_name = row[:column_name]
176
+ index[column_name] = {}
177
+ column = index[column_name]
178
+ column[:name] = index_name
179
+ column[:seq_in_index] = row[:seq_in_index]
180
+ column[:non_unique] = row[:non_unique]
181
+ column[:column_name] = row[:column_name]
181
182
  end
182
183
 
183
184
  result
@@ -0,0 +1,65 @@
1
+ <html>
2
+ <head>
3
+ <title>Databases</title>
4
+
5
+ <style>
6
+ body {
7
+ font-family: Helvetica;
8
+ }
9
+
10
+ h1 {
11
+ font-size: 30px;
12
+ margin-bottom: 30px;
13
+ }
14
+
15
+ .database a {
16
+ margin-right: 10px;
17
+ color: darkblue;
18
+ font-size: 16px;
19
+ }
20
+
21
+ .database h2 {
22
+ margin: 0px;
23
+ margin-top: 10px;
24
+ margin-bottom: 0px;
25
+ font-size: 20px;
26
+ font-weight: bold;
27
+ }
28
+
29
+ .database p {
30
+ margin: 0px;
31
+ margin-top: 10px;
32
+ padding-bottom: 20px;
33
+ font-size: 16px;
34
+ }
35
+
36
+ .database {
37
+ cursor: pointer;
38
+ border-bottom: 1px solid #eeeeee;
39
+ }
40
+
41
+ .database:last-child {
42
+ border-bottom: none;
43
+ }
44
+
45
+ .database:hover {
46
+ background: #eee;
47
+ }
48
+ </style>
49
+ </head>
50
+
51
+ <body>
52
+ <h1>Databases</h1>
53
+ <% databases.values.each do |database| %>
54
+ <div class="database" onclick="window.location='<%= "/db/#{database['url_path']}/app" %>'">
55
+ <h2><%= database['name'] %></h2>
56
+ <a href="/db/<%= database['url_path'] %>/app">query</a>
57
+ <a href="/db/<%= database['url_path'] %>/app?tab=saved">saved</a>
58
+ <a href="/db/<%= database['url_path'] %>/app?tab=structure">structure</a>
59
+ <p>
60
+ <%= database['description'] %>
61
+ </p>
62
+ </div>
63
+ <% end %>
64
+ </body>
65
+ </html>
@@ -0,0 +1,242 @@
1
+ body {
2
+ font-size: 16px;
3
+ margin: 0;
4
+ }
5
+
6
+ .main-box {
7
+ display: flex;
8
+ flex-direction: column;
9
+ flex: 1;
10
+ margin: 0;
11
+ height: 100%;
12
+ min-height: 100%;
13
+ }
14
+
15
+ .header {
16
+ display: flex;
17
+ flex: 1;
18
+ align-items: center;
19
+ justify-content: start;
20
+ padding-left: 5px;
21
+ color: #333;
22
+ font-weight: bold;
23
+ }
24
+
25
+ .tabs-box {
26
+ display: flex;
27
+ flex-direction: row;
28
+ border-bottom: 1px solid #ddd;
29
+ height: 36px;
30
+ font-size: 16px;
31
+ font-family: Helvetica;
32
+ }
33
+
34
+ .tab-button, .selected-tab-button {
35
+ border: none;
36
+ outline: none;
37
+ cursor: pointer;
38
+ width: 150px;
39
+ padding: 2px;
40
+ margin: 0px;
41
+ display: flex;
42
+ justify-content: center;
43
+ background-color: #fff;
44
+ }
45
+
46
+ .tab-button {
47
+ color: #888;
48
+ }
49
+
50
+ .tab-button:hover {
51
+ color: #333;
52
+ }
53
+
54
+ .selected-tab-button {
55
+ color: #333;
56
+ font-weight: bold;
57
+ }
58
+
59
+ .tab-content-element {
60
+ display: none;
61
+ }
62
+
63
+ .query-box {
64
+ display: flex;
65
+ flex-direction: column;
66
+ }
67
+
68
+ .query {
69
+ display: flex;
70
+ flex: 1;
71
+ }
72
+
73
+ .submit-box {
74
+ display: flex;
75
+ border-top: 1px solid #ddd;
76
+ height: 36px;
77
+ justify-content: right;
78
+ }
79
+
80
+ .status {
81
+ display: flex;
82
+ justify-content: center;
83
+ align-content: center;
84
+ flex-direction: column;
85
+ font-family: Helvetica;
86
+ }
87
+
88
+ .result-box, .saved-box, .graph-box, .structure-box {
89
+ flex: 1;
90
+ overflow: auto;
91
+ display: flex;
92
+ flex-direction: column;
93
+ }
94
+
95
+ .graph-box, .result-box {
96
+ border-top: 1px solid #ddd;
97
+ }
98
+
99
+ .graph-box {
100
+ padding: 20px;
101
+ }
102
+
103
+ table {
104
+ font-family: monospace;
105
+ flex: 1;
106
+ border-spacing: 0px;
107
+ display: flex;
108
+ width: 100%;
109
+ }
110
+
111
+ table td:last-child, table th:last-child {
112
+ width: 100%;
113
+ border-right: none !important;
114
+ }
115
+
116
+ td, th {
117
+ padding: 5px 20px 5px 5px;
118
+ font-weight: normal;
119
+ white-space: nowrap;
120
+ max-width: 500px;
121
+ overflow: hidden;
122
+ text-overflow: ellipsis;
123
+ }
124
+
125
+ td {
126
+ text-align: right;
127
+ }
128
+
129
+ th {
130
+ text-align: left;
131
+ font-weight: bold;
132
+ border-bottom: 1px solid #ddd;
133
+ border-right: 1px solid #ddd;
134
+ }
135
+
136
+ table {
137
+ display: block;
138
+ }
139
+
140
+ thead {
141
+ padding: 0px;
142
+ background-color: #fff;
143
+ position: -webkit-sticky;
144
+ position: sticky;
145
+ top: 0px;
146
+ z-index: 100;
147
+ table-layout:fixed;
148
+ }
149
+
150
+ .highlighted-row {
151
+ background: #eee;
152
+ }
153
+
154
+ .status-box {
155
+ padding: 5px;
156
+ display: flex;
157
+ flex-direction: rows;
158
+ justify-content: space-between;
159
+ border-top: 1px solid #ddd;
160
+ height: 30px;
161
+ }
162
+
163
+ .CodeMirror pre.CodeMirror-placeholder {
164
+ color: #999;
165
+ }
166
+
167
+ .tabs-box {
168
+ display: flex;
169
+ }
170
+
171
+ .saved-box {
172
+ font-family: Helvetica;
173
+ }
174
+
175
+ .saved-box h1 {
176
+ margin: 0px;
177
+ padding-left: 10px;
178
+ padding-right: 10px;
179
+ padding-top: 10px;
180
+ padding-bottom: 10px;
181
+ font-size: 16px;
182
+ font-weight: bold;
183
+ }
184
+
185
+ .saved-box div:first-child {
186
+ border-top: none !important;
187
+ }
188
+
189
+ .saved-box p {
190
+ margin: 0px;
191
+ padding-left: 20px;
192
+ padding-bottom: 20px;
193
+ }
194
+
195
+ .saved-box div {
196
+ cursor: pointer;
197
+ border-top: 1px solid #eeeeee;
198
+ }
199
+
200
+ .saved-box div:hover {
201
+ background: #eee;
202
+ }
203
+
204
+ .submit-button {
205
+ cursor: pointer;
206
+ margin-right: 10px;
207
+ }
208
+
209
+ .cm-editor.cm-focused {
210
+ outline: none !important;
211
+ }
212
+
213
+ .schemas, .tables {
214
+ border: none;
215
+ display: flex;
216
+ min-width: 200px;
217
+ }
218
+
219
+ .table-info {
220
+ display: grid;
221
+ grid-template-columns: 1;
222
+ grid-template-rows: 0.5fr 0.5fr;
223
+ justify-items: stretch;
224
+ flex: 1;
225
+ }
226
+
227
+ .columns {
228
+ border-bottom: 1px solid #ddd;
229
+ overflow: auto;
230
+ grid-column: 1;
231
+ grid-row: 1;
232
+ }
233
+
234
+ .indexes {
235
+ overflow: auto;
236
+ grid-column: 1;
237
+ grid-row: 2;
238
+ }
239
+
240
+ select {
241
+ outline: none;
242
+ }
@@ -0,0 +1,60 @@
1
+ <head>
2
+
3
+ <title>SQLUI</title>
4
+
5
+ <script src="sqlui.js"></script>
6
+ <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
7
+ <link rel="stylesheet" href="sqlui.css">
8
+ </head>
9
+
10
+ <body>
11
+ <div class="main-box">
12
+ <div class="tabs-box">
13
+ <div id="header" class="header">SQLUI</div>
14
+ <input id="query-tab-button" class="tab-button" type="button" value="Query" onclick="sqlui.selectTab('query')"></input>
15
+ <input id="graph-tab-button" class="tab-button" type="button" value="Graph" onclick="sqlui.selectTab('graph')"></input>
16
+ <input id="saved-tab-button" class="tab-button" type="button" value="Saved" onclick="sqlui.selectTab('saved')"></input>
17
+ <input id="structure-tab-button" class="tab-button" type="button" value="Structure" onclick="sqlui.selectTab('structure')"></input>
18
+ </div>
19
+
20
+ <div id="query-box" class="query-box tab-content-element graph-element query-element" style="display: none;">
21
+ <div id="query"></div>
22
+ </div>
23
+
24
+ <!--
25
+ <div id="submit-box" class="submit-box tab-content-element graph-element query-element" style="display: none;">
26
+ <input id="submit-button" class="submit-button" type="button" value="submit" onclick="submit();"></input>
27
+ </div>
28
+ -->
29
+
30
+ <div id="result-box" class="result-box tab-content-element query-element" style="display: none;">
31
+ </div>
32
+
33
+ <div id="graph-box" class="graph-box tab-content-element graph-element" style="display: none;">
34
+ </div>
35
+
36
+ <div id="saved-box" class="saved-box tab-content-element saved-element" style="display: none;">
37
+ </div>
38
+
39
+ <div id="structure-box" class="structure-box tab-content-element structure-element" style="display: none;">
40
+ <div style="display: flex; flex: 1; flex-direction: row; align-items: stretch;">
41
+ <select id="schemas" class="schemas" size="4">
42
+ </select>
43
+ <select id="tables" class="tables" size="4">
44
+ </select>
45
+ <div id="table-info" class="table-info">
46
+ <div id="columns" class="columns">
47
+ </div>
48
+ <div id="indexes" class="indexes">
49
+ </div>
50
+ </div>
51
+ </div>
52
+ </div>
53
+
54
+ <div id="status-box" class="status-box">
55
+ <div id="query-status" class="status tab-content-element query-element"></div>
56
+ <div id="graph-status" class="status tab-content-element graph-element"></div>
57
+ <div id="saved-status" class="status tab-content-element saved-element"></div>
58
+ </div>
59
+ </div>
60
+ </body>