{"id":13880781,"url":"https://github.com/cwqt/refract","last_synced_at":"2025-07-16T17:31:11.607Z","repository":{"id":37464755,"uuid":"485155339","full_name":"cwqt/refract","owner":"cwqt","description":"Generate Prisma from TypeScript","archived":false,"fork":false,"pushed_at":"2024-01-31T21:00:55.000Z","size":285,"stargazers_count":95,"open_issues_count":2,"forks_count":6,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-07-14T19:04:15.292Z","etag":null,"topics":["prisma","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cwqt.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","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-04-24T22:30:44.000Z","updated_at":"2025-04-03T10:44:53.000Z","dependencies_parsed_at":"2024-11-24T12:18:58.353Z","dependency_job_id":null,"html_url":"https://github.com/cwqt/refract","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/cwqt/refract","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cwqt%2Frefract","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cwqt%2Frefract/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cwqt%2Frefract/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cwqt%2Frefract/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cwqt","download_url":"https://codeload.github.com/cwqt/refract/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cwqt%2Frefract/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265527545,"owners_count":23782480,"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":["prisma","typescript"],"created_at":"2024-08-06T08:03:28.539Z","updated_at":"2025-07-16T17:31:11.235Z","avatar_url":"https://github.com/cwqt.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"# refract\n\nGenerate [Prisma](https://www.prisma.io) from TypeScript\n\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"https://ftp.cass.si/hzywUm159.png\" /\u003e\n\u003c/div\u003e\n\n## Installation\n\n```shell\nnpm i -D @cwqt/refract\nyarn add -D @cwqt/refract\n```\n\n## Usage\n\nSee [here for a full demo](./DEMO.md).\n\n- [Models](#model)\n- [Scalars](#scalars)\n  - [`@db` attributes](#--db--attributes)\n- [Relationships](#relationships)\n  - [Examples](#examples)\n    - [OneToOne](#onetoone)\n    - [Implicit ManyToMany](#implicit-manytomany)\n    - [Ambiguous relations](#ambiguous-relations)\n    - [Referentials Actions](#referentials-actions)\n- [Enums](#enums)\n- [Blocks](#blocks)\n- [Mixins](#mixins)\n- [Handling circular relationships](#handling-circular-relationships)\n\n---\n\nUse the `Refract` default export of this package to generate a Prisma file.\n\n```typescript\n// schema.ts\n\n// Import the entry-point\nimport Refract from '@cwqt/refract';\n// Import your custom Models\nimport { Roles, User, Posts } from './models';\n\nRefract({\n  // Supply models/enums for generation\n  schema: [Roles, User, Posts],\n  // https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#datasource\n  datasource: {\n    provider: 'postgresql',\n    url: 'env(\"DATABASE_URL\")',\n    shadowDatabaseUrl: 'env(\"DATABASE_SHADOW_URL\")',\n    referentialIntegrity: 'prisma',\n  },\n  // https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#generator\n  generators: [\n    {\n      provider: 'prisma-client-js',\n      previewFeatures: ['referentialIntegrity'],\n      engineType: 'library',\n      binaryTargets: ['native'],\n    },\n  ],\n  // Define output path for generated Prisma file\n  output: path.join(process.cwd(), 'schema.prisma'),\n});\n```\n\nA command like `npx ts-node schema.ts` will run this TypeScript code \u0026 generate\nthe resulting Prisma file at the `output` path.\n\n# Models\n\n```typescript\nconst User = Model('User', 'This is an optional comment');\n\nUser.Field('id', Int(Id, Default('autoincrement()')), 'The primary key');\n\n// // This is an optional comment\n// model User {\n//    // The primary key\n//    id  Int @id @default(autoincrement())\n// }\n```\n\n`Model` uses a fluid interface, so you can chain the following methods:\n\n- `.Field(name, scalar)`: Add a scalar column to a Model\n- `.Relation(name, relation)`: Add a relationship to a Model\n- `.Block(compound)`: Add a block field, e.g. `@@id`, `@@unique`, `@@map`\n- `.Mixin(mixin)`: Inherit columns from a Mixin for compositional Models\n- `.Raw(value)`: Escape hatch into writing raw Prisma\n\n# Scalars\n\nScalars are the types of data that the column contains, `Int`, `String`\netc. You can define \u0026 re-use Scalars wherever in your models\n\n```typescript\nconst PrimaryKey = Int(Id, Default('autoincrement()'));\n\n// id Int   @id @default(\"autoincrement()\")\nm.Field('id', PrimaryKey);\n```\n\n## Modifiers\n\nModifiers are functions/objects that append attributes to a column e.g.\n\n```typescript\n// String? @default(\"Hello World\")\nString(Default('Hello World'), Nullable);\n\n// Int @id @unique @default(autoincrement())\nInt(Id, Unique, Default('autoincrement()'));\n\n// DateTime @default(now()) @updatedAt\nDateTime(Default('now()'), UpdatedAt);\n```\n\nCertain modifiers are constrained to certain scalars, the mapping is:\n\n- `String`: Unique, Id, Default(string | 'auto()'), Limit(number)\n- `Int`: Unique, Id, Default('cuid' | 'autoincrement()' | 'uuid()' | number)\n- `Float`: Unique, Default(number)\n- `BigInt`: Unique, Default(BigInt)\n- `Bytes`: Unique\n- `Decimal`: Unique\n- `Boolean`: Unique\n- `DateTime`: Default('now()'), UpdatedAt\n- `Unsupported`\n\nAdditionally all scalars can use: Nullable, Map, Ignore, Raw \u0026 Array modifiers.\n\nThe `Raw()` modifier can be used as an escape hatch:\n\n```typescript\n// String  @db.ObjectId\nString(Raw('@db.ObjectId'));\n```\n\n## `@db` attributes\n\nCurrently there's support for `mysql`, `postgresql`, `cockroachdb` \u0026 `mongodb` `@db`\nattributes, and can be used like all the other modifiers.\n\n```typescript\nimport { MySql as db } from '@cwqt/refract';\n\n// email String @db.VarChar(255)\nm.Field('email', String(db.VarChar(255)));\n```\n\nCheck `src/public/db/mysql.ts` (`mongo.ts`/`postgresql.ts`/`cockroach.ts`) for list of mappings between scalar types \u0026\nattributes.\n\n# Relationships\n\n- `OneToMany` (model, name?, ...modifiers)\n  - Nullable\n- `OneToOne` (model, name?, fields, references, ...modifiers)\n- `OneToOne` (model, name?, ...modifiers)\n  - Nullable, OnUpdate(Action), OnDelete(Action)\n- `ManyToOne` (model, name?, fields, references, ...modifiers)\n  - Nullable, OnUpdate(Action), OnDelete(Action)\n\nWhere `Action` is one of: `Cascade`, `Restrict`, `NoAction`, `SetNull`, `SetDefault`\n\n## Examples\n\n### OneToOne\n\n\u003c!-- prettier-ignore --\u003e\n```typescript\nconst User = Model('User');\nconst Something = Model('Something');\n\nSomething\n  .Field('id', PrimaryKey)\n  // Holds foreign key\n  .Field('userId', Int())\n  .Relation('user', OneToOne(User, Fields('userId'), References('id')));\n  // Alternatively you can do Fields('userId', Int()) to avoid the extra\n  // .Field() call, this'll add the column to the model for you\n\nUser\n  .Field('id', PrimaryKey)\n  .Relation('thingy', OneToOne(Something));\n```\n\n### Implicit ManyToMany\n\n\u003chttps://www.prisma.io/docs/concepts/components/prisma-schema/relations/many-to-many-relations#implicit-many-to-many-relations\u003e\n\n\u003c!-- prettier-ignore --\u003e\n```typescript\nconst Post = Model('Post');\nconst Category = Model('Category');\n\nPost\n  .Field('id',            Int(Id, Default('autoincrement()')))\n  .Relation('categories', OneToMany(Category));\n\nCategory\n  .Field('id',            Int(Id, Default('autoincrement()')))\n  .Relation('posts',      OneToMany(Post));\n```\n\n### [Ambiguous relations](https://www.prisma.io/docs/concepts/components/prisma-schema/relations#disambiguating-relations)\n\nThe 2nd parameter of the Relation can be a string \u0026 explicitly denote the name\nof the relation.\n\n```typescript\n// pinnedBy   User?   @relation(name: \"PinnedPost\", fields: [pinnedById], references: [id])\nm.Relation(\n  'pinnedBy',\n  OneToOne(\n    User,\n    'PinnedPost',\n    Fields('pinnedById'),\n    References('id'),\n    Nullable,\n  ),\n);\n```\n\n### Referentials Actions\n\n`OnUpdate` \u0026 `OnDelete` modifiers can be used as follows:\n\n```typescript\n// tag    Tag?  @relation(fields: [tagId], references: [id], onUpdate: Cascade, onDelete: Cascade)\nm.Relation(\n  'tag',\n  ManyToOne(\n    Fields('tagId'),\n    References('id'),\n    OnUpdate('Cascade'),\n    OnDelete('Cascade'),\n    Nullable,\n  ),\n);\n```\n\n# Enums\n\nComposed of two parts:\n\n- `Enum(name, comment?, ...Key)`\n- `Key(value, ...modifiers, comment?)`\n  - Map\n\n\u003c!-- prettier-ignore --\u003e\n```typescript\nconst Animal = Enum(\n  'Animal',\n  Key('Seacow'),\n  Key('Capybara'),\n  Key('Otter', Map('otter')),\n);\n\n// fave  Animal @default(Seacow)\n// null  Animal?\nmodel\n  .Field('fave', Animal('Seacow'))\n  .Field('null', Animal());\n\nconst WithComment = Enum(\n  \"Foo\", \"This is with a comment\",\n  Key(\"Bar\", \"Another comment\")\n);\n// // This is with a comment\n// enum Foo {\n//  // Another comment\n//  Bar\n// }\n```\n\n# Blocks\n\nUsed for adding fields like `@@map`, `@@id`, `@@fulltext` etc.\n\n```typescript\nimport { Compound, Mongo as db } from '@cwqt/refract';\n\n// Creating a compound index\nmodel\n  .Field('id', Int(Id, Default('autoincrement()')))\n  .Field('authorId', Int())\n  .Relation('author', ManyToOne(User, Fields('authorId'), References('id')))\n  .Block(Compound.Id('id', 'authorId'));\n\n// e.g. in MongoDB schemas\nModel('User')\n  .Field('id', String(Id, db.ObjectId, Map('_id')))\n  .Block(Compound.Map('users'));\n```\n\n# Mixins\n\nAllows you to re-use groups of fields, compositional models.\n\n```typescript\nconst Timestamps = Mixin()\n  .Field('createdAt', DateTime(Default('now()')))\n  .Field('updatedAt', DateTime(Nullable, UpdatedAt));\n\nconst User = Model('User').Field('id', PrimaryKey).Mixin(Timestamps);\n\n// User will now have `createdAt` \u0026 `updatedAt` columns\n```\n\n## Programmatic usage\n\n```typescript\nconst prisma = Refract.generate({\n  datasource: {...},\n  generators: [...],\n  schema\n})\n\nconsole.log(prisma); // schema.prisma contents\n```\n\n---\n\n# Handling circular relationships\n\nAt some point you'll want to split the schema across files, which introduces issues with circular relationships when you're importing for `.Relation()`s in Node\n\nOne way to get around this is to have a file with all the models/enums defined, and have files import those \u0026 apply the fields, e.g.\n\n```typescript\n// models.ts ------------------------------\nconst User = Model(\"User\");\nconst Post = Model(\"Posts\");\n// ... and all the other Models\n\n// users.ts ------------------------------\nimport { User, Post } from './models'\n\nUser\n  .Field(\"id\",        Int(Id, Default(\"autoincrement()\")))\n  .Relation(\"posts\",  OneToMany(Post))\n\n// posts.ts  ------------------------------\nimport { User, Post } from './models'\n\nPost\n  .Field(\"id\",        Int(Id, Default(\"autoincrement()\")))\n  .Field(\"authorId\",  Int())\n  .Relation(\"author\", ManyToOne(User, Fields(\"authorId\"), References(\"id\")))\n\n// refract.ts ------------------------------\nimport * as schema from './models'\n\n// IMPORTANT: import the model files which performs the `.Field()`, `.Relation()`\n// etc. calls, thereby adding the columns to the models\nimport \"./posts\";\nimport \"./users\";\n\nRefract({\n  datasource: {...},\n  generators: [...],\n  schema\n})\n```\n\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"https://ftp.cass.si/=799p94e7.png\" width=\"40%\" \u003e\n\u003c/div\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcwqt%2Frefract","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcwqt%2Frefract","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcwqt%2Frefract/lists"}