1"use strict";(globalThis.webpackChunk_localrepo_postgraphile_website=globalThis.webpackChunk_localrepo_postgraphile_website||[]).push([[2909],{27420(e,n,t){t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>o,default:()=>c,frontMatter:()=>r,metadata:()=>s,toc:()=>d});const s=JSON.parse('{"id":"smart-tags-file","title":"The postgraphile.tags.json5 file","description":"You can load TagsFilePlugin as part of your configuration to have","source":"@site/versioned_docs/version-5/smart-tags-file.md","sourceDirName":".","slug":"/smart-tags-file","permalink":"/postgraphile/5/smart-tags-file","draft":false,"unlisted":false,"editUrl":"https://github.com/graphile/crystal/tree/main/postgraphile/website/postgraphile/smart-tags-file.md","tags":[],"version":"5","lastUpdatedAt":1761669037000,"frontMatter":{"title":"The postgraphile.tags.json5 file"},"sidebar":"docs","previous":{"title":"Smart Tags","permalink":"/postgraphile/5/smart-tags"},"next":{"title":"Smart Comments","permalink":"/postgraphile/5/smart-comments"}}');var i=t(31085),a=t(71184);const r={title:"The postgraphile.tags.json5 file"},o=void 0,l={},d=[{value:"Merging/Overriding",id:"mergingoverriding",level:3},{value:"File format",id:"file-format",level:3},{value:"Reading from an alternative path",id:"reading-from-an-alternative-path",level:2},{value:"Going further",id:"going-further",level:3}];function g(e){const n={a:"a",code:"code",em:"em",h2:"h2",h3:"h3",p:"p",pre:"pre",...(0,a.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsxs)(n.p,{children:["You can load ",(0,i.jsx)(n.code,{children:"TagsFilePlugin"})," as part of your configuration to have\nPostGraphile read a ",(0,i.jsx)(n.code,{children:"postgraphile.tags.json5"})," file from the current directory\nand process the tags and descriptions therein."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-js",metastring:'title="graphile.config.mjs"',children:'import { TagsFilePlugin } from "postgraphile/utils";\n\nexport default {\n // ...\n plugins: [TagsFilePlugin],\n};\n'})}),"\n",(0,i.jsx)(n.h3,{id:"mergingoverriding",children:"Merging/Overriding"}),"\n",(0,i.jsxs)(n.p,{children:["If you provide a description for an entity in ",(0,i.jsx)(n.code,{children:"postgraphile.tags.json5"})," then\nthat description will override any previous descriptions."]}),"\n",(0,i.jsxs)(n.p,{children:["If you provide tags for an entity in ",(0,i.jsx)(n.code,{children:"postgraphile.tags.json5"}),", those tags will\nbe ",(0,i.jsx)(n.em,{children:"merged"})," with previous tags overriding tags with the same names but retaining\nother tags."]}),"\n",(0,i.jsx)(n.h3,{id:"file-format",children:"File format"}),"\n",(0,i.jsxs)(n.p,{children:["The file is in JSON5 (you can just use regular JSON if you prefer, but the\nextension must be ",(0,i.jsx)(n.code,{children:".json5"}),") and is formatted like this:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-json5",children:'{\n version: 1,\n config: {\n /*\n * There can be entries here for:\n *\n * - `class`: for tables, composite types, views and materialized views\n * - `attribute`: for columns/attributes (of any \'class\' type)\n * - `constraint`: for table constraints\n * - `procedure`: for functions/procedures\n */\n class: {\n /*\n * The next level describes the named type. We\'ve just used the table\n * name `"post"` but it could be `"my_schema.post"` if you have multiple\n * tables with the same name and you don\'t want this rule to apply to\n * all of them.\n */\n post: {\n /*\n * This will override the description sourced from the PostgreSQL COMMENT.\n */\n description: "A post within our forum.",\n\n /*\n * Add tags specific to the \'post\' table here. You can omit this if you\n * don\'t want to add any tags.\n */\n tags: {\n foreignKey: [\n "(default_user_id) references user (id)|@fieldName defaultUser",\n "(organization_id) references organization (id)|@fieldName organization",\n ],\n },\n\n /*\n * We\'ve added a shortcut to class-types so you can tag/describe\n * columns at the same time of the class.\n */\n attribute: {\n /*\n * Assuming `body` is one of the columns in the \'post\' table.\n */\n body: {\n /*\n * Optional description, if provided overrides the PostgreSQL\n * `COMMENT ON COLUMN post.body`.\n */\n description: "The body of the post",\n tags: {\n /*\n * Here we indicate that the \'body\' field will not be available\n * in the update mutation.\n */\n omit: "update",\n },\n },\n },\n },\n },\n },\n}\n'})}),"\n",(0,i.jsx)(n.h2,{id:"reading-from-an-alternative-path",children:"Reading from an alternative path"}),"\n",(0,i.jsxs)(n.p,{children:["If you want to store your tags in a different file (e.g.\n",(0,i.jsx)(n.code,{children:"postgraphile.tags.json"}
1)," to support a wider range of parsers) then you can use\na custom plugin instead:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-js",metastring:'title="graphile.config.mjs"',children:'import { pgSmartTagsFromFile } from "postgraphile/utils";\n\nexport default {\n // ...\n plugins: [\n pgSmartTagsFromFile(\n // JSON and JSONC are also JSON5 compatible, so you can use these extensions if you prefer:\n "/path/to/my/tags.file.json",\n ),\n ],\n};\n'})}),"\n",(0,i.jsxs)(n.p,{children:["If you're trying to avoid the ",(0,i.jsx)(n.code,{children:"fs"})," module (e.g. because you're using webpack)\nthen building and loading a basic smart tags plugin that doesn't read from the\nfile system might look something like this:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-js",metastring:'title="graphile.config.mjs"',children:'import { jsonPgSmartTags } from "postgraphile/utils";\n\nconst MySmartTagsPlugin = jsonPgSmartTags({\n version: 1,\n config: {\n class: {\n post: {\n tags: {\n omit: "update",\n },\n },\n },\n },\n});\n\nexport default {\n // ...\n plugins: [MySmartTagsPlugin],\n};\n'})}),"\n",(0,i.jsx)(n.h3,{id:"going-further",children:"Going further"}),"\n",(0,i.jsxs)(n.p,{children:["For greater flexibility, you might choose to check out\n",(0,i.jsx)(n.a,{href:"./pg-smart-tags",children:"pgSmartTags"}),"."]})]})}function c(e={}){const{wrapper:n}={...(0,a.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(g,{...e})}):g(e)}},71184(e,n,t){t.d(n,{R:()=>r,x:()=>o});var s=t(14041);const i={},a=s.createContext(i);function r(e){const n=s.useContext(a);return s.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:r(e.components),s.createElement(a.Provider,{value:n},e.children)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.