{"id":20182954,"url":"https://github.com/theogravity/objection-generator","last_synced_at":"2025-04-10T05:23:53.913Z","repository":{"id":38007079,"uuid":"262627087","full_name":"theogravity/objection-generator","owner":"theogravity","description":"Generates knex migrations and objection.js models in Typescript from a YAML spec","archived":false,"fork":false,"pushed_at":"2023-01-11T05:30:27.000Z","size":405,"stargazers_count":13,"open_issues_count":1,"forks_count":3,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-24T06:45:25.401Z","etag":null,"topics":["generator","knex","knexjs","migrate","model","objection","objectionjs","orm","schema","typescript","yaml"],"latest_commit_sha":null,"homepage":"","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/theogravity.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-05-09T17:50:26.000Z","updated_at":"2024-06-07T10:36:38.000Z","dependencies_parsed_at":"2023-02-09T01:45:49.873Z","dependency_job_id":null,"html_url":"https://github.com/theogravity/objection-generator","commit_stats":null,"previous_names":[],"tags_count":18,"template":false,"template_full_name":"theogravity/boilerplate-typescript-old","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theogravity%2Fobjection-generator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theogravity%2Fobjection-generator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theogravity%2Fobjection-generator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theogravity%2Fobjection-generator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/theogravity","download_url":"https://codeload.github.com/theogravity/objection-generator/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248161732,"owners_count":21057643,"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":["generator","knex","knexjs","migrate","model","objection","objectionjs","orm","schema","typescript","yaml"],"created_at":"2024-11-14T02:43:27.711Z","updated_at":"2025-04-10T05:23:53.891Z","avatar_url":"https://github.com/theogravity.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# objection-generator\n\n[![NPM version](https://img.shields.io/npm/v/objection-generator.svg?style=flat-square)](https://www.npmjs.com/package/objection-generator)\n[![CircleCI](https://circleci.com/gh/theogravity/objection-generator.svg?style=svg)](https://circleci.com/gh/theogravity/objection-generator) \n![built with typescript](https://camo.githubusercontent.com/92e9f7b1209bab9e3e9cd8cdf62f072a624da461/68747470733a2f2f666c61742e62616467656e2e6e65742f62616467652f4275696c74253230576974682f547970655363726970742f626c7565) \n[![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)\n\nGenerates [`objection.js`](https://github.com/vincit/objection.js) models in Typescript \nfrom a YAML specification.\n\n- Generate your initial set of `objection.js` models from a YAML file\n- Supports `$ref` for re-using common definitions\n- Can also generate a basic [`knex`](http://knexjs.org/) migration file based on the YAML file\n\n\u003c!-- TOC --\u003e\n- [Installation](#installation)\n  - [Install the CLI utility](#install-the-cli-utility)\n  - [Install knex + objection (if you do not have it installed)](#install-knex--objection-if-you-do-not-have-it-installed)\n- [Usage](#usage)\n  - [Objection.js model generation](#objectionjs-model-generation)\n    - [Sample output](#sample-output)\n  - [Knex configuration](#knex-configuration)\n  - [Knex migration generation](#knex-migration-generation)\n    - [Limitations](#limitations)\n    - [Usage](#usage-1)\n    - [Sample output](#sample-output-1)\n    - [Run the migration](#run-the-migration)\n- [YAML spec](#yaml-spec)\n\n\u003c!-- TOC END --\u003e\n\n# Installation\n\n## Install the CLI utility\n\n`$ npm i objection-generator -g`\n\n## Install knex + objection (if you do not have it installed)\n\n`$ npm i knex objection --save`\n\n# Usage\n\n## Objection.js model generation\n\n`$ objection-generator generate \u003cspecFile\u003e \u003coutDir\u003e`\n\n```bash\nobjection-generator generate \u003cspecFile\u003e \u003coutDir\u003e\n\nGenerates objection.js models from a YAML file\n\nPositionals:\n  specFile  The YAML file to use to generate models.                                         [string] [required]\n  outDir    The directory to output the models.                                              [string] [required]                                                [string] [required]\n```\n\n### Sample output\n\nUsing the `sample.yaml` spec in this project:\n\n`$ objection-generator generate sample.yaml /tmp/lib`\n\nWill generate the following folder structure:\n\n```\n/tmp/lib/\n├── models/\n│   ├── BaseModel.ts\n│   ├── \u003cmodel\u003e.ts\n```\n\nWill generate models that look like this:\n\n```typescript\nimport { Model } from 'objection'\nimport path from 'path'\n\nimport { BaseModel } from './BaseModel'\n\nexport enum PersonGenderEnum {\n  MALE = 'Male',\n  FEMALE = 'Female',\n  OTHER = 'Other'\n}\nexport enum PersonFavFoodEnum {\n  PINE_APPLE = 'pine-apple',\n  BLUE_BERRY = 'blueBerry',\n  CHEESE_PIZZA = 'cheese_pizza'\n}\n\nexport class PersonModel extends BaseModel {\n  id: string\n  name: string\n  age: number | null\n  gender: PersonGenderEnum\n  favFood: PersonFavFoodEnum\n  username: string\n  created: string\n\n  static tableName = 'persons'\n\n  static get jsonSchema () {\n    return {\n      type: 'object',\n      required: ['name', 'username'],\n      properties: {\n        id: {\n          type: 'string'\n        },\n        name: {\n          type: 'string',\n          minLength: 1,\n          maxLength: 100\n        },\n        age: {\n          type: ['number', 'null']\n        },\n        gender: {\n          type: 'string',\n          enum: ['Male', 'Female', 'Other'],\n          default: 'Female'\n        },\n        favFood: {\n          type: 'string',\n          enum: ['pine-apple', 'blueBerry', 'cheese_pizza']\n        },\n        username: {\n          type: 'string',\n          minLength: 1,\n          maxLength: 25,\n          default: 'default-user'\n        },\n        created: {\n          type: 'string',\n          format: 'date-time'\n        }\n      }\n    }\n  }\n\n  static get relationMappings () {\n    return {\n      movies: {\n        relation: Model.ManyToManyRelation,\n        modelClass: path.join(__dirname, 'MovieModel'),\n        join: {\n          from: 'persons.id',\n          through: {\n            from: 'persons_movies.personId',\n            to: 'persons_movies.movieId'\n          },\n          to: 'movies.id'\n        }\n      },\n      reviews: {\n        relation: Model.HasManyRelation,\n        modelClass: path.join(__dirname, 'ReviewModel'),\n        join: {\n          from: 'persons.id',\n          to: 'review.authorId'\n        }\n      }\n    }\n  }\n}\n```\n\n## Knex configuration\n\nYou must use [`knexSnakeCaseMappers`](https://vincit.github.io/objection.js/api/objection/#knexsnakecasemappers) \nin your `knex` configuration.\n\n```typescript\nimport { knexSnakeCaseMappers } from 'objection'\nimport knex from 'knex'\n\nconst db = knex({\n  client: 'postgres',\n\n  connection: {\n    host: '127.0.0.1',\n    user: 'objection',\n    database: 'objection_test'\n  },\n  // allows usage of camel cased names in the model\n  // and snake cased fields in the database\n  ...knexSnakeCaseMappers()\n})\n```\n\n## Knex migration generation\n\nThe YAML can also be used to generate a basic migration file. This can be used as a\ngood starting base for building a desired migration.\n\n### Limitations\n\nThere are many limitations to the generation since there is not an exact mapping\nbetween JSON schema types / information in the objection models to an exact database\nspecification.\n\nSome limitations include:\n\n- No foreign keys are generated (PRs welcomed - make use of the `relations` please)\n- No through tables are generated\n\nPRs are welcomed for improvements!\n\n### Usage\n\n`$ objection-generator knex \u003cspecFile\u003e \u003coutDir\u003e`\n\n```bash\nobjection-generator knex \u003cspecFile\u003e \u003coutDir\u003e\n\nGenerates a basic knex migration from a YAML file\n\nPositionals:\n  specFile  The YAML file to use to generate models.                                         [string] [required]\n  outDir    The directory to output the models.                                              [string] [required]                                      [string] [required]\n```\n\n### Sample output\n\nUsing the `sample.yaml` spec in this project:\n\n`$ objection-generator knex sample.yaml /tmp/lib`\n\nWill generate the following folder structure:\n\n```\n/tmp/lib/\n├── migrations/\n│   └── 000-init.js\n└── migrate.js\n```\n\nExample migration output:\n\n```js\nasync function up (knex) {\n  await knex.schema.createTable('persons', table =\u003e {\n    table.string('id')\n    table.string('name', 100).notNullable()\n    table.integer('age')\n    table.enu('gender', ['Male', 'Female', 'Other']).defaultTo('Female')\n    table\n      .string('username', 25)\n      .notNullable()\n      .defaultTo('default-user')\n    table.datetime('created')\n\n    table.primary(['id'])\n\n    table.unique(['username'], 'uniq_username')\n\n    table.index(['age', 'name'], 'name_age_index')\n  })\n  await knex.schema.createTable('movies', table =\u003e {\n    table.string('id')\n    table.string('name', 255).notNullable()\n\n    table.primary(['id'])\n  })\n  await knex.schema.createTable('reviews', table =\u003e {\n    table.string('review_id')\n    table.string('author_id').notNullable()\n    table.string('movie_id').notNullable()\n    table.string('content')\n\n    table.primary(['review_id'])\n  })\n}\n\nasync function down (knex) {\n  await knex.schema.dropTable('persons')\n  await knex.schema.dropTable('movies')\n  await knex.schema.dropTable('reviews')\n}\n\nmodule.exports = {\n  up,\n  down\n}\n```\n\n### Run the migration\n\nThe output includes a sample migration script that uses `sqlite3` as the\ndatabase driver for quick prototyping. \n\n`$ npm i sqlite3 --save-dev`\n\n`$ node \u003coutputDir\u003e/migrate.js`\n\nModify this file to your liking to work with your own database.\n\n# YAML spec\n\nSee `sample.yaml` for an example spec.\n\n```yaml\nconfig:\n  model:\n    # Adds a prefix to the class names of the generated objection.js models\n    classNamePrefix:\n    # Adds a postfix to the class names of the generated objection.js models\n    classNamePostfix: Model\n\n# Objection models to generate\nmodels:\n  # Defines an objection model named Person (actually PersonModel with the postfix)\n  Person:\n    # database table name\n    tableName: persons\n    # maps to Model#jsonSchema()\n    # https://json-schema.org/understanding-json-schema/reference/type.html\n    # https://vincit.github.io/objection.js/guide/models.html#examples\n    jsonSchema:\n      required: ['name', 'username']\n      properties:\n        id:\n          type: string\n        name:\n          type: string\n          minLength: 1\n          maxLength: 100\n        age:\n          # You can define a re-usable set of properties and reference them via $ref\n          $ref: '#/components/fieldProperties/age'\n        gender:\n          type: string\n          enum: ['Male', 'Female', 'Other']\n          default: 'Female'\n        favFood:\n          type: string\n          enum: ['pine-apple', 'blueBerry', 'cheese_pizza']\n        childrenCount:\n          type: number\n          default: 0\n        username:\n          allOf:\n            # combine a ref and a non-ref, see json schema spec for more info\n            - $ref: '#/components/fieldProperties/username'\n            - default: 'default-user'\n        someOtherField:\n          type: string\n        created:\n          type: string\n          format: date-time\n    # Define relations - maps to Model#relationMappings()\n    # https://vincit.github.io/objection.js/guide/relations.html#examples\n    relations:\n      movies:\n        relation: Model.ManyToManyRelation\n        modelClass: Movie\n        join:\n          from: persons.id\n          through:\n            from: persons_movies.personId\n            to: persons_movies.movieId\n          to: movies.id\n      reviews:\n        relation: Model.HasManyRelation\n        modelClass: Review\n        join:\n          from: persons.id\n          to: review.authorId\n    # Section for knex-specific generation\n    database:\n      # define unique indices\n      unique:\n        # made-up name for the unique index\n        uniq_username:\n          # columns to add to unique index\n          # values will always be converted to snake case\n          columns: ['username']\n      # Define indices\n      index:\n        # made-up name for the index\n        name_age_index:\n          # columns to index\n          # values will always be converted to snake case\n          columns: ['age', 'name']\n      exclude:\n        # exclude these fields from being generated in the migration file\n        # this is if you want to have a field defined in the model\n        # but not in the database\n        columns: ['someOtherField']\n  Movie:\n    tableName: movies\n    jsonSchema:\n      required: ['name']\n      properties:\n        id:\n          type: string\n        name:\n          type: string\n          minLength: 1\n          maxLength: 255\n    relations:\n      reviews:\n        relation: Model.HasManyRelation\n        modelClass: Review\n        join:\n          from: movie.id\n          to: review.movieId\n  Review:\n    tableName: reviews\n    # If you want to use a primary key that's not called \"id\"\n    idColumn: reviewId\n    jsonSchema:\n      required: ['authorId', 'movieId']\n      properties:\n        reviewId:\n          type: string\n        authorId:\n          type: string\n        movieId:\n          type: string\n        content:\n          type: string\n    relations:\n      author:\n        relation: Model.HasOneRelation\n        modelClass: Person\n        join:\n          from: reviews.authorId\n          to: persons.id\n\n# components are re-usable elements that can be\n# referenced in the model via $ref\ncomponents:\n  # This is a made up section used for\n  # defining common field properties\n  fieldProperties:\n    age:\n      type: ['number', 'null']\n    username:\n      type: string\n      minLength: 1\n      maxLength: 25\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftheogravity%2Fobjection-generator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftheogravity%2Fobjection-generator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftheogravity%2Fobjection-generator/lists"}