You're Invited:Meet the Socket Team at RSAC and BSidesSF 2026, March 23–26.RSVP
Socket
Book a DemoSign in
Socket

@filtron/sql

Package Overview
Dependencies
Maintainers
1
Versions
4
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@filtron/sql

Filtron helper: generate safe, parameterized SQL WHERE clauses from filter expressions

latest
Source
npmnpm
Version
1.2.1
Version published
Maintainers
1
Created
Source

@filtron/sql

Convert Filtron AST to parameterized SQL WHERE clauses.

npm version npm bundle size codecov

Installation

npm install @filtron/sql

Usage

import { parse } from "@filtron/core";
import { toSQL } from "@filtron/sql";

const result = parse('age > 18 AND status = "active"');

if (result.success) {
  const { sql, params } = toSQL(result.ast);
  // sql: "(age > $1 AND status = $2)"
  // params: [18, "active"]

  await db.query(`SELECT * FROM users WHERE ${sql}`, params);
}

API

toSQL(ast, options?): SQLResult

Converts a Filtron AST to a parameterized SQL WHERE clause.

Returns:

interface SQLResult {
  sql: string;      // The WHERE clause (without "WHERE" keyword)
  params: unknown[]; // Parameter values in order
}

Options

OptionTypeDefaultDescription
parameterStyle"numbered" | "question""numbered"Placeholder format
fieldMapper(field: string) => stringundefinedTransform field names to column names
valueMapper(value: unknown) => unknownundefinedTransform values before parameterization
startIndexnumber1Starting index for numbered placeholders

Parameter styles

Numbered ($1, $2, ...) — PostgreSQL, CockroachDB:

const { sql, params } = toSQL(ast);
// sql: "(age > $1 AND status = $2)"

Question marks (?, ?, ...) — MariaDB, SQLite, DuckDB:

const { sql, params } = toSQL(ast, {
  parameterStyle: "question",
});
// sql: "(age > ? AND status = ?)"

Examples

Custom field mapping:

const { sql, params } = toSQL(ast, {
  fieldMapper: (field) => `users.${field}`,
});
// "age > 18" becomes "users.age > $1"

Table-qualified columns:

const { sql, params } = toSQL(ast, {
  fieldMapper: (field) => `"${field}"`,  // Quote column names
});

Start index (for combining queries):

const { sql, params } = toSQL(ast, {
  startIndex: 3,
});
// Placeholders start at $3

LIKE helpers

Helper functions for the contains operator (~):

import { toSQL, contains, prefix, suffix, escapeLike } from "@filtron/sql";
FunctionInputOutputUse case
contains"foo""%foo%"Substring match
prefix"foo""foo%"Starts with
suffix"foo""%foo"Ends with
escapeLike"a%b""a\\%b"Escape special chars

Usage with valueMapper:

const { sql, params } = toSQL(ast, {
  valueMapper: contains,
});
// Query "name ~ 'john'" produces params: ["%john%"]

Performance

For APIs with repeated filter queries, cache parsed results to avoid redundant parsing:

const cache = new Map<string, SQLResult>();

function getFilterSQL(filter: string): SQLResult | null {
  const cached = cache.get(filter);
  if (cached) return cached;

  const result = parse(filter);
  if (!result.success) return null;

  const sql = toSQL(result.ast, { parameterStyle: "question" });
  cache.set(filter, sql);
  return sql;
}

Consider using an LRU cache with a size limit for production:

// https://github.com/isaacs/node-lru-cache
import { LRUCache } from "lru-cache";

const cache = new LRUCache<string, SQLResult>({ max: 1000 });

Caching is effective when:

  • Users frequently repeat the same filter queries
  • Filter expressions are complex (nested AND/OR conditions)

For simple queries or unique filters, caching overhead is not worthwhile.

Caching at the HTTP level (database query results) is often more effective than caching a parsed Filtron SQLResult. Database queries are typically orders of magnitude slower than processing the Filtron query.

Security

All queries are parameterized to prevent SQL injection:

// User input with SQL injection attempt
const result = parse('name = "admin\' OR \'1\'=\'1"');
const { sql, params } = toSQL(result.ast);

// sql: "(name = $1)"
// params: ["admin' OR '1'='1"]  — treated as literal string value

Never interpolate user input directly into SQL. Always use the params array with your database driver's parameterized query support.

License

MIT

Keywords

ast

FAQs

Package last updated on 02 Jan 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts