{"id":20253605,"url":"https://github.com/graphile/smart-tags-table","last_synced_at":"2025-10-24T00:08:32.689Z","repository":{"id":57114178,"uuid":"348361594","full_name":"graphile/smart-tags-table","owner":"graphile","description":"Enables retrieving PostGraphile smart tags from a database table.","archived":false,"fork":false,"pushed_at":"2021-03-16T13:40:29.000Z","size":17,"stargazers_count":8,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-10T23:43:18.385Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/graphile.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-03-16T13:39:15.000Z","updated_at":"2021-06-24T02:27:55.000Z","dependencies_parsed_at":"2022-08-22T03:00:41.562Z","dependency_job_id":null,"html_url":"https://github.com/graphile/smart-tags-table","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphile%2Fsmart-tags-table","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphile%2Fsmart-tags-table/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphile%2Fsmart-tags-table/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphile%2Fsmart-tags-table/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/graphile","download_url":"https://codeload.github.com/graphile/smart-tags-table/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248317726,"owners_count":21083527,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-14T10:26:11.134Z","updated_at":"2025-10-24T00:08:32.610Z","avatar_url":"https://github.com/graphile.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# @graphile/smart-tags-table\n\nThis plugin allows you to store\n[smart tags](https://www.graphile.org/postgraphile/smart-tags/) into a database\ntable rather than using\n[database comments](https://www.graphile.org/postgraphile/smart-comments/) or\n[a dedicated file](https://www.graphile.org/postgraphile/smart-tags-file/).\n\nIn general, using the other approaches are preferred. This plugin is primarily\nintended for applications which are allowing users to manipulate the GraphQL and\nmaybe even database schema at run time.\n\n## Crowd-funded open-source software\n\nWe rely on the community's support to keep producing and maintaining OSS; if you\nfind this plugin helpful, please\n[click here to find out more about sponsors and sponsorship.](https://www.graphile.org/sponsor/)\n\n## Usage\n\nPlease note you have to create a `smart_tags` table as described\n[below](#smart-tags-table); we do not do this for you.\n\nFrom the CLI you can install this plugin and run using command line\n`postgraphile`:\n\n```\nyarn add postgraphile @graphile/smart-tags-table\nyarn postgraphile --append-plugins @graphile/smart-tags-table -c postgres://localhost/my_db --watch\n```\n\nIn library mode you can use `appendPlugins` to install the plugin, and you can\nalso choose the name of the table via the `smartTagsTable` option within\n`graphileBuildOptions` (should you wish to override it):\n\n```js\napp.use(\n  postgraphile(process.env.DATABASE_URL, process.env.SCHEMA_NAME, {\n    appendPlugins: [require(\"@graphile/smart-tags-table\")],\n    watchPg: true,\n    graphileBuildOptions: {\n      smartTagsTable: \"public.smart_tags\",\n    },\n  }),\n);\n```\n\n**NOTE**: watch mode consumes (very inefficiently) an entire PostgreSQL client\njust for this plugin, so your pg pool needs to be at least size 3 if you are\nusing watch mode (default is 10). Addressing this will require changes to the\nway that watch mode works throughout PostGraphile/Graphile Engine; the changes\nhave not been made yet.\n\n## Smart tags table\n\nYou must add a table to your database to store the smart tags (that's the entire\npoint of this plugin :wink:). The table follows a similar pattern to the\n[entries in a JSON smart tags file](https://www.graphile.org/postgraphile/make-pg-smart-tags-plugin/#makejsonpgsmarttagsplugin),\nnamely:\n\n- `kind` - one of:\n  - `class` - for tables, views, materialized views, compound types and other\n    table-like entities; things you'd find in the\n    [`pg_class` PostgreSQL system table](https://www.postgresql.org/docs/current/catalog-pg-class.html).\n  - `attribute` - for columns/attributes of a `class`; things you'd find in the\n    [`pg_attribute` PostgreSQL system table](https://www.postgresql.org/docs/current/catalog-pg-attribute.html).\n  - `constraint` - for constraints; things you'd find in the\n    [`pg_constraint` PostgreSQL system table](https://www.postgresql.org/docs/current/catalog-pg-constraint.html).\n  - `procedure` - for functions and procedures; things you'd find in the\n    [`pg_proc` PostgreSQL system table](https://www.postgresql.org/docs/current/catalog-pg-proc.html)\n- `identifier` - the textual representation of the entity to apply the tags to,\n  this will differ based on the `kind`:\n  - `class` - `schema_name.table_name`\n  - `attribute` - `schema_name.table_name.column_name`\n  - `constraint` - `schema_name.table_name.constraint_name`\n  - `procedure` - `schema_name.function_name`\n  - NOTE: since PostGraphile doesn't support function overloading, function\n    parameters are not factored into the identifier.\n  - NOTE: you may omit from the left until and including a period (`.`), this\n    will make the matching fuzzier which may result in applying the tags to\n    multiple identically named entities in different schemas/tables/etc; for\n    example the `id` column in a table `app_public.users` could be referred to\n    as `app_public.users.id` or `users.id` or just `id`.\n- `description` - optionally override the documentation for this entity (rather\n  than pulling from the relevant PostgreSQL comment).\n- `tags` - a JSON object containing the tags to apply to the entity; the values\n  within this object must be the boolean `true`, a string, or an array of\n  strings. All other values are invalid and may have unexpected consequences.\n\nA minimal implementation of the smart tags table would be:\n\n```sql\ncreate table public.smart_tags (\n  kind text not null,\n  identifier text not null,\n  description text,\n  tags json not null default '{}',\n  unique (kind, identifier)\n);\n```\n\nA fuller implementation with validation rules and support for watch mode could\nbe something like:\n\n```sql\n-- This is an optional validation function used in the `check` constraint\n-- below; you don't need it, but you do need to adhere to these rules.\ncreate function public.is_valid_smart_tags_json(tags json)\nreturns boolean as $$\n  -- Must be an object\n  select json_typeof(tags) = 'object'\n  and not exists(\n    select 1\n    -- And each value in the object...\n    from json_each(tags)\n    -- Must be 'true':\n    where value::text \u003c\u003e 'true'\n    -- Or a string:\n    and json_typeof(value) \u003c\u003e 'string'\n    -- Or an array of strings:\n    and (\n      json_typeof(value) \u003c\u003e 'array'\n      or exists(\n        select 1\n        from json_array_elements(value) v2\n        where json_typeof(v2) \u003c\u003e 'string'\n      )\n    )\n  );\n$$ language sql immutable;\n\n-- Your smart_tags table; you may rename this if you wish but you must tell\n-- PostGraphile what it's called via `graphileBuildOptions.smartTagsTable` as\n-- shown in usage above.\ncreate table public.smart_tags (\n  -- We don't care what kind of primary key you use, nor what you call it.\n  id serial primary key,\n\n  -- These columns are required to have the names and types as stated, the\n  -- check constraints are optional.\n  kind text not null check(kind in ('class', 'attribute', 'constraint', 'procedure')),\n  identifier text not null,\n  description text,\n  tags json not null default '{}' check(public.is_valid_smart_tags_json(tags)),\n\n  -- We require there's a unique index/constraint (or primary key\n  -- constraint) on these columns.\n  unique (kind, identifier)\n);\n\n-- This trigger function is used to notify PostGraphile that something has\n-- changed within the table; you only need this if you intend to support watch\n-- mode.\ncreate function public.tg_smart_tags__notify() returns trigger as $$\nbegin\n  perform pg_notify('smart_tags_table'::text, ''::text);\n  return null;\nend;\n$$ language plpgsql;\n\n-- This trigger is for watch mode, calling the function above.\ncreate trigger smart_tags_changed\n  after insert or update or delete on public.smart_tags\n  for each statement\n  execute procedure public.tg_smart_tags__notify();\n```\n\n## Thanks 🙏\n\nThis plugin was originally sponsored by [Surge](http://surge.io/) 🙌\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgraphile%2Fsmart-tags-table","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgraphile%2Fsmart-tags-table","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgraphile%2Fsmart-tags-table/lists"}