@proddata/node-cratedb
Version:
Node.js client for CrateDB
110 lines • 3.6 kB
JavaScript
;
import http from 'http';
import https from 'https';
import { CrateDBError, RequestError } from './utils/Error.js';
export class Cursor {
client;
sql;
cursorName;
isOpen;
agent;
cursorOptions;
constructor(client, sql) {
this.client = client;
this.sql = sql;
this.cursorName = `cursor_${Date.now()}`;
this.isOpen = false;
const agentOptions = {
keepAlive: true,
maxSockets: 1,
};
this.agent = client.getConfig().ssl ? new https.Agent(agentOptions) : new http.Agent(agentOptions);
this.cursorOptions = {
...client.getHttpOptions(),
agent: this.agent,
};
}
async open() {
if (this.isOpen) {
throw new Error('Cursor is already open');
}
// Start a transaction and declare the cursor
await this._execute('BEGIN');
await this._execute(`DECLARE ${this.cursorName} NO SCROLL CURSOR WITH HOLD FOR ${this.sql}`);
this.isOpen = true;
}
async fetchOne() {
this._ensureOpen();
const result = await this._execute(`FETCH NEXT FROM ${this.cursorName}`);
return result.length > 0 ? result[0] : null; // Return the first row or null
}
async fetchMany(size = 10) {
if (size < 1) {
// Return an empty array if size is less than 1
return [];
}
this._ensureOpen();
return await this._execute(`FETCH ${size} FROM ${this.cursorName}`);
}
async fetchAll() {
this._ensureOpen();
return await this._execute(`FETCH ALL FROM ${this.cursorName}`);
}
async *iterate(size = 100) {
this._ensureOpen();
while (true) {
const rows = await this.fetchMany(size);
if (!rows || rows.length === 0) {
break; // Stop iteration when no more rows are returned
}
for (const row of rows) {
yield row; // Yield one row at a time
}
}
}
async close() {
this._ensureOpen();
// Close the cursor and end the transaction
await this._execute(`CLOSE ${this.cursorName}`);
await this._execute('COMMIT');
this.isOpen = false;
// Destroy the agent's socket connections to ensure the TCP connection is closed
this.agent.destroy();
}
async _execute(sql) {
try {
const response = await this.client.execute(sql, undefined, {
rowMode: 'object',
httpOptions: this.cursorOptions,
});
if (!response.rows || !response.rowcount) {
return [];
}
return response.rows;
}
catch (error) {
if (error instanceof CrateDBError) {
throw error;
}
else if (error instanceof Error) {
throw new RequestError(`Error executing SQL: ${sql}. Details: ${error.message}`, { cause: error });
}
throw new RequestError('CrateDB request failed with an unknown error');
}
}
_rebuildObjects(cols, rows) {
return rows.map((row) => {
const obj = {};
cols.forEach((col, index) => {
obj[col] = row[index];
});
return obj;
});
}
_ensureOpen() {
if (!this.isOpen) {
throw new Error('Cursor is not open. Call open() before performing this operation.');
}
}
}
//# sourceMappingURL=Cursor.js.map