@worker-tools/deno-kv-storage
Version:
An implementation of the StorageArea (1,2,3) interface for Deno with an extensible system for supporting various database backends.
196 lines • 6.53 kB
JavaScript
import { getStr } from "./wasm.js";
import { Status, Types, Values } from "./constants.js";
import SqliteError from "./error.js";
import { RowObjects } from "./row_objects.js";
export class Rows {
/**
* Rows
*
* Rows represent a set of results from a query.
* They are iterable and yield arrays with
* the data from the selected columns.
*
* This class is not exported from the module
* and the only correct way to obtain a `Rows`
* object is by making a database query.
*/
constructor(wasm, stmt, cleanup) {
Object.defineProperty(this, "_wasm", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "_stmt", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "_cleanup", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "_done", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
this._wasm = wasm;
this._stmt = stmt;
this._done = false;
// if this is set, the Rows object will finalize the statement and remove it from the given set
this._cleanup = cleanup;
if (wasm == null) {
this._done = true;
}
}
/**
* Rows.return
*
* Implements the closing iterator
* protocol. See also:
* https://exploringjs.com/es6/ch_iteration.html#sec_closing-iterators
*/
return() {
if (!this._done) {
// Release transaction slot, if cleanup is
// the responsibility of this Rows object
if (this._cleanup != null) {
this._wasm.finalize(this._stmt);
this._cleanup.delete(this._stmt);
}
this._done = true;
}
return { done: true, value: null };
}
/**
* Rows.done
*
* Deprecated, prefer `Rows.return`.
*/
done() {
this.return();
}
/**
* Rows.next
*
* Implements the iterator protocol.
*/
next() {
if (this._done)
return { value: null, done: true };
// Load row data and advance statement
const row = this._get();
const status = this._wasm.step(this._stmt);
switch (status) {
case Status.SqliteRow:
// NO OP
break;
case Status.SqliteDone:
this.return();
break;
default:
this.return();
throw new SqliteError(this._wasm, status);
}
return { value: row, done: false };
}
/**
* Rows.columns
*
* Call this if you need column names from the result of a select query.
*
* This method returns an array of objects, where each object has the following properties:
*
* | Property | Value |
* |--------------|--------------------------------------------|
* | `name` | the result of `sqlite3_column_name` |
* | `originName` | the result of `sqlite3_column_origin_name` |
* | `tableName` | the result of `sqlite3_column_table_name` |
*/
columns() {
if (this._done) {
throw new SqliteError("Unable to retrieve column names as Rows already returned.");
}
const columnCount = this._wasm.column_count(this._stmt);
const columns = [];
for (let i = 0; i < columnCount; i++) {
const name = getStr(this._wasm, this._wasm.column_name(this._stmt, i));
const originName = getStr(this._wasm, this._wasm.column_origin_name(this._stmt, i));
const tableName = getStr(this._wasm, this._wasm.column_table_name(this._stmt, i));
columns.push({ name, originName, tableName });
}
return columns;
}
/**
* Rows.asObjects
*
* Call this if you need to ouput the rows as objects.
*
* const rows = [...db.query("SELECT name FROM users;").asObjects()];
*/
asObjects() {
return new RowObjects(this);
}
[Symbol.iterator]() {
return this;
}
_get() {
// Get results from row
const row = [];
// return row;
for (let i = 0, c = this._wasm.column_count(this._stmt); i < c; i++) {
switch (this._wasm.column_type(this._stmt, i)) {
case Types.Integer:
row.push(this._wasm.column_int(this._stmt, i));
break;
case Types.Float:
row.push(this._wasm.column_double(this._stmt, i));
break;
case Types.Text:
row.push(getStr(this._wasm, this._wasm.column_text(this._stmt, i)));
break;
case Types.Blob: {
const ptr = this._wasm.column_blob(this._stmt, i);
if (ptr === 0) {
// Zero pointer results in null
row.push(null);
}
else {
const length = this._wasm.column_bytes(this._stmt, i);
// Slice should copy the bytes, as it makes a shallow copy
row.push(new Uint8Array(this._wasm.memory.buffer, ptr, length).slice());
}
break;
}
case Types.BigInteger: {
const ptr = this._wasm.column_text(this._stmt, i);
row.push(BigInt(getStr(this._wasm, ptr)));
break;
}
default:
// TODO: Differentiate between NULL and not-recognized?
row.push(null);
break;
}
}
return row;
}
}
/**
* Empty
*
* A special constant. This is a `Rows` object
* which has no results. It is still iterable,
* however it won't yield any results.
*
* `Empty` is returned from queries which return
* no data.
*/
export const Empty = new Rows(null, Values.Null);
Empty._done = true; // TODO(dyedgreen): This is yikes...
//# sourceMappingURL=rows.js.map