diff --git a/README.md b/README.md index 8b3ac30..d222e8b 100644 --- a/README.md +++ b/README.md @@ -42,4 +42,22 @@ include the library itself (`knex`), but also transaction variables (`trx`, ### `knex/avoid-injections` -Avoid some issues related to SQL injection by disallowing plain strings as the query argument to the raw queries. Check out [the tests](https://github.com/AntonNiklasson/eslint-plugin-knex/blob/master/rules/avoid-injections.test.js) to get a sense for what is valid and not. +Avoid some issues related to SQL injection by disallowing plain strings as the query argument to the raw queries. Check +out [the tests](https://github.com/AntonNiklasson/eslint-plugin-knex/blob/master/rules/avoid-injections.test.js) to get +a sense for what is valid and not. + +### `knex/avoid-updating-all-rows` + +Avoid updating all rows of a table when unwanted. +You can ignore tables for which it is a legitimate usage. + +``` +{ + settings: { + knex: { + rule: { "avoid-updating-all-rows": { tablesToIgnore: ["author"] } }, + }, + } +} +``` + diff --git a/index.js b/index.js index a73ac9c..5e3215e 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,6 @@ module.exports = { rules: { - 'avoid-injections': require('./rules/avoid-injections') + 'avoid-injections': require('./rules/avoid-injections'), + 'avoid-updating-all-rows': require('./rules/avoid-updating-all-rows') } } diff --git a/rules/avoid-updating-all-rows.js b/rules/avoid-updating-all-rows.js new file mode 100644 index 0000000..f1c75e9 --- /dev/null +++ b/rules/avoid-updating-all-rows.js @@ -0,0 +1,35 @@ +const meta = { + type: "problem", + docs: { + description: "Avoid updating all rows", + }, + messages: { + avoid: `Avoid updating all rows`, + }, +}; + +const create = function(context) { + return { + [`CallExpression[callee.property.name='update'][callee.object.callee.name='knex']`](node) { + check(context, node); + }, + }; +}; +const check = function(context, node) { + + if (context.settings && context.settings.knex && context.settings.knex.rule) { + const ruleSettings = context.settings.knex.rule["avoid-updating-all-rows"]; + const tablesToIgnore = ruleSettings.tablesToIgnore; + const tableToUpdate = node.callee.object.arguments[0].value; + if (tablesToIgnore.includes(tableToUpdate)) { + return; + } + } + + context.report({ + node, + messageId: "avoid", + }); +}; + +module.exports = { meta, create }; diff --git a/rules/avoid-updating-all-rows.test.js b/rules/avoid-updating-all-rows.test.js new file mode 100644 index 0000000..5585551 --- /dev/null +++ b/rules/avoid-updating-all-rows.test.js @@ -0,0 +1,45 @@ +const { RuleTester } = require("eslint"); +const rule = require("./avoid-updating-all-rows"); + +function invalidCase(code, errors = [], others = {}) { + return Object.assign( + { + code, + errors, + }, + others, + ); +} + +const tester = new RuleTester({ + parserOptions: { ecmaVersion: 2015 }, +}); + +tester.run("avoid-updating-all-rows", rule, { + valid: ["knex('books').where({id:1}).update({'status': 'archived'})", + "sequelize('books').update({'status': 'archived'})", + { + code: "knex('books').update({'status': 'archived'})", + settings: { + knex: { + rule: { "avoid-updating-all-rows": { tablesToIgnore: ["books"] } }, + }, + }, + }], + invalid: [ + invalidCase("knex('books').update({'status': 'archived'})", [ + { messageId: "avoid" }, + ]), + invalidCase("knex('books').update({'status': 'archived'})", [ + { messageId: "avoid" }], + { + settings: { + knex: { + rule: { "avoid-updating-all-rows": { tablesToIgnore: ["author"] } }, + }, + }, + }, + ), + + ], +});