ESLint Plugin for Safe Kysely Operations

raw JSON →
1.0.1 verified Thu Apr 23 auth: no javascript

eslint-plugin-safe-kysely is an ESLint plugin designed to improve data safety in applications utilizing the Kysely query builder. Currently at version 1.0.1, this plugin enforces the inclusion of a `where` clause in all `updateTable` and `deleteFrom` Kysely call chains. Its primary goal is to prevent accidental mass data modification or deletion of entire tables by requiring explicit targeting of rows for such operations. Unlike runtime checks, this plugin performs static analysis during development, providing immediate feedback through ESLint warnings or errors before code is deployed. This ensures that potentially destructive database queries are identified and corrected early in the development lifecycle, significantly reducing the risk of data loss. While a specific release cadence is not yet established for this relatively new plugin, its initial stable release indicates a commitment to Kysely ecosystem safety. It differentiates itself by offering Kysely-specific static analysis for a critical aspect of database interaction.

error ESLint: Definition for rule 'safe-kysely/enforce-where-clause' was not found
cause The `eslint-plugin-safe-kysely` package is not installed, or it's not listed in the `plugins` array of your ESLint configuration.
fix
Run npm install eslint-plugin-safe-kysely --save-dev and ensure "safe-kysely" is added to the plugins array in your .eslintrc.json or .eslintrc.js file.
error Missing `where` clause with updateTable (or Missing `where` clause with deleteFrom)
cause An `updateTable` or `deleteFrom` operation is attempted without a subsequent `.where()` call in the Kysely query builder chain.
fix
Add a .where() method call to your Kysely query chain to specify the rows to be affected, e.g., .where('id', '=', 1) or .where({ foo: 'bar' }).
gotcha Forgetting to add `safe-kysely` to the `plugins` array in your ESLint configuration will prevent the rule from being recognized or applied.
fix Ensure `"safe-kysely"` is included in the `plugins` array in your `.eslintrc.json` or `.eslintrc.js` file.
gotcha When enabling rules from `eslint-plugin-safe-kysely`, you must prefix the rule name with `safe-kysely/`. Omitting this prefix (e.g., just `enforce-where-clause`) will result in ESLint not finding the rule.
fix Always use the full rule identifier, such as `"safe-kysely/enforce-where-clause": "error"`.
gotcha This plugin specifically targets `updateTable` and `deleteFrom` methods for `where` clause enforcement. It does not provide checks for other potentially unsafe Kysely operations, such as raw SQL queries or complex builder patterns outside of its defined scope.
fix Supplement this plugin with manual code reviews or additional static analysis tools for comprehensive database query safety beyond `updateTable` and `deleteFrom`.
npm install eslint-plugin-safe-kysely
yarn add eslint-plugin-safe-kysely
pnpm add eslint-plugin-safe-kysely

Demonstrates the installation of the plugin, ESLint configuration to enable the rule, and a Kysely update operation that correctly includes a `where` clause, satisfying the `enforce-where-clause` rule.

npm install eslint --save-dev
npm install eslint-plugin-safe-kysely --save-dev

# .eslintrc.json
{
  "env": {
    "node": true,
    "es2021": true
  },
  "extends": [
    "eslint:recommended"
  ],
  "parserOptions": {
    "ecmaVersion": "latest",
    "sourceType": "module"
  },
  "plugins": [
    "safe-kysely"
  ],
  "rules": {
    "safe-kysely/enforce-where-clause": "error"
  }
}

// example.ts (assuming Kysely and database client setup)
import { Kysely, PostgresDialect } from 'kysely';
import { Pool } from 'pg';

interface Database {
  person: {
    id: string;
    first_name: string;
    last_name: string;
    age: number;
  };
}

const db = new Kysely<Database>({
  dialect: new PostgresDialect({
    pool: new Pool({
      connectionString: process.env.DATABASE_URL ?? 'postgresql://user:password@host:port/database',
    }),
  }),
});

async function updatePersonAge(id: string, newAge: number) {
  // This operation is valid as it includes a .where() clause
  await db
    .updateTable('person')
    .set({ age: newAge })
    .where('id', '=', id)
    .execute();
  console.log(`Person ${id} age updated to ${newAge}.`);
}

// Example of an invalid operation (would be flagged by ESLint)
// await db.updateTable('person').set({ age: 0 }).execute(); 

updatePersonAge('123', 30);