sqlui 0.1.19 → 0.1.21
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.version +1 -1
- data/app/args.rb +33 -0
- data/app/database_config.rb +7 -7
- data/app/database_metadata.rb +116 -0
- data/app/deep.rb +58 -0
- data/app/mysql_types.rb +33 -0
- data/app/server.rb +125 -217
- data/app/sqlui.rb +36 -0
- data/app/sqlui_config.rb +11 -16
- data/app/views/databases.erb +70 -38
- data/bin/sqlui +3 -1
- data/client/resources/sqlui.css +288 -242
- data/client/resources/sqlui.html +8 -5
- data/client/resources/sqlui.js +168 -82
- metadata +7 -2
data/client/resources/sqlui.js
CHANGED
@@ -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
|
23875
|
-
return window.editorView.state.selection.main.
|
23874
|
+
function getSelection () {
|
23875
|
+
return [window.editorView.state.selection.main.from, window.editorView.state.selection.main.to]
|
23876
23876
|
}
|
23877
23877
|
|
23878
|
-
function
|
23879
|
-
window.editorView.dispatch(
|
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
|
-
|
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
|
24108
|
+
const selection = getSelection();
|
24100
24109
|
focus();
|
24101
|
-
|
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
|
24118
|
+
const selection = getSelection();
|
24110
24119
|
focus();
|
24111
|
-
|
24120
|
+
setSelection(selection);
|
24121
|
+
|
24122
|
+
loadQueryOrGraphTab(loadQueryResult, queryErrorCallback('query-status'));
|
24123
|
+
}
|
24112
24124
|
|
24113
|
-
|
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('
|
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
|
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
|
-
|
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,
|
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
|
-
|
24264
|
+
selection
|
24231
24265
|
})
|
24232
24266
|
})
|
24233
|
-
.then((response) =>
|
24234
|
-
|
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,
|
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) =>
|
24245
|
-
|
24246
|
-
|
24247
|
-
|
24248
|
-
|
24249
|
-
|
24250
|
-
|
24251
|
-
|
24252
|
-
|
24253
|
-
|
24254
|
-
|
24255
|
-
|
24256
|
-
|
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
|
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') &&
|
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
|
-
|
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
|
-
|
24292
|
-
setValue(result.query);
|
24293
|
-
}
|
24353
|
+
setValue(result.query);
|
24294
24354
|
callback();
|
24295
|
-
});
|
24355
|
+
}, errorCallback);
|
24296
24356
|
}
|
24297
|
-
if (params.has('
|
24357
|
+
if (params.has('selection')) {
|
24298
24358
|
focus();
|
24299
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
24451
|
-
|
24452
|
-
|
24453
|
-
|
24454
|
-
|
24455
|
-
|
24456
|
-
|
24457
|
-
|
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
|
-
|
24460
|
-
|
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.
|
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-
|
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
|