3.0.0 • Published 2 years ago

nestjs-objection v3.0.0

Weekly downloads
124
License
MIT
Repository
github
Last release
2 years ago

NestJS Objection

Table of Contents

Description

Integrates Objection.js and Knex with Nest

Installation

$ npm install nestjs-objection knex objection

You can also use the interactive CLI

npx nestjs-modules

Features

  • Decorators @InjectModel, @Table, @Column, @Relation
  • Synchronization synchronize(model, force?)
  • SoftDelete @Table({ softDelete: true })

Table options

NameTypeRequiredDefault
tableNamestringtrueclassName
softDeleteboolean / stringfalsefalse

Column options

NameTypeRequiredDefault
typecolumnTypestrue---
defaultanyfalse---
columnNamestringfalsefalse
nullablebooleanfalsefalse
notNullablebooleanfalsefalse
uniquebooleanfalsefalse
unsignedbooleanfalsefalse
primarybooleanfalsefalse

synchronize(model, force?)

NameTypeRequiredDefault
modelModeltrue---
forcebooleanfalsefalse

softDelete

MethodTypeOptionsReturn
deletefunction---QueryBuilder
softDeletefunction---QueryBuilder
forceDeletefunction---QueryBuilder
withDeletedfunction---QueryBuilder
onlyDeletedfunction---QueryBuilder
restorefunction---QueryBuilder

columnTypes

------------
incrementsbigIncrementsintegerbigInteger
textstringfloatdecimal
booleandatedatetimetime
timestamptimestampsbinaryjson
jsonbuuid

Examples

$ npm install nestjs-objection knex objection sqlite3

Models

// app.models.ts
import { 
  Model, Column, Relation, Table, relationTypes, columnTypes, 
} from 'nestjs-objection';

@Table({ tableName: 'posts' })
export class Post extends Model {
  @Column({ type: columnTypes.increments })
  id: number;
  @Column({ type: columnTypes.integer })
  userId: number;
  @Column({ type: columnTypes.string })
  title: string;
  @Column({ type: columnTypes.json })
  json: object;
}

@Table({ tableName: 'users' })
export class User extends Model {
  @Column({ type: columnTypes.increments })
  id: number;
  @Column({ type: columnTypes.string })
  name: string;
  @Relation({ 
    modelClass: Post, 
    relation: relationTypes.HasManyRelation, 
    join: { from: 'users.id', to: 'posts.userId' } 
  })
  posts: Post[];
}

ObjectionModule.forRoot(options, connection?)

// app.module.ts
import { Module } from '@nestjs/common';
import { ObjectionModule, Model } from 'nestjs-objection'
import { AppController } from './app.controller';
import { User, Post } from './app.models';

@Module({
  imports: [
    ObjectionModule.forRoot({
      Model,
      config: {
        client: "sqlite3",
        useNullAsDefault: true,
        connection: ':memory:',
      }
    }),
    ObjectionModule.forFeature([User, Post]),
  ],
  controllers: [AppController],
})
export class AppModule {}

ObjectionModule.forRootAsync(options, connection?)

// app.module.ts
import { Module } from '@nestjs/common';
import { ObjectionModule, Model } from 'nestjs-objection'
import { AppController } from './app.controller';
import { User, Post } from './app.models';

@Module({
  imports: [
    ObjectionModule.forRootAsync({
      useFactory: () => ({
        Model,
        config: {
          client: "sqlite3",
          useNullAsDefault: true,
          connection: ':memory:',
        },
      }),
    }),
    ObjectionModule.forFeature([User, Post]),
  ],
  controllers: [AppController],
})
export class AppModule {}

InjectModel(Model, connection?)

// app.controller.ts
import { Controller, Get } from '@nestjs/common';
import { 
  InjectModel, 
  synchronize, 
  InjectConnection, 
  Connection, 
} from 'nestjs-objection';
import { User, Post } from './app.models';

@Controller()
export class AppController {
  constructor(
    @InjectModel(User) private readonly userModel: typeof User,
    @InjectModel(Post) private readonly postModel: typeof Post,
    @InjectConnection() private readonly connection: Connection,
  ) {}

  @Get()
  async getHello() {
    await synchronize(User);
    await synchronize(Post);
    await this.userModel.query().insert({ name: 'Name' });
    await this.postModel.query().insert({ title: 'Title', userId: 1 });

    const users = await this.userModel
      .query()
      .select(['users.name'])
      .withGraphJoined('posts')
      .modifyGraph('posts', q => q.select(['posts.title']));

    const posts = await this.connection.table('posts');

    return { users, posts };
  }
}

SoftDeleteModel

import { SoftDeleteModel, columnTypes } from 'nestjs-objection';

@Table({ tableName: 'users', softDelete: true })
export class User extends SoftDeleteModel {
  @Column({ type: columnTypes.increments })
  id: number;
  @Column({ type: columnTypes.datetime })
  deletedAt: Date;
}
ObjectionModule.forRoot({
  Model: SoftDeleteModel,
  config: { /* ... */ }
})
this.userModel.query().where({ id: 1 }).delete(); // or softDelete()
this.userModel.query().where({ id: 1 }).withDeleted();
this.userModel.query().where({ id: 1 }).onlyDeleted();
this.userModel.query().where({ id: 1 }).forceDelete();
this.userModel.query().where({ id: 1 }).restore();

Typescript

// src/index.d.ts
declare module 'objection' {
  interface WhereMethod<QB extends AnyQueryBuilder> {
    <T>(columns: Partial<T>): QB;
    <T>(column: Partial<keyof T>, op: string, value: any): QB;
  }
  interface OrderByMethod<QB extends AnyQueryBuilder> {
    <T>(column: keyof T, order?: 'asc' | 'desc'): QB;
    <T>(columns: (Array<{ column: keyof T; order?: 'asc' | 'desc' }>)): QB;
  }
  interface SelectMethod<QB extends AnyQueryBuilder> {
    <T>(...columnNames: Array<Partial<keyof T>>): QB;
    <T>(columnNames: Array<Partial<keyof T>>): QB;
  }
  interface QueryBuilder<M extends Model, R = M[]> extends Promise<R> {
    forceDelete(): this;
    withDeleted(): this;
    onlyDeleted(): this;
    softDelete(): this;
    restore(): this;
  }
}
// with type-safe
const users = await this.userModel
  .query()
  .select<User>(['name'])
  .where<User>({ name: 'Name' })
  .orderBy<User>('name', 'desc')
  .withGraphFetched('posts')
  .modifyGraph('posts', q => q.select<Post>(['title']));

// without type-safe
const users = await this.userModel
  .query()
  .select(['name'])
  .where({ name: 'Name' })
  .orderBy('name', 'desc')
  .withGraphFetched('posts')
  .modifyGraph('posts', q => q.select(['title']));

License

MIT

3.0.0-test.1

2 years ago

3.0.0-test.2

2 years ago

3.0.0

2 years ago

2.2.0

4 years ago

2.2.0-test.1

4 years ago

2.1.0

4 years ago

2.1.0-test.2

4 years ago

2.1.0-test.1

4 years ago

2.0.1

4 years ago

2.0.0-test.5

4 years ago

2.0.0-test.6

4 years ago

2.0.0-test.3

4 years ago

2.0.0-test.4

4 years ago

2.0.0-test.2

4 years ago

2.0.0-test.1

4 years ago

2.0.0

4 years ago

1.1.0

4 years ago

1.0.1

4 years ago

1.0.0

4 years ago

0.3.2

4 years ago

0.3.1

4 years ago

0.3.0

4 years ago

0.2.3

4 years ago

0.2.2

4 years ago

0.2.1

4 years ago

0.2.0

4 years ago

0.1.0

4 years ago

0.0.8

4 years ago

0.0.7

4 years ago

0.0.6

4 years ago

0.0.5

4 years ago

0.0.3

4 years ago

0.0.4

4 years ago

0.0.2

4 years ago

0.0.1

4 years ago