{"id":15568728,"url":"https://github.com/nikolasburk/generated-columns","last_synced_at":"2025-04-24T00:05:43.602Z","repository":{"id":82369640,"uuid":"449726267","full_name":"nikolasburk/generated-columns","owner":"nikolasburk","description":null,"archived":false,"fork":false,"pushed_at":"2022-01-19T14:33:14.000Z","size":6,"stargazers_count":18,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-24T00:05:34.497Z","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":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nikolasburk.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-01-19T14:32:44.000Z","updated_at":"2025-02-06T04:30:06.000Z","dependencies_parsed_at":null,"dependency_job_id":"f4be6ab1-d48c-48bf-a235-0ab5f147eafd","html_url":"https://github.com/nikolasburk/generated-columns","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikolasburk%2Fgenerated-columns","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikolasburk%2Fgenerated-columns/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikolasburk%2Fgenerated-columns/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikolasburk%2Fgenerated-columns/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nikolasburk","download_url":"https://codeload.github.com/nikolasburk/generated-columns/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250535098,"owners_count":21446508,"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-10-02T17:20:37.768Z","updated_at":"2025-04-24T00:05:43.580Z","avatar_url":"https://github.com/nikolasburk.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Generated columns with PostgreSQL and Prisma\n\nThis example shows how to use [generated columns](https://www.postgresql.org/docs/12/ddl-generated-columns.html) (aka _computed fields_) with PostgreSQL and Prisma.\n\nWhile the `GENERATED` keyword that's used in PostgreSQL to define generated columns is not supported in the Prisma schema, you can still customize the SQL that's generated by Prisma Migrate to make sure certain fields of your Prisma models will be using `GENERATED` under the hood.\n\nThis project shows an example of such a migration.\n\n## Workflow\n\n### 1. Define your Prisma model\n\nIn this step, you define the Prisma model **inclduding the field you want to be generated**. For this simple demo, you can use the following:\n\n```prisma\nmodel User {\n  id        Int     @id @default(autoincrement())\n  firstName String?\n  lastName  String?\n  fullName  String? // GENERATED\n}\n```\n\n### 2. Create the SQL migration using the `--create-only` option\n\nNext, you'll generate the SQL migration file **without yet applying it to the database** using the following commnad:\n\n```\nnpx prisma migrate dev --name init --create-only\n```\n\n### 3. Customize the generated SQL to include the `GENERATED` keyword\n\nAfter you ran the command above, you can open the `migration.sql`-file inside of the `migrations/TIMESTAMP-init`-file. It should look as follows:\n\n```sql\n-- CreateTable\nCREATE TABLE \"User\" (\n    \"id\" SERIAL NOT NULL,\n    \"firstName\" TEXT,\n    \"lastName\" TEXT,\n    \"fullName\" TEXT,\n\n    CONSTRAINT \"User_pkey\" PRIMARY KEY (\"id\")\n);\n```\n\nYou can now manually edit this file to determine which of the columns should be generated, and by which rules. In this case, we want to concatenate the `firstName` and the `lastName` with a space in between:\n\n```sql\n-- CreateTable\nCREATE TABLE \"User\" (\n    \"id\" SERIAL NOT NULL,\n    \"firstName\" TEXT,\n    \"lastName\" TEXT,\n+   \"fullName\" TEXT GENERATED ALWAYS AS (\n+       CASE\n+           WHEN \"firstName\" IS NULL THEN \"lastName\"\n+           WHEN \"lastName\" IS NULL THEN \"firstName\"\n+           ELSE \"firstName\" || ' ' || \"lastName\"\n+       END\n+   ) STORED,\n\n    CONSTRAINT \"User_pkey\" PRIMARY KEY (\"id\")\n);\n```\n\n### 4. Apply the migration against the database\n\nFinally, you can use Prisma Migrate to actually make changes against the database schema:\n\n```\nnpx prisma migrate dev\n```\n\n### 5. Query with Prisma Client\n\nYou can now send queries against the `User` table using the generated `PrismaClient` instance.\n\nNote that **it is not possible to set a value for the `fullName` field when invoking `prisma.user.create(...)`, e.g.:\n\n```ts\nconst newUser = await prisma.user.create({\n  data: {\n    firstName: \"Jane\",\n    lastName: \"Doe\",\n    fullName: \"asd\" // not possible to set a value for a `GENERATED` column\n  }\n})\n```\n\nYou will see this error:\n\n```\nPrismaClientUnknownRequestError: \nInvalid `prisma.user.create()` invocation in\n/Users/nikolasburk/Desktop/script/script.ts:8:37\n\n   5 // A `main` function so that we can use async/await\n   6 async function main() {\n   7 \n→  8   const newUser = await prisma.user.create(\n  Error occurred during query execution:\nConnectorError(ConnectorError { user_facing_error: None, kind: QueryError(Error { kind: Db, cause: Some(DbError { severity: \"ERROR\", parsed_severity: Some(Error), code: SqlState(\"42601\"), message: \"cannot insert into column \\\"fullName\\\"\", detail: Some(\"Column \\\"fullName\\\" is a generated column.\"), hint: None, position: None, where_: None, schema: None, table: None, column: None, datatype: None, constraint: None, file: Some(\"rewriteHandler.c\"), line: Some(830), routine: Some(\"rewriteTargetListIU\") }) }) })\n    at cb (/Users/nikolasburk/Desktop/script/node_modules/@prisma/client/runtime/index.js:38692:17) {\n  clientVersion: '3.7.0'\n}\n```\n\nThis makes sense because the value of this column will always be computed based on the values of the `firstName` and `lastName` columns in a specific row. \n\nThe following code is going to work though:\n\n```ts\nconst newUser = await prisma.user.create({\n  data: {\n    firstName: \"Jane\",\n    lastName: \"Doe\",\n  }\n})\nconsole.log(newUser)\n```\n\nThis prints the following to the terminal:\n\n```js\n{ id: 1, firstName: 'Jane', lastName: 'Doe', fullName: 'Jane Doe' }\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnikolasburk%2Fgenerated-columns","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnikolasburk%2Fgenerated-columns","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnikolasburk%2Fgenerated-columns/lists"}