Skip to content

Commit

Permalink
refactor(lib): use nodejs client as wrapper, instead of implementing …
Browse files Browse the repository at this point in the history
…it independently.
  • Loading branch information
depyronick committed Dec 31, 2021
1 parent a044e21 commit 1c99eac
Show file tree
Hide file tree
Showing 12 changed files with 225 additions and 425 deletions.
164 changes: 101 additions & 63 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,3 @@
<p align="center">
<a href="http://nestjs.com/" target="blank"><img src="https://nestjs.com/img/logo_text.svg" width="320" alt="Nest Logo" /></a>
</p>

<p align="center">A progressive <a href="http://nodejs.org" target="blank">Node.js</a> framework for building efficient and scalable server-side applications.</p>
<p align="center">
<a href="https://www.npmjs.com/~nestjscore"><img src="https://img.shields.io/npm/v/@nestjs/core.svg" alt="NPM Version" /></a>
<a href="https://www.npmjs.com/~nestjscore"><img src="https://img.shields.io/npm/l/@nestjs/core.svg" alt="Package License" /></a>
<a href="https://www.npmjs.com/~nestjscore"><img src="https://img.shields.io/npm/dm/@nestjs/core.svg" alt="NPM Downloads" /></a>
<a href="https://circleci.com/gh/nestjs/nest" target="_blank"><img src="https://img.shields.io/circleci/build/github/nestjs/nest/master" alt="CircleCI" /></a>
<a href="https://coveralls.io/github/nestjs/nest?branch=master"><img src="https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#5" alt="Coverage" /></a>
<a href="https://discord.gg/G7Qnnhy" target="_blank"><img src="https://img.shields.io/badge/discord-online-brightgreen.svg" alt="Discord"/></a>
<a href="https://opencollective.com/nest#backer"><img src="https://opencollective.com/nest/backers/badge.svg" alt="Backers on Open Collective" /></a>
<a href="https://opencollective.com/nest#sponsor"><img src="https://opencollective.com/nest/sponsors/badge.svg" alt="Sponsors on Open Collective" /></a>
<a href="https://paypal.me/kamilmysliwiec"><img src="https://img.shields.io/badge/Donate-PayPal-dc3d53.svg"/></a>
<a href="https://twitter.com/nestframework"><img src="https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow"></a>
</p>
<!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)
[![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->

## Description

[ClickHouse®](https://clickhouse.com/) is an open-source, high performance columnar OLAP database management system for real-time analytics using SQL. ClickHouse combined with [TypeScript](https://www.typescriptlang.org/) helps you develop better type safety with your ClickHouse queries, giving you end-to-end typing.
Expand All @@ -32,7 +12,10 @@ $ npm i --save @depyronick/nestjs-clickhouse

## Quick Start

> This NestJS module is a wrapper for **[@depyronick/clickhouse-client](https://github.com/depyronick/clickhouse-client '@depyronick/clickhouse-client')**. You can find latest documentation for methods there.
### Importing the module

Once the installation process is complete, we can import the `ClickHouseModule` into the root `AppModule`.

```typescript
Expand All @@ -41,32 +24,40 @@ import { ClickHouseModule } from '@depyronick/nestjs-clickhouse';

@Module({
imports: [
ClickHouseModule.register([{
name: 'ANALYTICS_SERVER',
host: '127.0.0.1',
password: '7h3ul71m473p4555w0rd'
}])
ClickHouseModule.register([
{
name: 'ANALYTICS_SERVER',
host: '127.0.0.1',
password: '7h3ul71m473p4555w0rd',
},
]),
],
})
export class AppModule {}
```
The `register()` method will register a ClickHouse client with the specified connection options. See **[ClickHouseOptions](https://github.com/depyronick/nestjs-clickhouse/blob/main/lib/interfaces/ClickHouseModuleOptions.ts "ClickHouseOptions")** object for more information. Each registered client should have an unique `name` definition. The default value for `name` property is `CLICKHOUSE_DEFAULT`. This property will be used as an injection token.

The `register()` method will register a ClickHouse client with the specified connection options.

See **[ClickHouseOptions](https://github.com/depyronick/clickhouse-client/blob/main/src/client/interfaces/ClickHouseClientOptions.ts 'ClickHouseOptions')** object for more information.

Each registered client should have an unique `name` definition. The default value for `name` property is `CLICKHOUSE_DEFAULT`. This property will be used as an injection token.

### Interacting with ClickHouse Client

To interact with the ClickHouse server that you have just registered, inject it to your class using the injection token.

```typescript
constructor(
@Inject('ANALYTICS_SERVER')
@Inject('ANALYTICS_SERVER')
private analyticsServer: ClickHouseClient
) {}
```

> The `ClickHouseClient` class is imported from the `@depyronick/nestjs-clickhouse`.
There are two methods to interact with the server:
## Examples

### `ClickHouseClient.query<T>(query: string): Observable<T>`
#### `ClickHouseClient.query<T>(query: string): Observable<T>`

```typescript
import { Inject, Injectable } from '@nestjs/common';
Expand All @@ -85,11 +76,10 @@ interface VisitsTable {
export class AppService {
constructor(
@Inject('ANALYTICS_SERVER')
private readonly analyticsServer: ClickHouseClient
private readonly analyticsServer: ClickHouseClient,
) {
this
.analyticsServer
.query<VisitsTable>("SELECT * FROM visits LIMIT 10")
this.analyticsServer
.query<VisitsTable>('SELECT * FROM visits LIMIT 10')
.subscribe({
error: (err: any): void => {
// called when an error occurred during query
Expand All @@ -100,17 +90,57 @@ export class AppService {
},
complete: (): void => {
// called when stream is completed
}
},
});
}
}
```

#### `ClickHouseClient.queryPromise<T>(query: string): Promise<T[]>`

```typescript
import { Inject, Injectable } from '@nestjs/common';
import { ClickHouseClient } from '@depyronick/nestjs-clickhouse';

interface VisitsTable {
timestamp: number;
ip: string;
userAgent: string;
os: string;
version: string;
// ...
}

@Injectable()
export class AppService {
constructor(
@Inject('ANALYTICS_SERVER')
private readonly analyticsServer: ClickHouseClient,
) {
this.analyticsServer
.queryPromise<VisitsTable>('SELECT * FROM visits LIMIT 10')
.then((rows: VisitsTable[]) => {
// all retrieved rows
})
.catch((err) => {
// called when an error occurred during query
});

// or

const rows = await this.analyticsServer.queryPromise(
'SELECT * FROM visits LIMIT 10',
);
}
}
```

### `ClickHouseClient.insert<T>(table: string, data: T[]): Observable<any>`
#### `ClickHouseClient.insert<T>(table: string, data: T[]): Observable<any>`

The `insert` method accepts two inputs.

The `insert` method accepts two inputs.
- `table` is the name of the table that you'll be inserting data to.
- Table value could be prefixed with database like `analytics_db.visits`.
- `table` is the name of the table that you'll be inserting data to.
- Table value could be prefixed with database like `analytics_db.visits`.
- `data: T[]` array of JSON objects to insert.

```typescript
Expand All @@ -130,17 +160,19 @@ interface VisitsTable {
export class AppService {
constructor(
@Inject('ANALYTICS_SERVER')
private readonly analyticsServer: ClickHouseClient
private readonly analyticsServer: ClickHouseClient,
) {
this
.analyticsServer
.insert<VisitsTable>("visits", [{
timestamp: new Date().getTime(),
ip: '127.0.0.1',
os: 'OSX',
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/95.0.4638.69 Safari/537.36',
version: "1.0.0"
}])
this.analyticsServer
.insert<VisitsTable>('visits', [
{
timestamp: new Date().getTime(),
ip: '127.0.0.1',
os: 'OSX',
userAgent:
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/95.0.4638.69 Safari/537.36',
version: '1.0.0',
},
])
.subscribe({
error: (err: any): void => {
// called when an error occurred during insert
Expand All @@ -150,33 +182,38 @@ export class AppService {
},
complete: (): void => {
// called when insert is completed
}
})
},
});
}
}
```

## Multiple Clients

You can register multiple clients in the same application as follows:

```typescript
@Module({
imports: [
ClickHouseModule.register([{
name: 'ANALYTICS_SERVER',
host: '127.0.0.1',
password: '7h3ul71m473p4555w0rd'
}, {
name: 'CHAT_SERVER',
host: '192.168.1.110',
password: 'ch5ts3rv3Rp455w0rd'
}])
ClickHouseModule.register([
{
name: 'ANALYTICS_SERVER',
host: '127.0.0.1',
password: '7h3ul71m473p4555w0rd',
},
{
name: 'CHAT_SERVER',
host: '192.168.1.110',
password: 'ch5ts3rv3Rp455w0rd',
},
]),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule { }
export class AppModule {}
```

Then you can interact with these servers using their assigned injection tokens.

```typescript
Expand All @@ -190,10 +227,11 @@ constructor(
```

## Notes

- This repository will be actively maintained and improved.
- Currently only supports JSON format.
- Planning to support all applicable formats listed [here](https://clickhouse.com/docs/en/interfaces/formats/ "here").
- Planning to implement TCP protocol, if ClickHouse decides to [documentate](https://clickhouse.com/docs/en/interfaces/tcp/ "documentate") it.
- Currently only supports JSON format.
- Planning to support all applicable formats listed [here](https://clickhouse.com/docs/en/interfaces/formats/ 'here').
- Planning to implement TCP protocol, if ClickHouse decides to [documentate](https://clickhouse.com/docs/en/interfaces/tcp/ 'documentate') it.
- Planning to implement inserts with streams.
- This library supports http response compressions such as brotli, gzip and deflate.

Expand Down
8 changes: 6 additions & 2 deletions lib/clickhouse.module.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { DynamicModule, Module } from '@nestjs/common';

import { ClickHouseClient } from './client/ClickHouseClient';
import { ClickHouseModuleOptions } from './interfaces/ClickHouseModuleOptions';
import {
ClickHouseClient,
ClickHouseClientOptions as ClickHouseNodeClientOptions
} from '@depyronick/clickhouse-client';

export class ClickHouseModuleOptions extends ClickHouseNodeClientOptions { }

@Module({})
export class ClickHouseModule {
Expand Down
Loading

0 comments on commit 1c99eac

Please sign in to comment.