forked from sheetjs/docs.sheetjs.com
websqlite
This commit is contained in:
parent
45d0ed0e13
commit
009d4e0a21
@ -129,7 +129,7 @@ site.use(sheets({
|
||||
|
||||
:::note
|
||||
|
||||
This demo was last tested against `lume v1.17.5` on 2023 June 25.
|
||||
This demo was last tested against `lume v1.19.1` on 2023 October 14.
|
||||
|
||||
This example uses the Nunjucks template format. Lume plugins support additional
|
||||
template formats, including Markdown and JSX.
|
||||
@ -195,7 +195,7 @@ page will show the contents of the spreadsheet.
|
||||
5) While the server is still running, open `_data/pres.xlsx` in a spreadsheet
|
||||
editor and add a new row at the bottom of the sheet.
|
||||
|
||||
The page will refresh and show the new contents.
|
||||
After saving the spreadsheet, the page will refresh and show the new contents.
|
||||
|
||||
### Static Site
|
||||
|
||||
|
@ -47,7 +47,7 @@ This demo was tested in the following environments:
|
||||
| OS and Version | Arch | RN Platform | Date |
|
||||
|:---------------|:-----|:------------|:-----------|
|
||||
| Windows 10 | x64 | `v0.71.25` | 2023-07-24 |
|
||||
| Windows 11 | x64 | `v0.71.11` | 2023-05-11 |
|
||||
| Windows 11 | x64 | `v0.72.12` | 2023-10-14 |
|
||||
| Windows 11 | ARM | `v0.72.9` | 2023-09-18 |
|
||||
| MacOS 12.6 | x64 | `v0.71.26` | 2023-07-23 |
|
||||
| MacOS 13.5.2 | ARM | `v0.72.4` | 2023-09-18 |
|
||||
@ -394,16 +394,30 @@ been tested against both application types.
|
||||
|
||||
:::
|
||||
|
||||
0) Follow the ["Getting Started" guide](https://microsoft.github.io/react-native-windows/docs/getting-started)
|
||||
0) Install the [development dependencies](https://microsoft.github.io/react-native-windows/docs/rnw-dependencies).
|
||||
|
||||
:::caution pass
|
||||
|
||||
At the time of testing, NodeJS `v16` was required. A tool like
|
||||
In earlier versions of React Native, NodeJS `v16` was required. A tool like
|
||||
[`nvm-windows`](https://github.com/coreybutler/nvm-windows/releases) should be
|
||||
used to switch the NodeJS version.
|
||||
|
||||
:::
|
||||
|
||||
<details><summary><b>Installation Notes</b> (click to show)</summary>
|
||||
|
||||
When the demo was last tested, a PowerShell script installed dependencies:
|
||||
|
||||
```powershell
|
||||
Set-ExecutionPolicy Unrestricted -Scope Process -Force;
|
||||
iex (New-Object System.Net.WebClient).DownloadString('https://aka.ms/rnw-vs2022-deps.ps1');
|
||||
```
|
||||
|
||||
If any step fails to install, open the dependencies page and expand "Manual
|
||||
setup instructions" to find instructions for manual installation.
|
||||
|
||||
</details>
|
||||
|
||||
### Project Setup
|
||||
|
||||
1) Create a new project using React Native `0.72`:
|
||||
@ -578,7 +592,7 @@ curl -LO https://docs.sheetjs.com/reactnative/rnw/App.tsx
|
||||
|
||||
|
||||
|
||||
8) Test the app again:
|
||||
8) Launch the app again:
|
||||
|
||||
<Tabs groupId="arch">
|
||||
<TabItem value="x64" label="x64 (64-bit Windows)">
|
||||
@ -611,10 +625,10 @@ When this demo was last tested on Windows 11 ARM, the build failed.
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
Download <https://sheetjs.com/pres.xlsx>.
|
||||
9) Download <https://sheetjs.com/pres.xlsx>.
|
||||
|
||||
Click "Click here to Open File!" and use the file picker to select `pres.xlsx` .
|
||||
The app will refresh and display the data from the file.
|
||||
10) In the app, click "Click here to Open File!" and use the file picker to
|
||||
select `pres.xlsx` . The app will refresh and display the data from the file.
|
||||
|
||||
## macOS Demo
|
||||
|
||||
|
@ -242,7 +242,7 @@ This demo was last tested in the following deployments:
|
||||
| `darwin-x64` | `11.8.172.13` | `0.79.2` | 2023-10-12 |
|
||||
| `darwin-arm` | `11.4.183.2` | `0.71.2` | 2023-05-22 |
|
||||
| `win10-x64` | `11.8.172.13` | `0.79.2` | 2023-10-09 |
|
||||
| `win11-x64` | `11.7.439.6` | `0.75.1` | 2023-08-31 |
|
||||
| `win11-x64` | `11.8.172.13` | `0.79.2` | 2023-10-14 |
|
||||
| `linux-x64` | `11.8.172.13` | `0.79.2` | 2023-10-11 |
|
||||
| `linux-arm` | `11.7.439.6` | `0.75.1` | 2023-08-30 |
|
||||
|
||||
@ -353,6 +353,7 @@ This demo was last tested in the following deployments:
|
||||
| `darwin-x64` | `1.37.1` | 2023-10-12 |
|
||||
| `darwin-arm` | `1.34.1` | 2023-06-05 |
|
||||
| `win10-x64` | `1.37.1` | 2023-10-09 |
|
||||
| `win11-x64` | `1.37.2` | 2023-10-14 |
|
||||
| `win11-arm` | `1.37.0` | 2023-09-26 |
|
||||
| `linux-x64` | `1.37.1` | 2023-10-11 |
|
||||
| `linux-arm` | `1.36.3` | 2023-08-30 |
|
||||
|
@ -1,258 +0,0 @@
|
||||
---
|
||||
title: WebSQL and SQLite
|
||||
pagination_prev: demos/desktop/index
|
||||
pagination_next: demos/local/index
|
||||
sidebar_custom_props:
|
||||
type: web
|
||||
sql: true
|
||||
---
|
||||
|
||||
import current from '/version.js';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
WebSQL is a popular SQL-based in-browser database available on Chrome. In
|
||||
practice, it is powered by SQLite, and most simple SQLite-compatible queries
|
||||
work as-is in WebSQL.
|
||||
|
||||
The public demo <https://sheetjs.com/sql> generates a database from workbook.
|
||||
|
||||
:::caution pass
|
||||
|
||||
WebSQL is only supported in Chromium-based browsers including Chrome.
|
||||
|
||||
Safari historically supported WebSQL but Safari 13 dropped support. Legacy
|
||||
browsers including Internet Explorer and Firefox never added support.
|
||||
|
||||
:::
|
||||
|
||||
## WebSQL Details
|
||||
|
||||
Importing data from spreadsheets is straightforward using the `generate_sql`
|
||||
helper function from ["Generating Tables"](/docs/demos/data/sql#generating-tables).
|
||||
|
||||
The Web SQL Database API is callback-based. The following snippet wraps
|
||||
transactions in Promise objects:
|
||||
|
||||
```js
|
||||
const db = openDatabase('sheetql', '1.0', 'SheetJS WebSQL Test', 2097152);
|
||||
const stmts = generate_sql(ws, wsname);
|
||||
|
||||
// NOTE: tx.executeSql and db.transaction use callbacks. This wraps in Promises
|
||||
for(var stmt of stmts) await new Promise((res, rej) => {
|
||||
db.transaction(tx =>
|
||||
tx.executeSql(stmt, [],
|
||||
(tx, data) => res(data), // if the query is successful, return the data
|
||||
(tx, err) => rej(err) // if the query fails, reject with the error
|
||||
));
|
||||
});
|
||||
```
|
||||
|
||||
The result of a SQL SELECT statement is a `SQLResultSet`. The `rows` property
|
||||
is a `SQLResultSetRowList`. It is an "array-like" structure that has `length`
|
||||
and properties like `0`, `1`, etc. However, this is not a real Array object!
|
||||
|
||||
A real Array can be created using `Array.from`:
|
||||
|
||||
```js
|
||||
db.readTransaction(tx =>
|
||||
tx.executeSQL("SELECT * FROM DatabaseTable", [], (tx, data) => {
|
||||
// data.rows is "array-like", so `Array.from` can make it a real array
|
||||
const aoo = Array.from(data.rows);
|
||||
const ws = XLSX.utils.json_to_sheet(aoo);
|
||||
// ... perform an export here OR wrap in a Promise
|
||||
})
|
||||
);
|
||||
```
|
||||
|
||||
### Live Demo
|
||||
|
||||
:::note
|
||||
|
||||
This browser demo was tested in the following environments:
|
||||
|
||||
| Browser | Date |
|
||||
|:------------|:-----------|
|
||||
| Chrome 117 | 2023-10-11 |
|
||||
|
||||
Some lesser-used browsers do not support WebSQL:
|
||||
|
||||
| Browser | Date | Support |
|
||||
|:------------|:-----------|:------------------------------------|
|
||||
| Safari 17.0 | 2023-10-11 | Error `Web SQL is deprecated` |
|
||||
| Firefox 118 | 2023-10-11 | Error `openDatabase is not defined` |
|
||||
|
||||
:::
|
||||
|
||||
The following demo generates a database with 5 fixed SQL statements. Queries
|
||||
can be changed in the Live Editor. The WebSQL database can be inspected in the
|
||||
"WebSQL" section of the "Application" Tab of Developer Tools:
|
||||
|
||||
![WebSQL view in Developer Tools](pathname:///files/websql.png)
|
||||
|
||||
```jsx live
|
||||
function SheetQL() {
|
||||
const [out, setOut] = React.useState("");
|
||||
const queries = [
|
||||
'DROP TABLE IF EXISTS Presidents',
|
||||
'CREATE TABLE Presidents (Name TEXT, Idx REAL)',
|
||||
'INSERT INTO Presidents (Name, Idx) VALUES ("Barack Obama", 44)',
|
||||
'INSERT INTO Presidents (Name, Idx) VALUES ("Donald Trump", 45)',
|
||||
'INSERT INTO Presidents (Name, Idx) VALUES ("Joseph Biden", 46)'
|
||||
];
|
||||
const xport = React.useCallback(async() => {
|
||||
/* prep database */
|
||||
const db = openDatabase('sheetql', '1.0', 'SheetJS WebSQL Test', 2097152);
|
||||
|
||||
for(var q of queries) await new Promise((res, rej) => {
|
||||
db.transaction((tx) => {
|
||||
tx.executeSql(q, [], (tx, data) => res(data), (tx, err) => rej(err));
|
||||
});
|
||||
});
|
||||
|
||||
/* pull data and generate rows */
|
||||
db.readTransaction(tx => {
|
||||
tx.executeSql("SELECT * FROM Presidents", [], (tx, data) => {
|
||||
const aoo = Array.from(data.rows);
|
||||
setOut("QUERY RESULT:\n" + aoo.map(r => JSON.stringify(r)).join("\n") + "\n")
|
||||
const ws = XLSX.utils.json_to_sheet(aoo);
|
||||
const wb = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(wb, ws, "Presidents");
|
||||
XLSX.writeFile(wb, "SheetQL.xlsx");
|
||||
});
|
||||
});
|
||||
});
|
||||
return ( <pre>{out}<button onClick={xport}><b>Fetch!</b></button></pre> );
|
||||
}
|
||||
```
|
||||
|
||||
## Server-Side SQLite
|
||||
|
||||
Most platforms offer a simple way to query SQLite database files.
|
||||
|
||||
The following example shows how to query for each table in an SQLite database,
|
||||
query for the data for each table, add each non-empty table to a workbook, and
|
||||
export as XLSX.
|
||||
|
||||
The Chinook database is a MIT-licensed sample database. The original source code
|
||||
repository `http://chinookdatabase.codeplex.com` is no longer available, so the
|
||||
[raw SQL queries are mirrored here](pathname:///sqlite/chinook.sql).
|
||||
|
||||
:::note
|
||||
|
||||
This demo was last tested on 2023 May 28
|
||||
|
||||
:::
|
||||
|
||||
### NodeJS
|
||||
|
||||
The `better-sqlite3` module provides an API for working with SQLite databases.
|
||||
`Statement#all` runs a prepared statement and returns an array of objects:
|
||||
|
||||
```js
|
||||
import Database from "better-sqlite3";
|
||||
import * as XLSX from "xlsx";
|
||||
|
||||
/* open database */
|
||||
var db = Database("chinook.db");
|
||||
|
||||
/* get data from the `Invoice` table */
|
||||
var aoo = db.prepare("SELECT * FROM 'Invoice' LIMIT 100000").all();
|
||||
|
||||
/* create worksheet from the row objects */
|
||||
var ws = XLSX.utils.json_to_sheet(aoo, {dense: true});
|
||||
```
|
||||
|
||||
0) Build `chinook.db` from [the SQL statements](pathname:///sqlite/chinook.sql):
|
||||
|
||||
```bash
|
||||
curl -LO https://docs.sheetjs.com/sqlite/chinook.sql
|
||||
sqlite3 chinook.db ".read chinook.sql"
|
||||
```
|
||||
|
||||
1) Install the dependencies:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz better-sqlite3@8.1.0`}
|
||||
</CodeBlock>
|
||||
|
||||
2) Download [`SheetJSQLiteNode.mjs`](pathname:///sqlite/SheetJSQLiteNode.mjs):
|
||||
|
||||
```bash
|
||||
curl -LO https://docs.sheetjs.com/sqlite/SheetJSQLiteNode.mjs
|
||||
```
|
||||
|
||||
3) Run `node SheetJSQLiteNode.mjs` and open `SheetJSQLiteNode.xlsx`
|
||||
|
||||
### Bun
|
||||
|
||||
Bun ships with a built-in high-performance module `bun:sqlite`:
|
||||
|
||||
```js
|
||||
import { Database } from "bun:sqlite";
|
||||
import * as XLSX from "xlsx";
|
||||
|
||||
/* open database */
|
||||
var db = Database.open("chinook.db");
|
||||
|
||||
/* get data from the `Invoice` table */
|
||||
var aoo = db.prepare("SELECT * FROM 'Invoice' LIMIT 100000").all();
|
||||
|
||||
/* create worksheet from the row objects */
|
||||
var ws = XLSX.utils.json_to_sheet(aoo, {dense: true});
|
||||
```
|
||||
|
||||
0) Build `chinook.db` from [the SQL statements](pathname:///sqlite/chinook.sql):
|
||||
|
||||
```bash
|
||||
curl -LO https://docs.sheetjs.com/sqlite/chinook.sql
|
||||
sqlite3 chinook.db ".read chinook.sql"
|
||||
```
|
||||
|
||||
1) Install the dependencies:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
|
||||
</CodeBlock>
|
||||
|
||||
2) Download [`SheetJSQLiteBun.mjs`](pathname:///sqlite/SheetJSQLiteBun.mjs):
|
||||
|
||||
```bash
|
||||
curl -LO https://docs.sheetjs.com/sqlite/SheetJSQLiteBun.mjs
|
||||
```
|
||||
|
||||
3) Run `bun run SheetJSQLiteBun.mjs` and open `SheetJSQLiteBun.xlsx`
|
||||
|
||||
### Deno
|
||||
|
||||
Deno `sqlite` library returns raw arrays of arrays:
|
||||
|
||||
<CodeBlock language="ts">{`\
|
||||
import { DB } from "https://deno.land/x/sqlite/mod.ts";
|
||||
// @deno-types="https://cdn.sheetjs.com/xlsx-${current}/package/types/index.d.ts"
|
||||
import * as XLSX from "https://cdn.sheetjs.com/xlsx-${current}/package/xlsx.mjs";
|
||||
\n\
|
||||
/* open database */
|
||||
var db = new DB("chinook.db");
|
||||
\n\
|
||||
/* get data from the \`Invoice\` table */
|
||||
var aoa = db.prepareQuery("SELECT * FROM 'Invoice' LIMIT 100000").all();
|
||||
\n\
|
||||
/* create worksheet from the row objects */
|
||||
var data = [query.columns().map(x => x.name)].concat(aoa);
|
||||
var ws = XLSX.utils.aoa_to_sheet(data, {dense: true});`}
|
||||
</CodeBlock>
|
||||
|
||||
0) Build `chinook.db` from [the SQL statements](pathname:///sqlite/chinook.sql):
|
||||
|
||||
```bash
|
||||
curl -LO https://docs.sheetjs.com/sqlite/chinook.sql
|
||||
sqlite3 chinook.db ".read chinook.sql"
|
||||
```
|
||||
|
||||
1) Download [`SheetJSQLiteDeno.ts`](pathname:///sqlite/SheetJSQLiteDeno.ts):
|
||||
|
||||
```bash
|
||||
curl -LO https://docs.sheetjs.com/sqlite/SheetJSQLiteDeno.ts
|
||||
```
|
||||
|
||||
2) Run `deno run --allow-read --allow-write SheetJSQLiteDeno.ts` and open `SheetJSQLiteDeno.xlsx`
|
314
docz/docs/03-demos/07-data/11-sqlite.md
Normal file
314
docz/docs/03-demos/07-data/11-sqlite.md
Normal file
@ -0,0 +1,314 @@
|
||||
---
|
||||
title: Sheets with SQLite
|
||||
sidebar_label: SQLite
|
||||
pagination_prev: demos/desktop/index
|
||||
pagination_next: demos/local/index
|
||||
sidebar_custom_props:
|
||||
sql: true
|
||||
---
|
||||
|
||||
<head>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/sql.js/1.8.0/sql-wasm.js"></script>
|
||||
</head>
|
||||
|
||||
import current from '/version.js';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
[SQLite](https://sqlite.org/) is a lightweight embeddable SQL database engine.
|
||||
There are connector libraries for many popular JavaScript server-side platforms.
|
||||
|
||||
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
|
||||
data from spreadsheets.
|
||||
|
||||
This demo uses SQLite and SheetJS to exchange data between spreadsheets and SQL
|
||||
servers. We'll explore how to use save tables from a database to spreadsheets
|
||||
and how to add data from spreadsheets into a database.
|
||||
|
||||
:::note
|
||||
|
||||
This demo was last tested on 2023 October 13
|
||||
|
||||
:::
|
||||
|
||||
:::info pass
|
||||
|
||||
This demo covers SQLite `.db` file processing.
|
||||
|
||||
The [WebSQL demo](/docs/demos/local/websql) covers the Web SQL Database API, a
|
||||
SQLite-compatible database built into Chromium and Google Chrome.
|
||||
|
||||
:::
|
||||
|
||||
## Demo
|
||||
|
||||
The following examples show how to query for each table in an SQLite database,
|
||||
query for the data for each table, add each non-empty table to a workbook, and
|
||||
export as XLSX.
|
||||
|
||||
#### Sample Database
|
||||
|
||||
The Chinook database is a MIT-licensed sample database. The original source code
|
||||
repository `http://chinookdatabase.codeplex.com` is no longer available, so the
|
||||
[raw SQL queries are mirrored here](pathname:///sqlite/chinook.sql).
|
||||
|
||||
### Exporting Data
|
||||
|
||||
Connector libraries typically provide a way to generate an array of objects from
|
||||
the result of a `SELECT` query. For example, using `better-sqlite3` in NodeJS:
|
||||
|
||||
```js
|
||||
import Database from "better-sqlite3";
|
||||
|
||||
/* open database */
|
||||
var db = Database("chinook.db");
|
||||
|
||||
/* get data from the `Invoice` table */
|
||||
var aoo = db.prepare("SELECT * FROM 'Invoice' LIMIT 100000").all();
|
||||
```
|
||||
|
||||
The SheetJS `json_to_sheet` method[^1] can take the result and generate a
|
||||
worksheet object[^2]. The `book_new` and `book_append_sheet` methods[^3] help
|
||||
build a workbook object[^4]. The `writeFile` method[^5] generates a file:
|
||||
|
||||
```js
|
||||
import * as XLSX from "xlsx";
|
||||
|
||||
/* Create Worksheet from the row objects */
|
||||
var ws = XLSX.utils.json_to_sheet(aoo, {dense: true});
|
||||
|
||||
/* Add to Workbook */
|
||||
XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
|
||||
|
||||
/* Write File */
|
||||
XLSX.writeFile(wb, "SheetJSQLiteNode.xlsx");
|
||||
```
|
||||
|
||||
### Importing Data
|
||||
|
||||
The ["Generating Tables"](/docs/demos/data/sql#generating-tables) section
|
||||
includes a code snippet for generating SQLite-compatible SQL queries from a
|
||||
SheetJS worksheet object. Each query can be run sequentially.
|
||||
|
||||
## Browser
|
||||
|
||||
`sql.js`[^6] is a compiled version of SQLite into WebAssembly, making it usable
|
||||
in web browsers.
|
||||
|
||||
SQLite database files can be `fetch`ed and loaded:
|
||||
|
||||
```js
|
||||
/* Load sql.js library */
|
||||
const SQL = await initSqlJs(config);
|
||||
/* fetch sqlite database */
|
||||
const ab = await (await fetch("/sqlite/chinook.db")).arrayBuffer();
|
||||
/* connect to DB */
|
||||
const db = new SQL.Database(new Uint8Array(ab));
|
||||
```
|
||||
|
||||
The `sql.js` connector library uses an iterator-like interface. After preparing
|
||||
a statement, `Statement#step` loops over the result and `Statement#getAsObject`
|
||||
pulls each row as a row object:
|
||||
|
||||
```js
|
||||
/* perform query and get iterator */
|
||||
const sql = db.prepare("SELECT * FROM 'Invoice' LIMIT 100000").all();
|
||||
|
||||
/* create worksheet from the row objects */
|
||||
let ws;
|
||||
|
||||
while(sql.step()) {
|
||||
const row = sql.getAsObject();
|
||||
|
||||
if(!ws) ws = XLSX.utils.json_to_sheet([row], {dense: true, header});
|
||||
else XLSX.utils.sheet_add_json(ws, [row], { header, origin: -1, skipHeader: true});
|
||||
}
|
||||
```
|
||||
|
||||
### Demo
|
||||
|
||||
This demo fetches [`chinook.db`](pathname:///sqlite/chinook.db), loads into the
|
||||
SQLite engine and performs a series of queries to extract the data. Worksheets
|
||||
are created from the data. A workbook is created from the worksheets and
|
||||
exported to a XLSX file.
|
||||
|
||||
```jsx live
|
||||
function SheetJSQLJS() { return (<button onClick={async() => {
|
||||
/* Load sql.js library */
|
||||
const config = {
|
||||
locateFile: filename => `https://cdnjs.cloudflare.com/ajax/libs/sql.js/1.8.0/${filename}`
|
||||
}
|
||||
const SQL = await initSqlJs(config);
|
||||
|
||||
/* Initialize database */
|
||||
const ab = await (await fetch("/sqlite/chinook.db")).arrayBuffer();
|
||||
const db = new SQL.Database(new Uint8Array(ab));
|
||||
|
||||
/* Create new workbook */
|
||||
const wb = XLSX.utils.book_new();
|
||||
|
||||
/* Get all table names */
|
||||
const sql = db.prepare("SELECT name FROM sqlite_master WHERE type='table'");
|
||||
while(sql.step()) {
|
||||
const row = sql.getAsObject();
|
||||
|
||||
/* Get first 100K rows */
|
||||
const stmt = db.prepare("SELECT * FROM '" + row.name + "' LIMIT 100000");
|
||||
let header = [];
|
||||
let ws;
|
||||
while(stmt.step()) {
|
||||
/* create worksheet from headers */
|
||||
if(!ws) ws = XLSX.utils.aoa_to_sheet([header = stmt.getColumnNames()])
|
||||
|
||||
const rowobj = stmt.getAsObject();
|
||||
/* add to sheet */
|
||||
XLSX.utils.sheet_add_json(ws, [rowobj], { header, origin: -1, skipHeader: true});
|
||||
}
|
||||
if(ws) XLSX.utils.book_append_sheet(wb, ws, row.name);
|
||||
}
|
||||
XLSX.writeFile(wb, "SheetJSQLJS.xlsx");
|
||||
}}><b>Click here to start</b></button>) }
|
||||
```
|
||||
|
||||
## Server-Side Platforms
|
||||
|
||||
### NodeJS
|
||||
|
||||
The `better-sqlite3`[^7] native module embeds the SQLite C library.
|
||||
`Statement#all` runs a prepared statement and returns an array of objects:
|
||||
|
||||
```js
|
||||
import Database from "better-sqlite3";
|
||||
import * as XLSX from "xlsx";
|
||||
|
||||
/* open database */
|
||||
var db = Database("chinook.db");
|
||||
|
||||
/* get data from the `Invoice` table */
|
||||
var aoo = db.prepare("SELECT * FROM 'Invoice' LIMIT 100000").all();
|
||||
|
||||
/* create worksheet from the row objects */
|
||||
var ws = XLSX.utils.json_to_sheet(aoo, {dense: true});
|
||||
```
|
||||
|
||||
0) Build `chinook.db` from [the SQL statements](pathname:///sqlite/chinook.sql):
|
||||
|
||||
```bash
|
||||
curl -LO https://docs.sheetjs.com/sqlite/chinook.sql
|
||||
sqlite3 chinook.db ".read chinook.sql"
|
||||
```
|
||||
|
||||
1) Install the dependencies:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz better-sqlite3@9.0.0`}
|
||||
</CodeBlock>
|
||||
|
||||
2) Download [`SheetJSQLiteNode.mjs`](pathname:///sqlite/SheetJSQLiteNode.mjs):
|
||||
|
||||
```bash
|
||||
curl -LO https://docs.sheetjs.com/sqlite/SheetJSQLiteNode.mjs
|
||||
```
|
||||
|
||||
3) Run the script:
|
||||
|
||||
```bash
|
||||
node SheetJSQLiteNode.mjs
|
||||
```
|
||||
|
||||
Open `SheetJSQLiteNode.xlsx` with a spreadsheet editor.
|
||||
|
||||
### Bun
|
||||
|
||||
Bun ships with a built-in high-performance module `bun:sqlite`[^8]:
|
||||
|
||||
```js
|
||||
import { Database } from "bun:sqlite";
|
||||
import * as XLSX from "xlsx";
|
||||
|
||||
/* open database */
|
||||
var db = Database.open("chinook.db");
|
||||
|
||||
/* get data from the `Invoice` table */
|
||||
var aoo = db.prepare("SELECT * FROM 'Invoice' LIMIT 100000").all();
|
||||
|
||||
/* create worksheet from the row objects */
|
||||
var ws = XLSX.utils.json_to_sheet(aoo, {dense: true});
|
||||
```
|
||||
|
||||
0) Build `chinook.db` from [the SQL statements](pathname:///sqlite/chinook.sql):
|
||||
|
||||
```bash
|
||||
curl -LO https://docs.sheetjs.com/sqlite/chinook.sql
|
||||
sqlite3 chinook.db ".read chinook.sql"
|
||||
```
|
||||
|
||||
1) Install the dependencies:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
bun install https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
|
||||
</CodeBlock>
|
||||
|
||||
2) Download [`SheetJSQLiteBun.mjs`](pathname:///sqlite/SheetJSQLiteBun.mjs):
|
||||
|
||||
```bash
|
||||
curl -LO https://docs.sheetjs.com/sqlite/SheetJSQLiteBun.mjs
|
||||
```
|
||||
|
||||
3) Run the script:
|
||||
|
||||
```bash
|
||||
bun run SheetJSQLiteBun.mjs
|
||||
```
|
||||
|
||||
Open `SheetJSQLiteBun.xlsx` with a spreadsheet editor.
|
||||
|
||||
### Deno
|
||||
|
||||
Deno `sqlite` library[^9] returns raw arrays of arrays:
|
||||
|
||||
<CodeBlock language="ts">{`\
|
||||
import { DB } from "https://deno.land/x/sqlite/mod.ts";
|
||||
// @deno-types="https://cdn.sheetjs.com/xlsx-${current}/package/types/index.d.ts"
|
||||
import * as XLSX from "https://cdn.sheetjs.com/xlsx-${current}/package/xlsx.mjs";
|
||||
\n\
|
||||
/* open database */
|
||||
var db = new DB("chinook.db");
|
||||
\n\
|
||||
/* get data from the \`Invoice\` table */
|
||||
var aoa = db.prepareQuery("SELECT * FROM 'Invoice' LIMIT 100000").all();
|
||||
\n\
|
||||
/* create worksheet from the row objects */
|
||||
var data = [query.columns().map(x => x.name)].concat(aoa);
|
||||
var ws = XLSX.utils.aoa_to_sheet(data, {dense: true});`}
|
||||
</CodeBlock>
|
||||
|
||||
0) Build `chinook.db` from [the SQL statements](pathname:///sqlite/chinook.sql):
|
||||
|
||||
```bash
|
||||
curl -LO https://docs.sheetjs.com/sqlite/chinook.sql
|
||||
sqlite3 chinook.db ".read chinook.sql"
|
||||
```
|
||||
|
||||
1) Download [`SheetJSQLiteDeno.ts`](pathname:///sqlite/SheetJSQLiteDeno.ts):
|
||||
|
||||
```bash
|
||||
curl -LO https://docs.sheetjs.com/sqlite/SheetJSQLiteDeno.ts
|
||||
```
|
||||
|
||||
2) Run the script:
|
||||
|
||||
```bash
|
||||
deno run --allow-read --allow-write SheetJSQLiteDeno.ts
|
||||
```
|
||||
|
||||
Open `SheetJSQLiteDeno.xlsx` with a spreadsheet editor.
|
||||
|
||||
[^1]: See [`json_to_sheet` in "Utilities"](/docs/api/utilities/array#array-of-objects-input)
|
||||
[^2]: See ["Sheet Objects"](/docs/csf/sheet) in "SheetJS Data Model" for more details.
|
||||
[^3]: See ["Workbook Helpers" in "Utilities"](/docs/api/utilities/wb) for details on `book_new` and `book_append_sheet`.
|
||||
[^4]: See ["Workbook Objects"](/docs/csf/book) in "SheetJS Data Model" for more details.
|
||||
[^5]: See [`writeFile` in "Writing Files"](/docs/api/write-options)
|
||||
[^6]: See [the `sql.js` documentation](https://sql.js.org/documentation/)
|
||||
[^7]: The [documentation](https://github.com/WiseLibs/better-sqlite3/blob/master/docs/api.md) can be found in the project repository.
|
||||
[^8]: See ["SQLite"](https://bun.sh/docs/api/sqlite) in the BunJS documentation.
|
||||
[^9]: See [the `sqlite` module](https://deno.land/x/sqlite) on the Deno module registry.
|
@ -183,6 +183,7 @@ The following Web APIs are featured in separate demos:
|
||||
<a href={item.href}>{item.label}</a>{item.customProps?.summary && (" - " + item.customProps.summary)}
|
||||
</li>);
|
||||
})}
|
||||
<li><a href="/docs/demos/local/websql">Web SQL Database</a></li>
|
||||
<li><a href="/docs/demos/local/storageapi">Local Storage API</a></li>
|
||||
<li><a href="/docs/demos/local/indexeddb">IndexedDB API</a></li>
|
||||
</ul>
|
||||
|
217
docz/docs/03-demos/08-local/01-websql.md
Normal file
217
docz/docs/03-demos/08-local/01-websql.md
Normal file
@ -0,0 +1,217 @@
|
||||
---
|
||||
title: Sheets with WebSQL
|
||||
sidebar_label: Web SQL Database
|
||||
pagination_prev: demos/data/index
|
||||
pagination_next: demos/cloud/index
|
||||
sidebar_custom_props:
|
||||
summary: Reading and writing data in an in-browser SQL database
|
||||
---
|
||||
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
WebSQL (formally "Web SQL Database") is a popular SQL-based in-browser database
|
||||
available in Chromium and related browsers including Google Chrome. In practice,
|
||||
it is powered by SQLite. Many SQLite-compatible queries work as-is in WebSQL.
|
||||
|
||||
The public demo <https://sheetjs.com/sql> generates a database from workbook.
|
||||
|
||||
:::caution pass
|
||||
|
||||
WebSQL is only supported in Chromium-based browsers including Chrome.
|
||||
|
||||
Safari historically supported WebSQL but Safari 13 dropped support.
|
||||
|
||||
Legacy browsers including Internet Explorer and Firefox never added support.
|
||||
|
||||
:::
|
||||
|
||||
:::info pass
|
||||
|
||||
WebSQL is not commonly available on server-side platforms. Typically scripts
|
||||
will directly query SQLite databases using connector modules.
|
||||
|
||||
[The "SQLite" demo](/docs/demos/data/sqlite) covers NodeJS and other platforms.
|
||||
|
||||
:::
|
||||
|
||||
## Overview
|
||||
|
||||
Environments that support WebSQL expose the `openDatabase` global method. It
|
||||
takes 4 arguments:
|
||||
- internal database name
|
||||
- version string (`1.0`)
|
||||
- public display name
|
||||
- database size (measured in bytes)
|
||||
|
||||
The following command attempts to connect to the database named `sheetql`. If
|
||||
the database does not exist, it will create a new database with a hint to
|
||||
allocate 2MB of space.
|
||||
|
||||
```js
|
||||
const db = openDatabase('sheetql', '1.0', 'SheetJS WebSQL Test', 2097152);
|
||||
```
|
||||
|
||||
### Transactions and Queries
|
||||
|
||||
Queries are performed within transactions.
|
||||
|
||||
`Database#transaction` passes a transaction object to the callback argument:
|
||||
|
||||
```js
|
||||
db.transaction(function(tx) {
|
||||
/* tx is a transaction object */
|
||||
});
|
||||
```
|
||||
|
||||
Within a transaction, queries are performed with `Transaction#executeSql`. The
|
||||
method takes 4 arguments:
|
||||
- SQL statement stored in a string
|
||||
- Array of parameterized query arguments
|
||||
- Success callback
|
||||
- Error callback
|
||||
|
||||
If the query succeeds, the success callback will be invoked with two arguments:
|
||||
- Transaction object
|
||||
- Result of the query
|
||||
|
||||
If the query fails, the error callback will be invoked with two arguments:
|
||||
- Transaction object
|
||||
- Error information
|
||||
|
||||
The Web SQL Database API is callback-based. The following snippet runs one query
|
||||
and wraps the execution in a promise that resolves to the query result or
|
||||
rejects with the error:
|
||||
|
||||
```js
|
||||
function execute_simple_query(db, query) {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.transaction(tx =>
|
||||
tx.executeSQL(query, [],
|
||||
(tx, data) => resolve(data),
|
||||
(tx, err) => reject(err)
|
||||
)
|
||||
);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### Importing Data
|
||||
|
||||
Importing data from spreadsheets is straightforward using the `generate_sql`
|
||||
helper function from ["Generating Tables"](/docs/demos/data/sql#generating-tables)
|
||||
|
||||
```js
|
||||
const stmts = generate_sql(ws, wsname);
|
||||
|
||||
// NOTE: tx.executeSql and db.transaction use callbacks. This wraps in Promises
|
||||
for(var stmt of stmts) await new Promise((res, rej) => {
|
||||
db.transaction(tx =>
|
||||
tx.executeSql(stmt, [],
|
||||
(tx, data) => res(data), // if the query is successful, return the data
|
||||
(tx, err) => rej(err) // if the query fails, reject with the error
|
||||
));
|
||||
});
|
||||
```
|
||||
|
||||
Typically worksheet objects are extracted from workbook objects[^1] generated
|
||||
from the SheetJS `read` or `readFile` methods[^2].
|
||||
|
||||
### Exporting Data
|
||||
|
||||
The result of a SQL SELECT statement is a `SQLResultSet`. The `rows` property
|
||||
is a `SQLResultSetRowList`. It is an "array-like" structure that has `length`
|
||||
and properties like `0`, `1`, etc. However, this is not a real Array object!
|
||||
|
||||
A real Array can be created using `Array.from`. The SheetJS `json_to_sheet`
|
||||
method[^3] can generate a worksheet object[^4] from the real array:
|
||||
|
||||
```js
|
||||
db.readTransaction(tx =>
|
||||
tx.executeSQL("SELECT * FROM DatabaseTable", [], (tx, data) => {
|
||||
// data.rows is "array-like", so `Array.from` can make it a real array
|
||||
const aoo = Array.from(data.rows);
|
||||
const ws = XLSX.utils.json_to_sheet(aoo);
|
||||
// ... perform an export here OR wrap in a Promise
|
||||
})
|
||||
);
|
||||
```
|
||||
|
||||
Using `book_new` and `book_append_sheet`[^5], a workbook object can be created.
|
||||
This workbook is typically exported to the filesystem with `writeFile`[^6].
|
||||
|
||||
|
||||
|
||||
|
||||
## Live Demo
|
||||
|
||||
:::note
|
||||
|
||||
This browser demo was tested in the following environments:
|
||||
|
||||
| Browser | Date |
|
||||
|:------------|:-----------|
|
||||
| Chrome 117 | 2023-10-13 |
|
||||
|
||||
Some lesser-used browsers do not support WebSQL:
|
||||
|
||||
| Browser | Date | Support |
|
||||
|:------------|:-----------|:------------------------------------|
|
||||
| Safari 17.0 | 2023-10-13 | Error `Web SQL is deprecated` |
|
||||
| Firefox 118 | 2023-10-13 | Error `openDatabase is not defined` |
|
||||
|
||||
:::
|
||||
|
||||
### Export Demo
|
||||
|
||||
The following demo generates a database with 5 fixed SQL statements. Queries
|
||||
can be changed in the Live Editor. The WebSQL database can be inspected in the
|
||||
"WebSQL" section of the "Application" Tab of Developer Tools:
|
||||
|
||||
![WebSQL view in Developer Tools](pathname:///files/websql.png)
|
||||
|
||||
```jsx live
|
||||
function SheetQL() {
|
||||
const [out, setOut] = React.useState("");
|
||||
const queries = [
|
||||
'DROP TABLE IF EXISTS Presidents',
|
||||
'CREATE TABLE Presidents (Name TEXT, Idx REAL)',
|
||||
'INSERT INTO Presidents (Name, Idx) VALUES ("Barack Obama", 44)',
|
||||
'INSERT INTO Presidents (Name, Idx) VALUES ("Donald Trump", 45)',
|
||||
'INSERT INTO Presidents (Name, Idx) VALUES ("Joseph Biden", 46)'
|
||||
];
|
||||
const xport = React.useCallback(async() => {
|
||||
/* prep database */
|
||||
const db = openDatabase('sheetql', '1.0', 'SheetJS WebSQL Test', 2097152);
|
||||
|
||||
for(var q of queries) await new Promise((res, rej) => {
|
||||
db.transaction((tx) => {
|
||||
tx.executeSql(q, [], (tx, data) => res(data), (tx, err) => rej(err));
|
||||
});
|
||||
});
|
||||
|
||||
/* pull data and generate rows */
|
||||
db.readTransaction(tx => {
|
||||
tx.executeSql("SELECT * FROM Presidents", [], (tx, data) => {
|
||||
const aoo = Array.from(data.rows);
|
||||
setOut("QUERY RESULT:\n" + aoo.map(r => JSON.stringify(r)).join("\n") + "\n")
|
||||
const ws = XLSX.utils.json_to_sheet(aoo);
|
||||
const wb = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(wb, ws, "Presidents");
|
||||
XLSX.writeFile(wb, "SheetQL.xlsx");
|
||||
});
|
||||
});
|
||||
});
|
||||
return ( <pre>{out}<button onClick={xport}><b>Fetch!</b></button></pre> );
|
||||
}
|
||||
```
|
||||
|
||||
## Server-Side SQLite
|
||||
|
||||
**[The exposition has been moved to a separate page.](/docs/demos/data/sqlite)**
|
||||
|
||||
[^1]: See ["Workbook Object"](/docs/csf/book)
|
||||
[^2]: See [`read` and `readFile` in "Reading Files"](/docs/api/parse-options)
|
||||
[^3]: See [`json_to_sheet` in "Utilities"](/docs/api/utilities/array#array-of-objects-input)
|
||||
[^4]: See ["Sheet Objects"](/docs/csf/sheet)
|
||||
[^5]: See ["Workbook Helpers" in "Utilities"](/docs/api/utilities/wb) for details on `book_new` and `book_append_sheet`.
|
||||
[^6]: See [`writeFile` in "Writing Files"](/docs/api/write-options)
|
@ -22,7 +22,7 @@ tables with a content script and a background script.
|
||||
|
||||
:::note
|
||||
|
||||
This demo was last tested on 2023 June 06 against Chrome 114
|
||||
This demo was last tested on 2023 October 14 against Chrome 117.
|
||||
|
||||
:::
|
||||
|
||||
|
@ -94,7 +94,7 @@ This demo was tested in the following deployments:
|
||||
|
||||
| Architecture | Git Commit | Go version | Date |
|
||||
|:-------------|:-----------|:-----------|:-----------|
|
||||
| `darwin-x64` | `28ee0ee` | `1.19.3` | 2023-06-05 |
|
||||
| `darwin-x64` | `873a149` | `1.21.3` | 2023-10-14 |
|
||||
| `darwin-arm` | `28ee0ee` | `1.20.4` | 2023-06-05 |
|
||||
| `win10-x64` | `81d7606` | `1.20.2` | 2023-08-27 |
|
||||
| `win11-arm` | `fc55792` | `1.21.1` | 2023-09-25 |
|
||||
|
@ -44,7 +44,7 @@ These instructions were tested on the following platforms:
|
||||
| MacOS 10.13.6 (x64) | 2023-09-30 |
|
||||
| MacOS 13.6 (ARM64) | 2023-09-30 |
|
||||
| Windows 10 (x64) + WSL Ubuntu | 2023-07-23 |
|
||||
| Windows 11 (x64) + WSL Ubuntu | 2023-08-31 |
|
||||
| Windows 11 (x64) + WSL Ubuntu | 2023-10-14 |
|
||||
| Windows 11 (ARM) + WSL Ubuntu | 2023-09-18 |
|
||||
|
||||
With some additional dependencies, the unminified scripts are reproducible and
|
||||
@ -64,7 +64,50 @@ import TabItem from '@theme/TabItem';
|
||||
|
||||
A) Ensure WSL ("WSL 2" in Windows 10) and the Ubuntu distribution are installed.
|
||||
|
||||
B) Install mercurial and subversion:
|
||||
<details open><summary><b>Installation Notes</b> (click to hide)</summary>
|
||||
|
||||
In "Turn Windows features on or off", the following features must be enabled:
|
||||
|
||||
- "Hyper-V" (including every sub-feature)
|
||||
- "Virtual Machine Platform"
|
||||
- "Windows Hypervisor Platform"
|
||||
- "Windows Subsystem for Linux"
|
||||
|
||||
The following command installs Ubuntu within WSL:
|
||||
|
||||
```powershell
|
||||
wsl --install Ubuntu
|
||||
```
|
||||
|
||||
:::caution pass
|
||||
|
||||
In the last Windows 11 test, there was a `WSL_E_DEFAULT_DISTRO_NOT_FOUND` error.
|
||||
|
||||
The resolution is to switch to WSL1, install, and switch back to WSL2:
|
||||
|
||||
```
|
||||
wsl --set-default-version 1
|
||||
wsl --install Ubuntu
|
||||
wsl --set-default-version 2
|
||||
wsl --install Ubuntu
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
:::warning pass
|
||||
|
||||
**WSL will not run in a Windows on ARM VM on computers with the M1 CPU**
|
||||
|
||||
Apple Silicon M1 processors do not support nested virtualization.
|
||||
|
||||
M2 processors do support nested virtualization. SheetJS users have reported
|
||||
success with Windows on ARM running on computers with the M2 Max CPU.
|
||||
|
||||
:::
|
||||
|
||||
</details>
|
||||
|
||||
B) Install mercurial and subversion from within WSL:
|
||||
|
||||
```bash
|
||||
sudo apt-get update
|
||||
@ -93,7 +136,7 @@ sudo add-apt-repository --remove ppa:mercurial-ppa/releases
|
||||
|
||||
:::
|
||||
|
||||
C) Install NodeJS
|
||||
C) Install NodeJS within WSL:
|
||||
|
||||
:::info pass
|
||||
|
||||
@ -112,7 +155,9 @@ curl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E bash -
|
||||
sudo apt-get install -y nodejs
|
||||
```
|
||||
|
||||
Exit the WSL window and open a new one before proceeding:
|
||||
D) Exit the WSL session and start a new session
|
||||
|
||||
E) Install the `n` package and switch NodeJS vesrions:
|
||||
|
||||
```bash
|
||||
# Switch to `n`-managed NodeJS
|
||||
@ -130,12 +175,14 @@ sudo apt-get install -y npm
|
||||
|
||||
:::
|
||||
|
||||
D) Test clone the [`js-crc32` repo](https://git.sheetjs.com/sheetjs/js-crc32)
|
||||
F) Clone the [`js-crc32` repo](https://git.sheetjs.com/sheetjs/js-crc32)
|
||||
|
||||
```bash
|
||||
git clone https://git.sheetjs.com/sheetjs/js-crc32
|
||||
```
|
||||
|
||||
:::note pass
|
||||
|
||||
If this clone fails with an error message that mentions SSL or secure connection
|
||||
or certificates, build and install a version of Git with proper SSL support:
|
||||
|
||||
@ -146,7 +193,9 @@ chmod +x compile-git-with-openssl.sh
|
||||
./compile-git-with-openssl.sh
|
||||
```
|
||||
|
||||
E) Set `git` config `core.autocrlf` setting to `false`. The following commands
|
||||
:::
|
||||
|
||||
G) Set `git` config `core.autocrlf` setting to `false`. The following commands
|
||||
should be run twice, once within PowerShell (if Git for Windows is installed)
|
||||
and once within WSL bash:
|
||||
|
||||
@ -155,10 +204,16 @@ git config --global --add core.autocrlf false
|
||||
git config --global --unset core.autocrlf true
|
||||
```
|
||||
|
||||
F) Run `unzip`. If the program is missing, install manually:
|
||||
H) Run `unzip`. If the program is missing, install manually:
|
||||
|
||||
```bash
|
||||
sudo apt-get install -y unzip
|
||||
```
|
||||
|
||||
I) Run `make`. If the program is missing, install manually:
|
||||
|
||||
```bash
|
||||
sudo apt-get install -y make
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@ -207,7 +262,7 @@ for "LTS" and "Current" releases. The "LTS" version should be installed.
|
||||
In local testing, macOS 10.13 required NodeJS version `12.22.12`:
|
||||
|
||||
```bash
|
||||
curl -LO https://nodejs.org/download/release/v12.22.12/node-v12.22.12.pkg
|
||||
curl -LO https://nodejs.org/download/release/v12.22.12/node-v12.22.12.pkg
|
||||
open node-v12.22.12.pkg
|
||||
```
|
||||
|
||||
|
@ -216,6 +216,7 @@ const config = {
|
||||
{ from: '/docs/demos/localfile', to: '/docs/demos/local/file/' },
|
||||
{ from: '/docs/demos/data/indexeddb', to: '/docs/demos/local/indexeddb/' },
|
||||
{ from: '/docs/demos/data/storageapi', to: '/docs/demos/local/storageapi/' },
|
||||
{ from: '/docs/demos/data/websql', to: '/docs/demos/local/websql/' },
|
||||
/* desktop */
|
||||
{ from: '/docs/demos/cli', to: '/docs/demos/desktop/cli/' },
|
||||
{ from: '/docs/getting-started/demos/cli', to: '/docs/demos/desktop/cli/' },
|
||||
|
BIN
docz/static/sqlite/chinook.db
Normal file
BIN
docz/static/sqlite/chinook.db
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user