---
head:
  - - meta
    - name: description
      content: Use Objection.js with Express, TypeScript and Ts.ED.
  - - meta
    - name: keywords
      content: ts.ed express typescript objection.js node.js javascript decorators
---
# Objection.js

<Badge text="Contributors are welcome" />

This tutorial show yous how you can use [Objection.js](https://vincit.github.io/objection.js/) package with Ts.ED.

## Installation

Before using the `@tsed/objection` package, we need to install
the [Obection.js](https://www.npmjs.com/package/objection) and [Knex](https://www.npmjs.com/package/knex) modules.

Install the dependencies:

::: code-group

```sh [npm]
npm install --save @tsed/objection objection knex
```

```sh [yarn]
yarn add @tsed/objection objection knex
```

```sh [pnpm]
pnpm add @tsed/objection objection knex
```

```sh [bun]
bun add @tsed/objection objection knex
```

:::

We also need to install one of the following depending on the database you want to use:

::: code-group

```sh [npm]
npm install pg
npm install sqlite3
npm install mysql
npm install mysql2
```

```sh [yarn]
yarn add pg
yarn add sqlite3
yarn add mysql
yarn add mysql2
```

```sh [pnpm]
pnpm add pg
pnpm add sqlite3
pnpm add mysql
pnpm add mysql2
```

```sh [bun]
bun add pg
bun add sqlite3
bun add mysql
bun add mysql2
```

:::

## Configuration

Add a `knex` configuration to your Ts.ED configuration (see: http://knexjs.org/#Installation-client for options):

```typescript
import {Server} from "@tsed/platform-http";
import "@tsed/objection"; // don't forget to add this line!

@Configuration({
  // ...
  knex: {
    client: "sqlite3",
    connection: ":memory:"
  }
})
class Server {}
```

## Usage

You can use the [Entity](/ai/api/orm/objection/types/decorators/decorator-entity.md) decorator to create your models and make them work with Objection.js. `Entity` expects the
table name as its argument.

```typescript
import {Required, MinLength, MaxLength} from "@tsed/schema";
import {Inject} from "@tsed/di";
import {Entity, IdColumn} from "@tsed/objection";
import {Model} from "objection";

@Entity("users")
export class User extends Model {
  @IdColumn()
  id: number;

  @Property()
  @MaxLength(200)
  name: string;

  @Property()
  age: number;

  @Decimal({scale: 1, precision: 12})
  score: number;

  @Property()
  active: boolean;
}
```

## Relationships

Ts.ED enables you to define relationships between models on properties directly, using decorators such as
[BelongsToOne](/ai/api/orm/objection/types/decorators/decorator-belongs-to-one.md), [HasMany](/ai/api/orm/objection/types/decorators/decorator-has-many.md), [HasOne](/ai/api/orm/objection/types/decorators/decorator-has-one.md), [HasOneThroughRelation](/ai/api/orm/objection/types/decorators/decorator-has-one-through-relation.md), [ManyToMany](/ai/api/orm/objection/types/decorators/decorator-many-to-many.md) or [RelatesTo](/ai/api/orm/objection/types/decorators/decorator-relates-to.md).

You can supply a configuration object via ([RelationshipOpts](/ai/api/orm/objection/types/domain/type-relationship-opts.md)) into the decorator factor to override the default join
keys and configure a relationship like you normally would via `relationMappings`. For collection-type relationships, you
must also specify the model you wish to use and we will also apply the [CollectionOf](/ai/api/specs/schema/types/decorators/collections/decorator-collection-of.md) decorator for you automatically.

This expressive usage ensures that your domain models are correctly typed for usage
alongside [Objection.js's Graph API](https://vincit.github.io/objection.js/api/query-builder/eager-methods.html).

```typescript
/**
 * All work in a similar manner:
 * - @HasMany, @HasOne, @HasOneThroughRelation, @ManyToMany, @RelatesTo
 */
import {Entity, BelongsToOne} from "@tsed/objection";

@Entity("user")
class User extends Model {
  @IdColumn()
  id!: string;
}

@Entity("movie")
class Movie extends Model {
  @IdColumn()
  id!: string;

  ownerId!: string;

  @BelongsToOne()
  owner?: User;
}

// Retrieve the related user
const owner = await Movie.relatedQuery("owner").for(1);

// Retrieve the movie with their owner
const movie = await Movie.query().for(1).withGraphFetched("owner");
```

### Default joining keys

When used in conjunction with [Entity](/ai/api/orm/objection/types/decorators/decorator-entity.md) and [IdColumn](/ai/api/orm/objection/types/decorators/decorator-id-column.md), Ts.ED attempts to provide you with a sensible default for
your join keys out of the box, reducing the amount of boilerplate you need to write.

In the instance of [BelongsToOne](/ai/api/orm/objection/types/decorators/decorator-belongs-to-one.md), the default join keys will be:

```json
{
  "from": "<sourceModelTable>.<foreignModelProperty>Id",
  "to": "<foreignModelTable>.<foreignModelIdColumn>"
}
```

::: tip
An example of the keys outputted above could be `movie.ownerId` and `user.id` respectively.
:::

In the instances of [HasMany](/ai/api/orm/objection/types/decorators/decorator-has-many.md) and [HasOne](/ai/api/orm/objection/types/decorators/decorator-has-one.md), the default join keys will be:

```json
{
  "from": "<sourceModelTable>.<sourceModelIdColumn>",
  "to": "<foreignModelTable>.<sourceModelTable>Id"
}
```

::: tip
An example of the keys outputted above could be `user.id` and `authentication.userId` respectively.
:::

In the instances of [ManyToMany](/ai/api/orm/objection/types/decorators/decorator-many-to-many.md) and [HasOneThroughRelation](/ai/api/orm/objection/types/decorators/decorator-has-one-through-relation.md), the default join key will be:

```json
{
  "from": "<sourceModelTable>.<sourceModelIdColumn>",
  "through": {
    "from": "<sourceModelTable>_<foreignModelTable>.<sourceModelTable>Id",
    "to": "<sourceModelTable>_<foreignModelTable>.<foreignModelTable>Id"
  },
  "to": "<foreignModelTable>.<foreignModelIdColumn>"
}
```

::: tip
An example of the keys outputted above could be `user.id`, `user_authentication.userId`,
`user_authentication.authenticationId` and `authentication.id` respectively.
:::

## Get connection

```typescript
import {OBJECTION_CONNECTION} from "@tsed/objection";

@Injectable()
class MyService {
  @Inject(OBJECTION_CONNECTION)
  connection: OBJECTION_CONNECTION;

  $onInit() {
    console.log(this.connection);
  }
}
```

## Migration

Ts.ED can create columns based on the declared Model. Using `createColumns`, you can implement
a migration file as following:

```typescript
import {createColumns} from "@tsed/objection";
import {User} from "../domain/User";
import Knex from "objection";

export async function up(knex: Knex): Promise<any> {
  return knex.schema.createTable(User.tableName, async (table: Knex.TableBuilder) => {
    // createColumns for the given model
    createColumns(table, User);
  });
}

export async function down(knex: Knex): Promise<any> {
  return knex.schema.dropTable("users");
}
```

## Decorators

Ts.ED gives some decorators and services to write your code:

<ApiList query="status.includes('decorator') && status.includes('objection')" />

You can also use the common decorators to describe model (See [models](/docs/model.html) documentation):

<ApiList query="status.includes('decorator') && status.includes('schema')" />

## Author

<GithubContributors :users="['stefanvanherwijnen']"/>

## Maintainers

<GithubContributors :users="['stefanvanherwijnen']"/>

<div class="flex items-center justify-center p-5">
<Button href="/contributing.html" class="rounded-medium">
 Become maintainer
</Button>
</div>
