biome-plugin-drizzle
v0.1.0
Published
Biome linter plugin for Drizzle ORM safety rules - enforces .where() clauses on delete and update operations
Readme
biome-plugin-drizzle
Biome linter plugin for Drizzle ORM safety rules. Enforces .where() clauses on delete and update operations to prevent accidental data loss.
This plugin is a port of eslint-plugin-drizzle for the Biome toolchain.
Features
- enforce-delete-with-where: Catches
.delete()calls without.where()that would delete all rows - enforce-update-with-where: Catches
.update().set()calls without.where()that would update all rows - Object name filtering: Optionally restrict rules to specific Drizzle object names (e.g.,
db,tx) - CLI generator: Generate customized plugin configurations
Installation
npm install -D biome-plugin-drizzle @biomejs/biomeQuick Setup
Option 1: Using the CLI (Recommended)
# Initialize with default settings (broad matching)
npx biome-plugin-drizzle init
# Or initialize with object name filtering (reduces false positives)
npx biome-plugin-drizzle init --object-names db,txOption 2: Manual Configuration
Add the plugin to your biome.json:
{
"$schema": "https://biomejs.dev/schemas/2.0.0/schema.json",
"plugins": ["./node_modules/biome-plugin-drizzle/dist/drizzle.grit"],
"linter": {
"enabled": true
}
}Note: This plugin requires Biome 2.0.0 or later, which introduced support for GritQL plugins.
Then run Biome:
npx biome lint .Configuration
Default Plugin (Broad Matching)
The default plugin matches any .delete() or .update().set() call, which may cause false positives if you have other classes with similar method names.
{
"plugins": ["./node_modules/biome-plugin-drizzle/dist/drizzle.grit"]
}Generated Plugin (Object Name Filtering)
To reduce false positives, generate a customized plugin that only matches specific object names:
# Generate a plugin that only matches 'db' and 'tx' objects
npx biome-plugin-drizzle generate --out ./.biome/drizzle.grit --object-names db,txThen update your biome.json:
{
"plugins": ["./.biome/drizzle.grit"]
}This is equivalent to the ESLint plugin's drizzleObjectName option:
// ESLint equivalent
{
"drizzle/enforce-delete-with-where": ["error", { "drizzleObjectName": ["db", "tx"] }]
}Rules
drizzle/enforce-delete-with-where
Ensures all .delete() operations include a .where() clause to prevent accidental deletion of entire tables.
Failing Examples
// Will delete ALL rows in the users table!
db.delete(users);
// Still deletes all rows (returning doesn't add safety)
db.delete(users).returning();
// Async operations without where
await db.delete(posts);Passing Examples
// Safe: has where clause
db.delete(users).where(eq(users.id, 1));
// Safe: where can be anywhere in the chain
db.delete(users).returning().where(eq(users.id, 1));
// Safe: with CTEs
db.with(someCte).delete(users).where(eq(users.id, 1));drizzle/enforce-update-with-where
Ensures all .update().set() operations include a .where() clause to prevent accidental updates to entire tables.
Failing Examples
// Will update ALL rows in the users table!
db.update(users).set({ name: "John" });
// Still updates all rows
db.update(users).set({ status: "active" }).returning();
// Async operations without where
await db.update(posts).set({ views: 0 });Passing Examples
// Safe: has where clause
db.update(users).set({ name: "John" }).where(eq(users.id, 1));
// Safe: where can be anywhere in the chain
db.update(users).set({ email: "[email protected]" }).returning().where(eq(users.id, 1));
// Safe: complex conditions
db.update(users)
.set({ verified: true })
.where(and(eq(users.status, "pending"), gt(users.age, 18)));CLI Reference
init
Initialize biome-plugin-drizzle in your project.
npx biome-plugin-drizzle init [options]Options:
-c, --config <path>: Path to biome.json (default:./biome.json)--object-names <names>: Comma-separated list of Drizzle object names--out <path>: Output path for generated .grit file (default:./.biome/drizzle.grit)
generate
Generate a customized .grit plugin file.
npx biome-plugin-drizzle generate --out <path> [options]Options:
-o, --out <path>: Output path for the generated .grit file (required)--object-names <names>: Comma-separated list of Drizzle object names--no-delete-rule: Exclude the enforce-delete-with-where rule--no-update-rule: Exclude the enforce-update-with-where rule
print-path
Print the path to the installed default plugin.
npx biome-plugin-drizzle print-path [--absolute]Options:
--absolute: Print the absolute path instead of relative
Limitations
Biome Plugin System
- Biome linter plugins are currently GritQL-based and can only report diagnostics
- Unlike ESLint, Biome plugins cannot accept configuration options in
biome.json - Workaround: Use the CLI generator to create customized plugins with object name filtering
Pattern Matching
- The plugin uses structural pattern matching, which may not catch all edge cases
- Complex dynamic code patterns may not be detected
- When in doubt, add explicit
.where()clauses to your queries
How to Release
- Update version in
package.json - Update CHANGELOG if you have one
- Build and test:
npm run build npm test - Publish to npm:
npm publish
Contributing
Contributions are welcome! Please feel free to submit issues and pull requests.
License
MIT
Inspired by eslint-plugin-drizzle from the Drizzle Team.
