sqlui 0.1.19 → 0.1.20

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 () {
@@ -24157,9 +24178,21 @@ var sqlui = (function (exports) {
24157
24178
  window.savedLoaded = true;
24158
24179
  }
24159
24180
 
24160
- function submit () {
24181
+ function submitAll () {
24182
+ submit(null);
24183
+ }
24184
+
24185
+ function submitCurrent () {
24186
+ submit(getSelection());
24187
+ }
24188
+
24189
+ function submit (selection) {
24161
24190
  const url = new URL(window.location);
24162
- url.searchParams.set('cursor', getCursor());
24191
+ if (selection) {
24192
+ url.searchParams.set('selection', selection.join(':'));
24193
+ } else {
24194
+ url.searchParams.delete('selection');
24195
+ }
24163
24196
 
24164
24197
  let sql = getValue().trim();
24165
24198
  sql = sql === '' ? null : sql;
@@ -24218,7 +24251,7 @@ var sqlui = (function (exports) {
24218
24251
  }
24219
24252
  }
24220
24253
 
24221
- function fetchSql (sql, cursor, callback) {
24254
+ function fetchSql (sql, selection, successCallback, errorCallback) {
24222
24255
  fetch('query', {
24223
24256
  headers: {
24224
24257
  Accept: 'application/json',
@@ -24227,40 +24260,69 @@ var sqlui = (function (exports) {
24227
24260
  method: 'POST',
24228
24261
  body: JSON.stringify({
24229
24262
  sql,
24230
- cursor
24263
+ selection
24231
24264
  })
24232
24265
  })
24233
- .then((response) => response.json())
24234
- .then((result) => callback(result));
24266
+ .then((response) => {
24267
+ const contentType = response.headers.get('content-type');
24268
+ if (contentType && contentType.indexOf('application/json') !== -1) {
24269
+ response.json().then((result) => {
24270
+ if (result?.query) {
24271
+ successCallback(result);
24272
+ } else if (result?.error) {
24273
+ errorCallback(result.error, result.stacktrace);
24274
+ } else if (result) {
24275
+ errorCallback('failed to execute query', result.toString());
24276
+ } else {
24277
+ errorCallback('failed to execute query');
24278
+ }
24279
+ });
24280
+ } else {
24281
+ response.text().then((result) => {
24282
+ errorCallback('failed to execute query', result);
24283
+ });
24284
+ }
24285
+ })
24286
+ .catch(function (error) {
24287
+ errorCallback('failed to execute query', error.stack);
24288
+ });
24235
24289
  }
24236
24290
 
24237
- function fetchFile (name, callback) {
24291
+ function fetchFile (name, successCallback, errorCallback) {
24238
24292
  fetch(`query_file?file=${name}`, {
24239
24293
  headers: {
24240
24294
  Accept: 'application/json'
24241
24295
  },
24242
24296
  method: 'GET'
24243
24297
  })
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));
24298
+ .then((response) => {
24299
+ const contentType = response.headers.get('content-type');
24300
+ if (contentType && contentType.indexOf('application/json') !== -1) {
24301
+ response.json().then((result) => {
24302
+ if (result?.query) {
24303
+ successCallback(result);
24304
+ } else if (result?.error) {
24305
+ errorCallback(result.error, result.stacktrace);
24306
+ } else if (result) {
24307
+ errorCallback('failed to load file ', result.toString());
24308
+ } else {
24309
+ errorCallback('failed to load file');
24310
+ }
24311
+ });
24312
+ } else {
24313
+ errorCallback('failed to load file', response.toString());
24314
+ }
24315
+ })
24316
+ .catch(function (error) {
24317
+ errorCallback('failed to load file', error.stack);
24318
+ });
24257
24319
  }
24258
24320
 
24259
- function loadQueryOrGraphTab (callback) {
24321
+ function loadQueryOrGraphTab (callback, errorCallback) {
24260
24322
  const params = new URLSearchParams(window.location.search);
24261
24323
  const sql = params.get('sql');
24262
24324
  const file = params.get('file');
24263
- const cursor = params.has('cursor') ? params.get('cursor') : 0;
24325
+ const selection = params.has('selection') ? params.get('selection') : null;
24264
24326
 
24265
24327
  if (params.has('sql') && window.result && sql === window.result.query) {
24266
24328
  callback();
@@ -24270,7 +24332,7 @@ var sqlui = (function (exports) {
24270
24332
  return
24271
24333
  }
24272
24334
 
24273
- if (params.has('file') && params.has('sql') && cursor === window.result.cursor) {
24335
+ if (params.has('file') && params.has('sql') && selection === window.result.selection) {
24274
24336
  // TODO: show an error.
24275
24337
  throw new Error('You can only specify a file or sql, not both.')
24276
24338
  }
@@ -24279,24 +24341,21 @@ var sqlui = (function (exports) {
24279
24341
 
24280
24342
  if (params.has('sql')) {
24281
24343
  setValue(sql);
24282
- const cursor = params.has('cursor') ? params.get('cursor') : 0;
24283
- fetchSql(params.get('sql'), cursor, function (result) {
24344
+ fetchSql(params.get('sql'), selection, function (result) {
24284
24345
  window.result = result;
24285
24346
  callback();
24286
- });
24347
+ }, errorCallback);
24287
24348
  } else if (params.has('file')) {
24288
24349
  setValue('');
24289
24350
  fetchFile(file, function (result) {
24290
24351
  window.result = result;
24291
- if (window.result.query) {
24292
- setValue(result.query);
24293
- }
24352
+ setValue(result.query);
24294
24353
  callback();
24295
- });
24354
+ }, errorCallback);
24296
24355
  }
24297
- if (params.has('cursor')) {
24356
+ if (params.has('selection')) {
24298
24357
  focus();
24299
- setCursor(cursor);
24358
+ setSelection(params.get('selection').split(':'));
24300
24359
  }
24301
24360
  }
24302
24361
 
@@ -24308,9 +24367,9 @@ var sqlui = (function (exports) {
24308
24367
 
24309
24368
  setQueryStatus(window.result);
24310
24369
 
24311
- if (!window.result.rows) {
24312
- return
24313
- }
24370
+ // if (!window.result.rows) {
24371
+ // return
24372
+ // }
24314
24373
 
24315
24374
  const tableElement = document.createElement('table');
24316
24375
  const theadElement = document.createElement('thead');
@@ -24326,7 +24385,9 @@ var sqlui = (function (exports) {
24326
24385
  template.innerHTML = `<th class="cell">${column}</th>`;
24327
24386
  headerElement.appendChild(template.content.firstChild);
24328
24387
  });
24329
- headerElement.appendChild(document.createElement('th'));
24388
+ if (window.result.columns.length > 0) {
24389
+ headerElement.appendChild(document.createElement('th'));
24390
+ }
24330
24391
  let highlight = false;
24331
24392
  window.result.rows.forEach(function (row) {
24332
24393
  const rowElement = document.createElement('tr');
@@ -24362,8 +24423,11 @@ var sqlui = (function (exports) {
24362
24423
 
24363
24424
  window.result.rows.forEach((row) => {
24364
24425
  const rowValues = row.map((value, index) => {
24365
- if (window.result.column_types[index] === 'date') {
24426
+ if (window.result.column_types[index] === 'date' || window.result.column_types[index] === 'datetime') {
24366
24427
  return new Date(value)
24428
+ } else if (window.result.column_types[index] === 'timeofday') {
24429
+ // TODO: This should be hour, minute, second, milliseconds
24430
+ return [0, 0, 0, 0]
24367
24431
  } else {
24368
24432
  return value
24369
24433
  }
@@ -24387,13 +24451,6 @@ var sqlui = (function (exports) {
24387
24451
 
24388
24452
  function setGraphStatus (result) {
24389
24453
  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
24454
 
24398
24455
  if (result.total_rows === 1) {
24399
24456
  statusElement.innerText = `${result.total_rows} row`;
@@ -24408,13 +24465,6 @@ var sqlui = (function (exports) {
24408
24465
 
24409
24466
  function setQueryStatus (result) {
24410
24467
  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
24468
 
24419
24469
  if (result.total_rows === 1) {
24420
24470
  statusElement.innerText = `${result.total_rows} row`;
@@ -24447,23 +24497,58 @@ var sqlui = (function (exports) {
24447
24497
  }
24448
24498
 
24449
24499
  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');
24500
+ fetch('metadata', {
24501
+ headers: {
24502
+ Accept: 'application/json'
24503
+ },
24504
+ method: 'GET'
24505
+ })
24506
+ .then((response) => {
24507
+ const contentType = response.headers.get('content-type');
24508
+ if (contentType && contentType.indexOf('application/json') !== -1) {
24509
+ return response.json().then((result) => {
24510
+ if (result.error) {
24511
+ let error = `<pre>${result.error}`;
24512
+ if (result.stacktrace) {
24513
+ error += '\n' + result.stacktrace + '</pre>';
24514
+ }
24515
+ document.getElementById('loading-box').innerHTML = error;
24516
+ } else if (!result.server) {
24517
+ document.getElementById('loading-box').innerHTML = `
24518
+ <pre>
24519
+ error loading metadata, response:
24520
+ ${JSON.stringify(result)}
24521
+ </pre>
24522
+ `;
24523
+ } else {
24524
+ window.metadata = result;
24525
+ document.getElementById('loading-box').style.display = 'none';
24526
+ document.getElementById('main-box').style.display = 'flex';
24527
+ document.getElementById('server-name').innerText = result.server;
24528
+ const queryElement = document.getElementById('query');
24458
24529
 
24459
- init(queryElement, function () {
24460
- submit();
24530
+ init(queryElement, submitCurrent, submitAll);
24531
+ route();
24532
+ }
24533
+ })
24534
+ } else {
24535
+ console.log(response);
24536
+ document.getElementById('loading-box').style.display = 'flex';
24537
+ document.getElementById('main-box').style.display = 'none';
24538
+ document.getElementById('loading-box').innerHTML = `<pre>${response}</pre>`;
24539
+ }
24540
+ })
24541
+ .catch(function (error) {
24542
+ console.log(error);
24543
+ document.getElementById('loading-box').style.display = 'flex';
24544
+ document.getElementById('main-box').style.display = 'none';
24545
+ document.getElementById('loading-box').innerHTML = `<pre>${error.stack}</pre>`;
24461
24546
  });
24462
- route();
24463
- });
24464
24547
  };
24465
24548
 
24466
24549
  exports.selectTab = selectTab;
24550
+ exports.submitAll = submitAll;
24551
+ exports.submitCurrent = submitCurrent;
24467
24552
 
24468
24553
  return exports;
24469
24554
 
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.20
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-27 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