news 2026/9/24 11:14:48

使用 Prisma Bindings 从 Node 脚本访问 Prisma 服务

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
使用 Prisma Bindings 从 Node 脚本访问 Prisma 服务
  • 后端
  • 数据库
  • GraphQL

【免费下载链接】prisma1

💾 Database Tools incl. ORM, Migrations and Admin UI (Postgres, MySQL & MongoDB) [deprecated]

项目地址:https://gitcode.com/gh_mirrors/pr/prisma1
点击查看免费下载

本教程面向已拥有运行中 Prisma 服务的开发者,讲解如何在一个轻量 Node 脚本中,通过prisma-binding生成的类型化 API(即Prisma bindings)完成对 Prisma 服务的查询(query)、变更(mutation)与存在性检查(exists)等操作。读完本文,你将掌握从数据模型更新、项目目录搭建、GraphQL schema 下载,到编写并运行可复用的 Node 访问脚本的完整链路,并能理解 Prisma binding 底层如何基于 GraphQL schema 动态生成调用接口。

准备工作:你需要一个运行中的 Prisma 服务

本教程假设你已拥有一个可访问的 Prisma 服务,因此开始之前,请确保手里有该服务的endpoint(端点地址)。如果你还不清楚如何快速搭建自己的 Prisma 服务,可以参考仓库中以下教程(对应docs/1.13/03-Tutorials2/01-Setup-Prisma目录):

  • 在 Demo server 上设置 Prisma:使用 Prisma Cloud 托管的免费演示环境,适合学习、原型与开发,但存在限流与存储上限,不建议用于生产。
  • 使用新的 MySQL 数据库设置 Prisma
  • 使用新的 Postgres 数据库设置 Prisma
  • 连接你自己的空 MySQL 数据库设置 Prisma
  • 连接你自己的空 Postgres 数据库设置 Prisma

提示:教程中的每一步操作都带有编号标记,避免遗漏;如果你只关心操作步骤本身,可以直接按指令逐步执行。

Step 1:更新数据模型

首先确保你的 Prisma 服务具有本教程后续步骤所需的数据模型。本教程假定你的数据模型存放在单一文件datamodel.graphql中,如果实际布局不同,请相应调整。

操作 1:打开datamodel.graphql,将其内容更新为:

type User { id: ID! @unique name: String! posts: [Post!]! } type Post { id: ID! @unique title: String! content: String! published: Boolean! @default(value: "false") author: User! }

操作 2:保存文件后,打开终端并进入 Prisma 服务根目录(即prisma.yml所在目录),运行以下命令更新其 GraphQL API:

prisma deploy

更新后,Prisma 服务的 GraphQL API 将为UserPost两种类型暴露完整的 CRUD 操作,同时允许你修改二者之间的关系(relation):一个User拥有多条Postposts: [Post!]!),每条Post又必须归属一个Userauthor: User!)。

从源码看:prisma deploy之后发生了什么

prisma deploy会依据prisma.yml中的配置将数据模型同步到 Prisma 服务,并重新生成对应的 GraphQL API。这里值得一提的细节是@default(value: "false")指令——它让published字段在创建Post时自动获得默认值false,因此后续脚本创建文章时无需显式传入该字段。这一点在 Step 4 的示例输出中可以直接看到:createPost返回的对象里published: false,正是默认值起作用的证据。

Step 2:设置项目目录结构

数据模型更新完成后,开始搭建脚本项目。

操作 1:进入一个新目录,在终端中依次执行:

mkdir -p my-node-script/src touch my-node-script/src/index.js cd my-node-script yarn init -y

操作 2:接下来,把 Prisma 服务根目录移入my-node-script,并重命名为prisma

cd .. mkdir my-node-script/prisma mv datamodel.graphql prisma.yml my-node-script/prisma cd my-node-script

此时项目结构应如下所示:

. └── my-node-script ├── package.json ├── prisma │ ├── datamodel.graphql │ └── prisma.yml └── src └── index.js

操作 3:安装prisma-binding及 GraphQL 核心库:

yarn add prisma-binding graphql

prisma-binding是本教程的主角——它是从 Prisma schema 生成类型化 JavaScript API 的运行时库,graphql则提供底层 schema 解析与文档构建能力。从本仓库的 prisma-client-lib 包 源码可以看到,Prisma绑定实例在构造时会调用buildSchema(typeDefs)解析传入的 schema,并通过BatchedGraphQLClientSubscriptionClient分别建立查询/变更与订阅通道,这正是"绑定实例 = 面向 Prisma 服务的 JavaScript SDK"这一说法的实现基础。

Step 3:下载 Prisma database schema

下一步是把 Prisma GraphQL API 的 schema(即Prisma database schema)下载到本地项目,供 Prisma binding 指向使用。该操作借助 GraphQL CLI 与 GraphQL Config 完成。

操作 1:全局安装 GraphQL CLI:

yarn global add graphql-cli

操作 2:在my-node-script目录(服务根目录)创建.graphqlconfig.yml

touch .graphqlconfig.yml

操作 3:向其中写入以下内容,把 Prisma 的 GraphQL API 定义为一个project

projects: prisma: schemaPath: src/generated/prisma.graphql extensions: prisma: prisma/prisma.yml

此文件提供的信息会被 GraphQL CLI 以及 GraphQL Playground 共同使用:schemaPath指定下载后 schema 的落盘位置,extensions.prisma则指向你的prisma.yml,让 CLI 知道从哪里读取 endpoint 等连接信息。

操作 4:运行以下命令,将 Prisma database schema 下载到src/generated/prisma.graphql

graphql get-schema

下载完成后,定义了你数据库完整 CRUD API 的 Prisma database schema 就位于projects.prisma.schemaPath属性指定的位置(即src/generated/prisma.graphql)。

💡Pro tip:如果你希望每次部署(例如更新数据模型)后 schema 都自动刷新,可以在prisma.yml中添加如下post-deployment hookhooksprisma.yml中可选的配置项,用于在 Prisma CLI 特定动作前后执行终端命令,当前可用的是post-deploy(在prisma deploy之后触发),其类型为对象,键名与可用钩子一一对应。更完整的说明见 prisma.yml 配置参考:

hooks: post-deploy: - graphql get-schema -p prisma

仓库中 YAML-Structure.md 还给出了post-deploy同时执行多个任务的示例,例如打印部署完成信息、为dbproject 下载 schema、执行代码生成等,读者可自行参考扩展。

Step 4:使用 Prisma binding 发送查询与变更

本步骤将正式使用 Prisma binding 与你的 Prisma 服务通信。

首先,通过指向上一步下载的 schema 来实例化一个 Prisma binding;由于绑定实例需要连接到你的 Prisma API,因此还必须提供 Prisma API 的endpoint(该值可从prisma/prisma.yml中查到)。绑定实例充当 Prisma 服务的"JavaScript SDK",你可以调用其 API 向 Prisma 数据库发送查询与变更。

操作 1:将以下代码写入src/index.js。它创建了一个Prisma绑定实例,并依次执行创建用户、查询用户、创建文章、更新文章、级联查询以及批量删除等操作:

⚠️Important:务必把__YOUR_PRISMA_ENDPOINT__替换为你的 Prisma endpoint,它存储在prisma/prisma.yml中。

const { Prisma } = require("prisma-binding") const prisma = new Prisma({ typeDefs: "src/generated/prisma.graphql", endpoint: "__YOUR_PRISMA_ENDPOINT__" }) prisma.mutation .createUser({ data: { name: "Alice" } }, "{ id name }") .then(console.log) // { id: 'cjhcidn31c88i0b62zp4tdemt', name: 'Alice' } .then(() => prisma.query.users(null, "{ id name }")) .then(response => { console.log(response) // [ { id: 'cjhcidn31c88i0b62zp4tdemt', name: 'Alice' } ] return prisma.mutation.createPost({ data: { title: "Prisma rocks!", content: "Prisma rocks!", author: { connect: { id: response[0].id } } } }) }) .then(response => { console.log(response) /* { id: 'cjhcidoo5c8af0b62kv4dtv3c', title: 'Prisma rocks!', content: 'Prisma rocks!', published: false } */ return prisma.mutation.updatePost({ where: { id: response.id }, data: { published: true } }) }) .then(console.log) /* { id: 'cjhcidoo5c8af0b62kv4dtv3c', title: 'Prisma rocks!', content: 'Prisma rocks!', published: true } */ .then(() => prisma.query.users(null, "{ id posts { title } }")) .then(console.log) // [ { id: 'cjhcidn31c88i0b62zp4tdemt', posts: [ [Object] ] } ] .then(() => prisma.mutation.deleteManyPosts()) .then(console.log) // { count: 1 } .then(() => prisma.mutation.deleteManyUsers()) .then(console.log) // { count: 1 }

操作 2:运行脚本,观察终端打印的查询结果:

node src/index.js

理解绑定 API 的调用约定

从代码可以看出 Prisma binding 的两个关键调用形态:

  • query/mutation:每个数据模型类型对应一组方法,例如userscreateUserupdatePostdeleteManyPosts。方法签名通常为(args, selectionSet)——第一个参数是 GraphQL 变量(如datawhere),第二个参数是你想要返回的字段选择集(如"{ id name }")。绑定实例在内部会基于下载的 schema 解析出对应字段与类型,动态生成 GraphQL 文档后发送请求。
  • 关系写入:创建文章时通过author: { connect: { id: ... } }关联已存在的User,这是 Prisma 处理关系型嵌套写入的标准语法——connect表示"连接到已有节点",而create则表示"同时新建关联节点"。

从 Client.ts 的实现看,querymutation$subscribe$graphql$exists等属性均在构造阶段通过buildMethods()等内部方法构建:每个调用先记录为一组 "instructions",再经getDocumentForInstructions生成完整 GraphQL 文档并交由底层的BatchedGraphQLClient发送;同时它支持通过secret配置签发 JWT 令牌,以Authorization: Bearer <token>请求头完成鉴权。也就是说,你使用的"类型化 SDK"本质上是基于 schema 动态生成的、对 GraphQL 请求的封装层。

Step 5:使用exists检查特定节点的存在性

除了querymutation,Prisma binding 还提供了一个便捷属性exists,用于检查数据库中是否存在满足特定条件的节点。exists为数据模型中的每个类型暴露一个函数,函数名与类型同名(本例即prisma.exists.User(filter)prisma.exists.Post(filter))。这些函数接收filter参数,始终返回truefalse

因为Step 1创建的数据模型包含UserPost两个模型,Prisma 便生成了exists.Userexists.Post

操作 1:将以下代码写入src/index.js。它实例化 Prisma binding,创建用户与文章后使用exists验证节点存在性,删除数据后再验证节点已不存在:

⚠️Important:务必把__YOUR_PRISMA_ENDPOINT__替换为你的 Prisma endpoint,它存储在prisma/prisma.yml中。

const { Prisma } = require("prisma-binding") const prisma = new Prisma({ typeDefs: "src/generated/prisma.graphql", endpoint: "__YOUR_PRISMA_ENDPOINT__" }) prisma.mutation .createUser({ data: { name: "Alice" } }, "{ id name }") .then(response => { return prisma.mutation.createPost({ data: { title: "Prisma rocks!", content: "Prisma rocks!", author: { connect: { id: response.id } } } }) }) .then(() => prisma.exists.User({ name: "Alice" })) .then(response => console.log(response)) // true .then(() => prisma.exists.Post({ title: "Prisma rocks" })) .then(response => console.log(response)) // true .then(() => prisma.mutation.deleteManyPosts()) .then(() => prisma.mutation.deleteManyUsers()) .then(() => prisma.exists.Post({ title: "Prisma rocks" })) .then(response => console.log(response)) // false .then(() => prisma.exists.User({ name: "Alice" })) .then(console.log) // false

操作 2:运行脚本,观察终端打印的结果:

node src/index.js

exists的典型用途

exists非常适合在写入前做幂等校验或条件判断,例如"用户名是否已注册""文章标题是否已存在"这类场景。它避免了手写完整的users(where: ...)查询再自行判空的样板代码,返回值语义清晰(布尔值),可直接用于业务分支。在仓库的 Client.ts 中,$existsbuildExists()构建,内部同样基于 schema 中每个类型的where过滤参数生成对应查询,其实现与query/mutation共享同一套指令与文档生成管线。

Step 6:以字符串形式发送原始查询与变更

Prisma binding 还允许你通过request属性,把完整的查询/变更以字符串形式直接发给 Prisma 服务。这种方式更为冗长——你需要拼写完整操作,且响应会多一层开销:因为返回结果会以查询/变更的名称作为顶层 key 包裹。

说明:Prisma binding 的request底层使用graphql-request,因此与它拥有相同的 API 形态,即request(query, variables?)

操作 1:将src/index.js的内容替换为以下代码:

⚠️Important:务必把__YOUR_PRISMA_ENDPOINT__替换为你的 Prisma endpoint,它存储在prisma/prisma.yml中。

const { Prisma } = require("prisma-binding") const prisma = new Prisma({ typeDefs: "src/generated/prisma.graphql", endpoint: "__YOUR_PRISMA_ENDPOINT__" }) const query = ` { users { id name } } ` const mutation = ` mutation CreateUser($name: String!) { createUser(data: { name: $name }) { id name } } ` const variables = { name: 'Bob' } prisma.mutation .createUser({ data: { name: 'Alice' } }, '{ id name }') .then(console.log) // { id: 'cjhcijh30cgww0b622rwkkvbo', name: 'Alice' } .then(() => prisma.request(mutation, variables)) .then(console.log) // { createUser: { id: 'cjhcijjndch0d0b62qux6o52a', name: 'Bob' } } .then(() => prisma.query.users(null, '{ id name }')) .then(console.log) /* [ { id: 'cjhciiacxcf850b62mcuaa3uz', name: 'Alice' }, { id: 'cjhcijjndch0d0b62qux6o52a', name: 'Bob' } ] */ .then(() => prisma.request(query)) .then(console.log) /* { users: [ { id: 'cjhciiacxcf850b62mcuaa3uz', name: 'Alice' }, { id: 'cjhcijjndch0d0b62qux6o52a', name: 'Bob' } ] } */

操作 2:运行脚本,观察终端打印的结果:

node src/index.js

对比:request与类型化 API

对比 Step 4 与 Step 6 的输出可以清晰看到差异:

  • 类型化调用(prisma.query.usersprisma.mutation.createUser)返回的是字段选择集直接对应的结果,结构扁平、无需关心操作名。
  • 原始request调用则需要手写完整 GraphQL 文档(可含变量定义与操作名),其响应以操作名作为顶层 key(如{ createUser: {...} }{ users: [...] }),并且需要自行把变量作为第二个参数传入。

因此,request更适合"有现成 GraphQL 字符串/文档"或"需要动态拼接操作"的场景,而类型化 API 在开发体验与代码可读性上更胜一筹。

小结

本教程带你走完了"用 Node 脚本访问 Prisma 服务"的完整流程:

  1. 更新数据模型datamodel.graphql+prisma deploy),让 Prisma 服务暴露User/Post的 CRUD API;
  2. 搭建项目结构,将 Prisma 服务目录迁入脚本项目,安装prisma-bindinggraphql
  3. 下载 Prisma database schema.graphqlconfig.yml+graphql get-schema),并可选配置post-deployhook 实现自动刷新;
  4. 类型化调用prisma.query/prisma.mutation完成增删改查与关系连接;
  5. 存在性检查prisma.exists.User(...)/prisma.exists.Post(...),以布尔值快速判断节点是否存在;
  6. 原始请求prisma.request(query, variables),以字符串形式发送完整 GraphQL 文档。

这套能力可以无缝嵌入定时任务、数据迁移脚本、CI 校验、批量数据处理等场景,让 Node 脚本成为 Prisma 数据库的"一等公民"。对绑定实例内部机制感兴趣的读者,可继续阅读本仓库 prisma-client-lib 包 的源码,深入理解 schema 解析、指令生成与请求批处理的具体实现。

  • 后端
  • 数据库
  • GraphQL

【免费下载链接】prisma1

💾 Database Tools incl. ORM, Migrations and Admin UI (Postgres, MySQL & MongoDB) [deprecated]

项目地址:https://gitcode.com/gh_mirrors/pr/prisma1
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/24 11:14:21

Linux 启动流程与 systemd 运行目标实战手册

从按下电源键到出现登录提示符&#xff0c;要经过固件自检、GRUB2 引导、内核与 initramfs、systemd 拉起 target 一串环节&#xff0c;任何一环断了系统就起不来。 本文把启动过程拆成九步&#xff0c;讲清 systemd target 与传统运行级别的对应、运行目标的查看与切换&#x…

作者头像 李华
网站建设 2026/9/24 11:13:44

工控网络安全学习路线:从PLC协议解析到国产设备安全加固

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

作者头像 李华
网站建设 2026/9/24 11:11:27

从一条 SARIF 告警开始:OpenCodeReview × Jenkins 审查闭环实战

上一篇我们讨论了 OpenCodeReview 在 GitHub Actions 中的最短接入路径——一行 uses 即可启动 AI 审查。但对于大量运行 Jenkins 的团队来说&#xff0c;真正的战场在 Jenkinsfile 里。这篇文章从零开始&#xff0c;在 Jenkins 上搭建一条完整的 AI 审查闭环&#xff1a;从安装…

作者头像 李华
网站建设 2026/9/24 11:08:12

基于LM2596的±12V双路电源设计:拓扑、计算与PCB布局实战

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

作者头像 李华
网站建设 2026/9/24 11:06:22

昇腾硬件跑通DeepSeek V3-R1:从选型部署到避坑全流程

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

作者头像 李华
网站建设 2026/9/24 11:01:33

RK3588嵌入式AI工作站全栈实战:从硬件供电到YOLOv8部署

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

作者头像 李华