Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/theogravity/objection-generator
Generates knex migrations and objection.js models in Typescript from a YAML spec
https://github.com/theogravity/objection-generator
generator knex knexjs migrate model objection objectionjs orm schema typescript yaml
Last synced: about 20 hours ago
JSON representation
Generates knex migrations and objection.js models in Typescript from a YAML spec
- Host: GitHub
- URL: https://github.com/theogravity/objection-generator
- Owner: theogravity
- License: mit
- Created: 2020-05-09T17:50:26.000Z (over 4 years ago)
- Default Branch: master
- Last Pushed: 2023-01-11T05:30:27.000Z (almost 2 years ago)
- Last Synced: 2024-09-13T03:18:19.422Z (2 months ago)
- Topics: generator, knex, knexjs, migrate, model, objection, objectionjs, orm, schema, typescript, yaml
- Language: TypeScript
- Homepage:
- Size: 396 KB
- Stars: 13
- Watchers: 3
- Forks: 3
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
Awesome Lists containing this project
README
# objection-generator
[![NPM version](https://img.shields.io/npm/v/objection-generator.svg?style=flat-square)](https://www.npmjs.com/package/objection-generator)
[![CircleCI](https://circleci.com/gh/theogravity/objection-generator.svg?style=svg)](https://circleci.com/gh/theogravity/objection-generator)
![built with typescript](https://camo.githubusercontent.com/92e9f7b1209bab9e3e9cd8cdf62f072a624da461/68747470733a2f2f666c61742e62616467656e2e6e65742f62616467652f4275696c74253230576974682f547970655363726970742f626c7565)
[![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)Generates [`objection.js`](https://github.com/vincit/objection.js) models in Typescript
from a YAML specification.- Generate your initial set of `objection.js` models from a YAML file
- Supports `$ref` for re-using common definitions
- Can also generate a basic [`knex`](http://knexjs.org/) migration file based on the YAML file- [Installation](#installation)
- [Install the CLI utility](#install-the-cli-utility)
- [Install knex + objection (if you do not have it installed)](#install-knex--objection-if-you-do-not-have-it-installed)
- [Usage](#usage)
- [Objection.js model generation](#objectionjs-model-generation)
- [Sample output](#sample-output)
- [Knex configuration](#knex-configuration)
- [Knex migration generation](#knex-migration-generation)
- [Limitations](#limitations)
- [Usage](#usage-1)
- [Sample output](#sample-output-1)
- [Run the migration](#run-the-migration)
- [YAML spec](#yaml-spec)# Installation
## Install the CLI utility
`$ npm i objection-generator -g`
## Install knex + objection (if you do not have it installed)
`$ npm i knex objection --save`
# Usage
## Objection.js model generation
`$ objection-generator generate `
```bash
objection-generator generateGenerates objection.js models from a YAML file
Positionals:
specFile The YAML file to use to generate models. [string] [required]
outDir The directory to output the models. [string] [required] [string] [required]
```### Sample output
Using the `sample.yaml` spec in this project:
`$ objection-generator generate sample.yaml /tmp/lib`
Will generate the following folder structure:
```
/tmp/lib/
├── models/
│ ├── BaseModel.ts
│ ├── .ts
```Will generate models that look like this:
```typescript
import { Model } from 'objection'
import path from 'path'import { BaseModel } from './BaseModel'
export enum PersonGenderEnum {
MALE = 'Male',
FEMALE = 'Female',
OTHER = 'Other'
}
export enum PersonFavFoodEnum {
PINE_APPLE = 'pine-apple',
BLUE_BERRY = 'blueBerry',
CHEESE_PIZZA = 'cheese_pizza'
}export class PersonModel extends BaseModel {
id: string
name: string
age: number | null
gender: PersonGenderEnum
favFood: PersonFavFoodEnum
username: string
created: stringstatic tableName = 'persons'
static get jsonSchema () {
return {
type: 'object',
required: ['name', 'username'],
properties: {
id: {
type: 'string'
},
name: {
type: 'string',
minLength: 1,
maxLength: 100
},
age: {
type: ['number', 'null']
},
gender: {
type: 'string',
enum: ['Male', 'Female', 'Other'],
default: 'Female'
},
favFood: {
type: 'string',
enum: ['pine-apple', 'blueBerry', 'cheese_pizza']
},
username: {
type: 'string',
minLength: 1,
maxLength: 25,
default: 'default-user'
},
created: {
type: 'string',
format: 'date-time'
}
}
}
}static get relationMappings () {
return {
movies: {
relation: Model.ManyToManyRelation,
modelClass: path.join(__dirname, 'MovieModel'),
join: {
from: 'persons.id',
through: {
from: 'persons_movies.personId',
to: 'persons_movies.movieId'
},
to: 'movies.id'
}
},
reviews: {
relation: Model.HasManyRelation,
modelClass: path.join(__dirname, 'ReviewModel'),
join: {
from: 'persons.id',
to: 'review.authorId'
}
}
}
}
}
```## Knex configuration
You must use [`knexSnakeCaseMappers`](https://vincit.github.io/objection.js/api/objection/#knexsnakecasemappers)
in your `knex` configuration.```typescript
import { knexSnakeCaseMappers } from 'objection'
import knex from 'knex'const db = knex({
client: 'postgres',connection: {
host: '127.0.0.1',
user: 'objection',
database: 'objection_test'
},
// allows usage of camel cased names in the model
// and snake cased fields in the database
...knexSnakeCaseMappers()
})
```## Knex migration generation
The YAML can also be used to generate a basic migration file. This can be used as a
good starting base for building a desired migration.### Limitations
There are many limitations to the generation since there is not an exact mapping
between JSON schema types / information in the objection models to an exact database
specification.Some limitations include:
- No foreign keys are generated (PRs welcomed - make use of the `relations` please)
- No through tables are generatedPRs are welcomed for improvements!
### Usage
`$ objection-generator knex `
```bash
objection-generator knexGenerates a basic knex migration from a YAML file
Positionals:
specFile The YAML file to use to generate models. [string] [required]
outDir The directory to output the models. [string] [required] [string] [required]
```### Sample output
Using the `sample.yaml` spec in this project:
`$ objection-generator knex sample.yaml /tmp/lib`
Will generate the following folder structure:
```
/tmp/lib/
├── migrations/
│ └── 000-init.js
└── migrate.js
```Example migration output:
```js
async function up (knex) {
await knex.schema.createTable('persons', table => {
table.string('id')
table.string('name', 100).notNullable()
table.integer('age')
table.enu('gender', ['Male', 'Female', 'Other']).defaultTo('Female')
table
.string('username', 25)
.notNullable()
.defaultTo('default-user')
table.datetime('created')table.primary(['id'])
table.unique(['username'], 'uniq_username')
table.index(['age', 'name'], 'name_age_index')
})
await knex.schema.createTable('movies', table => {
table.string('id')
table.string('name', 255).notNullable()table.primary(['id'])
})
await knex.schema.createTable('reviews', table => {
table.string('review_id')
table.string('author_id').notNullable()
table.string('movie_id').notNullable()
table.string('content')table.primary(['review_id'])
})
}async function down (knex) {
await knex.schema.dropTable('persons')
await knex.schema.dropTable('movies')
await knex.schema.dropTable('reviews')
}module.exports = {
up,
down
}
```### Run the migration
The output includes a sample migration script that uses `sqlite3` as the
database driver for quick prototyping.`$ npm i sqlite3 --save-dev`
`$ node /migrate.js`
Modify this file to your liking to work with your own database.
# YAML spec
See `sample.yaml` for an example spec.
```yaml
config:
model:
# Adds a prefix to the class names of the generated objection.js models
classNamePrefix:
# Adds a postfix to the class names of the generated objection.js models
classNamePostfix: Model# Objection models to generate
models:
# Defines an objection model named Person (actually PersonModel with the postfix)
Person:
# database table name
tableName: persons
# maps to Model#jsonSchema()
# https://json-schema.org/understanding-json-schema/reference/type.html
# https://vincit.github.io/objection.js/guide/models.html#examples
jsonSchema:
required: ['name', 'username']
properties:
id:
type: string
name:
type: string
minLength: 1
maxLength: 100
age:
# You can define a re-usable set of properties and reference them via $ref
$ref: '#/components/fieldProperties/age'
gender:
type: string
enum: ['Male', 'Female', 'Other']
default: 'Female'
favFood:
type: string
enum: ['pine-apple', 'blueBerry', 'cheese_pizza']
childrenCount:
type: number
default: 0
username:
allOf:
# combine a ref and a non-ref, see json schema spec for more info
- $ref: '#/components/fieldProperties/username'
- default: 'default-user'
someOtherField:
type: string
created:
type: string
format: date-time
# Define relations - maps to Model#relationMappings()
# https://vincit.github.io/objection.js/guide/relations.html#examples
relations:
movies:
relation: Model.ManyToManyRelation
modelClass: Movie
join:
from: persons.id
through:
from: persons_movies.personId
to: persons_movies.movieId
to: movies.id
reviews:
relation: Model.HasManyRelation
modelClass: Review
join:
from: persons.id
to: review.authorId
# Section for knex-specific generation
database:
# define unique indices
unique:
# made-up name for the unique index
uniq_username:
# columns to add to unique index
# values will always be converted to snake case
columns: ['username']
# Define indices
index:
# made-up name for the index
name_age_index:
# columns to index
# values will always be converted to snake case
columns: ['age', 'name']
exclude:
# exclude these fields from being generated in the migration file
# this is if you want to have a field defined in the model
# but not in the database
columns: ['someOtherField']
Movie:
tableName: movies
jsonSchema:
required: ['name']
properties:
id:
type: string
name:
type: string
minLength: 1
maxLength: 255
relations:
reviews:
relation: Model.HasManyRelation
modelClass: Review
join:
from: movie.id
to: review.movieId
Review:
tableName: reviews
# If you want to use a primary key that's not called "id"
idColumn: reviewId
jsonSchema:
required: ['authorId', 'movieId']
properties:
reviewId:
type: string
authorId:
type: string
movieId:
type: string
content:
type: string
relations:
author:
relation: Model.HasOneRelation
modelClass: Person
join:
from: reviews.authorId
to: persons.id# components are re-usable elements that can be
# referenced in the model via $ref
components:
# This is a made up section used for
# defining common field properties
fieldProperties:
age:
type: ['number', 'null']
username:
type: string
minLength: 1
maxLength: 25
```