@ohos-ports/libsql-client 0.18.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +128 -0
- package/lib-cjs/hrana.js +372 -0
- package/lib-cjs/http.js +268 -0
- package/lib-cjs/node.js +41 -0
- package/lib-cjs/package.json +3 -0
- package/lib-cjs/sql_cache.js +91 -0
- package/lib-cjs/sqlite3.js +720 -0
- package/lib-cjs/web.js +41 -0
- package/lib-cjs/ws.js +395 -0
- package/lib-esm/hrana.d.ts +23 -0
- package/lib-esm/hrana.js +341 -0
- package/lib-esm/http.d.ts +39 -0
- package/lib-esm/http.js +232 -0
- package/lib-esm/node.d.ts +7 -0
- package/lib-esm/node.js +23 -0
- package/lib-esm/sql_cache.d.ts +7 -0
- package/lib-esm/sql_cache.js +87 -0
- package/lib-esm/sqlite3.d.ts +53 -0
- package/lib-esm/sqlite3.js +695 -0
- package/lib-esm/web.d.ts +6 -0
- package/lib-esm/web.js +22 -0
- package/lib-esm/ws.d.ts +50 -0
- package/lib-esm/ws.js +359 -0
- package/package.json +123 -0
package/README.md
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://tur.so/turso-ts">
|
|
3
|
+
<picture>
|
|
4
|
+
<img src="/.github/cover.png" alt="libSQL TypeScript" />
|
|
5
|
+
</picture>
|
|
6
|
+
</a>
|
|
7
|
+
<h1 align="center">libSQL TypeScript</h1>
|
|
8
|
+
</p>
|
|
9
|
+
|
|
10
|
+
<p align="center">
|
|
11
|
+
Databases for all TypeScript and JS multi-tenant apps.
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
<p align="center">
|
|
15
|
+
<a href="https://tur.so/turso-ts"><strong>Turso</strong></a> ·
|
|
16
|
+
<a href="https://docs.turso.tech"><strong>Docs</strong></a> ·
|
|
17
|
+
<a href="https://docs.turso.tech/sdk/ts/quickstart"><strong>Quickstart</strong></a> ·
|
|
18
|
+
<a href="https://docs.turso.tech/sdk/ts/reference"><strong>SDK Reference</strong></a> ·
|
|
19
|
+
<a href="https://turso.tech/blog"><strong>Blog & Tutorials</strong></a>
|
|
20
|
+
</p>
|
|
21
|
+
|
|
22
|
+
<p align="center">
|
|
23
|
+
<a href="LICENSE">
|
|
24
|
+
<picture>
|
|
25
|
+
<img src="https://img.shields.io/github/license/tursodatabase/libsql-client-ts?color=0F624B" alt="MIT License" />
|
|
26
|
+
</picture>
|
|
27
|
+
</a>
|
|
28
|
+
<a href="https://tur.so/discord-ts">
|
|
29
|
+
<picture>
|
|
30
|
+
<img src="https://img.shields.io/discord/933071162680958986?color=0F624B" alt="Discord" />
|
|
31
|
+
</picture>
|
|
32
|
+
</a>
|
|
33
|
+
<a href="#contributors">
|
|
34
|
+
<picture>
|
|
35
|
+
<img src="https://img.shields.io/github/contributors/tursodatabase/libsql-client-ts?color=0F624B" alt="Contributors" />
|
|
36
|
+
</picture>
|
|
37
|
+
</a>
|
|
38
|
+
<a href="https://www.npmjs.com/package/@libsql/client">
|
|
39
|
+
<picture>
|
|
40
|
+
<img src="https://img.shields.io/npm/dw/%40libsql%2Fclient?color=0F624B" alt="Weekly downloads" />
|
|
41
|
+
</picture>
|
|
42
|
+
</a>
|
|
43
|
+
<a href="/examples">
|
|
44
|
+
<picture>
|
|
45
|
+
<img src="https://img.shields.io/badge/browse-examples-0F624B" alt="Examples" />
|
|
46
|
+
</picture>
|
|
47
|
+
</a>
|
|
48
|
+
</p>
|
|
49
|
+
|
|
50
|
+
> **Looking for the Turso serverless package?** Check out [`@tursodatabase/serverless`](https://www.npmjs.com/package/@tursodatabase/serverless) — the lightest option with zero native dependencies, and will be the driver to later support concurrent writes. Use `@libsql/client` if you need a battle-tested driver today with ORM integration.
|
|
51
|
+
|
|
52
|
+
## Features
|
|
53
|
+
|
|
54
|
+
- 🔌 Works offline with [Embedded Replicas](https://docs.turso.tech/features/embedded-replicas/introduction)
|
|
55
|
+
- 🌎 Works with remote Turso databases
|
|
56
|
+
- ✨ Works with Turso [AI & Vector Search](https://docs.turso.tech/features/ai-and-embeddings)
|
|
57
|
+
- 🔐 Supports [encryption at rest](https://docs.turso.tech/libsql#encryption-at-rest)
|
|
58
|
+
|
|
59
|
+
## Install
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
npm install @libsql/client
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Quickstart
|
|
66
|
+
|
|
67
|
+
The example below uses Embedded Replicas and syncs every minute from Turso.
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
import { createClient } from "@libsql/client";
|
|
71
|
+
|
|
72
|
+
export const turso = createClient({
|
|
73
|
+
url: "file:local.db",
|
|
74
|
+
syncUrl: process.env.TURSO_DATABASE_URL,
|
|
75
|
+
authToken: process.env.TURSO_AUTH_TOKEN,
|
|
76
|
+
syncInterval: 60000,
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
await turso.batch(
|
|
80
|
+
[
|
|
81
|
+
"CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)",
|
|
82
|
+
{
|
|
83
|
+
sql: "INSERT INTO users(name) VALUES (?)",
|
|
84
|
+
args: ["Iku"],
|
|
85
|
+
},
|
|
86
|
+
],
|
|
87
|
+
"write",
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
await turso.execute({
|
|
91
|
+
sql: "SELECT * FROM users WHERE id = ?",
|
|
92
|
+
args: [1],
|
|
93
|
+
});
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Examples
|
|
97
|
+
|
|
98
|
+
| Example | Description |
|
|
99
|
+
| ------------------------------------- | --------------------------------------------------------------------------------------- |
|
|
100
|
+
| [local](examples/local) | Uses libsql with a local SQLite file. Creates database, inserts data, and queries. |
|
|
101
|
+
| [remote](examples/remote) | Connects to a remote database. Requires environment variables for URL and auth token. |
|
|
102
|
+
| [sync](examples/sync) | Demonstrates synchronization between local and remote databases. |
|
|
103
|
+
| [batch](examples/batch) | Executes multiple SQL statements in a single batch operation. |
|
|
104
|
+
| [transactions](examples/transactions) | Shows transaction usage: starting, performing operations, and committing/rolling back. |
|
|
105
|
+
| [memory](examples/memory) | Uses an in-memory SQLite database for temporary storage or fast access. |
|
|
106
|
+
| [vector](examples/vector) | Works with vector embeddings, storing and querying for similarity search. |
|
|
107
|
+
| [encryption](examples/encryption) | Creates and uses an encrypted SQLite database, demonstrating setup and data operations. |
|
|
108
|
+
| [ollama](examples/ollama) | Similarity search with Ollama and Mistral. |
|
|
109
|
+
|
|
110
|
+
## Documentation
|
|
111
|
+
|
|
112
|
+
Visit our [official documentation](https://docs.turso.tech/sdk/ts).
|
|
113
|
+
|
|
114
|
+
## Support
|
|
115
|
+
|
|
116
|
+
Join us [on Discord](https://tur.so/discord-ts) to get help using this SDK. Report security issues [via email](mailto:security@turso.tech).
|
|
117
|
+
|
|
118
|
+
## Contributors
|
|
119
|
+
|
|
120
|
+
See the [contributing guide](CONTRIBUTING.md) to learn how to get involved.
|
|
121
|
+
|
|
122
|
+

|
|
123
|
+
|
|
124
|
+
<a href="https://github.com/tursodatabase/libsql-client-ts/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22">
|
|
125
|
+
<picture>
|
|
126
|
+
<img src="https://img.shields.io/github/issues-search/tursodatabase/libsql-client-ts?label=good%20first%20issue&query=label%3A%22good%20first%20issue%22%20&color=0F624B" alt="good first issue" />
|
|
127
|
+
</picture>
|
|
128
|
+
</a>
|
package/lib-cjs/hrana.js
ADDED
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.mapHranaError = exports.resultSetFromHrana = exports.stmtToHrana = exports.executeHranaBatch = exports.HranaTransaction = void 0;
|
|
27
|
+
const hrana = __importStar(require("@libsql/hrana-client"));
|
|
28
|
+
const api_1 = require("@libsql/core/api");
|
|
29
|
+
const util_1 = require("@libsql/core/util");
|
|
30
|
+
class HranaTransaction {
|
|
31
|
+
#mode;
|
|
32
|
+
#version;
|
|
33
|
+
// Promise that is resolved when the BEGIN statement completes, or `undefined` if we haven't executed the
|
|
34
|
+
// BEGIN statement yet.
|
|
35
|
+
#started;
|
|
36
|
+
/** @private */
|
|
37
|
+
constructor(mode, version) {
|
|
38
|
+
this.#mode = mode;
|
|
39
|
+
this.#version = version;
|
|
40
|
+
this.#started = undefined;
|
|
41
|
+
}
|
|
42
|
+
execute(stmt) {
|
|
43
|
+
return this.batch([stmt]).then((results) => results[0]);
|
|
44
|
+
}
|
|
45
|
+
async batch(stmts) {
|
|
46
|
+
const stream = this._getStream();
|
|
47
|
+
if (stream.closed) {
|
|
48
|
+
throw new api_1.LibsqlError("Cannot execute statements because the transaction is closed", "TRANSACTION_CLOSED");
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
const hranaStmts = stmts.map(stmtToHrana);
|
|
52
|
+
let rowsPromises;
|
|
53
|
+
if (this.#started === undefined) {
|
|
54
|
+
// The transaction hasn't started yet, so we need to send the BEGIN statement in a batch with
|
|
55
|
+
// `hranaStmts`.
|
|
56
|
+
this._getSqlCache().apply(hranaStmts);
|
|
57
|
+
const batch = stream.batch(this.#version >= 3);
|
|
58
|
+
const beginStep = batch.step();
|
|
59
|
+
const beginPromise = beginStep.run((0, util_1.transactionModeToBegin)(this.#mode));
|
|
60
|
+
// Execute the `hranaStmts` only if the BEGIN succeeded, to make sure that we don't execute it
|
|
61
|
+
// outside of a transaction.
|
|
62
|
+
let lastStep = beginStep;
|
|
63
|
+
rowsPromises = hranaStmts.map((hranaStmt) => {
|
|
64
|
+
const stmtStep = batch
|
|
65
|
+
.step()
|
|
66
|
+
.condition(hrana.BatchCond.ok(lastStep));
|
|
67
|
+
if (this.#version >= 3) {
|
|
68
|
+
// If the Hrana version supports it, make sure that we are still in a transaction
|
|
69
|
+
stmtStep.condition(hrana.BatchCond.not(hrana.BatchCond.isAutocommit(batch)));
|
|
70
|
+
}
|
|
71
|
+
const rowsPromise = stmtStep.query(hranaStmt);
|
|
72
|
+
rowsPromise.catch(() => undefined); // silence Node warning
|
|
73
|
+
lastStep = stmtStep;
|
|
74
|
+
return rowsPromise;
|
|
75
|
+
});
|
|
76
|
+
// `this.#started` is resolved successfully only if the batch and the BEGIN statement inside
|
|
77
|
+
// of the batch are both successful.
|
|
78
|
+
this.#started = batch
|
|
79
|
+
.execute()
|
|
80
|
+
.then(() => beginPromise)
|
|
81
|
+
.then(() => undefined);
|
|
82
|
+
try {
|
|
83
|
+
await this.#started;
|
|
84
|
+
}
|
|
85
|
+
catch (e) {
|
|
86
|
+
// If the BEGIN failed, the transaction is unusable and we must close it. However, if the
|
|
87
|
+
// BEGIN suceeds and `hranaStmts` fail, the transaction is _not_ closed.
|
|
88
|
+
this.close();
|
|
89
|
+
throw e;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
if (this.#version < 3) {
|
|
94
|
+
// The transaction has started, so we must wait until the BEGIN statement completed to make
|
|
95
|
+
// sure that we don't execute `hranaStmts` outside of a transaction.
|
|
96
|
+
await this.#started;
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
// The transaction has started, but we will use `hrana.BatchCond.isAutocommit()` to make
|
|
100
|
+
// sure that we don't execute `hranaStmts` outside of a transaction, so we don't have to
|
|
101
|
+
// wait for `this.#started`
|
|
102
|
+
}
|
|
103
|
+
this._getSqlCache().apply(hranaStmts);
|
|
104
|
+
const batch = stream.batch(this.#version >= 3);
|
|
105
|
+
let lastStep = undefined;
|
|
106
|
+
rowsPromises = hranaStmts.map((hranaStmt) => {
|
|
107
|
+
const stmtStep = batch.step();
|
|
108
|
+
if (lastStep !== undefined) {
|
|
109
|
+
stmtStep.condition(hrana.BatchCond.ok(lastStep));
|
|
110
|
+
}
|
|
111
|
+
if (this.#version >= 3) {
|
|
112
|
+
stmtStep.condition(hrana.BatchCond.not(hrana.BatchCond.isAutocommit(batch)));
|
|
113
|
+
}
|
|
114
|
+
const rowsPromise = stmtStep.query(hranaStmt);
|
|
115
|
+
rowsPromise.catch(() => undefined); // silence Node warning
|
|
116
|
+
lastStep = stmtStep;
|
|
117
|
+
return rowsPromise;
|
|
118
|
+
});
|
|
119
|
+
await batch.execute();
|
|
120
|
+
}
|
|
121
|
+
const resultSets = [];
|
|
122
|
+
for (let i = 0; i < rowsPromises.length; i++) {
|
|
123
|
+
try {
|
|
124
|
+
const rows = await rowsPromises[i];
|
|
125
|
+
if (rows === undefined) {
|
|
126
|
+
throw new api_1.LibsqlBatchError("Statement in a transaction was not executed, " +
|
|
127
|
+
"probably because the transaction has been rolled back", i, "TRANSACTION_CLOSED");
|
|
128
|
+
}
|
|
129
|
+
resultSets.push(resultSetFromHrana(rows));
|
|
130
|
+
}
|
|
131
|
+
catch (e) {
|
|
132
|
+
if (e instanceof api_1.LibsqlBatchError) {
|
|
133
|
+
throw e;
|
|
134
|
+
}
|
|
135
|
+
// Map hrana errors to LibsqlError first, then wrap in LibsqlBatchError
|
|
136
|
+
const mappedError = mapHranaError(e);
|
|
137
|
+
if (mappedError instanceof api_1.LibsqlError) {
|
|
138
|
+
throw new api_1.LibsqlBatchError(mappedError.message, i, mappedError.code, mappedError.extendedCode, mappedError.rawCode, mappedError.cause instanceof Error
|
|
139
|
+
? mappedError.cause
|
|
140
|
+
: undefined);
|
|
141
|
+
}
|
|
142
|
+
throw mappedError;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return resultSets;
|
|
146
|
+
}
|
|
147
|
+
catch (e) {
|
|
148
|
+
throw mapHranaError(e);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
async executeMultiple(sql) {
|
|
152
|
+
const stream = this._getStream();
|
|
153
|
+
if (stream.closed) {
|
|
154
|
+
throw new api_1.LibsqlError("Cannot execute statements because the transaction is closed", "TRANSACTION_CLOSED");
|
|
155
|
+
}
|
|
156
|
+
try {
|
|
157
|
+
if (this.#started === undefined) {
|
|
158
|
+
// If the transaction hasn't started yet, start it now
|
|
159
|
+
this.#started = stream
|
|
160
|
+
.run((0, util_1.transactionModeToBegin)(this.#mode))
|
|
161
|
+
.then(() => undefined);
|
|
162
|
+
try {
|
|
163
|
+
await this.#started;
|
|
164
|
+
}
|
|
165
|
+
catch (e) {
|
|
166
|
+
this.close();
|
|
167
|
+
throw e;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
// Wait until the transaction has started
|
|
172
|
+
await this.#started;
|
|
173
|
+
}
|
|
174
|
+
await stream.sequence(sql);
|
|
175
|
+
}
|
|
176
|
+
catch (e) {
|
|
177
|
+
throw mapHranaError(e);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
async rollback() {
|
|
181
|
+
try {
|
|
182
|
+
const stream = this._getStream();
|
|
183
|
+
if (stream.closed) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
if (this.#started !== undefined) {
|
|
187
|
+
// We don't have to wait for the BEGIN statement to complete. If the BEGIN fails, we will
|
|
188
|
+
// execute a ROLLBACK outside of an active transaction, which should be harmless.
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
// We did nothing in the transaction, so there is nothing to rollback.
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
// Pipeline the ROLLBACK statement and the stream close.
|
|
195
|
+
const promise = stream.run("ROLLBACK").catch((e) => {
|
|
196
|
+
throw mapHranaError(e);
|
|
197
|
+
});
|
|
198
|
+
stream.closeGracefully();
|
|
199
|
+
await promise;
|
|
200
|
+
}
|
|
201
|
+
catch (e) {
|
|
202
|
+
throw mapHranaError(e);
|
|
203
|
+
}
|
|
204
|
+
finally {
|
|
205
|
+
// `this.close()` may close the `hrana.Client`, which aborts all pending stream requests, so we
|
|
206
|
+
// must call it _after_ we receive the ROLLBACK response.
|
|
207
|
+
// Also note that the current stream should already be closed, but we need to call `this.close()`
|
|
208
|
+
// anyway, because it may need to do more cleanup.
|
|
209
|
+
this.close();
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
async commit() {
|
|
213
|
+
// (this method is analogous to `rollback()`)
|
|
214
|
+
try {
|
|
215
|
+
const stream = this._getStream();
|
|
216
|
+
if (stream.closed) {
|
|
217
|
+
throw new api_1.LibsqlError("Cannot commit the transaction because it is already closed", "TRANSACTION_CLOSED");
|
|
218
|
+
}
|
|
219
|
+
if (this.#started !== undefined) {
|
|
220
|
+
// Make sure to execute the COMMIT only if the BEGIN was successful.
|
|
221
|
+
await this.#started;
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
const promise = stream.run("COMMIT").catch((e) => {
|
|
227
|
+
throw mapHranaError(e);
|
|
228
|
+
});
|
|
229
|
+
stream.closeGracefully();
|
|
230
|
+
await promise;
|
|
231
|
+
}
|
|
232
|
+
catch (e) {
|
|
233
|
+
throw mapHranaError(e);
|
|
234
|
+
}
|
|
235
|
+
finally {
|
|
236
|
+
this.close();
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
exports.HranaTransaction = HranaTransaction;
|
|
241
|
+
async function executeHranaBatch(mode, version, batch, hranaStmts, disableForeignKeys = false) {
|
|
242
|
+
if (disableForeignKeys) {
|
|
243
|
+
batch.step().run("PRAGMA foreign_keys=off");
|
|
244
|
+
}
|
|
245
|
+
const beginStep = batch.step();
|
|
246
|
+
const beginPromise = beginStep.run((0, util_1.transactionModeToBegin)(mode));
|
|
247
|
+
let lastStep = beginStep;
|
|
248
|
+
const stmtPromises = hranaStmts.map((hranaStmt) => {
|
|
249
|
+
const stmtStep = batch.step().condition(hrana.BatchCond.ok(lastStep));
|
|
250
|
+
if (version >= 3) {
|
|
251
|
+
stmtStep.condition(hrana.BatchCond.not(hrana.BatchCond.isAutocommit(batch)));
|
|
252
|
+
}
|
|
253
|
+
const stmtPromise = stmtStep.query(hranaStmt);
|
|
254
|
+
lastStep = stmtStep;
|
|
255
|
+
return stmtPromise;
|
|
256
|
+
});
|
|
257
|
+
const commitStep = batch.step().condition(hrana.BatchCond.ok(lastStep));
|
|
258
|
+
if (version >= 3) {
|
|
259
|
+
commitStep.condition(hrana.BatchCond.not(hrana.BatchCond.isAutocommit(batch)));
|
|
260
|
+
}
|
|
261
|
+
const commitPromise = commitStep.run("COMMIT");
|
|
262
|
+
const rollbackStep = batch
|
|
263
|
+
.step()
|
|
264
|
+
.condition(hrana.BatchCond.not(hrana.BatchCond.ok(commitStep)));
|
|
265
|
+
rollbackStep.run("ROLLBACK").catch((_) => undefined);
|
|
266
|
+
if (disableForeignKeys) {
|
|
267
|
+
batch.step().run("PRAGMA foreign_keys=on");
|
|
268
|
+
}
|
|
269
|
+
await batch.execute();
|
|
270
|
+
const resultSets = [];
|
|
271
|
+
await beginPromise;
|
|
272
|
+
for (let i = 0; i < stmtPromises.length; i++) {
|
|
273
|
+
try {
|
|
274
|
+
const hranaRows = await stmtPromises[i];
|
|
275
|
+
if (hranaRows === undefined) {
|
|
276
|
+
throw new api_1.LibsqlBatchError("Statement in a batch was not executed, probably because the transaction has been rolled back", i, "TRANSACTION_CLOSED");
|
|
277
|
+
}
|
|
278
|
+
resultSets.push(resultSetFromHrana(hranaRows));
|
|
279
|
+
}
|
|
280
|
+
catch (e) {
|
|
281
|
+
if (e instanceof api_1.LibsqlBatchError) {
|
|
282
|
+
throw e;
|
|
283
|
+
}
|
|
284
|
+
// Map hrana errors to LibsqlError first, then wrap in LibsqlBatchError
|
|
285
|
+
const mappedError = mapHranaError(e);
|
|
286
|
+
if (mappedError instanceof api_1.LibsqlError) {
|
|
287
|
+
throw new api_1.LibsqlBatchError(mappedError.message, i, mappedError.code, mappedError.extendedCode, mappedError.rawCode, mappedError.cause instanceof Error
|
|
288
|
+
? mappedError.cause
|
|
289
|
+
: undefined);
|
|
290
|
+
}
|
|
291
|
+
throw mappedError;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
await commitPromise;
|
|
295
|
+
return resultSets;
|
|
296
|
+
}
|
|
297
|
+
exports.executeHranaBatch = executeHranaBatch;
|
|
298
|
+
function stmtToHrana(stmt) {
|
|
299
|
+
let sql;
|
|
300
|
+
let args;
|
|
301
|
+
if (Array.isArray(stmt)) {
|
|
302
|
+
[sql, args] = stmt;
|
|
303
|
+
}
|
|
304
|
+
else if (typeof stmt === "string") {
|
|
305
|
+
sql = stmt;
|
|
306
|
+
}
|
|
307
|
+
else {
|
|
308
|
+
sql = stmt.sql;
|
|
309
|
+
args = stmt.args;
|
|
310
|
+
}
|
|
311
|
+
const hranaStmt = new hrana.Stmt(sql);
|
|
312
|
+
if (args) {
|
|
313
|
+
if (Array.isArray(args)) {
|
|
314
|
+
hranaStmt.bindIndexes(args);
|
|
315
|
+
}
|
|
316
|
+
else {
|
|
317
|
+
for (const [key, value] of Object.entries(args)) {
|
|
318
|
+
hranaStmt.bindName(key, value);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
return hranaStmt;
|
|
323
|
+
}
|
|
324
|
+
exports.stmtToHrana = stmtToHrana;
|
|
325
|
+
function resultSetFromHrana(hranaRows) {
|
|
326
|
+
const columns = hranaRows.columnNames.map((c) => c ?? "");
|
|
327
|
+
const columnTypes = hranaRows.columnDecltypes.map((c) => c ?? "");
|
|
328
|
+
const rows = hranaRows.rows;
|
|
329
|
+
const rowsAffected = hranaRows.affectedRowCount;
|
|
330
|
+
const lastInsertRowid = hranaRows.lastInsertRowid !== undefined
|
|
331
|
+
? hranaRows.lastInsertRowid
|
|
332
|
+
: undefined;
|
|
333
|
+
return new util_1.ResultSetImpl(columns, columnTypes, rows, rowsAffected, lastInsertRowid);
|
|
334
|
+
}
|
|
335
|
+
exports.resultSetFromHrana = resultSetFromHrana;
|
|
336
|
+
function mapHranaError(e) {
|
|
337
|
+
if (e instanceof hrana.ClientError) {
|
|
338
|
+
const code = mapHranaErrorCode(e);
|
|
339
|
+
// TODO: Parse extendedCode once the SQL over HTTP protocol supports it
|
|
340
|
+
return new api_1.LibsqlError(e.message, code, undefined, undefined, e);
|
|
341
|
+
}
|
|
342
|
+
return e;
|
|
343
|
+
}
|
|
344
|
+
exports.mapHranaError = mapHranaError;
|
|
345
|
+
function mapHranaErrorCode(e) {
|
|
346
|
+
if (e instanceof hrana.ResponseError && e.code !== undefined) {
|
|
347
|
+
return e.code;
|
|
348
|
+
}
|
|
349
|
+
else if (e instanceof hrana.ProtoError) {
|
|
350
|
+
return "HRANA_PROTO_ERROR";
|
|
351
|
+
}
|
|
352
|
+
else if (e instanceof hrana.ClosedError) {
|
|
353
|
+
return e.cause instanceof hrana.ClientError
|
|
354
|
+
? mapHranaErrorCode(e.cause)
|
|
355
|
+
: "HRANA_CLOSED_ERROR";
|
|
356
|
+
}
|
|
357
|
+
else if (e instanceof hrana.WebSocketError) {
|
|
358
|
+
return "HRANA_WEBSOCKET_ERROR";
|
|
359
|
+
}
|
|
360
|
+
else if (e instanceof hrana.HttpServerError) {
|
|
361
|
+
return "SERVER_ERROR";
|
|
362
|
+
}
|
|
363
|
+
else if (e instanceof hrana.ProtocolVersionError) {
|
|
364
|
+
return "PROTOCOL_VERSION_ERROR";
|
|
365
|
+
}
|
|
366
|
+
else if (e instanceof hrana.InternalError) {
|
|
367
|
+
return "INTERNAL_ERROR";
|
|
368
|
+
}
|
|
369
|
+
else {
|
|
370
|
+
return "UNKNOWN";
|
|
371
|
+
}
|
|
372
|
+
}
|