Comparing version 3.1.0 to 3.2.0
17
index.js
@@ -5,3 +5,3 @@ 'use strict'; | ||
const LUtils = require('larvitutils'); | ||
const lUtils = new LUtils(); | ||
const lUtils = new LUtils.Utils(); | ||
const mysql = require('mysql2/promise'); | ||
@@ -24,3 +24,3 @@ const mysqlSync = require('mysql2'); | ||
if (!this.options.log) this.options.log = new lUtils.Log('info'); | ||
if (!this.options.log) this.options.log = new LUtils.Log('info'); | ||
@@ -42,4 +42,13 @@ // Default to 3 retries on recoverable errors | ||
// Default to verbose log level for queries that change data | ||
if (this.options.dataChangeLogLevel === undefined) { | ||
this.options.dataChangeLogLevel = 'verbose'; | ||
} | ||
this.log = this.options.log; | ||
if (typeof this.log[this.options.dataChangeLogLevel] !== 'function') { | ||
throw new Error(`this.log[${this.options.dataChangeLogLevel}] is not a function`); | ||
} | ||
this.eventEmitter = new events.EventEmitter(); | ||
@@ -184,3 +193,3 @@ | ||
if (this.isSqlModifyingData(sql)) { | ||
this.log.verbose(logPrefix + 'Ran SQL: "' + sql + '" with dbFields: ' + JSON.stringify(dbFields) + ' in ' + queryTime + 'ms'); | ||
this.log[this.options.dataChangeLogLevel](logPrefix + 'Ran SQL: "' + sql + '" with dbFields: ' + JSON.stringify(dbFields) + ' in ' + queryTime + 'ms'); | ||
} | ||
@@ -296,3 +305,3 @@ | ||
if (this.isSqlModifyingData(sql)) { | ||
log.verbose(logPrefix + 'Ran SQL: "' + sql + '" with dbFields: ' + JSON.stringify(dbFields)); | ||
log[this.options.dataChangeLogLevel](logPrefix + 'Ran SQL: "' + sql + '" with dbFields: ' + JSON.stringify(dbFields)); | ||
} else if (sql.toUpperCase().startsWith('SELECT')) { | ||
@@ -299,0 +308,0 @@ log.debug(logPrefix + 'Ran SQL: "' + sql + '" with dbFields: ' + JSON.stringify(dbFields)); |
{ | ||
"name": "larvitdb", | ||
"version": "3.1.0", | ||
"version": "3.2.0", | ||
"description": "DB wrapper module for node.js", | ||
@@ -10,14 +10,13 @@ "main": "index.js", | ||
"dependencies": { | ||
"larvitutils": "2.3.0", | ||
"mysql2": "1.6.5" | ||
"larvitutils": "5.0.0", | ||
"mysql2": "2.3.3" | ||
}, | ||
"devDependencies": { | ||
"coveralls": "3.0.5", | ||
"eslint": "6.1.0", | ||
"nyc": "14.1.1", | ||
"tape": "4.11.0", | ||
"tape-eslint": "1.2.1" | ||
"eslint": "8.3.0", | ||
"nyc": "15.1.0", | ||
"tape": "5.3.2" | ||
}, | ||
"scripts": { | ||
"test": "npx tape test/*" | ||
"lint": "eslint *.js test/*.js", | ||
"test": "npm run lint && nyc tape test/*" | ||
}, | ||
@@ -24,0 +23,0 @@ "repository": { |
@@ -25,12 +25,13 @@ [](https://travis-ci.org/larvit/larvitdb) | ||
const db = new Db({ | ||
host: '127.0.0.1', // Do not use with socketPath | ||
socketPath: '/var/run/mysqld/mysqld.sock', // Do not use with host | ||
connectionLimit: 10, // Connections in the pool | ||
user: 'foo', | ||
password: 'bar', | ||
charset: 'utf8_general_ci', | ||
supportBigNumbers: true, | ||
database: 'my_database_name', | ||
log: log // Logging object. Will default to a simple console logger if not provided | ||
// See list of native options [here](https://github.com/felixge/node-mysql/#connection-options). | ||
host: '127.0.0.1', // Do not use with socketPath | ||
socketPath: '/var/run/mysqld/mysqld.sock', // Do not use with host | ||
connectionLimit: 10, // Connections in the pool | ||
user: 'foo', | ||
password: 'bar', | ||
charset: 'utf8_general_ci', | ||
supportBigNumbers: true, | ||
database: 'my_database_name', | ||
log: log, // Logging object. Will default to a simple console logger if not provided | ||
dataChangeLogLevel: 'debug', // Valid log level, levels in default provided logger: [info, verbose, debug, warning, error]. Defaults to 'verbose'. | ||
// See list of native options [here](https://github.com/felixge/node-mysql/#connection-options). | ||
}); | ||
@@ -105,15 +106,15 @@ ``` | ||
stream.on('fields', fields => { | ||
console.log('Array with field names that will be returned'); | ||
console.log('Array with field names that will be returned'); | ||
}); | ||
stream.on('result', row => { | ||
console.log('Handle row'); | ||
console.log('Handle row'); | ||
}); | ||
stream.on('error', err => { | ||
throw err; | ||
throw err; | ||
}); | ||
stream.on('end', () => { | ||
console.log('No more rows will come'); | ||
console.log('No more rows will come'); | ||
}); | ||
@@ -129,8 +130,8 @@ ``` | ||
const db = new Db({ | ||
socketPath: '/var/run/mysqld/mysqld.sock', | ||
user: 'foo', | ||
password: 'bar', | ||
database: 'my_database_name', | ||
retries: 5, // Defaults to 3 if omitted | ||
recoverableErrors: ['PROTOCOL_CONNECTION_LOST', 'ER_LOCK_DEADLOCK'] // What error codes to retry, these are the defaults | ||
socketPath: '/var/run/mysqld/mysqld.sock', | ||
user: 'foo', | ||
password: 'bar', | ||
database: 'my_database_name', | ||
retries: 5, // Defaults to 3 if omitted | ||
recoverableErrors: ['PROTOCOL_CONNECTION_LOST', 'ER_LOCK_DEADLOCK'] // What error codes to retry, these are the defaults | ||
}); | ||
@@ -150,4 +151,4 @@ | ||
const db = new Db({ | ||
... | ||
longQueryTime: 20000 | ||
... | ||
longQueryTime: 20000 | ||
}); | ||
@@ -160,4 +161,4 @@ ``` | ||
const db = new Db({ | ||
... | ||
longQueryTime: false | ||
... | ||
longQueryTime: false | ||
}); | ||
@@ -178,2 +179,5 @@ ``` | ||
### 3.2.0 | ||
* Added option for log level logging of data changing SQL queries | ||
### 3.1.0 | ||
@@ -180,0 +184,0 @@ * Added verbose level logging of data changing SQL queries |
237
test/test.js
'use strict'; | ||
const assert = require('assert'); | ||
const LUtils = require('larvitutils'); | ||
const lUtils = new LUtils(); | ||
const test = require('tape'); | ||
const log = new lUtils.Log('warn'); | ||
const log = new LUtils.Log('info'); | ||
const Db = require('../index.js'); | ||
@@ -15,3 +13,3 @@ const fs = require('fs'); | ||
async function dbTests(dbCon) { | ||
async function dbTests(dbCon, t) { | ||
await dbCon.query('CREATE TABLE `fjant` (`test` int NOT NULL) ENGINE=\'InnoDB\';'); | ||
@@ -22,13 +20,13 @@ await dbCon.query('INSERT INTO `fjant` VALUES(13);'); | ||
assert.strictEqual(testFromFjant.rows.length, 1); | ||
assert.strictEqual(testFromFjant.rows[0].test, 13); | ||
t.strictEqual(testFromFjant.rows.length, 1); | ||
t.strictEqual(testFromFjant.rows[0].test, 13); | ||
await dbCon.query('UPDATE fjant SET test = ?', 7); | ||
const testFromFjantAgain = await dbCon.query('SELECT test FROM fjant'); | ||
assert.strictEqual(testFromFjantAgain.rows.length, 1); | ||
assert.strictEqual(testFromFjantAgain.rows[0].test, 7); | ||
t.strictEqual(testFromFjantAgain.rows.length, 1); | ||
t.strictEqual(testFromFjantAgain.rows[0].test, 7); | ||
await dbCon.query('DELETE FROM fjant'); | ||
const testFromFjantLast = await dbCon.query('SELECT test FROM fjant'); | ||
assert.strictEqual(testFromFjantLast.rows.length, 0); | ||
t.strictEqual(testFromFjantLast.rows.length, 0); | ||
@@ -38,12 +36,6 @@ await dbCon.query('DROP TABLE fjant'); | ||
test('Setup db and do checks', t => { | ||
let confFile; | ||
async function setup(options) { | ||
options = options || {}; | ||
options.log = options.log || log; | ||
async function checkEmptyDb() { | ||
const { rows } = await db.query('SHOW TABLES'); | ||
if (rows.length) throw new Error('Database is not empty. To make a test, you must supply an empty database!'); | ||
t.end(); | ||
} | ||
async function runDbSetup(confFile) { | ||
@@ -55,9 +47,17 @@ let conf; | ||
conf = require(confFile); | ||
conf.log = log; | ||
const dbOptions = { | ||
...conf | ||
}; | ||
db = new Db(conf); | ||
await db.ready(); | ||
await checkEmptyDb(); | ||
for (const option in options) { | ||
dbOptions[option] = options[option]; | ||
} | ||
const dbInstance = new Db(dbOptions); | ||
await dbInstance.ready(); | ||
return dbInstance; | ||
} | ||
let confFile; | ||
if (process.env.TRAVIS) { | ||
@@ -73,22 +73,47 @@ confFile = __dirname + '/../config/db_travis.json'; | ||
fs.stat(confFile, err => { | ||
const altConfFile = __dirname + '/../config/' + confFile; | ||
return new Promise((res, rej) => { | ||
fs.stat(confFile, async (err) => { | ||
if (err) { | ||
const altConfFile = __dirname + '/../config/' + confFile; | ||
if (err) { | ||
log.info('Failed to find config file "' + confFile + '", retrying with "' + altConfFile + '"'); | ||
log.info('Failed to find config file "' + confFile + '", retrying with "' + altConfFile + '"'); | ||
fs.stat(altConfFile, err => { | ||
if (err) throw err; | ||
fs.stat(altConfFile, async (err) => { | ||
if (err) return rej(err); | ||
runDbSetup(altConfFile); | ||
}); | ||
} else { | ||
runDbSetup(confFile); | ||
} | ||
try { | ||
const dbInstance = await runDbSetup(altConfFile); | ||
return res(dbInstance); | ||
} catch (err) { | ||
return rej(err); | ||
} | ||
}); | ||
} else { | ||
try { | ||
const dbInstance = await runDbSetup(confFile); | ||
return res(dbInstance); | ||
} catch (err) { | ||
return rej(err); | ||
} | ||
} | ||
}); | ||
}); | ||
} | ||
test('Setup db and do checks', async (t) => { | ||
async function checkEmptyDb() { | ||
const { rows } = await db.query('SHOW TABLES'); | ||
if (rows.length) throw new Error('Database is not empty. To make a test, you must supply an empty database!'); | ||
} | ||
db = await setup(); | ||
await db.removeAllTables(); | ||
await checkEmptyDb(); | ||
t.end(); | ||
}); | ||
test('Simple queries', async (t) => { | ||
await dbTests(db); | ||
await dbTests(db, t); | ||
t.end(); | ||
@@ -99,3 +124,3 @@ }); | ||
const dbCon = await db.getConnection(); | ||
await dbTests(dbCon); | ||
await dbTests(dbCon, t); | ||
t.end(); | ||
@@ -125,6 +150,36 @@ }); | ||
const result = await db.query('SHOW TABLES'); | ||
assert.strictEqual(result.rows.length, 0); | ||
t.strictEqual(result.rows.length, 0); | ||
t.end(); | ||
}); | ||
test('Time zone dependent data', async (t) => { | ||
// Create table | ||
const sql = 'CREATE TABLE tzstuff (id int(11), tzstamp timestamp, tzdatetime datetime);'; | ||
await db.query(sql); | ||
// Set datetime as javascript Date object | ||
const dateObj = new Date('2018-03-04T17:38:20Z'); | ||
await db.query('INSERT INTO tzstuff VALUES(?,?,?);', [1, dateObj, dateObj]); | ||
// Check the values | ||
const result = await db.query('SELECT * FROM tzstuff ORDER BY id'); | ||
let foundRows = 0; | ||
for (let i = 0; result.rows[i] !== undefined; i++) { | ||
const row = result.rows[i]; | ||
if (row.id === 1) { | ||
foundRows++; | ||
t.strictEqual(row.tzstamp.toISOString(), '2018-03-04T17:38:20.000Z'); | ||
t.strictEqual(row.tzdatetime.toISOString(), '2018-03-04T17:38:20.000Z'); | ||
} | ||
} | ||
t.strictEqual(foundRows, 1); | ||
// Remove table | ||
await db.query('DROP TABLE tzstuff;'); | ||
t.end(); | ||
}); | ||
test('Stream rows', async (t) => { | ||
@@ -143,67 +198,77 @@ let rowNr = 0; | ||
query.on('error', err => { | ||
throw err; | ||
}); | ||
async function handleStream(query) { | ||
return new Promise((res, rej) => { | ||
query.on('error', err => { | ||
rej(err); | ||
}); | ||
query.on('fields', fields => { | ||
assert.strictEqual(fields[0].name, 'id'); | ||
assert.strictEqual(fields[1].name, 'name'); | ||
}); | ||
query.on('fields', fields => { | ||
t.strictEqual(fields[0].name, 'id'); | ||
t.strictEqual(fields[1].name, 'name'); | ||
}); | ||
query.on('result', row => { | ||
dbCon.pause(); // Pause streaming while handling row | ||
query.on('result', row => { | ||
dbCon.pause(); // Pause streaming while handling row | ||
rowNr++; | ||
rowNr++; | ||
if (rowNr === 1) { | ||
assert.strictEqual(row.id, 1); | ||
assert.strictEqual(row.name, 'bosse'); | ||
} else if (rowNr === 2) { | ||
assert.strictEqual(row.id, 2); | ||
assert.strictEqual(row.name, 'hasse'); | ||
} else if (rowNr === 2) { | ||
assert.strictEqual(row.id, 3); | ||
assert.strictEqual(row.name, 'vråkbert'); | ||
} | ||
if (rowNr === 1) { | ||
t.strictEqual(row.id, 1); | ||
t.strictEqual(row.name, 'bosse'); | ||
} else if (rowNr === 2) { | ||
t.strictEqual(row.id, 2); | ||
t.strictEqual(row.name, 'hasse'); | ||
} else if (rowNr === 2) { | ||
t.strictEqual(row.id, 3); | ||
t.strictEqual(row.name, 'vråkbert'); | ||
} | ||
dbCon.resume(); // Resume streaming when processing of row is done (this is normally done in async, doh) | ||
}); | ||
dbCon.resume(); // Resume streaming when processing of row is done (this is normally done in async, doh) | ||
}); | ||
query.on('end', async () => { | ||
assert.strictEqual(rowNr, 3); | ||
dbCon.release(); | ||
query.on('end', async () => { | ||
t.strictEqual(rowNr, 3); | ||
dbCon.release(); | ||
await db.removeAllTables(); | ||
res(); | ||
}); | ||
}); | ||
} | ||
t.end(); | ||
}); | ||
await handleStream(query); | ||
t.end(); | ||
}); | ||
test('Time zone dependent data', async (t) => { | ||
// Create table | ||
const sql = 'CREATE TABLE tzstuff (id int(11), tzstamp timestamp, tzdatetime datetime);'; | ||
await db.query(sql); | ||
test('Configure data change log level', async (t) => { | ||
let loggedDebugStr = ''; | ||
const specialLogger = { | ||
error: str => console.log(str), | ||
warn: str => console.log(str), | ||
info: str => console.log(str), | ||
verbose: str => console.log(str), | ||
debug: str => console.log(str), | ||
silly: str => console.log(str), | ||
specialDebug: str => loggedDebugStr = str | ||
}; | ||
const dbInstance = await setup({log: specialLogger, dataChangeLogLevel: 'specialDebug'}); | ||
// Set datetime as javascript Date object | ||
const dateObj = new Date('2018-03-04T17:38:20Z'); | ||
await db.query('INSERT INTO tzstuff VALUES(?,?,?);', [1, dateObj, dateObj]); | ||
await dbInstance.query('CREATE TABLE logTestTable (id int(11));'); | ||
await dbInstance.query('INSERT INTO logTestTable VALUES(?);', [1]); | ||
// Check the values | ||
const result = await db.query('SELECT * FROM tzstuff ORDER BY id'); | ||
let foundRows = 0; | ||
t.ok(loggedDebugStr.includes('Ran SQL: "INSERT INTO logTestTable VALUES(?);" with dbFields: [1] in ')); | ||
t.end(); | ||
}); | ||
for (let i = 0; result.rows[i] !== undefined; i++) { | ||
const row = result.rows[i]; | ||
test('Configure data change log level with invalid logger should throw', async (t) => { | ||
const specialLogger = { | ||
error: str => console.log(str) | ||
}; | ||
if (row.id === 1) { | ||
foundRows++; | ||
assert.strictEqual(row.tzstamp.toISOString(), '2018-03-04T17:38:20.000Z'); | ||
assert.strictEqual(row.tzdatetime.toISOString(), '2018-03-04T17:38:20.000Z'); | ||
} | ||
try { | ||
await setup({log: specialLogger, dataChangeLogLevel: 'nonExistingLogFunction'}); | ||
t.fail('Did not get expected exception'); | ||
} catch (err) { | ||
t.ok(true, 'Got expected exception: ' + err.message); | ||
} | ||
assert.strictEqual(foundRows, 1); | ||
// Remove table | ||
await db.query('DROP TABLE tzstuff;'); | ||
t.end(); | ||
@@ -210,0 +275,0 @@ }); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
29582
3
500
194
9
+ Addeddenque@2.1.0(transitive)
+ Addediconv-lite@0.6.3(transitive)
+ Addedlarvitutils@5.0.0(transitive)
+ Addedlru-cache@6.0.0(transitive)
+ Addedmysql2@2.3.3(transitive)
+ Addedyallist@4.0.0(transitive)
- Removeddenque@1.5.1(transitive)
- Removediconv-lite@0.4.24(transitive)
- Removedlarvitutils@2.3.0(transitive)
- Removedlru-cache@4.1.5(transitive)
- Removedmysql2@1.6.5(transitive)
- Removedpseudomap@1.0.2(transitive)
- Removedyallist@2.1.2(transitive)
Updatedlarvitutils@5.0.0
Updatedmysql2@2.3.3