@fizzyflow/suisql
Version:
SuiSQL is a library and set of tools for working with decentralized SQL databases on the Sui blockchain and Walrus protocol.
150 lines (126 loc) • 3.83 kB
text/typescript
import type SuiSql from "./SuiSql.js";
import type { Statement, BindParams } from "sql.js";
import { anyShallowCopy, isSureWriteSql } from "./SuiSqlUtils.js";
type SuiSqlStatementParams = {
suiSql: SuiSql,
statement?: Statement | undefined | null,
sql?: string | undefined | null,
params?: BindParams,
};
type WriteExecution = {
at: number,
sql: string,
params: BindParams,
};
export default class SuiSqlStatement {
private suiSql: SuiSql;
private stmp: Statement | undefined | null = null;
private sql: string | undefined | null = null;
private params: BindParams = null;
private executedAt: number | null = null;
public writeExecutions: Array<WriteExecution> = [];
constructor(params: SuiSqlStatementParams) {
this.suiSql = params.suiSql;
if (params.statement) {
this.stmp = params.statement;
this.sql = this.stmp.getSQL().trim();
} else if (params.sql) {
this.sql = params.sql.trim();
if (this.suiSql.db) {
this.stmp = this.suiSql.db.prepare(this.sql);
}
}
if (!this.stmp || !this.sql) {
throw new Error('either sql or statement param requried');
}
this.params = null;
if (params.params) {
this.bind(params.params);
}
this.executedAt = null;
this.writeExecutions = [];
}
bind(params: BindParams) {
this.params = params;
if (this.stmp) {
this.stmp.bind(params);
}
}
step() {
if (!this.stmp) {
return null;
}
this.executedAt = Date.now();
const stepResult = this.stmp.step();
if (this.sql && isSureWriteSql(this.sql)) {
this.writeExecutions.push({
params: anyShallowCopy(this.params),
sql: this.sql,
at: this.executedAt,
});
this.suiSql.markAsOk();
this.suiSql.mostRecentWriteChangeTime = this.executedAt;
}
return stepResult;
}
get() {
if (this.stmp) {
return this.stmp.get();
}
return null;
}
/**
* Shorthand for bind + step + reset Bind the values, execute the statement, ignoring the rows it returns, and resets it
*/
run(params = null) {
if (params) {
this.bind(params);
}
this.step();
this.reset();
}
/**
* Reset a statement, so that its parameters can be bound to new values It also clears all previous bindings, freeing the memory used by bound parameters.
*/
reset() {
if (this.stmp) {
return this.stmp.reset();
}
}
/**
* Free the memory used by the statement
*/
free() {
if (this.stmp) {
return this.stmp.free();
}
return false;
}
getAsObject() {
if (this.stmp) {
return this.stmp.getAsObject();
}
return null;
}
/**
* Loop over results from db. Callback may be an async function, waited to be fulfilled to get the next item.
* returns count of processed results.
*/
async forEach(callback: Function, maxCount?: number | undefined | null) {
let processedCount = 0;
let needMore = true;
while (needMore) {
let hasData = this.step();
if (hasData) {
await callback(this.getAsObject());
processedCount = processedCount + 1;
if (maxCount && maxCount < processedCount) {
needMore = false;
}
} else {
needMore = false;
}
}
return processedCount;
}
}