Skip to content

Add Ruby bindings for chDB C++ library #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Mar 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
*.so
*.bundle
*.swp
*.log
*.o

Gemfile.lock
.rspec_status
.ruby-version
.vscode

doc/
deps/
gems/
issues/
pkg/
ports/
tmp/
vendor/
test/
testdb/
ext/chdb/include/
ext/chdb/lib/
4 changes: 4 additions & 0 deletions .rspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
--format documentation
--color
--require spec_helper
--order rand
57 changes: 57 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
AllCops:
Exclude:
- 'vendor/**/*'
- 'spec/**/*'
- 'tmp/**/*'
- 'ext/**/extconf.rb'

NewCops: enable

TargetRubyVersion: 3.1

AutoCorrect: true

SuggestExtensions: false

Style:
StringLiterals:
EnforcedStyle: double_quotes

ParameterLists:
EnforcedStyle: compact

RedundantSelf:
Enabled: true

ModifierForm:
AllowModifierForm: true

Layout:
LineLength:
Max: 120

FirstParameterIndentation:
Enabled: true
EnforcedStyle: indented

Indentation:
Width: 2

Metrics:
ClassLength:
Max: 200

MethodLength:
Max: 20

ParameterLists:
Max: 5

Lint/AmbiguousOperator:
Enabled: false

Style/Documentation:
Enabled: false

Style/AccessModifierDeclarations:
Enabled: false
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# chdb-ruby Changelog

## [Unreleased]
16 changes: 16 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# frozen_string_literal: true

source 'https://rubygems.org'

gemspec

group :test do
gem 'rake-compiler', '1.2.9'
gem 'rake-compiler-dock', '1.9.1'
gem 'rspec', '3.12.0'
end

group :development do
gem 'rdoc', '6.12.0'
gem 'rubocop', '1.74.0', require: false
end
59 changes: 59 additions & 0 deletions INSTALLATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@

# Installation and Using chdb-ruby extensions

This document will help you install the `chdb-ruby` ruby gem.

## Installation

### Native Gems

Native (precompiled) gems are available for recent Ruby versions on these platforms:

- `aarch64-linux`
- `arm64-darwin`
- `x86_64-linux`
- `x86_64-darwin`

If you are using one of these Ruby versions on one of these platforms, the native gem is the recommended way to install chdb-ruby.

`chdb-ruby` gem does not provide a pure Ruby implementation. Installation will fail if your platform is unsupported.

## Post-Installation: Setting Up libchdb C++ Library

After installing the `chdb-ruby` gem, you must also install the `libchdb` C++ library locally. If the library path is not in your system's default search paths, you'll need to configure the runtime library loading path.

### 1. Download the C++ Library

You can either:
- Use the automated installation script:
```bash
curl -sSL https://github.com/chdb-io/chdb-io.github.io/blob/main/install_libchdb.sh | bash
```

- Or manually download from chdb releases(example for arm64-darwin (v3.12)):
```bash
wget https://github.com/chdb-io/chdb/releases/download/v3.12/macos-arm64-libchdb.tar.gz
tar -xzf macos-arm64-libchdb.tar.gz
```

### 2. Configure Library Path
- MacOS:
```bash
export DYLD_LIBRARY_PATH="/path/to/libchdb:$DYLD_LIBRARY_PATH"
```
(Add to your shell config file like ~/.zshrc for persistence)

- Linux:
```bash
export LD_LIBRARY_PATH="/path/to/libchdb:$LD_LIBRARY_PATH"
```

### 3. Verify Installation
- Ruby:
```bash
require 'chdb'
```

- Troubleshooting(If you get "Library not loaded" errors):
- Verify the path in DYLD_LIBRARY_PATH/LD_LIBRARY_PATH is correct
- Ensure you downloaded the right version for your platform
2 changes: 1 addition & 1 deletion LICENSE.txt → LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ Copyright 2025 chDB, Inc.
same "printed page" as the copyright notice for easier
identification within third-party archives.

Copyright 2023 chDB, Inc.
Copyright 2025 chDB, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
118 changes: 116 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,119 @@

[![chDB-ruby](https://github.com/chdb-io/chdb-ruby/actions/workflows/chdb.yml/badge.svg)](https://github.com/chdb-io/chdb-ruby/actions/workflows/chdb.yml)

# chdb-ruby
[chDB](https://github.com/chdb-io/chdb) ruby bindings and chDB cli.
# Ruby Interface for chdb

## Overview

This library allows Ruby programs to use the chDB embedded analytical database (https://github.com/chdb-io/chdb).

**Designed with SQLite3-compatible API style** - If you're familiar with Ruby's sqlite3 gem, you'll feel right at home with chdb-ruby's similar interface design.

Note that this module is only compatible with ChDB 3.0.0 or newer.

* Source code: https://github.com/chdb-io/chdb-ruby
* Download: http://rubygems.org/gems/chdb-ruby
* Documentation: https://clickhouse.com/docs/chdb

## Quick start

``` ruby
require 'chdb'

# Open a database
db = ChDB::Database.new('test_db', results_as_hash: true)

# Create a table
rows = db.execute <<-SQL
CREATE TABLE test_table(
id Int32,
name String)
ENGINE = MergeTree()
ORDER BY id);
SQL

# Execute a few inserts
{
1 => 'Alice',
2 => 'Bob'
}.each do |pair|
db.execute 'INSERT INTO test_table VALUES ( ?, ? )', pair
end

# Find a few rows
db.execute('SELECT * FROM test_table ORDER BY id') do |row|
p row
end
# [{ 'id' => '1', 'name' => 'Alice' },
# { 'id' => '2', 'name' => 'Bob' }]

# Open another database
db = ChDB::Database.new 'test2.db'

# Create another table
rows = db.execute <<-SQL
CREATE TABLE test2_table(
id Int32,
name String)
ENGINE = MergeTree()
ORDER BY id");
SQL

# Execute inserts with parameter markers
db.execute('INSERT INTO test2_table (id, name)
VALUES (?, ?)', [3, 'Charlie'])

db.execute2('SELECT * FROM test2_table') do |row|
p row
end
# [['id', 'name'], [3, 'Charlie']],
```

## Thread Safety

When using `ChDB::Database.new` to open a session, all read/write operations within that session are thread-safe. However, currently only one active session is allowed per process. Therefore, when you need to open another session, you must first close the previous session.

For example, the following code is fine because only the database
instance is shared among threads:

```ruby
require 'chdb'

db = ChDB::Database.new ":memory:'

latch = Queue.new

ts = 10.times.map {
Thread.new {
latch.pop
db.execute 'SELECT 1'
}
}
10.times { latch << nil }

p ts.map(&:value)
```

Other instances can be shared among threads, but they require that you provide
your own locking for thread safety. For example, `ChDB::Statement` objects
(prepared statements) are mutable, so applications must take care to add
appropriate locks to avoid data race conditions when sharing these objects
among threads.

It is generally recommended that if applications want to share a database among
threads, they _only_ share the database instance object. Other objects are
fine to share, but may require manual locking for thread safety.

## Support

### Installation

If you're having trouble with installation, please first read [`INSTALLATION.md`](./INSTALLATION.md).

### Bug reports

You can file the bug at the [github issues page](https://github.com/chdb-io/chdb-ruby/issues).

## License

This library is licensed under `Apache License 2.0`, see [`LICENSE`](./LICENSE).
6 changes: 6 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# frozen_string_literal: true

require 'bundler'
CHDB_SPEC = Bundler.load_gemspec('chdb.gemspec')

task default: %i[rubocop compile test]
61 changes: 61 additions & 0 deletions chdb.gemspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# frozen_string_literal: true

begin
require_relative 'lib/chdb/version'
rescue LoadError
puts 'WARNING: could not load ChDB::VERSION'
end

Gem::Specification.new do |s|
s.name = 'chdb-ruby'
s.version = defined?(ChDB::VERSION) ? ChDB::VERSION : '0.0.0'

s.summary = 'Ruby library to interface with the chDB database engine (https://clickhouse.com/docs/chdb).'
s.description = <<~TEXT
Ruby library to interface with the chDB database engine (https://clickhouse.com/docs/chdb). Precompiled
binaries are available for common platforms for recent versions of Ruby.
TEXT

s.authors = ['Xiaozhe Yu', 'Auxten Wang']

s.licenses = ['Apache-2.0']

s.required_ruby_version = Gem::Requirement.new('>= 3.1')

s.homepage = 'https://github.com/chdb-io/chdb-ruby'
s.metadata = {
'homepage_uri' => 'https://github.com/chdb-io/chdb-ruby',
'bug_tracker_uri' => 'https://github.com/chdb-io/chdb-ruby/issues',
'changelog_uri' => 'https://github.com/chdb-io/chdb-ruby/blob/main/CHANGELOG.md',
'source_code_uri' => 'https://github.com/chdb-io/chdb-ruby',

# https://guides.rubygems.org/mfa-requirement-opt-in/
'rubygems_mfa_required' => 'true'
}

s.files = [
# 'CHANGELOG.md',
'INSTALLATION.md',
'LICENSE',
'README.md',
'lib/chdb.rb',
'lib/chdb/constants.rb',
'lib/chdb/data_path.rb',
'lib/chdb/database.rb',
'lib/chdb/errors.rb',
'lib/chdb/local_result.rb',
'lib/chdb/parameter_binding.rb',
'lib/chdb/result_handler.rb',
'lib/chdb/result_set.rb',
'lib/chdb/sql_processor.rb',
'lib/chdb/statement.rb',
'lib/chdb/version_info.rb',
'lib/chdb/version.rb'
]

s.rdoc_options = ['--main', 'README.md']

s.add_dependency 'csv', '~> 3.1'

# s.extensions << 'ext/chdb/extconf.rb'
end
2 changes: 2 additions & 0 deletions dependencies.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
chdb:
version: "3.1.2"
Loading