sqlui 0.1.38 → 0.1.39
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 +11 -3
- data/app/database_config.rb +12 -1
- data/app/server.rb +1 -0
- data/app/sqlui_config.rb +1 -0
- data/client/resources/sqlui.js +234 -94
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 473ef1be7a3ad0a4e28d2ebf7ab4f52bfcb140a24ccbfcabab5ccbccf7e5d699
|
4
|
+
data.tar.gz: 8236b7ddf4245a64738b304029a291a04c33d7079045b3456d61b22d1f1fcf1c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 38dd32e339981bba7a401a6c53f5cf8233ffbe8d98fc69f79ceb4c575adbe8b7a2d7e6c7ab97f9a835ae69f63423b8b925978565c5d6e66aa5a3efa71e937e5a
|
7
|
+
data.tar.gz: 4e56ef90eba0ce8ad231fb80f7c93cb740eab46208a0c8a27d16e3f34568f4b40ece0c68d92f0c81101ad784e78609f34c90158731ef61d72ee3952847c6a2e1
|
data/.version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.39
|
data/app/args.rb
CHANGED
@@ -20,13 +20,21 @@ class Args
|
|
20
20
|
value
|
21
21
|
end
|
22
22
|
|
23
|
+
def self.fetch_optional_hash(hash, key)
|
24
|
+
fetch_optional(hash, key, Hash)
|
25
|
+
end
|
26
|
+
|
23
27
|
def self.fetch_non_nil(hash, key, *classes)
|
24
28
|
raise ArgumentError, "required parameter #{key} missing" unless hash.key?(key)
|
25
29
|
|
26
|
-
|
27
|
-
raise ArgumentError, "required parameter #{key} null" if value.nil?
|
30
|
+
raise ArgumentError, "required parameter #{key} null" if hash[key].nil?
|
28
31
|
|
29
|
-
|
32
|
+
fetch_optional(hash, key, *classes)
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.fetch_optional(hash, key, *classes)
|
36
|
+
value = hash[key]
|
37
|
+
if value && classes.size.positive? && !classes.find { |clazz| value.is_a?(clazz) }
|
30
38
|
if classes.size != 1
|
31
39
|
raise ArgumentError, "required parameter #{key} not #{classes.map(&:to_s).map(&:downcase).join(' or ')}"
|
32
40
|
end
|
data/app/database_config.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'mysql2'
|
4
|
+
require 'set'
|
5
|
+
|
4
6
|
require_relative 'args'
|
5
7
|
|
6
8
|
# Config for a single database.
|
7
9
|
class DatabaseConfig
|
8
|
-
attr_reader :display_name, :description, :url_path, :saved_path, :client_params
|
10
|
+
attr_reader :display_name, :description, :url_path, :saved_path, :table_aliases, :client_params
|
9
11
|
|
10
12
|
def initialize(hash)
|
11
13
|
@display_name = Args.fetch_non_empty_string(hash, :display_name).strip
|
@@ -15,6 +17,15 @@ class DatabaseConfig
|
|
15
17
|
raise ArgumentError, 'url_path should not end with a /' if @url_path.length > 1 && @url_path.end_with?('/')
|
16
18
|
|
17
19
|
@saved_path = Args.fetch_non_empty_string(hash, :saved_path).strip
|
20
|
+
@table_aliases = Args.fetch_optional_hash(hash, :table_aliases) || {}
|
21
|
+
@table_aliases = @table_aliases.each do |table, a|
|
22
|
+
raise ArgumentError, "invalid alias for table #{table} (#{a}), expected string" unless a.is_a?(String)
|
23
|
+
end
|
24
|
+
duplicate_aliases = @table_aliases.reject { |(_, v)| @table_aliases.values.count(v) == 1 }.to_h.values.to_set
|
25
|
+
if @table_aliases.values.to_set.size < @table_aliases.values.size
|
26
|
+
raise ArgumentError, "duplicate table aliases: #{duplicate_aliases.join(', ')}"
|
27
|
+
end
|
28
|
+
|
18
29
|
@client_params = Args.fetch_non_empty_hash(hash, :client_params)
|
19
30
|
end
|
20
31
|
|
data/app/server.rb
CHANGED
@@ -57,6 +57,7 @@ class Server < Sinatra::Base
|
|
57
57
|
server: "#{config.name} - #{database.display_name}",
|
58
58
|
list_url_path: config.list_url_path,
|
59
59
|
schemas: DatabaseMetadata.lookup(client, database),
|
60
|
+
table_aliases: database.table_aliases,
|
60
61
|
saved: Dir.glob("#{database.saved_path}/*.sql").to_h do |path|
|
61
62
|
contents = File.read(path)
|
62
63
|
comment_lines = contents.split("\n").take_while do |l|
|
data/app/sqlui_config.rb
CHANGED
data/client/resources/sqlui.js
CHANGED
@@ -1662,18 +1662,20 @@
|
|
1662
1662
|
return 0;
|
1663
1663
|
},
|
1664
1664
|
reconfigure: (state, oldState) => {
|
1665
|
-
let newVal =
|
1666
|
-
let oldAddr = oldState.config.address[id];
|
1665
|
+
let newVal, oldAddr = oldState.config.address[id];
|
1667
1666
|
if (oldAddr != null) {
|
1668
1667
|
let oldVal = getAddr(oldState, oldAddr);
|
1669
1668
|
if (this.dependencies.every(dep => {
|
1670
1669
|
return dep instanceof Facet ? oldState.facet(dep) === state.facet(dep) :
|
1671
1670
|
dep instanceof StateField ? oldState.field(dep, false) == state.field(dep, false) : true;
|
1672
|
-
}) || (multi ? compareArray(newVal, oldVal, compare) : compare(newVal, oldVal))) {
|
1671
|
+
}) || (multi ? compareArray(newVal = getter(state), oldVal, compare) : compare(newVal = getter(state), oldVal))) {
|
1673
1672
|
state.values[idx] = oldVal;
|
1674
1673
|
return 0;
|
1675
1674
|
}
|
1676
1675
|
}
|
1676
|
+
else {
|
1677
|
+
newVal = getter(state);
|
1678
|
+
}
|
1677
1679
|
state.values[idx] = newVal;
|
1678
1680
|
return 1 /* SlotStatus.Changed */;
|
1679
1681
|
}
|
@@ -2807,6 +2809,18 @@
|
|
2807
2809
|
/**
|
2808
2810
|
Find the values for a given language data field, provided by the
|
2809
2811
|
the [`languageData`](https://codemirror.net/6/docs/ref/#state.EditorState^languageData) facet.
|
2812
|
+
|
2813
|
+
Examples of language data fields are...
|
2814
|
+
|
2815
|
+
- [`"commentTokens"`](https://codemirror.net/6/docs/ref/#commands.CommentTokens) for specifying
|
2816
|
+
comment syntax.
|
2817
|
+
- [`"autocomplete"`](https://codemirror.net/6/docs/ref/#autocomplete.autocompletion^config.override)
|
2818
|
+
for providing language-specific completion sources.
|
2819
|
+
- [`"wordChars"`](https://codemirror.net/6/docs/ref/#state.EditorState.charCategorizer) for adding
|
2820
|
+
characters that should be considered part of words in this
|
2821
|
+
language.
|
2822
|
+
- [`"closeBrackets"`](https://codemirror.net/6/docs/ref/#autocomplete.CloseBracketConfig) controls
|
2823
|
+
bracket closing behavior.
|
2810
2824
|
*/
|
2811
2825
|
languageDataAt(name, pos, side = -1) {
|
2812
2826
|
let values = [];
|
@@ -3311,7 +3325,7 @@
|
|
3311
3325
|
*/
|
3312
3326
|
static eq(oldSets, newSets, from = 0, to) {
|
3313
3327
|
if (to == null)
|
3314
|
-
to = 1000000000 /* C.Far
|
3328
|
+
to = 1000000000 /* C.Far */ - 1;
|
3315
3329
|
let a = oldSets.filter(set => !set.isEmpty && newSets.indexOf(set) < 0);
|
3316
3330
|
let b = newSets.filter(set => !set.isEmpty && oldSets.indexOf(set) < 0);
|
3317
3331
|
if (a.length != b.length)
|
@@ -5019,7 +5033,7 @@
|
|
5019
5033
|
if (pos > 0 ? i == 0 : i == rects.length - 1 || rect.top < rect.bottom)
|
5020
5034
|
break;
|
5021
5035
|
}
|
5022
|
-
return flattenRect(rect, this.side > 0);
|
5036
|
+
return this.length ? rect : flattenRect(rect, this.side > 0);
|
5023
5037
|
}
|
5024
5038
|
get isEditable() { return false; }
|
5025
5039
|
destroy() {
|
@@ -5909,6 +5923,9 @@
|
|
5909
5923
|
const perLineTextDirection = /*@__PURE__*/Facet.define({
|
5910
5924
|
combine: values => values.some(x => x)
|
5911
5925
|
});
|
5926
|
+
const nativeSelectionHidden = /*@__PURE__*/Facet.define({
|
5927
|
+
combine: values => values.some(x => x)
|
5928
|
+
});
|
5912
5929
|
class ScrollTarget {
|
5913
5930
|
constructor(range, y = "nearest", x = "nearest", yMargin = 5, xMargin = 5) {
|
5914
5931
|
this.range = range;
|
@@ -6821,8 +6838,9 @@
|
|
6821
6838
|
enforceCursorAssoc() {
|
6822
6839
|
if (this.compositionDeco.size)
|
6823
6840
|
return;
|
6824
|
-
let cursor =
|
6825
|
-
let sel = getSelection$1(
|
6841
|
+
let { view } = this, cursor = view.state.selection.main;
|
6842
|
+
let sel = getSelection$1(view.root);
|
6843
|
+
let { anchorNode, anchorOffset } = view.observer.selectionRange;
|
6826
6844
|
if (!sel || !cursor.empty || !cursor.assoc || !sel.modify)
|
6827
6845
|
return;
|
6828
6846
|
let line = LineView.find(this, cursor.head);
|
@@ -6837,6 +6855,12 @@
|
|
6837
6855
|
let dom = this.domAtPos(cursor.head + cursor.assoc);
|
6838
6856
|
sel.collapse(dom.node, dom.offset);
|
6839
6857
|
sel.modify("move", cursor.assoc < 0 ? "forward" : "backward", "lineboundary");
|
6858
|
+
// This can go wrong in corner cases like single-character lines,
|
6859
|
+
// so check and reset if necessary.
|
6860
|
+
view.observer.readSelectionRange();
|
6861
|
+
let newRange = view.observer.selectionRange;
|
6862
|
+
if (view.docView.posFromDOM(newRange.anchorNode, newRange.anchorOffset) != cursor.from)
|
6863
|
+
sel.collapse(anchorNode, anchorOffset);
|
6840
6864
|
}
|
6841
6865
|
mayControlSelection() {
|
6842
6866
|
let active = this.view.root.activeElement;
|
@@ -8170,9 +8194,9 @@
|
|
8170
8194
|
|
8171
8195
|
const wrappingWhiteSpace = ["pre-wrap", "normal", "pre-line", "break-spaces"];
|
8172
8196
|
class HeightOracle {
|
8173
|
-
constructor() {
|
8197
|
+
constructor(lineWrapping) {
|
8198
|
+
this.lineWrapping = lineWrapping;
|
8174
8199
|
this.doc = Text.empty;
|
8175
|
-
this.lineWrapping = false;
|
8176
8200
|
this.heightSamples = {};
|
8177
8201
|
this.lineHeight = 14;
|
8178
8202
|
this.charWidth = 7;
|
@@ -8911,7 +8935,6 @@
|
|
8911
8935
|
this.contentDOMHeight = 0;
|
8912
8936
|
this.editorHeight = 0;
|
8913
8937
|
this.editorWidth = 0;
|
8914
|
-
this.heightOracle = new HeightOracle;
|
8915
8938
|
// See VP.MaxDOMHeight
|
8916
8939
|
this.scaler = IdScaler;
|
8917
8940
|
this.scrollTarget = null;
|
@@ -8920,7 +8943,7 @@
|
|
8920
8943
|
// Flag set when editor content was redrawn, so that the next
|
8921
8944
|
// measure stage knows it must read DOM layout
|
8922
8945
|
this.mustMeasureContent = true;
|
8923
|
-
this.defaultTextDirection = Direction.
|
8946
|
+
this.defaultTextDirection = Direction.LTR;
|
8924
8947
|
this.visibleRanges = [];
|
8925
8948
|
// Cursor 'assoc' is only significant when the cursor is on a line
|
8926
8949
|
// wrap point, where it must stick to the character that it is
|
@@ -8931,6 +8954,8 @@
|
|
8931
8954
|
// boundary and, if so, reset it to make sure it is positioned in
|
8932
8955
|
// the right place.
|
8933
8956
|
this.mustEnforceCursorAssoc = false;
|
8957
|
+
let guessWrapping = state.facet(contentAttributes).some(v => typeof v != "function" && v.class == "cm-lineWrapping");
|
8958
|
+
this.heightOracle = new HeightOracle(guessWrapping);
|
8934
8959
|
this.stateDeco = state.facet(decorations).filter(d => typeof d != "function");
|
8935
8960
|
this.heightMap = HeightMap.empty().applyChanges(this.stateDeco, Text.empty, this.heightOracle.setDoc(state.doc), [new ChangedRange(0, 0, 0, state.doc.length)]);
|
8936
8961
|
this.viewport = this.getViewport(0, null);
|
@@ -8985,7 +9010,8 @@
|
|
8985
9010
|
if (scrollTarget)
|
8986
9011
|
this.scrollTarget = scrollTarget;
|
8987
9012
|
if (!this.mustEnforceCursorAssoc && update.selectionSet && update.view.lineWrapping &&
|
8988
|
-
update.state.selection.main.empty && update.state.selection.main.assoc
|
9013
|
+
update.state.selection.main.empty && update.state.selection.main.assoc &&
|
9014
|
+
!update.state.facet(nativeSelectionHidden))
|
8989
9015
|
this.mustEnforceCursorAssoc = true;
|
8990
9016
|
}
|
8991
9017
|
measure(view) {
|
@@ -9048,7 +9074,7 @@
|
|
9048
9074
|
oracle.heightChanged = false;
|
9049
9075
|
for (let vp of this.viewports) {
|
9050
9076
|
let heights = vp.from == this.viewport.from ? lineHeights : view.docView.measureVisibleLineHeights(vp);
|
9051
|
-
this.heightMap = this.heightMap.updateHeight(oracle, 0, refresh, new MeasuredHeights(vp.from, heights));
|
9077
|
+
this.heightMap = (refresh ? HeightMap.empty().applyChanges(this.stateDeco, Text.empty, this.heightOracle, [new ChangedRange(0, 0, 0, view.state.doc.length)]) : this.heightMap).updateHeight(oracle, 0, refresh, new MeasuredHeights(vp.from, heights));
|
9052
9078
|
}
|
9053
9079
|
if (oracle.heightChanged)
|
9054
9080
|
result |= 2 /* UpdateFlag.Height */;
|
@@ -9614,7 +9640,11 @@
|
|
9614
9640
|
this.bounds = null;
|
9615
9641
|
this.text = "";
|
9616
9642
|
let { impreciseHead: iHead, impreciseAnchor: iAnchor } = view.docView;
|
9617
|
-
if (
|
9643
|
+
if (view.state.readOnly && start > -1) {
|
9644
|
+
// Ignore changes when the editor is read-only
|
9645
|
+
this.newSel = null;
|
9646
|
+
}
|
9647
|
+
else if (start > -1 && (this.bounds = view.docView.domBoundsAround(start, end, 0))) {
|
9618
9648
|
let selPoints = iHead || iAnchor ? [] : selectionPoints(view);
|
9619
9649
|
let reader = new DOMReader(selPoints, view.state);
|
9620
9650
|
reader.readRange(this.bounds.startDOM, this.bounds.endDOM);
|
@@ -9908,7 +9938,8 @@
|
|
9908
9938
|
this.onScroll = this.onScroll.bind(this);
|
9909
9939
|
if (typeof ResizeObserver == "function") {
|
9910
9940
|
this.resize = new ResizeObserver(() => {
|
9911
|
-
|
9941
|
+
var _a;
|
9942
|
+
if (((_a = this.view.docView) === null || _a === void 0 ? void 0 : _a.lastUpdate) < Date.now() - 75)
|
9912
9943
|
this.onResize();
|
9913
9944
|
});
|
9914
9945
|
this.resize.observe(view.scrollDOM);
|
@@ -11400,7 +11431,7 @@
|
|
11400
11431
|
if (scopeObj) {
|
11401
11432
|
if (runFor(scopeObj[prefix + modifiers(name, event, !isChar)]))
|
11402
11433
|
return true;
|
11403
|
-
if (isChar && (event.
|
11434
|
+
if (isChar && (event.altKey || event.metaKey || event.ctrlKey) &&
|
11404
11435
|
(baseName = base[event.keyCode]) && baseName != name) {
|
11405
11436
|
if (runFor(scopeObj[prefix + modifiers(baseName, event, true)]))
|
11406
11437
|
return true;
|
@@ -11452,7 +11483,8 @@
|
|
11452
11483
|
return [
|
11453
11484
|
selectionConfig.of(config),
|
11454
11485
|
drawSelectionPlugin,
|
11455
|
-
hideNativeSelection
|
11486
|
+
hideNativeSelection,
|
11487
|
+
nativeSelectionHidden.of(true)
|
11456
11488
|
];
|
11457
11489
|
}
|
11458
11490
|
class Piece {
|
@@ -12210,6 +12242,9 @@
|
|
12210
12242
|
keyup(e) {
|
12211
12243
|
if (e.keyCode == code || !getter(e))
|
12212
12244
|
this.set(false);
|
12245
|
+
},
|
12246
|
+
mousemove(e) {
|
12247
|
+
this.set(getter(e));
|
12213
12248
|
}
|
12214
12249
|
}
|
12215
12250
|
});
|
@@ -12444,7 +12479,7 @@
|
|
12444
12479
|
dom.classList.toggle("cm-tooltip-above", above);
|
12445
12480
|
dom.classList.toggle("cm-tooltip-below", !above);
|
12446
12481
|
if (tView.positioned)
|
12447
|
-
tView.positioned();
|
12482
|
+
tView.positioned(measured.space);
|
12448
12483
|
}
|
12449
12484
|
}
|
12450
12485
|
maybeMeasure() {
|
@@ -12560,10 +12595,10 @@
|
|
12560
12595
|
}
|
12561
12596
|
this.mounted = true;
|
12562
12597
|
}
|
12563
|
-
positioned() {
|
12598
|
+
positioned(space) {
|
12564
12599
|
for (let hostedView of this.manager.tooltipViews) {
|
12565
12600
|
if (hostedView.positioned)
|
12566
|
-
hostedView.positioned();
|
12601
|
+
hostedView.positioned(space);
|
12567
12602
|
}
|
12568
12603
|
}
|
12569
12604
|
update(update) {
|
@@ -12660,10 +12695,10 @@
|
|
12660
12695
|
}
|
12661
12696
|
}
|
12662
12697
|
}
|
12663
|
-
mouseleave() {
|
12698
|
+
mouseleave(e) {
|
12664
12699
|
clearTimeout(this.hoverTimeout);
|
12665
12700
|
this.hoverTimeout = -1;
|
12666
|
-
if (this.active)
|
12701
|
+
if (this.active && !isInTooltip(e.relatedTarget))
|
12667
12702
|
this.view.dispatch({ effects: this.setHover.of(null) });
|
12668
12703
|
}
|
12669
12704
|
destroy() {
|
@@ -15988,8 +16023,10 @@
|
|
15988
16023
|
Facet that defines a way to provide a function that computes the
|
15989
16024
|
appropriate indentation depth, as a column number (see
|
15990
16025
|
[`indentString`](https://codemirror.net/6/docs/ref/#language.indentString)), at the start of a given
|
15991
|
-
line
|
15992
|
-
determined
|
16026
|
+
line. A return value of `null` indicates no indentation can be
|
16027
|
+
determined, and the line should inherit the indentation of the one
|
16028
|
+
above it. A return value of `undefined` defers to the next indent
|
16029
|
+
service.
|
15993
16030
|
*/
|
15994
16031
|
const indentService = /*@__PURE__*/Facet.define();
|
15995
16032
|
/**
|
@@ -16047,7 +16084,7 @@
|
|
16047
16084
|
context = new IndentContext(context);
|
16048
16085
|
for (let service of context.state.facet(indentService)) {
|
16049
16086
|
let result = service(context, pos);
|
16050
|
-
if (result
|
16087
|
+
if (result !== undefined)
|
16051
16088
|
return result;
|
16052
16089
|
}
|
16053
16090
|
let tree = syntaxTree(context.state);
|
@@ -16355,7 +16392,7 @@
|
|
16355
16392
|
let tree = syntaxTree(state);
|
16356
16393
|
if (tree.length < end)
|
16357
16394
|
return null;
|
16358
|
-
let inner = tree.resolveInner(end);
|
16395
|
+
let inner = tree.resolveInner(end, 1);
|
16359
16396
|
let found = null;
|
16360
16397
|
for (let cur = inner; cur; cur = cur.parent) {
|
16361
16398
|
if (cur.to <= end || cur.from > end)
|
@@ -19520,14 +19557,14 @@
|
|
19520
19557
|
crelt("br"),
|
19521
19558
|
this.replaceField,
|
19522
19559
|
button("replace", () => replaceNext(view), [phrase(view, "replace")]),
|
19523
|
-
button("replaceAll", () => replaceAll(view), [phrase(view, "replace all")])
|
19524
|
-
|
19525
|
-
|
19526
|
-
|
19527
|
-
|
19528
|
-
|
19529
|
-
|
19530
|
-
]
|
19560
|
+
button("replaceAll", () => replaceAll(view), [phrase(view, "replace all")])
|
19561
|
+
],
|
19562
|
+
crelt("button", {
|
19563
|
+
name: "close",
|
19564
|
+
onclick: () => closeSearchPanel(view),
|
19565
|
+
"aria-label": phrase(view, "close"),
|
19566
|
+
type: "button"
|
19567
|
+
}, ["×"])
|
19531
19568
|
]);
|
19532
19569
|
}
|
19533
19570
|
commit() {
|
@@ -19767,6 +19804,11 @@
|
|
19767
19804
|
return new RegExp(`${addStart ? "^" : ""}(?:${source})${addEnd ? "$" : ""}`, (_a = expr.flags) !== null && _a !== void 0 ? _a : (expr.ignoreCase ? "i" : ""));
|
19768
19805
|
}
|
19769
19806
|
/**
|
19807
|
+
This annotation is added to transactions that are produced by
|
19808
|
+
picking a completion.
|
19809
|
+
*/
|
19810
|
+
const pickedCompletion = /*@__PURE__*/Annotation.define();
|
19811
|
+
/**
|
19770
19812
|
Helper function that returns a transaction spec which inserts a
|
19771
19813
|
completion's text in the main selection range, and any other
|
19772
19814
|
selection range that has the same text in front of it.
|
@@ -19792,7 +19834,7 @@
|
|
19792
19834
|
const apply = option.completion.apply || option.completion.label;
|
19793
19835
|
let result = option.source;
|
19794
19836
|
if (typeof apply == "string")
|
19795
|
-
view.dispatch(insertCompletionText(view.state, apply, result.from, result.to));
|
19837
|
+
view.dispatch(Object.assign(Object.assign({}, insertCompletionText(view.state, apply, result.from, result.to)), { annotations: pickedCompletion.of(option.completion) }));
|
19796
19838
|
else
|
19797
19839
|
apply(view, option.completion, result.from, result.to);
|
19798
19840
|
}
|
@@ -20027,6 +20069,7 @@
|
|
20027
20069
|
write: (pos) => this.positionInfo(pos),
|
20028
20070
|
key: this
|
20029
20071
|
};
|
20072
|
+
this.space = null;
|
20030
20073
|
let cState = view.state.field(stateField);
|
20031
20074
|
let { options, selected } = cState.open;
|
20032
20075
|
let config = view.state.facet(completionConfig);
|
@@ -20052,10 +20095,17 @@
|
|
20052
20095
|
}
|
20053
20096
|
mount() { this.updateSel(); }
|
20054
20097
|
update(update) {
|
20055
|
-
|
20098
|
+
var _a, _b, _c;
|
20099
|
+
let cState = update.state.field(this.stateField);
|
20100
|
+
let prevState = update.startState.field(this.stateField);
|
20101
|
+
if (cState != prevState) {
|
20056
20102
|
this.updateSel();
|
20103
|
+
if (((_a = cState.open) === null || _a === void 0 ? void 0 : _a.disabled) != ((_b = prevState.open) === null || _b === void 0 ? void 0 : _b.disabled))
|
20104
|
+
this.dom.classList.toggle("cm-tooltip-autocomplete-disabled", !!((_c = cState.open) === null || _c === void 0 ? void 0 : _c.disabled));
|
20105
|
+
}
|
20057
20106
|
}
|
20058
|
-
positioned() {
|
20107
|
+
positioned(space) {
|
20108
|
+
this.space = space;
|
20059
20109
|
if (this.info)
|
20060
20110
|
this.view.requestMeasure(this.placeInfo);
|
20061
20111
|
}
|
@@ -20122,27 +20172,32 @@
|
|
20122
20172
|
let sel = this.dom.querySelector("[aria-selected]");
|
20123
20173
|
if (!sel || !this.info)
|
20124
20174
|
return null;
|
20125
|
-
let win = this.dom.ownerDocument.defaultView || window;
|
20126
20175
|
let listRect = this.dom.getBoundingClientRect();
|
20127
20176
|
let infoRect = this.info.getBoundingClientRect();
|
20128
20177
|
let selRect = sel.getBoundingClientRect();
|
20129
|
-
|
20178
|
+
let space = this.space;
|
20179
|
+
if (!space) {
|
20180
|
+
let win = this.dom.ownerDocument.defaultView || window;
|
20181
|
+
space = { left: 0, top: 0, right: win.innerWidth, bottom: win.innerHeight };
|
20182
|
+
}
|
20183
|
+
if (selRect.top > Math.min(space.bottom, listRect.bottom) - 10 ||
|
20184
|
+
selRect.bottom < Math.max(space.top, listRect.top) + 10)
|
20130
20185
|
return null;
|
20131
20186
|
let rtl = this.view.textDirection == Direction.RTL, left = rtl, narrow = false, maxWidth;
|
20132
20187
|
let top = "", bottom = "";
|
20133
|
-
let spaceLeft = listRect.left, spaceRight =
|
20188
|
+
let spaceLeft = listRect.left - space.left, spaceRight = space.right - listRect.right;
|
20134
20189
|
if (left && spaceLeft < Math.min(infoRect.width, spaceRight))
|
20135
20190
|
left = false;
|
20136
20191
|
else if (!left && spaceRight < Math.min(infoRect.width, spaceLeft))
|
20137
20192
|
left = true;
|
20138
20193
|
if (infoRect.width <= (left ? spaceLeft : spaceRight)) {
|
20139
|
-
top = (Math.max(
|
20194
|
+
top = (Math.max(space.top, Math.min(selRect.top, space.bottom - infoRect.height)) - listRect.top) + "px";
|
20140
20195
|
maxWidth = Math.min(400 /* Info.Width */, left ? spaceLeft : spaceRight) + "px";
|
20141
20196
|
}
|
20142
20197
|
else {
|
20143
20198
|
narrow = true;
|
20144
|
-
maxWidth = Math.min(400 /* Info.Width */, (rtl ? listRect.right :
|
20145
|
-
let spaceBelow =
|
20199
|
+
maxWidth = Math.min(400 /* Info.Width */, (rtl ? listRect.right : space.right - listRect.left) - 30 /* Info.Margin */) + "px";
|
20200
|
+
let spaceBelow = space.bottom - listRect.bottom;
|
20146
20201
|
if (spaceBelow >= infoRect.height || spaceBelow > listRect.top) // Below the completion
|
20147
20202
|
top = (selRect.bottom - listRect.top) + "px";
|
20148
20203
|
else // Above it
|
@@ -20251,21 +20306,24 @@
|
|
20251
20306
|
return result;
|
20252
20307
|
}
|
20253
20308
|
class CompletionDialog {
|
20254
|
-
constructor(options, attrs, tooltip, timestamp, selected) {
|
20309
|
+
constructor(options, attrs, tooltip, timestamp, selected, disabled) {
|
20255
20310
|
this.options = options;
|
20256
20311
|
this.attrs = attrs;
|
20257
20312
|
this.tooltip = tooltip;
|
20258
20313
|
this.timestamp = timestamp;
|
20259
20314
|
this.selected = selected;
|
20315
|
+
this.disabled = disabled;
|
20260
20316
|
}
|
20261
20317
|
setSelected(selected, id) {
|
20262
20318
|
return selected == this.selected || selected >= this.options.length ? this
|
20263
|
-
: new CompletionDialog(this.options, makeAttrs(id, selected), this.tooltip, this.timestamp, selected);
|
20319
|
+
: new CompletionDialog(this.options, makeAttrs(id, selected), this.tooltip, this.timestamp, selected, this.disabled);
|
20264
20320
|
}
|
20265
20321
|
static build(active, state, id, prev, conf) {
|
20266
20322
|
let options = sortOptions(active, state);
|
20267
|
-
if (!options.length)
|
20268
|
-
return
|
20323
|
+
if (!options.length) {
|
20324
|
+
return prev && active.some(a => a.state == 1 /* State.Pending */) ?
|
20325
|
+
new CompletionDialog(prev.options, prev.attrs, prev.tooltip, prev.timestamp, prev.selected, true) : null;
|
20326
|
+
}
|
20269
20327
|
let selected = state.facet(completionConfig).selectOnOpen ? 0 : -1;
|
20270
20328
|
if (prev && prev.selected != selected && prev.selected != -1) {
|
20271
20329
|
let selectedValue = prev.options[prev.selected].completion;
|
@@ -20279,10 +20337,10 @@
|
|
20279
20337
|
pos: active.reduce((a, b) => b.hasResult() ? Math.min(a, b.from) : a, 1e8),
|
20280
20338
|
create: completionTooltip(completionState),
|
20281
20339
|
above: conf.aboveCursor,
|
20282
|
-
}, prev ? prev.timestamp : Date.now(), selected);
|
20340
|
+
}, prev ? prev.timestamp : Date.now(), selected, false);
|
20283
20341
|
}
|
20284
20342
|
map(changes) {
|
20285
|
-
return new CompletionDialog(this.options, this.attrs, Object.assign(Object.assign({}, this.tooltip), { pos: changes.mapPos(this.tooltip.pos) }), this.timestamp, this.selected);
|
20343
|
+
return new CompletionDialog(this.options, this.attrs, Object.assign(Object.assign({}, this.tooltip), { pos: changes.mapPos(this.tooltip.pos) }), this.timestamp, this.selected, this.disabled);
|
20286
20344
|
}
|
20287
20345
|
}
|
20288
20346
|
class CompletionState {
|
@@ -20305,9 +20363,12 @@
|
|
20305
20363
|
});
|
20306
20364
|
if (active.length == this.active.length && active.every((a, i) => a == this.active[i]))
|
20307
20365
|
active = this.active;
|
20308
|
-
let open =
|
20309
|
-
|
20310
|
-
|
20366
|
+
let open = this.open;
|
20367
|
+
if (tr.selection || active.some(a => a.hasResult() && tr.changes.touchesRange(a.from, a.to)) ||
|
20368
|
+
!sameResults(active, this.active))
|
20369
|
+
open = CompletionDialog.build(active, state, this.id, this.open, conf);
|
20370
|
+
else if (open && tr.docChanged)
|
20371
|
+
open = open.map(tr.changes);
|
20311
20372
|
if (!open && active.every(a => a.state != 1 /* State.Pending */) && active.some(a => a.hasResult()))
|
20312
20373
|
active = active.map(a => a.hasResult() ? new ActiveSource(a.source, 0 /* State.Inactive */) : a);
|
20313
20374
|
for (let effect of tr.effects)
|
@@ -20447,7 +20508,7 @@
|
|
20447
20508
|
function moveCompletionSelection(forward, by = "option") {
|
20448
20509
|
return (view) => {
|
20449
20510
|
let cState = view.state.field(completionState, false);
|
20450
|
-
if (!cState || !cState.open ||
|
20511
|
+
if (!cState || !cState.open || cState.open.disabled ||
|
20451
20512
|
Date.now() - cState.open.timestamp < view.state.facet(completionConfig).interactionDelay)
|
20452
20513
|
return false;
|
20453
20514
|
let step = 1, tooltip;
|
@@ -20472,7 +20533,8 @@
|
|
20472
20533
|
if (view.state.readOnly || !cState || !cState.open || cState.open.selected < 0 ||
|
20473
20534
|
Date.now() - cState.open.timestamp < view.state.facet(completionConfig).interactionDelay)
|
20474
20535
|
return false;
|
20475
|
-
|
20536
|
+
if (!cState.open.disabled)
|
20537
|
+
applyCompletion(view, cState.open.options[cState.open.selected]);
|
20476
20538
|
return true;
|
20477
20539
|
};
|
20478
20540
|
/**
|
@@ -20677,10 +20739,16 @@
|
|
20677
20739
|
background: "#17c",
|
20678
20740
|
color: "white",
|
20679
20741
|
},
|
20742
|
+
"&light .cm-tooltip-autocomplete-disabled ul li[aria-selected]": {
|
20743
|
+
background: "#777",
|
20744
|
+
},
|
20680
20745
|
"&dark .cm-tooltip-autocomplete ul li[aria-selected]": {
|
20681
20746
|
background: "#347",
|
20682
20747
|
color: "white",
|
20683
20748
|
},
|
20749
|
+
"&dark .cm-tooltip-autocomplete-disabled ul li[aria-selected]": {
|
20750
|
+
background: "#444",
|
20751
|
+
},
|
20684
20752
|
".cm-completionListIncompleteTop:before, .cm-completionListIncompleteBottom:after": {
|
20685
20753
|
content: '"···"',
|
20686
20754
|
opacity: 0.5,
|
@@ -22355,7 +22423,7 @@
|
|
22355
22423
|
}
|
22356
22424
|
let next = input.next, low = 0, high = data[state + 2];
|
22357
22425
|
// Special case for EOF
|
22358
|
-
if (input.next < 0 && high > low && data[accEnd + high * 3 - 3] == 65535 /* End */) {
|
22426
|
+
if (input.next < 0 && high > low && data[accEnd + high * 3 - 3] == 65535 /* End */ && data[accEnd + high * 3 - 3] == 65535 /* End */) {
|
22359
22427
|
state = data[accEnd + high * 3 - 1];
|
22360
22428
|
continue scan;
|
22361
22429
|
}
|
@@ -22363,7 +22431,7 @@
|
|
22363
22431
|
for (; low < high;) {
|
22364
22432
|
let mid = (low + high) >> 1;
|
22365
22433
|
let index = accEnd + mid + (mid << 1);
|
22366
|
-
let from = data[index], to = data[index + 1];
|
22434
|
+
let from = data[index], to = data[index + 1] || 0x10000;
|
22367
22435
|
if (next < from)
|
22368
22436
|
high = mid;
|
22369
22437
|
else if (next >= to)
|
@@ -23334,7 +23402,7 @@
|
|
23334
23402
|
spaceAfterDashes: false,
|
23335
23403
|
slashComments: false,
|
23336
23404
|
doubleQuotedStrings: false,
|
23337
|
-
|
23405
|
+
doubleDollarQuotedStrings: false,
|
23338
23406
|
unquotedBitLiterals: false,
|
23339
23407
|
treatBitsAsBytes: false,
|
23340
23408
|
charSetCasts: false,
|
@@ -23361,7 +23429,7 @@
|
|
23361
23429
|
input.advance();
|
23362
23430
|
input.acceptToken(whitespace);
|
23363
23431
|
}
|
23364
|
-
else if (next == 36 /* Ch.Dollar */ && input.next == 36 /* Ch.Dollar */ && d.
|
23432
|
+
else if (next == 36 /* Ch.Dollar */ && input.next == 36 /* Ch.Dollar */ && d.doubleDollarQuotedStrings) {
|
23365
23433
|
readDoubleDollarLiteral(input);
|
23366
23434
|
input.acceptToken(String$1);
|
23367
23435
|
}
|
@@ -23745,6 +23813,7 @@
|
|
23745
23813
|
static define(spec) {
|
23746
23814
|
let d = dialect(spec, spec.keywords, spec.types, spec.builtin);
|
23747
23815
|
let language = LRLanguage.define({
|
23816
|
+
name: "sql",
|
23748
23817
|
parser: parser.configure({
|
23749
23818
|
tokenizers: [{ from: tokens, to: tokensFor(d) }]
|
23750
23819
|
}),
|
@@ -23764,14 +23833,6 @@
|
|
23764
23833
|
return completeKeywords(dialect.dialect.words, upperCase);
|
23765
23834
|
}
|
23766
23835
|
/**
|
23767
|
-
FIXME remove on 1.0 @internal
|
23768
|
-
*/
|
23769
|
-
function keywordCompletion(dialect, upperCase = false) {
|
23770
|
-
return dialect.language.data.of({
|
23771
|
-
autocomplete: keywordCompletionSource(dialect, upperCase)
|
23772
|
-
});
|
23773
|
-
}
|
23774
|
-
/**
|
23775
23836
|
Returns a completion sources that provides schema-based completion
|
23776
23837
|
for the given configuration.
|
23777
23838
|
*/
|
@@ -23779,27 +23840,6 @@
|
|
23779
23840
|
return config.schema ? completeFromSchema(config.schema, config.tables, config.defaultTable, config.defaultSchema)
|
23780
23841
|
: () => null;
|
23781
23842
|
}
|
23782
|
-
/**
|
23783
|
-
FIXME remove on 1.0 @internal
|
23784
|
-
*/
|
23785
|
-
function schemaCompletion(config) {
|
23786
|
-
return config.schema ? (config.dialect || StandardSQL).language.data.of({
|
23787
|
-
autocomplete: schemaCompletionSource(config)
|
23788
|
-
}) : [];
|
23789
|
-
}
|
23790
|
-
/**
|
23791
|
-
SQL language support for the given SQL dialect, with keyword
|
23792
|
-
completion, and, if provided, schema-based completion as extra
|
23793
|
-
extensions.
|
23794
|
-
*/
|
23795
|
-
function sql(config = {}) {
|
23796
|
-
let lang = config.dialect || StandardSQL;
|
23797
|
-
return new LanguageSupport(lang.language, [schemaCompletion(config), keywordCompletion(lang, !!config.upperCaseKeywords)]);
|
23798
|
-
}
|
23799
|
-
/**
|
23800
|
-
The standard SQL dialect.
|
23801
|
-
*/
|
23802
|
-
const StandardSQL = /*@__PURE__*/SQLDialect.define({});
|
23803
23843
|
const MySQLKeywords = "accessible algorithm analyze asensitive authors auto_increment autocommit avg avg_row_length binlog btree cache catalog_name chain change changed checkpoint checksum class_origin client_statistics coalesce code collations columns comment committed completion concurrent consistent contains contributors convert database databases day_hour day_microsecond day_minute day_second delay_key_write delayed delimiter des_key_file dev_pop dev_samp deviance directory disable discard distinctrow div dual dumpfile enable enclosed ends engine engines enum errors escaped even event events every explain extended fast field fields flush force found_rows fulltext grants handler hash high_priority hosts hour_microsecond hour_minute hour_second ignore ignore_server_ids import index index_statistics infile innodb insensitive insert_method install invoker iterate keys kill linear lines list load lock logs low_priority master master_heartbeat_period master_ssl_verify_server_cert masters max max_rows maxvalue message_text middleint migrate min min_rows minute_microsecond minute_second mod mode modify mutex mysql_errno no_write_to_binlog offline offset one online optimize optionally outfile pack_keys parser partition partitions password phase plugin plugins prev processlist profile profiles purge query quick range read_write rebuild recover regexp relaylog remove rename reorganize repair repeatable replace require resume rlike row_format rtree schedule schema_name schemas second_microsecond security sensitive separator serializable server share show slave slow snapshot soname spatial sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache sql_small_result ssl starting starts std stddev stddev_pop stddev_samp storage straight_join subclass_origin sum suspend table_name table_statistics tables tablespace terminated triggers truncate uncommitted uninstall unlock upgrade use use_frm user_resources user_statistics utc_date utc_time utc_timestamp variables views warnings xa xor year_month zerofill";
|
23804
23844
|
const MySQLTypes = SQLTypes + "bool blob long longblob longtext medium mediumblob mediumint mediumtext tinyblob tinyint tinytext text bigint int1 int2 int3 int4 int8 float4 float8 varbinary varcharacter precision datetime unsigned signed";
|
23805
23845
|
const MySQLBuiltin = "charset clear edit ego help nopager notee nowarning pager print prompt quit rehash source status system tee";
|
@@ -23869,7 +23909,6 @@
|
|
23869
23909
|
}
|
23870
23910
|
const type = 'text/plain';
|
23871
23911
|
let text = window.sqlFetch.result.columns.map((header) => {
|
23872
|
-
console.log(header.includes(delimiter));
|
23873
23912
|
if (typeof header === 'string' && (header.includes('"') || header.includes(delimiter))) {
|
23874
23913
|
return `"${header.replaceAll('"', '""')}"`
|
23875
23914
|
} else {
|
@@ -23912,10 +23951,35 @@
|
|
23912
23951
|
});
|
23913
23952
|
const schemas = Object.entries(window.metadata.schemas);
|
23914
23953
|
const editorSchema = {};
|
23954
|
+
const tables = [];
|
23955
|
+
const hasTableAliases = Object.keys(window.metadata.table_aliases).length > 0;
|
23915
23956
|
schemas.forEach(([schemaName, schema]) => {
|
23916
23957
|
Object.entries(schema.tables).forEach(([tableName, table]) => {
|
23917
23958
|
const qualifiedTableName = schemas.length === 1 ? tableName : `${schemaName}.${tableName}`;
|
23918
|
-
|
23959
|
+
const columns = Object.keys(table.columns);
|
23960
|
+
editorSchema[qualifiedTableName] = columns;
|
23961
|
+
const alias = window.metadata.table_aliases[tableName];
|
23962
|
+
if (alias) {
|
23963
|
+
editorSchema[alias] = columns;
|
23964
|
+
tables.push({
|
23965
|
+
label: qualifiedTableName,
|
23966
|
+
detail: alias,
|
23967
|
+
alias_type: 'with',
|
23968
|
+
quoted: '`' + qualifiedTableName + '` ' + alias,
|
23969
|
+
unquoted: `${qualifiedTableName} ${alias}`
|
23970
|
+
});
|
23971
|
+
tables.push({
|
23972
|
+
label: qualifiedTableName,
|
23973
|
+
detail: alias,
|
23974
|
+
alias_type: 'only',
|
23975
|
+
quoted: '`' + alias + '`',
|
23976
|
+
unquoted: alias
|
23977
|
+
});
|
23978
|
+
} else {
|
23979
|
+
tables.push({
|
23980
|
+
label: qualifiedTableName
|
23981
|
+
});
|
23982
|
+
}
|
23919
23983
|
});
|
23920
23984
|
});
|
23921
23985
|
// I prefer to use Cmd-Enter/Ctrl-Enter to submit the query. Here I am replacing the default mapping.
|
@@ -23948,6 +24012,80 @@
|
|
23948
24012
|
...completionKeymap,
|
23949
24013
|
...lintKeymap
|
23950
24014
|
]);
|
24015
|
+
const sqlConfig = {
|
24016
|
+
dialect: MySQL,
|
24017
|
+
upperCaseKeywords: true,
|
24018
|
+
schema: editorSchema,
|
24019
|
+
tables
|
24020
|
+
};
|
24021
|
+
const scs = schemaCompletionSource(sqlConfig);
|
24022
|
+
const sqlExtension = new LanguageSupport(
|
24023
|
+
MySQL.language,
|
24024
|
+
[
|
24025
|
+
MySQL.language.data.of({
|
24026
|
+
autocomplete: (context) => {
|
24027
|
+
const result = scs(context);
|
24028
|
+
if (!hasTableAliases || !result?.options) return result
|
24029
|
+
|
24030
|
+
const tree = syntaxTree(context.state);
|
24031
|
+
let node = tree.resolveInner(context.pos, -1);
|
24032
|
+
|
24033
|
+
// We are trying to identify the case where we are autocompleting a table name after "from" or "join"
|
24034
|
+
// TODO: we don't handle the case where a user typed "select table.foo from". In that case we probably
|
24035
|
+
// shouldn't autocomplete the alias. Though, if the user typed "select table.foo, t.bar", we won't know
|
24036
|
+
// what to do.
|
24037
|
+
// TODO: if table aliases aren't enabled, we don't need to override autocomplete.
|
24038
|
+
|
24039
|
+
if (node?.name === 'Statement') {
|
24040
|
+
// The node can be a Statement if the cursor is at the end of "from " and there is a complete
|
24041
|
+
// statement in the editor (semicolon present). In that case we want to find the node just before the
|
24042
|
+
// current position so that we can check whether it is "from" or "join".
|
24043
|
+
node = node.childBefore(context.pos);
|
24044
|
+
} else if (node?.name === 'Script') {
|
24045
|
+
// It seems the node can sometimes be a Script if the cursor is at the end of the last statement in the
|
24046
|
+
// editor and the statement doesn't end in a semicolon. In that case we can find the last statement in the
|
24047
|
+
// Script so that we can check whether it is "from" or "join".
|
24048
|
+
node = node.lastChild?.childBefore(context.pos);
|
24049
|
+
} else if (['Identifier', 'QuotedIdentifier', 'Keyword'].includes(node?.name)) {
|
24050
|
+
// If the node is an Identifier, we might be in the middle of typing the table name. If the node is a
|
24051
|
+
// Keyword but isn't "from" or "join", we might be in the middle of typing a table name that is similar
|
24052
|
+
// to a Keyword, for instance "orders" or "selections" or "fromages". In these cases, look for the previous
|
24053
|
+
// sibling so that we can check whether it is "from" or "join".
|
24054
|
+
node = node.prevSibling;
|
24055
|
+
}
|
24056
|
+
|
24057
|
+
const nodeText = node ? context.state.doc.sliceString(node.from, node.to).toLowerCase() : null;
|
24058
|
+
if (node?.name === 'Keyword' && ['from', 'join'].includes(nodeText)) {
|
24059
|
+
result.options = result.options.filter((option) => {
|
24060
|
+
return option.alias_type === undefined || option.alias_type === 'with'
|
24061
|
+
});
|
24062
|
+
} else {
|
24063
|
+
result.options = result.options.filter((option) => {
|
24064
|
+
return option.alias_type === undefined || option.alias_type === 'only'
|
24065
|
+
});
|
24066
|
+
}
|
24067
|
+
result.options = result.options.map((option) => {
|
24068
|
+
// Some shenanigans. If the default autocomplete function quoted the label, we want to ensure the quote
|
24069
|
+
// only applies to the table name and not the alias. You might think we could do this by overriding the
|
24070
|
+
// apply function but apply is set to null when quoting.
|
24071
|
+
// See https://github.com/codemirror/lang-sql/blob/ebf115fffdbe07f91465ccbd82868c587f8182bc/src/complete.ts#L90
|
24072
|
+
if (option.alias_type) {
|
24073
|
+
if (option.label.match(/^`.*`$/)) {
|
24074
|
+
option.apply = option.quoted;
|
24075
|
+
} else {
|
24076
|
+
option.apply = option.unquoted;
|
24077
|
+
}
|
24078
|
+
}
|
24079
|
+
return option
|
24080
|
+
});
|
24081
|
+
return result
|
24082
|
+
}
|
24083
|
+
}),
|
24084
|
+
MySQL.language.data.of({
|
24085
|
+
autocomplete: keywordCompletionSource(MySQL, true)
|
24086
|
+
})
|
24087
|
+
]
|
24088
|
+
);
|
23951
24089
|
window.editorView = new EditorView({
|
23952
24090
|
state: EditorState.create({
|
23953
24091
|
extensions: [
|
@@ -23969,11 +24107,7 @@
|
|
23969
24107
|
highlightActiveLine(),
|
23970
24108
|
highlightSelectionMatches(),
|
23971
24109
|
editorKeymap,
|
23972
|
-
|
23973
|
-
dialect: MySQL,
|
23974
|
-
upperCaseKeywords: true,
|
23975
|
-
schema: editorSchema
|
23976
|
-
}),
|
24110
|
+
sqlExtension,
|
23977
24111
|
fixedHeightEditor,
|
23978
24112
|
placeholder('Let\'s query!')
|
23979
24113
|
]
|
@@ -24161,6 +24295,12 @@
|
|
24161
24295
|
while (tablesElement.firstChild) {
|
24162
24296
|
tablesElement.removeChild(tablesElement.firstChild);
|
24163
24297
|
}
|
24298
|
+
while (columnsElement.firstChild) {
|
24299
|
+
columnsElement.removeChild(columnsElement.firstChild);
|
24300
|
+
}
|
24301
|
+
while (indexesElement.firstChild) {
|
24302
|
+
indexesElement.removeChild(indexesElement.firstChild);
|
24303
|
+
}
|
24164
24304
|
const schemaName = schemasElement.value;
|
24165
24305
|
const schema = window.metadata.schemas[schemaName];
|
24166
24306
|
const tableNames = Object.keys(schema.tables);
|
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.39
|
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-11-
|
11
|
+
date: 2022-11-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: mysql2
|