'use strict'; const fs = require('fs'); const path = require('path'); const util = require('./util'); const SqliteError = require('./sqlite-error'); let DEFAULT_ADDON; function Database(filenameGiven, options) { if (new.target == null) { return new Database(filenameGiven, options); } // Apply defaults if (filenameGiven == null) filenameGiven = ''; if (options == null) options = {}; // Validate arguments if (typeof filenameGiven !== 'string') throw new TypeError('Expected first argument to be a string'); if (typeof options !== 'object') throw new TypeError('Expected second argument to be an options object'); if ('readOnly' in options) throw new TypeError('Misspelled option "readOnly" should be "readonly"'); if ('memory' in options) throw new TypeError('Option "memory" was removed in v7.0.0 (use ":memory:" filename instead)'); // Interpret options const filename = filenameGiven.trim(); const anonymous = filename === '' || filename === ':memory:'; const readonly = util.getBooleanOption(options, 'readonly'); const fileMustExist = util.getBooleanOption(options, 'fileMustExist'); const timeout = 'timeout' in options ? options.timeout : 5000; const verbose = 'verbose' in options ? options.verbose : null; const nativeBindingPath = 'nativeBinding' in options ? options.nativeBinding : null; // Validate interpreted options if (readonly && anonymous) throw new TypeError('In-memory/temporary databases cannot be readonly'); if (!Number.isInteger(timeout) || timeout < 0) throw new TypeError('Expected the "timeout" option to be a positive integer'); if (timeout > 0x7fffffff) throw new RangeError('Option "timeout" cannot be greater than 2147483647'); if (verbose != null && typeof verbose !== 'function') throw new TypeError('Expected the "verbose" option to be a function'); if (nativeBindingPath != null && typeof nativeBindingPath !== 'string') throw new TypeError('Expected the "nativeBinding" option to be a string'); // Load the native addon let addon; if (nativeBindingPath == null) { addon = DEFAULT_ADDON || (DEFAULT_ADDON = require('bindings')('better_sqlite3.node')); } else { addon = require(path.resolve(nativeBindingPath).replace(/(\.node)?$/, '.node')); } if (!addon.isInitialized) { addon.setErrorConstructor(SqliteError); addon.setLogHandler(logHandlerWrap); addon.isInitialized = true; } // Make sure the specified directory exists if (!anonymous && !fs.existsSync(path.dirname(filename))) { throw new TypeError('Cannot open database because the directory does not exist'); } Object.defineProperties(this, { [util.cppdb]: { value: new addon.Database(filename, filenameGiven, anonymous, readonly, fileMustExist, timeout, verbose || null) }, ...wrappers.getters, }); } let logHandler; function logHandlerWrap(code, warning) { if (logHandler) { logHandler(code, warning); } } function noop() {} const wrappers = require('./methods/wrappers'); Database.prototype.prepare = wrappers.prepare; Database.prototype.transaction = require('./methods/transaction'); Database.prototype.pragma = require('./methods/pragma'); Database.prototype.backup = require('./methods/backup'); Database.prototype.function = require('./methods/function'); Database.prototype.aggregate = require('./methods/aggregate'); Database.prototype.table = require('./methods/table'); Database.prototype.createFTS5Tokenizer = require('./methods/createFTS5Tokenizer'); Database.prototype.exec = wrappers.exec; Database.prototype.close = wrappers.close; Database.prototype.defaultSafeIntegers = wrappers.defaultSafeIntegers; Database.prototype.unsafeMode = wrappers.unsafeMode; Database.prototype.signalTokenize = wrappers.signalTokenize; Database.prototype[util.inspect] = require('./methods/inspect'); // Static Database.setLogHandler = function setLogHandler(fn) { logHandler = fn; } module.exports = Database;