diff --git a/lib/dialects/better-sqlite3/index.js b/lib/dialects/better-sqlite3/index.js index 18cf15768d..85a5ba6922 100644 --- a/lib/dialects/better-sqlite3/index.js +++ b/lib/dialects/better-sqlite3/index.js @@ -13,6 +13,7 @@ class Client_BetterSQLite3 extends Client_SQLite3 { return new this.driver(this.connectionSettings.filename, { nativeBinding: options.nativeBinding, + readonly: !!options.readonly, }); } diff --git a/test/db-less-test-suite.js b/test/db-less-test-suite.js index 8cac595595..1100a29312 100644 --- a/test/db-less-test-suite.js +++ b/test/db-less-test-suite.js @@ -50,6 +50,10 @@ if (config.mysql) { require('./unit/dialects/mysql'); } +if (config['better-sqlite3']) { + require('./unit/dialects/better-sqlite3'); +} + describe('CLI tests', function () { this.timeout(process.env.KNEX_TEST_TIMEOUT || 5000); require('./cli/help.spec'); diff --git a/test/unit/dialects/better-sqlite3.js b/test/unit/dialects/better-sqlite3.js index dbf3dfe23e..8f16cd716b 100644 --- a/test/unit/dialects/better-sqlite3.js +++ b/test/unit/dialects/better-sqlite3.js @@ -12,12 +12,18 @@ describe('better-sqlite3 unit tests', () => { connection: { filename: ':memory:', options: { - nativeBinding: path.resolve(__dirname, '../../../node_modules/better-sqlite3/build/Release/better_sqlite3.node'), + nativeBinding: path.resolve( + __dirname, + '../../../node_modules/better-sqlite3/build/Release/better_sqlite3.node' + ), }, }, }); - const result = await knexInstance.select(knexInstance.raw('2 + 2 as answer')).first().catch(err => err); + const result = await knexInstance + .select(knexInstance.raw('2 + 2 as answer')) + .first() + .catch((err) => err); expect(result.answer).to.equal(4); }); @@ -33,10 +39,61 @@ describe('better-sqlite3 unit tests', () => { }, }); - const result = await knexInstance.select(knexInstance.raw('2 + 2 as answer')).first().catch(err => err); + const result = await knexInstance + .select(knexInstance.raw('2 + 2 as answer')) + .first() + .catch((err) => err); console.dir(result); expect(result).to.be.an('error'); expect(result.code).to.equal('MODULE_NOT_FOUND'); }); }); + + describe('readonly', () => { + it('should initialize the DB with the passed-in `readonly` option', async () => { + const knexInstance = knex({ + client: 'better-sqlite3', + useNullAsDefault: true, + connection: { + filename: __dirname + '/../test.sqlite3', + options: { + readonly: true, + }, + }, + }); + + const connection = await knexInstance.client.acquireConnection(); + expect(connection.readonly).to.equal(true); + }); + + it('should prevent writing to the DB', async () => { + const knexInstance = knex({ + client: 'better-sqlite3', + useNullAsDefault: true, + connection: { + filename: __dirname + '/../test.sqlite3', + options: { + readonly: true, + }, + }, + }); + + await expect( + knexInstance.raw('create table shouldFail (x integer)') + ).to.eventually.be.rejectedWith('attempt to write a readonly database'); + }); + + it('should fall back on `readonly` = `false`', async () => { + const knexInstance = knex({ + client: 'better-sqlite3', + useNullAsDefault: true, + connection: { + filename: __dirname + '/../test.sqlite3', + }, + }); + + const connection = await knexInstance.client.acquireConnection(); + expect(connection.readonly).to.equal(false); + }); + }); }); diff --git a/types/index.d.ts b/types/index.d.ts index 87e9ca230f..0220a7cf48 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -3055,6 +3055,7 @@ export declare namespace Knex { filename: string; options?: { nativeBinding?: string; + readonly?: boolean; }; }