Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ target 'SQLiteViewer' do
use_frameworks!

# Pods for SQLiteViewer
pod 'Http.swift', '~> 2.1'
pod 'Http.swift', '~> 2.2.1'
pod 'SQLite.swift', '~> 0.11.5'

target 'SQLiteViewerTests' do
Expand Down
2 changes: 1 addition & 1 deletion SQLite.viewer.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ Pod::Spec.new do |s|
s.source_files = 'Sources/*.swift'
s.resource_bundles = { 'com.biatoms.sqlite-viewer.assets' => ['Sources/**/*.{js,css,ico,html}'] }

s.dependency 'Http.swift', '~> 2.1.1'
s.dependency 'Http.swift', '~> 2.2.1'
s.dependency 'SQLite.swift', '>= 0.11.5'
end
62 changes: 62 additions & 0 deletions Sources/Assets/css/app.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#query-container {
position: fixed;
left: 0px;
top: 0px;
width: 100%;
height: 50px;
z-index: 2;
background: white;
}
#query-container>div {
display: flex;
vertical-align: middle;
}
#query-container>div>textarea {
flex-grow: 1;
min-width: 50%;
}
.row {
margin: 50px 0 0;
display: grid;
grid-template-columns: 1fr 1fr 8fr;
gap: 10px;
}
.row>div.databases {
grid-area: 1/1/1/1;
}
.row>div.tables {
grid-area: 1/2/1/2;
}
.row>div.data {
grid-area: 1/3/1/3;
}
table thead {
position: sticky;
top: 50px;
z-index: 1;
}
table thead td, table thead th {
background: white;
}
table tr td {
position: relative;
}
table tr td .edit-item {
opacity: 0;
position: absolute;
top: 0px;
right: 0px;
}
table tr:hover td .edit-item {
opacity: 1;
}
table tbody td span {
display: inline-block;
}
table tbody td.is-long span {
width: 50vw;
word-break: break-all;
}
table tbody td.is-null {
color: gray;
}
19 changes: 8 additions & 11 deletions Sources/Assets/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,36 +8,34 @@
<script src="bootstrap.min.js"></script>
<script src="flash-alert.min.js"></script>
<script src="api.js"></script>
<script src="app.js"></script>
<link rel="stylesheet" href="css/app.css" type="text/css">
</head>
<body>
<form>
<form id="query-container">
<div class="form-small">
<div>
<textarea id="query" style="width: 50%"></textarea>
</div>
<textarea id="query" placeholder="Type in your SQL query and click Run query"></textarea>
<button type="button" class="btn btn-primary" onclick="executeQuery($('#query').val())">Run query</button>
</div>
</form>
<div>
<button type="button" class="btn btn-primary" onclick="download()">Download database</button>
</div>
<div class="row">
<div class="col-sm-2">
<div class="databases">
<div class="panel panel-default">
<div class="panel-heading">Databases</div>
</div>
<div id="db-list" class="list-group">
</div>
<button type="button" class="btn btn-primary" onclick="download()">Download database</button>
</div>
<div class="col-sm-2">
<div class="tables">
<div class="panel panel-default">
<div class="panel-heading">Tables</div>
</div>
<div id="table-list" class="list-group">
</div>
</div>

<div class="col-sm-8">
<div class="data">
<div class="panel panel-default">
<div class="panel-heading">Data</div>
</div>
Expand All @@ -46,6 +44,5 @@
</div>
</div>
</div>
<script src="app.js"></script>
</body>
</html>
43 changes: 33 additions & 10 deletions Sources/Assets/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,11 @@ function refreshTableList() {
function refreshTableData() {
$('#table-data').empty();
Api.getTableData(currentDatabase, currentTable, function (data) {
displayTable(data);
displayTable(data, currentTable);
})
}

function displayTable(data) {
function displayTable(data, tablename) {
var elem = $('#table-data');
elem.empty();
var table = $('<table class="table"/>');
Expand All @@ -78,28 +78,51 @@ function displayTable(data) {
data.rows.forEach(function (row) {
var rowElem = $('<tr/>');
tableBody.append(rowElem);
row.forEach(function (data) {
rowElem.append($('<td/>').text(data));
row.forEach(function (value, index) {
let origValue = value;
if (data.blobs.indexOf(index) !== -1 && value) {
value = 'blob: ' + value;
}
let cell = $('<td/>').append($('<span>').text(value ?? 'null'));
if (value == null) {
cell.addClass('is-null');
} else if (value?.length > 200) {
cell.addClass('is-long');
}
rowElem.append(cell);
if (tablename && data.columns[0] === 'Z_PK') {
// This is a CoreData helper
cell.append($('<a>').addClass('edit-item').text('edit').attr('href', '#').on('click', function(e) {
$('#query').val('UPDATE '+tablename+' SET '+data.columns[index]+' = \''+escapeSqlite(origValue)+'\' WHERE '+data.columns[0]+' = \''+escapeSqlite(row[0])+'\'');
message('SQL updated');
e.preventDefault(true);
e.stopPropagation(true);
return false;
}));
}
})
});
}

function escapeSqlite(string) {
return (''+string).replace(/'/g, '\'\'');
}

function executeQuery(query) {
Api.executeQuery(currentDatabase, query, function (data) {
if (data.hasOwnProperty('affected_rows')) {
message(data.affected_rows + " rows are affected.");
message(data.affected_rows + ' rows are affected.');
} else {
displayTable(data);
message("Query completed.");
message('Query completed.');
}
});
}

function download() {
Api.downloadDatabase(currentDatabase, function() {
message(currentDatabase + " is downloaded.")
message(currentDatabase + ' is downloaded.');
});
}

init();
$(document).ready(function () {
init();
})
18 changes: 16 additions & 2 deletions Sources/DatabaseController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,24 @@ open class DatabaseController {
func toArray<S: Sequence>(_ elements: S) -> Array<S.Element> { // resolves ambiguity
return Array(elements)
}

var blobs: [Int] = []
var rows = toArray(statement)
if !JSONSerialization.isValidJSONObject(rows) {
for (rowIndex, row) in rows.enumerated() {
for (cellIndex, cell) in row.enumerated() {
if let cellBlob = cell as? SQLite.Blob {
if !blobs.contains(cellIndex) {
blobs.append(cellIndex)
}
rows[rowIndex][cellIndex] = Data(cellBlob.bytes).base64EncodedString()
}
}
}
}
return [
"columns": statement.columnNames,
"rows": toArray(statement)
"blobs": blobs,
"rows": rows
]
}
}
2 changes: 1 addition & 1 deletion Sources/SQLiteViewer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import HttpSwift
import SQLite

open class SQLiteViewer {
open static var shared = SQLiteViewer()
public static var shared = SQLiteViewer()

public var assetDir: String = ""
public var dbDir: String = "" {
Expand Down