SQLite Explorer (Dev Branch)

View and interact with your Val Town SQLite data. It's based off Steve's excellent SQLite Admin val, adding the ability to run SQLite queries directly in the interface. This new version has a revised UI and that's heavily inspired by LibSQL Studio by invisal. This is now more an SPA, with tables, queries and results showing up on the same page.

image.webp

Install

Install the latest stable version (v81) by forking this val:

Install Stable Release (v81)

Authentication

Login to your SQLite Explorer with password authentication with your Val Town API Token as the password.

Todos / Plans

  • improve error handling
  • improve table formatting
  • sticky table headers
  • add codemirror
  • add loading indication to the run button (initial version shipped)
  • add ability to favorite queries
  • add saving of last query run for a table (started)
  • add visible output for non-query statements
  • add schema viewing
  • add refresh to table list sidebar after CREATE/DROP/ALTER statements
  • add automatic execution of initial select query on double click
  • add views to the sidebar
  • add triggers to sidebar
  • add upload from SQL, CSV and JSON
  • add ability to connect to a non-val town Turso database
  • fix wonky sidebar separator height problem (thanks to @stevekrouse)
  • make result tables scrollable
  • add export to CSV, and JSON (CSV and JSON helper functions written in this val. Thanks to @pomdtr for merging the initial version!)
  • add listener for cmd+enter to submit query
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/** @jsxImportSource https://esm.sh/hono@latest/jsx **/
import { modifyFetchHandler } from "https://esm.town/v/andreterron/codeOnValTown?v=50";
import { iframeHandler } from "https://esm.town/v/nbbaier/iframeHandler";
import { resetStyle } from "https://esm.town/v/nbbaier/resetStyle";
import { sqlToCSV, sqlToJSON } from "https://esm.town/v/nbbaier/sqliteExportHelpers";
import {
EditorSection,
MockTable,
Separator,
Table,
TablesList,
} from "https://esm.town/v/nbbaier/sqliteStudioComponents";
import { sqliteStyle } from "https://esm.town/v/nbbaier/sqliteStyle";
import { passwordAuth } from "https://esm.town/v/pomdtr/password_auth?v=70";
import { ResultSet, sqlite } from "https://esm.town/v/std/sqlite";
import { reloadOnSaveFetchMiddleware } from "https://esm.town/v/stevekrouse/reloadOnSave";
import { Hono } from "npm:hono";
import type { FC } from "npm:hono/jsx";
import { jsxRenderer } from "npm:hono/jsx-renderer";
import papa from "npm:papaparse";
const HTML: FC = ({ children }) => {
return (
<html>
<head>
<title>SQLite Explorer</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@300..700&family=Source+Sans+3:ital,wght@0,200..900;1,200..900&display=swap"
rel="stylesheet"
/>
<style
dangerouslySetInnerHTML={{ __html: resetStyle }}
/>
<style
dangerouslySetInnerHTML={{ __html: sqliteStyle }}
/>
<script src="https://unpkg.com/htmx.org@1.9.9/dist/htmx.min.js"></script>
<script src="https://unpkg.com/hyperscript.org@0.9.12"></script>
<script type="module" src="https://esm.town/v/nbbaier/resizeScript" />
<script type="module" src="https://esm.town/v/nbbaier/tableSelectScript" />
<script
type="module"
src="https://raw.esm.sh/code-mirror-web-component@0.0.20/dist/code-mirror.js"
>
</script>
</head>
<body _="
on keydown[event.metaKey and key is 'Enter'] log 'command + enter' then send submitForm to #sql-editor
">
<div class="root-container">
<header>
<h1>SQLite Explorer</h1>
</header>
{children}
</div>
<script type="module" src="https://esm.town/v/nbbaier/downloadScript" />
<script type="module" src="https://esm.town/v/nbbaier/enableButtonsScript" />
<script type="module" src="https://esm.town/v/nbbaier/getCodeScript" />
</body>
</html>
);
};
const app = new Hono();
app.use(
"*",
jsxRenderer(
({ children }) => {
return <HTML children={children} />;
},
{ docType: false },
),
);
app.get("/", async (c) => {
let data = await sqlite.batch(
[
`SELECT name FROM sqlite_schema WHERE type ='table' AND name NOT LIKE 'sqlite_%';`,
`SELECT name FROM sqlite_schema WHERE type ='view' AND name NOT LIKE 'sqlite_%';`,
],
);
let views = data[1].rows.map(view => {
return { type: "view", name: view[0] };
});
let tables = data[0].rows.map(view => {
return { type: "table", name: view[0] };
});
return c.render(
<main class="sidebar-layout">
<div class="sidebar">
<TablesList tables={[...tables, ...views]}></TablesList>

SQLite Explorer (Dev Branch)

View and interact with your Val Town SQLite data. It's based off Steve's excellent SQLite Admin val, adding the ability to run SQLite queries directly in the interface. This new version has a revised UI and that's heavily inspired by LibSQL Studio by invisal. This is now more an SPA, with tables, queries and results showing up on the same page.

image.webp

Install

Install the latest stable version (v81) by forking this val:

Install Stable Release (v81)

Authentication

Login to your SQLite Explorer with password authentication with your Val Town API Token as the password.

Todos / Plans

  • improve error handling
  • improve table formatting
  • sticky table headers
  • add codemirror
  • add loading indication to the run button (initial version shipped)
  • add ability to favorite queries
  • add saving of last query run for a table (started)
  • add visible output for non-query statements
  • add schema viewing
  • add refresh to table list sidebar after CREATE/DROP/ALTER statements
  • add automatic execution of initial select query on double click
  • add views to the sidebar
  • add triggers to sidebar
  • add upload from SQL, CSV and JSON
  • add ability to connect to a non-val town Turso database
  • fix wonky sidebar separator height problem (thanks to @stevekrouse)
  • make result tables scrollable
  • add export to CSV, and JSON (CSV and JSON helper functions written in this val. Thanks to @pomdtr for merging the initial version!)
  • add listener for cmd+enter to submit query
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/** @jsxImportSource https://esm.sh/hono@latest/jsx **/
import { modifyFetchHandler } from "https://esm.town/v/andreterron/codeOnValTown?v=50";
import { iframeHandler } from "https://esm.town/v/nbbaier/iframeHandler";
import { resetStyle } from "https://esm.town/v/nbbaier/resetStyle";
import { sqlToCSV, sqlToJSON } from "https://esm.town/v/nbbaier/sqliteExportHelpers";
import {
EditorSection,
MockTable,
Separator,
Table,
TablesList,
} from "https://esm.town/v/nbbaier/sqliteStudioComponents";
import { sqliteStyle } from "https://esm.town/v/nbbaier/sqliteStyle";
import { passwordAuth } from "https://esm.town/v/pomdtr/password_auth?v=70";
import { ResultSet, sqlite } from "https://esm.town/v/std/sqlite";
import { reloadOnSaveFetchMiddleware } from "https://esm.town/v/stevekrouse/reloadOnSave";
import { Hono } from "npm:hono";
import type { FC } from "npm:hono/jsx";
import { jsxRenderer } from "npm:hono/jsx-renderer";
import papa from "npm:papaparse";
const HTML: FC = ({ children }) => {
return (
<html>
<head>
<title>SQLite Explorer</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@300..700&family=Source+Sans+3:ital,wght@0,200..900;1,200..900&display=swap"
rel="stylesheet"
/>
<style
dangerouslySetInnerHTML={{ __html: resetStyle }}
/>
<style
dangerouslySetInnerHTML={{ __html: sqliteStyle }}
/>
<script src="https://unpkg.com/htmx.org@1.9.9/dist/htmx.min.js"></script>
<script src="https://unpkg.com/hyperscript.org@0.9.12"></script>
<script type="module" src="https://esm.town/v/nbbaier/resizeScript" />
<script type="module" src="https://esm.town/v/nbbaier/tableSelectScript" />
<script
type="module"
src="https://raw.esm.sh/code-mirror-web-component@0.0.20/dist/code-mirror.js"
>
</script>
</head>
<body _="
on keydown[event.metaKey and key is 'Enter'] log 'command + enter' then send submitForm to #sql-editor
">
<div class="root-container">
<header>
<h1>SQLite Explorer</h1>
</header>
{children}
</div>
<script type="module" src="https://esm.town/v/nbbaier/downloadScript" />
<script type="module" src="https://esm.town/v/nbbaier/enableButtonsScript" />
<script type="module" src="https://esm.town/v/nbbaier/getCodeScript" />
</body>
</html>
);
};
const app = new Hono();
app.use(
"*",
jsxRenderer(
({ children }) => {
return <HTML children={children} />;
},
{ docType: false },
),
);
app.get("/", async (c) => {
let data = await sqlite.batch(
[
`SELECT name FROM sqlite_schema WHERE type ='table' AND name NOT LIKE 'sqlite_%';`,
`SELECT name FROM sqlite_schema WHERE type ='view' AND name NOT LIKE 'sqlite_%';`,
],
);
let views = data[1].rows.map(view => {
return { type: "view", name: view[0] };
});
let tables = data[0].rows.map(view => {
return { type: "table", name: view[0] };
});
return c.render(
<main class="sidebar-layout">
<div class="sidebar">
<TablesList tables={[...tables, ...views]}></TablesList>

SQLite Explorer (Dev Branch)

View and interact with your Val Town SQLite data. It's based off Steve's excellent SQLite Admin val, adding the ability to run SQLite queries directly in the interface. This new version has a revised UI and that's heavily inspired by LibSQL Studio by invisal. This is now more an SPA, with tables, queries and results showing up on the same page.

image.webp

Install

Install the latest stable version (v66) by forking this val:

Install v66

Authentication

Login to your SQLite Explorer with password authentication with your Val Town API Token as the password.

Todos / Plans

  • improve error handling
  • improve table formatting
  • sticky table headers
  • add codemirror
  • add loading indication to the run button (initial version shipped)
  • add ability to favorite queries
  • add saving of last query run for a table (started)
  • add visible output for non-query statements
  • add schema viewing
  • add refresh to table list sidebar after CREATE/DROP/ALTER statements
  • add automatic execution of initial select query on double click
  • add views to the sidebar
  • add triggers to sidebar
  • add upload from SQL, CSV and JSON
  • add ability to connect to a non-val town Turso database
  • fix wonky sidebar separator height problem (thanks to @stevekrouse)
  • make result tables scrollable
  • add export to CSV, and JSON (CSV and JSON helper functions written in this val. Thanks to @pomdtr for merging the initial version!)
  • add listener for cmd+enter to submit query
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/** @jsxImportSource https://esm.sh/hono@latest/jsx **/
import { modifyFetchHandler } from "https://esm.town/v/andreterron/codeOnValTown?v=50";
import { resetStyle } from "https://esm.town/v/nbbaier/resetStyle";
import { sqlToCSV, sqlToJSON } from "https://esm.town/v/nbbaier/sqliteExportHelpers";
import {
EditorSection,
MockTable,
Separator,
Table,
TablesList,
} from "https://esm.town/v/nbbaier/sqliteStudioComponents_DEV";
import { sqliteStyle } from "https://esm.town/v/nbbaier/sqliteStyle_DEV";
import { passwordAuth } from "https://esm.town/v/pomdtr/password_auth?v=70";
import { Statement } from "https://esm.town/v/postpostscript/sqliteBuilder";
import { ResultSet, sqlite } from "https://esm.town/v/std/sqlite";
import { reloadOnSaveFetchMiddleware } from "https://esm.town/v/stevekrouse/reloadOnSave";
import { Hono } from "npm:hono";
import type { FC } from "npm:hono/jsx";
import { jsxRenderer } from "npm:hono/jsx-renderer";
import papa from "npm:papaparse";
const HTML: FC = ({ children }) => {
return (
<html>
<head>
<title>SQLite Explorer (dev)</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@300..700&family=Source+Sans+3:ital,wght@0,200..900;1,200..900&display=swap"
rel="stylesheet"
/>
<style
dangerouslySetInnerHTML={{ __html: resetStyle }}
/>
<style
dangerouslySetInnerHTML={{ __html: sqliteStyle }}
/>
<script src="https://unpkg.com/htmx.org@1.9.9/dist/htmx.min.js"></script>
<script src="https://unpkg.com/hyperscript.org@0.9.12"></script>
<script type="module" src="https://esm.town/v/nbbaier/resizeScript" />
<script type="module" src="https://esm.town/v/nbbaier/tableSelectScript" />
<script
type="module"
src="https://raw.esm.sh/code-mirror-web-component@0.0.20/dist/code-mirror.js"
>
</script>
</head>
<body _="
on keydown[event.metaKey and key is 'Enter'] log 'command + enter' then send submitForm to #sql-editor
">
<div class="root-container">
<header>
<h1>SQLite Explorer (dev)</h1>
</header>
{children}
</div>
<script type="module" src="https://esm.town/v/nbbaier/downloadScript_DEV" />
<script type="module" src="https://esm.town/v/nbbaier/enableButtonsScript_DEV" />
<script type="module" src="https://esm.town/v/nbbaier/getCodeScript" />
</body>
</html>
);
};
const app = new Hono();
app.use(
"*",
jsxRenderer(
({ children }) => {
return <HTML children={children} />;
},
{ docType: false },
),
);
app.get("/", async (c) => {
let data = await sqlite.batch(
[
`SELECT name FROM sqlite_schema WHERE type ='table' AND name NOT LIKE 'sqlite_%';`,
`SELECT name FROM sqlite_schema WHERE type ='view' AND name NOT LIKE 'sqlite_%';`,
],
);
let views = data[1].rows.map(view => {
return { type: "view", name: view[0] };
});
let tables = data[0].rows.map(view => {
return { type: "table", name: view[0] };
});
return c.render(
<main class="sidebar-layout">
<div class="sidebar">
<TablesList tables={[...tables, ...views]}></TablesList>
</div>

SQLite Explorer

View and interact with your Val Town SQLite data. It's based off Steve's excellent SQLite Admin val, adding the ability to run SQLite queries directly in the interface. This new version has a revised UI and that's heavily inspired by LibSQL Studio by invisal. This is now more an SPA, with tables, queries and results showing up on the same page.

image.webp

Install

Install the latest stable version (v66) by forking this val:

Install v66

Authentication

Login to your SQLite Explorer with password authentication with your Val Town API Token as the password.

Todos / Plans

  • improve error handling
  • improve table formatting
  • sticky table headers
  • add codemirror
  • add loading indication to the run button (initial version shipped)
  • add ability to favorite queries
  • add saving of last query run for a table (started)
  • add visible output for non-query statements
  • add schema viewing
  • add refresh to table list sidebar after CREATE/DROP/ALTER statements
  • add automatic execution of initial select query on double click
  • add views to the sidebar
  • add triggers to sidebar
  • add upload from SQL, CSV and JSON
  • add ability to connect to a non-val town Turso database
  • fix wonky sidebar separator height problem (thanks to @stevekrouse)
  • make result tables scrollable
  • add export to CSV, and JSON (CSV and JSON helper functions written in this val. Thanks to @pomdtr for merging the initial version!)
  • add listener for cmd+enter to submit query
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/** @jsxImportSource https://esm.sh/hono@latest/jsx **/
import { modifyFetchHandler } from "https://esm.town/v/andreterron/codeOnValTown?v=50";
import { resetStyle } from "https://esm.town/v/nbbaier/resetStyle";
import { sqlToCSV, sqlToJSON } from "https://esm.town/v/nbbaier/sqliteExportHelpers";
import {
EditorSection,
MockTable,
Separator,
Table,
TablesList,
} from "https://esm.town/v/nbbaier/sqliteStudioComponents";
import { RunSVG, TableSVG } from "https://esm.town/v/nbbaier/sqliteStudioSVGs";
import { sqliteStyle } from "https://esm.town/v/nbbaier/sqliteStyle";
import { passwordAuth } from "https://esm.town/v/pomdtr/password_auth?v=70";
import { sqlite } from "https://esm.town/v/std/sqlite";
import { Hono } from "npm:hono";
import type { FC } from "npm:hono/jsx";
import { jsxRenderer } from "npm:hono/jsx-renderer";
const HTML: FC = ({ children }) => {
return (
<html>
<head>
<title>SQLite Explorer</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@300..700&family=Source+Sans+3:ital,wght@0,200..900;1,200..900&display=swap"
rel="stylesheet"
/>
<style
dangerouslySetInnerHTML={{ __html: resetStyle }}
/>
<style
dangerouslySetInnerHTML={{ __html: sqliteStyle }}
/>
<script src="https://unpkg.com/htmx.org@1.9.9/dist/htmx.min.js"></script>
<script src="https://unpkg.com/hyperscript.org@0.9.12"></script>
<script type="module" src="https://esm.town/v/nbbaier/resizeScript" />
<script type="module" src="https://esm.town/v/nbbaier/tableSelectScript" />
</head>
<body _="
on keydown[event.metaKey and key is 'Enter'] log 'command + enter' then send submitForm to #sql-editor
">
<div class="root-container">
<header>
<h1>sqlite explorer</h1>
</header>
{children}
</div>
<script type="module" src="https://esm.town/v/nbbaier/downloadScript" />
<script type="module" src="https://esm.town/v/nbbaier/enableButtonsScript" />
</body>
</html>
);
};
const app = new Hono();
app.use(
"*",
jsxRenderer(
({ children }) => {
return <HTML children={children} />;
},
{ docType: false },
),
);
app.get("/", async (c) => {
let data = await sqlite.execute(`
SELECT
name
FROM
sqlite_schema
WHERE
type ='table' AND
name NOT LIKE 'sqlite_%';`);
let tables = data.rows;
return c.render(
<main class="sidebar-layout">
<div class="sidebar">
<TablesList tables={tables}></TablesList>
</div>
<Separator direction="horizontal"></Separator>
<div class="not-sidebar">
<EditorSection />
<Separator direction="vertical" isResizer={true}></Separator>
<div class="bottom-container">
<div id="results-table" class="bottom">
</div>
</div>
</div>
</main>,
);
});
app.post("/query", async (c) => {
const query = (await c.req.parseBody()).query as string;

SQLite Explorer

View and interact with your Val Town SQLite data. It's based off Steve's excellent SQLite Admin val, adding the ability to run SQLite queries directly in the interface. This new version has a revised UI and that's heavily inspired by LibSQL Studio by invisal. This is now more an SPA, with tables, queries and results showing up on the same page.

image.webp

Install

Install the latest stable version (v66) by forking this val:

Install v66

Authentication

Login to your SQLite Explorer with password authentication with your Val Town API Token as the password.

Todos / Plans

  • improve error handling
  • improve table formatting
  • sticky table headers
  • add codemirror
  • add loading indication to the run button (initial version shipped)
  • add ability to favorite queries
  • add saving of last query run for a table (started)
  • add visible output for non-query statements
  • add schema viewing
  • add refresh to table list sidebar after CREATE/DROP/ALTER statements
  • add automatic execution of initial select query on double click
  • add views to the sidebar
  • add triggers to sidebar
  • add upload from SQL, CSV and JSON
  • add ability to connect to a non-val town Turso database
  • fix wonky sidebar separator height problem (thanks to @stevekrouse)
  • make result tables scrollable
  • add export to CSV, and JSON (CSV and JSON helper functions written in this val. Thanks to @pomdtr for merging the initial version!)
  • add listener for cmd+enter to submit query
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/** @jsxImportSource https://esm.sh/hono@latest/jsx **/
import { modifyFetchHandler } from "https://esm.town/v/andreterron/codeOnValTown?v=50";
import { resetStyle } from "https://esm.town/v/nbbaier/resetStyle";
import { sqlToCSV, sqlToJSON } from "https://esm.town/v/nbbaier/sqliteExportHelpers";
import {
EditorSection,
MockTable,
Separator,
Table,
TablesList,
} from "https://esm.town/v/nbbaier/sqliteStudioComponents";
import { RunSVG, TableSVG } from "https://esm.town/v/nbbaier/sqliteStudioSVGs";
import { sqliteStyle } from "https://esm.town/v/nbbaier/sqliteStyle";
import { passwordAuth } from "https://esm.town/v/pomdtr/password_auth?v=70";
import { sqlite } from "https://esm.town/v/std/sqlite";
import { Hono } from "npm:hono";
import type { FC } from "npm:hono/jsx";
import { jsxRenderer } from "npm:hono/jsx-renderer";
const HTML: FC = ({ children }) => {
return (
<html>
<head>
<title>SQLite Explorer</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@300..700&family=Source+Sans+3:ital,wght@0,200..900;1,200..900&display=swap"
rel="stylesheet"
/>
<style
dangerouslySetInnerHTML={{ __html: resetStyle }}
/>
<style
dangerouslySetInnerHTML={{ __html: sqliteStyle }}
/>
<script src="https://unpkg.com/htmx.org@1.9.9/dist/htmx.min.js"></script>
<script src="https://unpkg.com/hyperscript.org@0.9.12"></script>
<script type="module" src="https://esm.town/v/nbbaier/resizeScript" />
<script type="module" src="https://esm.town/v/nbbaier/tableSelectScript" />
</head>
<body _="
on keydown[event.metaKey and key is 'Enter'] log 'command + enter' then send submitForm to #sql-editor
">
<div class="root-container">
<header>
<h1>sqlite explorer</h1>
</header>
{children}
</div>
<script type="module" src="https://esm.town/v/nbbaier/downloadScript" />
<script type="module" src="https://esm.town/v/nbbaier/enableButtonsScript" />
</body>
</html>
);
};
const app = new Hono();
app.use(
"*",
jsxRenderer(
({ children }) => {
return <HTML children={children} />;
},
{ docType: false },
),
);
app.get("/", async (c) => {
let data = await sqlite.execute(`
SELECT
name
FROM
sqlite_schema
WHERE
type ='table' AND
name NOT LIKE 'sqlite_%';`);
let tables = data.rows;
return c.render(
<main class="sidebar-layout">
<div class="sidebar">
<TablesList tables={tables}></TablesList>
</div>
<Separator direction="horizontal"></Separator>
<div class="not-sidebar">
<EditorSection />
<Separator direction="vertical" isResizer={true}></Separator>
<div class="bottom-container">
<div id="results-table" class="bottom">
</div>
</div>
</div>
</main>,
);
});
app.post("/query", async (c) => {
const query = (await c.req.parseBody()).query as string;

SQLite Explorer

View and interact with your Val Town SQLite data. It's based off Steve's excellent SQLite Admin val, adding the ability to run SQLite queries directly in the interface. This new version has a revised UI and that's heavily inspired by LibSQL Studio by invisal. This is now more an SPA, with tables, queries and results showing up on the same page.

image.webp

Install

Install the latest stable version (v66) by forking this val:

Install v66

Authentication

Login to your SQLite Explorer with password authentication with your Val Town API Token as the password.

Todos / Plans

  • improve error handling
  • improve table formatting
  • sticky table headers
  • add codemirror
  • add loading indication to the run button (initial version shipped)
  • add ability to favorite queries
  • add saving of last query run for a table (started)
  • add visible output for non-query statements
  • add schema viewing
  • add refresh to table list sidebar after CREATE/DROP/ALTER statements
  • add automatic execution of initial select query on double click
  • add views to the sidebar
  • add triggers to sidebar
  • add upload from SQL, CSV and JSON
  • add ability to connect to a non-val town Turso database
  • fix wonky sidebar separator height problem (thanks to @stevekrouse)
  • make result tables scrollable
  • add export to CSV, and JSON (CSV and JSON helper functions written in this val. Thanks to @pomdtr for merging the initial version!)
  • add listener for cmd+enter to submit query
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/** @jsxImportSource https://esm.sh/hono@latest/jsx **/
import { modifyFetchHandler } from "https://esm.town/v/andreterron/codeOnValTown?v=50";
import { resetStyle } from "https://esm.town/v/nbbaier/resetStyle";
import { sqlToCSV, sqlToJSON } from "https://esm.town/v/nbbaier/sqliteExportHelpers";
import {
EditorSection,
MockTable,
Separator,
Table,
TablesList,
} from "https://esm.town/v/nbbaier/sqliteStudioComponents";
import { RunSVG, TableSVG } from "https://esm.town/v/nbbaier/sqliteStudioSVGs";
import { sqliteStyle } from "https://esm.town/v/nbbaier/sqliteStyle";
import { passwordAuth } from "https://esm.town/v/pomdtr/password_auth?v=70";
import { sqlite } from "https://esm.town/v/std/sqlite";
import { Hono } from "npm:hono";
import type { FC } from "npm:hono/jsx";
import { jsxRenderer } from "npm:hono/jsx-renderer";
const HTML: FC = ({ children }) => {
return (
<html>
<head>
<title>SQLite Explorer</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@300..700&family=Source+Sans+3:ital,wght@0,200..900;1,200..900&display=swap"
rel="stylesheet"
/>
<style
dangerouslySetInnerHTML={{ __html: resetStyle }}
/>
<style
dangerouslySetInnerHTML={{ __html: sqliteStyle }}
/>
<script src="https://unpkg.com/htmx.org@1.9.9/dist/htmx.min.js"></script>
<script src="https://unpkg.com/hyperscript.org@0.9.12"></script>
<script type="module" src="https://esm.town/v/nbbaier/resizeScript" />
<script type="module" src="https://esm.town/v/nbbaier/tableSelectScript" />
</head>
<body _="
on keydown[event.metaKey and key is 'Enter'] log 'command + enter' then send submitForm to #sql-editor
">
<div class="root-container">
<header>
<h1>sqlite explorer</h1>
</header>
{children}
</div>
<script type="module" src="https://esm.town/v/nbbaier/downloadScript" />
<script type="module" src="https://esm.town/v/nbbaier/enableButtonsScript" />
</body>
</html>
);
};
const app = new Hono();
app.use(
"*",
jsxRenderer(
({ children }) => {
return <HTML children={children} />;
},
{ docType: false },
),
);
app.get("/", async (c) => {
let data = await sqlite.execute(`
SELECT
name
FROM
sqlite_schema
WHERE
type ='table' AND
name NOT LIKE 'sqlite_%';`);
let tables = data.rows;
return c.render(
<main class="sidebar-layout">
<div class="sidebar">
<TablesList tables={tables}></TablesList>
</div>
<Separator direction="horizontal"></Separator>
<div class="not-sidebar">
<EditorSection />
<Separator direction="vertical" isResizer={true}></Separator>
<div class="bottom-container">
<div id="results-table" class="bottom">
</div>
</div>
</div>
</main>,
);
});
app.post("/query", async (c) => {
const query = (await c.req.parseBody()).query as string;

SQLite Explorer

View and interact with your Val Town SQLite data. It's based off Steve's excellent SQLite Admin val, adding the ability to run SQLite queries directly in the interface. This new version has a revised UI and that's heavily inspired by LibSQL Studio by invisal. This is now more an SPA, with tables, queries and results showing up on the same page.

image.webp

Install

Install the latest stable version (v64) by forking this val that imports & exports it in your account:

Install v64

Authentication

Login to your SQLite Explorer with password authentication with your Val Town API Token as the password.

Todos / Plans

  • fix wonky sidebar separator height problem (thanks to @stevekrouse)
  • improve error handling
  • improve table formatting
  • make result tables scrollable
  • sticky table headers
  • add codemirror
  • add loading indication to the run button (initial version shipped)
  • add ability to favorite queries
  • add saving of last query run for a table (started)
  • add visible output for non-query statements
  • add schema viewing
  • add export to CSV, and JSON (CSV and JSON helper functions written in this val. Thanks to @pomdtr for merging the initial version!)
  • add refresh to table list sidebar after CREATE/DROP/ALTER statements
  • add automatic execution of initial select query on double click
  • add listener for cmd+enter to submit query
  • add views to the sidebar
  • add triggers to sidebar
  • add upload from SQL, CSV and JSON
  • add ability to connect to a non-val town Turso database
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/** @jsxImportSource https://esm.sh/hono@latest/jsx **/
import { resetStyle } from "https://esm.town/v/nbbaier/resetStyle";
import { sqlToCSV, sqlToJSON } from "https://esm.town/v/nbbaier/sqliteExportHelpers";
import {
EditorSection,
MockTable,
Separator,
Table,
TablesList,
} from "https://esm.town/v/nbbaier/sqliteStudioComponents";
import { RunSVG, TableSVG } from "https://esm.town/v/nbbaier/sqliteStudioSVGs";
import { sqliteStyle } from "https://esm.town/v/nbbaier/sqliteStyle";
import { passwordAuth } from "https://esm.town/v/pomdtr/password_auth?v=70";
import { sqlite } from "https://esm.town/v/std/sqlite";
import { Hono } from "npm:hono";
import type { FC } from "npm:hono/jsx";
import { jsxRenderer } from "npm:hono/jsx-renderer";
const HTML: FC = ({ children }) => {
return (
<html>
<head>
<title>SQLite Explorer</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@300..700&family=Source+Sans+3:ital,wght@0,200..900;1,200..900&display=swap"
rel="stylesheet"
/>
<style
dangerouslySetInnerHTML={{ __html: resetStyle }}
/>
<style
dangerouslySetInnerHTML={{ __html: sqliteStyle }}
/>
<script src="https://unpkg.com/htmx.org@1.9.9/dist/htmx.min.js"></script>
<script src="https://unpkg.com/hyperscript.org@0.9.12"></script>
<script type="module" src="https://esm.town/v/nbbaier/resizeScript" />
<script type="module" src="https://esm.town/v/nbbaier/tableSelectScript" />
</head>
<body _="
on keydown[event.metaKey and key is 'Enter'] log 'command + enter' then send submitForm to #sql-editor
">
<div class="root-container">
<header>
<h1>sqlite explorer</h1>
</header>
{children}
</div>
<script type="module" src="https://esm.town/v/nbbaier/downloadScript" />
<script type="module" src="https://esm.town/v/nbbaier/enableButtonsScript" />
</body>
</html>
);
};
const app = new Hono();
app.use(
"*",
jsxRenderer(
({ children }) => {
return <HTML children={children} />;
},
{ docType: false },
),
);
app.get("/", async (c) => {
let data = await sqlite.execute(`
SELECT
name
FROM
sqlite_schema
WHERE
type ='table' AND
name NOT LIKE 'sqlite_%';`);
let tables = data.rows;
return c.render(
<main class="sidebar-layout">
<div class="sidebar">
<TablesList tables={tables}></TablesList>
</div>
<Separator direction="horizontal"></Separator>
<div class="not-sidebar">
<EditorSection />
<Separator direction="vertical" isResizer={true}></Separator>
<div class="bottom-container">
<div id="results-table" class="bottom">
</div>
</div>
</div>
</main>,
);
});
app.post("/query", async (c) => {
const query = (await c.req.parseBody()).query as string;
try {

fork of @nbbaier/sqliteExplorerApp with my authentication middleware

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/** @jsxImportSource https://esm.sh/hono@latest/jsx **/
import { resetStyle } from "https://esm.town/v/nbbaier/resetStyle";
import { sqlToCSV, sqlToJSON } from "https://esm.town/v/nbbaier/sqliteExportHelpers";
import {
EditorSection,
MockTable,
Separator,
Table,
TablesList,
} from "https://esm.town/v/nbbaier/sqliteStudioComponents";
import { RunSVG, TableSVG } from "https://esm.town/v/nbbaier/sqliteStudioSVGs";
import { sqliteStyle } from "https://esm.town/v/nbbaier/sqliteStyle";
import { basicAuth } from "https://esm.town/v/pomdtr/basicAuth";
import {
type AuthContextVariables,
authMiddlewareCookie,
userActionsDisplay,
} from "https://esm.town/v/postpostscript/authMiddleware";
import { LibsqlError } from "https://esm.town/v/postpostscript/sqliteBuilder";
import { sqliteReadonly } from "https://esm.town/v/postpostscript/sqliteReadonly";
import { sqlite } from "https://esm.town/v/std/sqlite";
import { type Context, Hono } from "npm:hono";
import { getCookie, setCookie } from "npm:hono/cookie";
import type { FC } from "npm:hono/jsx";
import { jsxRenderer, useRequestContext } from "npm:hono/jsx-renderer";
const authStyle = `
h1, .user-details {
display: inline-block;
}
.user-details {
float: right;
padding: 0.7em 2em 0 0;
}
.logout {
margin-left: 1.5em;
}
.auth-middleware, .sign-in-form {
padding: 1em;
}
label {
display: block;
padding-bottom: 1em;
}
`;
const HTML: FC = ({ children }) => {
const c = useRequestContext<HonoEnv>();
const source = c.get("source");
return (
<html>
<head>
<title>SQLite Explorer</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@300..700&family=Source+Sans+3:ital,wght@0,200..900;1,200..900&display=swap"
rel="stylesheet"
/>
<style
dangerouslySetInnerHTML={{ __html: resetStyle }}
/>
<style
dangerouslySetInnerHTML={{ __html: sqliteStyle }}
/>
<style
dangerouslySetInnerHTML={{ __html: authStyle }}
/>
<script src="https://unpkg.com/htmx.org@1.9.9/dist/htmx.min.js"></script>
<script src="https://unpkg.com/hyperscript.org@0.9.12"></script>
<script type="module" src="https://esm.town/v/nbbaier/resizeScript" />
</head>
<body _="
on keydown[event.metaKey and key is 'Enter'] log 'command + enter' then send submitForm to #sql-editor
on keydown[event.ctrlKey and key is 'Enter'] log 'ctrl + enter' then send submitForm to #sql-editor
">
<div class="root-container">
<header>
{c.get("auth") && (
<span
class="user-details"
dangerouslySetInnerHTML={{
__html: userActionsDisplay(c.get("auth"), { order: ["profile", "username", "logout"] }).toString(),
}}
/>
)}
<h1>sqlite explorer</h1>
<select hx-get="/?set-source=1" hx-target=".sidebar" name="source">
<option value="default" selected={source === "default"}>Default (@std/sqlite)</option>
<option value="universe" selected={source === "universe"}>
Universe (@postpostscript/sqliteReadonly)
</option>
</select>
</header>
{children}
</div>
<script type="module" src="https://esm.town/v/nbbaier/downloadScript" />
<script type="module" src="https://esm.town/v/nbbaier/enableButtonsScript" />
</body>

SQLite Explorer

View and interact with your Val Town SQLite data. It's based off Steve's excellent SQLite Admin val, adding the ability to run SQLite queries directly in the interface. This new version has a revised UI and that's heavily inspired by LibSQL Studio by invisal. This is now more an SPA, with tables, queries and results showing up on the same page.

image.webp

Install

Install the latest stable version (v37) by forking this val that imports & exports it in your account:

Install v37

Authentication

SQLite Explorer basic authentication with your Val Town API Token as the password (leave the username field blank).

Todos / Plans

  • fix wonky sidebar separator height problem
  • improve error handling
  • improve table formatting
  • make result tables scrollable
  • add codemirror
  • add loading indication to the run button (initial version shipped)
  • add ability to favorite queries
  • add saving of last query run for a table (started)
  • add visible output for non-query statements
  • add schema viewing
  • add export to CSV, and JSON (CSV and JSON helper functions written in this val)
  • add export to sqlite
  • add refresh to table list sidebar after CREATE/DROP/ALTER statements
  • add automatic execution of initial select query on double click
  • add listener for cmd+enter to submit query
  • add views to the sidebar
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/** @jsxImportSource https://esm.sh/hono@latest/jsx **/
import { resetStyle } from "https://esm.town/v/nbbaier/resetStyle";
import { sqlToCSV, sqlToJSON } from "https://esm.town/v/nbbaier/sqliteExportHelpers?v=4";
import {
EditorSection,
MockTable,
Separator,
Table,
TablesList,
} from "https://esm.town/v/nbbaier/sqliteStudioComponents";
import { RunSVG, TableSVG } from "https://esm.town/v/nbbaier/sqliteStudioSVGs";
import { sqliteStyle } from "https://esm.town/v/nbbaier/sqliteStyle";
import { basicAuth } from "https://esm.town/v/pomdtr/basicAuth";
import { sqlite } from "https://esm.town/v/std/sqlite";
import { Hono } from "npm:hono";
import type { FC } from "npm:hono/jsx";
import { jsxRenderer } from "npm:hono/jsx-renderer";
const HTML: FC = ({ children }) => {
return (
<html>
<head>
<title>SQLite Explorer</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@300..700&family=Source+Sans+3:ital,wght@0,200..900;1,200..900&display=swap"
rel="stylesheet"
/>
<style
dangerouslySetInnerHTML={{ __html: resetStyle }}
/>
<style
dangerouslySetInnerHTML={{ __html: sqliteStyle }}
/>
<script src="https://unpkg.com/htmx.org@1.9.9/dist/htmx.min.js"></script>
<script src="https://unpkg.com/hyperscript.org@0.9.12"></script>
<script type="module" src="https://esm.town/v/nbbaier/resizeScript" />
<script type="module" src="https://esm.town/v/nbbaier/tableSelectScript" />
</head>
<body _="
on keydown[event.metaKey and key is 'Enter'] log 'command + enter' then send submitForm to #sql-editor
">
<div class="root-container">
<header>
<h1>sqlite explorer</h1>
</header>
{children}
</div>
</body>
</html>
);
};
const app = new Hono();
app.use(
"*",
jsxRenderer(
({ children }) => {
return <HTML children={children} />;
},
{ docType: false },
),
);
app.get("/", async (c) => {
let data = await sqlite.execute(`
SELECT
name
FROM
sqlite_schema
WHERE
type ='table' AND
name NOT LIKE 'sqlite_%';`);
let tables = data.rows;
return c.render(
<main class="sidebar-layout">
<div class="sidebar">
<TablesList tables={tables}></TablesList>
</div>
<Separator direction="horizontal"></Separator>
<div class="not-sidebar">
<EditorSection />
<Separator direction="vertical" isResizer={true}></Separator>
<div class="bottom-container">
<div id="results-table" class="bottom">
</div>
</div>
</div>
</main>,
);
});
app.post("/query", async (c) => {
const query = (await c.req.parseBody()).query as string;
try {
console.log(`attempting:`, query);
const rs = await sqlite.execute(query);
1
Next