EverShop 数据层基石:@evershop/postgres-query-builder 查询构建器全面指南
电商后端前端【免费下载链接】evershop️ Typescript E-commerce Platform项目地址https://gitcode.com/GitHub_Trending/ev/evershop点击查看免费下载本指南围绕 EverShop 开源电商平台TypeScript 实现所依赖的独立数据库工具包evershop/postgres-query-builder展开完整讲解它的安装方式、链式查询 API、参数绑定与 SQL 注入防护机制、事务处理以及它在 EverShop 各业务模块中的真实落地用法。读完本文你将掌握如何用一套简洁的异步 API 完成 PostgreSQL 的增删改查、关联查询与事务控制并理解其全部用户数据经参数绑定转义的安全设计。包概述与安装evershop/postgres-query-builder是 EverShop 平台的数据访问层核心工具定位为一个用于 NodeJS 的 PostgreSQL 查询构建器见 packages/postgres-query-builder/README.md。它完整实现了 async/await 异步编程模型所有查询方法均返回 Promise可直接配合node-postgrespg包使用。在 package.json 中可以看到其工程形态包名evershop/postgres-query-builder当前版本2.1.0模块类型type: moduleESM主入口为编译后的dist/index.js运行时要求node 18.0.0依赖仅两个pg ^8.10.0与uniqid ^5.3.0后者用于生成绑定参数占位键许可证MIT安装方式npm install evershop/postgres-query-builder由于它依赖pg实际使用前你还需要准备好一个pg.Pool连接池实例例如const { Pool } require(pg); const pool new Pool({ host: localhost, port: 5432, user: evershop, password: your_password, database: evershop });基础查询SELECT 与简单 WHERE最简单的一次查询只涉及两个环节用select()指定字段用from()指定表然后execute(pool)执行const { select } require(evershop/postgres-query-builder); const products await select(*) .from(product) .where(product_id, , 1) .execute(pool);execute()返回的是查询结果的行数组rows可以直接遍历使用。where()接受三个参数字段名、操作符、值。支持标准 SQL 操作符、、、LIKE、IN等。追加更多条件时可以使用.and()const { select } require(evershop/postgres-query-builder); const products await select(*) .from(product) .where(product_id, , 1) .and(sku, LIKE, sku) .execute(pool);如果你需要OR条件可以直接在查询对象上继续链式调用orWhere()const { select } require(evershop/postgres-query-builder); const query select(*).from(product); query.where(product_id, , 1).and(sku, LIKE, sku); query.orWhere(price, , 100); const products await query.execute(pool);从源码实现看src/index.tsQuery类内部维护了一个_where的Where节点where/andWhere/orWhere都会以AND/OR作为链接符link挂载到条件树上。值得注意的细节是当_where树为空时andWhere/orWhere会退化为where避免生成无谓的AND/OR前缀条件渲染时第一个叶子会去掉自身的链接符最终输出形如WHERE (...)的规范 SQL。表关联JOIN 查询多表关联是电商查询的高频场景例如商品表关联价格表。构建器提供leftJoin、rightJoin、innerJoin三种方式通过.on()指定连接条件const { select } require(evershop/postgres-query-builder); const query select(*).from(product); query.leftJoin(price).on(product.product_id, , price.product_id); query.where(product_id, , 1).and(sku, LIKE, sku); query.andWhere(price, , 100); const products await query.execute(pool);源码中的Join类src/index.ts 的Join定义会为每个连接保存{ type, table, alias, on }元组其中on是一个以ON为链接符的独立条件节点渲染时拼接为LEFT JOIN price AS price ON ...。on()方法返回该条件节点因此你也可以在.on()之后继续链式追加AND/OR条件。若在未声明任何 join 的情况下调用.on()会抛出Invalid call错误。另外从SelectQuery的 API 可以看到 join 还支持别名leftJoin(product, p)并且 EverShop 内部专门为 COUNT 类查询提供了pruneUnreferencedLeftJoins()方法当某个 LEFT JOIN 在 SELECT、WHERE、GROUP BY、HAVING、ORDER BY 以及其它 JOIN 的 ON 子句中都没有被引用时会将其从 SQL 中剔除并清理其绑定参数避免 LEFT JOIN 带来的行数膨胀拖慢计数查询该优化注释中记录了对 30 万商品目录的实测效果。写操作INSERT、UPDATE、DELETE 与 UPSERTINSERTinsert(table).given(data)传入一个对象构建器只会把表中真实存在的列写入 SQL多余字段自动忽略const { insert } require(evershop/postgres-query-builder); const query insert(user) .given({ name: David, email: emailemail.com, phone: 123456, status: 1, notExistedColumn: This will not be a part of the query }); await query.execute(pool);UPDATEupdate(table).given(data).where(...)同样只更新存在的列并通过WHERE限定行const { update } require(evershop/postgres-query-builder); const query update(user) .given({ name: David, email: emailemail.com, phone: 123456, status: 1, notExistedColumn: This will not be a part of query }) .where(user_id, , 1); await query.execute(pool);写操作的底层机制INSERT/UPDATE 的实现有一个共同点它们在生成 SQL 之前会先通过information_schema.columns查询目标表的列元数据列名、数据类型、是否可空、是否自增等然后只挑选.given()中确实存在于表结构中的字段参与生成 SQL。这样notExistedColumn这类不存在的键会被静默过滤从根上杜绝了拼错列名导致运行时错误。另外一个实用行为是构建器会检测identity_generation为BY DEFAULT/ALWAYS的标识列作为主键执行 INSERT 后返回的单行对象会被附加insertId属性即主键值执行 UPDATE 后则附加updatedId。两条语句末尾都带有RETURNING *因此你能直接拿到写入后的完整行数据。DELETEdel()工厂函数生成删除语句const { del } require(evershop/postgres-query-builder); await del(user) .where(user_id, , 1) .execute(pool);从DeleteQuery的实现看SQL 由DELETE FROM table WHERE 片段拼接而成同样支持.and()/.or()链式条件。UPSERTinsertOnUpdate除了 README 展示的基础写操作源码中还提供了 README 未展开的insertOnUpdate()工厂函数用于实现 PostgreSQL 的INSERT ... ON CONFLICT (...) DO UPDATE SET ...语义。它要求第二个参数为冲突列数组且不能为空const { insertOnUpdate } require(evershop/postgres-query-builder); const query insertOnUpdate(product, [sku]) .given({ sku: SKU-001, name: Updated name, price: 100 }); await query.execute(pool);生成的 SQL 形如INSERT INTO product (...) VALUES (...) ON CONFLICT (sku) DO UPDATE SET name :..., price :... RETURNING *。该 API 在 EverShop 中广泛用于幂等写入场景例如 URL 重写记录的落库见 recordRedirect.ts。事务处理多步写操作需要保证原子性时可以使用包导出的连接管理与事务控制函数。流程是先从连接池取出独立连接显式BEGIN成功后COMMIT异常时ROLLBACKconst { Pool } require(pg); const { insert, getConnection, startTransaction, commit, rollback } require(evershop/postgres-query-builder); const pool new Pool(connectionSetting); // Create a connection from the pool const connection await getConnection(pool); // Start a transaction await startTransaction(connection); try { await insert(user) .given({ name: David, email: emailemail.com, phone: 123456, status: 1, notExistedColumn: This will not be a part of the query }) .execute(connection); await commit(connection); } catch (e) { await rollback(connection); }对应的实现位于 src/index.ts 的 Connection management functions 部分getConnection(pool)等价于pool.connect()从连接池取出一个独占连接startTransaction(connection)执行BEGIN并在连接对象上打上INTRANSACTION true标记commit(connection)执行COMMIT然后release(connection)归还连接rollback(connection)执行ROLLBACK并释放连接内部的release()会额外检查INTRANSACTION标记——事务未结束的连接不会被提前归还连接池这正是事务内多次execute(connection)能共享同一连接的原因。execute()的第二个参数releaseConnection默认true控制执行后是否自动释放连接在事务内应保持其默认行为不变事务本身会管理连接的归还。参数绑定与 SQL 注入防护README 的安全章节明确承诺所有用户提供的数据都会被转义All user provided data will be escaped。这一承诺通过**参数绑定parameterized query**机制实现而不是简单的字符串拼接。从 src/index.ts 的Query.execute()与SelectQuery.execute()实现可以看到完整链路每个值占位符都以uniqid()生成的随机键命名形如:xxxx值被收集进内部的_binding字典数组、对象等复合值由 toString.js 先做JSON.stringify序列化真正执行前构建器把:key逐一替换为pg驱动需要的$1, $2, ...位置参数并将值按序放入values数组最终通过connection.query({ text, values })交给node-postgres执行由数据库驱动完成转义与安全处理。因此用户输入永远不会以字面量形式拼进 SQL 文本这是该构建器防注入的核心保障。需要原样插入 SQL 表达式如函数、运算符或原始片段时包提供了sql()与value()两个辅助函数返回带有isSQL标记的SQLValue对象sql(NOW())会被当作合法 SQL 片段原样进入语句value(...)则强制按普通值处理。字段名解析规则见 fieldResolve.js普通字段会被包裹成字段表.字段形式会被解析为表.字段从而规避注入与命名冲突。进阶查询能力排序、分页、分组与单行加载SelectQuery还提供 README 未逐一展开但源码中完整实现的进阶能力const { select, sql } require(evershop/postgres-query-builder); const products await select(product_id, sku) .from(product) .where(status, , 1) .orderBy(created_at, DESC) // 排序默认 ASC .limit(0, 20) // limit(offset, limit) 分页 .groupBy(sku) // 分组 .having(COUNT(product_id), , 10) // 分组后过滤 .execute(pool);各能力要点orderBy(field, direction)第二参数默认ASC也可用orderDirection()单独设置方向limit(offset, limit)注意参数顺序是偏移量在前、条数在后渲染为LIMIT n OFFSET mgroupBy(...fields)接受可变参数字段经fieldResolve规范化having(field, operator, value)作用于分组结果load(connection)等价于limit(0, 1)后取第一行返回单行对象或null适合按主键取一条记录的场景见SelectQuery.load()实现clone()深度克隆整棵查询树含 WHERE、JOIN、ORDER BY 等便于在不影响原查询的前提下派生变体EverShop 的计数查询即基于此思路removeOrderBy()/removeGroupBy()/removeLimit()动态移除查询子句。SelectQuery.execute()还内置了两类容错逻辑当 PostgreSQL 返回42703未定义的列错误时自动移除ORDER BY后重试一次——兼容某些旧表缺少排序列的场景当返回22P02无效文本表示通常发生在对空结果集执行COUNT类聚合、类型转换异常时若 SELECT 列表含COUNT(...)则返回[{ count: 0 }]而非抛错保证分页接口总能拿到安全的计数结果。在 EverShop 项目中的实际应用该构建器并非孤立工具而是 EverShop 整个数据层的底座。EverShop 在其核心包内提供了类型安全封装层 packages/evershop/src/lib/postgres/query.ts在原生 API 之上叠加了 TypeScript 类型约束定义TableName联合类型覆盖product、order、customer、cart、url_rewrite、changeset等 50 张已知表并保留string回退以兼容自定义表通过RowOfT、ColumnOfT、AllPrefixedColumns映射类型实现表 → 行类型 → 列名的自动关联让.given()、.where()、.select()的字段参数获得自动补全与编译期校验提供TypedQueryChain、TypedInsertQuery、TypedUpdateQuery、TypedDeleteQuery、TypedInsertOnUpdateQuery、TypedJoin等链式接口并把select/insert/update/del/insertOnUpdate以及sql/value/getConnection/startTransaction/commit/rollback等全部重新导出。实际业务代码中的典型用法如 getCurrentUser.tsimport { select } from ../../../../lib/postgres/query.js; const currentAdminUser await select() .from(admin_user) .where(uuid, , adminUserUuid) .load(pool);数据库连接池则在 packages/evershop/src/lib/postgres/connection.ts 中统一构建通过DB_HOST/DB_PORT/DB_USER/DB_PASSWORD/DB_NAME等环境变量读取连接配置支持DB_SSLMODEdisable/require/prefer/verify-ca/verify-full/no-verify以及DB_SSLROOTCERT/DB_SSLCERT/DB_SSLKEY配置 SSL 证书链并在onConnect钩子中按店铺时区设置SET TIMEZONE。理解这套封装有助于你在自己的 NodeJS 项目中直接复用evershop/postgres-query-builder的完整能力。赞分享电商后端前端【免费下载链接】evershop️ Typescript E-commerce Platform项目地址https://gitcode.com/GitHub_Trending/ev/evershop点击查看免费下载相关推荐Vue Query Builder完全指南3分钟构建复杂数据查询界面Vue Query Builder完全指南3分钟构建复杂数据查询界面 Vue Query Builder是一个强大的Vue.js UI组件库专门用于构建包含前端UI组件使用 mcp-use 构建生产级 MCP 服务器从脚手架到工具、资源与 Widget 的完整实践指南使用 mcp use 构建生产级 MCP 服务器从脚手架到工具、资源与 Widget 的完整实践指南 导读 本文是 CopilotKit 仓库中 open m人工智能AI AgentAgent 框架前端后端Vue Query Builder实战指南轻松构建智能数据查询界面Vue Query Builder实战指南轻松构建智能数据查询界面 在当今数据驱动的时代如何让用户能够直观地构建复杂的数据查询条件成为了许多应用面临的挑战。前端UI组件上一篇Steam游戏库智能分类革命Depressurizer让你的游戏世界井然有序下一篇litellm 自定义提供商从0到1一个类接入任意 LLM创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

架构图里也能用品牌图标:3个theSVG品牌图标集成Mermaid、Draw.io与Excalidraw的技巧

架构图里也能用品牌图标:3个theSVG品牌图标集成Mermaid、Draw.io与Excalidraw的技巧

架构图里也能用品牌图标:3个theSVG品牌图标集成Mermaid、Draw.io与Excalidraw的技巧 【免费下载链接】thesvg 7,400 brand SVG icons for developers. Tree-shakeable, typed, open source. npm i thesvg 项目地址: https://gitcode.com/gh_mirrors/th/thesvg …

2026/10/2 17:08:33 阅读更多 →
Pi Agent 终端图片显示实战:TaoToken 统一 Key 接入与渲染验证

Pi Agent 终端图片显示实战:TaoToken 统一 Key 接入与渲染验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/2 17:07:33 阅读更多 →
c++ 11 的abi的介绍

c++ 11 的abi的介绍

C 中的 ABI 是什么? ABI 全称是 Application Binary Interface(应用程序二进制接口)。具体解释 C 的 ABI 是指编译器和链接器在编译阶段约定的一套底层规则,主要包括: 函数名修饰(Name Mangling&#xff09…

2026/10/2 17:07:33 阅读更多 →

最新新闻

基于Python机器学习的加密恶意流量检测平台实战

基于Python机器学习的加密恶意流量检测平台实战

简介:本资源为基于Python机器学习的加密恶意流量分析与检测平台完整项目包,面向计算机、自动化等专业学生及安全方向从业者,可用于毕业设计、课程大作业或期末课程设计,帮助解决加密恶意流量识别与可视化监测问题。压缩包共134个文…

2026/10/2 18:19:10 阅读更多 →
微信小程序AI健康问诊系统:从设计到上线全解析

微信小程序AI健康问诊系统:从设计到上线全解析

挂号排队两小时,问诊三分钟,这是很多人去医院的真实体验。也正是因为这个痛点,我决定做一个“微信小程序的AI健康问诊系统”,把日常健康评估、症状初步分析和健康建议这些事,搬到用户手机里。这篇文章我会把这套个人健…

2026/10/2 18:19:10 阅读更多 →
微信小程序AI健康问诊系统开发实战:从架构到落地的完整方案

微信小程序AI健康问诊系统开发实战:从架构到落地的完整方案

做医疗健康类小程序的朋友应该都有体会:用户一进来就问症状、找建议、要评估,但你一个个人开发者或者小团队,手里既没有医生资源,也没有成熟的知识库,很难凭人力撑起有质量的问答。我自己在做一个“微信小程序的AI健康…

2026/10/2 18:19:10 阅读更多 →
macOS下Git换行符警告CRLF/LF排查与.gitattributes规范化全攻略

macOS下Git换行符警告CRLF/LF排查与.gitattributes规范化全攻略

1. 先看warning到底在说什么:换行符差异的前因后果在 macOS 上跑git add或git commit时,突然冒出一句:warning: CRLF will be replaced by LF in src/main.py. The file will have its original line endings in your working directory.第一…

2026/10/2 18:19:10 阅读更多 →
Unreal引擎开发踩坑实录:渲染、物理与性能问题排查指南

Unreal引擎开发踩坑实录:渲染、物理与性能问题排查指南

在Unreal引擎里摸爬滚打了这几年,从4.22一路用到5.2,大大小小的坑踩了不少。有的问题查了两三天,最后发现就是某个勾选框没开;有的问题看着像是引擎Bug,翻源码才发现是自己资源命名不规范。这篇东西算是我个人的问题处…

2026/10/2 18:19:10 阅读更多 →
DeepSeek Harness实战:用Vibe Coding从零构建待办应用

DeepSeek Harness实战:用Vibe Coding从零构建待办应用

最近在技术群和社区里,看到越来越多朋友开始尝试 AI 辅助编程,也就是常说的 Vibe Coding。工具装了一堆,但很多人卡在同一个地方:不知道除了“让 AI 写一段代码”之外,怎么把这类工具真正嵌入到自己的开发流程里。尤其…

2026/10/2 18:18:10 阅读更多 →

日新闻

从零搭建AI工程化:模型之外的完整闭环

从零搭建AI工程化:模型之外的完整闭环

先搞清楚一件事:从零开始做 AI 工程化,难的从来不是调模型、写提示词,而是把一套原型 Demo 变成长得像是“正经系统”的东西。你手里可能已经有了能跑通的代码,也可能刚读完一些概念,但真到了要把它变成可维护、可观测…

2026/10/2 0:00:20 阅读更多 →
大模型训练显存估计与混合精度训练实战指南

大模型训练显存估计与混合精度训练实战指南

1. 大模型训练显存估计与混合精度训练详解显存不够用,几乎是每个做大模型训练的人都会撞上的第一堵墙。你可能也经历过:模型代码写完了,数据管道跑通了,满心欢喜地按下训练启动脚本,结果几秒钟后终端弹出一行红字——C…

2026/10/2 0:00:20 阅读更多 →
小样本学习数据集选型指南:27个真正可用的高质量数据集

小样本学习数据集选型指南:27个真正可用的高质量数据集

1. 小样本学习的“弹药库”:为什么你总在找数据集,却总找不到真正能用的? 小样本、数据集——这两个词最近半年在我处理的200多个AI项目咨询里,出现频率排进前三。不是模型调不好,不是代码写不对,而是卡在…

2026/10/2 0:00:20 阅读更多 →

周新闻

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解 【免费下载链接】spirula-studio Cross-vendor 3D Gaussian Splatting trainer - video to splat to mesh, Vulkan or CUDA. 项目地址: https://gitcode.com/GitHub_Trending/sp/spirula-studio Sp…

2026/10/1 19:40:48 阅读更多 →
SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南 模板网站太丑不够用?别急着加滤镜,那是治标不治本。很多老板盯着后台流量掉得眼红,却还在纠结首页Banner的圆角是不是3像素。这就像穿着西装去挖土,姿势不对,努力白费。我整理这份 速查手册…

2026/10/1 19:41:40 阅读更多 →
FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏

FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏

FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏 【免费下载链接】FireRed-OpenStoryline FireRed-OpenStoryline is an AI video editing agent that transforms manual editing into intention-driven directing through natural language …

2026/10/1 20:05:24 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/2 10:36:31 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/2 5:26:06 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/2 6:09:11 阅读更多 →