{"_id":"@dev5c32373043/nestjs-cassyllandra","name":"@dev5c32373043/nestjs-cassyllandra","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@dev5c32373043/nestjs-cassyllandra","description":"Set of utilities for NestJS based on express-cassandra package","author":{"name":"dev5c32373043"},"version":"1.0.0","license":"MIT","main":"dist/index.js","types":"dist/index.d.ts","scripts":{"lint":"tslint -p tsconfig.json -c tslint.json","build":"rm -rf dist && tsc -p tsconfig.json","publish:npm":"npm publish --access public","prepublish:npm":"npm run build","test":"jest --config ./test/jest-conf.json --runInBand"},"dependencies":{"cassandra-driver":"^4.6.4","express-cassandra":"^2.9.0","merge-deep":"^3.0.3"},"peerDependencies":{"@nestjs/common":"^8.0.0 || ^9.0.0 || ^10.0.0","@nestjs/core":"^8.0.0 || ^9.0.0 || ^10.0.0","reflect-metadata":"^0.1.13","rxjs":"^6.0.0 || ^7.0.0"},"devDependencies":{"@nestjs/common":"^10.0.2","@nestjs/core":"^10.0.2","@nestjs/testing":"^10.0.5","@ngneat/falso":"^6.4.0","@types/jest":"^29.5.2","@types/node":"^20.3.1","@typescript-eslint/eslint-plugin":"^6.0.0","@typescript-eslint/parser":"^6.0.0","eslint":"^8.44.0","eslint-config-prettier":"^8.8.0","eslint-plugin-prettier":"^5.0.0","jest":"^29.6.1","lint-staged":"^13.2.2","prettier":"^3.0.0","reflect-metadata":"^0.1.13","rxjs":"^7.8.1","ts-jest":"^29.1.1","ts-loader":"^9.4.4","ts-node":"^10.9.1","tsconfig-paths":"^4.2.0","tslint":"^6.1.3","typescript":"^5.1.3"},"lint-staged":{"*.ts":["prettier --write","git add"]},"engines":{"node":">=14.17.0"},"homepage":"https://github.com/dev5c32373043/nestjs-cassyllandra#readme","repository":{"type":"git","url":"git+https://github.com/dev5c32373043/nestjs-cassyllandra.git"},"bugs":{"url":"https://github.com/dev5c32373043/nestjs-cassyllandra/issues"},"keywords":["nest","nestjs","orm","scylla","scylladb","cassandra","express-cassandra"],"directories":{"lib":"lib","test":"test"},"gitHead":"cba4713a537e63ac7bd992400380ed6fb1261154","_id":"@dev5c32373043/nestjs-cassyllandra@1.0.0","_nodeVersion":"18.16.0","_npmVersion":"9.7.1","dist":{"integrity":"sha512-+qdhbMC1ZSheZrBR/hEeuu629MUFU1u6jDo7fzgGWrQgqtR12RT1SyDP511ezA3scyuf1qCdqru+REo+EcFIdw==","shasum":"043d2f4fc9625545aaa931eba90b9379f6f0b8ac","tarball":"https://registry.npmjs.org/@dev5c32373043/nestjs-cassyllandra/-/nestjs-cassyllandra-1.0.0.tgz","fileCount":176,"unpackedSize":212819,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDheFtC2gdPtSrJdPTiVFteBiLQTWX5XWz6YRuRpLHaJgIgNJjQlsK549TYnfw8O+vWDnMSXb/OsBY88mbaM3/E99I="}]},"_npmUser":{"name":"pickydude","email":"nofound12345@gmail.com"},"maintainers":[{"name":"pickydude","email":"nofound12345@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/nestjs-cassyllandra_1.0.0_1689607901446_0.2039350588631812"},"_hasShrinkwrap":false}},"time":{"created":"2023-07-17T15:31:41.373Z","1.0.0":"2023-07-17T15:31:41.685Z","modified":"2023-07-17T15:31:41.985Z"},"maintainers":[{"name":"pickydude","email":"nofound12345@gmail.com"}],"description":"Set of utilities for NestJS based on express-cassandra package","homepage":"https://github.com/dev5c32373043/nestjs-cassyllandra#readme","keywords":["nest","nestjs","orm","scylla","scylladb","cassandra","express-cassandra"],"repository":{"type":"git","url":"git+https://github.com/dev5c32373043/nestjs-cassyllandra.git"},"author":{"name":"dev5c32373043"},"bugs":{"url":"https://github.com/dev5c32373043/nestjs-cassyllandra/issues"},"license":"MIT","readme":"# Cassyllandra 🦠‍\n\nSet of utilities for NestJS based on [express-cassandra](https://www.npmjs.com/package/express-cassandra) package.\n[express-cassandra](https://www.npmjs.com/package/express-cassandra) is a Cassandra ORM/ODM/OGM for NodeJS with support for Apache Cassandra, ScyllaDB, Datastax Enterprise, Elassandra & JanusGraph.\n\nBased on https://www.npmjs.com/package/@ouato/nestjs-express-cassandra with bug fixes, new features, dependency updates and more.\n\n## Installation\n\n```bash\n$ npm i @dev5c32373043/nestjs-cassyllandra\n```\n\n## Usage\n\n```typescript\nimport { CassyllandraModule } from '@dev5c32373043/nestjs-cassyllandra';\n\n@Module({\n  imports: [\n    CassyllandraModule.forRoot({\n      clientOptions: {\n        contactPoints: ['127.0.0.1'],\n        keyspace: 'dev',\n        localDataCenter: 'datacenter1',\n        queryOptions: {\n          consistency: 1,\n        },\n      },\n      ormOptions: {\n        createKeyspace: true,\n        defaultReplicationStrategy: {\n          class: 'SimpleStrategy',\n          replication_factor: 1,\n        },\n        migration: 'alter',\n      },\n      skipQueryTypeCheck: true,\n    }),\n  ],\n  providers: [],\n})\nexport class AppModule {}\n```\n\n`skipQueryTypeCheck: boolean` - globally skip field type check in queries instead of [per field basis](https://github.com/masumsoft/express-cassandra/blob/master/docs/validators.md#disabling-built-in-type-validation), default: false\n\nFor more client options look [here](https://docs.datastax.com/en/developer/nodejs-driver/4.6/api/type.ClientOptions/)\n\nFor more details about orm options look [here](https://express-cassandra.readthedocs.io/en/stable/usage/)\n\n## Async options\n\nQuite often you might want to asynchronously pass your module options instead of passing them beforehand. In such case, use forRootAsync() method, that provides a couple of various ways to deal with async data.\n\n**1. Use factory**\n\n```typescript\nCassyllandraModule.forRootAsync({\n  useFactory: () => ({...}),\n})\n```\n\nObviously, our factory behaves like every other one (might be `async` and is able to inject dependencies through `inject`).\n\n```typescript\nCassyllandraModule.forRootAsync({\n  imports: [ConfigModule],\n  useFactory: (configService: ConfigService) => configService.get('db'),\n  inject: [ConfigService],\n});\n```\n\n**2. Use class**\n\n```typescript\nCassyllandraModule.forRootAsync({\n  useClass: ConfigService,\n});\n```\n\nAbove construction will instantiate `ConfigService` inside `CassyllandraModule` and will leverage it to create options object.\n\n```typescript\nclass ConfigService implements CassyllandraOptionsFactory {\n  createCassyllandraOptions(): CassyllandraModuleOptions {\n    return {...};\n  }\n}\n```\n\n**3. Use existing**\n\n```typescript\nCassyllandraModule.forRootAsync({\n  imports: [ConfigModule],\n  useExisting: ConfigService,\n});\n```\n\nIt works the same as `useClass` with one critical difference - `CassyllandraModule` will look up imported modules to reuse already created ConfigService, instead of instantiating it on its own.\n\n## ORM Options\n\nDefining our entity.\n\n```typescript\nimport {\n  Entity,\n  Column,\n  GeneratedUUidColumn,\n  CreateDateColumn,\n  UpdateDateColumn,\n  VersionColumn,\n} from '@dev5c32373043/nestjs-cassyllandra';\n\n@Entity({\n  table_name: 'activities',\n  key: ['id'],\n})\nexport class ActivityEntity {\n  @GeneratedUUidColumn()\n  id: any;\n\n  @Column({\n    name: 'action',\n    type: 'text',\n    rule: {\n      required: true,\n    },\n  })\n  action: string;\n\n  @Column({\n    name: 'time',\n    type: 'timestamp',\n    default: { $db_function: 'toTimestamp(now())' },\n  })\n  time: Date;\n\n  @Column({\n    name: 'username',\n    type: 'text',\n    rule: {\n      required: true,\n    },\n  })\n  username: string;\n\n  @Column({\n    name: 'value',\n    type: 'float',\n    default: '1',\n  })\n  value: number;\n\n  @CreateDateColumn()\n  createdAt: Date;\n\n  @UpdateDateColumn()\n  updatedAt: Date;\n\n  @VersionColumn()\n  __v: string;\n}\n```\n\nLet's have a look at the `ActivityModule`\n\n```typescript\nimport { Module } from '@nestjs/common';\nimport { CassyllandraModule } from '@dev5c32373043/nestjs-cassyllandra';\nimport { ActivityService } from './activity.service';\nimport { ActivityController } from './activity.controller';\nimport { ActivityEntity } from './activity.entity';\n\n@Module({\n  imports: [CassyllandraModule.forFeature([ActivityEntity])],\n  providers: [ActivityService],\n  controllers: [ActivityController],\n})\nexport class ActivityModule {}\n```\n\nThis module uses `forFeature()` method to define which entities shall be registered in the current scope. Thanks to that we can inject the `ActivityEntity` to the `ActivityService` using the `@InjectModel()` decorator:\n\n```typescript\nimport { Injectable } from '@nestjs/common';\nimport { InjectModel, BaseModel } from '@dev5c32373043/nestjs-cassyllandra';\nimport { ActivityEntity } from './activity.entity';\n\n@Injectable()\nexport class ActivityService {\n  constructor(\n    @InjectModel(ActivityEntity)\n    private readonly activityEntity: BaseModel<ActivityEntity>,\n  ) {}\n\n  getByAction(action: string): Promise<ActivityEntity> {\n    return this.activityEntity.findOneAsync({ action }, { raw: true, allow_filtering: true });\n  }\n}\n```\n\n**Using Column Decorators:**\nTo auto-generate uuid/timeuuid column, you need to decorate an entity's properties you want to make into an auto-generated\nuuid/timeuuid column with a `@GeneratedUUidColumn` decorator.\n\n```typescript\nimport { Entity, Column, GeneratedUUidColumn } from '@dev5c32373043/nestjs-cassyllandra';\n\n@Entity({\n  table_name: 'activities',\n  key: ['id'],\n})\nexport class ActivityEntity {\n  @GeneratedUUidColumn()\n  id: any;\n\n  @GeneratedUUidColumn('timeuuid')\n  time_id: any;\n}\n```\n\nTo auto-generate createdDate/updatedDate column, you need to decorate an entity's properties you want to make into an auto-generated\ncreatedDate/updatedDate column with a `@CreateDateColumn` or `@UpdateDateColumn` decorator (not combine with `@Column` decorator).\n\nTo index a column, you need to decorate an entity's properties you want to index with a `@IndexColumn` decorator.\n\nTo auto-generate version column, you need to decorate an entity's properties you want to make into an auto-generated\nversion column with a `@VersionColumn` decorator (not combine with `@Column` decorator).\n\n```typescript\nimport {\n  Column,\n  Entity,\n  IndexColumn,\n  VersionColumn,\n  UpdateDateColumn,\n  CreateDateColumn,\n  GeneratedUUidColumn,\n} from '@dev5c32373043/nestjs-cassyllandra';\n\n@Entity({\n  table_name: 'activities',\n  key: ['id'],\n})\nexport class ActivityEntity {\n  @GeneratedUUidColumn()\n  id: any;\n\n  @Column({\n    type: 'text',\n  })\n  @IndexColumn()\n  action: string;\n\n  @CreateDateColumn()\n  createdAt: Date;\n\n  @UpdateDateColumn()\n  updatedAt: Date;\n\n  @VersionColumn()\n  __v: any;\n}\n```\n\n**Using Hook Function Decorators:**\nAn entity of express-cassandra support multiple hook function. For more details [see](https://express-cassandra.readthedocs.io/en/stable/management/#hook-functions).\n\nTo create hook function in an entity use `@BeforeSave`, `@AfterSave`, `@BeforeUpdate`, `@AfterUpdate`, `@BeforeDelete`, `@AfterDelete` decorators.\n\n```typescript\nimport {\n  Entity,\n  Column,\n  AfterSave,\n  BeforeSave,\n  AfterUpdate,\n  AfterDelete,\n  BeforeDelete,\n  BeforeUpdate,\n  GeneratedUUidColumn,\n} from '@dev5c32373043/nestjs-cassyllandra';\n\n@Entity({\n  table_name: 'activities',\n  key: ['id'],\n})\nexport class ActivityEntity {\n  @GeneratedUUidColumn()\n  id: any;\n\n  @BeforeSave()\n  beforeSave(instance) {\n    // your code here\n  }\n\n  @AfterSave()\n  afterSave(instance) {\n    // your code here\n  }\n\n  @BeforeUpdate()\n  beforeUpdate(query, updateValues, options) {\n    // your code here\n  }\n\n  @AfterUpdate()\n  afterUpdate(query, updateValues, options) {\n    // your code here\n  }\n\n  @BeforeDelete()\n  beforeDelete(query, options) {\n    // your code here\n  }\n\n  @AfterDelete()\n  afterDelete(query, options) {\n    // your code here\n  }\n}\n```\n\n## Using Model\n\n### Important Note: `BaseModel<T>` is a wrapper for [express-cassandra](https://www.npmjs.com/package/express-cassandra) model. If column names in the model differ (e.g., `@Column({ name: 'my_field', type: 'text' }) myField: string`), you must handle the mapping yourself. Alternatively, consider using the `Repository` for a cleaner approach. Choose based on your needs.\n\n```typescript\nimport { Injectable } from '@nestjs/common';\nimport { BaseModel, InjectModel, ResultSet } from '@dev5c32373043/nestjs-cassyllandra';\n\nimport { ActivityEntity } from './activity.model';\n\n@Injectable()\nexport class ActivityService {\n  readonly entitySource: string;\n\n  constructor(\n    @InjectModel(ActivityEntity)\n    readonly activityModel: BaseModel<ActivityEntity>,\n  ) {\n    this.entitySource = `${this.activityModel.get_keyspace_name()}\".\"${this.activityModel.get_table_name()}`;\n  }\n\n  async save(payload) {\n    const activity = new this.activityModel(payload);\n    await activity.saveAsync();\n    return activity.toJSON();\n  }\n\n  async update(query, payload) {\n    return this.activityModel.updateAsync(query, payload);\n  }\n\n  async delete(query, opts) {\n    return this.activityModel.deleteAsync(query, opts);\n  }\n\n  async find(query, opts) {\n    return this.activityModel.findAsync(query, opts);\n  }\n\n  async findOne(q, opts) {\n    return this.activityModel.findOneAsync(q, opts);\n  }\n\n  async stream(query, opts, onRead) {\n    return new Promise((resolve, reject) => {\n      this.activityModel.stream(query, opts, onRead, err => {\n        if (err) return reject(err);\n        resolve(null);\n      });\n    });\n  }\n\n  eachRow(query, opts, onRead): Promise<any> {\n    return new Promise((resolve, reject) =>\n      this.activityModel.eachRow(query, opts, onRead, err => {\n        if (err) return reject(err);\n        resolve(null);\n      }),\n    );\n  }\n\n  async rawQuery(query, params = []): Promise<ResultSet> {\n    return this.activityModel.execute_queryAsync(query, params);\n  }\n\n  async doBatch(queries: { query: string; params: any[] }[]): Promise<void> {\n    await activityModel.execute_batchAsync(queries);\n  }\n\n  async truncate(): Promise<void> {\n    await this.activityModel.truncateAsync();\n  }\n}\n```\n\nFor more details look [here](https://express-cassandra.readthedocs.io/en/stable/)\n\n## Using Repository\n\n```typescript\nimport { Module } from '@nestjs/common';\nimport { CassyllandraModule } from '@dev5c32373043/nestjs-cassyllandra';\nimport { ActivityService } from './activity.service';\nimport { ActivityController } from './activity.controller';\nimport { ActivityEntity } from './activity.entity';\n\n@Module({\n  imports: [CassyllandraModule.forFeature([ActivityEntity])],\n  providers: [ActivityService],\n  controllers: [ActivityController],\n})\nexport class ActivityModule {}\n```\n\n```typescript\nimport { Injectable } from '@nestjs/common';\nimport { InjectRepository, Repository } from '@dev5c32373043/nestjs-cassyllandra';\nimport { ActivityEntity } from './activity.entity';\n\n@Injectable()\nexport class ActivityService {\n  constructor(\n    @InjectRepository(ActivityEntity)\n    private readonly activityRepository: Repository<ActivityEntity>,\n  ) {}\n\n  async create(payload): Promise<ActivityEntity> {\n    return this.activityRepository.create(payload);\n  }\n\n  async insertMany(payload): Promise<ActivityEntity[]> {\n    return this.activityRepository.insertMany(payload);\n  }\n\n  async update(query, payload, opts = {}): Promise<any> {\n    return this.activityRepository.update(query, payload, opts);\n  }\n\n  async removeOne(entity, opts = {}): Promise<void> {\n    await this.activityRepository.removeOne(entity, opts);\n  }\n\n  async removeMany(entities, opts = {}): Promise<void> {\n    await this.activityRepository.removeMany(entities, opts);\n  }\n\n  async delete(query, opts = {}): Promise<void> {\n    await this.activityRepository.delete(query, opts);\n  }\n\n  async find(q?: object, opts?: object): Promise<ActivityEntity[]> {\n    return this.activityRepository.find(q, opts);\n  }\n\n  async findOne(q?: object, opts?: object): Promise<ActivityEntity> {\n    return this.activityRepository.findOne(q, opts);\n  }\n\n  async findOneOrFail(q?: object, opts?: object): Promise<ActivityEntity> {\n    return this.activityRepository.findOneOrFail(q, opts);\n  }\n\n  async stream(query, opts, onRead): Promise<any> {\n    return this.activityRepository.stream(query, opts, onRead);\n  }\n\n  async eachRow(query, opts, onRead): Promise<any> {\n    return this.activityRepository.eachRow(query, opts, onRead);\n  }\n\n  async rawQuery(query): Promise<ResultSet> {\n    return this.activityRepository.executeQuery(query);\n  }\n\n  async truncate(): Promise<void> {\n    await this.activityRepository.truncate();\n  }\n}\n```\n\n**Using Batch operations:**\n\n```typescript\n@Injectable()\nexport class ActivitiesService {\n  constructor(\n    @InjectRepository(ActivityEntity)\n    private readonly activityRepository: Repository<ActivityEntity>,\n  ) {}\n\n  async performBatchOps(): Promise<void> {\n    const activity1 = { id: 'c4a07d0f-51f1-4a7d-9dcb-b3166265931d', action: 'action', username: 'user', value: 0 };\n    const activity2 = {\n      id: 'c7579abc-e22f-411d-a7c7-a445952701d8',\n      action: 'action',\n      username: 'inactive user',\n      value: 0,\n    };\n\n    const batch = this.activityRepository.initBatch();\n    batch.insert({ action: 'new action', username: 'user', value: 1 });\n    batch.update({ id: activity1.id }, { value: 1 });\n    batch.remove({ id: activity2.id });\n\n    await batch.execute();\n  }\n}\n```\n\n## Using Custom Repository\n\nLet's create a repository:\n\n```typescript\nimport { Repository, EntityRepository } from '@dev5c32373043/nestjs-cassyllandra';\nimport { ActivityEntity } from './activity.entity';\n\n@EntityRepository(ActivityEntity)\nexport class ActivityRepository extends Repository<ActivityEntity> {\n  async findById(id: any): Promise<ActivityEntity> {\n    return this.findOne({ id: id });\n  }\n}\n```\n\nLet's have a look at the `ActivityModule`:\n\n```typescript\nimport { Module } from '@nestjs/common';\nimport { CassyllandraModule } from '@dev5c32373043/nestjs-cassyllandra';\n\nimport { ActivitiesController } from './activities.controller';\nimport { ActivityRepository } from './activity.repository';\nimport { ActivityService } from './activity.service';\nimport { ActivityEntity } from './activity.entity';\n\n@Module({\n  imports: [CassyllandraModule.forFeature([ActivityEntity, ActivityRepository])],\n  providers: [ActivityService],\n  controllers: [ActivitiesController],\n})\nexport class ActivitiesModule {}\n```\n\nNow let's use `ActivityRepository` in `ActivityService`:\n\n```typescript\nimport { Injectable } from '@nestjs/common';\nimport { InjectRepository } from '@dev5c32373043/nestjs-cassyllandra';\n\nimport { ActivityRepository } from './activity.repository';\nimport { ActivityEntity } from './activity.entity';\n\n@Injectable()\nexport class ActivityService {\n  constructor(\n    @InjectRepository(ActivityRepository)\n    private readonly activityRepository: ActivityRepository,\n  ) {}\n\n  async getById(id: any): Promise<ActivityEntity> {\n    return this.activityRepository.findById(id);\n  }\n}\n```\n\nInjecting connection:\n\n```typescript\nimport { Injectable } from '@nestjs/common';\nimport { InjectRepository, InjectConnection } from '@dev5c32373043/nestjs-cassyllandra';\n\nimport { ActivityRepository } from './activity.repository';\nimport { ActivityEntity } from './activity.entity';\n\n@Injectable()\nexport class PersonService {\n  constructor(\n    @InjectConnection()\n    private readonly connection: Connection,\n    @InjectRepository(ActivityRepository)\n    private readonly activityRepository: ActivityRepository,\n  ) {}\n\n  async getById(id: any): Promise<ActivityEntity> {\n    return this.activityRepository.findById(id);\n  }\n}\n```\n\n## Using Elassandra\n\nExpress cassandra support `Elassandra`. For more details [see](https://express-cassandra.readthedocs.io/en/stable/elassandra/).\n\n```typescript\n@Module({\n  imports: [\n    ScyllaModule.forRoot({\n      clientOptions: {\n        // omitted other options for clarity\n      },\n      ormOptions: {\n        // omitted other options for clarity\n        migration: 'alter',\n        manageESIndex: true,\n      },\n    }),\n  ],\n  providers: [], // [...]\n})\nexport class AppModule {}\n```\n\n```typescript\nimport { Entity, Column } from '@dev5c32373043/nestjs-cassyllandra';\n\n@Entity({\n  table_name: 'activities',\n  key: ['id'],\n  es_index_mapping: {\n    discover: '.*',\n    properties: {\n      action: {\n        type: 'string',\n        index: 'analyzed',\n      },\n    },\n  },\n})\nexport class ActivityEntity {\n  @Column({\n    type: 'uuid',\n    default: { $db_function: 'uuid()' },\n  })\n  id: any;\n\n  @Column({\n    type: 'text',\n  })\n  action: string;\n}\n```\n\n```typescript\nimport { Module } from '@nestjs/common';\nimport { CassyllandraModule } from '@dev5c32373043/nestjs-cassyllandra';\n\nimport { ActivitiesController } from './activities.controller';\nimport { ActivitiesService } from './activities.service';\nimport { ActivityEntity } from './activity.entity';\n\n@Module({\n  imports: [CassyllandraModule.forFeature([ActivityEntity])],\n  providers: [ActivitiesService],\n  controllers: [ActivitiesController],\n})\nexport class ActivitiesModule {}\n```\n\n```typescript\nimport { Injectable } from '@nestjs/common';\nimport { InjectModel, BaseModel } from '@dev5c32373043/nestjs-cassyllandra';\nimport { promisify } from 'util';\n\nimport { ActivityEntity } from './activity.entity';\n\n@Injectable()\nexport class ActivitiesService {\n  constructor(\n    @InjectModel(ActivityEntity)\n    private readonly activityEntity: BaseModel<ActivityEntity>,\n  ) {}\n\n  searchName(action: string): Promise<any> {\n    return promisify(this.activityEntity.search)({ q: `action:${action}` });\n  }\n}\n```\n\n## Requirements\n\n- [Node.js][node] 14.17.0+\n- [Nest.js][nestjs] 8.0.0+\n\n[node]: https://nodejs.org/\n[nestjs]: https://nestjs.com/\n\n## Contributing\n\nAny contribution is highly appreciated.\n","readmeFilename":"README.md"}