ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

PostGraphile 数据库函数限制全解析:VARIADIC、重载函数与 record 返回类型

PostGraphile 数据库函数限制全解析:VARIADIC、重载函数与 record 返回类型 PostGraphile 数据库函数限制全解析VARIADIC、重载函数与 record 返回类型【免费下载链接】crystal Graphiles Crystal Monorepo; home to Grafast, PostGraphile, pg-introspection, pg-sql2 and much more!项目地址: https://gitcode.com/gh_mirrors/cry/crystalPostGraphilev5支持将 PostgreSQL 函数自动暴露为 GraphQL 的查询、变更与计算字段但并非所有 PostgreSQL 函数都能被支持。本文以官方文档 Function Restrictions 为主线结合pg-introspection的源码实现系统梳理三类不受支持的函数形态、背后的技术原因以及推荐的规避与改造方案。PostGraphile 对数据库函数支持的整体图景PostGraphile 的一大特性就是数据库驱动 schema它通过内省introspection读取数据库结构把表、视图、枚举、函数等自动转换为可查询的 GraphQL 类型。函数是其中最灵活的扩展手段之一官方文档 Database Functions 将函数的使用方式归纳为三种Computed Columns计算字段为表类型附加一个计算字段参考 computed-columns.mdCustom Queries自定义查询在根级Query上暴露字段可返回标量、列表、自定义类型、表行甚至表连接参考 custom-queries.mdCustom Mutations自定义变更在根级Mutation上暴露字段可返回void、标量、列表、自定义类型、表行或表行列表但不能返回连接因为变更无法分页参考 custom-mutations.md。PostGraphile 支持非常广泛的函数形态SQL 或 PL/pgSQL 等语言编写、任意参数组合、不同的返回类型标量、复合类型、表行、集合等。但官方文档明确指出有三类函数目前不被支持在规划数据库函数时需要特别注意。不支持的函数类型清单根据官方文档PostGraphile 对 PostgreSQL 函数的支持存在以下边界遇到以下三类函数时 PostGraphile 不会将其暴露到 GraphQL schema 中VARIADIC可变参数函数重载函数overloaded functions——因为目前无法在 GraphQL 中优雅地暴露它们返回record且没有更多类型信息的函数——因为 PostGraphile 不知道这个record会包含哪些列因此无法将其转换为 GraphQL 类型。为什么 VARIADIC 函数不被支持VARIADIC 是 PostgreSQL 的可变参数语法允许函数接收不定数量的同类型参数例如create function concat_all(variadic parts text[]) returns text as $$ select string_agg(part, ) from unnest(parts) as part; $$ language sql;从 GraphQL 的角度看VARIADIC 的调用方式与普通数组参数存在语义差异客户端要么必须显式传入数组要么需要依赖 PostGraphile 的扁平化参数argument expansion机制把不定数量的标量展开为多个独立参数。目前 PostGraphile 尚未对这种调用形态提供稳定的映射方案因此直接选择不支持。从源码层面看pg-introspection在内省阶段其实是收集了可变参数信息的。introspection.ts 中PgProc类型定义了provariadic字段注释明确写着Data type of the variadic array parameters elements, or zero if the function does not have a variadic parameter。这意味着底层数据是齐备的provariadic对应的正是 PostgreSQL 系统表pg_proc中的provariadic列只是 schema 生成层尚未利用该信息去暴露 VARIADIC 函数。规避建议把 VARIADIC 参数改写为普通的数组参数即可。例如上面例子可改写为create function concat_all(parts text[]) returns text as $$ select string_agg(part, ) from unnest(parts) as part; $$ language sql;这样 PostGraphile 就能将其暴露为一个接收[String]数组参数的标准字段。为什么重载函数不被支持PostgreSQL 允许同名但参数列表不同的多个函数共存函数重载。例如create function search_users(name text) returns setof users as $$ ... $$ language sql; create function search_users(email text) returns setof users as $$ ... $$ language sql;在 SQL 层面数据库可以通过参数类型区分调用目标但 GraphQL 的字段名在同一个对象类型内必须唯一重载函数会映射为完全相同的 GraphQL 字段名searchUsersPostGraphile 无法在不破坏 GraphQL 命名规范的前提下把它们整洁地neatly同时暴露出来。官方文档给出的原因正是因为目前无法在 GraphQL 中优雅地暴露它们。规避建议在数据库层为同名函数起不同的名字或者使用name/ 智能注释smart comments为它们指定不同的 GraphQL 字段名避免字段名冲突。例如将第二个函数命名为search_users_by_email。为什么返回record的函数不被支持PostgreSQL 中函数可以声明返回匿名的record类型此时列集合由函数体实际返回的内容决定通常配合OUT参数或在调用时指定列清单。例如create function get_something() returns record as $$ select 1, hello; $$ language sql;对于这种函数PostGraphile 无法提前得知record将包含哪些列列名、列类型都是运行期才知道的也就无法构建对应的 GraphQL 对象类型因此在内省阶段就直接将其排除了。这一点在源码中有非常直接的证据。pg-introspection生成内省 SQL 时在查询pg_proc的 CTEprocs里加了这样一行过滤条件introspection.tsprocs as ( select pg_proc.oid as _id, * from pg_catalog.pg_proc where pronamespace in (...) and prorettype operator(pg_catalog.) 2279 )这里的2279正是 PostgreSQL 内置的record类型的 OIDprorettype operator() 2279即排除所有返回类型为record的函数。也就是说返回record的函数在数据库内省阶段就被过滤掉了根本不会进入 schema 构建流程。同时augmentIntrospection.ts 中通过entity.getReturnType memo(() getType(entity.prorettype))依据prorettype函数返回类型的 OID见 introspection.ts解析函数返回类型这进一步印证了返回类型信息是 schema 生成的硬依赖——缺少确定的返回类型转换就无法完成。解决办法官方推荐将返回类型从record改为一个已定义的复合类型即用CREATE TYPE或其他类似方式先定义一个具名的复合类型再让函数返回该类型-- 1. 先定义复合类型 create type my_result as ( id int, label text ); -- 2. 函数返回具名复合类型 create function get_something() returns my_result as $$ select 1, hello; $$ language sql;这样 PostGraphile 就能基于my_result的列定义构建出对应的 GraphQL 对象类型函数得以正常暴露。从内省到暴露函数是如何进入 schema 的理解了上述限制有必要再看一眼 PostGraphile 暴露函数的整体链路以便判断你的函数为什么没出现在 schema 里内省Introspectionpg-introspection通过makeIntrospectionQuery()生成并执行内省 SQL见 introspection.ts从pg_proc、pg_type、pg_namespace等系统表收集函数及其参数、返回类型等元数据此阶段即排除了record返回类型OID 2279。增强AugmentationaugmentIntrospection.ts 对原始内省结果做关联解析例如getReturnType、getParameters等记忆化访问器为上层提供便捷的类型/参数对象。Schema 生成PostGraphile 的插件系统位于 postgraphile/postgraphile/src基于增强后的内省结果按函数用途计算字段 / 自定义查询 / 自定义变更将函数映射为 GraphQL 字段。如果你的函数符合本文所述三类限制它会在第 1 步或第 3 步被静默忽略——这也是排查函数未出现在 GraphQL schema 中问题时的首要检查点。相关边界PROCEDURE 同样不支持与函数限制相关但容易被混淆的是PostGraphile 目前也不支持 PostgreSQL 11 引入的存储过程PROCEDURE只支持函数FUNCTION。官方在 procedures.md 中明确说明PostGraphile does not currently have support for proceduresintroduced in PostgreSQL 11however we have solid support for functions。因此如果你的业务逻辑以CREATE PROCEDURE形式存在需要改写为CREATE FUNCTION才能被 PostGraphile 利用。可以推断未来对 PROCEDURE 的支持同样会面临与函数类似的返回类型与重载约束问题。总结与实践清单函数形态是否支持原因推荐改造常规函数标量 / 复合类型 / 表行 / 集合返回✅ 支持返回类型可确定参数可映射—VARIADIC 函数❌ 不支持可变参数无法整洁映射为 GraphQL 参数改为普通数组参数重载函数同名不同参数❌ 不支持GraphQL 字段名必须唯一无法优雅暴露不同名或用智能注释指定不同字段名返回匿名record的函数❌ 不支持无法确定record列信息无法构建 GraphQL 类型用CREATE TYPE定义复合类型作为返回类型PROCEDURE 存储过程❌ 不支持尚未实现改写为CREATE FUNCTION在基于 PostGraphile v5 设计数据库 API 时请将上表作为函数建模的红线清单优先使用返回具名复合类型或表行的函数、避免函数重载、用数组参数替代 VARIADIC即可让绝大多数数据库业务逻辑顺畅地暴露为 GraphQL 能力。更完整的函数使用指南可继续阅读 functions.md 及其关联的 computed-columns.md、custom-queries.md 与 custom-mutations.md。【免费下载链接】crystal Graphiles Crystal Monorepo; home to Grafast, PostGraphile, pg-introspection, pg-sql2 and much more!项目地址: https://gitcode.com/gh_mirrors/cry/crystal创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表