A progressive Node.js framework for building efficient and scalable server-side applications.
Description
Azure Database (Table Storage, Cosmos DB - NoSQL) module for Nest framework (node.js)
Disclaimer
You are reading documentation for version 3. If you are looking for version 2 documentation, click here. Please also note that version 2 is no longer maintained and will not receive any updates!
Before Installation
For Table Storage
- Create a Storage account and resource (read more)
- Note down the "Connection string" - You will need it later
For Cosmos DB (NoSQL ONLY)
- Create a Cosmos DB account and resource (read more)
- Note down the "URI", Database name and the "Primary Key" (or "Secondary Key") - You will need them later
Installation
$ npm i --save @nestjs/azure-database
Usage
For Azure Table Storage support
- Create or update your existing
.env
file with the following content:
AZURE_STORAGE_CONNECTION_STRING=
-
IMPORTANT: Make sure to add your .env
file to your .gitignore! The .env
file MUST NOT be versioned on Git.
-
Make sure to include the following call to your main.ts
file:
if (process.env.NODE_ENV !== 'production') require('dotenv').config();
This line must be added before any other imports!
- The
AzureTableStorageModule
will automatically read the AZURE_STORAGE_CONNECTION_STRING
environment variable and use it to connect to your Azure Storage account.
Example
Check out the Table Storage example project included in the sample folder
Prepare your entity
- Create a new feature module, eg. with the nest CLI:
$ nest generate module event
- Create a Data Transfer Object (DTO) inside a file named
event.dto.ts
:
export class EventDTO {
name: string;
type: string;
}
- Create a file called
event.entity.ts
and describe the entity model using plain JavaScript objects. The only requirement is to provide a partitionKey
and a rowKey
properties. For instance, the shape of the following entity:
export class Event {
partitionKey: string;
rowKey: string;
name: string;
type: string;
}
- Import the
AzureTableStorageModule
inside your Nest feature module event.module.ts
:
import { Module } from '@nestjs/common';
import { AzureTableStorageModule } from '@nestjs/azure-database';
@Module({
imports: [AzureTableStorageModule.forFeature(Event)],
})
export class EventModule {}
You can optionally pass in the following arguments:
import { Module } from '@nestjs/common';
import { AzureTableStorageModule } from '@nestjs/azure-database';
@Module({
imports: [
AzureTableStorageModule.forFeature(Event, {
table: 'foobar',
createTableIfNotExists: true,
}),
],
})
export class EventModule {}
table: string
: The name of the table. If not provided, the name of the Event
entity will be used as a table namecreateTableIfNotExists: boolean
: Whether to automatically create the table if it doesn't exists or not:
- If
true
the table will be created during the startup of the app. - If
false
the table will not be created. You will have to create the table by yourself before querying it!
CRUD operations
- Create a service that will abstract the CRUD operations:
$ nest generate service event
- Use the
@InjectRepository(Event)
to get an instance of the Azure Repository
for the entity definition created earlier:
import { InjectRepository, Repository } from '@nestjs/azure-database';
import { Injectable } from '@nestjs/common';
import { Event } from './event.entity';
@Injectable()
export class EventService {
constructor(
@InjectRepository(Event)
private readonly eventRepository: Repository<Event>,
) {}
}
The AzureTableStorageRepository
provides a list of public methods for managing various CRUD operations:
CREATE
create(entity: T): Promise<T | null>
: creates a new entity.
async create(event: Event): Promise<Event> {
return await this.eventRepository.create(event);
}
READ
find(partitionKey: string, rowKey: string): Promise<T>
: finds one entity using its partitionKey
and rowKey
.
async find(partitionKey: string, rowKey: string): Promise<Event> {
return await this.eventRepository.find(partitionKey, rowKey);
}
findAll(): Promise<T[]>
: finds all entities (NOTE: odata filters are not supported yet).
async findAll(): Promise<Event[]> {
return await this.eventRepository.findAll();
}
UPDATE
update(partitionKey: string, rowKey: string, entity: T): Promise<T>
: Updates an entity using a "merge" strategy.
async update(
partitionKey: string,
rowKey: string,
event: Event,
): Promise<Event> {
return await this.eventRepository.update(partitionKey, rowKey, event);
}
DELETE
delete(partitionKey: string, rowKey: string): Promise<DeleteTableEntityResponse>
: Removes an entity from the table.
async delete(partitionKey: string, rowKey: string): Promise<void> {
await this.eventRepository.delete(partitionKey, rowKey);
}
For Azure Cosmos DB support
- Create or update your existing
.env
file with the following content:
AZURE_COSMOS_DB_NAME=
AZURE_COSMOS_DB_ENDPOINT=
AZURE_COSMOS_DB_KEY=
-
IMPORTANT: Make sure to add your .env
file to your .gitignore! The .env
file MUST NOT be versioned on Git.
-
Make sure to include the following call to your main.ts
file:
if (process.env.NODE_ENV !== 'production') require('dotenv').config();
This line must be added before any other imports!
Example
Note: Check out the CosmosDB example project included in the sample folder
Prepare your entity
- Create a new feature module, eg. with the nest CLI:
$ nest generate module event
- Create a Data Transfer Object (DTO) inside a file named
event.dto.ts
:
export class EventDTO {
id?: string;
name: string;
type: string;
createdAt: Date;
}
- Create a file called
event.entity.ts
and describe the entity model using the provided decorators:
For instance, the shape of the following entity:
import { CosmosDateTime, CosmosPartitionKey } from '@nestjs/azure-database';
@CosmosPartitionKey('type')
export class Event {
name: string;
type: string;
@CosmosDateTime() createdAt: Date;
}
Will be automatically converted to:
{
"name": "NestJS Meetup",
"type": "Meetup",
"createdAt": "2019-11-15T17:05:25.427Z"
}
- Import the
AzureCosmosDbModule
inside your Nest feature module event.module.ts
:
import { AzureCosmosDbModule } from '@nestjs/azure-database';
import { Module } from '@nestjs/common';
import { Event } from './event.entity';
@Module({
imports: [
AzureCosmosDbModule.forRoot({
dbName: process.env.AZURE_COSMOS_DB_NAME,
endpoint: process.env.AZURE_COSMOS_DB_ENDPOINT,
key: process.env.AZURE_COSMOS_DB_KEY,
retryAttempts: 1,
}),
AzureCosmosDbModule.forFeature([{ dto: Event }]),
],
})
export class EventModule {}
CRUD operations
- Create a service that will abstract the CRUD operations:
$ nest generate service event
- Use the
@InjectModel(Event)
to get an instance of the Azure Cosmos DB Container for the entity definition created earlier:
import { InjectModel } from '@nestjs/azure-database';
import type { Container } from '@azure/cosmos';
import { Injectable } from '@nestjs/common';
import { Event } from './event.entity';
@Injectable()
export class EventService {
constructor(
@InjectModel(Event)
private readonly eventContainer: Container,
) {}
}
@InjectModel(Event)
will inject an Azure Cosmos DB Container
instance for the Event
entity. The Container
provides a list of public methods for managing the database.
IMPORTANT: Please note that the Container
instance is not a NestJS repository. It is the actual instance provided by the official Azure Cosmos DB SDK.
CREATE
create(entity: T): Promise<T>
: creates a new entity.
async create(eventDto: EventDTO): Promise<Event> {
const { resource } = await this.eventContainer.items.create<Event>(
eventDto,
);
return resource;
}
READ
Items.query<T>(query: string | SqlQuerySpec, options?: FeedOptions): QueryIterator<T>
: Queries the database using a SQL query.
QueryIterator<Event>.fetchAll(): Promise<FeedResponse<Event>>
: Fetches all the results of the query.
async getEvents(): Promise<Event[]> {
const querySpec = {
query: 'SELECT * FROM events',
};
const { resources } = await this.eventContainer.items
.query<Event>(querySpec)
.fetchAll();
return resources;
}
UPDATE
Item.replace<
T& Resource>(body:
T & Resource, options?: RequestOptions): Promise<ItemResponse<
T & Resource>>
: Replaces an item in the database.
async updateEvent(
id: string,
type: string,
eventData: EventDTO,
): Promise<Event> {
let { resource: item } = await this.eventContainer
.item(id, type)
.read<Event>();
item = {
...item,
...eventData,
};
const { resource: replaced } = await this.eventContainer
.item(id, type)
.replace(item);
return replaced;
}
DELETE
Item.delete<T>(options?: RequestOptions): Promise<ItemResponse<T>>
: Deletes an item from the database.
async deleteEvent(id: string, type: string): Promise<Event> {
const { resource: deleted } = await this.eventContainer
.item(id, type)
.delete<Event>();
return deleted;
}
Support
Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please read more here.
Stay in touch
License
Nest is MIT licensed.