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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@makebelieve21213-packages/clickhouse-client

v1.0.1

Published

ClickHouse database client module for NestJS with migration support for OLAP analytics

Readme

@makebelieve21213-packages/clickhouse-client

ClickHouse database client для NestJS с поддержкой TypeScript и полной типобезопасностью.

📋 Содержание

🚀 Возможности

  • NestJS интеграция - глобальный модуль с forRootAsync для простой интеграции
  • Type-safe API - полная типобезопасность TypeScript с экспортируемыми типами
  • ClickHouse клиент - использование официального @clickhouse/client
  • Конфигурация - поддержка конфигурации через ConfigModule
  • Миграции - поддержка миграций через clickhouse-migrations
  • Singleton паттерн - эффективное использование ресурсов
  • Graceful shutdown - корректное закрытие соединения при завершении приложения
  • Обработка ошибок - детальная обработка ошибок API с логированием
  • Параметризованные запросы - безопасность через параметризацию
  • 100% покрытие тестами - надежность и качество кода

📋 Требования

  • Node.js: >= 22.11.0
  • NestJS: >= 11.0.0
  • ClickHouse Server: рекомендуется версия 23.x или выше

📦 Установка

npm install @makebelieve21213-packages/clickhouse-client

Зависимости

{
  "@nestjs/common": "^11.0.0",
  "@nestjs/config": "^4.0.0",
  "@clickhouse/client": "^1.12.0",
  "@packages/logger": "^1.0.0",
  "@packages/types": "^1.0.0",
  "reflect-metadata": "^0.1.13 || ^0.2.0"
}

📁 Структура пакета

src/
├── main/                    # NestJS модуль
├── types/                   # TypeScript типы
├── migrations/              # SQL миграции
├── utils/                   # Утилиты
└── index.ts                 # Экспорты

🏗️ Архитектура

Пакет предоставляет NestJS глобальный модуль ClickhouseClientModule для работы с ClickHouse базой данных через официальный клиент @clickhouse/client.

Основные компоненты:

  • ClickhouseClientModule - NestJS глобальный модуль
  • ClickhouseClientService - сервис для работы с базой данных
  • ClickhouseConfig - конфигурация клиента

🔧 Быстрый старт

Шаг 1: Настройка переменных окружения

CH_URL=http://localhost:8123
CH_USERNAME=default
CH_PASSWORD=your-password-here
CH_DATABASE=NA_KOLENKE_CHAIN

Шаг 2: Создание конфигурации

Создайте файл clickhouse.config.ts в вашем сервисе:

import { registerAs } from "@nestjs/config";
import type { ClickhouseConfig } from "@makebelieve21213-packages/clickhouse-client";
import { CONFIG_SYMBOLS } from "@packages/types";

const clickhouseConfig = registerAs<ClickhouseConfig>(
  CONFIG_SYMBOLS.CLICKHOUSE,
  (): ClickhouseConfig => ({
    url: process.env.CH_URL!,
    username: process.env.CH_USERNAME!,
    password: process.env.CH_PASSWORD!,
    database: process.env.CH_DATABASE!,
  }),
);

export default clickhouseConfig;

Шаг 3: Регистрация модуля

// app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { ClickhouseClientModule, type ClickhouseConfig } from '@makebelieve21213-packages/clickhouse-client';
import { CONFIG_SYMBOLS } from '@packages/types';
import clickhouseConfig from 'src/configs/clickhouse.config';

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
      load: [clickhouseConfig],
    }),
    ClickhouseClientModule.forRootAsync({
      imports: [ConfigModule],
      useFactory: (...args: unknown[]) => {
        const configService = args[0] as ConfigService;
        return configService.get<ClickhouseConfig>(CONFIG_SYMBOLS.CLICKHOUSE)!;
      },
      inject: [ConfigService],
    }),
  ],
})
export class AppModule {}

Шаг 4: Использование сервиса

// analytics.service.ts
import { Injectable } from '@nestjs/common';
import { ClickhouseClientService } from '@makebelieve21213-packages/clickhouse-client';
import type { Transfer } from './types';

@Injectable()
export class AnalyticsService {
  constructor(private readonly clickhouse: ClickhouseClientService) {}

  async getTransfers(blockNumber: number): Promise<Transfer[]> {
    return await this.clickhouse.query<Transfer>(
      'SELECT * FROM transfers WHERE block_number > {blockNumber:UInt64}',
      { blockNumber }
    );
  }
}

📚 API Reference

ClickhouseClientModule

forRootAsync(options):

ClickhouseClientModule.forRootAsync({
  imports: [ConfigModule],
  useFactory: (...args: unknown[]) => {
    const configService = args[0] as ConfigService;
    return configService.get<ClickhouseConfig>(CONFIG_SYMBOLS.CLICKHOUSE)!;
  },
  inject: [ConfigService],
})

Экспортирует: ClickhouseClientService (глобально)

ClickhouseClientService

Конфигурация:

  • url: string - URL сервера ClickHouse
  • username: string - имя пользователя
  • password: string - пароль
  • database: string - имя базы данных

Методы:

exec(sql, params?)

Выполняет SQL команды (CREATE, INSERT, UPDATE, DELETE, ALTER). Поддерживает выполнение нескольких команд, разделенных точкой с запятой.

async exec(sql: string, params?: Record<string, unknown>): Promise<void>

Пример:

// Создание таблицы
await clickhouse.exec(`
  CREATE TABLE IF NOT EXISTS test_table (
    id UInt64,
    name String,
    created_at DateTime64(3, 'UTC')
  ) ENGINE = MergeTree() ORDER BY id
`);

// Выполнение с параметрами
await clickhouse.exec(
  'ALTER TABLE test_table DELETE WHERE id = {id:UInt64}',
  { id: 123 }
);

// Множественные команды
await clickhouse.exec(`
  CREATE TABLE IF NOT EXISTS table1 (id UInt64) ENGINE = Memory;
  CREATE TABLE IF NOT EXISTS table2 (id UInt64) ENGINE = Memory;
`);

query<T>(sql, params?)

Выполняет SELECT запросы и возвращает результат в формате JSON.

async query<T>(sql: string, params?: Record<string, unknown>): Promise<T[]>

Пример:

interface Transfer {
  contract_address: string;
  block_number: number;
  tx_hash: string;
  from: string;
  to: string;
  value: number;
}

// Простой запрос
const transfers = await clickhouse.query<Transfer>(
  'SELECT * FROM transfers LIMIT 10'
);

// Запрос с параметрами
const recentTransfers = await clickhouse.query<Transfer>(
  'SELECT * FROM transfers WHERE block_number > {blockNumber:UInt64} AND timestamp > {date:DateTime64}',
  { 
    blockNumber: 18000000,
    date: new Date().toISOString()
  }
);

// Агрегация данных
const stats = await clickhouse.query<{ count: number; total_value: number }>(
  'SELECT count() as count, sum(value) as total_value FROM transfers WHERE block_number > {blockNumber:UInt64}',
  { blockNumber: 18000000 }
);

insert<T>(tableName, rows)

Вставляет массив объектов в указанную таблицу. Автоматически фильтрует null и undefined значения.

async insert<T>(tableName: string, rows: T[]): Promise<void>

Пример:

const transfersData = [
  {
    contract_address: '0x123...',
    transfer_type: 'ERC-20',
    block_number: 18000001,
    timestamp: new Date().toISOString(),
    tx_hash: '0xabc...',
    from: '0x456...',
    to: '0x789...',
    value: 100.5,
    symbol: 'ETH',
    gas_used: 21000,
    gas_price: 20000000000,
    fee_eth: 0.00042
  },
  // ... больше данных
];

// Вставка в основную таблицу
await clickhouse.insert('transfers', transfersData);

// Вставка в буферную таблицу (рекомендуется для массовых операций)
await clickhouse.insert('transfers_buffer', transfersData);

get client()

Прямой доступ к клиенту ClickHouse для расширенных операций.

get client(): ClickHouseClient | undefined

Пример:

// Получение статистики сервера
const stats = await clickhouse.client?.query({
  query: 'SELECT * FROM system.metrics',
  format: 'JSON'
});

🧪 Примеры использования

Выполнение команд

await clickhouse.exec('CREATE TABLE test (id UInt64) ENGINE = Memory');

Типизированные запросы

const transfers = await clickhouse.query<Transfer>(
  'SELECT * FROM transfers WHERE block_number > {blockNumber:UInt64}',
  { blockNumber: 18000000 }
);

Массовая вставка

await clickhouse.insert('transfers_buffer', transfersData);

📝 Миграции

Пакет включает систему миграций для управления схемой базы данных через clickhouse-migrations.

Структура миграций

Миграции находятся в папке src/migrations/:

  • 1_create_main_database.sql - Создание основной базы данных NA_KOLENKE_CHAIN
  • 2_create_analytics_table.sql - Создание таблиц transfers и transfers_buffer

Выполнение миграций

pnpm run migrate:dev

Создание новой миграции

  1. Создайте новый файл в src/migrations/ с номером и описательным именем:

    3_add_user_table.sql
  2. Добавьте SQL команды:

    CREATE TABLE IF NOT EXISTS NA_KOLENKE_CHAIN.users (
        id UInt64,
        wallet_address String,
        created_at DateTime64(3, 'UTC')
    ) ENGINE = MergeTree() ORDER BY id;
  3. Выполните миграцию:

    pnpm run migrate:dev

🚨 Troubleshooting

Connection timeout

Решение: Проверить доступность сервера ClickHouse, проверить переменные окружения CH_URL, CH_USERNAME, CH_PASSWORD.

Table not found

Решение: Выполнить миграции через pnpm run migrate:dev, проверить правильность имени базы данных.

Query execution failed

Решение: Проверить синтаксис SQL запроса, проверить типы параметров в параметризованных запросах.

Insert failed

Решение: Проверить соответствие полей объектов названиям колонок таблицы, проверить типы данных.

🧪 Тестирование

Пакет имеет 100% покрытие тестами.

pnpm test                # Все тесты
pnpm test:coverage       # С покрытием
pnpm test:watch          # Watch режим

🔧 Конфигурация

interface ClickhouseConfig {
  url: string;        // URL сервера ClickHouse
  username: string;   // Имя пользователя
  password: string;   // Пароль
  database: string;   // Имя базы данных
}

Примечание: Конфигурация должна создаваться в сервисе, который использует пакет.

📦 Зависимости

  • @nestjs/common - NestJS core
  • @nestjs/config - NestJS config
  • @clickhouse/client - официальный клиент ClickHouse
  • @packages/logger - логирование
  • @packages/types - типы для конфигурации
  • clickhouse-migrations - утилита для миграций
  • reflect-metadata - TypeScript decorators

📄 Лицензия

MIT

👥 Автор

Skryabin Aleksey