Skip to content

Commit

Permalink
Merge pull request #255 from tursodatabase/simpler-batch-api
Browse files Browse the repository at this point in the history
use simpler batch input
  • Loading branch information
penberg authored Sep 26, 2024
2 parents d84a4a4 + 0cfe870 commit 80c2767
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 19 deletions.
16 changes: 16 additions & 0 deletions packages/libsql-client/examples/example.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,22 @@ async function example() {
],
"write",
);

await db.batch(
[
{
sql: "INSERT INTO users (email) VALUES (?)",
args: ["[email protected]"],
},
["INSERT INTO users (email) VALUES (?)", ["[email protected]"]],
{
sql: "INSERT INTO users (email) VALUES (:email)",
args: { email: "[email protected]" },
},
],
"write",
);

const rs = await db.execute("SELECT * FROM users");
console.log(rs);
}
Expand Down
29 changes: 20 additions & 9 deletions packages/libsql-client/src/hrana.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type {
ResultSet,
Transaction,
TransactionMode,
InArgs,
} from "@libsql/core/api";
import { LibsqlError } from "@libsql/core/api";
import type { SqlCache } from "./sql_cache.js";
Expand Down Expand Up @@ -309,17 +310,27 @@ export async function executeHranaBatch(
return resultSets;
}

export function stmtToHrana(stmt: InStatement): hrana.Stmt {
if (typeof stmt === "string") {
return new hrana.Stmt(stmt);
}
export function stmtToHrana(stmt: InStatement | [string, InArgs?]): hrana.Stmt {
let sql: string;
let args: InArgs | undefined;

const hranaStmt = new hrana.Stmt(stmt.sql);
if (Array.isArray(stmt.args)) {
hranaStmt.bindIndexes(stmt.args);
if (Array.isArray(stmt)) {
[sql, args] = stmt;
} else if (typeof stmt === "string") {
sql = stmt;
} else {
for (const [key, value] of Object.entries(stmt.args)) {
hranaStmt.bindName(key, value);
sql = stmt.sql;
args = stmt.args;
}

const hranaStmt = new hrana.Stmt(sql);
if (args) {
if (Array.isArray(args)) {
hranaStmt.bindIndexes(args);
} else {
for (const [key, value] of Object.entries(args)) {
hranaStmt.bindName(key, value);
}
}
}

Expand Down
14 changes: 12 additions & 2 deletions packages/libsql-client/src/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,12 +135,22 @@ export class HttpClient implements Client {
}

async batch(
stmts: Array<InStatement>,
stmts: Array<InStatement | [string, InArgs?]>,
mode: TransactionMode = "deferred",
): Promise<Array<ResultSet>> {
return this.limit<Array<ResultSet>>(async () => {
try {
const hranaStmts = stmts.map(stmtToHrana);
const normalizedStmts = stmts.map(stmt => {
if (Array.isArray(stmt)) {
return {
sql: stmt[0],
args: stmt[1] || []
};
}
return stmt;
});

const hranaStmts = normalizedStmts.map(stmtToHrana);
const version = await this.#client.getVersion();

// Pipeline all operations, so `hrana.HttpClient` can open the stream, execute the batch and
Expand Down
16 changes: 12 additions & 4 deletions packages/libsql-client/src/sqlite3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ export class Sqlite3Client implements Client {
}

async batch(
stmts: Array<InStatement>,
stmts: Array<InStatement | [string, InArgs?]>,
mode: TransactionMode = "deferred",
): Promise<Array<ResultSet>> {
this.#checkNotClosed();
Expand All @@ -153,7 +153,10 @@ export class Sqlite3Client implements Client {
"TRANSACTION_CLOSED",
);
}
return executeStmt(db, stmt, this.#intMode);
const normalizedStmt: InStatement = Array.isArray(stmt)
? { sql: stmt[0], args: stmt[1] || [] }
: stmt;
return executeStmt(db, normalizedStmt, this.#intMode);
});
executeStmt(db, "COMMIT", this.#intMode);
return resultSets;
Expand Down Expand Up @@ -271,10 +274,15 @@ export class Sqlite3Transaction implements Transaction {
return executeStmt(this.#database, stmt, this.#intMode);
}

async batch(stmts: Array<InStatement>): Promise<Array<ResultSet>> {
async batch(
stmts: Array<InStatement | [string, InArgs?]>,
): Promise<Array<ResultSet>> {
return stmts.map((stmt) => {
this.#checkNotClosed();
return executeStmt(this.#database, stmt, this.#intMode);
const normalizedStmt: InStatement = Array.isArray(stmt)
? { sql: stmt[0], args: stmt[1] || [] }
: stmt;
return executeStmt(this.#database, normalizedStmt, this.#intMode);
});
}

Expand Down
14 changes: 12 additions & 2 deletions packages/libsql-client/src/ws.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,13 +192,23 @@ export class WsClient implements Client {
}

async batch(
stmts: Array<InStatement>,
stmts: Array<InStatement | [string, InArgs?]>,
mode: TransactionMode = "deferred",
): Promise<Array<ResultSet>> {
return this.limit<Array<ResultSet>>(async () => {
const streamState = await this.#openStream();
try {
const hranaStmts = stmts.map(stmtToHrana);
const normalizedStmts = stmts.map(stmt => {
if (Array.isArray(stmt)) {
return {
sql: stmt[0],
args: stmt[1] || []
};
}
return stmt;
});

const hranaStmts = normalizedStmts.map(stmtToHrana);
const version = await streamState.conn.client.getVersion();

// Schedule all operations synchronously, so they will be pipelined and executed in a single
Expand Down
4 changes: 2 additions & 2 deletions packages/libsql-core/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ export interface Client {
* ```
*/
batch(
stmts: Array<InStatement>,
stmts: Array<InStatement | [string, InArgs?]>,
mode?: TransactionMode,
): Promise<Array<ResultSet>>;

Expand Down Expand Up @@ -469,7 +469,7 @@ export type Value = null | string | number | bigint | ArrayBuffer;

export type InValue = Value | boolean | Uint8Array | Date;

export type InStatement = { sql: string; args: InArgs } | string;
export type InStatement = { sql: string; args?: InArgs } | string;
export type InArgs = Array<InValue> | Record<string, InValue>;

/** Error thrown by the client. */
Expand Down

0 comments on commit 80c2767

Please sign in to comment.