@chromav/frizzle

中文文档
0.4.6发布于 2026/10/23MITTypeScriptES Module零依赖近 30 天下载 7084

一个有趣的,类型安全的查询编译器,带有解析器-组合器语法,可插接代码生成器,以及内置验证. 过滤、 排序和查询您的数据 .

中文使用文档
文档目录28 节
  1. 安装
  2. 快速启动
  3. 过滤查询
  4. 过滤器 + 排序并进行计划验证
  5. SQL 构建器替代品( Drizzle)
  6. 在代码中构建过滤器, 验证一次
  7. 原始 SQL 目标
  8. 拦截管道
  9. 查询语法
  10. 过滤操作符
  11. 逻辑操作符
  12. 排序和标记
  13. 限制
  14. 处理错误
  15. 条目点
  16. 说明
  17. 参考截取器
  18. 查询拦截器
  19. 写入截取器
  20. SQL 目标
  21. 对话框接口
  22. 写入操作
  23. 建筑
  24. 文档
  25. 核心
  26. 数据库目标
  27. 指南
  28. 许可证

微风

一个类型安全查询编译器和服务层工具包. 解析URL-安全过滤字符串,编译为数据库查询(Drizzle ORM或生于SQL),并作曲截取器管道用于范围界定,软删除,以及审计线索——但投出零个例外.

?filter=status eq 'active' AND priority eq 'high'&sort=createdAt:desc&limit=50

安装

npm install @chromav/frizzle

Drizzle ORM是一种可选的对等依赖——只有在使用 Drizzle 代码生成器时才需要.

npm install drizzle-orm  # if using @chromav/frizzle/drizzle

对等范围是 >=0.30.0 || >=1.0.0-beta.1。 RQB compileFilter 需要细雨-orm 1.0(β/rc),因为它的输出使用v2关系-query对象过滤语法(OR, (中文(简体) ), AND, (中文(简体) ), RAW),而细雨-orm 0.x没有. compileFilterToSQL 财务报告和审定财务报表 @chromav/frizzle/sql 整个范围的工作.

快速启动

过滤查询

import { isSuccess } from "@chromav/frizzle";
import { compileFilter } from "@chromav/frizzle/drizzle";

const result = await compileFilter(
  "status eq 'active' and priority eq 'high'",
  { status: "status", priority: "priority" }
);

if (isSuccess(result)) {
  const tasks = await db.query.tasks.findMany({
    where: result.data,
  });
}

compileFilter 目标 Drizzle 的关系查询(db.query.*)和需要细雨1.0(β/弧);见 安装。要添加您自己的条件,请将两者包入 AND —— 说 { AND: [{ workspaceId }, result.data] } - 而不是传播 result.data,可以让用户过滤器替换您的密钥.

过滤器 + 排序并进行计划验证

import { isSuccess } from "@chromav/frizzle";
import { compileFilter, compileSort } from "@chromav/frizzle/drizzle";
import type { Schema } from "@chromav/frizzle";

const schema: Schema = {
  status: { type: "enum", enumValues: ["active", "pending", "done"] },
  priority: { type: "enum", enumValues: ["low", "medium", "high"] },
  title: { type: "string" },
  createdAt: { type: "date" },
};

const columns = {
  status: "status",
  priority: "priority",
  title: "title",
  createdAt: "createdAt",
};

// Validates field names, operators, and value types before compiling
const filterResult = await compileFilter(
  "status eq 'active' and title contains 'deploy'",
  columns,
  { schema }
);

const sortResult = compileSort("createdAt:desc", columns);

if (isSuccess(filterResult) && isSuccess(sortResult)) {
  const tasks = await db.query.tasks.findMany({
    where: filterResult.data,
    orderBy: sortResult.data,
  });
}

SQL 构建器替代品( Drizzle)

import { isSuccess } from "@chromav/frizzle";
import { compileFilterToSQL } from "@chromav/frizzle/drizzle";

// Pass Drizzle column objects instead of strings
const result = compileFilterToSQL("status eq 'active'", {
  status: tasks.status,
  priority: tasks.priority,
});

if (isSuccess(result)) {
  const rows = await db.select().from(tasks).where(result.data);
}

在代码中构建过滤器, 验证一次

有两个层次可以结合,每个层次都有自己的 and 编号 : or数字 :

你有过与实例
过滤树在汇编之前: parseFilter 返回,或从 f 建设者f.and, (中文(简体) ), f.or然后用简略的参数输入用户过滤器 validateFilter
对象,在编译后: compileFilter 输出、范围、描述过滤器andWhere, (中文(简体) ), orWhere和一个编译的用户过滤器 { workspaceId }

当可以时,更倾向于将树组合在一起:结果通过一个过滤器来验证(限制,计划).

import { f, isError, validateFilter } from "@chromav/frizzle";
import { generateDrizzleQuery } from "@chromav/frizzle/drizzle";

// f.and / f.or skip undefined, and group an or inside an and so the tree means what it says
const filter = f.and(
  userFilter,                                        // e.g. from parseFilter(params.filter)
  region ? f.in("region", region.split(",")) : undefined,
);

// Schema checks plus the limits (maxParameters etc.) on the combined tree.
// On an error, reject the request: running the query without the filter
// would also drop the region restriction.
const valid = filter ? validateFilter(filter, schema) : undefined;
if (valid && isError(valid)) {
  return badRequest(valid.error);
}

// One field map filters and sorts: `name` is filtered through a resolver, sorted by its column
const query = generateDrizzleQuery(
  { filter: valid?.data, sort: [{ field: "name", direction: "asc" }] },
  db.select().from(countries).$dynamic(),
  { region: countries.region, name: { column: countries.name, where: nameOrAlias } },
  { db }, // passed to resolvers as their third argument
);

见 Schema 验证 财务报告和审定财务报表 Drizzle 整合。 。 。 .

原始 SQL 目标

对于数据库 Drizzle 不覆盖(例如:Trino, Spark, Iceberg):

import { compileSelect } from "@chromav/frizzle/sql";
import { sqliteDialect } from "@chromav/frizzle/sql";

const columns = { status: "status", priority: "priority", createdAt: "created_at" };

const { sql, parameters } = compileSelect("tasks", {
  filter: { status: "active", priority: { gte: 3 } },
  sort: { createdAt: "desc" },
  take: 20,
}, columns, sqliteDialect);

// sql: SELECT * FROM "tasks" WHERE "status" = ? AND "priority" >= ? ORDER BY "created_at" DESC LIMIT ?
// parameters: ["active", 3, 20]

拦截管道

将贯穿各领域的关切编为可重复使用的拦截器:

import {
  scopeQueryInterceptor,
  softDeleteQueryInterceptor,
  scopeWriteInterceptor,
  softDeleteWriteInterceptor,
  injectWriteInterceptor,
} from "@chromav/frizzle";

// Read pipeline: every query is scoped to workspace + excludes deleted
const queryInterceptors = [
  scopeQueryInterceptor({ workspaceId: "ws-123" }),
  softDeleteQueryInterceptor(),
];

// Write pipeline: scope + audit + soft-delete transform
const writeInterceptors = [
  scopeWriteInterceptor({ workspaceId: "ws-123" }),
  injectWriteInterceptor("user-456"),
  softDeleteWriteInterceptor("user-456"),
];

查询语法

过滤操作符

运算符类别示例
eq, (中文(简体) ), ne比较status eq 'active'
gt, (中文(简体) ), gte, (中文(简体) ), lt, (中文(简体) ), lte比较age gte 18
like, (中文(简体) ), ilike字符串( 子字符串)name like 'john'
contains, (中文(简体) ), starts_with, (中文(简体) ), ends_with字符串title contains 'deploy'
in, (中文(简体) ), not_in阵列status in ['active', 'pending']
between范围age between [18, 65]
is_null, (中文(简体) ), is_not_null无效检查assignedTo is_null

符号别名也起作用 : =, (中文(简体) ), !=, (中文(简体) ), >, (中文(简体) ), >=, (中文(简体) ), <, (中文(简体) ), <=。 。 。 .

字符串运算符字面匹配值 : % 财务报告和审定财务报表 _ 普通字符,而不是通配符(title contains '50%' 找到文本 50%) (中文(简体) ).

逻辑操作符

status eq 'active' and priority eq 'high'
status eq 'active' or status eq 'pending'
(status eq 'active' or status eq 'pending') and priority eq 'high'

AND 绑定比 OR。父体优先.

排序和标记

sort=name:asc,createdAt:desc
limit=50
offset=100

排序方向必须是 asc 或者说 desc· ; limit 必须是从 1 到 1 的整数 maxLimit (默认 1000)和 offset 非负整数。 其他的都是个 INVALID_VALUE 错误.

限制

滤波器被封顶在32个等高的括号内(maxDepth),100个值(maxParameters,匹配 Cloudflare D1 的有限参数上限),和 1000 个比较(maxConditions) (中文(简体) ). 超越者返回 a LIMIT_EXCEEDED 错误。 超过每个电话,例如. compileFilter(expr, columns, { maxParameters: 50 })。见 限制。 。 。 .

处理错误

所有行动返回 Result<T> -没有例外.

import { isSuccess, isError } from "@chromav/frizzle";

const result = await compileFilter("bad ?? syntax", columns);

if (isError(result)) {
  result.error.message;     // "Expected operator, got '?'"
  result.error.position;    // 4
  result.error.code;        // "SYNTAX_ERROR"
  result.error.suggestions; // Possible fixes (e.g. close field names, for UNKNOWN_FIELD)
}

条目点

导入目录
@chromav/frizzle核心:编译器,解析器,AST类型,结果类型,计划类型,查询字符串解析器,描述器,截取器
@chromav/frizzle/drizzle滴入 ORM : compileFilter, (中文(简体) ), compileFilterToSQL, (中文(简体) ), compileSort, (中文(简体) ), DrizzleCodeGenerator
@chromav/frizzle/sql原始 SQL : compileSelect, (中文(简体) ), compileFilter, (中文(简体) ), compileFilterNode, (中文(简体) ), compileInsert, (中文(简体) ), compileUpdate, (中文(简体) ), compileDelete, (中文(简体) ), Dialect, (中文(简体) ), sqliteDialect

核心包的依赖性为零. @chromav/frizzle/drizzle 需求 drizzle-orm 作为同伴的依赖. @chromav/frizzle/sql 没有依赖关系.

说明

Frizzle在到达数据库适配器之前,使用通过拦截管流出的数据库不可知中间表示.

QueryDescriptor 描述读取操作:

import { mergeDescriptors } from "@chromav/frizzle";
import type { QueryDescriptor } from "@chromav/frizzle";

// A QueryDescriptor is a plain object; mergeDescriptors combines two
const base: QueryDescriptor = { filter: { workspaceId: "ws-1" } };
const descriptor = mergeDescriptors(base, {
  filter: { status: "active" },
  sort: { createdAt: "desc" },
  take: 20,
  skip: 0,
  select: { id: true, title: true, status: true },
  include: { assignee: true },
});

WriteDescriptor 描述一个写入操作:

import { createWriteDescriptor, mergeWriteDescriptor } from "@chromav/frizzle";

// Insert
const insert = createWriteDescriptor("insert", { title: "New task", status: "backlog" });

// Update
const update = mergeWriteDescriptor(
  createWriteDescriptor("update", { status: "done" }),
  { targetIds: ["task-1", "task-2"] },
);

// Delete
const remove = mergeWriteDescriptor(
  createWriteDescriptor("delete"),
  { targetIds: ["task-3"] },
);

参考截取器

共同事务层模式的可再使用实施。 全部从主出口 @chromav/frizzle 进入点.

查询拦截器

截取器说明
scopeQueryInterceptor(fields)在每个查询中添加租户/工作空间过滤器
softDeleteQueryInterceptor(config?)不包括被软删除的行isDeleted: false(中文(简体) )
defaultIncludesInterceptor(defaults)深层默认关系包括
extraScopeInterceptor(scopeFn)从工厂中添加特定实体过滤条件

写入截取器

截取器说明
scopeWriteInterceptor(fields)将范围值输入到每个写入中
softDeleteWriteInterceptor(userId, config?)变换删除 更新方式 isDeleted: true
injectWriteInterceptor(userId, config?)喷出 createdById 插入时, updatedById 更新
extraScopeWriteInterceptor(scopeFn)插入额外范围字段

所有截取器都是通用的(可配置的列名,通用范围字段)并只使用frizzle自己的类型——0外在依赖.

SQL 目标

这个 @chromav/frizzle/sql 出入口编译了参数化的SQL字符串的描述符. 它支持任何 SQL 数据库通过 Dialect 接口.

对话框接口

import type { Dialect } from "@chromav/frizzle/sql";

const trinoDialect: Dialect = {
  name: "trino",
  quoteIdentifier: (name) => `"${name}"`,
  parameter: (index) => `$${index + 1}`,
  booleanLiteral: (v) => v ? "TRUE" : "FALSE",
  supportsILike: true,
  escapeLikePattern: (p) => p.replace(/[%_\\]/g, "\\$&"),
};

写入操作

import { compileInsert, compileUpdate, compileDelete } from "@chromav/frizzle/sql";
import { createWriteDescriptor, mergeWriteDescriptor } from "@chromav/frizzle";
import { sqliteDialect } from "@chromav/frizzle/sql";

const insert = createWriteDescriptor("insert", { title: "Task", status: "backlog" });
const { sql, parameters } = compileInsert("tasks", insert, sqliteDialect);
// sql: INSERT INTO "tasks" ("title", "status") VALUES (?, ?)

const update = mergeWriteDescriptor(
  createWriteDescriptor("update", { status: "done" }),
  { targetIds: ["t-1"] },
);
const { sql, parameters } = compileUpdate("tasks", update, sqliteDialect);
// sql: UPDATE "tasks" SET "status" = ? WHERE "id" = ?

建筑

URL query string
    ↓ parseQueryString()
QueryDescriptor (database-agnostic IR)
    ↓ interceptor pipeline (scope, soft-delete, inject, ...)
QueryDescriptor (enriched)
    ↓ adapter
    ├── @chromav/frizzle/drizzle → Drizzle RQB findMany/findFirst
    └── @chromav/frizzle/sql     → parameterized SQL string

文档

核心

  • 开始 ——两种方法,结构概述,每个步骤产生什么
  • 说明 – 查询描述器和写入描述器作为数据库不可知的IRs
  • 截取器 ——管道概念,参考实施,自写
  • 查询语言 – 完整的语法参考,每个操作符都有示例
  • Schema 验证 – 字段类型,操作员相容性,运行时谜题
  • 处理错误 - 结果类型、错误代码、弹性模式
  • 查询谱 (EBNF) - 正式语法

数据库目标

指南

  • 食谱 – Express, Hono, Next.js, React Router 例 + filter UI 模式
  • URL 示例 — 50+ 真实世界 URL 查询模式

许可证

麻省理工学院

版本与发布记录

@chromav/frizzle 共发布 11 个版本,首次发布于 2026/08/25;过去 12 个月发布了 11 个版本。

版本发布日期距今
0.4.6latest2026/10/2317 天前
0.4.52026/10/1228 天前
0.4.42026/10/071 个月前
0.4.32026/10/061 个月前
0.4.22026/10/061 个月前
0.4.12026/10/051 个月前

关于 @chromav/frizzle 的常见问题

@chromav/frizzle 是什么?

一个有趣的,类型安全的查询编译器,带有解析器-组合器语法,可插接代码生成器,以及内置验证. 过滤、 排序和查询您的数据 .

如何安装 @chromav/frizzle?

在项目目录运行 npm install @chromav/frizzle,或使用 pnpm add / yarn add / bun add。

@chromav/frizzle 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@chromav/frizzle 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@chromav/frizzle 可以商用吗?

@chromav/frizzle 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@chromav/frizzle 的下载量有多少?

根据 npm 官方下载统计,@chromav/frizzle 在 2026/10/10 – 2026/11/08 这 30 天内被下载 7,084 次,日均约 236 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@chromav/frizzle 还在维护吗?

最新版本 0.4.6 发布于 2026/10/23(17 天前);至今共发布 11 个版本,其中过去 12 个月发布了 11 个;首次发布于 2026/08/25。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。