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

@nestlike/drizzle-orm

v0.1.1

Published

NestJS module for adding Drizzle ORM to applications

Downloads

49

Readme

@nestlike/drizzle-orm

Bring your NestJS app to the next level by integrating Drizzle ORM.

Installation

First you must install the package and it's peer dependencies.

npm i @nestlike/drizzle-orm drizzle-orm

After that you should also install a database client. You can find more information about that and available options in the offical documentation.

Let's assume you want to use Postgres.js.

npm i postgres

Of course you can also install and work with Drizzle Kit. This module is just a thin wrapper and won't stand in your way.

Configuration

Now you can import the module and confgure it in your application. In a new application created with the NestJS CLI that could look like the following.

import { Module } from '@nestjs/common';
import { DrizzleModule } from '@nestlike/drizzle-orm';
import postgres from 'postgres';

import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
    imports: [
        DrizzleModule.forRoot({
            driver: 'postgres-js',
            client: postgres('postgres://postgres:[email protected]:5432/db')
        })
    ],
    controllers: [AppController],
    providers: [AppService]
})
export class AppModule { }

Notice that you don't have to create a drizzle instance. That is done behind the scenes to make things easier. All you need to do is configure the driver you want to use and provide a client. Asynchronous confiiguration is also possible using the forRootAsync method.

Adding Schemas

After the module is configured you can add schemas in your feature modules. Let's assume you have created a UsersModule and a PostsModule by generating resources with the NestJS CLI.

Defining the tables for your entities

NestJS has created the files .src/users/entities/user.entity.ts and .src/posts/entities/post.entity.ts for you. To get the most out of code scaffolding we will just use them for defining our tables like we would with TypeORM.

Of course you are completely free to chose a folder structure and naming convention that makes sense for yourself. You could for example move those files to ./src/users/schema/users.table.ts adn ./src/posts/schema/posts.table.ts.

Now let's have a look at how we would implement the relational queries examples from Drizzle's documentation.

We will start with our .src/users/entities/user.entity.ts:

import { relations } from 'drizzle-orm';
import { serial, text, pgTable } from 'drizzle-orm/pg-core';

import { postEntity } from '../../posts/entities/post.entity';

export const userEntity = pgTable('users', {
    id: serial('id').primaryKey(),
    name: text('name').notNull()
});

export const userRelations = relations(userEntity, ({ many }) => ({
    posts: many(postEntity)
}));

Our .src/posts/entities/post.entity.ts would look like this:

import { relations } from 'drizzle-orm';
import { integer, serial, text, pgTable } from 'drizzle-orm/pg-core';

import { userEntity } from '../../users/entities/user.entity';

export const postEntity = pgTable('posts', {
    id: serial('id').primaryKey(),
    content: text('content').notNull(),
    authorId: integer('author_id').notNull()
});

export const postRelations = relations(postEntity, ({ one }) => ({
    author: one(userEntity, { fields: [postEntity.authorId], references: [userEntity.id] })
}));

And that's it! We defined our entities the NestJS way by organizing them in feature modules instead of a single schema file. Pretty neat, isn't it?

Informing DrizzleModule about your schema

The only thing missing now is letting DrizzleModule know about your schema. For that we can use the forFeature or forFeatureAsync method when importing the module in our feature module.

Let's have a look at ./src/users/users.module.ts:

import { Module } from '@nestjs/common';
import { DrizzleModule } from '@nestlike/drizzle-orm';

import { UsersService } from './users.service';
import { UsersController } from './users.controller';

// We can just import the entire module here if it only exports tables
// and relations and therefore is a valid schema that we can provide to
// the drizzle instance behind the scenes.
import * as schema from './entities/user.entity';

// In case you have other exports or multiple entities defined in your feature
// module you must handcraft your schema object. This gives you complete freedom
// and makes it even possible to rename keys.
import { userEntity, userRelations } from './entities/user.entity';

const schema2 = { users: userEntity, userRelations };

// Next we leverage declaration merging to make sure that Drizzle's type
// system knows about the feature's entities and their relationships.
declare module '@nestlike/drizzle-orm' {
    interface DrizzleSchema extends Required<typeof schema> { }
}

@Module({
    imports: [DrizzleModule.forFeature(schema)],
    controllers: [UsersController],
    providers: [UsersService]
})
export class UsersModule { }

For ./src/posts/posts.module.ts we do the same:

import { Module } from '@nestjs/common';
import { DrizzleModule } from '@nestlike/drizzle-orm';

import { PostsService } from './posts.service';
import { PostsController } from './posts.controller';
import * as schema from './entities/post.entity';

declare module '@nestlike/drizzle-orm' {
    interface DrizzleSchema extends Required<typeof schema> { }
}

@Module({
    imports: [DrizzleModule.forFeature(schema)],
    controllers: [PostsController],
    providers: [PostsService]
})
export class PostsModule { }

Querying the database

Finally we can access the drizzle instance in our application. For example in ./src/users/users.service.ts:

import { Injectable, Inject } from '@nestjs/common';
import { eq } from 'drizzle-orm';

// Notice that we import PostgresJsDatabase from '@nestlike/drizzle-orm' and
// not from 'drizzle-orm/postgres-js'. The difference is that it is not generic
// and already knows the type  for our schema because we merged our custom
// declarations earlier.
import { DRIZZLE_DB, PostgresJsDatabase } from '@nestlike/drizzle-orm';

import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { userEntity } from './entities/user.entity';

@Injectable()
export class UsersService {

    constructor(@Inject(DRIZZLE_DB) private db: PostgresJsDatabase) { }

    async create(createUserDto: CreateUserDto) {
        return this.db.insert(userEntity).values(createUserDto).returning();
    }

    async findAll() {
        return this.db.query.userEntity.findMany({ with: { posts: true } });
    }

    async findOne(id: number) {
        return this.db.query.userEntity.findFirst({ where: eq(userEntity.id, id) });
    }

    async update(id: number, updateUserDto: UpdateUserDto) {
        return this.db.update(userEntity).set(updateUserDto).where(eq(userEntity.id, id)).returning();
    }

    async remove(id: number) {
        return this.db.delete(userEntity).where(eq(userEntity.id, id)).returning();
    }

}

Running

Finally you can start your application.

nest start

Using Drizzle Kit

Drizzle Kit works just as expected. You must only make sure that it picks up your schema files by providing a correct configuration. For example:

import type { Config } from 'drizzle-kit';

export default {
  schema: './src/**/entities/*.entity.ts',
  out: './drizzle'
} satisfies Config;

Bonus

One more nice thing that Drizzle gives us is an integration with Zod. Nothing stops us from using it as well. Since this is opt-in you will not find a full blown tutorial here and just some basic ideas. You should install two more packages:

npm i drizzle-zod nestjs-zod

After that you can define your DTOs like this:

import { createSelectSchema } from 'drizzle-zod';
import { createZodDto } from 'nestjs-zod';
import { z } from 'zod';

import { userEntity } from '../entities/user.entity';
import { postEntity } from '../../posts/entities/post.entity';

const userSchema = createSelectSchema(userEntity)
    .and(z.object({ posts: z.array(createSelectSchema(postEntity)) }));

export class UserDto extends createZodDto(userSchema) { }

You can read more about validation and even full Swagger support here.