
数据库后端【免费下载链接】convex-backendThe open-source reactive database for app developers项目地址https://gitcode.com/gh_mirrors/co/convex-backend点击查看免费下载导读本文围绕npm-packages/private-demos/pagination-visualization/convex/README.md展开它是 Convex 项目中每个convex/函数目录的标准引导文档告诉你如何编写带参数校验的 query 查询函数与 mutation 变更函数、如何把函数引用到 React 组件中使用以及如何用 Convex CLI 推送函数到部署环境。我们将以这份引导文档为主体结合pagination-visualization演示项目的真实源码与convexnpm 包中的usePaginatedQuery实现讲透 query/mutation 的完整写法、_generated类型生成机制以及在此基础上进阶的分页查询原理。读完本文你将能独立编写、校验、调用和部署自己的 Convex 后端函数。一、convex/函数目录与引导文档的定位在 Convex 项目中你的所有后端函数都集中放在根目录下的convex/文件夹里。pagination-visualization演示项目的目录结构为npm-packages/private-demos/pagination-visualization/ ├── convex/ # 后端函数目录 │ ├── _generated/ # CLI 自动生成的类型与 API 引用 │ ├── README.md # 本文所依据的引导文档 │ ├── names.ts # 真实的 query/mutation 函数 │ └── schema.ts # 可选的数据库 schema 定义 ├── src/ # 前端 React 代码 │ ├── App.tsx # 分页可视化界面 │ └── main.tsx └── package.json # 依赖与启动脚本README.md的第一行 Welcome to your Convex functions directory! 明确点出了它的身份——这是脚手架生成的标准引导页告诉新项目开发者在哪里写函数convex/目录内的任意.ts文件query 和 mutation 分别长什么样、怎么在 React 里调用如何用 CLI 把函数部署到远端。它提到的两处官方文档入口docs.convex.dev/functions、docs.convex.dev/database/reading-data对应着本仓库中 convex 包 等源码注释里反复引用的同名文档。也就是说这份 README 是整个函数开发流程的目录页而本仓库里的源码则是它背后完整的实现。二、Query 函数从定义到 React 调用2.1 带参数校验的 query 定义README 给出的标准 query 模板如下原文完整继承// convex/myFunctions.ts import { query } from ./_generated/server; import { v } from convex/values; export const myQueryFunction query({ // Validators for arguments. args: { first: v.number(), second: v.string(), }, // Function implementation. handler: async (ctx, args) { // Read the database as many times as you need here. const documents await ctx.db.query(tablename).collect(); // Arguments passed from the client are properties of the args object. console.log(args.first, args.second); // Write arbitrary JavaScript here: filter, aggregate, build derived data, // remove non-public properties, or create new objects. return documents; }, });这里有几个值得展开的要点1query来自./_generated/server而不是从convex包直接导入。_generated/目录由 Convex CLI 自动生成它在编译期把你的函数与类型系统连接起来。该演示项目的 convex/_generated/server.d.ts 就是生成产物之一你可以打开查看其中的query、mutation类型签名。2args中的 Validator 是参数校验器。v.number()、v.string()来自convex/values用于在运行时校验客户端传入的参数。README 注释里说Validators for arguments——如果客户端传入的类型不匹配函数会直接拒绝执行并返回错误。这是 Convex 相比普通 JS 后端的显著差异参数契约在函数定义处就强制执行。在 npm-packages/convex/src/values 中可以看到完整的校验器体系包括v.id()、v.array()、v.union()、v.optional()等。3handler的第一个参数ctx是执行上下文。通过ctx.db可以查询数据库。ctx.db.query(tablename).collect()返回表中全部文档README 注释特别说明Read the database as many times as you need here——即 handler 内可以自由多次读取数据库。2.2 在 React 组件中使用 queryREADME 给出了对应的 React 端用法const data useQuery(api.myFunctions.myQueryFunction, { first: 10, second: hello, });要点是useQuery的第一个参数不是字符串函数名而是api.myFunctions.myQueryFunction——这个api对象同样来自./_generated/api如演示项目中的 convex/_generated/api.ts它提供全类型安全的函数引用函数名拼错、参数类型不匹配都会在编译期报错。useQuery是响应式的当first、second对应的查询结果在服务端发生变化时组件会自动重新渲染拿到最新数据无需手动刷新。三、Mutation 函数写入数据库的正确姿势3.1 标准 mutation 模板README 给出的 mutation 模板原文完整继承// convex/myFunctions.ts import { mutation } from ./_generated/server; import { v } from convex/values; export const myMutationFunction mutation({ // Validators for arguments. args: { first: v.string(), second: v.string(), }, // Function implementation. handler: async (ctx, args) { // Insert or modify documents in the database here. // Mutations can also read from the database like queries. const message { body: args.first, author: args.second }; const id await ctx.db.insert(messages, message); // Optionally, return a value from your mutation. return await ctx.db.get(messages, id); }, });与 query 的关键差异mutation 用于写入数据ctx.db.insert插入文档、ctx.db.delete删除文档同时 mutation 内也可以像 query 一样读取数据库README 注释明示 Mutations can also read from the database like queriesmutation 的 handler 执行在事务中要么全部生效要么全部回滚mutation 可以返回一个值上例返回刚插入的文档也可以什么都不返回。3.2 在 React 中调用 mutationREADME 给出的两种调用方式const mutation useMutation(api.myFunctions.myMutationFunction); function handleButtonPress() { // fire and forget, the most common way to use mutations mutation({ first: Hello!, second: me }); // OR // use the result once the mutation has completed mutation({ first: Hello!, second: me }).then((result) console.log(result), ); }两种方式的取舍在 README 注释里说得很清楚fire and forget直接调用不等待最常见的方式适用于不需要关心结果的场景如记录一次点击等待完成.then(...)获取返回值当 UI 需要依赖 mutation 的执行结果如展示新文档 ID、跳转页面时使用。注意useMutation返回的mutation本身就是一个可调用函数它的签名与后端myMutationFunction的args严格对应。四、进阶示例pagination-visualization 如何落地这些模板引导文档教你写第一个 query/mutation而演示项目则把它们用到了真实场景。查看 convex/names.ts可以看到模板的实战变形4.1 一个真正的 query带索引的分页查询export const getPeople query({ args: { paginationOpts: paginationOptsValidator, }, handler: async ({ db }, { paginationOpts }) { return await db .query(people) .withIndex(by_name) .paginate(paginationOpts); }, });与引导模板相比这里出现了三个新概念paginationOptsValidator来自convex/server分页参数校验器定义在 npm-packages/convex/src/server/pagination.ts结构为{ numItems, cursor, endCursor?, id?, maximumRowsRead?, maximumBytesRead? }.withIndex(by_name)按 convex/schema.ts 中声明的people表索引查询export default defineSchema({ people: defineTable({ name: v.string(), }).index(by_name, [name]), });schema 文件是可选的README 注释 The schema is entirely optional. You can delete this file and the app will continue to work.它的价值在于提供更精确的 TypeScript 类型并声明查询索引.paginate(paginationOpts)服务端分页 API。它的底层实现会发起1.0/queryPage异步系统调用携带cursor、endCursor、pageSize、maximumRowsRead、maximumBytesRead等参数见 query_impl.ts。4.2 一组真正的 mutationseed / addPerson / deletePersonexport const seed mutation({ args: { names: v.array(v.string()) }, handler: async ({ db }, { names }) { // Remove all existing rows for await (const row of db.query(people)) { await db.delete(row._id); } for (const name of names) { await db.insert(people, { name }); } }, }); export const addPerson mutation({ args: { name: v.string() }, handler: async ({ db }, { name }) { await db.insert(people, { name }); }, }); export const deletePerson mutation({ args: { id: v.id(people) }, handler: async ({ db }, { id }) { await db.delete(id); }, });这三个 mutation 演示了引导模板之外的能力v.array(v.string())表示参数是字符串数组v.id(people)表示参数必须是people表的合法文档 ID类型校验直接与 schema 关联在 mutation 中用for await遍历并删除全部旧数据实现了先清空再灌入的 seed 逻辑——这正是引导文档所说mutation 内也可以读取数据库的实际应用。在 src/App.tsx 中它们通过useMutation(api.names.addPerson)、useMutation(api.names.deletePerson)、useMutation(api.names.seed)接入 UI点击 Seed 按钮会随机抽取 20 个名字灌入数据库。五、深入分页引导模板之外的完整链路pagination-visualization的核心价值是把分页过程中每一页到底发生了什么可视化出来。这需要理解前端 hook 与服务端 API 的配合。5.1 客户端usePaginatedQuery与usePaginatedQueryInternal前端核心代码在 src/App.tsxconst { user: { results, status, loadMore }, internal, } usePaginatedQueryInternal( api.names.getPeople, {}, { initialNumItems: 5, [includePage]: true }, );这里用到的是convex/react导出的内部版本usePaginatedQueryInternalusePaginatedQuery的底层实现见 use_paginated_query.ts。普通项目用公开的usePaginatedQuery即可const { results, status, isLoading, loadMore } usePaginatedQuery( api.messages.list, { channel: #general }, { initialNumItems: 5 }, );usePaginatedQuery会做三件事注入分页参数自动在 args 里加上paginationOpts: { numItems, cursor, id }其中cursor: null表示从第一页开始见源码 L231-L237拼接所有页把已加载的每一页page结果拼成一个完整列表results管理状态机返回statusLoadingFirstPage/CanLoadMore/LoadingMore/Exhausted和loadMore(n)回调。5.2 分页状态机与异常恢复从 use_paginated_query.ts 的状态构造逻辑可以看到完整的状态定义statusisLoading含义loadMore 行为LoadingFirstPagetrue正在加载第一页noopCanLoadMorefalse还有更多数据可加载发起下一页请求LoadingMoretrue正在加载后续页noopExhaustedfalse已到列表末尾noopError内部版本false查询出错noop另外当服务端返回InvalidCursor错误时例如分页所依赖的数据在读取过程中发生了变化hook 会主动重置分页状态从头开始见源码 L290-L310并在 logger 中打印警告。每个分页会话还会携带一个自增的paginationId作为 cache-buster保证新会话不会错误复用旧的订阅结果见 L452-L480。5.3 服务端PaginationResult与页面拆分服务端.paginate()的返回结构PaginationResult定义在 pagination.tsinterface PaginationResultT { page: T[]; // 本页结果 isDone: boolean; // 是否已到末尾 continueCursor: Cursor; // 下一页的游标 splitCursor?: Cursor | null; // 拆分本页为两半的游标 pageStatus?: SplitRecommended | SplitRequired | null; }其中pageStatus是响应式分页的进阶机制当一页读取的数据量过大时服务端可能返回SplitRecommended建议拆分甚至SplitRequired页面可能不完整必须拆分。客户端检测到这些信号后会调用splitQuery把这一页拆成(cursor, splitCursor]和(splitCursor, continueCursor]两个半页并行加载见 L60-L96。pagination-visualization的 App.tsx 正是把这些页面的边界、每个分页参数numItems、cursor、endCursor、id等逐条渲染出来并用颜色标记游标让你直观看到响应式数据变化时分页如何自动调整——这是理解endCursor参数作用确保数据变化时页面之间不出现空隙见 pagination.ts的最佳实验场。六、用 Convex CLI 推送与运行README 的最后一段说明了 CLI 的使用方式Use the Convex CLI to push your functions to a deployment. See everything the Convex CLI can do by runningnpx convex -hin your project root directory. To learn more, launch the docs withnpx convex docs.在pagination-visualization项目中实际运行npx convex dev --start vite --open这是 package.json 中定义的dev脚本convex dev会持续监听convex/目录把函数同步到本地开发部署并自动生成_generated/文件--start vite --open则同时启动 Vite 开发服务器并打开浏览器。常用 CLI 命令速查命令作用npx convex -h查看全部 CLI 命令npx convex docs在本地启动官方文档npx convex dev本地开发监听函数变更、同步部署、生成_generatednpx convex dev --once单次同步后退出CI 场景常用npx convex deploy推送函数到生产部署README 特别提示要在project root directory项目根目录运行这些命令——因为 CLI 需要读取根目录下的convex.json与package.json来确定项目配置。七、快速上手清单结合引导文档与演示项目一个完整的新手路径如下初始化项目创建convex/目录放入README.md脚手架会生成与函数文件定义 schema可选在 convex/schema.ts 中用defineSchema/defineTable声明表和索引编写函数query 用query({ args: {...}, handler })写入用mutation({...})参数一律用v校验器声明跑一次 CLInpx convex dev生成_generated/此后 import./_generated/server、../convex/_generated/api均获得类型安全接入前端useQuery(api.xxx, args)读、useMutation(api.xxx)写列表加载用usePaginatedQuery配合initialNumItems与loadMore验证效果对照pagination-visualization的可视化界面loadMore(5)、Seed 按钮、页面边界渲染确认每个status的流转是否符合预期。结语convex/README.md虽然只是一份脚手架引导但它浓缩了 Convex 函数开发的全部核心动作用 Validator 声明参数契约、用ctx.db读写数据、用_generated获得类型安全、用 CLI 完成部署。在此基础上pagination-visualization演示项目把 query/mutation 模板延展成了带索引、带分页、带响应式可视化的完整应用而 use_paginated_query.ts 与 pagination.ts 则揭示了游标、页面拆分与状态机背后的实现细节。从模板到实战再到源码级原理这条路径正是理解 Convex 后端开发的最佳入口。赞分享数据库后端【免费下载链接】convex-backendThe open-source reactive database for app developers项目地址https://gitcode.com/gh_mirrors/co/convex-backend点击查看免费下载相关推荐Convex 函数目录开发指南从零编写 Convex query 与 mutation 函数convex-backend 实战Convex 函数目录开发指南从零编写 Convex query 与 mutation 函数convex backend 实战 本指南以 convex b数据库后端Convex Backend 函数开发入门从 Query 到 Mutation 的类型安全实战指南Convex Backend 函数开发入门从 Query 到 Mutation 的类型安全实战指南 Convex 是一个面向应用开发者的开源响应式数据库其核数据库后端Convex 函数目录入门指南从 Query 到 Mutation 的完整开发实战Convex 函数目录入门指南从 Query 到 Mutation 的完整开发实战 本文以 convex backend 仓库中 tour chat 教程项目数据库后端创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考