knex
This commit is contained in:
parent
7f366322e7
commit
4fd04640ae
@ -65,7 +65,7 @@ Snyk security tooling may report errors involving "Prototype Pollution":
|
||||
Prototype Pollution [Medium Severity][https://security.snyk.io/vuln/SNYK-JS-XLSX-5457926]
|
||||
```
|
||||
|
||||
As noted in the [Snyk report](https://security.snyk.io/vuln/SNYK-JS-XLSX-5457926):
|
||||
As noted in the [Snyk report](https://web.archive.org/web/20230920204324/https://security.snyk.io/vuln/SNYK-JS-XLSX-5457926):
|
||||
|
||||
> The issue is resolved in version 0.19.3
|
||||
|
||||
|
@ -55,7 +55,7 @@ Snyk security tooling may report errors involving "Prototype Pollution":
|
||||
Prototype Pollution [Medium Severity][https://security.snyk.io/vuln/SNYK-JS-XLSX-5457926]
|
||||
```
|
||||
|
||||
As noted in the [Snyk report](https://security.snyk.io/vuln/SNYK-JS-XLSX-5457926):
|
||||
As noted in the [Snyk report](https://web.archive.org/web/20230920204324/https://security.snyk.io/vuln/SNYK-JS-XLSX-5457926):
|
||||
|
||||
> The issue is resolved in version 0.19.3
|
||||
|
||||
|
@ -50,7 +50,7 @@ Bun supports both "CommonJS" and "ESM" modules.
|
||||
|
||||
:::info pass
|
||||
|
||||
It is strongly recommended to use CommonJS in Bun.
|
||||
**It is strongly recommended to use CommonJS in Bun.**
|
||||
|
||||
:::
|
||||
|
||||
|
@ -246,7 +246,7 @@ The first presidential term can be found with the following function:
|
||||
const first_prez_term = prez => prez.terms.find(term => term.type === "prez");
|
||||
```
|
||||
|
||||
:::note
|
||||
:::note pass
|
||||
|
||||
If no element in the array matches the criterion, `Array#find` does not return
|
||||
a value. In this case, since `prez` was created by filtering for people that
|
||||
@ -647,10 +647,23 @@ The server process will display a URL (typically `http://127.0.0.1:8080`). Open
|
||||
|
||||
Install the dependencies:
|
||||
|
||||
<Tabs groupId="ssplat">
|
||||
<TabItem value="nodejs" label="NodeJS">
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
|
||||
</CodeBlock>
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="bun" label="Bun">
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
bun install https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
|
||||
</CodeBlock>
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
Save the following script to `SheetJSNodeJS.js`:
|
||||
|
||||
```js title="SheetJSNodeJS.js"
|
||||
@ -693,10 +706,23 @@ const XLSX = require("xlsx");
|
||||
|
||||
After saving the script, run the script:
|
||||
|
||||
<Tabs groupId="ssplat">
|
||||
<TabItem value="nodejs" label="NodeJS">
|
||||
|
||||
```bash
|
||||
node SheetJSNodeJS.js
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="bun" label="Bun">
|
||||
|
||||
```bash
|
||||
bun run SheetJSNodeJS.js
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This script will write a new file `Presidents.xlsx` in the same folder.
|
||||
|
||||
:::caution pass
|
||||
@ -818,63 +844,6 @@ After saving the script, run the script:
|
||||
deno run -A SheetJSDeno.ts
|
||||
```
|
||||
|
||||
This script will write a new file `Presidents.xlsx` in the same folder.
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="bun" label="Bun">
|
||||
|
||||
<p>Download <a href={`https://cdn.sheetjs.com/xlsx-${current}/package/xlsx.mjs`}>https://cdn.sheetjs.com/xlsx-{current}/package/xlsx.mjs</a> to <code>xlsx.mjs</code>:</p>
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
curl -LO https://cdn.sheetjs.com/xlsx-${current}/package/xlsx.mjs`}
|
||||
</CodeBlock>
|
||||
|
||||
Save the following script to `SheetJSBun.js`:
|
||||
|
||||
```js title="SheetJSBun.js"
|
||||
import * as XLSX from './xlsx.mjs';
|
||||
import * as fs from 'fs';
|
||||
XLSX.set_fs(fs);
|
||||
|
||||
/* fetch JSON data and parse */
|
||||
const url = "https://sheetjs.com/data/executive.json";
|
||||
const raw_data = await (await fetch(url)).json();
|
||||
|
||||
/* filter for the Presidents */
|
||||
const prez = raw_data.filter((row) => row.terms.some((term) => term.type === "prez"));
|
||||
|
||||
/* sort by first presidential term */
|
||||
prez.forEach(row => row.start = row.terms.find(term => term.type === "prez").start);
|
||||
prez.sort((l,r) => l.start.localeCompare(r.start));
|
||||
|
||||
/* flatten objects */
|
||||
const rows = prez.map((row) => ({
|
||||
name: row.name.first + " " + row.name.last,
|
||||
birthday: row.bio.birthday
|
||||
}));
|
||||
|
||||
/* generate worksheet and workbook */
|
||||
const worksheet = XLSX.utils.json_to_sheet(rows);
|
||||
const workbook = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, "Dates");
|
||||
|
||||
/* fix headers */
|
||||
XLSX.utils.sheet_add_aoa(worksheet, [["Name", "Birthday"]], { origin: "A1" });
|
||||
|
||||
/* calculate column width */
|
||||
const max_width = rows.reduce((w, r) => Math.max(w, r.name.length), 10);
|
||||
worksheet["!cols"] = [ { wch: max_width } ];
|
||||
|
||||
/* create an XLSX file and try to save to Presidents.xlsx */
|
||||
XLSX.writeFile(workbook, "Presidents.xlsx", { compression: true });
|
||||
```
|
||||
|
||||
After saving the script, run the script:
|
||||
|
||||
```bash
|
||||
bun SheetJSBun.js
|
||||
```
|
||||
|
||||
This script will write a new file `Presidents.xlsx` in the same folder.
|
||||
|
||||
</TabItem>
|
||||
@ -1054,7 +1023,7 @@ export default App;
|
||||
<Tabs>
|
||||
<TabItem value="asim" label="Android">
|
||||
|
||||
:::note
|
||||
:::note pass
|
||||
|
||||
The Android demo has been tested in Windows 10 and in macOS.
|
||||
|
||||
@ -1169,5 +1138,5 @@ see a preview of the data. The Numbers app can open the file.
|
||||
[^4]: See [`book_new` in "Utilities"](/docs/api/utilities/wb)
|
||||
[^5]: See [`book_append_sheet` in "Utilities"](/docs/api/utilities/wb)
|
||||
[^6]: See [`sheet_add_aoa` in "Utilities"](/docs/api/utilities/array#array-of-arrays-input)
|
||||
[^7]: See ["Row and Column Properties"](/docs/csf/features/#row-and-column-properties)
|
||||
[^7]: See ["Column Properties"](/docs/csf/features/colprops)
|
||||
[^8]: See [`writeFile` in "Writing Files"](/docs/api/write-options)
|
@ -775,10 +775,23 @@ The server process will display a URL (typically `http://127.0.0.1:8080`). Open
|
||||
|
||||
Install the dependencies:
|
||||
|
||||
<Tabs groupId="ssplat">
|
||||
<TabItem value="nodejs" label="NodeJS">
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
|
||||
</CodeBlock>
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="bun" label="Bun">
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
bun install https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
|
||||
</CodeBlock>
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
Save the following script to `SheetJSNodeJS.js`:
|
||||
|
||||
```js title="SheetJSNodeJS.js"
|
||||
@ -813,10 +826,23 @@ const XLSX = require("xlsx");
|
||||
|
||||
After saving the script, run the script:
|
||||
|
||||
<Tabs groupId="ssplat">
|
||||
<TabItem value="nodejs" label="NodeJS">
|
||||
|
||||
```bash
|
||||
node SheetJSNodeJS.js
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="bun" label="Bun">
|
||||
|
||||
```bash
|
||||
bun run SheetJSNodeJS.js
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This script will print the rows in tab-separated values (TSV) format:
|
||||
|
||||
```
|
||||
@ -985,7 +1011,7 @@ export default App;
|
||||
<Tabs>
|
||||
<TabItem value="asim" label="Android">
|
||||
|
||||
:::note
|
||||
:::note pass
|
||||
|
||||
The Android demo has been tested in Windows 10 and in macOS.
|
||||
|
||||
|
@ -22,7 +22,7 @@ This demo was last verified on 2023 September 03.
|
||||
|
||||
## Live Demo
|
||||
|
||||
:::note pass
|
||||
:::caution pass
|
||||
|
||||
Due to CSS conflicts between the data grid and the documentation generator,
|
||||
features like scrolling may not work as expected.
|
||||
|
@ -21,7 +21,7 @@ This demo was last verified on 2023 September 03.
|
||||
|
||||
## Live Demo
|
||||
|
||||
:::note
|
||||
:::caution pass
|
||||
|
||||
Due to CSS conflicts between the data grid and the documentation generator,
|
||||
features like scrolling may not work as expected.
|
||||
|
@ -75,7 +75,7 @@ function rdg_to_ws(rows: Row[]): WorkSheet {
|
||||
}
|
||||
```
|
||||
|
||||
:::caution
|
||||
:::caution pass
|
||||
|
||||
When the demo was last refreshed, row array objects were preserved. This was
|
||||
not the case in a later release. The row arrays must be re-created.
|
||||
|
@ -131,7 +131,7 @@ function ws_to_muidg(ws: WorkSheet): RowCol {
|
||||
|
||||
In the other direction, a worksheet can be generated with `aoa_to_sheet`:
|
||||
|
||||
:::caution
|
||||
:::caution pass
|
||||
|
||||
`x-data-grid` does not properly preserve row array objects, so the row arrays
|
||||
must be re-created. The snippet defines a `arrayify` function.
|
||||
|
@ -11,7 +11,7 @@ Various JavaScript UI components provide a more interactive editing experience.
|
||||
Most are able to interchange with arrays of arrays or arrays of data objects.
|
||||
This demo focuses on a few open source data grids.
|
||||
|
||||
:::note
|
||||
:::tip pass
|
||||
|
||||
[SheetJS Pro](https://sheetjs.com/pro) offers additional features like styling
|
||||
and images. The UI tools typically support many of these advanced features.
|
||||
|
@ -362,7 +362,7 @@ async function workbook_dl_axios(url) {
|
||||
This demo uses `axios` to download <https://sheetjs.com/pres.numbers> and show
|
||||
the data in an HTML table.
|
||||
|
||||
:::caution
|
||||
:::caution pass
|
||||
|
||||
If the live demo shows a message
|
||||
|
||||
@ -471,7 +471,7 @@ superagent
|
||||
This demo uses `superagent` to download <https://sheetjs.com/pres.numbers> and
|
||||
show the data in an HTML table.
|
||||
|
||||
:::caution
|
||||
:::caution pass
|
||||
|
||||
If the live demo shows a message
|
||||
|
||||
|
@ -54,7 +54,7 @@ It is strongly recommended to first test with an independent service provider.
|
||||
This demo will start with a free 30-day trial of Fastmail. At the time the demo
|
||||
was last tested, no payment details were required.
|
||||
|
||||
:::caution
|
||||
:::caution pass
|
||||
|
||||
A valid phone number (for SMS verification) was required.
|
||||
|
||||
@ -105,7 +105,7 @@ const msg = { from: "*", to: "*", subject: "*", text: "*",
|
||||
}
|
||||
```
|
||||
|
||||
:::caution
|
||||
:::caution pass
|
||||
|
||||
The file name must have the expected extension for the `bookType`!
|
||||
|
||||
@ -195,7 +195,7 @@ including `accepted` and `response`. The recipient inbox should receive an email
|
||||
shortly. The email will include an attachment `SheetJSMailExport.xlsb` which
|
||||
can be opened in Excel.
|
||||
|
||||
:::caution
|
||||
:::caution pass
|
||||
|
||||
The app password must be entered in step 3. If the account password was used,
|
||||
the mailer will fail with a message that includes:
|
||||
|
@ -17,7 +17,7 @@ is a transformer that generates GraphQL nodes for each row of each worksheet.
|
||||
The plugin is officially supported by the Gatsby team. The plugin documentation
|
||||
includes examples and more detailed usage instructions.
|
||||
|
||||
:::note
|
||||
:::note pass
|
||||
|
||||
`gatsby-transformer-excel` is maintained by the Gatsby core team and all bugs
|
||||
should be directed to the main Gatsby project. If it is determined to be a bug
|
||||
@ -25,7 +25,7 @@ in the parsing logic, issues should then be raised with the SheetJS project.
|
||||
|
||||
:::
|
||||
|
||||
:::caution
|
||||
:::caution pass
|
||||
|
||||
`gatsby-transformer-excel` uses an older version of the library. It can be
|
||||
overridden through a `package.json` override in the latest versions of NodeJS:
|
||||
|
@ -9,10 +9,11 @@ sidebar_custom_props:
|
||||
import current from '/version.js';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
:::note
|
||||
:::info pass
|
||||
|
||||
This demo covers static asset imports. For processing files in the browser, the
|
||||
["Bundlers" demo](/docs/demos/frontend/bundler#webpack) includes an example.
|
||||
["Bundlers" demo](/docs/demos/frontend/bundler#webpack) includes an example of
|
||||
importing the SheetJS library in a browser script.
|
||||
|
||||
:::
|
||||
|
||||
|
@ -314,7 +314,7 @@ The app should now show two buttons at the bottom:
|
||||
|
||||
![Quasar Step 6](pathname:///mobile/quasar6.png)
|
||||
|
||||
:::caution
|
||||
:::caution pass
|
||||
|
||||
If the app is blank or not refreshing, delete the app and close the simulator,
|
||||
then restart the development process.
|
||||
|
@ -121,7 +121,7 @@ async function importFile() {
|
||||
}
|
||||
```
|
||||
|
||||
:::note
|
||||
:::note pass
|
||||
|
||||
In older versions of Electron, `showOpenDialog` returned the path directly:
|
||||
|
||||
@ -161,7 +161,7 @@ async function exportFile(workbook) {
|
||||
}
|
||||
```
|
||||
|
||||
:::note
|
||||
:::note pass
|
||||
|
||||
In older versions of Electron, `showSaveDialog` returned the path directly:
|
||||
|
||||
@ -208,7 +208,7 @@ The demo project is wired for `electron-forge` to build the standalone binary.
|
||||
- [`index.html`](pathname:///electron/index.html) : window page
|
||||
- [`index.js`](pathname:///electron/index.js) : script loaded in render context
|
||||
|
||||
:::caution
|
||||
:::caution pass
|
||||
|
||||
Right-click each link and select "Save Link As...". Left-clicking a link will
|
||||
try to load the page in your browser. The goal is to save the file contents.
|
||||
@ -302,7 +302,7 @@ the required changes for Electron 23.0.0.
|
||||
There are no Electron-specific workarounds in the library, but Electron broke
|
||||
backwards compatibility multiple times. A summary of changes is noted below.
|
||||
|
||||
:::caution
|
||||
:::caution pass
|
||||
|
||||
Electron 6.x changed the `dialog` API. Methods like `showSaveDialog` originally
|
||||
returned an array of strings, but now returns a `Promise`. This change was not
|
||||
|
@ -130,7 +130,7 @@ This demo was tested against NW.js 0.78.0 on 2023 July 27.
|
||||
|
||||
2) Download [`index.html`](pathname:///nwjs/index.html) into the same folder.
|
||||
|
||||
:::caution
|
||||
:::caution pass
|
||||
|
||||
Right-click the link and select "Save Link As...". Left-clicking the link will
|
||||
try to load the page in your browser. The goal is to save the file contents.
|
||||
|
@ -228,7 +228,7 @@ export default App;
|
||||
|
||||
## Native Modules
|
||||
|
||||
:::caution
|
||||
:::caution pass
|
||||
|
||||
As with the mobile versions of React Native, file operations are not provided
|
||||
by the base SDK. The examples include native code for both Windows and macOS.
|
||||
@ -387,7 +387,7 @@ There is no simple standalone executable file at the end of the process.
|
||||
|
||||
:::
|
||||
|
||||
:::note
|
||||
:::note pass
|
||||
|
||||
React Native Windows supports writing native code in C++ or C#. This demo has
|
||||
been tested against both application types.
|
||||
@ -396,7 +396,7 @@ been tested against both application types.
|
||||
|
||||
0) Follow the ["Getting Started" guide](https://microsoft.github.io/react-native-windows/docs/getting-started)
|
||||
|
||||
:::caution
|
||||
:::caution pass
|
||||
|
||||
At the time of testing, NodeJS `v16` was required. A tool like
|
||||
[`nvm-windows`](https://github.com/coreybutler/nvm-windows/releases) should be
|
||||
@ -447,7 +447,7 @@ npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
|
||||
npx react-native run-windows --no-telemetry
|
||||
```
|
||||
|
||||
:::caution
|
||||
:::caution pass
|
||||
|
||||
When the demo was tested in Windows 11, the run step failed with the message:
|
||||
|
||||
|
@ -112,7 +112,7 @@ npx nexe -t 14.15.3 xlsx-cli.js
|
||||
|
||||
This generates `xlsx-cli` or `xlsx-cli.exe` depending on platform.
|
||||
|
||||
:::caution
|
||||
:::caution pass
|
||||
|
||||
When the demo was tested on `darwin-arm`, the `mac-arm64` pre-built package was
|
||||
missing. The package must be built from source:
|
||||
|
@ -16,7 +16,7 @@ work as-is in WebSQL.
|
||||
|
||||
The public demo <https://sheetjs.com/sql> generates a database from workbook.
|
||||
|
||||
:::caution
|
||||
:::caution pass
|
||||
|
||||
WebSQL is only supported in Chromium-based browsers including Chrome.
|
||||
|
||||
|
@ -9,33 +9,169 @@ sidebar_custom_props:
|
||||
import current from '/version.js';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
[KnexJS](https://knexjs.org/) is a SQL query builder with support for a number
|
||||
of SQL dialects.
|
||||
|
||||
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
|
||||
data from spreadsheets.
|
||||
|
||||
This demo uses KnexJS 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 April 19 with Knex 2.4.2 and `better-sqlite`.
|
||||
This demo was last tested on 2023 September 23 with Knex 2.5.1. The demo uses
|
||||
the SQLite backend with the `better-sqlite3` connector.
|
||||
|
||||
:::
|
||||
|
||||
## Integration Details
|
||||
|
||||
#### Importing Data
|
||||
The [SheetJS NodeJS module](/docs/getting-started/installation/nodejs) can be
|
||||
loaded in NodeJS scripts that use KnexJS.
|
||||
|
||||
`sheet_to_json` generates an array of objects. An `INSERT` statement can be
|
||||
generated from each row object using `knex.insert`:
|
||||
### Exporting Data
|
||||
|
||||
The KnexJS `select` method[^1] creates a `SELECT` query. The return value is a
|
||||
Promise that resolves to an array of objects.
|
||||
|
||||
The SheetJS `json_to_sheet` method[^2] can generate a worksheet object[^3] from
|
||||
the array of objects:
|
||||
|
||||
```js
|
||||
const aoo = XLSX.utils.sheet_to_json(ws);
|
||||
for(let i = 0; i < aoo.length; ++i) await knex.insert(aoo[i]).into(table_name);
|
||||
```
|
||||
const table_name = "Tabeller1"; // name of table
|
||||
|
||||
#### Exporting Data
|
||||
|
||||
The result of a `SELECT` statement is an array of objects:
|
||||
|
||||
```js
|
||||
/* fetch all data from specified table */
|
||||
const aoo = await knex.select("*").from(table_name);
|
||||
|
||||
/* generate a SheetJS worksheet object from the data */
|
||||
const worksheet = XLSX.utils.json_to_sheet(aoo);
|
||||
```
|
||||
|
||||
A workbook object can be built from the worksheet using utility functions[^4].
|
||||
The workbook can be exported using the SheetJS `writeFile` method[^5]:
|
||||
|
||||
```js
|
||||
/* create a new workbook and add the worksheet */
|
||||
const wb = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(wb, worksheet, "Sheet1");
|
||||
|
||||
/* export workbook to XLSX */
|
||||
XLSX.writeFile(wb, "SheetJSKnexJSExport.xlsx");
|
||||
```
|
||||
|
||||
### Importing Data
|
||||
|
||||
The SheetJS `sheet_to_json` function[^6] takes a worksheet object and generates
|
||||
an array of objects.
|
||||
|
||||
The KnexJS `insert` method[^7] creates `INSERT` queries. The return value is a
|
||||
Promise that resolves when the query is executed:
|
||||
|
||||
```js
|
||||
const table_name = "Blatte1"; // name of table
|
||||
|
||||
/* generate an array of arrays from the worksheet */
|
||||
const aoo = XLSX.utils.sheet_to_json(ws);
|
||||
|
||||
/* insert every row into the specified database table */
|
||||
await knex.insert(aoo).into(table_name);
|
||||
```
|
||||
|
||||
### Creating a Table
|
||||
|
||||
The KnexJS Schema Builder supports creating tables with `createTable`[^8] and
|
||||
dropping tables with `dropTableIfExists`[^9].
|
||||
|
||||
The array of objects can be scanned to determine column names and types.
|
||||
|
||||
<details><summary><b>Implementation Details</b> (click to show)</summary>
|
||||
|
||||
The `aoo_to_knex_table` function:
|
||||
|
||||
- scans each row object to determine column names and types
|
||||
- drops and creates a new table with the determined column names and types
|
||||
- loads the entire dataset into the new table
|
||||
|
||||
```js
|
||||
/* create table and load data given an array of objects and a Knex connection */
|
||||
async function aoo_to_knex_table(knex, aoo, table_name) {
|
||||
/* define types that can be converted (e.g. boolean can be stored in float) */
|
||||
const T_FLOAT = ["float", "boolean"];
|
||||
const T_BOOL = ["boolean"];
|
||||
|
||||
/* types is a map from column headers to Knex schema column type */
|
||||
const types = {};
|
||||
|
||||
/* names is an ordered list of the column header names */
|
||||
const names = [];
|
||||
|
||||
/* loop across each row object */
|
||||
aoo.forEach(row =>
|
||||
/* Object.entries returns a row of [key, value] pairs */
|
||||
Object.entries(row).forEach(([k,v]) => {
|
||||
|
||||
/* If this is first occurrence, mark unknown and append header to names */
|
||||
if(!types[k]) { types[k] = ""; names.push(k); }
|
||||
|
||||
/* skip null and undefined values */
|
||||
if(v == null) return;
|
||||
|
||||
/* check and resolve type */
|
||||
switch(typeof v) {
|
||||
/* change type if it is empty or can be stored in a float */
|
||||
case "number": if(!types[k] || T_FLOAT.includes(types[k])) types[k] = "float"; break;
|
||||
/* change type if it is empty or can be stored in a boolean */
|
||||
case "boolean": if(!types[k] || T_BOOL.includes(types[k])) types[k] = "boolean"; break;
|
||||
/* no other type can hold strings */
|
||||
case "string": types[k] = "text"; break;
|
||||
default: types[k] = "text"; break;
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
/* Delete table if it exists in the DB */
|
||||
await knex.schema.dropTableIfExists(table_name);
|
||||
|
||||
/* use column type info to create table */
|
||||
await knex.schema.createTable(table_name, (table) => {
|
||||
names.forEach(h => {
|
||||
/* call schema function e.g. table.text("Name"); table.float("Index"); */
|
||||
table[types[h] || "text"](h);
|
||||
});
|
||||
});
|
||||
|
||||
/* insert each row */
|
||||
await knex.insert(aoo).into(table_name);
|
||||
return knex;
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
:::note pass
|
||||
|
||||
The `Knex` constructor may display a warning when connecting to SQLite:
|
||||
|
||||
```
|
||||
sqlite does not support inserting default values. Set the `useNullAsDefault` flag to hide this warning. (see docs https://knexjs.org/guide/query-builder.html#insert).
|
||||
```
|
||||
|
||||
That flag should be added to the options argument:
|
||||
|
||||
```js
|
||||
const Knex = require('knex');
|
||||
let knex = Knex({
|
||||
client: 'better-sqlite3',
|
||||
connection: { filename: "SheetJSKnex.db" },
|
||||
// highlight-next-line
|
||||
useNullAsDefault: true
|
||||
});
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
## Complete Example
|
||||
|
||||
1) Install dependencies:
|
||||
@ -50,109 +186,22 @@ npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz knex be
|
||||
curl -LO https://sheetjs.com/pres.numbers
|
||||
```
|
||||
|
||||
3) Save the following utility script to `sheetjsknex.js`:
|
||||
3) Download [`SheetJSKnexTest.js`](pathname:///knex/SheetJSKnexTest.js):
|
||||
|
||||
```js title="sheetjsknex.js"
|
||||
const XLSX = require("xlsx");
|
||||
|
||||
// define mapping between determined types and Knex types
|
||||
const PG = { "n": "float", "s": "text", "b": "boolean" };
|
||||
|
||||
async function ws_to_knex(knex, ws, table_name) {
|
||||
|
||||
// generate an array of objects from the data
|
||||
const aoo = XLSX.utils.sheet_to_json(ws);
|
||||
|
||||
// types will map column headers to types, while hdr holds headers in order
|
||||
const types = {}, hdr = [];
|
||||
|
||||
// loop across each row object
|
||||
aoo.forEach(row =>
|
||||
// Object.entries returns a row of [key, value] pairs. Loop across those
|
||||
Object.entries(row).forEach(([k,v]) => {
|
||||
|
||||
// If this is first time seeing key, mark unknown and append header array
|
||||
if(!types[k]) { types[k] = "?"; hdr.push(k); }
|
||||
|
||||
// skip null and undefined
|
||||
if(v == null) return;
|
||||
|
||||
// check and resolve type
|
||||
switch(typeof v) {
|
||||
case "string": // strings are the broadest type
|
||||
types[k] = "s"; break;
|
||||
case "number": // if column is not string, number is the broadest type
|
||||
if(types[k] != "s") types[k] = "n"; break;
|
||||
case "boolean": // only mark boolean if column is unknown or boolean
|
||||
if("?b".includes(types[k])) types[k] = "b"; break;
|
||||
default: types[k] = "s"; break; // default to string type
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
await knex.schema.dropTableIfExists(table_name);
|
||||
|
||||
// use column type info to create table
|
||||
await knex.schema.createTable(table_name, (table) => { hdr.forEach(h => { table[PG[types[h]] || "text"](h); }); });
|
||||
|
||||
// insert each non-empty row object
|
||||
for(let i = 0; i < aoo.length; ++i) {
|
||||
if(!aoo[i] || !Object.keys(aoo[i]).length) continue;
|
||||
try { await knex.insert(aoo[i]).into(table_name); } catch(e) {}
|
||||
}
|
||||
return knex;
|
||||
}
|
||||
|
||||
async function knex_to_ws(knex, table_name) {
|
||||
const aoo = await knex.select("*").from(table_name);
|
||||
return XLSX.utils.json_to_sheet(aoo);
|
||||
}
|
||||
|
||||
module.exports = { ws_to_knex, knex_to_ws };
|
||||
```bash
|
||||
curl -LO https://docs.sheetjs.com/knex/SheetJSKnexTest.js
|
||||
```
|
||||
|
||||
4) Save the following to `SheetJSKnexTest.js`:
|
||||
|
||||
```js title="SheetJSKnexTest.js"
|
||||
const { ws_to_knex, knex_to_ws } = require("./sheetjsknex");
|
||||
const Knex = require('knex');
|
||||
This script will:
|
||||
- read and parse the test file `pres.numbers`
|
||||
- create a connection to a SQLite database stored at `SheetJSKnex.db`
|
||||
- load data from the first worksheet into a table with name `Test_Table`
|
||||
- disconnect and reconnect to the database
|
||||
- dump data from the table `Test_Table`
|
||||
- export the dataset to `SheetJSKnex.xlsx`
|
||||
|
||||
/* read file and get first worksheet */
|
||||
const XLSX = require("xlsx");
|
||||
const oldwb = XLSX.readFile("pres.numbers");
|
||||
const wsname = oldwb.SheetNames[0];
|
||||
const oldws = oldwb.Sheets[wsname];
|
||||
|
||||
(async() => {
|
||||
/* open connection to SheetJSKnex.db */
|
||||
let knex = Knex({ client: 'better-sqlite3', connection: { filename: "SheetJSKnex.db" } });
|
||||
try {
|
||||
/* load data into database and close connection */
|
||||
await ws_to_knex(knex, oldws, "Test_Table");
|
||||
} finally { knex.destroy(); }
|
||||
|
||||
/* reconnect to SheetJSKnex.db */
|
||||
knex = Knex({ client: 'better-sqlite3', connection: { filename: "SheetJSKnex.db" } });
|
||||
try {
|
||||
/* get data from db */
|
||||
const aoo = await knex.select("*").from("Test_Table");
|
||||
|
||||
/* export to file */
|
||||
const newws = await knex_to_ws(knex, "Test_Table");
|
||||
const newwb = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(newwb, newws, "Export");
|
||||
XLSX.writeFile(newwb, "SheetJSKnex.xlsx");
|
||||
} finally { knex.destroy(); }
|
||||
})();
|
||||
```
|
||||
|
||||
This script will read `pres.numbers` and load data into a table `Test_Table`.
|
||||
The SQLite database will be saved to `SheetJSKnex.db`.
|
||||
|
||||
After closing the connection, the script will make a new connection and export
|
||||
data to `SheetJSKnex.xlsx`.
|
||||
|
||||
5) Run the script:
|
||||
4) Run the script:
|
||||
|
||||
```bash
|
||||
node SheetJSKnexTest.js
|
||||
@ -171,3 +220,13 @@ npx xlsx-cli SheetJSKnex.xlsx
|
||||
```bash
|
||||
sqlite3 SheetJSKnex.db 'select * from Test_Table'
|
||||
```
|
||||
|
||||
[^1]: See [`select`](https://knexjs.org/guide/query-builder.html#select) in the KnexJS query builder documentation.
|
||||
[^2]: See [`json_to_sheet` in "Utilities"](/docs/api/utilities/array#array-of-objects-input)
|
||||
[^3]: See ["Sheet Objects"](/docs/csf/sheet) in "SheetJS Data Model" for more details.
|
||||
[^4]: See ["Workbook Helpers" in "Utilities"](/docs/api/utilities/wb) for details on `book_new` and `book_append_sheet`.
|
||||
[^5]: See [`writeFile` in "Writing Files"](/docs/api/write-options)
|
||||
[^6]: See [`sheet_to_json` in "Utilities"](/docs/api/utilities/array#array-output)
|
||||
[^7]: See [`insert`](https://knexjs.org/guide/query-builder.html#insert) in the KnexJS query builder documentation.
|
||||
[^8]: See [`createTable`](https://knexjs.org/guide/schema-builder.html#createtable) in the KnexJS Schema Builder documentation.
|
||||
[^9]: See [`dropTableIfExists`](https://knexjs.org/guide/schema-builder.html#droptableifexists) in the KnexJS Schema Builder documentation.
|
||||
|
@ -59,7 +59,7 @@ INTO XLSX( -- export data to file
|
||||
|
||||
</details>
|
||||
|
||||
:::caution
|
||||
:::caution pass
|
||||
|
||||
If the live demo shows a message
|
||||
|
||||
@ -196,7 +196,7 @@ The `XLSX` "into" target calls `XLSX.writeFile` under the hood:
|
||||
|
||||
## NodeJS
|
||||
|
||||
:::caution
|
||||
:::caution pass
|
||||
|
||||
`alasql` uses an older version of the library. It can be overridden through a
|
||||
`package.json` override in the latest versions of NodeJS:
|
||||
|
@ -116,7 +116,7 @@ const ws = XLSX.utils.json_to_sheet(aoo);
|
||||
When a strict schema is needed, the `sheet_to_json` helper function generates
|
||||
arrays of JS objects that can be scanned to determine the column "types".
|
||||
|
||||
:::note
|
||||
:::note pass
|
||||
|
||||
Document databases like MongoDB tend not to require schemas. Arrays of objects
|
||||
can be used directly without setting up a schema:
|
||||
|
@ -390,7 +390,7 @@ the feature in version 86. Safari did not support File System Access API.
|
||||
|
||||
:::
|
||||
|
||||
:::caution
|
||||
:::caution pass
|
||||
|
||||
When this demo was last tested, Google Chrome did not add an entry to the
|
||||
"Downloads" list. Nevertheless the actual file was written correctly.
|
||||
|
@ -28,7 +28,7 @@ a popular choice for offline storage.
|
||||
|
||||
A number of popular wrapper libraries seek to simplify IndexedDB operations.
|
||||
|
||||
:::note
|
||||
:::note pass
|
||||
|
||||
The wrapper libraries in this section have been used by SheetJS users in
|
||||
production sites.
|
||||
|
@ -12,7 +12,7 @@ Salesforce apps can use third-party libraries in "Lightning Web Components".
|
||||
This demo assumes familiarity with Lightning Web Components. Salesforce has a
|
||||
[detailed introduction.](https://developer.salesforce.com/docs/component-library/documentation/en/lwc/lwc.get_started_introduction)
|
||||
|
||||
:::caution
|
||||
:::caution pass
|
||||
|
||||
Salesforce may change the platform in backwards-incompatible ways, so the demo
|
||||
may require some adjustments. The official documentation should be consulted.
|
||||
@ -152,7 +152,7 @@ The easiest approach is to right-click the link and select "Save Link As..."
|
||||
sfdx force:source:deploy -p force-app -u SALESFORCE@USER.NAME # replace with actual username
|
||||
```
|
||||
|
||||
:::note
|
||||
:::note pass
|
||||
|
||||
The official documentation recommends adding a static resource with a ZIP file.
|
||||
That approach is not explored in this demo.
|
||||
@ -207,7 +207,7 @@ export default class SheetComponent extends LightningElement {
|
||||
|
||||
## Exporting Data from SF Lists
|
||||
|
||||
:::note
|
||||
:::note pass
|
||||
|
||||
There are many different data types and APIs. This demo uses the deprecated
|
||||
`getListUi` function to pull account data.
|
||||
@ -381,7 +381,7 @@ The simple export has all of the data:
|
||||
|
||||
![Excel Export](pathname:///files/sfxlexport.png)
|
||||
|
||||
:::note
|
||||
:::tip pass
|
||||
|
||||
[SheetJS Pro](https://sheetjs.com/pro) offers additional styling options like
|
||||
cell styling, automatic column width calculations, and frozen rows.
|
||||
|
@ -10,7 +10,7 @@ import CodeBlock from '@theme/CodeBlock';
|
||||
AWS is a Cloud Services platform which includes traditional virtual machine
|
||||
support, "Serverless Functions", cloud storage and much more.
|
||||
|
||||
:::caution
|
||||
:::caution pass
|
||||
|
||||
AWS iterates quickly and there is no guarantee that the referenced services
|
||||
will be available in the future.
|
||||
|
@ -10,7 +10,7 @@ import CodeBlock from '@theme/CodeBlock';
|
||||
Azure is a Cloud Services platform which includes traditional virtual machine
|
||||
support, "Serverless Functions", cloud storage and much more.
|
||||
|
||||
:::caution
|
||||
:::caution pass
|
||||
|
||||
Azure iterates quickly and there is no guarantee that the referenced services
|
||||
will be available in the future.
|
||||
|
@ -48,7 +48,7 @@ As a project from the company, the entire lifecycle uses GitHub offerings:
|
||||
- `flat-postprocessing` Post-processing helper functions and examples
|
||||
- "Flat Viewer": Web viewer for structured CSV and JSON data on GitHub
|
||||
|
||||
:::caution
|
||||
:::caution pass
|
||||
|
||||
A GitHub account is required. When the demo was tested, free GitHub accounts had
|
||||
no Actions usage limits for public repositories.
|
||||
|
@ -20,7 +20,7 @@ This breaks web frameworks that use the filesystem in body parsing.
|
||||
|
||||
:::
|
||||
|
||||
:::caution
|
||||
:::caution pass
|
||||
|
||||
When the demo was last tested, Deno Deploy required a GitHub account.
|
||||
|
||||
|
@ -4,7 +4,7 @@ pagination_prev: demos/cloud/index
|
||||
pagination_next: demos/bigdata/index
|
||||
---
|
||||
|
||||
:::note
|
||||
:::note pass
|
||||
|
||||
This demo showcases Manifest V2 and Manifest V3 extensions. Chrome Web Store
|
||||
will not accept new V2 extensions, but these can be sideloaded using the
|
||||
|
@ -119,7 +119,7 @@ This demo was tested in the following deployments:
|
||||
|:-------------|:--------|:-----------|
|
||||
| `darwin-x64` | `2.7.0` | 2023-07-24 |
|
||||
| `darwin-arm` | `2.7.0` | 2023-06-05 |
|
||||
| `linux-x64` | `2.7.0` | 2023-06-02 |
|
||||
| `linux-x64` | `2.7.0` | 2023-09-22 |
|
||||
| `linux-arm` | `2.7.0` | 2023-08-30 |
|
||||
| `win10-x64` | `2.7.0` | 2023-07-24 |
|
||||
|
||||
|
@ -15,7 +15,7 @@ can be parsed and evaluated in a Rhino context.
|
||||
This demo wraps workbooks and sheets into separate Java classes. The final
|
||||
result is a JAR.
|
||||
|
||||
:::caution
|
||||
:::caution pass
|
||||
|
||||
Rhino does not support Uint8Array, so certain formats like NUMBERS cannot be
|
||||
parsed or written from Rhino JS code!
|
||||
@ -24,7 +24,7 @@ parsed or written from Rhino JS code!
|
||||
|
||||
## Integration Details
|
||||
|
||||
:::note
|
||||
:::caution pass
|
||||
|
||||
Due to code generation errors, optimization must be turned off:
|
||||
|
||||
|
@ -165,6 +165,7 @@ This demo was tested in the following deployments:
|
||||
|:-------------|:------------------|:-----------|
|
||||
| `darwin-x64` | `3.0.0-beta-2051` | 2023-09-16 |
|
||||
| `win10-x64` | `3.0.0-beta-2051` | 2023-09-16 |
|
||||
| `linux-x64` | `3.0.0-beta-2051` | 2023-09-22 |
|
||||
|
||||
:::
|
||||
|
||||
@ -337,6 +338,7 @@ tested platforms are listed below:
|
||||
|:-----------------|:------------|
|
||||
| Intel Mac | `osx-x64` |
|
||||
| Windows 10 (x64) | `win10-x64` |
|
||||
| Linux (x64) | `linux-x64` |
|
||||
|
||||
9) Build the standalone application. Replace `$RID` with the real value in:
|
||||
|
||||
@ -353,6 +355,15 @@ For Intel Mac, the RID is `osx-x64` and the command is
|
||||
|
||||
```bash
|
||||
dotnet publish -c Release -r osx-x64 --self-contained true -p:PublishSingleFile=true -p:PublishTrimmed=true
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="linux-x64" label="Linux x64">
|
||||
|
||||
For x64 Linux, the RID is `linux-x64` and the command is
|
||||
|
||||
```bash
|
||||
dotnet publish -c Release -r linux-x64 --self-contained true -p:PublishSingleFile=true -p:PublishTrimmed=true
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@ -383,6 +394,15 @@ For Intel Mac, the RID is `osx-x64` and the command is:
|
||||
|
||||
```bash
|
||||
cp bin/Release/net6.0/osx-x64/publish/SheetJSJint .
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="linux-x64" label="Linux x64">
|
||||
|
||||
For x64 Linux, the RID is `linux-x64` and the command is
|
||||
|
||||
```bash
|
||||
cp bin/Release/net6.0/linux-x64/publish/SheetJSJint .
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@ -422,5 +442,5 @@ copy .\bin\Release\net6.0\win10-x64\publish\SheetJSJint.exe .
|
||||
[^2]: See [`read` in "Reading Files"](/docs/api/parse-options)
|
||||
[^3]: See [`write` in "Writing Files"](/docs/api/write-options)
|
||||
[^4]: See ["Supported Output Formats" in "Writing Files"](/docs/api/write-options#supported-output-formats) for details on `bookType`
|
||||
[^5]: At the time of writing, <https://dotnet.microsoft.com/en-us/download> is the official endpoint.
|
||||
[^5]: At the time of writing, <https://dotnet.microsoft.com/en-us/download> is the official endpoint. For Steam Deck Holo and other Arch Linux distributions, the `dotnet-sdk` and `dotnet-runtime` packages should be installed using `pacman`.
|
||||
[^6]: See [".NET RID Catalog"](https://learn.microsoft.com/en-us/dotnet/core/rid-catalog) in the .NET documentation
|
@ -26,7 +26,7 @@ command-line tool for reading data from files.
|
||||
:::info pass
|
||||
|
||||
Many Hermes functions are not documented. The explanation was verified against
|
||||
commit `70af78b`.
|
||||
commit `49e1930`.
|
||||
|
||||
:::
|
||||
|
||||
@ -207,7 +207,7 @@ Standard SheetJS operations can pick the first worksheet and generate CSV string
|
||||
data from the worksheet. Hermes provides methods to convert the JS strings back
|
||||
to `std::string` objects for further processing in C++.
|
||||
|
||||
:::note
|
||||
:::note pass
|
||||
|
||||
It is strongly recommended to create a stub function to perform the entire
|
||||
workflow in JS code and pass the final result back to C++.
|
||||
@ -340,7 +340,7 @@ This demo was tested in the following deployments:
|
||||
|:-------------|:-----------|:-----------|
|
||||
| `darwin-x64` | `70af78b` | 2023-08-27 |
|
||||
| `darwin-arm` | `869312f` | 2023-06-05 |
|
||||
| `linux-x64` | `70af78b` | 2023-08-27 |
|
||||
| `linux-x64` | `49e1930` | 2023-09-22 |
|
||||
| `linux-arm` | `70af78b` | 2023-08-27 |
|
||||
|
||||
:::
|
||||
|
@ -81,7 +81,7 @@ This demo was tested in the following deployments:
|
||||
gem install execjs
|
||||
```
|
||||
|
||||
:::note
|
||||
:::note pass
|
||||
|
||||
The command may need to be run as an administrator or root user:
|
||||
|
||||
|
@ -40,7 +40,7 @@ JsSetCurrentContext(JS_INVALID_REFERENCE);
|
||||
JsDisposeRuntime(runtime);
|
||||
```
|
||||
|
||||
:::note
|
||||
:::note pass
|
||||
|
||||
Cleanup and validation code is omitted from the discussion. The integration
|
||||
example shows structured validation and controlled memory usage.
|
||||
@ -181,7 +181,7 @@ cd ChakraCore
|
||||
cd ..
|
||||
```
|
||||
|
||||
:::caution
|
||||
:::caution pass
|
||||
|
||||
When this demo was last tested, the build failed with the message:
|
||||
|
||||
@ -216,7 +216,7 @@ cd ..
|
||||
```
|
||||
|
||||
|
||||
:::caution
|
||||
:::caution pass
|
||||
|
||||
When this demo was last tested, the build failed with the message:
|
||||
|
||||
@ -238,7 +238,7 @@ cd ..
|
||||
</TabItem>
|
||||
<TabItem value="linux-x64" label="Linux">
|
||||
|
||||
:::caution
|
||||
:::caution pass
|
||||
|
||||
When the demo was last tested, ChakraCore JIT was not supported.
|
||||
|
||||
@ -297,7 +297,7 @@ curl -L -O https://docs.sheetjs.com/chakra/Makefile
|
||||
make
|
||||
```
|
||||
|
||||
:::caution
|
||||
:::caution pass
|
||||
|
||||
When this demo was last tested on macOS, the build failed with the message:
|
||||
|
||||
|
@ -125,14 +125,23 @@ generates a C library and a standalone CLI tool.
|
||||
|
||||
The simplest way to interact with the engine is to pass Base64 strings.
|
||||
|
||||
:::note
|
||||
:::note pass
|
||||
|
||||
This demo was tested in the following deployments:
|
||||
|
||||
| Architecture | Commit | Date |
|
||||
|:-------------|:----------|:-----------|
|
||||
| `darwin-x64` | `a588e49` | 2023-09-22 |
|
||||
| `linux-x64` | `a588e49` | 2023-09-22 |
|
||||
|
||||
:::note pass
|
||||
|
||||
While applications should link against the official libraries, the standalone tool
|
||||
is useful for verifying functionality.
|
||||
|
||||
:::
|
||||
|
||||
:::caution
|
||||
:::caution pass
|
||||
|
||||
This demo requires a much larger heap size than is normally used in JerryScript
|
||||
deployments! In local testing, the following sizes were needed:
|
||||
|
@ -143,7 +143,7 @@ import * as XLSX from 'https://cdn.sheetjs.com/xlsx-${current}/package/xlsx.mjs'
|
||||
\n\
|
||||
const workbook = XLSX.readFile("test.xlsx");`}</CodeBlock>
|
||||
|
||||
:::note
|
||||
:::note pass
|
||||
|
||||
Applications reading files must be invoked with the `--allow-read` flag.
|
||||
|
||||
@ -369,7 +369,7 @@ const server = new Drash.Server({ hostname: "", port: 7262, protocol: "http",
|
||||
\n\
|
||||
server.run();`}</CodeBlock>
|
||||
|
||||
:::note
|
||||
:::note pass
|
||||
|
||||
Deno must be run with the `--allow-net` flag to enable network requests:
|
||||
|
||||
@ -518,7 +518,7 @@ const data = await (await fetch(url)).arrayBuffer();
|
||||
/* data is an ArrayBuffer */
|
||||
const workbook = XLSX.read(data);`}</CodeBlock>
|
||||
|
||||
:::note
|
||||
:::note pass
|
||||
|
||||
Deno must be run with the `--allow-net` flag to enable network requests:
|
||||
|
||||
@ -557,7 +557,7 @@ req.end();
|
||||
|
||||
### Example: Readable Streams
|
||||
|
||||
:::caution
|
||||
:::caution pass
|
||||
|
||||
The recommended approach is to buffer streams in memory and process once all of
|
||||
the data has been collected. A proper streaming parse is technically impossible.
|
||||
|
@ -15,7 +15,7 @@ read from data sources and write to data sources.
|
||||
|
||||
### Worksheets
|
||||
|
||||
:::note
|
||||
:::note pass
|
||||
|
||||
Worksheet names are case-sensitive.
|
||||
|
||||
@ -191,7 +191,7 @@ worksheet["!merges"].push({
|
||||
});
|
||||
```
|
||||
|
||||
:::caution
|
||||
:::caution pass
|
||||
|
||||
This approach does not verify if two merged ranges intersect.
|
||||
|
||||
|
@ -54,7 +54,7 @@ referencing the other export functions.
|
||||
The second `opts` argument is optional. ["Writing Options"](/docs/api/write-options)
|
||||
covers the supported properties and behaviors.
|
||||
|
||||
:::note
|
||||
:::note pass
|
||||
|
||||
The `writeFile` and `writeFileXLSX` methods uses platform-specific APIs to save
|
||||
files. The APIs do not generally provide feedback on whether files were created.
|
||||
@ -218,7 +218,7 @@ import * as XLSX from 'https://cdn.sheetjs.com/xlsx-${current}/package/xlsx.mjs'
|
||||
\n\
|
||||
XLSX.writeFile(workbook, "test.xlsx");`}</CodeBlock>
|
||||
|
||||
:::note
|
||||
:::note pass
|
||||
|
||||
Applications writing files must be invoked with the `--allow-write` flag.
|
||||
|
||||
@ -303,7 +303,7 @@ This example focuses on responses to network requests in a server-side platform
|
||||
like NodeJS. While files can be generated in the web browser, server-side file
|
||||
generation allows for exact audit trails and has better mobile user support.
|
||||
|
||||
:::caution
|
||||
:::caution pass
|
||||
|
||||
Production deployments should use a server framework like ExpressJS. These
|
||||
snippets use low-level APIs for illustration purposes.
|
||||
@ -489,7 +489,7 @@ like `XMLHttpRequest` and `fetch` as well as third-party libraries.
|
||||
<Tabs>
|
||||
<TabItem value="browser" label="Browser">
|
||||
|
||||
:::caution
|
||||
:::caution pass
|
||||
|
||||
Some platforms like Azure and AWS will attempt to parse POST request bodies as
|
||||
UTF-8 strings before user code can see the data. This will result in corrupt
|
||||
|
@ -151,7 +151,7 @@ The following table covers some common formats:
|
||||
| `A/P` | Meridiem ("A" or "P") |
|
||||
| `AM/PM` | Meridiem ("AM" or "PM") |
|
||||
|
||||
:::note
|
||||
:::note pass
|
||||
|
||||
`m` and `mm` are context-dependent. It is interpreted as "minutes" when the
|
||||
previous or next date token represents a time (hours or seconds):
|
||||
@ -278,7 +278,7 @@ function LocalInfo() {
|
||||
</>)}
|
||||
```
|
||||
|
||||
:::caution
|
||||
:::caution pass
|
||||
|
||||
The timezone information is provided by the JavaScript engine and local settings.
|
||||
There are outstanding Google Chrome and V8 bugs related to rounded offsets for
|
||||
|
@ -34,7 +34,7 @@ support Excel styled comments or Excel legacy notes.
|
||||
|
||||
The letter R (R) marks features parsed but not written in the format.
|
||||
|
||||
:::note
|
||||
:::note pass
|
||||
|
||||
[SheetJS Pro](https://sheetjs.com/pro) supports comment rich text and styling.
|
||||
|
||||
@ -78,6 +78,10 @@ characters may cause issues with other formats.
|
||||
|
||||
:::
|
||||
|
||||
## Demos
|
||||
|
||||
#### Export
|
||||
|
||||
<details open><summary><b>Live Export Example</b> (click to hide)</summary>
|
||||
|
||||
This example creates a small worksheet with a comment in cell A1:
|
||||
@ -98,7 +102,9 @@ function SheetJSComments1() {
|
||||
|
||||
</details>
|
||||
|
||||
<details open><summary><b>Live Import Example</b> (click to hide)</summary>
|
||||
#### Import
|
||||
|
||||
<details><summary><b>Live Import Example</b> (click to show)</summary>
|
||||
|
||||
This example displays every comment in the workbook:
|
||||
|
||||
@ -149,7 +155,10 @@ cell.c.hidden = true;
|
||||
cell.c.push({a:"SheetJS", t:"This comment will be hidden"});
|
||||
```
|
||||
|
||||
<details open><summary><b>Live Example</b> (click to hide)</summary>
|
||||
<details><summary><b>Live Example</b> (click to show)</summary>
|
||||
|
||||
The following demo creates a worksheet with two comments. The comment in cell A1
|
||||
will be visibile and the comment in cell A2 will be hidden.
|
||||
|
||||
```jsx live
|
||||
function SheetJSComments2() {
|
||||
@ -203,7 +212,7 @@ There is no Active Directory or Office 365 metadata associated with authors.
|
||||
<details open><summary><b>Live Example</b> (click to hide)</summary>
|
||||
|
||||
```jsx live
|
||||
function SheetJSComments2() {
|
||||
function SheetJSThreadedComments() {
|
||||
return ( <button onClick={() => {
|
||||
var ws = XLSX.utils.aoa_to_sheet([["SheetJS"], [5433795]]);
|
||||
|
||||
|
@ -98,7 +98,7 @@ data from SheetJS worksheet objects.
|
||||
|
||||
#### Example Sheet
|
||||
|
||||
:::note
|
||||
:::note pass
|
||||
|
||||
The live examples are based on the following worksheet:
|
||||
|
||||
@ -284,7 +284,7 @@ default column order is determined by the first appearance of the field using
|
||||
|
||||
[UTC option is explained in "Dates"](/docs/csf/features/dates#utc-option)
|
||||
|
||||
:::caution
|
||||
:::caution pass
|
||||
|
||||
All fields from each row will be written! `header` hints at a particular order
|
||||
but is not exclusive. To remove fields from the export, filter the data source.
|
||||
@ -431,7 +431,7 @@ XLSX.utils.sheet_add_json(ws, [
|
||||
], {header: ["A", "B", "C", "D", "E", "F", "G"], skipHeader: true, origin: -1});
|
||||
```
|
||||
|
||||
:::note
|
||||
:::note pass
|
||||
|
||||
If the `header` option is an array, `sheet_add_json` and `sheet_to_json` will
|
||||
append missing elements.
|
||||
@ -479,7 +479,7 @@ var aoa = XLSX.utils.sheet_to_json(ws, {header: 1, ...other_opts});
|
||||
</TabItem>
|
||||
<TabItem name="TS" value="TypeScript">
|
||||
|
||||
:::caution
|
||||
:::caution pass
|
||||
|
||||
TypeScript types are purely informational. They are not included at run time
|
||||
and do not influence the behavior of the `sheet_to_json` function.
|
||||
|
@ -8,7 +8,7 @@ functions (`XLSX.read` and `XLSX.readFile`) can parse HTML strings and the write
|
||||
functions (`XLSX.write` and `XLSX.writeFile`) can generate HTML strings, the
|
||||
utility functions in this section can use DOM features.
|
||||
|
||||
:::note
|
||||
:::note pass
|
||||
|
||||
SheetJS CE primarily focuses on data and number formatting.
|
||||
|
||||
@ -437,7 +437,7 @@ function SheetJSHTMLValueOverride() {
|
||||
`table_to_book` / `table_to_sheet` / `sheet_add_dom` act on HTML DOM elements.
|
||||
Traditionally there is no DOM in server-side environments including NodeJS.
|
||||
|
||||
:::note
|
||||
:::note pass
|
||||
|
||||
The simplest approach for server-side processing is to automate a headless web
|
||||
browser. ["Browser Automation"](/docs/demos/net/headless) covers some browsers.
|
||||
|
@ -39,7 +39,7 @@ These instructions were tested on the following platforms:
|
||||
|
||||
| Platform | Test Date |
|
||||
|:------------------------------|:-----------|
|
||||
| Linux (Steam Deck Holo x64) | 2023-07-12 |
|
||||
| Linux (Steam Deck Holo x64) | 2023-09-22 |
|
||||
| Linux (Ubuntu 18 AArch64) | 2023-09-07 |
|
||||
| MacOS 10.13 (x64) | 2023-04-04 |
|
||||
| MacOS 13.0 (ARM64) | 2023-04-13 |
|
||||
|
@ -1,5 +1,5 @@
|
||||
# Note: The official Hermes documentation includes zero guidance on embedding.
|
||||
# Tested against commit 70af78ba69391645749b40a3674d7321c4d6177a
|
||||
# Tested against commit 49e1930dbab6f4c6444d61ca9674cbd5795253fb
|
||||
|
||||
MYCC=llvm-g++
|
||||
POSTAMBLE=-framework CoreFoundation
|
||||
@ -64,5 +64,5 @@ sheetjs-hermes: sheetjs-hermes.cpp init
|
||||
|
||||
.PHONY: init
|
||||
init:
|
||||
if [ ! -e hermes ]; then git clone https://github.com/facebook/hermes.git; cd hermes; git checkout 70af78ba69391645749b40a3674d7321c4d6177a; cd ..; fi
|
||||
if [ ! -e hermes ]; then git clone https://github.com/facebook/hermes.git; cd hermes; git checkout 49e1930dbab6f4c6444d61ca9674cbd5795253fb; cd ..; fi
|
||||
if [ ! -e build_release ]; then cmake -S hermes -B build_release -G Ninja -DCMAKE_BUILD_TYPE=Release; cmake --build ./build_release; fi
|
88
docz/static/knex/SheetJSKnexTest.js
Normal file
88
docz/static/knex/SheetJSKnexTest.js
Normal file
@ -0,0 +1,88 @@
|
||||
const Knex = require('knex');
|
||||
const XLSX = require("xlsx");
|
||||
|
||||
/* read file and get first worksheet */
|
||||
const oldwb = XLSX.readFile("pres.numbers");
|
||||
const oldws = oldwb.Sheets[oldwb.SheetNames[0]];
|
||||
|
||||
/* create table and load data given an array of objects and a Knex connection */
|
||||
async function aoo_to_knex_table(knex, aoo, table_name) {
|
||||
/* define types that can be converted (e.g. boolean can be stored in float) */
|
||||
const T_FLOAT = ["float", "boolean"];
|
||||
const T_BOOL = ["boolean"];
|
||||
|
||||
/* types is a map from column headers to Knex schema column type */
|
||||
const types = {};
|
||||
|
||||
/* names is an ordered list of the column header names */
|
||||
const names = [];
|
||||
|
||||
/* loop across each row object */
|
||||
aoo.forEach(row =>
|
||||
/* Object.entries returns a row of [key, value] pairs */
|
||||
Object.entries(row).forEach(([k,v]) => {
|
||||
|
||||
/* If this is first occurrence, mark unknown and append header to names */
|
||||
if(!types[k]) { types[k] = ""; names.push(k); }
|
||||
|
||||
/* skip null and undefined values */
|
||||
if(v == null) return;
|
||||
|
||||
/* check and resolve type */
|
||||
switch(typeof v) {
|
||||
/* change type if it is empty or can be stored in a float */
|
||||
case "number": if(!types[k] || T_FLOAT.includes(types[k])) types[k] = "float"; break;
|
||||
/* change type if it is empty or can be stored in a boolean */
|
||||
case "boolean": if(!types[k] || T_BOOL.includes(types[k])) types[k] = "boolean"; break;
|
||||
/* no other type can hold strings */
|
||||
case "string": types[k] = "text"; break;
|
||||
default: types[k] = "text"; break;
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
/* Delete table if it exists in the DB */
|
||||
await knex.schema.dropTableIfExists(table_name);
|
||||
|
||||
/* use column type info to create table */
|
||||
await knex.schema.createTable(table_name, (table) => {
|
||||
names.forEach(h => {
|
||||
/* call schema function e.g. table.text("Name"); table.float("Index"); */
|
||||
table[types[h] || "text"](h);
|
||||
});
|
||||
});
|
||||
|
||||
/* insert each row */
|
||||
await knex.insert(aoo).into(table_name);
|
||||
return knex;
|
||||
}
|
||||
|
||||
(async() => {
|
||||
/* open connection to SheetJSKnex.db */
|
||||
let knex = Knex({ client: 'better-sqlite3', connection: { filename: "SheetJSKnex.db" }, useNullAsDefault: true });
|
||||
|
||||
try {
|
||||
/* generate array of objects from worksheet */
|
||||
const aoo = XLSX.utils.sheet_to_json(oldws);
|
||||
|
||||
/* create table and load data */
|
||||
await aoo_to_knex_table(knex, aoo, "Test_Table");
|
||||
} finally {
|
||||
/* disconnect */
|
||||
knex.destroy();
|
||||
}
|
||||
|
||||
/* reconnect to SheetJSKnex.db */
|
||||
knex = Knex({ client: 'better-sqlite3', connection: { filename: "SheetJSKnex.db" }, useNullAsDefault: true });
|
||||
|
||||
try {
|
||||
/* get data from db */
|
||||
const aoo = await knex.select("*").from("Test_Table");
|
||||
|
||||
/* export to file */
|
||||
const newws = XLSX.utils.json_to_sheet(aoo);
|
||||
const newwb = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(newwb, newws, "Export");
|
||||
XLSX.writeFile(newwb, "SheetJSKnex.xlsx");
|
||||
} finally { knex.destroy(); }
|
||||
})();
|
Loading…
Reference in New Issue
Block a user