standalone

This commit is contained in:
SheetJS 2023-08-23 04:05:30 -04:00
parent 4c191dcc59
commit 584af134db
4 changed files with 146 additions and 44 deletions

@ -28,14 +28,13 @@ new versions are released!
:::
:::warning
:::warning pass
A number of services host older versions of the SheetJS libraries. Due to
syncing issues, they are generally out of date.
They are known CDN bugs.
<https://cdn.sheetjs.com/> is the authoritative source for SheetJS modules.
**The SheetJS CDN** <https://cdn.sheetjs.com/> **is the authoritative source**
**for SheetJS scripts**
:::
@ -67,6 +66,23 @@ scratch, a single script tag should be added at the top of the HTML page:
</details>
### Vendoring
For general stability, "vendoring" scripts is the recommended approach:
<p>1) Download the script (<code parentName="pre">xlsx.full.min.js</code>) for
the desired version. The current version is available at <a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js`}>https://cdn.sheetjs.com/xlsx-{current}/package/dist/xlsx.full.min.js</a></p>
2) Move the script to a `public` folder with other scripts.
3) Reference the local script from HTML pages:
```html
<script src="/public/xlsx.full.min.js"></script>
```
This script assigns to `window.XLSX`. The global can be used in other scripts.
### Internet Explorer and Older Browsers
For broad compatibility with JavaScript engines, the library is written using
@ -104,11 +120,11 @@ importScripts("https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.mi
## ECMAScript Module Imports
:::caution
:::caution pass
This section refers to imports using `script type="module"`. For imports in
modern projects using Webpack or React or Angular or VueJS, the installation is
described [in the next section](/docs/getting-started/installation/frameworks).
described [in "Frameworks and Bundlers"](/docs/getting-started/installation/frameworks).
:::
@ -132,15 +148,19 @@ set_cptable(cptable);
</script>`}
</CodeBlock>
Dynamic imports with `import()` can be used in data export scenarios. This
example will download the library only when the export button is pressed:
Web Worker support is noted in [the "Web Workers" demo](/docs/demos/bigdata/worker#installation)
### Dynamic Imports
Dynamic imports with `import()` will only download the SheetJS scripts when they
are used. This example will download the library when data is exported:
<CodeBlock language="html">{`\
<button id="xport">Export</button>
<script type="module">
xport.addEventListener("click", async() => {
\n\
/* dynamically import the library in the event listener */
/* dynamically import the script in the event listener */
// highlight-next-line
const XLSX = await import("https://cdn.sheetjs.com/xlsx-${current}/package/xlsx.mjs");
\n\
@ -152,11 +172,38 @@ xport.addEventListener("click", async() => {
</script>`}
</CodeBlock>
Web Worker support is noted in [the demo](/docs/demos/bigdata/worker#installation)
:::caution pass
The callback functions must be marked as `async` and the script block must have
the attribute `type="module"`
:::
If Encoding support is required, `cpexcel.full.mjs` must be manually imported:
<CodeBlock language="html">{`\
<button id="xport">Export</button>
<script type="module">
xport.addEventListener("click", async() => {
\n\
/* dynamically import the scripts in the event listener */
// highlight-start
const XLSX = await import("https://cdn.sheetjs.com/xlsx-${current}/package/xlsx.mjs");
const cptable = await import("https://cdn.sheetjs.com/xlsx-${current}/package/dist/cpexcel.full.mjs");
XLSX.set_cptable(cptable);
// highlight-end
\n\
const wb = XLSX.utils.book_new();
const ws = XLSX.utils.aoa_to_sheet([["a","b","c"],[1,2,3]]);
XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
XLSX.writeFile(wb, "SheetJSESMTest.xlsx");
});
</script>`}
</CodeBlock>
## Bower
:::caution
:::warning pass
Bower is deprecated and the maintainers recommend using other tools.

@ -51,7 +51,7 @@ This demo was tested in the following environments:
| Windows 10 | x64 | `v0.71.25` | 2023-07-24 |
| Windows 11 | x64 | `v0.71.11` | 2023-05-11 |
| MacOS 12.6 | x64 | `v0.71.26` | 2023-07-23 |
| MacOS 13.4 | arm | `v0.71.18` | 2023-07-06 |
| MacOS 13.4 | ARM | `v0.71.18` | 2023-07-06 |
:::

@ -1,5 +1,7 @@
---
title: Redis
title: Redis Databases Wrapped in Sheets
sidebar_label: Redis
description: Store complex datasets in Redis. Seamlessly save data to spreadsheets and read data from sheets using SheetJS. Enable Excel spreadsheet experts to update content.
pagination_prev: demos/desktop/index
pagination_next: demos/local/index
sidebar_custom_props:
@ -9,6 +11,18 @@ sidebar_custom_props:
import current from '/version.js';
import CodeBlock from '@theme/CodeBlock';
[Redis](https://redis.io/) is a open source in-memory data store. It is capable
of storing sets, lists and other simple data structures.
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
data from spreadsheets.
This demo defines a schema for storing Redis databases in spreadsheets. We'll
explore how to use SheetJS and Redis NodeJS connector modules to pull data
from XLSX files to a Redis database and to serialize a database to a workbook.
#### Overview
Redis has 5 core data types: "String", List", "Set", "Sorted Set", and "Hash".
Since the keys and values are limited to simple strings (and numbers), it is
possible to store complete databases in a single worksheet.
@ -17,7 +31,7 @@ possible to store complete databases in a single worksheet.
## Integration Details
:::note
:::note pass
[`SheetJSRedis.mjs`](pathname:///nosql/SheetJSRedis.mjs) exports the methods:
- `redis_to_ws` creates a SheetJS worksheet by querying a redis client
@ -25,11 +39,32 @@ possible to store complete databases in a single worksheet.
:::
The first row holds the data type and the second row holds the property name.
### Array of Arrays
The "Exporting Data" snippets generate arrays of arrays that can be added to a
worksheet using `sheet_add_aoa`. Since the data is column-oriented, the goal is
to add the data starting in the first row of the column after the data:
The shared data representation is an "array of arrays"[^1]. Each array within
the structure corresponds to one row.
The Redis to SheetJS converter generates an array of arrays of the data by
running queries to fetch data from the database. The SheetJS `aoa_to_sheet` and
`sheet_add_aoa`[^2] methods build up worksheets from arrays of arrays. Once the
worksheet is created, it can be added to a SheetJS workbook object[^3] and
exported using `writeFile`[^4].
The SheetJS to Redis converter works in reverse. Workbook files are parsed with
the SheetJS `readFile` method[^5] and the desired worksheet is pulled from the
workbook object. An array of arrays can be created with the `sheet_to_json`[^6]
utility function. The data structure can be scanned to generate Redis queries.
### Appending Columns
Since the data is column-oriented, the goal is to add the data starting on the
first row of the column after the data.
To calculate the starting point for writing data, SheetJS provides `encode_cell`
and `decode_range` utility functions for working with addresses and ranges[^7].
The following snippet takes an array of arrays of values and writes the values
to a worksheet starting from the column after the worksheet range:
```js
function add_aoa_to_next_column(worksheet, aoa) {
@ -45,14 +80,7 @@ function add_aoa_to_next_column(worksheet, aoa) {
}
```
The "Importing Data" snippets generate redis queries. The `ws_to_redis` function
first generates an array of arrays with `sheet_to_json`:
```js
const aoa = XLSX.utils.sheet_to_json(worksheet, { header: 1 });
```
#### Strings
### Strings
Strings can be stored in a unified String table. The first column holds keys
and the second column holds values:
@ -67,7 +95,11 @@ XXX| A | B |
```
The SheetJS array-of-arrays representation of the string table is an array of
key/value pairs:
key/value pairs.
The pairs can be generated from Redis by querying for all of the keys using the
`KEYS`[^8] method, testing if the corresponding value is a string using the
`TYPE`[^9] method, and fetching string values using the `GET`[^10] method:
```js
const aoa = ["Strings"]; aoa.length = 2; // [ "Strings", empty ]
@ -80,7 +112,7 @@ for(let key of keys) {
}
```
#### Lists
### Lists
Lists are unidimensional and can be stored in their own columns.
@ -94,15 +126,18 @@ XXX| C |
```
The SheetJS array-of-arrays representation of lists is a column of values.
`LRANGE` returns a simple array of values. `sheet_add_aoa` interprets the result
as one row. The code transposes the result with `values.map(v => [v])`.
Redis `LRANGE`[^11] returns a simple array of values. `sheet_add_aoa` interprets
the result as one row, so the data should be transposed.
The code transposes the result with `values.map(v => [v])`.
```js
const values = await client.LRANGE(key, 0, -1);
const aoa = [ ["List"], [key] ].concat(values.map(v => [v]));
```
#### Sets
### Sets
Sets are unidimensional and can be stored in their own columns.
@ -116,15 +151,18 @@ XXX| D |
```
The SheetJS array-of-arrays representation of sets is a column of values.
`SMEMBERS` returns a simple array of values. `sheet_add_aoa` interprets result
as one row. The code transposes the result with `values.map(v => [v])`.
Redis `SMEMBERS`[^12] returns an array of values. `sheet_add_aoa` interprets the
result as one row, so the data should be transposed.
The code transposes the result with `values.map(v => [v])`.
```js
const values = await client.SMEMBERS(key);
const aoa = [ ["Set"], [key] ].concat(values.map(v => [v]));
```
#### Sorted Sets
### Sorted Sets
Sorted Sets have an associated score which can be stored in the second column.
@ -138,14 +176,15 @@ XXX| E | F |
```
The SheetJS array-of-arrays representation is an array of key/score pairs.
`ZRANGE_WITHSCORES` returns an array of objects which can be reshaped.
`ZRANGE_WITHSCORES`[^13] returns an array of objects which can be reshaped.
```js
const values = await client.ZRANGE_WITHSCORES(key, 0, -1);
const aoa = [ ["Sorted"], [key] ].concat(values.map(v => [v.value, v.score]));
```
#### Hashes
### Hashes
Hashes are stored like the string table, with key and value columns in order.
@ -159,7 +198,8 @@ XXX| G | H |
```
The SheetJS array-of-arrays representation is an array of key/value pairs.
`HGETALL` returns a plain object which can be converted using `Object.entries`:
`HGETALL`[^14] returns an object which can be converted using `Object.entries`:
```js
const values = await client.HGETALL(key);
@ -170,8 +210,8 @@ const aoa = [ ["Hash"], [key] ].concat(Object.entries(values));
:::note
This demo was last tested on 2023 May 11 with Redis 7.0.11, Redis connector
module 4.6.6 and NodeJS 20.1.0.
This demo was last tested on 2023 August 22 with Redis 7.2.0, Redis connector
module 4.6.7 and NodeJS 20.5.1.
:::
@ -187,10 +227,10 @@ this demo also requires NodeJS version 18 or later.
:::note
This demo was last tested on Intel macOS. Redis was installed with:
This demo was last tested on macOS. Redis was installed with:
```bash
brew install redis@7.0.11
brew install redis
```
The following command started the server process:
@ -214,7 +254,7 @@ curl -LO https://docs.sheetjs.com/nosql/SheetJSRedisTest.mjs
2) Install dependencies:
<CodeBlock language="bash">{`\
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz redis@4.6.6`}
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz redis@4.6.7`}
</CodeBlock>
3) Run the test script:
@ -226,3 +266,18 @@ node SheetJSRedisTest.mjs
Inspect the output and compare with the data in `SheetJSRedisTest.mjs`.
Open `SheetJSRedis.xlsx` and verify the columns have the correct data
[^1]: See ["Array of Arrays" in "Utility Functions"](/docs/api/utilities/array#array-of-arrays)
[^2]: See ["Array of Arrays Input" in "Utility Functions"](/docs/api/utilities/array#array-of-arrays-input).
[^3]: See ["Workbook Helpers" in "Utility Functions"](/docs/api/utilities/wb)
[^4]: See [`writeFile` in "Writing Files"](/docs/api/write-options)
[^5]: See [`readFile` in "Reading Files"](/docs/api/parse-options)
[^6]: See [`sheet_to_json` in "Utilities"](/docs/api/utilities/array#array-output)
[^7]: See ["Utilities" in "Addresses and Ranges"](/docs/csf/general#utilities)
[^8]: See [`KEYS`](https://redis.io/commands/keys/) in the Redis documentation.
[^9]: See [`TYPE`](https://redis.io/commands/type/) in the Redis documentation.
[^10]: See [`GET`](https://redis.io/commands/get/) in the Redis documentation.
[^11]: See [`LRANGE`](https://redis.io/commands/lrange/) in the Redis documentation.
[^12]: See [`SMEMBERS`](https://redis.io/commands/smembers/) in the Redis documentation.
[^13]: The official command is [`ZRANGE`](https://redis.io/commands/zrange/). `ZRANGE_WITHSCORES` is a special command supported by the NodeJS wrapper.
[^14]: See [`HGETALL`](https://redis.io/commands/hgetall/) in the Redis documentation.

@ -40,9 +40,9 @@ These instructions were tested on the following platforms:
| Platform | Test Date |
|:------------------------------|:-----------|
| Linux (Steam Deck Holo 3.4.8) | 2023-07-12 |
| Linux (Ubuntu 18.04 aarch64) | 2023-04-13 |
| Linux (Ubuntu 18.04 AArch64) | 2023-04-13 |
| MacOS 10.13 (x64) | 2023-04-04 |
| MacOS 13.0 (arm64) | 2023-04-13 |
| MacOS 13.0 (ARM64) | 2023-04-13 |
| Windows 10 (x64) + WSL Ubuntu | 2023-07-23 |
| Windows 11 (x64) + WSL Ubuntu | 2023-04-04 |