Skip to content

leanscript/quark

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

7 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

@leanscript/quark

quark logo

Features :

  • Generate CRUD REST API with decorators and no BS
  • Validation based on schema decorators
  • Database agnostic
  • Search agnostic
  • Native SQL drivers for MySQL, PostgreSQL and SQLite

Futures compatibles plugins :

  • MySQL Database Service
  • PostgreSQL Database Service
  • SQLite Database Service
  • MongoDB Database Service
  • Swagger doc
  • Meilisearch Search Service
  • Mailer Notification Service
  • Slack Notification Service
  • Console helper

Quick start

Configure your app

// app.module.ts
import { Module } from "@nestjs/common";
import { DatabaseService } from "./services/db.service";
import { SearchService } from "./services/search.service";
import { UsersModule } from "./users/users.module";
import { MetaModule } from "meta-nest";

@Module({
  imports: [
    UsersModule, // ie we will use UsersModule
    MetaModule.forRoot({
      // Configure the module with your custom DatabaseService & SearchService
      DatabaseService,
      SearchService,
    }),
  ],
  providers: [DatabaseService, SearchService], // Import your custom DatabaseService & SearchService
})
export class AppModule {}

Configure your module

// users/users.module.ts
import { Module } from '@nestjs/common';
import { UsersService } from './users.service';
import { MetaModule } from 'meta-nest';
import { UsersController } from './users.controller';

@Module({
  imports: [MetaModule)], // Register simply the MetaModule in your feature module
  controllers: [UsersController],
  providers: [UsersService],
  exports: [UsersService],
})
export class UsersModule {}

Configure your controller

// users/users.controller.ts
import { Controller } from "@nestjs/common";

import { User } from "./user.schema";
import { ApiGroup } from "../core/decorators/api-group.decorator";
import { MetaController } from "../core/decorators/meta.decorator";

// Use ApiGroup instead of ApiTags for swagger api tagging
@ApiGroup("Users")
@Controller()
// MetaController enable you to setup easily your generic CRUD api
@MetaController({
  key: "users",
  schema: User,
  routes: ["GET", "POST", "PATCH", "DESTROY", "ACTIONS"],
})
export class UsersController {
  constructor() {}
  // ...
}

Inject your Database & Search services

// users/users.service.ts
import { Injectable, Inject } from '@nestjs/common';
import { DatabaseService } from '../services/db.service';
import { SearchService } from '../services/search.service';

@Injectable()
export class UsersService {
  constructor(
    // Use @Inject('DatabaseService') to skip reimporting your db service in your user module
    @Inject('DatabaseService') private db: DatabaseService
    // Use @Inject('SearchService') to skip reimporting your search service in your user module
    @Inject('SearchService') private db: SearchService
  ) {}
  // ...
}

Configure your schema

// users/users.service.ts

// You can use class-validator & class-transformer on your schema
import { Exclude, Transform } from "class-transformer";
import { IsEmail, Length } from "class-validator";
import { ApiProperty } from "@nestjs/swagger";

import { ObjectId } from "mongodb";
import { PrimaryKey, MetaModel } from "meta-nest";

// You need to extends MetaModel to use your schema with meta-nest
export class User extends MetaModel {
  // PrimaryKey let you specify the pk of your schema
  // By default meta-nest will target 'id' property
  @PrimaryKey()
  @Transform((value) => value.obj._id.toString())
  _id: ObjectId;

  @Length(3, 10)
  @ApiProperty({ example: "Foo Bar", description: "The name of the user" })
  name: string;

  @IsEmail()
  @ApiProperty({
    example: "api-generator@mail.com",
    description: "The email of the user",
  })
  email: string;

  @Exclude()
  password: string;

  @Length(3, 10)
  @ApiProperty({
    example: "Xx_Foo_Bar_xX",
    description: "The username of the user",
  })
  username: string;

  constructor(partial: Partial<User>) {
    // Don't forget super when extending class
    super();
    Object.assign(this, partial);
  }
}

Check your api

Go to /api to check your api swagger.

Create your custom DatabaseService

To use your custom DatabaseService with meta-nest your service need to implement DatabaseServiceInterface. As long as your service follows the interface, you can make any DB driver works with meta-nest.

import { Injectable, Inject } from "@nestjs/common";
import { DatabaseServiceInterface } from "meta-nest";

@Injectable()
export class DatabaseService implements DatabaseServiceInterface {
  // ...
}

Use a native SQL driver

Quark also provides native SQL drivers built from scratch. They generate parameterized SQL internally and delegate execution to the native client you install in your app.

pnpm add pg
pnpm add mysql2
pnpm add better-sqlite3
pnpm add mongodb
import {
  MetaModule,
  createPostgresqlDatabaseService,
  createMysqlDatabaseService,
  createSqliteDatabaseService,
  createMongoDatabaseService,
} from "@quark/core";

const DatabaseService = createPostgresqlDatabaseService({
  connection: {
    host: process.env.POSTGRES_HOST,
    port: Number(process.env.POSTGRES_PORT || 5432),
    user: process.env.POSTGRES_USER,
    password: process.env.POSTGRES_PASSWORD,
    database: process.env.POSTGRES_DATABASE,
  },
});

// MySQL
createMysqlDatabaseService({ connection: mysqlConnectionOptions });

// SQLite
createSqliteDatabaseService({ filename: "./data/app.sqlite" });

// MongoDB
createMongoDatabaseService({
  uri: process.env.MONGODB_URI,
  database: process.env.MONGODB_DATABASE,
});

@Module({
  imports: [
    MetaModule.forRoot({
      DatabaseService,
      SearchService,
    }),
  ],
})
export class AppModule {}

See .docs/sql-drivers.md and .docs/mongodb.md for naming, primary keys, native relations (one-to-one, one-to-many, many-to-many) with selected relation columns, and raw query examples.

Create your custom SearchService

To use your custom SearchService with meta-nest your service need to implement SearchServiceInterface. As long as your service follows the interface, you can make any Search Engine works with meta-nest.

import { Injectable, Inject } from "@nestjs/common";
import { SearchServiceInterface } from "meta-nest";

@Injectable()
export class SearchService implements SearchServiceInterface {
  // ...
}

Configure multiple endpoint per controller

// users/users.controller.ts
import { Controller } from "@nestjs/common";

import { User } from "./user.schema";
import { ApiGroup } from "../core/decorators/api-group.decorator";
import { MetaController } from "../core/decorators/meta.decorator";

// Use ApiGroup instead of ApiTags for swagger api tagging
@ApiGroup("Users")
@Controller()
// You can scope your controller and using multiple MetaController
@MetaController({
  key: "teachers",
  schema: User,
  scope: { type: "teacher" },
  routes: ["GET", "POST", "PATCH", "DESTROY", "ACTIONS"],
})
@MetaController({
  key: "students",
  schema: User,
  scope: { type: "student" },
  routes: ["GET", "POST", "PATCH", "DESTROY", "ACTIONS"],
})
export class UsersController {
  constructor() {}
  // ...
}

About

πŸ”§ DB & Search engine agnostic API CRUD generator for NestJS

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors