@cyber-rom/nestjs-scylladb
Version:
Based on https://www.npmjs.com/package/@ouato/nestjs-express-cassandra With support columns name mapping
472 lines (379 loc) • 11.4 kB
Markdown
Based on https://www.npmjs.com/package/@ouato/nestjs-express-cassandra
With support columns name mapping
## Installation
```bash
$ npm i --save @cyber-rom/nestjs-scylladb
```
## Usage
Import `ScyllaModule`:
```typescript
@Module({
imports: [
ScyllaModule.forRoot({...})
],
providers: []
})
export class AppModule {}
```
## Async options
Quite often you might want to asynchronously pass your module options instead of passing them beforehand. In such case, use registerAsync() method, that provides a couple of various ways to deal with async data.
**1. Use factory**
```typescript
ScyllaModule.forRootAsync({
useFactory: () => ({...}),
})
```
Obviously, our factory behaves like every other one (might be `async` and is able to inject dependencies through `inject`).
```typescript
ScyllaModule.forRootAsync({
imports: [ConfigModule],
useFactory: (configService: ConfigService) => configService.getDbConfig(),
inject: [ConfigService],
});
```
**2. Use class**
```typescript
ScyllaModule.forRootAsync({
useClass: ConfigService,
});
```
Above construction will instantiate `ConfigService` inside `ScyllaModule` and will leverage it to create options object.
```typescript
class ConfigService implements ScyllaOptionsFactory {
createScyllaOptions(): ScyllaModuleOptions {
return {...};
}
}
```
**3. Use existing**
```typescript
ScyllaModule.forRootAsync({
imports: [ConfigModule],
useExisting: ConfigService,
});
```
It works the same as `useClass` with one critical difference - `ScyllaModule` will look up imported modules to reuse already created ConfigService, instead of instantiating it on its own.
## ORM Options
```typescript
import {Entity, Column} from '@cyber-rom/nestjs-scylladb';
@Entity({
table_name: 'photo',
key: ['id'],
})
export class PhotoEntity {
@Column({
type: 'uuid',
default: {$db_function: 'uuid()'},
})
id: any;
@Column({
name: 'photo_name',
type: 'text',
})
name: string;
}
```
Let's have a look at the `PhotoModule`
```typescript
import {Module} from '@nestjs/common';
import {ScyllaModule} from '@cyber-rom/nestjs-scylladb';
import {PhotoService} from './photo.service';
import {PhotoController} from './photo.controller';
import {PhotoEntity} from './photo.entity';
@Module({
imports: [ScyllaModule.forFeature([PhotoEntity])],
providers: [PhotoService],
controllers: [PhotoController],
})
export class PhotoModule {}
```
This module uses `forFeature()` method to define which entities shall be registered in the current scope. Thanks to that we can inject the `PhotoEntity` to the `PhotoService` using the `@InjectModel()` decorator:
```typescript
import {Injectable} from '@nestjs/common';
import {InjectModel, BaseModel} from '@cyber-rom/nestjs-scylladb';
import {PhotoEntity} from './photo.entity';
@Injectable()
export class PersonService {
constructor(
@InjectModel(PhotoEntity)
private readonly photoEntity: BaseModel<PhotoEntity>,
) {}
getByName(name: string): Promise<PhotoEntity> {
return this.photoEntity.findOneAsync({name: name}, {raw: true});
}
}
```
**Using Column Decorators:**
To auto-generate uuid/timeuuid column, you need to decorate an entity's properties you want to make into an auto-generated
uuid/timeuuid column with a `@GeneratedUUidColumn` decorator.
```typescript
import {Entity, Column, GeneratedUUidColumn} from '@cyber-rom/nestjs-scylladb';
@Entity({
table_name: 'photo',
key: ['id'],
})
export class PhotoEntity {
@GeneratedUUidColumn()
id: any;
@GeneratedUUidColumn('timeuuid')
time_id: any;
@Column({
type: 'text',
})
name: string;
}
```
To auto-generate createdDate/updatedDate column, you need to decorate an entity's properties you want to make into an auto-generated
createdDate/updatedDate column with a `@CreateDateColumn` or `@UpdateDateColumn` decorator (not combine with `@Column` decorator).
To index a column, you need to decorate an entity's properties you want to index with a `@IndexColumn` decorator.
To auto-generate version column, you need to decorate an entity's properties you want to make into an auto-generated
version column with a `@VersionColumn` decorator (not combine with `@Column` decorator).
```typescript
import {
Column,
Entity,
IndexColumn,
VersionColumn,
UpdateDateColumn,
CreateDateColumn,
GeneratedUUidColumn,
} from '@cyber-rom/nestjs-scylladb';
@Entity({
table_name: 'photo',
key: ['id'],
})
export class PhotoEntity {
@GeneratedUUidColumn()
id: any;
@GeneratedUUidColumn('timeuuid')
time_id: any;
@Column({
type: 'text',
})
@IndexColumn()
name: string;
@CreateDateColumn()
created_at: Date;
@UpdateDateColumn()
updated_at: Date;
@VersionColumn()
__v1: any;
}
```
**Using Hook Function Decorators:**
An entity of express-cassandra support multiple hook function. For more details [see](https://express-cassandra.readthedocs.io/en/stable/management/#hook-functions).
To create hook function in an entity use `@BeforeSave`, `@AfterSave`, `@BeforeUpdate`, `@AfterUpdate`, `@BeforeDelete`, `@AfterDelete` decorators.
```typescript
import {
Entity,
Column,
AfterSave,
BeforeSave,
AfterUpdate,
AfterDelete,
BeforeDelete,
BeforeUpdate,
GeneratedUUidColumn,
} from '@cyber-rom/nestjs-scylladb';
@Entity({
table_name: 'photo',
key: ['id'],
})
export class PhotoEntity {
@GeneratedUUidColumn()
id: any;
@GeneratedUUidColumn('timeuuid')
time_id: any;
@BeforeSave()
beforeSave(instance: this, options: any) {}
@AfterSave()
afterSave(instance: this, options: any) {}
@BeforeUpdate()
beforeUpdate(query: any, updateValues: any, options: any) {}
@AfterUpdate()
afterUpdate(query: any, updateValues: any, options: any) {}
@BeforeDelete()
beforeDelete(query: any, options: any) {}
@AfterDelete()
afterDelete(query: any, options: any) {}
}
```
## Using Repository
```typescript
import {Module} from '@nestjs/common';
import {ScyllaModule} from '@cyber-rom/nestjs-scylladb';
import {PhotoService} from './photo.service';
import {PhotoController} from './photo.controller';
import {PhotoEntity} from './photo.entity';
@Module({
imports: [ScyllaModule.forFeature([PhotoEntity])],
providers: [PhotoService],
controllers: [PhotoController],
})
export class PhotoModule {}
```
```typescript
import {Injectable} from '@nestjs/common';
import {InjectRepository, Repository} from '@cyber-rom/nestjs-scylladb';
import {PhotoEntity} from './photo.entity';
import {Observable} from 'rxjs';
@Injectable()
export class PersonService {
constructor(
@InjectRepository(PhotoEntity)
private readonly photoRepository: Repository<PhotoEntity>,
) {}
getById(id: id): Observable<PhotoEntity> {
return this.photoRepository.findOne({id});
}
}
```
## Using Custom Repository
Let's create a repository:
```typescript
import {Repository, EntityRepository} from '@cyber-rom/nestjs-scylladb';
import {PhotoEntity} from './photo.entity';
import {Observable} from 'rxjs';
@EntityRepository(PhotoEntity)
export class PhotoRepository extends Repository<PhotoEntity> {
findById(id: any): Observable<PhotoEntity> {
return this.findOne({id: id});
}
}
```
Let's have a look at the `PhotoModule`:
```typescript
import {Module} from '@nestjs/common';
import {ScyllaModule} from '@cyber-rom/nestjs-scylladb';
import {PhotoController} from './photo.controller';
import {PhotoRepository} from './photo.repository';
import {PhotoService} from './photo.service';
import {PhotoEntity} from './photo.entity';
@Module({
imports: [ScyllaModule.forFeature([PhotoEntity, PhotoRepository])],
providers: [PhotoService],
controllers: [PhotoController],
})
export class PhotoModule {}
```
Now let's use `PhotoRepository` in `PhotoService`:
```typescript
import {Observable} from 'rxjs';
import {Injectable} from '@nestjs/common';
import {InjectRepository} from '@cyber-rom/nestjs-scylladb';
import {PhotoRepository} from './photo.repository';
import {PhotoEntity} from './photo.entity';
@Injectable()
export class PersonService {
constructor(
@InjectRepository(PhotoRepository)
private readonly photoRepository: PhotoRepository,
) {}
getById(id: any): Observable<PhotoEntity> {
return this.photoRepository.findById(id);
}
}
```
Injecting connection:
```typescript
import {Observable} from 'rxjs';
import {Injectable} from '@nestjs/common';
import {InjectRepository, InjectConnection} from '@cyber-rom/nestjs-scylladb';
import {PhotoRepository} from './photo.repository';
import {PhotoEntity} from './photo.entity';
@Injectable()
export class PersonService {
constructor(
@InjectConnection()
private readonly connection: Connection,
@InjectRepository(PhotoRepository)
private readonly photoRepository: PhotoRepository,
) {}
getById(id: any): Observable<PhotoEntity> {
return this.photoRepository.findById(id);
}
}
```
## Using Elassandra
Express cassandra support `Elassandra`. For more details [see](https://express-cassandra.readthedocs.io/en/stable/elassandra/).
```typescript
@Module({
imports: [
ScyllaModule.forRoot({
clientOptions: {
// omitted other options for clarity
},
ormOptions: {
// omitted other options for clarity
migration: 'alter',
manageESIndex: true,
}
})
],
providers: [] // [...]
})
export class AppModule {}
```
```typescript
import {Entity, Column} from '@cyber-rom/nestjs-scylladb';
@Entity<PhotoEntity>({
table_name: 'photo',
key: ['id'],
es_index_mapping: {
discover: '.*',
properties: {
name: {
type: 'string',
index: 'analyzed',
},
},
},
})
export class PhotoEntity {
@Column({
type: 'uuid',
default: {$db_function: 'uuid()'},
})
id: any;
@Column({
type: 'text',
})
name: string;
}
```
```typescript
import {Module} from '@nestjs/common';
import {ScyllaModule} from '@cyber-rom/nestjs-scylladb';
import {PhotoController} from './photo.controller';
import {PhotoService} from './photo.service';
import {PhotoEntity} from './photo.entity';
@Module({
imports: [ScyllaModule.forFeature([PhotoEntity])],
providers: [PhotoService],
controllers: [PhotoController],
})
export class PhotoModule {}
```
```typescript
import {Injectable} from '@nestjs/common';
import {InjectModel, BaseModel} from '@cyber-rom/nestjs-scylladb';
import {PhotoEntity} from './photo.entity';
@Injectable()
export class PersonService {
constructor(
@InjectModel(PhotoEntity)
private readonly photoEntity: BaseModel<PhotoEntity>,
) {}
searchName(name: string): Promise<any> {
return new Promise((resolve, reject) => {
this.catModel.search({q: `name:${name}`}, (err, response) => {
if (err) {
return reject(err);
} else {
return response(response);
}
});
});
}
}
```