sqlui 0.1.56 → 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: 54098affe9aed43da3e5cfb8ac348989f4965f790ecdfec200ec9e79d3b7b532
4
- data.tar.gz: cd5b2dea4f9f7afc1a465e6c6d68f8e84982547032e90fd5f979c4f6f72eb452
3
+ metadata.gz: be280a4fa679ca8aa39ad6dfd93705c85b87b54993cf4ea601fa6260978ae349
4
+ data.tar.gz: db66920d0dd4c222bc5f4626046d7305be478afb11a816fb5c450a09d97b7f2b
5
5
  SHA512:
6
- metadata.gz: 9444bf4a2cb0bb5d9f397d2ed6ad0ef212846db09172314083f7f951f3a1e58ec9965f1b6f08432ce74739cdf7e35b7d112b4ba0a4c9a5c62abdb7763e8c371a
7
- data.tar.gz: c37479f67876f510a7a6c65c72bf4abbb7c0eeb7bd3b82fc6f0571f91a369685db75b177b50db7b95a533254c40a769248b588d79b41cd79fd475a26d6999c14
6
+ metadata.gz: 0f436e784f0ac4b187805ed276323a9e712a9f0aee3e5beb504971956abd5588e8e044a9495618e4be82f018b0c20d88f50a37d3d379fc6e2d08e6a962000a43
7
+ data.tar.gz: ed51e6754f145b23d184542bdbc97c76bbcd52d3bc17c0bbebb7c2adb0534486c097e9af379c453b2c16b6b850fbd7252f9b03e43df71962771e1e29f99d9a4a
data/.release-version CHANGED
@@ -1 +1 @@
1
- 0.1.56
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,7 +282,6 @@ table {
282
282
  border-spacing: 0;
283
283
  color: #333;
284
284
  font-size: 18px;
285
- width: 100%;
286
285
  }
287
286
 
288
287
  table td:last-child, table th:last-child {
@@ -295,6 +294,10 @@ td, th {
295
294
  max-width: 500px;
296
295
  }
297
296
 
297
+ td:last-child, th:last-child {
298
+ max-width: none;
299
+ }
300
+
298
301
  td {
299
302
  overflow: hidden;
300
303
  text-overflow: ellipsis;
@@ -490,15 +493,8 @@ select {
490
493
  font-size: 16px;
491
494
  }
492
495
 
493
- #next-button {
494
-
495
- }
496
-
497
- #prev-button {
498
- margin: 0 10px;
499
- }
500
-
501
496
  .pagination-button {
497
+ margin: 0 10px;
502
498
  cursor: pointer;
503
499
  background: none;
504
500
  color: #333;
@@ -24296,48 +24296,51 @@
24296
24296
  }
24297
24297
 
24298
24298
  class Drag {
24299
+ tableElement = null
24299
24300
  scrolled = null
24300
24301
  scrollOffset = null
24301
24302
  containerOffset = null
24302
24303
  containerWidth = null
24303
24304
  thElement = null
24304
24305
  colElement = null
24305
- otherColWidths = null
24306
+ otherColsWidth = null
24306
24307
  lastColElement = null
24307
24308
  }
24308
24309
 
24309
24310
  let drag = new Drag();
24310
24311
 
24311
24312
  document.addEventListener('mousedown', (event) => {
24312
- if (event.target.classList.contains('col-resizer')) {
24313
- drag = new Drag();
24314
- event.preventDefault();
24315
- const thElement = event.target.parentElement.parentElement;
24316
- if (thElement.tagName.toLowerCase() !== 'th') {
24317
- throw new Error(`expected th element, found: ${thElement}`)
24318
- }
24319
- const trElement = thElement.parentElement;
24320
- const theadElement = trElement.parentElement;
24321
- const tableElement = theadElement.parentElement;
24322
- const containerElement = tableElement.parentElement;
24323
- drag.containerWidth = containerElement.clientWidth;
24324
- drag.scrollOffset = containerElement.scrollLeft;
24325
- drag.scrolled = drag.scrollOffset > 0;
24326
- drag.containerOffset = containerElement.offsetLeft;
24327
- drag.thElement = thElement;
24328
- drag.colElement = document.getElementById(event.target.dataset.colId);
24329
-
24330
- const colElements = Array.from(drag.colElement.parentElement.childNodes);
24331
- drag.lastColElement = colElements[colElements.length - 1];
24332
- drag.otherColsWidth = 0;
24333
- for (let i = 0; i < colElements.length - 1; i++) {
24334
- if (colElements[i] !== drag.colElement) {
24335
- drag.otherColsWidth += colElements[i].getBoundingClientRect().width;
24336
- }
24337
- colElements[i].style.width = `${colElements[i].getBoundingClientRect().width}px`;
24338
- }
24339
- 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}`)
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`;
24340
24341
  }
24342
+ tableElement.style.tableLayout = 'fixed';
24343
+ tableElement.style.width = `${tableElement.getBoundingClientRect().width}px`;
24341
24344
  });
24342
24345
 
24343
24346
  document.addEventListener('mouseup', (event) => {
@@ -24351,134 +24354,156 @@
24351
24354
  if (newColumnWidth < drag.colElement.getBoundingClientRect().width && newColumnWidth < 30) return
24352
24355
 
24353
24356
  drag.colElement.style.width = `${newColumnWidth}px`;
24357
+ drag.tableElement.columnsWidth = newColumnWidth + drag.otherColsWidth;
24358
+ let lastColWidth;
24354
24359
  if (drag.scrolled) {
24355
- drag.lastColElement.style.width = ((drag.scrollOffset + drag.containerWidth) - (newColumnWidth + drag.otherColsWidth)) + 'px';
24360
+ lastColWidth = (drag.scrollOffset + drag.containerWidth) - (drag.tableElement.columnsWidth);
24356
24361
  } else {
24357
- drag.lastColElement.style.width = (Math.max(10, drag.containerWidth - (newColumnWidth + drag.otherColsWidth))) + 'px';
24362
+ lastColWidth = Math.max(10, drag.containerWidth - (drag.tableElement.columnsWidth));
24358
24363
  }
24364
+ drag.lastColElement.style.width = lastColWidth + 'px';
24365
+ drag.tableElement.style.width = (drag.otherColsWidth + newColumnWidth + lastColWidth) + 'px';
24359
24366
  });
24360
24367
 
24361
- function createTable (containerElement, columns, rows, id, cellRenderer) {
24362
- if (!containerElement) throw new Error('missing table containerElement')
24363
- if (!columns) throw new Error('missing table columns')
24364
- if (!rows) throw new Error('missing table rows')
24365
- if (!id) throw new Error('missing table id')
24368
+ class ResizeTable extends HTMLTableElement {
24369
+ constructor (columns, rows, cellRenderer) {
24370
+ super();
24366
24371
 
24367
- const tableElement = document.createElement('table');
24368
- containerElement.appendChild(tableElement);
24369
- if (id) tableElement.id = id;
24370
- tableElement.style.tableLayout = 'auto';
24372
+ this.columns = columns;
24373
+ this.cellRenderer = cellRenderer;
24371
24374
 
24372
- const colgroupElement = document.createElement('colgroup');
24373
- tableElement.appendChild(colgroupElement);
24375
+ this.style.tableLayout = 'auto';
24376
+ this.style.width = '100%';
24374
24377
 
24375
- const theadElement = document.createElement('thead');
24376
- tableElement.appendChild(theadElement);
24378
+ const colgroupElement = document.createElement('colgroup');
24379
+ this.appendChild(colgroupElement);
24377
24380
 
24378
- const headerTrElement = document.createElement('tr');
24379
- theadElement.appendChild(headerTrElement);
24381
+ const theadElement = document.createElement('thead');
24382
+ this.appendChild(theadElement);
24380
24383
 
24381
- if (columns.length > 0) {
24382
- const colElements = [];
24383
- columns.forEach(function (column, index) {
24384
- const headerElement = document.createElement('th');
24385
- headerTrElement.appendChild(headerElement);
24384
+ const headerTrElement = document.createElement('tr');
24385
+ theadElement.appendChild(headerTrElement);
24386
24386
 
24387
- const contentWrapperElement = document.createElement('div');
24388
- contentWrapperElement.classList.add('col-content-wrapper');
24389
- 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);
24390
24392
 
24391
- const nameElement = document.createElement('div');
24392
- nameElement.classList.add('col-name');
24393
- contentWrapperElement.appendChild(nameElement);
24393
+ const contentWrapperElement = document.createElement('div');
24394
+ contentWrapperElement.classList.add('col-content-wrapper');
24395
+ headerElement.appendChild(contentWrapperElement);
24394
24396
 
24395
- const colElement = document.createElement('col');
24396
- colElement.id = `${id}-col-${index}`;
24397
- colgroupElement.appendChild(colElement);
24398
- colElements.push(colElement);
24397
+ const nameElement = document.createElement('div');
24398
+ nameElement.classList.add('col-name');
24399
+ contentWrapperElement.appendChild(nameElement);
24399
24400
 
24400
- const resizerElement = document.createElement('div');
24401
- resizerElement.classList.add('col-resizer');
24402
- resizerElement.dataset.colId = colElement.id;
24403
- contentWrapperElement.appendChild(resizerElement);
24401
+ const colElement = document.createElement('col');
24402
+ colElement.dataset.colId = `col-${index}`;
24403
+ colgroupElement.appendChild(colElement);
24404
+ colElements.push(colElement);
24404
24405
 
24405
- nameElement.innerText = column;
24406
- });
24406
+ const resizerElement = document.createElement('div');
24407
+ resizerElement.classList.add('col-resizer');
24408
+ resizerElement.dataset.colId = colElement.dataset.colId;
24409
+ contentWrapperElement.appendChild(resizerElement);
24407
24410
 
24408
- headerTrElement.appendChild(document.createElement('th'));
24409
- const lastColElement = document.createElement('col');
24410
- lastColElement.style.width = '100%';
24411
- colElements.push(lastColElement);
24411
+ nameElement.innerText = column;
24412
+ });
24412
24413
 
24413
- let columnsWidth;
24414
- function resize () {
24415
- if (tableElement.style.tableLayout === 'auto') {
24416
- return
24417
- }
24418
- if (!columnsWidth) {
24419
- columnsWidth = 0;
24420
- colElements.slice(0, -1).forEach((element, index) => {
24421
- columnsWidth += element.getBoundingClientRect().width;
24422
- });
24423
- }
24424
- const remainingWidth = Math.max(10, containerElement.clientWidth - columnsWidth);
24425
- colElements.slice(-1)[0].style.width = `${remainingWidth}px`;
24426
- tableElement.style.width = `${columnsWidth + remainingWidth}px`;
24427
- }
24414
+ headerTrElement.appendChild(document.createElement('th'));
24415
+ const lastColElement = document.createElement('col');
24416
+ lastColElement.style.width = '100%';
24417
+ colElements.push(lastColElement);
24428
24418
 
24429
- const resizeObserver = new ResizeObserver(resize);
24430
- resizeObserver.observe(containerElement);
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
+ }
24431
24427
 
24432
- const mutationObserver = new MutationObserver((mutationList, observer) => {
24433
- if (!tableElement.parentElement) {
24434
- resizeObserver.unobserve(containerElement);
24435
- resizeObserver.unobserve(containerElement);
24436
- observer.disconnect();
24437
- }
24438
- });
24439
- mutationObserver.observe(containerElement, { childList: true });
24440
- colgroupElement.appendChild(lastColElement);
24428
+ if (observer.resizeObserver) {
24429
+ observer.resizeObserver.unobserve(mutation.target);
24430
+ observer.resizeObserver = null;
24431
+ }
24432
+ observer.disconnect();
24433
+ }.bind(this));
24434
+ }.bind(this));
24441
24435
 
24442
- setTableBody(rows, tableElement, cellRenderer);
24443
- }
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;
24444
24445
 
24445
- return tableElement
24446
- }
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')
24447
24450
 
24448
- function getTableBody (tableElement) {
24449
- return tableElement.getElementsByTagName('tbody')[0]
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);
24451
24456
 
24452
- function setTableBody (rows, tableElement, cellRenderer) {
24453
- tableElement.style.tableLayout = 'auto';
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);
24454
24464
 
24455
- let tbodyElement = getTableBody(tableElement);
24456
- tbodyElement?.parentElement?.removeChild(tbodyElement);
24465
+ colgroupElement.appendChild(lastColElement);
24457
24466
 
24458
- tbodyElement = document.createElement('tbody');
24459
- tableElement.appendChild(tbodyElement);
24460
-
24461
- let highlight = false;
24462
- rows.forEach(function (row) {
24463
- const rowElement = document.createElement('tr');
24464
- if (highlight) {
24465
- rowElement.classList.add('highlighted-row');
24467
+ this.updateTableBody(rows, cellRenderer);
24466
24468
  }
24467
- highlight = !highlight;
24468
- tbodyElement.appendChild(rowElement);
24469
- row.forEach(function (value, index) {
24470
- if (cellRenderer) {
24471
- cellRenderer(rowElement, index, value);
24472
- } else {
24473
- const cellElement = document.createElement('td');
24474
- cellElement.innerText = value;
24475
- 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');
24476
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'));
24477
24497
  });
24478
- rowElement.appendChild(document.createElement('td'));
24479
- });
24498
+ }
24499
+
24500
+ getTableBody () {
24501
+ return this.tbodyElement
24502
+ }
24480
24503
  }
24481
24504
 
24505
+ customElements.define('resize-table', ResizeTable, { extends: 'table' });
24506
+
24482
24507
  /* global google */
24483
24508
 
24484
24509
  const PAGE_SIZE = 500;
@@ -24548,6 +24573,10 @@
24548
24573
  copyTextToClipboard(toTsv(window.sqlFetch.result.columns, window.sqlFetch.result.rows));
24549
24574
  }
24550
24575
  });
24576
+ addClickListener(document.getElementById('first-button'), (event) => {
24577
+ window.sqlFetch.page = 0;
24578
+ displaySqlFetch(window.sqlFetch);
24579
+ });
24551
24580
  addClickListener(document.getElementById('prev-button'), (event) => {
24552
24581
  window.sqlFetch.page -= 1;
24553
24582
  displaySqlFetch(window.sqlFetch);
@@ -24556,6 +24585,10 @@
24556
24585
  window.sqlFetch.page += 1;
24557
24586
  displaySqlFetch(window.sqlFetch);
24558
24587
  });
24588
+ addClickListener(document.getElementById('last-button'), (event) => {
24589
+ window.sqlFetch.page = window.sqlFetch.pageCount - 1;
24590
+ displaySqlFetch(window.sqlFetch);
24591
+ });
24559
24592
  addClickListener(document.getElementById('submit-dropdown-button-download-csv'), () => {
24560
24593
  if (!window.sqlFetch?.result) return
24561
24594
 
@@ -24811,7 +24844,7 @@
24811
24844
  cellElement.innerText = value;
24812
24845
  rowElement.appendChild(cellElement);
24813
24846
  };
24814
- createTable(columnsElement, columns, rows, 'columns-table', cellRenderer);
24847
+ columnsElement.appendChild(new ResizeTable(columns, rows, cellRenderer));
24815
24848
  }
24816
24849
 
24817
24850
  const indexEntries = Object.entries(table.indexes);
@@ -24837,7 +24870,7 @@
24837
24870
  cellElement.innerText = value;
24838
24871
  rowElement.appendChild(cellElement);
24839
24872
  };
24840
- createTable(indexesElement, columns, rows, 'tables-table', cellRenderer);
24873
+ indexesElement.appendChild(new ResizeTable(columns, rows, cellRenderer));
24841
24874
  }
24842
24875
  });
24843
24876
  window.structureLoaded = true;
@@ -25291,20 +25324,18 @@
25291
25324
 
25292
25325
  let tableElement = document.getElementById('result-table');
25293
25326
  if (tableElement) {
25294
- const resultBody = getTableBody(tableElement);
25327
+ const resultBody = tableElement.getTableBody();
25295
25328
  if (resultBody.dataset.page === fetch.page) {
25296
25329
  // Results already displayed.
25297
25330
  return
25298
25331
  }
25299
- setTableBody(rows, tableElement, resultCellRenderer);
25332
+ tableElement.updateTableBody(rows, resultCellRenderer);
25300
25333
  } else {
25301
25334
  clearResultBox();
25302
- tableElement = createTable(
25303
- document.getElementById('result-box'),
25304
- fetch.result.columns,
25305
- rows,
25306
- 'result-table',
25307
- 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);
25308
25339
  }
25309
25340
  tableElement.setAttribute('data-page', fetch.page);
25310
25341
  }
@@ -25462,7 +25493,7 @@
25462
25493
  }
25463
25494
 
25464
25495
  if (result.total_rows > result.rows.length) {
25465
- message += ` (truncated to ${result.rows.length})`;
25496
+ message += ` (truncated to ${result.rows.length.toLocaleString()})`;
25466
25497
  }
25467
25498
  setStatus(message);
25468
25499
 
@@ -25474,6 +25505,16 @@
25474
25505
  document.getElementById('next-button').disabled = sqlFetch.page + 1 === sqlFetch.pageCount;
25475
25506
  document.getElementById('prev-button').disabled = sqlFetch.page === 0;
25476
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
+ }
25477
25518
  }
25478
25519
 
25479
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.56
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