Skip to content
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
3 changes: 2 additions & 1 deletion .github/workflows/bun-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@ jobs:
with:
bun-version: latest
- run: bun install
- run: bun example.ts
- run: bun run build
- run: bun run example.ts
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
node_modules

/lib/libchdb_bun.dylib
*.so
/lib/chdb_bun.dylib
/lib/libchdb.so
/lib/index.js
/lib/index.d.ts
44 changes: 15 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,48 +14,34 @@ Experimental [chDB](https://github.com/chdb-io/chdb) FFI bindings for the [bun r

#### Build binding
```bash
bun install chdb-bun
bun run build
bun run example.ts
```

#### Usage

#### Query Constructor
```js
import { db } from 'chdb-bun';

const conn = new db('CSV')
console.log(conn.query("SELECT version()"));
```

#### Query _(query, *format)_
#### Query(query, *format) (ephemeral)
```javascript
import { db } from 'chdb-bun';
const conn = new db('CSV')
import { query } from 'chdb-bun';

// Query (ephemeral)
var result = conn.query("SELECT version()", "CSV");
console.log(result) // 23.10.1.1
var result = query("SELECT version()", "CSV");
console.log(result); // 23.10.1.1
```

#### Session _(query, *format, *path)_
#### Session.Query(query, *format)
```javascript
import { db } from 'chdb-bun';
const conn = new db('CSV', '/tmp')
import { Session } from 'chdb-bun';
const sess = new Session('./chdb-bun-tmp');

// Query Session (persistent)
conn.session("CREATE FUNCTION IF NOT EXISTS hello AS () -> 'chDB'");
result = conn.session("SELECT hello()", "CSV");
console.log(result)
```
sess.query("CREATE FUNCTION IF NOT EXISTS hello AS () -> 'Hello chDB'", "CSV");
var result = sess.query("SELECT hello()", "CSV");
console.log(result);

> ⚠️ Sessions persist table data to disk. You can specify `path` to implement auto-cleanup strategies:
```javascript
const temperment = require("temperment");
const tmp = temperment.directory();
conn.session("CREATE FUNCTION IF NOT EXISTS hello AS () -> 'chDB'", "CSV", tmp)
var result = = chdb.Session("SELECT hello();")
console.log(result) // chDB
tmp.cleanup.sync();
// Before cleanup, you can find the database files in `./chdb-bun-tmp`

sess.cleanup(); // cleanup session, this will delete the database
```

<br>
18 changes: 11 additions & 7 deletions example.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import { db, chdb } from ".";
import { query, Session } from ".";

const conn = new db("CSV", "/tmp");
// Create a new session instance
const session = new Session("./chdb-bun-tmp");
var result;

// Test query
result = conn.query("SELECT version(), chdb()");
// Test standalone query
result = query("SELECT version(), 'Hello chDB', chdb()", "CSV");
console.log(result);

// Test session
conn.session("CREATE FUNCTION IF NOT EXISTS hello AS () -> 'chDB'");
result = conn.session("SELECT hello()", "CSV");
// Test session query
session.query("CREATE FUNCTION IF NOT EXISTS hello AS () -> 'chDB'", "CSV");
result = session.query("SELECT hello()", "CSV");
console.log(result);

// Clean up the session
session.cleanup();
53 changes: 35 additions & 18 deletions index.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,56 @@
import { dlopen, FFIType, suffix, CString, ptr } from "bun:ffi";
import { dlopen, FFIType } from "bun:ffi";
import { rmdirSync, mkdtempSync } from 'fs';

const path = `lib/libchdb_bun.${suffix}`;
const path = `chdb_bun.so`;

const { symbols: chdb } = dlopen(path, {
Execute: {
Query: {
args: [FFIType.cstring, FFIType.cstring],
returns: FFIType.cstring,
},
ExecuteSession: {
QuerySession: {
args: [FFIType.cstring, FFIType.cstring, FFIType.cstring],
returns: FFIType.cstring,
},
});

class db {
format: string;
// Standalone exported query function
export function query(query: string, format: string = "CSV") {
if (!query) {
return "";
}
return chdb.Query(Buffer.from(query + "\0"), Buffer.from(format + "\0"));
}

// Session class with path handling
class Session {
path: string;
isTemp: boolean;

query(query: string, format: string = "CSV") {
if (!query) {
return "";
}
return chdb.Execute(Buffer.from(query + "\0"), Buffer.from(format + "\0"));
}
session(query: string, format: string = "CSV", path: string = "/tmp") {
if (!query) return "";
return chdb.ExecuteSession(
return chdb.QuerySession(
Buffer.from(query + "\0"),
Buffer.from(format + "\0"),
Buffer.from(path + "\0")
Buffer.from(this.path + "\0")
);
}
constructor(format: string = "JSONCompact", path: string = ".") {
this.format = format;
this.path = path;

constructor(path: string = "") {
if (path === "") {
// Create a temporary directory
this.path = mkdtempSync("tmp-");
this.isTemp = true;
} else {
this.path = path;
this.isTemp = false;
}
}

// Cleanup method to delete the temporary directory
cleanup() {
rmdirSync(this.path, { recursive: true });
}
}

export { chdb, db };
export { chdb, Session };
5 changes: 4 additions & 1 deletion lib/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
## libchdb `Execute` function binding
## libchdb `Query` function binding

```bash
# install dependencies
./update_libchdb.sh

# build the dynamic library

./build.sh
Expand Down
9 changes: 0 additions & 9 deletions lib/binding.bun

This file was deleted.

11 changes: 8 additions & 3 deletions lib/build.sh
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
#!/bin/bash

if [ "$(uname)" == "Darwin" ]; then
gcc -dynamiclib -o libchdb_bun.dylib -L. -lchdb libchdb_bun.c
clang -O3 -dynamiclib -o chdb_bun.so -L. -lchdb chdb_bun.c
elif [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]; then
gcc -shared -fPIC -o libchdb_bun.so libchdb_bun.c -L. -lchdb
clang -O3 -shared -fPIC -o chdb_bun.so -L. -lchdb chdb_bun.c
else
echo "Unsupported operating system"
exit 1
fi
fi

mv chdb_bun.so ../chdb_bun.so
mv libchdb.so ../libchdb.so
28 changes: 28 additions & 0 deletions lib/chdb.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#pragma once

#ifdef __cplusplus
# include <cstddef>
# include <cstdint>
extern "C" {
#else
# include <stddef.h>
# include <stdint.h>
#endif

#define CHDB_EXPORT __attribute__((visibility("default")))
struct CHDB_EXPORT local_result
{
char * buf;
size_t len;
void * _vec; // std::vector<char> *, for freeing
double elapsed;
uint64_t rows_read;
uint64_t bytes_read;
};

CHDB_EXPORT struct local_result * query_stable(int argc, char ** argv);
CHDB_EXPORT void free_result(struct local_result * result);

#ifdef __cplusplus
}
#endif
77 changes: 77 additions & 0 deletions lib/chdb_bun.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#include "chdb.h"
#include "chdb_bun.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_FORMAT_LENGTH 64
#define MAX_PATH_LENGTH 4096
#define MAX_ARG_COUNT 6

// Utility function to construct argument string
void construct_arg(char *dest, const char *prefix, const char *value,
size_t dest_size) {
snprintf(dest, dest_size, "%s%s", prefix, value);
}

// Generalized query function
char *general_query(int argc, char *args[]) {
struct local_result *result = query_stable(argc, args);

if (result == NULL) {
return NULL;
} else {
return result->buf;
}
}

// Query function without session
char *Query(const char *query, const char *format) {
char dataFormat[MAX_FORMAT_LENGTH];
char *dataQuery;
char *args[MAX_ARG_COUNT] = {"clickhouse", "--multiquery", NULL, NULL};
int argc = 4;

construct_arg(dataFormat, "--output-format=", format, MAX_FORMAT_LENGTH);
args[2] = dataFormat;

dataQuery = (char *)malloc(strlen(query) + strlen("--query=") + 1);
if (dataQuery == NULL) {
return NULL;
}
construct_arg(dataQuery, "--query=", query,
strlen(query) + strlen("--query=") + 1);
args[3] = dataQuery;

char *result = general_query(argc, args);
free(dataQuery);
return result;
}

// QuerySession function will save the session to the path
// queries with same path will use the same session
char *QuerySession(const char *query, const char *format, const char *path) {
char dataFormat[MAX_FORMAT_LENGTH];
char dataPath[MAX_PATH_LENGTH];
char *dataQuery;
char *args[MAX_ARG_COUNT] = {"clickhouse", "--multiquery", NULL, NULL, NULL};
int argc = 5;

construct_arg(dataFormat, "--output-format=", format, MAX_FORMAT_LENGTH);
args[2] = dataFormat;

dataQuery = (char *)malloc(strlen(query) + strlen("--query=") + 1);
if (dataQuery == NULL) {
return NULL;
}
construct_arg(dataQuery, "--query=", query,
strlen(query) + strlen("--query=") + 1);
args[3] = dataQuery;

construct_arg(dataPath, "--path=", path, MAX_PATH_LENGTH);
args[4] = dataPath;

char *result = general_query(argc, args);
free(dataQuery);
return result;
}
4 changes: 4 additions & 0 deletions lib/chdb_bun.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#pragma once

char *Query(const char *query, const char *format);
char *QuerySession(const char *query, const char *format, const char *path);
28 changes: 0 additions & 28 deletions lib/libchdb.h

This file was deleted.

Loading