postgresql
This commit is contained in:
parent
32521763a6
commit
5e3369edda
@ -152,15 +152,7 @@ can be adapted to generate SQL statements for a variety of databases, including:
|
||||
|
||||
**PostgreSQL**
|
||||
|
||||
The `pg` connector library was tested against the `generate_sql` output as-is.
|
||||
|
||||
The `rows` property of a query result is an array of objects that plays nice
|
||||
with `json_to_sheet`:
|
||||
|
||||
```js
|
||||
const aoa = await connection.query(`SELECT * FROM DataTable`).rows;
|
||||
const worksheet = XLSX.utils.json_to_sheet(aoa);
|
||||
```
|
||||
**[The exposition has been moved to a separate page.](/docs/demos/data/postgresql)**
|
||||
|
||||
**MySQL / MariaDB**
|
||||
|
||||
|
411
docz/docs/03-demos/07-data/16-postgresql.md
Normal file
411
docz/docs/03-demos/07-data/16-postgresql.md
Normal file
@ -0,0 +1,411 @@
|
||||
---
|
||||
title: Sheets with PostgreSQL
|
||||
sidebar_label: PostgreSQL
|
||||
pagination_prev: demos/desktop/index
|
||||
pagination_next: demos/local/index
|
||||
sidebar_custom_props:
|
||||
sql: true
|
||||
---
|
||||
|
||||
import current from '/version.js';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
[PostgreSQL](https://postgresql.org/) (colloquially referenced as "Postgres") is
|
||||
an open source object-relational database system.
|
||||
|
||||
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
|
||||
data from spreadsheets.
|
||||
|
||||
This demo uses SheetJS to exchange data between spreadsheets and PostgreSQL
|
||||
databases. We'll explore how to use save tables from a database to spreadsheets
|
||||
and how to add data from spreadsheets into a database.
|
||||
|
||||
:::caution pass
|
||||
|
||||
**It is strongly recommended to use PostgreSQL with a query builder or ORM.**
|
||||
|
||||
While it is possible to generate SQL statements directly, there are many subtle
|
||||
details and pitfalls. Battle-tested solutions generally provide mitigations
|
||||
against SQL injection and other vulnerabilities.
|
||||
|
||||
:::
|
||||
|
||||
:::note
|
||||
|
||||
This demo was last tested on 2023 October 30 with PostgreSQL 16.0.1. The demo
|
||||
uses `pg` connector module version 8.11.3.
|
||||
|
||||
:::
|
||||
|
||||
## Integration Details
|
||||
|
||||
The [SheetJS NodeJS module](/docs/getting-started/installation/nodejs) can be
|
||||
loaded in NodeJS scripts that connect to PostgreSQL databases.
|
||||
|
||||
This demo uses the `pg` connector module[^1], but the same mechanics apply to
|
||||
other PostgreSQL libraries.
|
||||
|
||||
### Exporting Data
|
||||
|
||||
`Client#query` returns a Promise that resolves to a result set. The `rows`
|
||||
property of the result is an array of objects.
|
||||
|
||||
The SheetJS `json_to_sheet` method[^2] can generate a worksheet object[^3] from
|
||||
the array of objects:
|
||||
|
||||
```js
|
||||
const table_name = "Tabeller1"; // name of table
|
||||
|
||||
/* fetch all data from specified table */
|
||||
const res = await client.query(`SELECT * FROM ${table_name}`);
|
||||
|
||||
/* generate a SheetJS worksheet object from the data */
|
||||
const worksheet = XLSX.utils.json_to_sheet(res.rows);
|
||||
```
|
||||
|
||||
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, "SheetJSPGExport.xlsx");
|
||||
```
|
||||
|
||||
### Importing Data
|
||||
|
||||
The SheetJS `sheet_to_json` function[^6] takes a worksheet object and generates
|
||||
an array of objects.
|
||||
|
||||
Queries must be manually generated from the objects. Assuming the field names
|
||||
in the object match the column headers, a loop can generate `INSERT` queries.
|
||||
|
||||
:::warning pass
|
||||
|
||||
**PostgreSQL does not allow parameterized queries with variable column names**
|
||||
|
||||
```sql
|
||||
INSERT INTO table_name (?) VALUES (?);
|
||||
-- ---------------------^ variable column names are not valid
|
||||
```
|
||||
|
||||
Queries are generated manually. To help prevent SQL injection vulnerabilities,
|
||||
the `pg-format`[^7] module escapes identifiers and fields.
|
||||
|
||||
:::
|
||||
|
||||
```js
|
||||
/* generate an array of arrays from the worksheet */
|
||||
const aoo = XLSX.utils.sheet_to_json(ws);
|
||||
|
||||
const table_name = "Blatte1"; // name of table
|
||||
|
||||
/* loop through the data rows */
|
||||
for(let row of aoo) {
|
||||
|
||||
/* generate format helper strings */
|
||||
const ent = Object.entries(row);
|
||||
const Istr = Array.from({length: entries.length}, ()=>"%I").join(", ");
|
||||
const Lstr = Array.from({length: entries.length}, ()=>"%L").join(", ");
|
||||
|
||||
/* generate INSERT statement */
|
||||
let query = format.withArray(
|
||||
`INSERT INTO %I (${Istr}) VALUES(${Lstr})`,
|
||||
[ table_name, ...ent.map(x => x[0]), ...ent.map(x => x[1]) ]
|
||||
);
|
||||
|
||||
/* execute INSERT statement */
|
||||
await client.query(query);
|
||||
}
|
||||
```
|
||||
|
||||
### Creating a Table
|
||||
|
||||
The array of objects can be scanned to determine column names and types. With
|
||||
the names and types, a `CREATE TABLE` query can be written.
|
||||
|
||||
<details><summary><b>Implementation Details</b> (click to show)</summary>
|
||||
|
||||
The `aoo_to_pg_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 PostgreSQL client */
|
||||
async function aoo_to_pg_table(client, aoo, table_name) {
|
||||
/* define types that can be converted (e.g. boolean can be stored in float) */
|
||||
const T_FLOAT = ["float8", "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] = "float8"; 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 */
|
||||
const query = format("DROP TABLE IF EXISTS %I;", table_name);
|
||||
await client.query(query);
|
||||
|
||||
/* Create table */
|
||||
{
|
||||
const entries = Object.entries(types);
|
||||
const Istr = entries.map(e => format(`%I ${e[1]}`, e[0])).join(", ");
|
||||
let query = format.withArray(`CREATE TABLE %I (${Istr});`, [ table_name ]);
|
||||
await client.query(query);
|
||||
}
|
||||
|
||||
/* Insert each row */
|
||||
for(let row of aoo) {
|
||||
const ent = Object.entries(row);
|
||||
const Istr = Array.from({length: ent.length}, ()=>"%I").join(", ");
|
||||
const Lstr = Array.from({length: ent.length}, ()=>"%L").join(", ");
|
||||
let query = format.withArray(
|
||||
`INSERT INTO %I (${Istr}) VALUES (${Lstr});`,
|
||||
[ table_name, ...ent.map(x => x[0]), ...ent.map(x => x[1]) ]
|
||||
);
|
||||
await client.query(query);
|
||||
}
|
||||
|
||||
return client;
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
## Complete Example
|
||||
|
||||
0) Install and start the PostgreSQL server.
|
||||
|
||||
<details><summary><b>Installation Notes</b> (click to show)</summary>
|
||||
|
||||
On macOS, install the `postgresql` formula with Homebrew:
|
||||
|
||||
```bash
|
||||
brew install postgresql@16
|
||||
```
|
||||
|
||||
The last few lines of the installer explains how to start the database:
|
||||
|
||||
```text
|
||||
Or, if you don't want/need a background service you can just run:
|
||||
// highlight-next-line
|
||||
LC_ALL="C" /usr/local/opt/postgresql@16/bin/postgres -D /usr/local/var/postgresql@16
|
||||
```
|
||||
|
||||
Run the command to start a local database instance.
|
||||
|
||||
</details>
|
||||
|
||||
1) Drop any existing database with the name `SheetJSPG`:
|
||||
|
||||
```bash
|
||||
dropdb SheetJSPG
|
||||
```
|
||||
|
||||
:::info pass
|
||||
|
||||
If the server is running elsewhere, or if the username is different from the
|
||||
current user, command-line flags can override the defaults.
|
||||
|
||||
| Option | Explanation
|
||||
|:--------------|:--------------------------|
|
||||
| `-h HOSTNAME` | Name of the server |
|
||||
| `-p PORT` | specifies the port number |
|
||||
| `-U USERNAME` | specifies the username |
|
||||
|
||||
:::
|
||||
|
||||
2) Create an empty `SheetJSPG` database using the `createdb` command:
|
||||
|
||||
```bash
|
||||
createdb SheetJSPG
|
||||
```
|
||||
|
||||
:::note pass
|
||||
|
||||
`createdb` supports the same `-h`, `-p`, and `-U` flags as `dropdb`.
|
||||
|
||||
:::
|
||||
|
||||
### Connector Test
|
||||
|
||||
3) Create a project folder:
|
||||
|
||||
```bash
|
||||
mkdir sheetjs-pg
|
||||
cd sheetjs-pg
|
||||
npm init -y
|
||||
```
|
||||
|
||||
4) Install the `pg` connector module:
|
||||
|
||||
```bash
|
||||
npm i --save pg@8.11.3
|
||||
```
|
||||
|
||||
5) Save the following example codeblock to `PGTest.js`:
|
||||
|
||||
```js title="PGTest.js"
|
||||
const pg = require("pg");
|
||||
const client = new pg.Client({
|
||||
database:"SheetJSPG",
|
||||
// highlight-start
|
||||
host: "127.0.0.1", // localhost
|
||||
port: 5432,
|
||||
//user: "",
|
||||
//password: ""
|
||||
// highlight-end
|
||||
});
|
||||
(async() => {
|
||||
|
||||
await client.connect();
|
||||
const res = await client.query('SELECT $1::text as message', ['Hello world!']);
|
||||
console.log(res.rows[0].message); // Hello world!
|
||||
await client.end();
|
||||
|
||||
})();
|
||||
```
|
||||
|
||||
6) Edit the new `PGTest.js` script and modify the highlighted lines from the
|
||||
codeblock to reflect the database deployment settings.
|
||||
|
||||
The settings in the codeblock match the default configuration for macOS Homebrew
|
||||
PostgreSQL server. For other deployments:
|
||||
|
||||
- If the server is not running on your computer, set `host` and `port` to the
|
||||
correct host name and port number.
|
||||
|
||||
- If the server expects a different username and password, uncomment the `user`
|
||||
and `password` lines and replace the values with the username and password.
|
||||
|
||||
7) Run the script:
|
||||
|
||||
```bash
|
||||
node PGTest.js
|
||||
```
|
||||
|
||||
It should print `Hello world!`
|
||||
|
||||
:::caution pass
|
||||
|
||||
If the output is not `Hello world!` or if there is an error, please report the
|
||||
issue to the `pg` connector project for further diagnosis[^8]
|
||||
|
||||
:::
|
||||
|
||||
### Add SheetJS
|
||||
|
||||
8) Install dependencies:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz pg-format@1.0.4`}
|
||||
</CodeBlock>
|
||||
|
||||
9) Download [`SheetJSPG.js`](pathname:///postgresql/SheetJSPG.js):
|
||||
|
||||
```bash
|
||||
curl -LO https://docs.sheetjs.com/postgresql/SheetJSPG.js
|
||||
```
|
||||
|
||||
This script will:
|
||||
- read and parse the test file `pres.numbers`
|
||||
- create a connection to the `SheetJSPG` database on a local PostgreSQL server
|
||||
- load data from the first worksheet into a table with name `Presidents`
|
||||
- disconnect and reconnect to the database
|
||||
- dump data from the table `Presidents`
|
||||
- export the dataset to `SheetJSPG.xlsx`
|
||||
|
||||
10) Edit the `SheetJSPG.js` script.
|
||||
|
||||
The script defines an `opts` object:
|
||||
|
||||
```js title="SheetJSPG.js (configuration lines)"
|
||||
const XLSX = require("xlsx");
|
||||
const opts = {
|
||||
database:"SheetJSPG",
|
||||
// highlight-start
|
||||
host: "127.0.0.1", // localhost
|
||||
port: 5432,
|
||||
//user: "",
|
||||
//password: ""
|
||||
// highlight-end
|
||||
};
|
||||
```
|
||||
|
||||
The settings in the codeblock match the default configuration for macOS Homebrew
|
||||
PostgreSQL server. For other deployments:
|
||||
|
||||
- If the server is not running on your computer, set `host` and `port` to the
|
||||
correct host name and port number.
|
||||
|
||||
- If the server expects a different username and password, uncomment the `user`
|
||||
and `password` lines and replace the values with the username and password.
|
||||
|
||||
11) Run the script:
|
||||
|
||||
```bash
|
||||
node SheetJSPG.js
|
||||
```
|
||||
|
||||
12) Verify the result:
|
||||
|
||||
- `SheetJSPG.xlsx` can be opened in a spreadsheet app or tested in the terminal
|
||||
|
||||
```bash
|
||||
npx xlsx-cli SheetJSPG.xlsx
|
||||
```
|
||||
|
||||
- The database server can be queried using the `psql` command line tool.
|
||||
|
||||
If the server is running locally, the command will be:
|
||||
|
||||
```bash
|
||||
psql SheetJSPG -c 'SELECT * FROM "Presidents";'
|
||||
```
|
||||
|
||||
:::note pass
|
||||
|
||||
`psql` supports the same `-h`, `-p`, and `-U` flags as `dropdb` and `createdb`.
|
||||
|
||||
:::
|
||||
|
||||
|
||||
[^1]: See [the official `pg` website](https://node-postgres.com/) for more info.
|
||||
[^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]: The [`pg-format`](https://npm.im/pg-format) package is available on the public NPM registry. Even though the project is marked as deprecated, the official [`pg` website still recommends `pg-format`](https://node-postgres.com/features/queries#parameterized-query:~:text=use%20pg%2Dformat%20package%20for%20handling%20escaping)
|
||||
[^8]: The official [issue tracker](https://github.com/brianc/node-postgres/issues) is hosted on GitHub
|
@ -8,6 +8,16 @@ import current from '/version.js';
|
||||
|
||||
This section lists the functions defined in the library.
|
||||
|
||||
:::info pass
|
||||
|
||||
**The ["SheetJS Data Model"](/docs/csf) section covers spreadsheet features.**
|
||||
|
||||
The API functions primarily focus on conversions between data representations.
|
||||
|
||||
:::
|
||||
|
||||
## Library access
|
||||
|
||||
Using the ["Standalone" scripts](/docs/getting-started/installation/standalone),
|
||||
`XLSX` is added to the `window` or other `global` object.
|
||||
|
||||
|
@ -17,7 +17,7 @@ and `sheet_to_json`[^4].
|
||||
|
||||
The library is also available for standalone use on the SheetJS CDN[^5].
|
||||
|
||||
The source code and project documentation is hosted on the SheetJS git server at
|
||||
Source code and project documentation are hosted on the SheetJS git server at
|
||||
<https://git.sheetjs.com/sheetjs/sheetjs/src/branch/master/packages/ssf>
|
||||
|
||||
## Live Demo
|
||||
@ -30,21 +30,28 @@ particular format is not supported.
|
||||
function SheetJSSSF() {
|
||||
const [fmt, setFmt] = React.useState("#,##0");
|
||||
const [val, setVal] = React.useState(7262);
|
||||
const [text, setText] = React.useState("");
|
||||
|
||||
const format = (fmt, val) => { try {
|
||||
return XLSX.SSF.format(fmt, val);
|
||||
} catch(e) { return "ERROR: " + (e && e.message || e); } };
|
||||
React.useEffect(() => {
|
||||
let v = +val;
|
||||
if(!isFinite(v)) return setText(`ERROR: ${val} is not a valid number!`);
|
||||
try {
|
||||
setText(XLSX.SSF.format(fmt, v));
|
||||
} catch(e) { setText("ERROR: " + (e && e.message || e)); }
|
||||
}, [fmt, val]);
|
||||
const goodstyle = { backgroundColor: "#C6EFCE", color: "#006100" };
|
||||
const badstyle = { backgroundColor: "#FFC7CE", color: "#9C0006" };
|
||||
|
||||
return ( <table>
|
||||
<tr><td><b>Number Format</b></td><td>
|
||||
<input type="text" value={fmt} onChange={e => setFmt(e.target.value)}/>
|
||||
</td></tr>
|
||||
<tr><td><b>Number Value</b></td><td>
|
||||
<input type="text" value={val} onChange={e => setVal(+e.target.value)}/>
|
||||
<input type="text" value={val} onChange={e => setVal(e.target.value)}/>
|
||||
</td></tr>
|
||||
<tr><td colspan="2"></td></tr>
|
||||
<tr><td><b>Formatted Text</b></td><td>
|
||||
<code>{format(fmt, val)}</code>
|
||||
<code style={/ERROR/.test(text)?badstyle:goodstyle}>{text}</code>
|
||||
</td></tr>
|
||||
</table> );
|
||||
}
|
16
docz/docs/12-constellation/11-crc32.md
Normal file
16
docz/docs/12-constellation/11-crc32.md
Normal file
@ -0,0 +1,16 @@
|
||||
---
|
||||
title: CRC32 Checksum
|
||||
hide_table_of_contents: true
|
||||
---
|
||||
|
||||
The SheetJS `crc-32` library computes standard CRC32 and Castagnoli CRC32C
|
||||
checksums. It is a core component in ZIP file processing, powering XLSX, XLSB,
|
||||
ODS, NUMBERS, and other formats.
|
||||
|
||||
The library is also available for standalone use on the SheetJS CDN[^1].
|
||||
|
||||
Source code and project documentation are hosted on the SheetJS git server at
|
||||
<https://git.sheetjs.com/sheetjs/js-crc32>
|
||||
|
||||
|
||||
[^1]: See <https://cdn.sheetjs.com/crc-32/> for more details.
|
@ -1,4 +1,4 @@
|
||||
{
|
||||
"label": "Constellation",
|
||||
"position": 9
|
||||
"position": 12
|
||||
}
|
114
docz/static/postgresql/SheetJSPG.js
Normal file
114
docz/static/postgresql/SheetJSPG.js
Normal file
@ -0,0 +1,114 @@
|
||||
const pg = require("pg"), format = require("pg-format");
|
||||
const XLSX = require("xlsx");
|
||||
const opts = {
|
||||
database:"SheetJSPG",
|
||||
host: "127.0.0.1", // localhost
|
||||
port: 5432,
|
||||
//user: "",
|
||||
//password: ""
|
||||
};
|
||||
|
||||
/* create table and load data given an array of objects and a PostgreSQL client */
|
||||
async function aoo_to_pg_table(client, aoo, table_name) {
|
||||
/* define types that can be converted (e.g. boolean can be stored in float) */
|
||||
const T_FLOAT = ["float8", "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] = "float8"; 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 */
|
||||
const query = format("DROP TABLE IF EXISTS %I;", table_name);
|
||||
await client.query(query);
|
||||
|
||||
/* Create table */
|
||||
{
|
||||
const entries = Object.entries(types);
|
||||
const Istr = entries.map(e => format(`%I ${e[1]}`, e[0])).join(", ");
|
||||
let query = format.withArray(`CREATE TABLE %I (${Istr});`, [ table_name ]);
|
||||
await client.query(query);
|
||||
}
|
||||
|
||||
/* Insert each row */
|
||||
for(let row of aoo) {
|
||||
const ent = Object.entries(row);
|
||||
const Istr = Array.from({length: ent.length}, ()=>"%I").join(", ");
|
||||
const Lstr = Array.from({length: ent.length}, ()=>"%L").join(", ");
|
||||
let query = format.withArray(
|
||||
`INSERT INTO %I (${Istr}) VALUES (${Lstr});`,
|
||||
[ table_name, ...ent.map(x => x[0]), ...ent.map(x => x[1]) ]
|
||||
);
|
||||
await client.query(query);
|
||||
}
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
(async() => {
|
||||
|
||||
/* read file and get first worksheet */
|
||||
const oldwb = XLSX.readFile("pres.numbers");
|
||||
const oldws = oldwb.Sheets[oldwb.SheetNames[0]];
|
||||
|
||||
/* import data to postgres */
|
||||
let client = new pg.Client(opts);
|
||||
try {
|
||||
/* open connection to PostgreSQL database */
|
||||
await client.connect();
|
||||
|
||||
/* generate array of objects from worksheet */
|
||||
const aoo = XLSX.utils.sheet_to_json(oldws);
|
||||
|
||||
/* create table and load data */
|
||||
await aoo_to_pg_table(client, aoo, "Presidents");
|
||||
} finally {
|
||||
/* disconnect */
|
||||
await client.end();
|
||||
}
|
||||
|
||||
/* export data to xlsx */
|
||||
client = new pg.Client(opts);
|
||||
try {
|
||||
/* open connection to PostgreSQL database */
|
||||
await client.connect();
|
||||
|
||||
/* fetch all data from specified table */
|
||||
const res = await client.query(format(`SELECT * FROM %I`, "Presidents"));
|
||||
|
||||
/* export to file */
|
||||
const newws = XLSX.utils.json_to_sheet(res.rows);
|
||||
const newwb = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(newwb, newws, "Export");
|
||||
XLSX.writeFile(newwb, "SheetJSPGExport.xlsx");
|
||||
} finally {
|
||||
/* disconnect */
|
||||
await client.end();
|
||||
}
|
||||
})();
|
Loading…
Reference in New Issue
Block a user