sqlui 0.1.55 → 0.1.57

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