websqlite

This commit is contained in:
SheetJS 2023-10-14 22:39:07 -04:00
parent 45d0ed0e13
commit 009d4e0a21
12 changed files with 623 additions and 278 deletions

@ -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`

@ -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>

@ -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/' },

Binary file not shown.