Skip to content

Commit a76e02c

Browse files
committed
Implement Statement.reader property for better-sqlite3 compatibility
Returns true if the statement returns data (has columns), false otherwise. This allows checking whether a prepared statement is a reader (SELECT, or INSERT/UPDATE/DELETE with RETURNING) before execution.
1 parent 148b56d commit a76e02c

5 files changed

Lines changed: 90 additions & 2 deletions

File tree

compat.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ class Statement {
255255
}
256256

257257
get reader() {
258-
throw new Error("not implemented");
258+
return this.stmt.columns().length > 0;
259259
}
260260

261261
/**

docs/api.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,10 @@ Toggle query duration timing.
179179

180180
Returns the columns in the result set returned by this prepared statement.
181181

182+
### reader ⇒ boolean
183+
184+
Returns `true` if the statement returns data (i.e., it is a `SELECT` statement or an `INSERT`/`UPDATE`/`DELETE` with a `RETURNING` clause), `false` otherwise.
185+
182186
### bind([...bindParameters]) ⇒ this
183187

184188
This function is currently not supported.

integration-tests/tests/async.test.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,48 @@ test.serial("Concurrent writes over same connection", async (t) => {
410410
t.is(rows.length, 1000);
411411
});
412412

413+
test.serial("Statement.reader [SELECT is true]", async (t) => {
414+
const db = t.context.db;
415+
const stmt = await db.prepare("SELECT * FROM users WHERE id = ?");
416+
t.is(stmt.reader, true);
417+
});
418+
419+
test.serial("Statement.reader [INSERT is false]", async (t) => {
420+
const db = t.context.db;
421+
const stmt = await db.prepare("INSERT INTO users (name, email) VALUES (?, ?)");
422+
t.is(stmt.reader, false);
423+
});
424+
425+
test.serial("Statement.reader [UPDATE is false]", async (t) => {
426+
const db = t.context.db;
427+
const stmt = await db.prepare("UPDATE users SET name = ? WHERE id = ?");
428+
t.is(stmt.reader, false);
429+
});
430+
431+
test.serial("Statement.reader [DELETE is false]", async (t) => {
432+
const db = t.context.db;
433+
const stmt = await db.prepare("DELETE FROM users WHERE id = ?");
434+
t.is(stmt.reader, false);
435+
});
436+
437+
test.serial("Statement.reader [INSERT RETURNING is true]", async (t) => {
438+
const db = t.context.db;
439+
const stmt = await db.prepare("INSERT INTO users (name, email) VALUES (?, ?) RETURNING *");
440+
t.is(stmt.reader, true);
441+
});
442+
443+
test.serial("Statement.reader [UPDATE RETURNING is true]", async (t) => {
444+
const db = t.context.db;
445+
const stmt = await db.prepare("UPDATE users SET name = ? WHERE id = ? RETURNING *");
446+
t.is(stmt.reader, true);
447+
});
448+
449+
test.serial("Statement.reader [DELETE RETURNING is true]", async (t) => {
450+
const db = t.context.db;
451+
const stmt = await db.prepare("DELETE FROM users WHERE id = ? RETURNING *");
452+
t.is(stmt.reader, true);
453+
});
454+
413455
const connect = async (path_opt, options = {}) => {
414456
const path = path_opt ?? "hello.db";
415457
const provider = process.env.PROVIDER;

integration-tests/tests/sync.test.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,48 @@ test.serial("Timeout option", async (t) => {
457457
fs.unlinkSync(path);
458458
});
459459

460+
test.serial("Statement.reader [SELECT is true]", async (t) => {
461+
const db = t.context.db;
462+
const stmt = db.prepare("SELECT * FROM users WHERE id = ?");
463+
t.is(stmt.reader, true);
464+
});
465+
466+
test.serial("Statement.reader [INSERT is false]", async (t) => {
467+
const db = t.context.db;
468+
const stmt = db.prepare("INSERT INTO users (name, email) VALUES (?, ?)");
469+
t.is(stmt.reader, false);
470+
});
471+
472+
test.serial("Statement.reader [UPDATE is false]", async (t) => {
473+
const db = t.context.db;
474+
const stmt = db.prepare("UPDATE users SET name = ? WHERE id = ?");
475+
t.is(stmt.reader, false);
476+
});
477+
478+
test.serial("Statement.reader [DELETE is false]", async (t) => {
479+
const db = t.context.db;
480+
const stmt = db.prepare("DELETE FROM users WHERE id = ?");
481+
t.is(stmt.reader, false);
482+
});
483+
484+
test.serial("Statement.reader [INSERT RETURNING is true]", async (t) => {
485+
const db = t.context.db;
486+
const stmt = db.prepare("INSERT INTO users (name, email) VALUES (?, ?) RETURNING *");
487+
t.is(stmt.reader, true);
488+
});
489+
490+
test.serial("Statement.reader [UPDATE RETURNING is true]", async (t) => {
491+
const db = t.context.db;
492+
const stmt = db.prepare("UPDATE users SET name = ? WHERE id = ? RETURNING *");
493+
t.is(stmt.reader, true);
494+
});
495+
496+
test.serial("Statement.reader [DELETE RETURNING is true]", async (t) => {
497+
const db = t.context.db;
498+
const stmt = db.prepare("DELETE FROM users WHERE id = ? RETURNING *");
499+
t.is(stmt.reader, true);
500+
});
501+
460502
const connect = async (path_opt, options = {}) => {
461503
const path = path_opt ?? "hello.db";
462504
const provider = process.env.PROVIDER;

promise.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ class Statement {
300300
}
301301

302302
get reader() {
303-
throw new Error("not implemented");
303+
return this.stmt.columns().length > 0;
304304
}
305305

306306
/**

0 commit comments

Comments
 (0)