npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@mwaeckerlin/schematics

v1.5.0

Published

Nest - modern, fast, powerful node.js web framework (@schematics)

Downloads

1

Readme

Changes to Original

The origin of this project is: https://github.com/nestjs/schematics

The application files have been adapted according to the descriptions in my blog.

Additional generators:

  • database or db: add MikroORM based database connection
    • type defines the default database type, e.g. sqlite
  • openapi or api: Generate a server (Controller + DTO) from a OpenAPI 3 JSON file
    • first commandline parameter: file name of the OpenAPI JSON
    • second command line parameter: name of the controller (optional, otherwise, contoler name is taken from first path element)
  • kafka: add kafka connection (not started yet)

Also Generates:

  • Dockerfile
  • docker-compose.yml

Install:

npm i -g @mwaeckerlin/schematics

Usage:

nest new -c @mwaeckerlin/schematics [options] [name]

Example:

nest new -c @mwaeckerlin/schematics -p npm -l ts test
cd test
npm install
npm run start:debug

Or:

docker-compose up --build

Add Database

Create a database, run initial migration (if you don't use SQLitem then you need to run a database with docker-compose up -d db for the initial migration):

nest new -c @mwaeckerlin/schematics -p npm test
cd test
nest g -c @mwaeckerlin/schematics db
nest g -c @mwaeckerlin/schematics res user
npm install
npm run build
docker-compose up -d db
npm run migration:initial
docker-compose up

If you get:

  code: 'ER_ACCESS_DENIED_ERROR',
  errno: 1045,
  sqlState: '28000',
  sqlMessage: "Access denied for user 'user'@'172.24.0.1' (using password: YES)",

Then you probably still have an old docker volume created with another password:

$ docker volume ls
DRIVER    VOLUME NAME
local     test_db-volume

Remove it:

docker-compose rm -vfs
docker volume rm test_db-volume

Or remove everything:

docker system prune --all --volumes

Real Live Example

Let's implement the MikroORM example from my Blog: A databse with Author, Publisher and Book, where the Book refers to any number of Authors and Publishers, while there is no reference from Author or Publisher to the Book (unidirectional).

Setup Basics

nest new -c @mwaeckerlin/schematics -p npm test
cd test
nest g -c @mwaeckerlin/schematics db
nest g -c @mwaeckerlin/schematics res author
nest g -c @mwaeckerlin/schematics res punlisher
nest g -c @mwaeckerlin/schematics res book

Entities

First we define the entities (the database schema).

Please note that comments are automatically added to the return value description in the generated API documentation.

Author

Just add the properties:

import { Entity, Property } from '@mikro-orm/core'
import { Base } from '../../base/entities/base.entity'
import { CreateAuthorDto } from '../dto/create-author.dto'

@Entity()
export class Author extends Base {
  constructor(createAuthorDto: CreateAuthorDto) {
    super()
    Object.assign(this, createAuthorDto)
  }

  /* author's first name(s) */
  @Property()
  first_names?: string[]

  /* author's family name(s) */
  @Property()
  last_names!: string[]

  /* date of birth of the author */
  @Property()
  born?: Date

  /* date of death of the author, if applicable */
  @Property()
  died?: Date
}
Publisher

Just add the properties:

import { Entity, Property } from '@mikro-orm/core'
import { Base } from '../../base/entities/base.entity'
import { CreatePublisherDto } from '../dto/create-publisher.dto'

@Entity()
export class Publisher extends Base {
  constructor(createPublisherDto: CreatePublisherDto) {
    super()
    Object.assign(this, createPublisherDto)
  }

  /* name(s) of the publisher */
  @Property()
  publisher_names!: string[]

  /* full address of the publisher, may contain several lines */
  @Property()
  publisher_address_lines?: string[]

}
Book

The book is a little bit more complex, since it refers to Author and Publisher:

import { Collection, Entity, ManyToMany, Property } from '@mikro-orm/core'
import { Author } from 'src/author/entities/author.entity'
import { Publisher } from 'src/publisher/entities/publisher.entity'
import { Base } from '../../base/entities/base.entity'
import { CreateBookDto } from '../dto/create-book.dto'

@Entity()
export class Book extends Base {
  constructor(createBookDto: CreateBookDto, authors?: Author[], publishers?: Publisher[]) {
    super()
    Object.assign(this, {...createBookDto, authors, publishers})
  }

  /* title(s) of the book */
  @Property()
  titles!: string[]

  /* full structure of the author(s) of the book */
  @ManyToMany()
  authors =  new Collection<Author>(this)

  /* full structure of the publisher(s) of the book */
  @ManyToMany()
  publishers = new Collection<Publisher>(this)

  /* ISBN is available */
  @Property()
  isbn?: string

}

Creation DTOs

The update DTOs are generic, but in the creation DTOs you need to set the values that will be passed thriough the REST API.

Please note that comments are automatically added to the interface description.

Author
export class CreateAuthorDto {
  /* author's first name(s) */
  first_names?: string[]
  /* author's family name(s) */
  last_names!: string[]
  /* date of birth of the author */
  born?: Date
  /* date of death of the author, if applicable */
  died?: Date
}```

##### Publisher

```typescript
export class CreatePublisherDto {
  /* name(s) of the publisher */
  publisher_names?: string[]
  /* full address of the publisher, may contain several lines */
  publisher_address_lines?: string[]
}
Book

At creation, authors and publishers are referenced as ids.

export class CreateBookDto {
  /* title(s) of the book */
  titles?: string[]
  /* database id(s) of the author(s) of the book */
  authors?: string[]
  /* database id(s) of the publisher(s) of the book */
  publishers?: string[]
  /* ISBN is available */
  isbn?: string
}

Book Service

Only the Book service needs changes because the Book needs to refer to Author and Publisher. All controlers and the services of Author and Publisher remain unchanged.

import { Injectable, Logger, NotFoundException } from '@nestjs/common'
import { Book } from './entities/book.entity'
import { CreateBookDto } from './dto/create-book.dto'
import { UpdateBookDto } from './dto/update-book.dto'
import { EntityManager } from '@mikro-orm/core'
import { Publisher } from '../publisher/entities/publisher.entity'
import { Author } from '../author/entities/author.entity'

@Injectable()
export class BookService {
  private readonly logger = new Logger(BookService.name)
  constructor(private readonly em: EntityManager) { }

  async create(createBookDto: CreateBookDto): Promise<Book> {
    return await this.em.transactional(async (em) => {
      const authors = await em.find(Author, { id: { $in: createBookDto.authors ?? [] } })
      if ((authors?.length ?? 0) !== (createBookDto?.authors?.length ?? 0)) throw new NotFoundException('author not found')
      const publishers = await em.find(Publisher, { id: { $in: createBookDto.publishers ?? [] } })
      if ((publishers?.length ?? 0) !== (createBookDto?.publishers?.length ?? 0)) throw new NotFoundException('publisher not found')
      const book = new Book(createBookDto, authors, publishers)
      await em.persistAndFlush(book)
      return book
    })
  }

  async findAll(query: Object = {}): Promise<Book[]> {
    return this.em.find(Book, query, { populate: ['authors', 'publishers'] })
  }

  async findOne(id: string): Promise<Book> {
    return this.em.findOneOrFail(Book, id, { populate: ['authors', 'publishers'] })
  }

  async update(id: string, updateBookDto: UpdateBookDto): Promise<Book> {
    return await this.em.transactional(async (em) => {
      const authors = await em.find(Author, { id: { $in: updateBookDto.authors ?? [] } })
      if ((authors?.length ?? 0) !== (updateBookDto?.authors?.length ?? 0)) throw new NotFoundException('author not found')
      const publishers = await em.find(Publisher, { id: { $in: updateBookDto.publishers ?? [] } })
      if ((publishers?.length ?? 0) !== (updateBookDto?.publishers?.length ?? 0)) throw new NotFoundException('publisher not found')
      const book = await em.findOneOrFail(Book, { id })
      Object.assign(book, {
        ...updateBookDto,
        authors: updateBookDto.authors === null ? book.authors : authors,
        publishers: updateBookDto.publishers === null ? book.publishers : publishers
      })
      await em.persistAndFlush(book)
      return book
    })
  }

  async remove(id: string): Promise<Book> {
    const book = await this.em.findOneOrFail(Book, id)
    await this.em.removeAndFlush(book)
    return book
  }
}

Run

That's it, prepare it and generate the first migration:

npm i
npm run build
npm run migration:initial

Start it:

npm start

Then browse to [http://localhost:4000/api] and play with the API!

Description

The Nest CLI is a command-line interface tool that helps you to initialize, develop, and maintain your Nest applications. It assists in multiple ways, including scaffolding the project, serving it in development mode, and building and bundling the application for production distribution. It embodies best-practice architectural patterns to encourage well-structured apps. Read more here.

Installation

$ npm install -g @mwaeckerlin/schematics

Usage

To use @mwaeckerlin/schematics, you need to explicitly refere to it:

$ nest new -c @mwaeckerlin/schematics [options] [name]

Learn more in the official documentation.

Stay in touch

License

Nest is MIT licensed.