npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@rfjs/sql-filter

v0.1.0

Published

Generic boolean filter-group to SQL builder with pluggable leaf renderers (built-in column leaf)

Readme

@rfjs/sql-filter

English → README.md

通用的布林 filter-group → 參數化 SQL 產生器,搭配可插拔的 leaf 渲染器。它負責樹與邏輯(and/or/nor/not,任意巢狀),把每個 leaf 交給你提供的渲染器 —— 也就是它懂「怎麼組合條件」,不懂「條件是什麼意思」。內建一個 column 渲染器,對宣告過的欄位白名單產生 PostgreSQL WHERE / ORDER BY。零執行期相依。

這是底層核心;@rfjs/pg-filter 的欄位端就是建構在它之上。


安裝

npm i @rfjs/sql-filter

兩層

 FilterGroup<L>  ──buildFilterGroup(group, renderLeaf, params)──▶  "a=$1 and (b=$2 or c=$3)"
   (樹 + 邏輯)         每個 leaf L 都交給「你的」renderLeaf
        │
        └─ 內建 column 層:buildColumnQuery(config, group) ──▶ { where, values }
                 leaf 是 { column, operator, value },依欄位白名單 + 型別表安全渲染

1. 通用核心 —— 自帶 leaf 渲染器

import { buildFilterGroup, ParamBuilder, type FilterGroup } from "@rfjs/sql-filter";

type Leaf = { col: string; val: unknown };
const group: FilterGroup<Leaf> = {
  logic: "and",
  filters: [{ col: "a", val: 1 }, { logic: "or", filters: [{ col: "b", val: 2 }, { col: "c", val: 3 }] }],
};

const params = new ParamBuilder();
const where = buildFilterGroup(group, (leaf, p) => `${leaf.col} = ${p.add(leaf.val)}`, params);
// where  → "a = $1 and (b = $2 or c = $3)"
// params.values → [1, 2, 3]

ParamBuilder.add(value) 回傳下一個 $N 佔位並累積該值 —— 所以輸出永遠是參數化的(不會把值字串拼接進 SQL)。

2. 內建 column 層

import { buildColumnQuery, type ColumnConfig } from "@rfjs/sql-filter";

const config: ColumnConfig = {
  name: { column: "name", type: "text" },
  createdAt: { column: "created_at", type: "timestamp" },
};

const { where, values } = buildColumnQuery(config, {
  logic: "and",
  filters: [
    { column: "name", operator: "contains", value: "sales" },
    { column: "createdAt", operator: "gte", value: "2026-01-01" },
  ],
});
// where  → "\"name\" like '%' || $1 || '%' escape '\\' and \"created_at\" >= $2"
// values → ["sales", "2026-01-01"]

buildColumnOrderBy(config, sorts) 用同樣方式產生參數化的 ORDER BY

Column operator 與型別

column 層是純量介面,但不僅限於單值相等:除了 eq/neq/比較運算子之外,對支援的型別它也會產生 IN-list 的 = ANY(terms)與 range 的 BETWEEN(range)。operator 會依欄位宣告的 type 驗證:

| ColumnType | 允許的 ColumnOperator | |--------------|-------------------------| | text | eq neq isnull isnotnull contains startswith endswith icontains istartswith iendswith ieq ineq terms gt gte lt lte | | numeric / timestamp | eq neq isnull isnotnull gt gte lt lte terms range | | uuid | eq neq isnull isnotnull terms | | boolean | eq neq isnull isnotnull |

contains/startswith/endswith區分大小寫的子字串/前綴/後綴比對(LIKE,並會跳脫 %/_/\,讓詞彙逐字比對而非當成萬用字元)。要不分大小寫請用 iX 家族:icontains/istartswith/iendswith(ILIKE,同樣的跳脫)與 ieq/ineq(lower(欄位) = / <> lower($n))。terms 接受非空陣列,產生 = ANY($n)——整個陣列會綁定成單一參數,不是每個元素一個參數。range 接受 [lo, hi] 兩個值,產生 BETWEEN $n AND $n+1

值都是單一值,除了 terms(陣列)與 range(兩個值);isnull/isnotnull 不帶值。未知欄位或型別不允許的 operator 會丟 ColumnQueryError(UNKNOWN_COLUMN / UNSUPPORTED_OPERATOR)。

跨引擎的 operator 全貌(哪個引擎有 terms/range 等)請見 @rfjs/filter-builder 的矩陣。

公開 API

  • enginebuildFilterGroup(group, renderLeaf, params)
  • param-builderParamBuilder(add(value) → "$N".values)
  • columnbuildColumnQuerybuildColumnOrderByColumnConfigColumnConditionColumnOperatorColumnTypeColumnSortSpec
  • typesFilterGroup<L>LogicalOperator
  • errorsColumnQueryError(code:UNKNOWN_COLUMN | UNSUPPORTED_OPERATOR | INVALID_PARAM_OFFSET)

相關套件

設計筆記:docs/superpowers/specs/2026-06-15-sql-filter-design.md