實戰(zhàn)指南:用 PostgreSQL 函數(shù)為 GraphQL 類型擴展字段)
后端API網(wǎng)關(guān)【免費下載鏈接】crystal Graphiles Crystal Monorepo; home to Grafast, PostGraphile, pg-introspection, pg-sql2 and much more!項目地址https://gitcode.com/gh_mirrors/cry/crystal點擊查看免費下載計算列Computed Columns是 PostGraphile 的一項核心能力你只需要在 PostgreSQL 中定義符合約定的函數(shù)PostGraphile 就會自動把它暴露為對應表類型上的 GraphQL 字段——客戶端看起來就像在查詢一個普通列而實際值是函數(shù)計算的結(jié)果。本篇以官方快速參考示例為骨架結(jié)合倉庫源碼與測試證據(jù)帶你掌握計算列的命名約定、參數(shù)設(shè)計、返回類型標量/集合/連接以及性能與調(diào)試要點讀完即可在自己的 schema 中直接落地。一、什么是計算列計算列會為 GraphQL 表類型“附加”一個看似額外的字段。與真實列不同這個字段的值來自 PostgreSQL schema 中定義的一個函數(shù)。PostGraphile 會自動將這個函數(shù)暴露為類型上的字段它可以接收參數(shù)來影響計算結(jié)果并且可以返回標量、復合類型record、列表或集合。對于RETURNS SETOF ...的集合返回PostGraphile 會根據(jù)行為配置將其暴露為連接connection或列表。在 v4 快速參考文檔 中官方用 examples 倉庫的 schematopic表 topics_body_summary函數(shù)演示了完整效果v5 完整文檔 則給出了完整的識別規(guī)則與實現(xiàn)細節(jié)。兩者結(jié)合即可獲得從入門到原理的完整認知。二、被識別為計算列的函數(shù)需要滿足的規(guī)則要讓 PostGraphile 把某個函數(shù)當作計算列處理函數(shù)必須同時滿足以下條件來源computed-columns.md規(guī)則說明滿足通用函數(shù)限制詳見 function-restrictions.md不支持VARIADIC函數(shù)、不支持重載函數(shù)、不支持無類型信息的record返回命名以表名開頭函數(shù)名必須以它所屬的表名開頭后跟下劃線_首個參數(shù)為表類型第一個參數(shù)必須是該表對應的復合類型不能返回VOIDRETURNS VOID的函數(shù)不會被識別必須是STABLE或IMMUTABLE未聲明時為VOLATILE默認會被視為變更操作而非查詢與表同 schema函數(shù)必須定義在表所在的同一個 PostgreSQL schema 中例如假設(shè)存在person表下面的函數(shù)create function person_full_name(person person) returns text as $$ select person.given_name || || person.family_name $$ language sql stable;就會為person類型創(chuàng)建計算列可像普通字段一樣查詢{ personById(id: …) { # nodeId, id, ... fullName # 計算列但客戶端完全無感知 } }三、快速參考示例bodySummary 字段v4 快速參考文檔給出的第一個示例是在topic(id: 2)上同時查詢真實列body與計算列bodySummary{ topic(id: 2) { body bodySummary } }對應的 SQL 函數(shù)定義如下注意函數(shù)名topics_body_summary以表名topics開頭首參數(shù)為表類型t app_public.topics聲明為language sql stable第二個參數(shù)max_length帶默認值 30create function app_public.topics_body_summary( t app_public.topics, max_length int 30 ) returns text language sql stable as $$ select case when length(t.body) max_length then left(t.body, max_length - 3) || ... else t.body end; $$;查詢結(jié)果為{ topic: { body: PostGraphile is a powerful, idomatic, and elegant tool., bodySummary: PostGraphile is a powerful,... } }值得說明的是示例中的字段名bodySummary而非默認的bodySummaryByTopic是使用了graphile-contrib/pg-simplify-inflector插件簡化命名后的結(jié)果這一點在快速參考文檔開頭有明確提示——不同命名策略下字段名會不同但計算列機制本身不變。四、帶參數(shù)的計算列動態(tài)控制函數(shù)行為函數(shù)除首個表類型參數(shù)外聲明的其他參數(shù)都會暴露為 GraphQL 字段參數(shù)。上面的函數(shù)聲明了max_length int 30因此可以在查詢中傳參覆蓋默認值{ topic(id: 2) { body bodySummary(maxLength: 20) } }結(jié)果中摘要被截斷到 20 個字符左右{ topic: { body: PostGraphile is a powerful, idomatic, and elegant tool., bodySummary: PostGraphile is a... } }這種“額外參數(shù)自動暴露為 GraphQL 參數(shù)”的能力讓同一個計算列可以承擔不同粒度的計算。更完整的參數(shù)化示例見 v5 文檔-- 創(chuàng)建 User.greet(greeting: String) 字符串字段 create function my_schema.users_greet( u my_schema.users, --- 必填的表類型參數(shù)不暴露 greeting text --- 額外參數(shù)會暴露為 GraphQL 參數(shù) ) returns text as $$ select greeting || , || u.first_name || || u.last_name || !; $$ language sql stable strict;對應查詢{ userById(id: …) { greet(greeting: Greetings and salutations) } }注意strict聲明SQL 函數(shù)在參數(shù)為 NULL 時返回 NULL。倉庫測試 procedure-computed-fields.test.graphql 中還對“默認參數(shù)、可選參數(shù)、按名傳參”的組合行為做了系統(tǒng)驗證如headlineTrimmed(length: 15)、headlineTrimmed(length: 20, omission: [...])其生成的 SQL見 procedure-computed-fields.sql展示了帶默認值與不帶默認值的參數(shù)如何被分別編譯為位置參數(shù)或命名參數(shù)c : $2::int4。五、標量、集合與連接一個完整的 users/friends 示例v5 文檔給出了一個同時覆蓋“標量字段”與“連接字段”的完整示例。先建兩張表create table my_schema.users ( id serial not null primary key, first_name varchar not null, last_name varchar not null ); create table my_schema.friendships ( user_id integer not null, target_id integer not null, primary key (user_id, target_id) );然后創(chuàng)建兩個計算列函數(shù)-- 創(chuàng)建 User.name 字符串字段標量 create function my_schema.users_name(u my_schema.users) returns varchar as $$ select u.first_name || || u.last_name; $$ language sql stable; -- 創(chuàng)建 User.friends 連接集合 create function my_schema.users_friends(u my_schema.users) returns setof my_schema.users as $$ select users.* from my_schema.users inner join my_schema.friendships on (friendships.target_id users.id) where friendships.user_id u.id; $$ language sql stable;其中||是 PostgreSQL 的字符串拼接運算符returns setof my_schema.users使得users_friends被暴露為User.friends連接而不是返回多行導致父查詢行數(shù)膨脹。集合返回的底層處理v5 文檔特別提示如果函數(shù)返回集合如person_favorite_posts(person)PostGraphile 會自動把該選擇包裝成子查詢聚合防止父查詢產(chǎn)生多余行。手工等價的 SQL 大致是select person.id, array( select posts.* from person_favorite_posts(person) posts ) as favorite_posts from person where id $1;這一行為在倉庫測試中有直接證據(jù)simple-procedure-computed-fields.sql 中person_friends返回 setof被編譯為array(select ... from c.person_friends(__person__) ...)的子查詢聚合procedure-computed-fields.sql 則進一步覆蓋了computedTextArray、computedIntervalArray、computedCompoundTypeArray數(shù)組元素為復合類型以及computedIntervalSetSETOF 暴露為帶 cursor 的連接等復雜返回類型對應的預期結(jié)果見 procedure-computed-fields.json5。六、為什么叫“計算列”PostgreSQL 的字段選擇語法PostgreSQL 官方文檔指出col(table)與table.col兩種寫法可以互換——函數(shù)接受復合類型單參數(shù)時既可以用字段選擇語法調(diào)用也可以用函數(shù)式風格書寫。PostGraphile 正是利用了這一特性來模擬“計算字段”。所以在 PostGraphile 之外你也可以手工執(zhí)行等價的 SQLselect person.id, person.person_full_name as full_name -- 或等價寫法 -- person_full_name(person) as full_name from person where id $1;person.person_full_name讓函數(shù)看起來就像person表上的一個列盡管該列并不存在——“computed column function” 這個命名即來源于此。七、性能說明函數(shù)調(diào)用被內(nèi)聯(lián)進原始 SELECTPostGraphile 會把計算列的函數(shù)調(diào)用內(nèi)聯(lián)到原始的SELECT語句中詳見 computed-columns.md 中生成的 SQLa.post_headline_trimmed(__post__, $1::int4) as 2直接作為 SELECT 列表項出現(xiàn)因此不需要額外向數(shù)據(jù)庫發(fā)起查詢。但需要注意每個函數(shù)調(diào)用本身仍有一定開銷在數(shù)千行上執(zhí)行時開銷會累積PostgreSQL 有時可以內(nèi)聯(lián) SQL 函數(shù)以獲得更好的性能但內(nèi)聯(lián)失敗時性能可能下降如果遇到性能問題可以考慮改用extendSchema方案見 extend-schema.md 及 functions.md 中“Example computed column function”一節(jié)的說明。從測試證據(jù)看計算列還可用作排序依據(jù)orderby-computed測試orderby-computed.test.graphql 使用orderBy: [COMPUTED_ASC, ROW_ID_ASC]生成的 SQL 中排序鍵直接是order by c.edge_case_computed(__edge_case__) asc, __edge_case__.row_id asc見 orderby-computed.sql同樣無需額外的查詢往返。八、調(diào)試清單計算列缺失或行為異常時如果計算列沒有出現(xiàn)或行為不符合預期請按 v5 調(diào)試清單 逐項排查命名函數(shù)名以表名 下劃線開頭例如person表對應person_full_name首參數(shù)第一個參數(shù)必須是表類型例如person_full_name(p person)穩(wěn)定性函數(shù)標記為stable或immutablevolatile是默認值會被當作變更操作同 schema函數(shù)與表定義在同一個 schemacreate function same_schema_here.person_full_name(p same_schema_here.person)SQL 自檢在純 SQL 中用table.function或function(table)語法驗證函數(shù)本身可正確執(zhí)行select person_full_name(person) from person。九、延伸閱讀計算列完整規(guī)范與規(guī)則computed-columns.md通用函數(shù)限制VARIADIC、重載、record 等function-restrictions.md連接connection形態(tài)說明connections.md用extendSchema替代計算列以優(yōu)化性能extend-schema.md函數(shù)性能深入討論functions.md自定義查詢與建議含計算列設(shè)計建議custom-queries.md測試證據(jù)查詢與 SQL 快照見tests/queries/v4 目錄下的procedure-computed-fields.*、orderby-computed.*系列文件贊分享后端API網(wǎng)關(guān)【免費下載鏈接】crystal Graphiles Crystal Monorepo; home to Grafast, PostGraphile, pg-introspection, pg-sql2 and much more!項目地址https://gitcode.com/gh_mirrors/cry/crystal點擊查看免費下載相關(guān)推薦PostGraphile 計算列Computed Columns實戰(zhàn)指南用 PostgreSQL 函數(shù)為 GraphQL 類型動態(tài)擴展字段PostGraphile 計算列Computed Columns實戰(zhàn)指南用 PostgreSQL 函數(shù)為 GraphQL 類型動態(tài)擴展字段 PostGra后端API網(wǎng)關(guān)PostGraphile 計算列Computed Columns完整指南用 PostgreSQL 函數(shù)為 GraphQL 類型動態(tài)添加字段PostGraphile 計算列Computed Columns完整指南用 PostgreSQL 函數(shù)為 GraphQL 類型動態(tài)添加字段 導讀 計算列后端API網(wǎng)關(guān)PostGraphile 計算列Computed Columns完全指南用 PostgreSQL 函數(shù)為 GraphQL 表類型添加動態(tài)字段PostGraphile 計算列Computed Columns完全指南用 PostgreSQL 函數(shù)為 GraphQL 表類型添加動態(tài)字段 導讀 計算列后端API網(wǎng)關(guān)創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考