sqlui 0.1.19 → 0.1.21

Sign up to get free protection for your applications and to get access to all the features.
@@ -4150,7 +4150,7 @@ var sqlui = (function (exports) {
4150
4150
  return name
4151
4151
  }
4152
4152
 
4153
- function getSelection(root) {
4153
+ function getSelection$1(root) {
4154
4154
  let target;
4155
4155
  // Browsers differ on whether shadow roots have a getSelection
4156
4156
  // method. If it exists, use that, otherwise, call it on the
@@ -6773,7 +6773,7 @@ var sqlui = (function (exports) {
6773
6773
  this.dom.blur();
6774
6774
  this.dom.focus({ preventScroll: true });
6775
6775
  }
6776
- let rawSel = getSelection(this.view.root);
6776
+ let rawSel = getSelection$1(this.view.root);
6777
6777
  if (!rawSel) ;
6778
6778
  else if (main.empty) {
6779
6779
  // Work around https://bugzilla.mozilla.org/show_bug.cgi?id=1612076
@@ -6822,7 +6822,7 @@ var sqlui = (function (exports) {
6822
6822
  if (this.compositionDeco.size)
6823
6823
  return;
6824
6824
  let cursor = this.view.state.selection.main;
6825
- let sel = getSelection(this.view.root);
6825
+ let sel = getSelection$1(this.view.root);
6826
6826
  if (!sel || !cursor.empty || !cursor.assoc || !sel.modify)
6827
6827
  return;
6828
6828
  let line = LineView.find(this, cursor.head);
@@ -7763,7 +7763,7 @@ var sqlui = (function (exports) {
7763
7763
  return false;
7764
7764
  // On boundary clicks, check whether the coordinates are inside the
7765
7765
  // selection's client rectangles
7766
- let sel = getSelection(view.root);
7766
+ let sel = getSelection$1(view.root);
7767
7767
  if (!sel || sel.rangeCount == 0)
7768
7768
  return true;
7769
7769
  let rects = sel.getRangeAt(0).getClientRects();
@@ -9998,7 +9998,7 @@ var sqlui = (function (exports) {
9998
9998
  // https://github.com/codemirror/dev/issues/414
9999
9999
  let range = browser.safari && view.root.nodeType == 11 &&
10000
10000
  deepActiveElement(this.dom.ownerDocument) == this.dom &&
10001
- safariSelectionRangeHack(this.view) || getSelection(view.root);
10001
+ safariSelectionRangeHack(this.view) || getSelection$1(view.root);
10002
10002
  if (!range || this.selectionRange.eq(range))
10003
10003
  return false;
10004
10004
  let local = hasSelection(this.dom, range);
@@ -23850,7 +23850,7 @@ var sqlui = (function (exports) {
23850
23850
 
23851
23851
  /* global google */
23852
23852
 
23853
- function init (parent, onSubmit) {
23853
+ function init (parent, onSubmit, onShiftSubmit) {
23854
23854
  const fixedHeightEditor = EditorView.theme({
23855
23855
  '.cm-scroller': { height: '200px', overflow: 'auto', resize: 'vertical' }
23856
23856
  });
@@ -23858,7 +23858,7 @@ var sqlui = (function (exports) {
23858
23858
  state: EditorState.create({
23859
23859
  extensions: [
23860
23860
  keymap.of([
23861
- { key: 'Ctrl-Enter', run: onSubmit, preventDefault: true },
23861
+ { key: 'Ctrl-Enter', run: onSubmit, preventDefault: true, shift: onShiftSubmit },
23862
23862
  ...defaultKeymap
23863
23863
  ]),
23864
23864
  basicSetup,
@@ -23871,12 +23871,19 @@ var sqlui = (function (exports) {
23871
23871
  });
23872
23872
  }
23873
23873
 
23874
- function getCursor () {
23875
- return window.editorView.state.selection.main.head
23874
+ function getSelection () {
23875
+ return [window.editorView.state.selection.main.from, window.editorView.state.selection.main.to]
23876
23876
  }
23877
23877
 
23878
- function setCursor (cursor) {
23879
- window.editorView.dispatch({ selection: { anchor: Math.min(cursor, window.editorView.state.doc.length) } });
23878
+ function setSelection (selection) {
23879
+ window.editorView.dispatch(
23880
+ {
23881
+ selection: {
23882
+ anchor: Math.min(selection[0], window.editorView.state.doc.length),
23883
+ head: Math.min(selection[1], window.editorView.state.doc.length)
23884
+ }
23885
+ }
23886
+ );
23880
23887
  }
23881
23888
 
23882
23889
  function focus () {
@@ -24067,7 +24074,9 @@ var sqlui = (function (exports) {
24067
24074
  headerElement.innerText = columnName;
24068
24075
  headerTrElement.appendChild(headerElement);
24069
24076
  });
24070
- headerTrElement.appendChild(document.createElement('th'));
24077
+ if (columns.length > 0) {
24078
+ headerTrElement.appendChild(document.createElement('th'));
24079
+ }
24071
24080
  let highlight = false;
24072
24081
  rows.forEach(function (row) {
24073
24082
  const rowElement = document.createElement('tr');
@@ -24093,12 +24102,12 @@ var sqlui = (function (exports) {
24093
24102
 
24094
24103
  google.charts.load('current', { packages: ['corechart', 'line'] });
24095
24104
  google.charts.setOnLoadCallback(function () {
24096
- loadQueryOrGraphTab(loadGraphResult);
24105
+ loadQueryOrGraphTab(loadGraphResult, queryErrorCallback('graph-status'));
24097
24106
  });
24098
24107
 
24099
- const cursor = getCursor();
24108
+ const selection = getSelection();
24100
24109
  focus();
24101
- setCursor(cursor);
24110
+ setSelection(selection);
24102
24111
  }
24103
24112
 
24104
24113
  function selectQueryTab () {
@@ -24106,11 +24115,23 @@ var sqlui = (function (exports) {
24106
24115
  selected.style.display = 'flex';
24107
24116
  });
24108
24117
 
24109
- const cursor = getCursor();
24118
+ const selection = getSelection();
24110
24119
  focus();
24111
- setCursor(cursor);
24120
+ setSelection(selection);
24121
+
24122
+ loadQueryOrGraphTab(loadQueryResult, queryErrorCallback('query-status'));
24123
+ }
24112
24124
 
24113
- loadQueryOrGraphTab(loadQueryResult);
24125
+ function queryErrorCallback (statusElementId) {
24126
+ const statusElement = document.getElementById(statusElementId);
24127
+ return function (message, error) {
24128
+ if (error) {
24129
+ console.log(`${message}\n${error}`);
24130
+ statusElement.innerText = `error: ${message} (check console)`;
24131
+ } else {
24132
+ statusElement.innerText = `error: ${message}`;
24133
+ }
24134
+ }
24114
24135
  }
24115
24136
 
24116
24137
  function selectSavedTab () {
@@ -24135,6 +24156,7 @@ var sqlui = (function (exports) {
24135
24156
  }
24136
24157
  saved.forEach(file => {
24137
24158
  const divElement = document.createElement('div');
24159
+ divElement.classList.add('saved-list-item');
24138
24160
  divElement.addEventListener('click', function (event) {
24139
24161
  clearResult();
24140
24162
  const url = new URL(window.location);
@@ -24144,7 +24166,7 @@ var sqlui = (function (exports) {
24144
24166
  window.history.pushState({}, '', url);
24145
24167
  route();
24146
24168
  });
24147
- const nameElement = document.createElement('h1');
24169
+ const nameElement = document.createElement('h2');
24148
24170
  nameElement.innerText = file.filename;
24149
24171
  divElement.appendChild(nameElement);
24150
24172
 
@@ -24157,9 +24179,21 @@ var sqlui = (function (exports) {
24157
24179
  window.savedLoaded = true;
24158
24180
  }
24159
24181
 
24160
- function submit () {
24182
+ function submitAll () {
24183
+ submit(null);
24184
+ }
24185
+
24186
+ function submitCurrent () {
24187
+ submit(getSelection());
24188
+ }
24189
+
24190
+ function submit (selection) {
24161
24191
  const url = new URL(window.location);
24162
- url.searchParams.set('cursor', getCursor());
24192
+ if (selection) {
24193
+ url.searchParams.set('selection', selection.join(':'));
24194
+ } else {
24195
+ url.searchParams.delete('selection');
24196
+ }
24163
24197
 
24164
24198
  let sql = getValue().trim();
24165
24199
  sql = sql === '' ? null : sql;
@@ -24218,7 +24252,7 @@ var sqlui = (function (exports) {
24218
24252
  }
24219
24253
  }
24220
24254
 
24221
- function fetchSql (sql, cursor, callback) {
24255
+ function fetchSql (sql, selection, successCallback, errorCallback) {
24222
24256
  fetch('query', {
24223
24257
  headers: {
24224
24258
  Accept: 'application/json',
@@ -24227,40 +24261,69 @@ var sqlui = (function (exports) {
24227
24261
  method: 'POST',
24228
24262
  body: JSON.stringify({
24229
24263
  sql,
24230
- cursor
24264
+ selection
24231
24265
  })
24232
24266
  })
24233
- .then((response) => response.json())
24234
- .then((result) => callback(result));
24267
+ .then((response) => {
24268
+ const contentType = response.headers.get('content-type');
24269
+ if (contentType && contentType.indexOf('application/json') !== -1) {
24270
+ response.json().then((result) => {
24271
+ if (result?.query) {
24272
+ successCallback(result);
24273
+ } else if (result?.error) {
24274
+ errorCallback(result.error, result.stacktrace);
24275
+ } else if (result) {
24276
+ errorCallback('failed to execute query', result.toString());
24277
+ } else {
24278
+ errorCallback('failed to execute query');
24279
+ }
24280
+ });
24281
+ } else {
24282
+ response.text().then((result) => {
24283
+ errorCallback('failed to execute query', result);
24284
+ });
24285
+ }
24286
+ })
24287
+ .catch(function (error) {
24288
+ errorCallback('failed to execute query', error.stack);
24289
+ });
24235
24290
  }
24236
24291
 
24237
- function fetchFile (name, callback) {
24292
+ function fetchFile (name, successCallback, errorCallback) {
24238
24293
  fetch(`query_file?file=${name}`, {
24239
24294
  headers: {
24240
24295
  Accept: 'application/json'
24241
24296
  },
24242
24297
  method: 'GET'
24243
24298
  })
24244
- .then((response) => response.json())
24245
- .then((result) => callback(result));
24246
- }
24247
-
24248
- function fetchMetadata (callback) {
24249
- fetch('metadata', {
24250
- headers: {
24251
- Accept: 'application/json'
24252
- },
24253
- method: 'GET'
24254
- })
24255
- .then((response) => response.json())
24256
- .then((result) => callback(result));
24299
+ .then((response) => {
24300
+ const contentType = response.headers.get('content-type');
24301
+ if (contentType && contentType.indexOf('application/json') !== -1) {
24302
+ response.json().then((result) => {
24303
+ if (result?.query) {
24304
+ successCallback(result);
24305
+ } else if (result?.error) {
24306
+ errorCallback(result.error, result.stacktrace);
24307
+ } else if (result) {
24308
+ errorCallback('failed to load file ', result.toString());
24309
+ } else {
24310
+ errorCallback('failed to load file');
24311
+ }
24312
+ });
24313
+ } else {
24314
+ errorCallback('failed to load file', response.toString());
24315
+ }
24316
+ })
24317
+ .catch(function (error) {
24318
+ errorCallback('failed to load file', error.stack);
24319
+ });
24257
24320
  }
24258
24321
 
24259
- function loadQueryOrGraphTab (callback) {
24322
+ function loadQueryOrGraphTab (callback, errorCallback) {
24260
24323
  const params = new URLSearchParams(window.location.search);
24261
24324
  const sql = params.get('sql');
24262
24325
  const file = params.get('file');
24263
- const cursor = params.has('cursor') ? params.get('cursor') : 0;
24326
+ const selection = params.has('selection') ? params.get('selection') : null;
24264
24327
 
24265
24328
  if (params.has('sql') && window.result && sql === window.result.query) {
24266
24329
  callback();
@@ -24270,7 +24333,7 @@ var sqlui = (function (exports) {
24270
24333
  return
24271
24334
  }
24272
24335
 
24273
- if (params.has('file') && params.has('sql') && cursor === window.result.cursor) {
24336
+ if (params.has('file') && params.has('sql') && selection === window.result.selection) {
24274
24337
  // TODO: show an error.
24275
24338
  throw new Error('You can only specify a file or sql, not both.')
24276
24339
  }
@@ -24279,24 +24342,21 @@ var sqlui = (function (exports) {
24279
24342
 
24280
24343
  if (params.has('sql')) {
24281
24344
  setValue(sql);
24282
- const cursor = params.has('cursor') ? params.get('cursor') : 0;
24283
- fetchSql(params.get('sql'), cursor, function (result) {
24345
+ fetchSql(params.get('sql'), selection, function (result) {
24284
24346
  window.result = result;
24285
24347
  callback();
24286
- });
24348
+ }, errorCallback);
24287
24349
  } else if (params.has('file')) {
24288
24350
  setValue('');
24289
24351
  fetchFile(file, function (result) {
24290
24352
  window.result = result;
24291
- if (window.result.query) {
24292
- setValue(result.query);
24293
- }
24353
+ setValue(result.query);
24294
24354
  callback();
24295
- });
24355
+ }, errorCallback);
24296
24356
  }
24297
- if (params.has('cursor')) {
24357
+ if (params.has('selection')) {
24298
24358
  focus();
24299
- setCursor(cursor);
24359
+ setSelection(params.get('selection').split(':'));
24300
24360
  }
24301
24361
  }
24302
24362
 
@@ -24308,9 +24368,9 @@ var sqlui = (function (exports) {
24308
24368
 
24309
24369
  setQueryStatus(window.result);
24310
24370
 
24311
- if (!window.result.rows) {
24312
- return
24313
- }
24371
+ // if (!window.result.rows) {
24372
+ // return
24373
+ // }
24314
24374
 
24315
24375
  const tableElement = document.createElement('table');
24316
24376
  const theadElement = document.createElement('thead');
@@ -24326,7 +24386,9 @@ var sqlui = (function (exports) {
24326
24386
  template.innerHTML = `<th class="cell">${column}</th>`;
24327
24387
  headerElement.appendChild(template.content.firstChild);
24328
24388
  });
24329
- headerElement.appendChild(document.createElement('th'));
24389
+ if (window.result.columns.length > 0) {
24390
+ headerElement.appendChild(document.createElement('th'));
24391
+ }
24330
24392
  let highlight = false;
24331
24393
  window.result.rows.forEach(function (row) {
24332
24394
  const rowElement = document.createElement('tr');
@@ -24362,8 +24424,11 @@ var sqlui = (function (exports) {
24362
24424
 
24363
24425
  window.result.rows.forEach((row) => {
24364
24426
  const rowValues = row.map((value, index) => {
24365
- if (window.result.column_types[index] === 'date') {
24427
+ if (window.result.column_types[index] === 'date' || window.result.column_types[index] === 'datetime') {
24366
24428
  return new Date(value)
24429
+ } else if (window.result.column_types[index] === 'timeofday') {
24430
+ // TODO: This should be hour, minute, second, milliseconds
24431
+ return [0, 0, 0, 0]
24367
24432
  } else {
24368
24433
  return value
24369
24434
  }
@@ -24387,13 +24452,6 @@ var sqlui = (function (exports) {
24387
24452
 
24388
24453
  function setGraphStatus (result) {
24389
24454
  const statusElement = document.getElementById('graph-status');
24390
- if (!result.rows) {
24391
- // TODO use a popup
24392
- console.log('error parsing graph result');
24393
- console.log(JSON.stringify(result, null, 2));
24394
- statusElement.innerText = 'error, check console';
24395
- return
24396
- }
24397
24455
 
24398
24456
  if (result.total_rows === 1) {
24399
24457
  statusElement.innerText = `${result.total_rows} row`;
@@ -24408,13 +24466,6 @@ var sqlui = (function (exports) {
24408
24466
 
24409
24467
  function setQueryStatus (result) {
24410
24468
  const statusElement = document.getElementById('query-status');
24411
- if (!result.rows) {
24412
- // TODO use a popup
24413
- console.log('error parsing query result');
24414
- console.log(JSON.stringify(result, null, 2));
24415
- statusElement.innerText = 'error, check console';
24416
- return
24417
- }
24418
24469
 
24419
24470
  if (result.total_rows === 1) {
24420
24471
  statusElement.innerText = `${result.total_rows} row`;
@@ -24447,23 +24498,58 @@ var sqlui = (function (exports) {
24447
24498
  }
24448
24499
 
24449
24500
  window.onload = function () {
24450
- fetchMetadata(function (result) {
24451
- window.metadata = result;
24452
- if (!result.server) {
24453
- // TODO show error
24454
- throw new Error('unexpected metadata response')
24455
- }
24456
- document.getElementById('header').innerText = result.server;
24457
- const queryElement = document.getElementById('query');
24501
+ fetch('metadata', {
24502
+ headers: {
24503
+ Accept: 'application/json'
24504
+ },
24505
+ method: 'GET'
24506
+ })
24507
+ .then((response) => {
24508
+ const contentType = response.headers.get('content-type');
24509
+ if (contentType && contentType.indexOf('application/json') !== -1) {
24510
+ return response.json().then((result) => {
24511
+ if (result.error) {
24512
+ let error = `<pre>${result.error}`;
24513
+ if (result.stacktrace) {
24514
+ error += '\n' + result.stacktrace + '</pre>';
24515
+ }
24516
+ document.getElementById('loading-box').innerHTML = error;
24517
+ } else if (!result.server) {
24518
+ document.getElementById('loading-box').innerHTML = `
24519
+ <pre>
24520
+ error loading metadata, response:
24521
+ ${JSON.stringify(result)}
24522
+ </pre>
24523
+ `;
24524
+ } else {
24525
+ window.metadata = result;
24526
+ document.getElementById('loading-box').style.display = 'none';
24527
+ document.getElementById('main-box').style.display = 'flex';
24528
+ document.getElementById('server-name').innerText = result.server;
24529
+ const queryElement = document.getElementById('query');
24458
24530
 
24459
- init(queryElement, function () {
24460
- submit();
24531
+ init(queryElement, submitCurrent, submitAll);
24532
+ route();
24533
+ }
24534
+ })
24535
+ } else {
24536
+ console.log(response);
24537
+ document.getElementById('loading-box').style.display = 'flex';
24538
+ document.getElementById('main-box').style.display = 'none';
24539
+ document.getElementById('loading-box').innerHTML = `<pre>${response}</pre>`;
24540
+ }
24541
+ })
24542
+ .catch(function (error) {
24543
+ console.log(error);
24544
+ document.getElementById('loading-box').style.display = 'flex';
24545
+ document.getElementById('main-box').style.display = 'none';
24546
+ document.getElementById('loading-box').innerHTML = `<pre>${error.stack}</pre>`;
24461
24547
  });
24462
- route();
24463
- });
24464
24548
  };
24465
24549
 
24466
24550
  exports.selectTab = selectTab;
24551
+ exports.submitAll = submitAll;
24552
+ exports.submitCurrent = submitCurrent;
24467
24553
 
24468
24554
  return exports;
24469
24555
 
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.19
4
+ version: 0.1.21
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-10-25 00:00:00.000000000 Z
11
+ date: 2022-10-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mysql2
@@ -158,10 +158,15 @@ extensions: []
158
158
  extra_rdoc_files: []
159
159
  files:
160
160
  - ".version"
161
+ - app/args.rb
161
162
  - app/database_config.rb
163
+ - app/database_metadata.rb
164
+ - app/deep.rb
162
165
  - app/environment.rb
166
+ - app/mysql_types.rb
163
167
  - app/server.rb
164
168
  - app/sql_parser.rb
169
+ - app/sqlui.rb
165
170
  - app/sqlui_config.rb
166
171
  - app/views/databases.erb
167
172
  - bin/sqlui