sqlui 0.1.55 → 0.1.57

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: 5ac5672ec8d9668ee10c58ccf407a63f297b411ff055cadfc89ce9090369bb2d
4
- data.tar.gz: 146c7af99506528b86b8721db25dfffec71dbb5af32f9ed711a7b7b781ae0dbb
3
+ metadata.gz: be280a4fa679ca8aa39ad6dfd93705c85b87b54993cf4ea601fa6260978ae349
4
+ data.tar.gz: db66920d0dd4c222bc5f4626046d7305be478afb11a816fb5c450a09d97b7f2b
5
5
  SHA512:
6
- metadata.gz: 31d766b04ba02bf3f0bc4d369614b87bc5c527e6f96634d3019875f71cb84d6906aba812d54175ca65782cadee47355df87018c8c190a8cf33fce2a306a32def
7
- data.tar.gz: c05a7fff480f3fe42925a7a07cddebddbff979f74e3bdac898a585439d251c180d682da66a7e6b98d4f0e175def931f03dff23d3d5406fd9c273f1953dcc0d6a
6
+ metadata.gz: 0f436e784f0ac4b187805ed276323a9e712a9f0aee3e5beb504971956abd5588e8e044a9495618e4be82f018b0c20d88f50a37d3d379fc6e2d08e6a962000a43
7
+ data.tar.gz: ed51e6754f145b23d184542bdbc97c76bbcd52d3bc17c0bbebb7c2adb0534486c097e9af379c453b2c16b6b850fbd7252f9b03e43df71962771e1e29f99d9a4a
data/.release-version CHANGED
@@ -1 +1 @@
1
- 0.1.55
1
+ 0.1.57
data/app/server.rb CHANGED
@@ -138,13 +138,13 @@ class Server < Sinatra::Base
138
138
  break client_error('missing sql') unless params[:sql]
139
139
 
140
140
  variables = params[:variables] || {}
141
- sql = find_selected_query(params[:sql], params[:selection])
141
+ queries = find_selected_queries(params[:sql], params[:selection])
142
142
 
143
143
  status 200
144
144
  headers 'Content-Type' => 'application/json; charset=utf-8'
145
145
 
146
146
  database.with_client do |client|
147
- query_result = execute_query(client, variables, sql)
147
+ query_result = execute_query(client, variables, queries)
148
148
  stream do |out|
149
149
  if query_result
150
150
  json = <<~RES.chomp
@@ -159,7 +159,7 @@ class Server < Sinatra::Base
159
159
  out << json
160
160
  bytes = json.bytesize
161
161
  query_result.each_with_index do |row, i|
162
- json = "#{i.zero? ? '' : ','}\n #{row.to_json}"
162
+ json = "#{i.zero? ? '' : ','}\n #{row.map { |v| big_decimal_to_float(v) }.to_json}"
163
163
  bytes += json.bytesize
164
164
  break if i == Sqlui::MAX_ROWS || bytes > Sqlui::MAX_BYTES
165
165
 
@@ -191,7 +191,7 @@ class Server < Sinatra::Base
191
191
 
192
192
  sql = Base64.decode64(params[:sql]).force_encoding('UTF-8')
193
193
  variables = params.map { |k, v| k[0] == '_' ? [k, v] : nil }.compact.to_h
194
- sql = find_selected_query(sql, params[:selection])
194
+ queries = find_selected_queries(sql, params[:selection])
195
195
 
196
196
  content_type 'application/csv; charset=utf-8'
197
197
  headers 'Cache-Control' => 'no-cache'
@@ -199,11 +199,11 @@ class Server < Sinatra::Base
199
199
  status 200
200
200
 
201
201
  database.with_client do |client|
202
- query_result = execute_query(client, variables, sql)
202
+ query_result = execute_query(client, variables, queries)
203
203
  stream do |out|
204
204
  out << CSV::Row.new(query_result.fields, query_result.fields, header_row: true).to_s.strip
205
205
  query_result.each do |row|
206
- out << "\n#{CSV::Row.new(query_result.fields, row).to_s.strip}"
206
+ out << "\n#{CSV::Row.new(query_result.fields, row.map { |v| big_decimal_to_float(v) }).to_s.strip}"
207
207
  end
208
208
  end
209
209
  end
@@ -250,33 +250,45 @@ class Server < Sinatra::Base
250
250
  body({ error: message, stacktrace: stacktrace }.compact.to_json)
251
251
  end
252
252
 
253
- def find_selected_query(full_sql, selection)
254
- return full_sql unless selection
255
-
256
- if selection.include?('-')
257
- # sort because the selection could be in either direction
258
- selection = selection.split('-').map { |v| Integer(v) }.sort
259
- else
260
- selection = Integer(selection)
261
- selection = [selection, selection]
262
- end
253
+ def find_selected_queries(full_sql, selection)
254
+ if selection
255
+ if selection.include?('-')
256
+ # sort because the selection could be in either direction
257
+ selection = selection.split('-').map { |v| Integer(v) }.sort
258
+ else
259
+ selection = Integer(selection)
260
+ selection = [selection, selection]
261
+ end
263
262
 
264
- if selection[0] == selection[1]
265
- SqlParser.find_statement_at_cursor(full_sql, selection[0])
263
+ if selection[0] == selection[1]
264
+ [SqlParser.find_statement_at_cursor(full_sql, selection[0])]
265
+ else
266
+ SqlParser.split(full_sql[selection[0], selection[1]])
267
+ end
266
268
  else
267
- full_sql[selection[0], selection[1]]
269
+ SqlParser.split(full_sql)
268
270
  end
269
271
  end
270
272
 
271
- def execute_query(client, variables, sql)
273
+ def execute_query(client, variables, queries)
272
274
  variables.each do |name, value|
273
275
  client.query("SET @#{name} = #{value};")
274
276
  end
275
- queries = if sql.include?(';')
276
- sql.split(/(?<=;)/).map(&:strip).reject(&:empty?)
277
- else
278
- [sql]
279
- end
280
277
  queries.map { |current| client.query(current) }.last
281
278
  end
279
+
280
+ def big_decimal_to_float(maybe_big_decimal)
281
+ # TODO: This BigDecimal thing needs some thought.
282
+ if maybe_big_decimal.is_a?(BigDecimal)
283
+ big_decimal_string = maybe_big_decimal.to_s('F')
284
+ float = maybe_big_decimal.to_f
285
+ if big_decimal_string == float.to_s
286
+ float
287
+ else
288
+ big_decimal_string
289
+ end
290
+ else
291
+ maybe_big_decimal
292
+ end
293
+ end
282
294
  end
data/app/sql_parser.rb CHANGED
@@ -12,6 +12,10 @@ class SqlParser
12
12
  part_with_range[0]
13
13
  end
14
14
 
15
+ def self.split(sql)
16
+ parse(sql).map(&:first)
17
+ end
18
+
15
19
  def self.parse(sql)
16
20
  scanner = StringScanner.new(sql)
17
21
  statements = []
data/app/sqlui.rb CHANGED
@@ -6,8 +6,8 @@ require_relative 'version'
6
6
 
7
7
  # Main entry point.
8
8
  class Sqlui
9
- MAX_ROWS = 5_000
10
- MAX_BYTES = 10 * 1_024 * 1_024
9
+ MAX_ROWS = 50_000
10
+ MAX_BYTES = 10 * 1_024 * 1_024 # 10 MB
11
11
 
12
12
  def initialize(config_file)
13
13
  raise 'you must specify a configuration file' unless config_file
data/app/views/sqlui.erb CHANGED
@@ -100,8 +100,10 @@
100
100
  <div style="flex: 1;"></div>
101
101
  <div id="pagination-box" class="tab-content-element">
102
102
  <div id="page-count-box"></div>
103
+ <input id="first-button" class="pagination-button" type="button" value="First" />
103
104
  <input id="prev-button" class="pagination-button" type="button" value="Prev" />
104
105
  <input id="next-button" class="pagination-button" type="button" value="Next" />
106
+ <input id="last-button" class="pagination-button" type="button" value="Last" />
105
107
  </div>
106
108
  </div>
107
109
  </div>
@@ -282,8 +282,6 @@ table {
282
282
  border-spacing: 0;
283
283
  color: #333;
284
284
  font-size: 18px;
285
- width: 100%;
286
- table-layout: auto; /* Will be overridden if a column is resized. */
287
285
  }
288
286
 
289
287
  table td:last-child, table th:last-child {
@@ -296,6 +294,10 @@ td, th {
296
294
  max-width: 500px;
297
295
  }
298
296
 
297
+ td:last-child, th:last-child {
298
+ max-width: none;
299
+ }
300
+
299
301
  td {
300
302
  overflow: hidden;
301
303
  text-overflow: ellipsis;
@@ -491,15 +493,8 @@ select {
491
493
  font-size: 16px;
492
494
  }
493
495
 
494
- #next-button {
495
-
496
- }
497
-
498
- #prev-button {
499
- margin: 0 10px;
500
- }
501
-
502
496
  .pagination-button {
497
+ margin: 0 10px;
503
498
  cursor: pointer;
504
499
  background: none;
505
500
  color: #333;
@@ -24295,180 +24295,215 @@
24295
24295
  return match ? match[1] : identifier
24296
24296
  }
24297
24297
 
24298
- const drag = {
24299
- containerElement: null,
24300
- tableElement: null,
24301
- thElement: null,
24302
- colElement: null,
24303
- otherColWidths: null,
24304
- lastColElement: null
24305
- };
24298
+ class Drag {
24299
+ tableElement = null
24300
+ scrolled = null
24301
+ scrollOffset = null
24302
+ containerOffset = null
24303
+ containerWidth = null
24304
+ thElement = null
24305
+ colElement = null
24306
+ otherColsWidth = null
24307
+ lastColElement = null
24308
+ }
24309
+
24310
+ let drag = new Drag();
24306
24311
 
24307
24312
  document.addEventListener('mousedown', (event) => {
24308
- if (event.target.classList.contains('col-resizer')) {
24309
- event.preventDefault();
24310
- const thElement = event.target.parentElement.parentElement;
24311
- if (thElement.tagName.toLowerCase() !== 'th') {
24312
- throw new Error(`expected th element, found: ${thElement}`)
24313
- }
24314
- const trElement = thElement.parentElement;
24315
- const theadElement = trElement.parentElement;
24316
- drag.tableElement = theadElement.parentElement;
24317
- drag.containerElement = drag.tableElement.parentElement;
24318
- drag.thElement = thElement;
24319
- drag.colElement = document.getElementById(event.target.dataset.colId);
24320
-
24321
- const colElements = Array.from(drag.colElement.parentElement.childNodes);
24322
- drag.lastColElement = colElements[colElements.length - 1];
24323
- drag.otherColWidths = [];
24324
- for (let i = 0; i < colElements.length - 1; i++) {
24325
- if (colElements[i] !== drag.colElement) {
24326
- drag.otherColWidths.push(colElements[i].getBoundingClientRect().width);
24327
- }
24328
- }
24329
- colElements.forEach((element) => {
24330
- element.style.width = `${element.getBoundingClientRect().width}px`;
24331
- });
24332
- drag.tableElement.style.tableLayout = 'fixed';
24313
+ if (!event.target.classList.contains('col-resizer')) return
24314
+
24315
+ drag = new Drag();
24316
+ event.preventDefault();
24317
+ const thElement = event.target.parentElement.parentElement;
24318
+ if (thElement.tagName.toLowerCase() !== 'th') {
24319
+ throw new Error(`expected th element, found: ${thElement}`)
24333
24320
  }
24321
+ const trElement = thElement.parentElement;
24322
+ const theadElement = trElement.parentElement;
24323
+ const tableElement = theadElement.parentElement;
24324
+ const containerElement = tableElement.parentElement;
24325
+ drag.tableElement = tableElement;
24326
+ drag.containerWidth = containerElement.clientWidth;
24327
+ drag.scrollOffset = containerElement.scrollLeft;
24328
+ drag.scrolled = drag.scrollOffset > 0;
24329
+ drag.containerOffset = containerElement.offsetLeft;
24330
+ drag.thElement = thElement;
24331
+ drag.colElement = tableElement.querySelector(`col[data-col-id=${event.target.dataset.colId}]`);
24332
+
24333
+ const colElements = Array.from(drag.colElement.parentElement.childNodes);
24334
+ drag.lastColElement = colElements[colElements.length - 1];
24335
+ drag.otherColsWidth = 0;
24336
+ for (let i = 0; i < colElements.length; i++) {
24337
+ if (colElements[i] !== drag.colElement && i !== (colElements.length - 1)) {
24338
+ drag.otherColsWidth += colElements[i].getBoundingClientRect().width;
24339
+ }
24340
+ colElements[i].style.width = `${colElements[i].getBoundingClientRect().width}px`;
24341
+ }
24342
+ tableElement.style.tableLayout = 'fixed';
24343
+ tableElement.style.width = `${tableElement.getBoundingClientRect().width}px`;
24334
24344
  });
24335
24345
 
24336
24346
  document.addEventListener('mouseup', (event) => {
24337
- drag.containerElement = null;
24338
- drag.tableElement = null;
24339
- drag.thElement = null;
24340
- drag.colElement = null;
24341
- drag.otherColWidths = null;
24342
- drag.lastColElement = null;
24347
+ drag = new Drag();
24343
24348
  });
24344
24349
 
24345
24350
  document.addEventListener('mousemove', (event) => {
24346
- if (drag.colElement) {
24347
- const scrollOffset = drag.containerElement.scrollLeft;
24348
- const scrolled = scrollOffset > 0;
24349
- const containerOffset = drag.containerElement.offsetLeft;
24350
- const newColumnWidth = Math.max(0, scrollOffset + (event.clientX - containerOffset) - drag.thElement.offsetLeft);
24351
- if (newColumnWidth < drag.colElement.getBoundingClientRect().width && newColumnWidth < 30) return
24352
-
24353
- drag.colElement.style.width = `${newColumnWidth}px`;
24354
- let runningWidth = newColumnWidth;
24355
- drag.otherColWidths.forEach((width) => {
24356
- runningWidth += width;
24357
- });
24358
- let remainingWidth;
24359
- if (scrolled) {
24360
- remainingWidth = (scrollOffset + drag.containerElement.clientWidth) - runningWidth;
24361
- } else {
24362
- remainingWidth = Math.max(10, drag.containerElement.clientWidth - runningWidth);
24363
- }
24364
- drag.lastColElement.style.width = `${remainingWidth}px`;
24365
- runningWidth += remainingWidth;
24366
- drag.tableElement.style.width = `${runningWidth}px`;
24351
+ if (!drag.colElement) return
24352
+
24353
+ const newColumnWidth = Math.max(0, drag.scrollOffset + (event.clientX - drag.containerOffset) - drag.thElement.offsetLeft);
24354
+ if (newColumnWidth < drag.colElement.getBoundingClientRect().width && newColumnWidth < 30) return
24355
+
24356
+ drag.colElement.style.width = `${newColumnWidth}px`;
24357
+ drag.tableElement.columnsWidth = newColumnWidth + drag.otherColsWidth;
24358
+ let lastColWidth;
24359
+ if (drag.scrolled) {
24360
+ lastColWidth = (drag.scrollOffset + drag.containerWidth) - (drag.tableElement.columnsWidth);
24361
+ } else {
24362
+ lastColWidth = Math.max(10, drag.containerWidth - (drag.tableElement.columnsWidth));
24367
24363
  }
24364
+ drag.lastColElement.style.width = lastColWidth + 'px';
24365
+ drag.tableElement.style.width = (drag.otherColsWidth + newColumnWidth + lastColWidth) + 'px';
24368
24366
  });
24369
24367
 
24370
- function createTable (containerElement, columns, rows, id, cellRenderer) {
24371
- if (!containerElement) throw new Error('missing table containerElement')
24372
- if (!columns) throw new Error('missing table columns')
24373
- if (!rows) throw new Error('missing table rows')
24374
- if (!id) throw new Error('missing table id')
24368
+ class ResizeTable extends HTMLTableElement {
24369
+ constructor (columns, rows, cellRenderer) {
24370
+ super();
24375
24371
 
24376
- const tableElement = document.createElement('table');
24377
- containerElement.appendChild(tableElement);
24378
- if (id) tableElement.id = id;
24372
+ this.columns = columns;
24373
+ this.cellRenderer = cellRenderer;
24379
24374
 
24380
- const colgroupElement = document.createElement('colgroup');
24381
- tableElement.appendChild(colgroupElement);
24375
+ this.style.tableLayout = 'auto';
24376
+ this.style.width = '100%';
24382
24377
 
24383
- const theadElement = document.createElement('thead');
24384
- tableElement.appendChild(theadElement);
24378
+ const colgroupElement = document.createElement('colgroup');
24379
+ this.appendChild(colgroupElement);
24385
24380
 
24386
- const headerTrElement = document.createElement('tr');
24387
- theadElement.appendChild(headerTrElement);
24381
+ const theadElement = document.createElement('thead');
24382
+ this.appendChild(theadElement);
24388
24383
 
24389
- const nonLastColElements = [];
24390
- columns.forEach(function (column, index) {
24391
- const headerElement = document.createElement('th');
24392
- headerTrElement.appendChild(headerElement);
24384
+ const headerTrElement = document.createElement('tr');
24385
+ theadElement.appendChild(headerTrElement);
24393
24386
 
24394
- const contentWrapperElement = document.createElement('div');
24395
- contentWrapperElement.classList.add('col-content-wrapper');
24396
- headerElement.appendChild(contentWrapperElement);
24387
+ if (columns.length > 0) {
24388
+ const colElements = [];
24389
+ columns.forEach(function (column, index) {
24390
+ const headerElement = document.createElement('th');
24391
+ headerTrElement.appendChild(headerElement);
24397
24392
 
24398
- const nameElement = document.createElement('div');
24399
- nameElement.classList.add('col-name');
24400
- contentWrapperElement.appendChild(nameElement);
24393
+ const contentWrapperElement = document.createElement('div');
24394
+ contentWrapperElement.classList.add('col-content-wrapper');
24395
+ headerElement.appendChild(contentWrapperElement);
24401
24396
 
24402
- const colElement = document.createElement('col');
24403
- colElement.id = `${id}-col-${index}`;
24404
- colgroupElement.appendChild(colElement);
24405
- nonLastColElements.push(colElement);
24397
+ const nameElement = document.createElement('div');
24398
+ nameElement.classList.add('col-name');
24399
+ contentWrapperElement.appendChild(nameElement);
24406
24400
 
24407
- const resizerElement = document.createElement('div');
24408
- resizerElement.classList.add('col-resizer');
24409
- resizerElement.dataset.colId = colElement.id;
24410
- contentWrapperElement.appendChild(resizerElement);
24401
+ const colElement = document.createElement('col');
24402
+ colElement.dataset.colId = `col-${index}`;
24403
+ colgroupElement.appendChild(colElement);
24404
+ colElements.push(colElement);
24411
24405
 
24412
- nameElement.innerText = column;
24413
- });
24414
- if (columns.length > 0) {
24415
- headerTrElement.appendChild(document.createElement('th'));
24416
- const lastColElement = document.createElement('col');
24417
- lastColElement.style.width = '100%';
24418
- function resize () {
24419
- let runningWidth = 0;
24420
- const colElements = Array.from(tableElement.getElementsByTagName('col'));
24421
- nonLastColElements.forEach((element, index) => {
24422
- runningWidth += element.getBoundingClientRect().width;
24406
+ const resizerElement = document.createElement('div');
24407
+ resizerElement.classList.add('col-resizer');
24408
+ resizerElement.dataset.colId = colElement.dataset.colId;
24409
+ contentWrapperElement.appendChild(resizerElement);
24410
+
24411
+ nameElement.innerText = column;
24423
24412
  });
24424
- const remainingWidth = Math.max(10, containerElement.clientWidth - runningWidth);
24425
- colElements[colElements.length - 1].style.width = `${remainingWidth}px`;
24426
- runningWidth += remainingWidth;
24427
- tableElement.style.width = `${runningWidth}px`;
24428
- }
24429
24413
 
24430
- const resizeObserver = new ResizeObserver(resize);
24431
- resizeObserver.observe(containerElement);
24414
+ headerTrElement.appendChild(document.createElement('th'));
24415
+ const lastColElement = document.createElement('col');
24416
+ lastColElement.style.width = '100%';
24417
+ colElements.push(lastColElement);
24432
24418
 
24433
- const mutationObserver = new MutationObserver((mutationList, observer) => {
24434
- if (!tableElement.parentElement) {
24435
- resizeObserver.unobserve(containerElement);
24436
- resizeObserver.unobserve(containerElement);
24437
- observer.disconnect();
24438
- }
24439
- });
24440
- mutationObserver.observe(containerElement, { childList: true });
24441
- colgroupElement.appendChild(lastColElement);
24419
+ const containerMutationObserver = new MutationObserver(function (mutationList, observer) {
24420
+ mutationList.forEach(function (mutation) {
24421
+ if (this.parentElement) {
24422
+ if (this.parentElement !== mutation.target) {
24423
+ throw new Error('Unexpected table parent')
24424
+ }
24425
+ return
24426
+ }
24442
24427
 
24443
- createTableBody(rows, tableElement, cellRenderer);
24444
- }
24445
- }
24428
+ if (observer.resizeObserver) {
24429
+ observer.resizeObserver.unobserve(mutation.target);
24430
+ observer.resizeObserver = null;
24431
+ }
24432
+ observer.disconnect();
24433
+ }.bind(this));
24434
+ }.bind(this));
24446
24435
 
24447
- function createTableBody (rows, tableElement, cellRenderer) {
24448
- const tbodyElement = document.createElement('tbody');
24449
- tableElement.appendChild(tbodyElement);
24436
+ const tableResizeObserver = new ResizeObserver(function () {
24437
+ if (!this.parentElement) {
24438
+ this.observingContainer = false;
24439
+ return
24440
+ }
24441
+ if (this.observingContainer) {
24442
+ return
24443
+ }
24444
+ this.observingContainer = true;
24450
24445
 
24451
- let highlight = false;
24452
- rows.forEach(function (row) {
24453
- const rowElement = document.createElement('tr');
24454
- if (highlight) {
24455
- rowElement.classList.add('highlighted-row');
24446
+ const containerResizeObserver = new ResizeObserver(function () {
24447
+ if (this.style.tableLayout === 'auto') return
24448
+ if (this.parentElement.scrollLeft > 0) return
24449
+ if (!this.columnsWidth) throw new Error('columnsWidth not set')
24450
+
24451
+ const remainingWidth = Math.max(10, this.parentElement.clientWidth - this.columnsWidth);
24452
+ colElements.slice(-1)[0].style.width = `${remainingWidth}px`;
24453
+ this.style.width = `${this.columnsWidth + remainingWidth}px`;
24454
+ }.bind(this));
24455
+ containerResizeObserver.observe(this.parentElement);
24456
+
24457
+ containerMutationObserver.resizeObserver = containerResizeObserver;
24458
+ containerMutationObserver.containerElement = this.parentElement;
24459
+ console.log('observing');
24460
+ console.log(this.parentElement);
24461
+ containerMutationObserver.observe(this.parentElement, { childList: true });
24462
+ }.bind(this));
24463
+ tableResizeObserver.observe(this);
24464
+
24465
+ colgroupElement.appendChild(lastColElement);
24466
+
24467
+ this.updateTableBody(rows, cellRenderer);
24456
24468
  }
24457
- highlight = !highlight;
24458
- tbodyElement.appendChild(rowElement);
24459
- row.forEach(function (value, index) {
24460
- if (cellRenderer) {
24461
- cellRenderer(rowElement, index, value);
24462
- } else {
24463
- const cellElement = document.createElement('td');
24464
- cellElement.innerText = value;
24465
- rowElement.appendChild(cellElement);
24469
+ }
24470
+
24471
+ updateTableBody (rows, cellRenderer) {
24472
+ this.style.tableLayout = 'auto';
24473
+
24474
+ if (this.tbodyElement) this.removeChild(this.tbodyElement);
24475
+ const tbodyElement = document.createElement('tbody');
24476
+ this.appendChild(tbodyElement);
24477
+ this.tbodyElement = tbodyElement;
24478
+
24479
+ let highlight = false;
24480
+ rows.forEach(function (row) {
24481
+ const rowElement = document.createElement('tr');
24482
+ if (highlight) {
24483
+ rowElement.classList.add('highlighted-row');
24466
24484
  }
24485
+ highlight = !highlight;
24486
+ tbodyElement.appendChild(rowElement);
24487
+ row.forEach(function (value, index) {
24488
+ if (cellRenderer) {
24489
+ cellRenderer(rowElement, index, value);
24490
+ } else {
24491
+ const cellElement = document.createElement('td');
24492
+ cellElement.innerText = value;
24493
+ rowElement.appendChild(cellElement);
24494
+ }
24495
+ });
24496
+ rowElement.appendChild(document.createElement('td'));
24467
24497
  });
24468
- rowElement.appendChild(document.createElement('td'));
24469
- });
24498
+ }
24499
+
24500
+ getTableBody () {
24501
+ return this.tbodyElement
24502
+ }
24470
24503
  }
24471
24504
 
24505
+ customElements.define('resize-table', ResizeTable, { extends: 'table' });
24506
+
24472
24507
  /* global google */
24473
24508
 
24474
24509
  const PAGE_SIZE = 500;
@@ -24538,6 +24573,10 @@
24538
24573
  copyTextToClipboard(toTsv(window.sqlFetch.result.columns, window.sqlFetch.result.rows));
24539
24574
  }
24540
24575
  });
24576
+ addClickListener(document.getElementById('first-button'), (event) => {
24577
+ window.sqlFetch.page = 0;
24578
+ displaySqlFetch(window.sqlFetch);
24579
+ });
24541
24580
  addClickListener(document.getElementById('prev-button'), (event) => {
24542
24581
  window.sqlFetch.page -= 1;
24543
24582
  displaySqlFetch(window.sqlFetch);
@@ -24546,6 +24585,10 @@
24546
24585
  window.sqlFetch.page += 1;
24547
24586
  displaySqlFetch(window.sqlFetch);
24548
24587
  });
24588
+ addClickListener(document.getElementById('last-button'), (event) => {
24589
+ window.sqlFetch.page = window.sqlFetch.pageCount - 1;
24590
+ displaySqlFetch(window.sqlFetch);
24591
+ });
24549
24592
  addClickListener(document.getElementById('submit-dropdown-button-download-csv'), () => {
24550
24593
  if (!window.sqlFetch?.result) return
24551
24594
 
@@ -24694,6 +24737,8 @@
24694
24737
  selected.style.display = 'none';
24695
24738
  });
24696
24739
 
24740
+ setStatus('');
24741
+
24697
24742
  switch (window.tab) {
24698
24743
  case 'query':
24699
24744
  selectResultTab(internal);
@@ -24799,7 +24844,7 @@
24799
24844
  cellElement.innerText = value;
24800
24845
  rowElement.appendChild(cellElement);
24801
24846
  };
24802
- createTable(columnsElement, columns, rows, 'columns-table', cellRenderer);
24847
+ columnsElement.appendChild(new ResizeTable(columns, rows, cellRenderer));
24803
24848
  }
24804
24849
 
24805
24850
  const indexEntries = Object.entries(table.indexes);
@@ -24825,7 +24870,7 @@
24825
24870
  cellElement.innerText = value;
24826
24871
  rowElement.appendChild(cellElement);
24827
24872
  };
24828
- createTable(indexesElement, columns, rows, 'tables-table', cellRenderer);
24873
+ indexesElement.appendChild(new ResizeTable(columns, rows, cellRenderer));
24829
24874
  }
24830
24875
  });
24831
24876
  window.structureLoaded = true;
@@ -25274,28 +25319,25 @@
25274
25319
 
25275
25320
  displaySqlFetchResultStatus(fetch);
25276
25321
 
25277
- const resultBody = document.querySelector('table[id="result-table"] > tbody');
25278
25322
  const pageStart = fetch.page * fetch.pageSize;
25279
25323
  const rows = fetch.result.rows.slice(pageStart, pageStart + fetch.pageSize);
25280
- if (resultBody) {
25324
+
25325
+ let tableElement = document.getElementById('result-table');
25326
+ if (tableElement) {
25327
+ const resultBody = tableElement.getTableBody();
25281
25328
  if (resultBody.dataset.page === fetch.page) {
25282
25329
  // Results already displayed.
25283
25330
  return
25284
25331
  }
25285
- resultBody.parentElement.removeChild(resultBody);
25286
- createTableBody(rows, document.getElementById('result-table'), resultCellRenderer);
25332
+ tableElement.updateTableBody(rows, resultCellRenderer);
25287
25333
  } else {
25288
25334
  clearResultBox();
25289
- createTable(
25290
- document.getElementById('result-box'),
25291
- fetch.result.columns,
25292
- rows,
25293
- 'result-table',
25294
- resultCellRenderer);
25335
+ const resultBoxElement = document.getElementById('result-box');
25336
+ tableElement = new ResizeTable(fetch.result.columns, rows, resultCellRenderer);
25337
+ tableElement.id = 'result-table';
25338
+ resultBoxElement.appendChild(tableElement);
25295
25339
  }
25296
- document
25297
- .querySelector('table[id="result-table"] > tbody')
25298
- .setAttribute('data-page', fetch.page);
25340
+ tableElement.setAttribute('data-page', fetch.page);
25299
25341
  }
25300
25342
 
25301
25343
  function disableDownloadButtons () {
@@ -25451,7 +25493,7 @@
25451
25493
  }
25452
25494
 
25453
25495
  if (result.total_rows > result.rows.length) {
25454
- message += ` (truncated to ${result.rows.length})`;
25496
+ message += ` (truncated to ${result.rows.length.toLocaleString()})`;
25455
25497
  }
25456
25498
  setStatus(message);
25457
25499
 
@@ -25463,6 +25505,16 @@
25463
25505
  document.getElementById('next-button').disabled = sqlFetch.page + 1 === sqlFetch.pageCount;
25464
25506
  document.getElementById('prev-button').disabled = sqlFetch.page === 0;
25465
25507
  }
25508
+
25509
+ if (sqlFetch.pageCount > 2) {
25510
+ document.getElementById('first-button').style.display = 'flex';
25511
+ document.getElementById('last-button').style.display = 'flex';
25512
+ document.getElementById('first-button').disabled = sqlFetch.page === 0;
25513
+ document.getElementById('last-button').disabled = sqlFetch.page === sqlFetch.pageCount - 1;
25514
+ } else {
25515
+ document.getElementById('last-button').style.display = 'none';
25516
+ document.getElementById('first-button').style.display = 'none';
25517
+ }
25466
25518
  }
25467
25519
 
25468
25520
  window.addEventListener('popstate', function (event) {
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sqlui
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.55
4
+ version: 0.1.57
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick Dower
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-12-09 00:00:00.000000000 Z
11
+ date: 2022-12-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: airbrake