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 🙏

© 2025 – Pkg Stats / Ryan Hefner

webfunny-clickhouse

v0.0.6

Published

A Sequelize-like ORM for ClickHouse with parameterized queries and SQL injection protection. Backward compatible with webfunny-node-clickhouse.

Readme

webfunny-clickhouse

A Sequelize-like ORM for ClickHouse with parameterized queries and SQL injection protection

npm version License: MIT

✨ Features

  • 🛡️ SQL Injection Protection - Parameterized queries prevent SQL injection attacks
  • 📝 Sequelize-like API - Familiar ORM-style interface for ClickHouse
  • 🔗 Chain Query Builder - Build complex queries with method chaining
  • 🎯 Rich Operators - Support for 18+ query operators (eq, gt, like, in, between, etc.)
  • 🚀 Auto Table Creation - Intelligent table creation with existence checking
  • 📊 Type Inference - Automatic type detection for query parameters
  • Performance - Built on official @clickhouse/client
  • 🔄 Backward Compatible - Works alongside existing SQL queries

📦 Installation

npm install webfunny-clickhouse @clickhouse/client

🚀 Quick Start

const WebfunnyClickHouse = require('webfunny-clickhouse')
const { Op } = WebfunnyClickHouse
const { createClient } = require('@clickhouse/client')

// Create ClickHouse client
const client = createClient({
  host: 'http://localhost:8123',
  username: 'default',
  password: '',
  database: 'default'
})

// Create model instance
const User = new WebfunnyClickHouse({
  client,
  tableName: 'users'
})

// Query data
const users = await User.findAll({
  where: {
    age: { [Op.gt]: 18 },
    status: 'active'
  },
  limit: 10
})

console.log(users)

📚 Documentation

Basic Usage

Query Records

// Find all
const users = await User.findAll({
  where: { status: 'active' }
})

// Find one
const user = await User.findOne({
  where: { id: 123 }
})

// Find by primary key
const user = await User.findByPk(123)

// Count
const count = await User.count({
  where: { status: 'active' }
})

Create Records

// Create single record
await User.create({
  name: 'John',
  age: 25,
  email: '[email protected]'
})

// Bulk create
await User.bulkCreate([
  { name: 'John', age: 25 },
  { name: 'Jane', age: 23 }
])

Update Records

await User.update(
  { status: 'inactive' },
  { where: { id: 123 } }
)

Delete Records

await User.destroy({
  where: { id: 123 }
})

Operators

const { Op } = WebfunnyClickHouse

// Comparison
{ field: { [Op.eq]: value } }     // =
{ field: { [Op.ne]: value } }     // !=
{ field: { [Op.gt]: value } }     // >
{ field: { [Op.gte]: value } }    // >=
{ field: { [Op.lt]: value } }     // <
{ field: { [Op.lte]: value } }    // <=

// Range
{ field: { [Op.in]: [1, 2, 3] } }           // IN
{ field: { [Op.notIn]: [1, 2, 3] } }        // NOT IN
{ field: { [Op.between]: [10, 100] } }      // BETWEEN

// String
{ field: { [Op.like]: '%test%' } }          // LIKE
{ field: { [Op.notLike]: '%test%' } }       // NOT LIKE
{ field: { [Op.startsWith]: 'test' } }      // LIKE 'test%'
{ field: { [Op.endsWith]: 'test' } }        // LIKE '%test'

// NULL
{ field: { [Op.isNull]: true } }            // IS NULL
{ field: { [Op.isNotNull]: true } }         // IS NOT NULL

// Logic
{
  [Op.and]: [
    { field1: value1 },
    { field2: value2 }
  ]
}
{
  [Op.or]: [
    { field1: value1 },
    { field2: value2 }
  ]
}

Chain Query Builder

// Basic chain
const users = await User
  .select(['id', 'name', 'age'])
  .where({ status: 'active' })
  .orderBy('age', 'DESC')
  .limit(10)
  .execute()

// Complex chain
const users = await User
  .select('*')
  .where({ status: 'active' })
  .whereRaw('age > :minAge', { minAge: 18 })
  .orderBy('createdAt', 'DESC')
  .limit(10)
  .offset(0)
  .execute()

// Get first record
const user = await User
  .where({ status: 'active' })
  .orderBy('createdAt', 'DESC')
  .first()

// Get count
const count = await User
  .where({ status: 'active' })
  .count()

Parameterized Queries

// Named parameters (recommended)
const result = await User.query(
  'SELECT * FROM users WHERE id = :id AND name = :name',
  {
    replacements: {
      id: 123,
      name: 'John'
    }
  }
)

// Positional parameters
const result = await User.query(
  'SELECT * FROM users WHERE id = ? AND name = ?',
  {
    replacements: [123, 'John']
  }
)

// IN clause (auto-expand)
const result = await User.query(
  'SELECT * FROM users WHERE id IN (:ids)',
  {
    replacements: {
      ids: [1, 2, 3, 4, 5]
    }
  }
)

Advanced Usage

Complex Conditions

const users = await User.findAll({
  where: {
    [Op.and]: [
      { status: 'active' },
      { age: { [Op.gte]: 18 } },
      {
        [Op.or]: [
          { role: 'admin' },
          { role: 'moderator' }
        ]
      }
    ]
  }
})

Pagination

const page = 1
const pageSize = 20
const offset = (page - 1) * pageSize

const users = await User.findAll({
  where: { status: 'active' },
  limit: pageSize,
  offset: offset,
  order: [['createdAt', 'DESC']]
})

const total = await User.count({
  where: { status: 'active' }
})

Dynamic Table Names

// For log tables with dynamic names
const ErrorLog = new WebfunnyClickHouse({
  client,
  tableName: 'error_log' // default table name
})

// Use different table
const errors = await ErrorLog.findAll({
  where: { level: 'error' },
  tableName: `error_log_20241004` // override
})

// Or use withTable
const errors = await ErrorLog
  .withTable('error_log_20241004')
  .where({ level: 'error' })
  .execute()

Auto Table Creation

const User = new WebfunnyClickHouse({
  client,
  schemaPath: './schema/user.js' // schema file
})

// Auto create table if not exists
// force: true means fail-safe mode
await User.createTable({ force: true })

🔐 Security Features

  1. SQL Injection Prevention - All user inputs are parameterized
  2. Type Safety - Automatic type inference and conversion
  3. Input Validation - Table names and field names are validated
  4. Whitelist Mechanism - Support for dynamic table name whitelisting

📊 Performance

  • Built on official @clickhouse/client
  • Parameterization adds ~5-10% parsing overhead
  • Network I/O is still the bottleneck
  • Security benefits far outweigh performance cost

🧪 Testing

npm test

📝 Examples

See examples/ directory for complete examples.

🤝 Contributing

Contributions are welcome! Please read our Contributing Guide first.

📄 License

MIT © Webfunny Team

🔗 Links

💡 Comparison with Other Libraries

| Feature | webfunny-clickhouse | sequelize | raw SQL | |---------|---------------------|-----------|---------| | SQL Injection Protection | ✅ | ✅ | ❌ | | ORM-like API | ✅ | ✅ | ❌ | | ClickHouse Optimized | ✅ | ❌ | ✅ | | Type Safety | ✅ | ✅ | ❌ | | Chain Query Builder | ✅ | ✅ | ❌ | | Learning Curve | Low | Medium | Low |

🌟 Who's Using


Made with ❤️ by Webfunny Team