Skip to content

Commit

Permalink
Add download link for BLOBs
Browse files Browse the repository at this point in the history
  • Loading branch information
yuraj11 committed Jan 20, 2024
1 parent 8f482c1 commit df7b21e
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 32 deletions.
17 changes: 1 addition & 16 deletions css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,10 @@ body {
background: #f5f5f5;
}

.node-info {
font-style: italic;
display: none;
margin: 0;
padding: 0;
}

.drag {
background-color: lightblue;
}

.info-items td {
vertical-align: top;
}

.info-items td:first-child {
width: 90px;
}

#header {
background: #A0CFFF;
color: #3474A8;
Expand All @@ -36,7 +21,7 @@ body {
}

.ace_hidden-cursors {
opacity: 0
opacity: 0;
}

.table-hover tbody tr:hover td, .table-hover tbody tr:hover th {
Expand Down
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ <h4 class="mb-0">SQLite Viewer</h4>
<script src="js/mindmup-editabletable.js"></script>
<script src="js/jszip.min.js"></script>
<script src="js/FileSaver.min.js"></script>
<script src="js/main.js?v=16"></script>
<script src="js/main.js?v=17"></script>

</body>
</html>
85 changes: 70 additions & 15 deletions js/main.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"use strict";

const SQL_WASM_PATH = "https://inloop.github.io/sqlite-viewer/js/sql-wasm.wasm";

const SQL_FROM_REGEX = /FROM\s+((?=['"])((["'])(?<g1>[^'"]+))|(?<g2>\w+))/mi;
Expand All @@ -15,7 +17,8 @@ const selectFormatter = function (item) {
const index = item.text.indexOf("(");
if (index > -1) {
const name = item.text.substring(0, index);
return $(`<span>${name}<span style="color:#ccc">${item.text.substring(index - 1)}</span></span>`);
const tableName = item.text.substring(index - 1);
return $(`<span>${name}<span style="color:#ccc">${tableName}</span></span>`);
} else {
return item.text;
}
Expand All @@ -26,7 +29,7 @@ initialize();
function initialize() {
let fileReaderOpts = {
readAsDefault: "ArrayBuffer", on: {
load: function (e, file) {
load: function (e) {
loadDB(e.target.result);
}
}
Expand Down Expand Up @@ -98,13 +101,16 @@ function loadDB(arrayBuffer) {
resetTableList();

initSqlJs({locateFile: file => SQL_WASM_PATH}).then(function (SQL) {
let tables;
let tables = null;
try {
db = new SQL.Database(new Uint8Array(arrayBuffer));

//Get all table names from master table
tables = db.prepare("SELECT * FROM sqlite_master WHERE type='table' OR type='view' ORDER BY name");
} catch (ex) {
if (tables !== null) {
tables.free();
}
setIsLoading(false);
window.alert(ex);
return;
Expand All @@ -126,6 +132,7 @@ function loadDB(arrayBuffer) {
const tableType = type !== "table" ? `, ${type}` : "";
tableList.append(`<option value="${name}">${name} (${rowCount} rows${tableType})</option>`);
}
tables.free();

//Select first table and show It
tableList.val(firstTableName);
Expand All @@ -144,8 +151,11 @@ function loadDB(arrayBuffer) {
function getTableRowsCount(name) {
const sel = db.prepare(`SELECT COUNT(*) AS count FROM '${name}'`);
if (sel.step()) {
return sel.getAsObject()["count"];
const count = sel.getAsObject()["count"];
sel.free();
return count;
} else {
sel.free();
return -1;
}
}
Expand All @@ -162,12 +172,14 @@ function getQueryRowCount(query) {
const sel = db.prepare(queryReplaced);
if (sel.step()) {
const count = sel.getAsObject()["count"];
sel.free();

lastCachedQueryCount.select = query;
lastCachedQueryCount.count = count;

return count;
} else {
sel.free();
return -1;
}
} else {
Expand All @@ -176,19 +188,21 @@ function getQueryRowCount(query) {
}

function getTableColumnTypes(tableName) {
let result = [];
let result = new Map();
const sel = db.prepare(`PRAGMA table_info('${tableName}')`);

while (sel.step()) {
const obj = sel.getAsObject();
result[obj.name] = obj["type"];
let type = obj["type"];
if (obj["notnull"] === 1) {
result[obj.name] += " NOT NULL";
type += " NOT NULL";
}
if (obj["pk"] === 1) {
result[obj.name] += " PRIMARY KEY";
type += " PRIMARY KEY";
}
result.set(obj.name, type);
}
sel.free();

return result;
}
Expand Down Expand Up @@ -284,7 +298,7 @@ function setPage(el, next) {
const query = editor.getValue();
const limit = parseLimitFromQuery(query);

let pageToSet;
let pageToSet = 0;
if (typeof next !== "undefined") {
pageToSet = (next ? limit.currentPage : limit.currentPage - 2);
} else {
Expand Down Expand Up @@ -362,24 +376,27 @@ function renderQuery(query) {
infoBox.hide();
dataBox.show();

let columnTypes = [];
let columnTypes = new Map();
const tableName = getTableNameFromQuery(query);
if (tableName != null) {
columnTypes = getTableColumnTypes(tableName);
}

let sel;
let sel = null;
try {
sel = db.prepare(query);
} catch (ex) {
if (sel != null) {
sel.free();
}
showError(ex);
return;
}

let isEmptyTable = true;
const columnNames = sel.getColumnNames();
for (let i = 0; i < columnNames.length; i++) {
const type = columnTypes[columnNames[i]];
const type = columnTypes.get(columnNames[i]);
thead.append(`<th><span data-bs-toggle="tooltip" title="${type}">${columnNames[i]}</span></th>`);
}

Expand All @@ -388,11 +405,21 @@ function renderQuery(query) {
const tr = $('<tr>');
const s = sel.get();
for (let i = 0; i < s.length; i++) {
let value = htmlEncode(s[i]);
tr.append(`<td><span title="${value}">${value}</span></td>`);
const type = columnTypes.get(columnNames[i]).toLowerCase();
if (type === "blob" || type === "blob sub_type binary") {
if (s[i] === null) {
tr.append(`<td><span title="Blob">null</span></td>`);
} else {
renderBlobItem(tr, s[i]);
}
} else {
let value = htmlEncode(s[i]);
tr.append(`<td><span title="${value}">${value}</span></td>`);
}
}
tbody.append(tr);
}
sel.free();

if (isEmptyTable) {
infoBox.text("No data for given select.");
Expand All @@ -408,6 +435,30 @@ function renderQuery(query) {
dataBox.editableTableWidget();
}

function renderBlobItem(tr, bytes) {
const td = document.createElement("td");
const span = document.createElement("span");
span.title = "Blob";
const downloadLink = document.createElement("a");
downloadLink.href = "javascript:void(0)";
downloadLink.innerText = `Download (${formatBytes(bytes.length)})`;
downloadLink.onclick = function () {
saveAs(new Blob([bytes]), "blob");
};
span.append(downloadLink);
td.append(span);
tr.append(td);
}

function formatBytes(bytes,decimals) {
if(bytes === 0) return '0 Bytes';
const k = 1024,
dm = decimals || 2,
sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],
i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
}

function onKeyDown(e) {
if ((e.ctrlKey || e.metaKey) && e.key === "Enter") {
executeSql();
Expand All @@ -425,10 +476,13 @@ function arrayToCsv(data) {

function exportCsvTableQuery(query) {
let exportedRows = [];
let sel;
let sel = null;
try {
sel = db.prepare(query);
} catch (ex) {
if (sel != null) {
sel.free();
}
showError(ex);
setIsLoading(false);
return null;
Expand All @@ -441,6 +495,7 @@ function exportCsvTableQuery(query) {
const rows = sel.get();
exportedRows.push(...[rows]);
}
sel.free();
return exportedRows;
}

Expand Down

0 comments on commit df7b21e

Please sign in to comment.