Database-js XLSX Wrapper
The `database-js-xlsx` package provides a robust `database-js` compatible interface for interacting with Microsoft Excel XLSX files, acting as a crucial bridge between SQL-like queries and spreadsheet data. It is built upon the `xlsx-populate` library for efficient in-memory spreadsheet manipulation and utilizes `node-sqlparser` to interpret SQL commands. Currently stable at version 1.0.6, its release cadence is tied to its underlying dependencies and the `database-js` ecosystem, rather than a fixed schedule. A key advantage of `database-js-xlsx` is its cross-platform compatibility, a significant improvement over Windows-specific drivers within the `database-js` family, such as `database-js-adodb`. Developers should note that the library works with an in-memory copy of the spreadsheet; all changes are buffered and written back to disk only when the connection is explicitly closed. This design means any external modifications to the file during an active connection will be overwritten. The SQL capabilities are limited, supporting SELECT, UPDATE, INSERT, and DELETE statements with functional WHERE clauses, but explicitly prohibiting JOINs and currently lacking support for GROUP BY. Furthermore, LIMIT and OFFSET operations are consolidated into a single `LIMIT [offset,]number` syntax, requiring developers to adapt their pagination strategies accordingly. This package is ideal for Node.js applications needing to perform basic CRUD operations on Excel data programmatically without complex setup or platform restrictions.
Common errors
-
Error: Cannot find module 'database-js2'
cause The official README example for `database-js-xlsx` contains a typo, instructing users to `require('database-js2')` instead of the correct `database-js` package.fixUpdate your `require` statement from `require('database-js2')` to `require('database-js')`. -
Error: "JOIN" is not allowed
cause The underlying SQL parser (`node-sqlparser`) used by `database-js-xlsx` explicitly does not support SQL JOIN clauses for combining data from multiple tables/sheets.fixRefactor your query to avoid `JOIN` operations. Instead, perform multiple `SELECT` statements and merge the results in your application logic. -
Error: "GROUP BY" is not supported
cause The `database-js-xlsx` library, via `node-sqlparser`, currently lacks support for the `GROUP BY` SQL clause, preventing server-side aggregation.fixRetrieve the necessary data without `GROUP BY` and then perform the aggregation (e.g., summing, counting) programmatically in your JavaScript/TypeScript code. -
TypeError: connection.prepareStatement is not a function
cause The `database-js-xlsx` driver has not been correctly registered with the `database-js` core library, likely because `require('database-js-xlsx')` was omitted or occurred after the connection attempt.fixEnsure that `require('database-js-xlsx');` is executed early in your application's lifecycle, preferably before any `new Database(...)` calls, to register the XLSX driver.
Warnings
- gotcha The README example for importing the `Database` class uses `require('database-js2')`. This is a typo, as `database-js2` does not exist on npm. The correct package to import for the `Database` class is `database-js`.
- gotcha This library operates on an in-memory copy of the XLSX file. Any changes made to the physical file on disk by external processes while a connection is open will be overwritten when `connection.close()` is called, as the in-memory state is written back to the original file path.
- gotcha The SQL parser has significant limitations. Specifically, `JOIN` clauses are not supported, and `GROUP BY` is not yet implemented. Complex queries requiring these features must be broken down and processed in application logic.
- gotcha The `LIMIT` and `OFFSET` SQL clauses are combined into a single `LIMIT [offset,]number` syntax. This deviates from standard SQL and requires careful attention when implementing pagination.
Install
-
npm install database-js-xlsx -
yarn add database-js-xlsx -
pnpm add database-js-xlsx
Imports
- Database
const Database = require('database-js2');const Database = require('database-js'); - driver registration
require('database-js-xlsx');
Quickstart
const Database = require('database-js');
const path = require('path');
// This import is crucial for the 'database-js-xlsx' driver to be available
require('database-js-xlsx');
(async () => {
let connection, statement, rows;
const filePath = path.join(__dirname, 'test.xlsx');
// For a new file, 'test.xlsx' will be created on connection.close()
connection = new Database(`database-js-xlsx:///${filePath}`);
try {
console.log("Connected to XLSX file. Initializing with sample data if new.");
// Example: Create/Ensure Sheet1 has columns if it's a new file
// Note: This operation may implicitly create Sheet1 and its headers if not present
try {
await connection.prepareStatement("CREATE TABLE IF NOT EXISTS Sheet1 (Name TEXT, City TEXT, State TEXT, Age INTEGER)");
} catch (e) {
// CREATE TABLE is not directly supported, but the first INSERT will define schema
console.log("CREATE TABLE is not supported, proceeding with inserts to define schema.");
}
// Example: Insert data (if no data exists for 'Alice')
console.log("\nInserting new data into Sheet1 (if not exists)...");
statement = await connection.prepareStatement("INSERT OR IGNORE INTO Sheet1 (Name, City, State, Age) VALUES (?, ?, ?, ?)");
await statement.query('Alice Smith', 'Anytown', 'CA', 25);
await statement.query('Bob Johnson', 'Otherville', 'NY', 32);
console.log("Sample data ensured.");
// Example: Select data
statement = await connection.prepareStatement("SELECT * FROM Sheet1 WHERE State = ?");
rows = await statement.query('CA');
console.log("\nQuery Results for 'CA':");
console.log(rows);
// Example: Update data
console.log("\nUpdating Alice Smith's age...");
statement = await connection.prepareStatement("UPDATE Sheet1 SET Age = ? WHERE Name = ?");
await statement.query(26, 'Alice Smith');
console.log("Alice Smith's age updated.");
// Verify changes
statement = await connection.prepareStatement("SELECT * FROM Sheet1 WHERE Name = ?");
rows = await statement.query('Alice Smith');
console.log("\nVerifying updated data for Alice Smith:");
console.log(rows);
// Example: Delete data
console.log("\nDeleting Bob Johnson's data...");
statement = await connection.prepareStatement("DELETE FROM Sheet1 WHERE Name = ?");
await statement.query('Bob Johnson');
console.log("Bob Johnson's data deleted.");
} catch (error) {
console.error("An error occurred:", error);
} finally {
if (connection) {
console.log(`\nClosing connection and saving changes to '${filePath}'...`);
await connection.close();
console.log("Connection closed and file saved.");
}
}
})();