Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@libsql/client

Package Overview
Dependencies
Maintainers
3
Versions
93
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@libsql/client - npm Package Compare versions

Comparing version 0.2.0 to 0.2.1

lib-cjs/util.js

4

lib-cjs/config.js

@@ -5,4 +5,4 @@ "use strict";

const api_js_1 = require("./api.js");
const help_js_1 = require("./help.js");
const uri_js_1 = require("./uri.js");
const util_js_1 = require("./util.js");
function expandConfig(config, preferHttp) {

@@ -60,3 +60,3 @@ if (typeof config !== "object") {

`got ${JSON.stringify(uri.scheme + ":")}. ` +
`For more information, please read ${help_js_1.supportedUrlLink}`, "URL_SCHEME_NOT_SUPPORTED");
`For more information, please read ${util_js_1.supportedUrlLink}`, "URL_SCHEME_NOT_SUPPORTED");
}

@@ -63,0 +63,0 @@ if (uri.fragment !== undefined) {

@@ -29,3 +29,5 @@ "use strict";

const api_js_1 = require("./api.js");
const util_js_1 = require("./util.js");
class HranaTransaction {
#mode;
// Promise that is resolved when the BEGIN statement completes, or `undefined` if we haven't executed the

@@ -35,3 +37,4 @@ // BEGIN statement yet.

/** @private */
constructor() {
constructor(mode) {
this.#mode = mode;
this.#started = undefined;

@@ -53,3 +56,3 @@ }

const beginStep = batch.step();
const beginPromise = beginStep.run("BEGIN");
const beginPromise = beginStep.run((0, util_js_1.transactionModeToBegin)(this.#mode));
// Execute the `stmt` only if the BEGIN succeeded, to make sure that we don't execute it

@@ -89,2 +92,93 @@ // outside of a transaction.

}
async batch(stmts) {
const stream = this._getStream();
if (stream.closed) {
throw new api_js_1.LibsqlError("Cannot execute a batch because the transaction is closed", "TRANSACTION_CLOSED");
}
try {
const hranaStmts = stmts.map(stmtToHrana);
// This is analogous to `execute()`, please read the comments there
let rowsPromises;
if (this.#started === undefined) {
this._getSqlCache().apply(hranaStmts);
const batch = stream.batch();
const beginStep = batch.step();
const beginPromise = beginStep.run((0, util_js_1.transactionModeToBegin)(this.#mode));
let lastStep = beginStep;
rowsPromises = hranaStmts.map((hranaStmt) => {
const stmtStep = batch.step()
.condition(hrana.BatchCond.ok(lastStep));
const rowsPromise = stmtStep.query(hranaStmt);
lastStep = stmtStep;
return rowsPromise;
});
this.#started = batch.execute()
.then(() => beginPromise)
.then(() => undefined);
try {
await this.#started;
}
catch (e) {
this.close();
throw e;
}
}
else {
await this.#started;
this._getSqlCache().apply(hranaStmts);
const batch = stream.batch();
let lastStep = undefined;
rowsPromises = hranaStmts.map((hranaStmt) => {
const stmtStep = batch.step();
if (lastStep !== undefined) {
stmtStep.condition(hrana.BatchCond.ok(lastStep));
}
const rowsPromise = stmtStep.query(hranaStmt);
lastStep = stmtStep;
return rowsPromise;
});
await batch.execute();
}
const resultSets = [];
for (const rowsPromise of rowsPromises) {
const rows = await rowsPromise;
if (rows === undefined) {
throw new api_js_1.LibsqlError("Server did not return a result for statement in a batch", "SERVER_ERROR");
}
resultSets.push(resultSetFromHrana(rows));
}
return resultSets;
}
catch (e) {
throw mapHranaError(e);
}
}
async executeMultiple(sql) {
const stream = this._getStream();
if (stream.closed) {
throw new api_js_1.LibsqlError("Cannot execute statements because the transaction is closed", "TRANSACTION_CLOSED");
}
try {
if (this.#started === undefined) {
// If the transaction hasn't started yet, start it now
this.#started = stream.run((0, util_js_1.transactionModeToBegin)(this.#mode))
.then(() => undefined);
try {
await this.#started;
}
catch (e) {
this.close();
throw e;
}
}
else {
// Wait until the transaction has started
await this.#started;
}
await stream.sequence(sql);
}
catch (e) {
throw mapHranaError(e);
}
}
async rollback() {

@@ -149,5 +243,5 @@ try {

exports.HranaTransaction = HranaTransaction;
async function executeHranaBatch(batch, hranaStmts) {
async function executeHranaBatch(mode, batch, hranaStmts) {
const beginStep = batch.step();
const beginPromise = beginStep.run("BEGIN");
const beginPromise = beginStep.run((0, util_js_1.transactionModeToBegin)(mode));
let lastStep = beginStep;

@@ -154,0 +248,0 @@ const stmtPromises = hranaStmts.map((hranaStmt) => {

@@ -33,6 +33,6 @@ "use strict";

const config_js_1 = require("./config.js");
const help_js_1 = require("./help.js");
const hrana_js_1 = require("./hrana.js");
const sql_cache_js_1 = require("./sql_cache.js");
const uri_js_1 = require("./uri.js");
const util_js_1 = require("./util.js");
__exportStar(require("./api.js"), exports);

@@ -47,3 +47,3 @@ function createClient(config) {

throw new api_js_1.LibsqlError('The HTTP client supports only "libsql:", "https:" and "http:" URLs, ' +
`got ${JSON.stringify(config.scheme)}. For more information, please read ${help_js_1.supportedUrlLink}`, "URL_SCHEME_NOT_SUPPORTED");
`got ${JSON.stringify(config.scheme)}. For more information, please read ${util_js_1.supportedUrlLink}`, "URL_SCHEME_NOT_SUPPORTED");
}

@@ -86,3 +86,4 @@ if (config.scheme === "http" && config.tls) {

}
async batch(stmts) {
async batch(arg1, arg2 = undefined) {
const { mode, stmts } = (0, util_js_1.extractBatchArgs)(arg1, arg2);
try {

@@ -100,3 +101,3 @@ const hranaStmts = stmts.map(hrana_js_1.stmtToHrana);

const batch = stream.batch();
resultsPromise = (0, hrana_js_1.executeHranaBatch)(batch, hranaStmts);
resultsPromise = (0, hrana_js_1.executeHranaBatch)(mode, batch, hranaStmts);
}

@@ -112,5 +113,5 @@ finally {

}
async transaction() {
async transaction(mode = "write") {
try {
return new HttpTransaction(this.#client.openStream());
return new HttpTransaction(this.#client.openStream(), mode);
}

@@ -121,2 +122,20 @@ catch (e) {

}
async executeMultiple(sql) {
try {
// Pipeline all operations, so `hrana.HttpClient` can open the stream, execute the sequence and
// close the stream in a single HTTP request.
let promise;
const stream = this.#client.openStream();
try {
promise = stream.sequence(sql);
}
finally {
stream.close();
}
await promise;
}
catch (e) {
throw (0, hrana_js_1.mapHranaError)(e);
}
}
close() {

@@ -134,4 +153,4 @@ this.#client.close();

/** @private */
constructor(stream) {
super();
constructor(stream, mode) {
super(mode);
this.#stream = stream;

@@ -138,0 +157,0 @@ this.#sqlCache = new sql_cache_js_1.SqlCache(stream, sqlCacheCapacity);

@@ -25,3 +25,3 @@ "use strict";

const config_js_1 = require("./config.js");
const help_js_1 = require("./help.js");
const util_js_1 = require("./util.js");
__exportStar(require("./api.js"), exports);

@@ -36,3 +36,3 @@ function createClient(config) {

throw new api_js_1.LibsqlError(`URL scheme ${JSON.stringify(config.scheme + ":")} is not supported by the local sqlite3 client. ` +
`For more information, please read ${help_js_1.supportedUrlLink}`, "URL_SCHEME_NOT_SUPPORTED");
`For more information, please read ${util_js_1.supportedUrlLink}`, "URL_SCHEME_NOT_SUPPORTED");
}

@@ -46,3 +46,3 @@ const authority = config.authority;

'or with three slashes ("file:///absolute/path.db"). ' +
`For more information, please read ${help_js_1.supportedUrlLink}`, "URL_INVALID");
`For more information, please read ${util_js_1.supportedUrlLink}`, "URL_INVALID");
}

@@ -88,13 +88,10 @@ if (authority.port !== undefined) {

}
async batch(stmts) {
async batch(arg1, arg2 = undefined) {
const { mode, stmts } = (0, util_js_1.extractBatchArgs)(arg1, arg2);
this.#checkNotClosed();
const db = new better_sqlite3_1.default(this.path, this.options);
try {
if (stmts.length > 1) {
executeStmt(db, "BEGIN");
}
executeStmt(db, (0, util_js_1.transactionModeToBegin)(mode));
const resultSets = stmts.map(stmt => executeStmt(db, stmt));
if (stmts.length > 1) {
executeStmt(db, "COMMIT");
}
executeStmt(db, "COMMIT");
return resultSets;

@@ -106,7 +103,7 @@ }

}
async transaction() {
async transaction(mode = "write") {
this.#checkNotClosed();
const db = new better_sqlite3_1.default(this.path, this.options);
try {
executeStmt(db, "BEGIN");
executeStmt(db, (0, util_js_1.transactionModeToBegin)(mode));
return new Sqlite3Transaction(db);

@@ -119,2 +116,12 @@ }

}
async executeMultiple(sql) {
this.#checkNotClosed();
const db = new better_sqlite3_1.default(this.path, this.options);
try {
return executeMultiple(db, sql);
}
finally {
db.close();
}
}
close() {

@@ -140,2 +147,10 @@ this.closed = true;

}
async batch(stmts) {
this.#checkNotClosed();
return stmts.map(stmt => executeStmt(this.database, stmt));
}
async executeMultiple(sql) {
this.#checkNotClosed();
return executeMultiple(this.database, sql);
}
async rollback() {

@@ -213,6 +228,3 @@ if (!this.database.open) {

catch (e) {
if (e instanceof better_sqlite3_1.default.SqliteError) {
throw new api_js_1.LibsqlError(e.message, e.code, e);
}
throw e;
throw mapSqliteError(e);
}

@@ -271,1 +283,15 @@ }

const maxInteger = 9223372036854775807n;
function executeMultiple(db, sql) {
try {
db.exec(sql);
}
catch (e) {
throw mapSqliteError(e);
}
}
function mapSqliteError(e) {
if (e instanceof better_sqlite3_1.default.SqliteError) {
return new api_js_1.LibsqlError(e.message, e.code, e);
}
return e;
}

@@ -20,3 +20,3 @@ "use strict";

const config_js_1 = require("./config.js");
const help_js_1 = require("./help.js");
const util_js_1 = require("./util.js");
const ws_js_1 = require("./ws.js");

@@ -39,5 +39,5 @@ const http_js_1 = require("./http.js");

throw new api_js_1.LibsqlError('The client that uses Web standard APIs supports only "libsql:", "wss:", "ws:", "https:" and "http:" URLs, ' +
`got ${JSON.stringify(config.scheme + ":")}. For more information, please read ${help_js_1.supportedUrlLink}`, "URL_SCHEME_NOT_SUPPORTED");
`got ${JSON.stringify(config.scheme + ":")}. For more information, please read ${util_js_1.supportedUrlLink}`, "URL_SCHEME_NOT_SUPPORTED");
}
}
exports._createClient = _createClient;

@@ -33,6 +33,6 @@ "use strict";

const config_js_1 = require("./config.js");
const help_js_1 = require("./help.js");
const hrana_js_1 = require("./hrana.js");
const sql_cache_js_1 = require("./sql_cache.js");
const uri_js_1 = require("./uri.js");
const util_js_1 = require("./util.js");
__exportStar(require("./api.js"), exports);

@@ -47,3 +47,3 @@ function createClient(config) {

throw new api_js_1.LibsqlError('The WebSocket client supports only "libsql:", "wss:" and "ws:" URLs, ' +
`got ${JSON.stringify(config.scheme + ":")}. For more information, please read ${help_js_1.supportedUrlLink}`, "URL_SCHEME_NOT_SUPPORTED");
`got ${JSON.stringify(config.scheme + ":")}. For more information, please read ${util_js_1.supportedUrlLink}`, "URL_SCHEME_NOT_SUPPORTED");
}

@@ -67,3 +67,3 @@ if (config.scheme === "ws" && config.tls) {

`a "${suggestedScheme}:" URL (${JSON.stringify(suggestedUrl)}). ` +
`For more information, please read ${help_js_1.supportedUrlLink}`, "WEBSOCKETS_NOT_SUPPORTED");
`For more information, please read ${util_js_1.supportedUrlLink}`, "WEBSOCKETS_NOT_SUPPORTED");
}

@@ -112,3 +112,4 @@ throw (0, hrana_js_1.mapHranaError)(e);

}
async batch(stmts) {
async batch(arg1, arg2 = undefined) {
const { mode, stmts } = (0, util_js_1.extractBatchArgs)(arg1, arg2);
const streamState = await this.#openStream();

@@ -121,3 +122,3 @@ try {

const batch = streamState.stream.batch();
const resultsPromise = (0, hrana_js_1.executeHranaBatch)(batch, hranaStmts);
const resultsPromise = (0, hrana_js_1.executeHranaBatch)(mode, batch, hranaStmts);
streamState.stream.close();

@@ -133,3 +134,3 @@ return await resultsPromise;

}
async transaction() {
async transaction(mode = "write") {
const streamState = await this.#openStream();

@@ -139,3 +140,3 @@ try {

// network roundtrip
return new WsTransaction(this, streamState);
return new WsTransaction(this, streamState, mode);
}

@@ -147,2 +148,18 @@ catch (e) {

}
async executeMultiple(sql) {
const streamState = await this.#openStream();
try {
// Schedule all operations synchronously, so they will be pipelined and executed in a single
// network roundtrip.
const promise = streamState.stream.sequence(sql);
streamState.stream.close();
await promise;
}
catch (e) {
throw (0, hrana_js_1.mapHranaError)(e);
}
finally {
this._closeStream(streamState);
}
}
async #openStream() {

@@ -257,4 +274,4 @@ if (this.closed) {

/** @private */
constructor(client, state) {
super();
constructor(client, state, mode) {
super(mode);
this.#client = client;

@@ -261,0 +278,0 @@ this.#streamState = state;

@@ -53,2 +53,5 @@ /** Configuration object for {@link createClient}. */

*
* The `mode` parameter selects the transaction mode for the batch; please see {@link TransactionMode} for
* details.
*
* If any of the statements in the batch fails with an error, the batch is aborted, the transaction is

@@ -61,3 +64,3 @@ * rolled back and the returned promise is rejected.

* ```javascript
* const rss = await client.batch([
* const rss = await client.batch("write", [
* // batch statement without arguments

@@ -80,4 +83,12 @@ * "DELETE FROM books WHERE name LIKE '%Crusoe'",

*/
batch(mode: TransactionMode, stmts: Array<InStatement>): Promise<Array<ResultSet>>;
/** Execute a batch of SQL statement in the `"write"` transaction mode.
*
* Please see {@link batch} for details.
*
* @deprecated Please specify the `mode` explicitly. The default `"write"` will be removed in the next
* major release.
*/
batch(stmts: Array<InStatement>): Promise<Array<ResultSet>>;
/** Starts an interactive transaction.
/** Start an interactive transaction.
*

@@ -88,2 +99,5 @@ * Interactive transactions allow you to interleave execution of SQL statements with your application

*
* The `mode` parameter selects the transaction mode for the interactive transaction; please see {@link
* TransactionMode} for details.
*
* You **must** make sure that the returned {@link Transaction} object is closed, by calling {@link

@@ -97,3 +111,10 @@ * Transaction.close}, {@link Transaction.commit} or {@link Transaction.rollback}. The best practice is

* // do some operations with the transaction here
* ...
* await transaction.execute({
* sql: "INSERT INTO books (name, author) VALUES (?, ?)",
* args: ["First Impressions", "Jane Austen"],
* });
* await transaction.execute({
* sql: "UPDATE books SET name = ? WHERE name = ?",
* args: ["Pride and Prejudice", "First Impressions"],
* });
*

@@ -108,3 +129,32 @@ * // if all went well, commit the transaction

*/
transaction(mode: TransactionMode): Promise<Transaction>;
/** Start an interactive transaction in `"write"` mode.
*
* Please see {@link transaction} for details.
*
* @deprecated Please specify the `mode` explicitly. The default `"write"` will be removed in the next
* major release.
*/
transaction(): Promise<Transaction>;
/** Execute a sequence of SQL statements separated by semicolons.
*
* The statements are executed sequentially on a new logical database connection. If a statement fails,
* further statements are not executed and this method throws an error. All results from the statements
* are ignored.
*
* We do not wrap the statements in a transaction, but the SQL can contain explicit transaction-control
* statements such as `BEGIN` and `COMMIT`.
*
* This method is intended to be used with existing SQL scripts, such as migrations or small database
* dumps. If you want to execute a sequence of statements programmatically, please use {@link batch}
* instead.
*
* ```javascript
* await client.executeMultiple(`
* CREATE TABLE books (id INTEGER PRIMARY KEY, title TEXT NOT NULL, author_id INTEGER NOT NULL);
* CREATE TABLE authors (id INTEGER PRIMARY KEY, name TEXT NOT NULL);
* `);
* ```
*/
executeMultiple(sql: string): Promise<void>;
/** Close the client and release resources.

@@ -138,3 +188,10 @@ *

* // do some operations with the transaction here
* ...
* await transaction.execute({
* sql: "INSERT INTO books (name, author) VALUES (?, ?)",
* args: ["First Impressions", "Jane Austen"],
* });
* await transaction.execute({
* sql: "UPDATE books SET name = ? WHERE name = ?",
* args: ["Pride and Prejudice", "First Impressions"],
* });
*

@@ -150,10 +207,33 @@ * // if all went well, commit the transaction

export interface Transaction {
/** Executes an SQL statement in the transaction.
/** Execute an SQL statement in this transaction.
*
* If the statement makes any changes to the database, these changes won't be visible to statements
* outside of this transaction until you call {@link rollback}.
*
* ```javascript
* await transaction.execute({
* sql: "INSERT INTO books (name, author) VALUES (?, ?)",
* args: ["First Impressions", "Jane Austen"],
* });
* ```
*/
execute(stmt: InStatement): Promise<ResultSet>;
/** Rolls back any changes from this transaction.
/** Execute a batch of SQL statements in this transaction.
*
* If any of the statements in the batch fails with an error, further statements are not executed and the
* returned promise is rejected with an error, but the transaction is not rolled back.
*/
batch(stmts: Array<InStatement>): Promise<Array<ResultSet>>;
/** Execute a sequence of SQL statements separated by semicolons.
*
* The statements are executed sequentially in the transaction. If a statement fails, further statements
* are not executed and this method throws an error, but the transaction won't be rolled back. All results
* from the statements are ignored.
*
* This method is intended to be used with existing SQL scripts, such as migrations or small database
* dumps. If you want to execute statements programmatically, please use {@link batch} instead.
*/
executeMultiple(sql: string): Promise<void>;
/** Roll back any changes from this transaction.
*
* This method closes the transaction and undoes any changes done by the previous SQL statements on this

@@ -163,3 +243,3 @@ * transaction. You cannot call this method after calling {@link commit}, though.

rollback(): Promise<void>;
/** Commits changes from this transaction to the database.
/** Commit changes from this transaction to the database.
*

@@ -171,3 +251,3 @@ * This method closes the transaction and applies all changes done by the previous SQL statement on this

commit(): Promise<void>;
/** Closes the transaction.
/** Close the transaction.
*

@@ -189,2 +269,29 @@ * This method closes the transaction and releases any resources associated with the transaction. If the

}
/** Transaction mode.
*
* The client supports multiple modes for transactions:
*
* - `"write"` is a read-write transaction, started with `BEGIN IMMEDIATE`. This transaction mode supports
* both read statements (`SELECT`) and write statements (`INSERT`, `UPDATE`, `CREATE TABLE`, etc). The libSQL
* server cannot process multiple write transactions concurrently, so if there is another write transaction
* already started, our transaction will wait in a queue before it can begin.
*
* - `"read"` is a read-only transaction, started with `BEGIN TRANSACTION READONLY` (a libSQL extension). This
* transaction mode supports only reads (`SELECT`) and will not accept write statements. The libSQL server can
* handle multiple read transactions at the same time, so we don't need to wait for other transactions to
* complete. A read-only transaction can also be executed on a local replica, so it provides lower latency.
*
* - `"deferred"` is a transaction started with `BEGIN DEFERRED`, which starts as a read transaction, but the
* first write statement will try to upgrade it to a write transaction. However, this upgrade may fail if
* there already is a write transaction executing on the server, so you should be ready to handle these
* failures.
*
* If your transaction includes only read statements, `"read"` is always preferred over `"deferred"` or
* `"write"`, because `"read"` transactions can be executed on a replica and don't block other transactions.
*
* If your transaction includes both read and write statements, you should be using the `"write"` mode most of
* the time. Use the `"deferred"` mode only if you prefer to fail the write transaction instead of waiting for
* the previous write transactions to complete.
*/
export type TransactionMode = "write" | "read" | "deferred";
/** Result of executing an SQL statement.

@@ -191,0 +298,0 @@ *

import { LibsqlError } from "./api.js";
import { supportedUrlLink } from "./help.js";
import { parseUri } from "./uri.js";
import { supportedUrlLink } from "./util.js";
export function expandConfig(config, preferHttp) {

@@ -5,0 +5,0 @@ if (typeof config !== "object") {

import * as hrana from "@libsql/hrana-client";
import type { InStatement, ResultSet, Transaction } from "./api.js";
import type { InStatement, ResultSet, Transaction, TransactionMode } from "./api.js";
import type { SqlCache } from "./sql_cache.js";

@@ -7,3 +7,3 @@ export declare abstract class HranaTransaction implements Transaction {

/** @private */
constructor();
constructor(mode: TransactionMode);
/** @private */

@@ -16,8 +16,10 @@ abstract _getStream(): hrana.Stream;

execute(stmt: InStatement): Promise<ResultSet>;
batch(stmts: Array<InStatement>): Promise<Array<ResultSet>>;
executeMultiple(sql: string): Promise<void>;
rollback(): Promise<void>;
commit(): Promise<void>;
}
export declare function executeHranaBatch(batch: hrana.Batch, hranaStmts: Array<hrana.Stmt>): Promise<Array<ResultSet>>;
export declare function executeHranaBatch(mode: TransactionMode, batch: hrana.Batch, hranaStmts: Array<hrana.Stmt>): Promise<Array<ResultSet>>;
export declare function stmtToHrana(stmt: InStatement): hrana.Stmt;
export declare function resultSetFromHrana(hranaRows: hrana.RowsResult): ResultSet;
export declare function mapHranaError(e: unknown): unknown;
import * as hrana from "@libsql/hrana-client";
import { LibsqlError } from "./api.js";
import { transactionModeToBegin } from "./util.js";
export class HranaTransaction {
#mode;
// Promise that is resolved when the BEGIN statement completes, or `undefined` if we haven't executed the

@@ -8,3 +10,4 @@ // BEGIN statement yet.

/** @private */
constructor() {
constructor(mode) {
this.#mode = mode;
this.#started = undefined;

@@ -26,3 +29,3 @@ }

const beginStep = batch.step();
const beginPromise = beginStep.run("BEGIN");
const beginPromise = beginStep.run(transactionModeToBegin(this.#mode));
// Execute the `stmt` only if the BEGIN succeeded, to make sure that we don't execute it

@@ -62,2 +65,93 @@ // outside of a transaction.

}
async batch(stmts) {
const stream = this._getStream();
if (stream.closed) {
throw new LibsqlError("Cannot execute a batch because the transaction is closed", "TRANSACTION_CLOSED");
}
try {
const hranaStmts = stmts.map(stmtToHrana);
// This is analogous to `execute()`, please read the comments there
let rowsPromises;
if (this.#started === undefined) {
this._getSqlCache().apply(hranaStmts);
const batch = stream.batch();
const beginStep = batch.step();
const beginPromise = beginStep.run(transactionModeToBegin(this.#mode));
let lastStep = beginStep;
rowsPromises = hranaStmts.map((hranaStmt) => {
const stmtStep = batch.step()
.condition(hrana.BatchCond.ok(lastStep));
const rowsPromise = stmtStep.query(hranaStmt);
lastStep = stmtStep;
return rowsPromise;
});
this.#started = batch.execute()
.then(() => beginPromise)
.then(() => undefined);
try {
await this.#started;
}
catch (e) {
this.close();
throw e;
}
}
else {
await this.#started;
this._getSqlCache().apply(hranaStmts);
const batch = stream.batch();
let lastStep = undefined;
rowsPromises = hranaStmts.map((hranaStmt) => {
const stmtStep = batch.step();
if (lastStep !== undefined) {
stmtStep.condition(hrana.BatchCond.ok(lastStep));
}
const rowsPromise = stmtStep.query(hranaStmt);
lastStep = stmtStep;
return rowsPromise;
});
await batch.execute();
}
const resultSets = [];
for (const rowsPromise of rowsPromises) {
const rows = await rowsPromise;
if (rows === undefined) {
throw new LibsqlError("Server did not return a result for statement in a batch", "SERVER_ERROR");
}
resultSets.push(resultSetFromHrana(rows));
}
return resultSets;
}
catch (e) {
throw mapHranaError(e);
}
}
async executeMultiple(sql) {
const stream = this._getStream();
if (stream.closed) {
throw new LibsqlError("Cannot execute statements because the transaction is closed", "TRANSACTION_CLOSED");
}
try {
if (this.#started === undefined) {
// If the transaction hasn't started yet, start it now
this.#started = stream.run(transactionModeToBegin(this.#mode))
.then(() => undefined);
try {
await this.#started;
}
catch (e) {
this.close();
throw e;
}
}
else {
// Wait until the transaction has started
await this.#started;
}
await stream.sequence(sql);
}
catch (e) {
throw mapHranaError(e);
}
}
async rollback() {

@@ -121,5 +215,5 @@ try {

}
export async function executeHranaBatch(batch, hranaStmts) {
export async function executeHranaBatch(mode, batch, hranaStmts) {
const beginStep = batch.step();
const beginPromise = beginStep.run("BEGIN");
const beginPromise = beginStep.run(transactionModeToBegin(mode));
let lastStep = beginStep;

@@ -126,0 +220,0 @@ const stmtPromises = hranaStmts.map((hranaStmt) => {

@@ -5,2 +5,3 @@ /// <reference types="node" />

import type { InStatement, ResultSet, Transaction } from "./api.js";
import { TransactionMode } from "./api.js";
import type { ExpandedConfig } from "./config.js";

@@ -18,4 +19,6 @@ import { HranaTransaction } from "./hrana.js";

execute(stmt: InStatement): Promise<ResultSet>;
batch(mode: TransactionMode, stmts: Array<InStatement>): Promise<Array<ResultSet>>;
batch(stmts: Array<InStatement>): Promise<Array<ResultSet>>;
transaction(): Promise<HttpTransaction>;
transaction(mode?: TransactionMode): Promise<HttpTransaction>;
executeMultiple(sql: string): Promise<void>;
close(): void;

@@ -27,3 +30,3 @@ get closed(): boolean;

/** @private */
constructor(stream: hrana.HttpStream);
constructor(stream: hrana.HttpStream, mode: TransactionMode);
/** @private */

@@ -30,0 +33,0 @@ _getStream(): hrana.Stream;

import * as hrana from "@libsql/hrana-client";
import { LibsqlError } from "./api.js";
import { expandConfig } from "./config.js";
import { supportedUrlLink } from "./help.js";
import { HranaTransaction, executeHranaBatch, stmtToHrana, resultSetFromHrana, mapHranaError, } from "./hrana.js";
import { SqlCache } from "./sql_cache.js";
import { encodeBaseUrl } from "./uri.js";
import { supportedUrlLink, extractBatchArgs } from "./util.js";
export * from "./api.js";

@@ -53,3 +53,4 @@ export function createClient(config) {

}
async batch(stmts) {
async batch(arg1, arg2 = undefined) {
const { mode, stmts } = extractBatchArgs(arg1, arg2);
try {

@@ -67,3 +68,3 @@ const hranaStmts = stmts.map(stmtToHrana);

const batch = stream.batch();
resultsPromise = executeHranaBatch(batch, hranaStmts);
resultsPromise = executeHranaBatch(mode, batch, hranaStmts);
}

@@ -79,5 +80,5 @@ finally {

}
async transaction() {
async transaction(mode = "write") {
try {
return new HttpTransaction(this.#client.openStream());
return new HttpTransaction(this.#client.openStream(), mode);
}

@@ -88,2 +89,20 @@ catch (e) {

}
async executeMultiple(sql) {
try {
// Pipeline all operations, so `hrana.HttpClient` can open the stream, execute the sequence and
// close the stream in a single HTTP request.
let promise;
const stream = this.#client.openStream();
try {
promise = stream.sequence(sql);
}
finally {
stream.close();
}
await promise;
}
catch (e) {
throw mapHranaError(e);
}
}
close() {

@@ -100,4 +119,4 @@ this.#client.close();

/** @private */
constructor(stream) {
super();
constructor(stream, mode) {
super(mode);
this.#stream = stream;

@@ -104,0 +123,0 @@ this.#sqlCache = new SqlCache(stream, sqlCacheCapacity);

import Database from "better-sqlite3";
import type { Config, Client, Transaction, ResultSet, InStatement } from "./api.js";
import type { Config, Client, Transaction, TransactionMode, ResultSet, InStatement } from "./api.js";
import type { ExpandedConfig } from "./config.js";

@@ -16,4 +16,6 @@ export * from "./api.js";

execute(stmt: InStatement): Promise<ResultSet>;
batch(mode: TransactionMode, stmts: Array<InStatement>): Promise<Array<ResultSet>>;
batch(stmts: Array<InStatement>): Promise<Array<ResultSet>>;
transaction(): Promise<Transaction>;
transaction(mode?: TransactionMode): Promise<Transaction>;
executeMultiple(sql: string): Promise<void>;
close(): void;

@@ -27,2 +29,4 @@ }

execute(stmt: InStatement): Promise<ResultSet>;
batch(stmts: Array<InStatement>): Promise<Array<ResultSet>>;
executeMultiple(sql: string): Promise<void>;
rollback(): Promise<void>;

@@ -29,0 +33,0 @@ commit(): Promise<void>;

@@ -5,3 +5,3 @@ import Database from "better-sqlite3";

import { expandConfig } from "./config.js";
import { supportedUrlLink } from "./help.js";
import { supportedUrlLink, transactionModeToBegin, extractBatchArgs } from "./util.js";
export * from "./api.js";

@@ -64,13 +64,10 @@ export function createClient(config) {

}
async batch(stmts) {
async batch(arg1, arg2 = undefined) {
const { mode, stmts } = extractBatchArgs(arg1, arg2);
this.#checkNotClosed();
const db = new Database(this.path, this.options);
try {
if (stmts.length > 1) {
executeStmt(db, "BEGIN");
}
executeStmt(db, transactionModeToBegin(mode));
const resultSets = stmts.map(stmt => executeStmt(db, stmt));
if (stmts.length > 1) {
executeStmt(db, "COMMIT");
}
executeStmt(db, "COMMIT");
return resultSets;

@@ -82,7 +79,7 @@ }

}
async transaction() {
async transaction(mode = "write") {
this.#checkNotClosed();
const db = new Database(this.path, this.options);
try {
executeStmt(db, "BEGIN");
executeStmt(db, transactionModeToBegin(mode));
return new Sqlite3Transaction(db);

@@ -95,2 +92,12 @@ }

}
async executeMultiple(sql) {
this.#checkNotClosed();
const db = new Database(this.path, this.options);
try {
return executeMultiple(db, sql);
}
finally {
db.close();
}
}
close() {

@@ -115,2 +122,10 @@ this.closed = true;

}
async batch(stmts) {
this.#checkNotClosed();
return stmts.map(stmt => executeStmt(this.database, stmt));
}
async executeMultiple(sql) {
this.#checkNotClosed();
return executeMultiple(this.database, sql);
}
async rollback() {

@@ -187,6 +202,3 @@ if (!this.database.open) {

catch (e) {
if (e instanceof Database.SqliteError) {
throw new LibsqlError(e.message, e.code, e);
}
throw e;
throw mapSqliteError(e);
}

@@ -245,1 +257,15 @@ }

const maxInteger = 9223372036854775807n;
function executeMultiple(db, sql) {
try {
db.exec(sql);
}
catch (e) {
throw mapSqliteError(e);
}
}
function mapSqliteError(e) {
if (e instanceof Database.SqliteError) {
return new LibsqlError(e.message, e.code, e);
}
return e;
}
import { LibsqlError } from "./api.js";
import { expandConfig } from "./config.js";
import { supportedUrlLink } from "./help.js";
import { supportedUrlLink } from "./util.js";
import { _createClient as _createWsClient } from "./ws.js";

@@ -5,0 +5,0 @@ import { _createClient as _createHttpClient } from "./http.js";

/// <reference types="node" />
import * as hrana from "@libsql/hrana-client";
import type { Config, Client, Transaction, ResultSet, InStatement } from "./api.js";
import { TransactionMode } from "./api.js";
import type { ExpandedConfig } from "./config.js";

@@ -28,4 +29,6 @@ import { HranaTransaction } from "./hrana.js";

execute(stmt: InStatement): Promise<ResultSet>;
batch(mode: TransactionMode, stmts: Array<InStatement>): Promise<Array<ResultSet>>;
batch(stmts: Array<InStatement>): Promise<Array<ResultSet>>;
transaction(): Promise<WsTransaction>;
transaction(mode?: TransactionMode): Promise<WsTransaction>;
executeMultiple(sql: string): Promise<void>;
_closeStream(streamState: StreamState): void;

@@ -37,3 +40,3 @@ close(): void;

/** @private */
constructor(client: WsClient, state: StreamState);
constructor(client: WsClient, state: StreamState, mode: TransactionMode);
/** @private */

@@ -40,0 +43,0 @@ _getStream(): hrana.Stream;

import * as hrana from "@libsql/hrana-client";
import { LibsqlError } from "./api.js";
import { expandConfig } from "./config.js";
import { supportedUrlLink } from "./help.js";
import { HranaTransaction, executeHranaBatch, stmtToHrana, resultSetFromHrana, mapHranaError, } from "./hrana.js";
import { SqlCache } from "./sql_cache.js";
import { encodeBaseUrl } from "./uri.js";
import { supportedUrlLink, extractBatchArgs } from "./util.js";
export * from "./api.js";

@@ -78,3 +78,4 @@ export function createClient(config) {

}
async batch(stmts) {
async batch(arg1, arg2 = undefined) {
const { mode, stmts } = extractBatchArgs(arg1, arg2);
const streamState = await this.#openStream();

@@ -87,3 +88,3 @@ try {

const batch = streamState.stream.batch();
const resultsPromise = executeHranaBatch(batch, hranaStmts);
const resultsPromise = executeHranaBatch(mode, batch, hranaStmts);
streamState.stream.close();

@@ -99,3 +100,3 @@ return await resultsPromise;

}
async transaction() {
async transaction(mode = "write") {
const streamState = await this.#openStream();

@@ -105,3 +106,3 @@ try {

// network roundtrip
return new WsTransaction(this, streamState);
return new WsTransaction(this, streamState, mode);
}

@@ -113,2 +114,18 @@ catch (e) {

}
async executeMultiple(sql) {
const streamState = await this.#openStream();
try {
// Schedule all operations synchronously, so they will be pipelined and executed in a single
// network roundtrip.
const promise = streamState.stream.sequence(sql);
streamState.stream.close();
await promise;
}
catch (e) {
throw mapHranaError(e);
}
finally {
this._closeStream(streamState);
}
}
async #openStream() {

@@ -222,4 +239,4 @@ if (this.closed) {

/** @private */
constructor(client, state) {
super();
constructor(client, state, mode) {
super(mode);
this.#client = client;

@@ -226,0 +243,0 @@ this.#streamState = state;

{
"name": "@libsql/client",
"version": "0.2.0",
"version": "0.2.1",
"keywords": [

@@ -90,3 +90,3 @@ "libsql",

"dependencies": {
"@libsql/hrana-client": "^0.4.0",
"@libsql/hrana-client": "^0.4.1",
"better-sqlite3": "^8.0.1",

@@ -93,0 +93,0 @@ "js-base64": "^3.7.5"

@@ -52,4 +52,2 @@ # JavaScript & TypeScript SDK for libSQL

In each case, the client API is the same, with the exception that [HTTP URLs](#http-urls) don't support interactive transactions.
### Local SQLite files

@@ -56,0 +54,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc