Skip to content

Commit ff828b1

Browse files
committed
chore: Initial commit
1 parent a58de04 commit ff828b1

File tree

6 files changed

+640
-0
lines changed

6 files changed

+640
-0
lines changed

dropzone.min.css

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dropzone.min.js

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

gui.js

+206
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
const execBtn = document.getElementById("execute");
2+
const outputElm = document.getElementById('output');
3+
const errorElm = document.getElementById('error');
4+
const commandsElm = document.getElementById('commands');
5+
const dbFileElm = document.getElementById('dbfile');
6+
const savedbElm = document.getElementById('savedb');
7+
const querySection = document.getElementById('query');
8+
const uploadSection = document.getElementById('dropzone');
9+
10+
// Start the worker in which sql.js will run
11+
const worker = new Worker("worker.sql-wasm.js");
12+
worker.onerror = error;
13+
14+
// Open a database
15+
worker.postMessage({ action: 'open' });
16+
17+
// Connect to the HTML element we 'print' to
18+
function print(text) {
19+
outputElm.innerHTML = text.replace(/\n/g, '<br>');
20+
}
21+
22+
function error(e) {
23+
console.log(e);
24+
errorElm.classList.remove('visually-hidden');
25+
errorElm.classList.add('alert', 'alert-danger');
26+
errorElm.textContent = e.message;
27+
}
28+
29+
function noerror() {
30+
errorElm.classList.add('visually-hidden');
31+
errorElm.classList.remove('alert', 'alert-danger');
32+
}
33+
34+
// Run a command in the database
35+
function execute(commands) {
36+
tic();
37+
worker.onmessage = function (event) {
38+
var results = event.data.results;
39+
40+
toc("Executing SQL");
41+
if (!results) {
42+
error({message: event.data.error});
43+
return;
44+
}
45+
46+
tic();
47+
outputElm.innerHTML = "";
48+
for (var i = 0; i < results.length; i++) {
49+
outputElm.appendChild(tableCreate(results[i].columns, results[i].values));
50+
}
51+
toc("Displaying results");
52+
}
53+
worker.postMessage({ action: 'exec', sql: commands });
54+
outputElm.textContent = "Fetching results...";
55+
}
56+
57+
// Create an HTML table
58+
var tableCreate = function () {
59+
function valconcat(vals, tagName) {
60+
if (vals.length === 0) return '';
61+
var open = '<' + tagName + '>', close = '</' + tagName + '>';
62+
return open + vals.join(close + open) + close;
63+
}
64+
return function (columns, values) {
65+
var tbl = document.createElement('table');
66+
tbl.classList.add('table', 'table-hover')
67+
var html = '<thead>' + valconcat(columns, 'th') + '</thead>';
68+
var rows = values.map(function (v) { return valconcat(v, 'td'); });
69+
html += '<tbody>' + valconcat(rows, 'tr') + '</tbody>';
70+
tbl.innerHTML = html;
71+
return tbl;
72+
}
73+
}();
74+
75+
// Execute the commands when the button is clicked
76+
function execEditorContents() {
77+
noerror()
78+
execute(editor.getValue() + ';');
79+
}
80+
execBtn.addEventListener("click", execEditorContents, true);
81+
82+
// Performance measurement functions
83+
var tictime;
84+
if (!window.performance || !performance.now) { window.performance = { now: Date.now } }
85+
function tic() { tictime = performance.now() }
86+
function toc(msg) {
87+
var dt = performance.now() - tictime;
88+
console.log((msg || 'toc') + ": " + dt + "ms");
89+
}
90+
91+
// Add syntax highlihjting to the textarea
92+
var editor = CodeMirror.fromTextArea(commandsElm, {
93+
mode: 'text/x-sql',
94+
viewportMargin: Infinity,
95+
autofocus: true,
96+
indentWithTabs: true,
97+
smartIndent: true,
98+
lineNumbers: true,
99+
matchBrackets: true,
100+
autofocus: true,
101+
extraKeys: {
102+
"Ctrl-Enter": execEditorContents,
103+
"Ctrl-S": savedb,
104+
}
105+
});
106+
107+
// Load a db from a file
108+
var dbFile = new FileReader();
109+
var defaultQuery = "SELECT `name`, `sql`\n FROM `sqlite_master`\n WHERE type='table';"
110+
111+
dbFile.onload = function () {
112+
worker.onmessage = function () {
113+
toc("Loading database from file");
114+
// Show the schema of the loaded database
115+
editor.setValue(localStorage.getItem('lastQuery') || defaultQuery);
116+
execEditorContents();
117+
118+
uploadSection.classList.add('visually-hidden');
119+
querySection.classList.remove('visually-hidden');
120+
noerror();
121+
};
122+
tic();
123+
try {
124+
worker.postMessage({ action: 'open', buffer: dbFile.result }, [dbFile.result]);
125+
}
126+
catch (exception) {
127+
worker.postMessage({ action: 'open', buffer: dbFile.result });
128+
}
129+
}
130+
131+
132+
function init() {
133+
let dropzoneElement = new Dropzone("#demo-upload");
134+
135+
136+
dropzoneElement.uploadFiles = function(files) {
137+
var self = this,
138+
minSteps = 6,
139+
maxSteps = 60,
140+
timeBetweenSteps = 1,
141+
bytesPerStep = 1000000;
142+
143+
for (var i = 0; i < files.length; i++) {
144+
145+
var file = files[i];
146+
totalSteps = Math.round(Math.min(maxSteps, Math.max(minSteps, file.size / bytesPerStep)));
147+
148+
for (var step = 0; step < totalSteps; step++) {
149+
var duration = timeBetweenSteps * (step + 1);
150+
setTimeout(function(file, totalSteps, step) {
151+
return function() {
152+
file.upload = {
153+
progress: 100 * (step + 1) / totalSteps,
154+
total: file.size,
155+
bytesSent: (step + 1) * file.size / totalSteps
156+
};
157+
158+
self.emit('uploadprogress', file, file.upload.progress, file.upload.bytesSent);
159+
if (file.upload.progress == 100) {
160+
file.status = Dropzone.SUCCESS;
161+
self.emit("success", file, 'success', null);
162+
self.emit("complete", file);
163+
self.processQueue();
164+
}
165+
};
166+
}(file, totalSteps, step), duration);
167+
}
168+
dbFile.readAsArrayBuffer(files[0]);
169+
}
170+
}
171+
172+
function saveQuery(e) {
173+
if (e.getValue()) {
174+
localStorage.setItem('lastQuery', e.getValue());
175+
}
176+
}
177+
178+
editor.setValue(localStorage.getItem('lastQuery') || defaultQuery);
179+
editor.on("changes", saveQuery);
180+
}
181+
182+
Dropzone.autoDiscover = false;
183+
document.addEventListener("DOMContentLoaded", init);
184+
185+
// Save the db to a file
186+
function savedb() {
187+
worker.onmessage = function (event) {
188+
toc("Exporting the database");
189+
var arraybuff = event.data.buffer;
190+
var blob = new Blob([arraybuff]);
191+
var a = document.createElement("a");
192+
document.body.appendChild(a);
193+
a.href = window.URL.createObjectURL(blob);
194+
a.download = "sql.db";
195+
a.onclick = function () {
196+
setTimeout(function () {
197+
window.URL.revokeObjectURL(a.href);
198+
}, 1500);
199+
};
200+
a.click();
201+
};
202+
tic();
203+
worker.postMessage({ action: 'export' });
204+
}
205+
206+
savedbElm.addEventListener("click", savedb, true);

sql-wasm.wasm

1.08 MB
Binary file not shown.

sql.html

+137
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
<!doctype html>
2+
<html>
3+
4+
<head>
5+
<meta charset="utf-8">
6+
<meta name="viewport" content="width=device-width, initial-scale=1">
7+
<title>משחקים ב־SQL</title>
8+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.1/codemirror.css">
9+
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/5.0.0-alpha2/css/bootstrap.min.css" integrity="sha384-DhY6onE6f3zzKbjUPRc2hOzGAdEf4/Dz+WJwBvEYL/lkkIsI3ihufq9hk9K4lVoK" crossorigin="anonymous">
10+
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.1/codemirror.js"></script>
11+
<style>
12+
h1, h2 h3, p, form, main, footer {
13+
direction: rtl;
14+
text-align: right;
15+
}
16+
17+
textarea, #code-section, table, table * {
18+
direction: ltr;
19+
text-align: left;
20+
}
21+
22+
#results table {
23+
width: 100%;
24+
}
25+
26+
h1, h2, h3 {
27+
text-align: center;
28+
margin-top: 1.5rem;
29+
margin-bottom: 1.5rem;
30+
}
31+
32+
footer {
33+
position: fixed;
34+
left: 0;
35+
bottom: 0;
36+
padding: 0.5rem;
37+
width: 100%;
38+
text-align: center;
39+
background: #aaa;
40+
color: white;
41+
margin-top: 2em;
42+
text-decoration: white;
43+
}
44+
45+
footer > a:link {
46+
color: white;
47+
}
48+
49+
footer > a:visited {
50+
color: #d9d9d9;
51+
}
52+
53+
.dropzone {
54+
align-items: center;
55+
background: white;
56+
border-radius: 5px !important;
57+
border: 2px dashed #0087f7 !important;
58+
display: flex;
59+
justify-content: center;
60+
min-height: 30vh !important;
61+
}
62+
63+
#dropzone {
64+
width: 60%;
65+
height: 60%;
66+
margin-right: auto;
67+
margin-left: auto;
68+
margin-top: 5%;
69+
}
70+
71+
#buttons {
72+
margin: 1rem;
73+
margin-left: auto;
74+
margin-right: auto;
75+
padding: 0.5rem;
76+
width: max-content;
77+
}
78+
79+
#error {
80+
width: 60%;
81+
margin-top: 3rem;
82+
margin-left: auto;
83+
margin-right: auto;
84+
text-align: left;
85+
}
86+
87+
#results {
88+
margin-bottom: 3rem;
89+
}
90+
</style>
91+
<link rel="stylesheet" href="dropzone.min.css">
92+
</head>
93+
<body>
94+
<div class="container">
95+
<h1>הריצו את ה־SQL שלכם</h1>
96+
97+
<main>
98+
<div id="dropzone">
99+
<form action="/upload" class="dropzone needsclick dz-clickable" id="demo-upload">
100+
<div class="dz-message needsclick">
101+
<button type="button" name='file' id='dbfile' class="dz-button">גררו לכאן את קובץ מסד הנתונים, או לחצו ובחרו אותו מהמחשב שלכם.</button>
102+
</div>
103+
</form>
104+
</div>
105+
<div id="query" class="visually-hidden">
106+
<label for='commands'>הזינו שאילתה:</label>
107+
<br>
108+
109+
<div id="code-section">
110+
<textarea id="commands">SELECT * FROM movies;</textarea>
111+
</div>
112+
113+
114+
<div id="buttons">
115+
<button id="execute" class="btn btn-primary">הריצו</button>
116+
<button id='savedb' class="btn btn-secondary">שמרו</button>
117+
</div>
118+
</div>
119+
120+
<div id="results">
121+
<div id="error" class="error" role="alert"></div>
122+
<pre id="output"></pre>
123+
</div>
124+
</main>
125+
126+
127+
<footer>
128+
אנחנו משתמשים ב־<a href='https://github.com/sql-js/sql.js'>sql.js</a> כמנוע.
129+
רוב ה־GUI נכתב על־ידי ים מסיקה, עבור קורס פייתון (<a href='https://github.com/PythonFreeCourse/sql-js-gui'>sql-js-gui</a>).
130+
</footer>
131+
132+
</div>
133+
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.1/mode/sql/sql.min.js"></script>
134+
<script type="text/javascript" src="dropzone.min.js"></script>
135+
<script type="text/javascript" src="gui.js"></script>
136+
</body>
137+
</html>

0 commit comments

Comments
 (0)