ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

PostGraphile 枚举(Enum)完整指南:PostgreSQL 枚举、Enum 表与 extendSchema 的三种实践方案

PostGraphile 枚举(Enum)完整指南:PostgreSQL 枚举、Enum 表与 extendSchema 的三种实践方案 后端API网关【免费下载链接】crystal Graphiles Crystal Monorepo; home to Grafast, PostGraphile, pg-introspection, pg-sql2 and much more!项目地址https://gitcode.com/gh_mirrors/cry/crystal点击查看免费下载导读本指南聚焦 PostGraphileCrystal Monorepo 中的核心项目位于postgraphile/postgraphile如何将数据库中的枚举约束自动映射为 GraphQL 枚举类型并系统讲解三种在 GraphQL Schema 中引入枚举的实战方案直接使用 PostgreSQL 原生枚举、基于智能标签Smart Tags的 Enum 表方案以及使用extendSchema手工定义 GraphQL 枚举。读完本文你将掌握enum、enumName、enumDescription等智能标签的完整用法理解它们在源码中的实现原理并能在自己的 PostGraphile 项目中根据场景选型。PostgreSQL 原生枚举的自动映射PostGraphile 会自动将 PostgreSQL 枚举类型CREATE TYPE ... AS ENUM映射为 GraphQL 枚举类型并自动重命名以符合 GraphQL 的命名要求与惯例例如转为大驼峰 UpperCamelCase。这是一个零配置、开箱即用的能力。以下示例中我们在数据库里定义了一个枚举类型animal_type和一张引用它的表create type animal_type as enum ( CAT, DOG, FISH ); create table pets ( id serial primary key, type animal_type not null, name text not null );映射到 GraphQL 后pets.type字段的类型将成为一个 GraphQL 枚举例如AnimalType其枚举值包含CAT、DOG、FISH并且由于type列带有NOT NULL约束生成的字段也是非空的。从底层实现看PostGraphile 在 Dataplan-PG 层面对 PostgreSQL 枚举的建模依赖dataplan/pg提供的enumCodec工厂函数见 grafast/dataplan-pg/src/codecs.ts。enumCodec接收名称、SQL 标识符、值列表与描述等配置返回的 codec 标记了isEnum: true、hasNaturalEquality: true枚举值天然支持相等比较且hasNaturalOrdering: false枚举没有自然的排序语义这直接决定了枚举字段在过滤、排序等行为中的表现。PostGraphile 正是基于这类 codec 来构建 GraphQL 枚举类型与对应取值。用enumName与enumDescription定制枚举映射后生成的枚举名称有时并不符合业务预期此时可以通过智能标签Smart Tags中的enumName和enumDescription分别设置枚举的名称与描述。COMMENT ON TYPE animal_type IS Eenum\nenumName TypeOfAnimal;在 PostgreSQL 中使用COMMENT ON ... IS语法写入 Smart Comments智能注释enum标记该类型为枚举enumName指定其在 GraphQL 中的名称。这里enum表明这个 PostgreSQL 类型应当被当作枚举处理enumName覆盖生成的 GraphQL 枚举名称enumDescription覆盖生成的 GraphQL 枚举描述。关于智能标签的通用机制前缀的来源、合法取值、除智能注释外的其他注入方式如postgraphile.tags.json5标签文件、pgSmartTags实例或自定义插件可参考 postgraphile/website/postgraphile/smart-tags.md 文档。值得注意的是PostGraphile 的 V4 兼容层PgV4InflectionPlugin中同样识别enumName标签并据此覆盖枚举名称见 postgraphile/postgraphile/src/plugins/PgV4InflectionPlugin.ts当约束或类上带有enumName标签时enumTableEnum转译器会直接返回该字符串否则才走默认的大驼峰命名逻辑。这说明enumName的能力是内置、稳定的不依赖某个具体版本。为什么有人不用 PostgreSQL 原生枚举PostgreSQL 原生枚举虽然好用但存在两个众所周知的技术限制在需要频繁演进枚举值时会造成困扰无法删除枚举值PostgreSQL 不允许从已存在的枚举类型中删除某个值一旦上线便无法回收无法在事务内新增枚举值ALTER TYPE ... ADD VALUE不能在事务块内执行这给自动化迁移尤其是事务化的迁移工具带来了困难。因此很多团队选择不用 PostgreSQL 枚举但依然想在 GraphQL 中获得枚举体验。PostGraphile 为此提供了多种替代方案核心思路是让数据仍然存储在普通表/文本列中仅在 GraphQL 层以枚举形态暴露。方案一Enum 表Enum TablesEnum 表方案利用 PostgreSQL 的外键foreign key关系将某个列的取值约束在一张值表的小集合内再通过enum智能标签告诉 PostGraphile 这张表应当被建模为 GraphQL 枚举。基本用法使用该特性需要满足两个条件有一张专门存放枚举值的表Enum 表通过enum智能标签标记该表。create table animal_type ( type text primary key, description text ); comment on table animal_type is Eenum; insert into animal_type (type, description) values (CAT, A feline animal), (DOG, A canine animal), (FISH, An aquatic animal); create table pets ( id serial primary key, type text not null references animal_type, name text not null );要点说明主键列即枚举值Enum 表的主键列示例中的type的取值将变成 GraphQL 枚举值例如CAT、DOG、FISHdescription列即枚举值描述如果表中存在名为description的列其内容会被用作对应枚举值的描述GraphQL 中的 description这会让文档与自省introspection信息更加友好外键即合法性约束pets.type通过references animal_type确保写入的值一定在枚举集合内数据库层面的约束保证了 GraphQL 枚举语义的正确性。在唯一约束Unique Constraint上使用enum除表之外enum智能标签同样支持作用于唯一约束注意是唯一约束不是普通索引。这意味着你可以把多个枚举塞进同一张表中每个枚举对应表上的一个唯一约束从而用一张表承载多个枚举。PostGraphile 的测试库中就有这样的真实示例见 postgraphile/postgraphile/tests/kitchen-sink-schema.sqllots_of_enums表包含四列每列各有一个UNIQUE约束分别打上enum标签并用enumName为其中两个命名create table enum_tables.lots_of_enums ( id serial primary key, enum_1 text, enum_2 varchar(3), enum_3 char(2), enum_4 text, description text, constraint enum_1 unique(enum_1), constraint enum_2 unique(enum_2), constraint enum_3 unique(enum_3), constraint enum_4 unique(enum_4) ); comment on table enum_tables.lots_of_enums is Eomit; comment on constraint enum_1 on enum_tables.lots_of_enums is Eenum\nenumName EnumTheFirst; comment on constraint enum_2 on enum_tables.lots_of_enums is Eenum\nenumName EnumTheSecond; comment on constraint enum_3 on enum_tables.lots_of_enums is Eenum; comment on constraint enum_4 on enum_tables.lots_of_enums is Eenum;官方文档提醒这种单表多枚举的模式并不被推荐但在社区生态中确有使用因此 PostGraphile 予以支持。若选择此模式请注意各唯一约束列的类型应与实际取值一致示例中分别使用了text、varchar(3)、char(2)并留意类型长度对取值集合的影响。自定义描述列与枚举名称自定义描述列若不想使用默认的description列可将enumDescription智能注释打在想要的列上comment on column animal_type.description is EenumDescription;自定义枚举名称与原生枚举一致使用enumNamecomment on table animal_type is Eenum\nenumName TypeOfAnimal;名称必须符合 GraphQLName规范只能包含字母、数字与下划线且不能以数字开头。Enum 表的源码验证PostGraphile 的 V4 转译器中enumTableEnum正是为 Enum 表枚举命名服务的见 postgraphile/postgraphile/src/plugins/PgV4InflectionPlugin.ts其命名逻辑如下若约束上带enumName标签直接使用若约束是主键contype p再看表上的enumName标签否则默认用表名的大驼峰形式若约束是非主键唯一约束默认用表名 列名的大驼峰形式例如lots_of_enums的enum_1唯一约束会生成类似LotsOfEnumsEnum1的默认名称除非用enumName覆盖。此外测试套件中有大量 Enum 表的端到端用例例如 postgraphile/postgraphile/tests/mutations/v4/enum_tables.mutations.sql 展示了 Enum 表在 CRUD 变更中的实际 SQL 形态可以作为理解该特性行为的参考。方案二使用 extendSchema 手工定义枚举如果你希望完全掌控枚举的定义包括其 GraphQL 类型名、值、描述以及与底层数据值的映射关系可以使用 PostGraphile 的extendSchema辅助函数以标准的 GraphQL IDL/SDL 语法编写枚举。import { constant } from postgraphile/grafast; import { gql, extendSchema } from postgraphile/utils; const myPlugin extendSchema(() ({ typeDefs: gql enum AnimalType { A feline animal CAT A canine animal DOG An aquatic animal FISH } extend type Pet { type: AnimalType! } , enums: { AnimalType: { values: { CAT: cat, DOG: dog, FISH: fish, }, }, }, objects: { Pet: { plans: { type() { /* TODO: add logic here */ return constant(cat); }, }, }, }, }));这个示例包含三层关键内容typeDefs用 GraphQL SDL 声明AnimalType枚举含每个值的描述并通过extend type Pet在已有类型Pet上新增一个type: AnimalType!字段enums配置将 GraphQL 枚举值与底层数据值建立映射CAT对应cat、DOG对应dog、FISH对应fish。这是GraphQL 枚举名 → 数据库/业务值的桥梁objects的plans为Pet.type字段提供 plan resolver这里用constant(cat)返回一个常量步骤作为示例实际使用时你需要替换为读取真实数据例如从Pet数据源取出类型字段的逻辑TODO注释处即待补全的业务逻辑。extendSchema方案的优点是完全自由枚举的名称、值、描述、与数据的映射都由你显式声明缺点是手写内容较多且需要自己维护字段解析逻辑适合数据形态与枚举取值不一致、或需要跨表映射的场景。方案三底层 Graphile Build API除上述两种方式外你还可以直接使用底层的 Graphile Build API 来添加一个新的GraphQLEnumType。这是最高级、最灵活也最底层的做法当内置的enum标签与extendSchema都无法满足需求时例如需要根据运行时信息动态构造枚举类型可以基于 Graphile Build 的build与注册机制自行构建GraphQLEnumType实例并注册到 schema 中。官方文档对此仅作提及未展开完整示例由于该 API 更接近框架内部实现一般仅在编写自定义插件时使用建议以 postgraphile/website/postgraphile/extending-raw.md 中关于插件与类型构建的说明为起点深入学习。三种方案对比与选型建议方案数据存储枚举集合维护适用场景注意事项PostgreSQL 原生枚举原生enum类型无法删除值、无法在事务内加值取值稳定、几乎不变PostGraphile 自动映射零配置Enum 表enum普通表 外键就是普通表的行可任意增删改枚举值可能演进、需要描述列需enum标签描述列默认description可enumDescription覆盖extendSchema由你决定由你决定代码内维护需要完全掌控枚举与底层值的映射需手写 plan resolver枚举名须符合 GraphQLName规范常见问题与最佳实践枚举名称冲突多个枚举经映射后可能产生相同名称可用enumName显式区分务必保证最终名称符合 GraphQLName规范。智能标签的注入方式不止一种本文示例以数据库智能注释Smart Comments为主但你同样可以在postgraphile.tags.json5标签文件、pgSmartTags实例或自定义插件中注入enum/enumName/enumDescription等标签效果一致。详见 smart-tags.md 与 smart-tags-file.md。改动即时生效若使用--watch模式运行 PostGraphile智能标签的变更几乎会立刻反映在 Ruru / GraphiQL 中否则需要重启服务。Enum 表视图enum也适用于视图配合primaryKey等虚拟约束例如测试库中的abcd_view便是一个以视图形式暴露的 Enum 表见 kitchen-sink-schema.sql适合对既有视图直接暴露枚举语义的场景。权限与枚举Enum 表方案中枚举值集合的读写依然遵循 PostgreSQL 行级权限与 PostGraphile 的权限模型可在此基础上实现更细粒度的控制。总结PostGraphile 为在 GraphQL 层暴露枚举提供了从零配置到完全可控的完整梯度PostgreSQL 原生枚举开箱即用Enum 表方案结合enum/enumName/enumDescription智能标签在保留数据库约束的同时绕开原生枚举的演进限制extendSchema与底层 Graphile Build API 则面向需要完全自定义的场景。实际选型时建议优先评估枚举值的演进频率取值稳定选原生枚举需要频繁增删值选 Enum 表需要复杂映射则选extendSchema。赞分享后端API网关【免费下载链接】crystal Graphiles Crystal Monorepo; home to Grafast, PostGraphile, pg-introspection, pg-sql2 and much more!项目地址https://gitcode.com/gh_mirrors/cry/crystal点击查看免费下载相关推荐PostGraphile 5 枚举Enums完全指南PostgreSQL 原生枚举、枚举表与 extendSchema 三种实现方案PostGraphile 5 枚举Enums完全指南PostgreSQL 原生枚举、枚举表与 extendSchema 三种实现方案 导读 在 PostG后端API网关TypeScript 枚举Enum完全指南数字枚举、常量枚举与反向映射深度解读TypeScript 枚举Enum完全指南数字枚举、常量枚举与反向映射深度解读 本文基于开源仓库 typ/typescript book https://文档教程PDF补丁丁完整指南批量修复PDF书签、一键合并图片为PDF的免费工具箱PDF补丁丁完整指南批量修复PDF书签、一键合并图片为PDF的免费工具箱 PDF 书签一改名就提示无法打开文档或者文档一点开就偷偷弹出网页PDF 补丁桌面应用文档创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表