diff --git a/.github/workflows/bun-test.yml b/.github/workflows/bun-test.yml
index e969160..29d6eba 100644
--- a/.github/workflows/bun-test.yml
+++ b/.github/workflows/bun-test.yml
@@ -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
diff --git a/.gitignore b/.gitignore
index 4bfd115..0b95b7c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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
diff --git a/README.md b/README.md
index f992e5b..e054899 100644
--- a/README.md
+++ b/README.md
@@ -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
```
diff --git a/example.ts b/example.ts
index 3f061fd..61bdc96 100644
--- a/example.ts
+++ b/example.ts
@@ -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();
diff --git a/index.ts b/index.ts
index 9264281..b6ca1aa 100644
--- a/index.ts
+++ b/index.ts
@@ -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 };
diff --git a/lib/README.md b/lib/README.md
index 8ba8dca..f38c410 100644
--- a/lib/README.md
+++ b/lib/README.md
@@ -1,6 +1,9 @@
-## libchdb `Execute` function binding
+## libchdb `Query` function binding
```bash
+# install dependencies
+./update_libchdb.sh
+
# build the dynamic library
./build.sh
diff --git a/lib/binding.bun b/lib/binding.bun
deleted file mode 100644
index 9c2eb2a..0000000
--- a/lib/binding.bun
+++ /dev/null
@@ -1,9 +0,0 @@
-export function Execute(query: string, format: string): string {
- const executeFn = ffi('char *Execute(char *, char *)');
- const result = executeFn(query, format);
- if (result === null) {
- throw new Error('Out of memory');
- }
- defer free_result(result)
- return result;
-}
diff --git a/lib/build.sh b/lib/build.sh
index 71e4ffd..e1110d2 100755
--- a/lib/build.sh
+++ b/lib/build.sh
@@ -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
\ No newline at end of file
+fi
+
+mv chdb_bun.so ../chdb_bun.so
+mv libchdb.so ../libchdb.so
\ No newline at end of file
diff --git a/lib/chdb.h b/lib/chdb.h
new file mode 100644
index 0000000..48a8380
--- /dev/null
+++ b/lib/chdb.h
@@ -0,0 +1,28 @@
+#pragma once
+
+#ifdef __cplusplus
+# include
+# include
+extern "C" {
+#else
+# include
+# include
+#endif
+
+#define CHDB_EXPORT __attribute__((visibility("default")))
+struct CHDB_EXPORT local_result
+{
+ char * buf;
+ size_t len;
+ void * _vec; // std::vector *, 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
diff --git a/lib/chdb_bun.c b/lib/chdb_bun.c
new file mode 100644
index 0000000..e64c74d
--- /dev/null
+++ b/lib/chdb_bun.c
@@ -0,0 +1,77 @@
+#include "chdb.h"
+#include "chdb_bun.h"
+#include
+#include
+#include
+
+#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;
+}
diff --git a/lib/chdb_bun.h b/lib/chdb_bun.h
new file mode 100644
index 0000000..24594ad
--- /dev/null
+++ b/lib/chdb_bun.h
@@ -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);
diff --git a/lib/libchdb.h b/lib/libchdb.h
deleted file mode 100644
index 64e5ff2..0000000
--- a/lib/libchdb.h
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef CHDB_H
-#define CHDB_H
-
-#include
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct local_result
-{
- char * buf;
- size_t len;
- void * _vec; // std::vector *, for freeing
-};
-
-const char* ares_query(const char* queryStr, const char* format);
-struct local_result* query_stable(int arg, char ** argv);
-struct local_result* queryToBuffer(const char *queryStr, const char *format);
-
-#ifdef __cplusplus
-}
-
-void free_result(local_result * result);
-
-#endif
-
-#endif
diff --git a/lib/libchdb_bun.c b/lib/libchdb_bun.c
deleted file mode 100644
index 19f4903..0000000
--- a/lib/libchdb_bun.c
+++ /dev/null
@@ -1,71 +0,0 @@
-#include
-#include
-#include "libchdb.h"
-#include "libchdb_bun.h"
-
-char *Execute(char *query, char *format) {
- char *argv[] = {(char *)"clickhouse", (char *)"--multiquery", (char *)"--output-format=CSV", (char *)"--query="};
- char dataFormat[100];
- char *localQuery;
- int argc = 4;
- struct local_result *result;
-
- snprintf(dataFormat, sizeof(dataFormat), "--format=%s", format);
- argv[2] = strdup(dataFormat);
-
- localQuery = (char *) malloc(strlen(query) + 10);
- if (localQuery == NULL) {
- return NULL;
- }
-
- sprintf(localQuery, "--query=%s", query);
- argv[3] = strdup(localQuery);
- free(localQuery);
-
- result = query_stable(argc, argv);
-
- free(argv[2]);
- free(argv[3]);
-
- if (result == NULL) {
- return NULL;
- } else {
- return result->buf;
- }
-}
-
-char *ExecuteSession(char *query, char *format, char *path) {
- char *argv[] = {(char *)"clickhouse", (char *)"--multiquery", (char *)"--output-format=CSV", (char *)"--query=", (char *)"--path=."};
- char dataFormat[100];
- char dataPath[100];
- char *localQuery;
- int argc = 5;
- struct local_result *result;
-
- snprintf(dataFormat, sizeof(dataFormat), "--format=%s", format);
- argv[2] = strdup(dataFormat);
-
- snprintf(dataPath, sizeof(dataPath), "--path=%s", path);
- argv[4] = strdup(dataPath);
-
- localQuery = (char *) malloc(strlen(query) + 10);
- if (localQuery == NULL) {
- return NULL;
- }
-
- sprintf(localQuery, "--query=%s", query);
- argv[3] = strdup(localQuery);
- free(localQuery);
-
- result = query_stable(argc, argv);
-
- free(argv[2]);
- free(argv[3]);
- free(argv[4]);
-
- if (result == NULL) {
- return NULL;
- } else {
- return result->buf;
- }
-}
diff --git a/lib/libchdb_bun.h b/lib/libchdb_bun.h
deleted file mode 100644
index 1a668c1..0000000
--- a/lib/libchdb_bun.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef LIBCHDB_BUN_H
-#define LIBCHDB_BUN_H
-
-char *Execute(char *query, char *format);
-char *ExecuteSession(char *query, char *format, char *path);
-
-#endif
diff --git a/lib/libchdb_bun.so b/lib/libchdb_bun.so
deleted file mode 100755
index 61622b0..0000000
Binary files a/lib/libchdb_bun.so and /dev/null differ
diff --git a/lib/update_libchdb.sh b/lib/update_libchdb.sh
new file mode 100755
index 0000000..fee5ce5
--- /dev/null
+++ b/lib/update_libchdb.sh
@@ -0,0 +1,43 @@
+
+#!/bin/bash
+
+# Get the newest release version
+LATEST_RELEASE=$(curl --silent "https://api.github.com/repos/chdb-io/chdb/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
+
+# Download the correct version based on the platform
+case "$(uname -s)" in
+ Linux)
+ if [[ $(uname -m) == "aarch64" ]]; then
+ PLATFORM="linux-aarch64-libchdb.tar.gz"
+ else
+ PLATFORM="linux-x86_64-libchdb.tar.gz"
+ fi
+ ;;
+ Darwin)
+ if [[ $(uname -m) == "arm64" ]]; then
+ PLATFORM="macos-arm64-libchdb.tar.gz"
+ else
+ PLATFORM="macos-x86_64-libchdb.tar.gz"
+ fi
+ ;;
+ *)
+ echo "Unsupported platform"
+ exit 1
+ ;;
+esac
+
+DOWNLOAD_URL="https://github.com/chdb-io/chdb/releases/download/$LATEST_RELEASE/$PLATFORM"
+
+echo "Downloading $PLATFORM from $DOWNLOAD_URL"
+
+# Download the file
+curl -L -o libchdb.tar.gz $DOWNLOAD_URL
+
+# Untar the file
+tar -xzf libchdb.tar.gz
+
+# Set execute permission for libchdb.so
+chmod +x libchdb.so
+
+# Clean up
+rm -f libchdb.tar.gz
diff --git a/package.json b/package.json
index 350d471..d2da4a2 100644
--- a/package.json
+++ b/package.json
@@ -1,14 +1,8 @@
{
"name": "chdb-bun",
- "version": "1.0.4",
+ "version": "1.1.0",
+ "author": "Farmer Sun ",
"module": "lib/index.js",
- "types": "lib/index.d.ts",
- "scripts": {
- "build:lib": "cd lib && ./build.sh",
- "build:ts": "bun build index.ts --target=bun --outfile=lib/index.js --sourcemap=inline && tsc --declaration --emitDeclarationOnly --types bun-types --declarationDir lib index.ts",
- "build": "bun run build:ts && bun run build:lib"
- },
- "type": "module",
"devDependencies": {
"bun-types": "^1.0.19",
"typescript": "^5.3.3"
@@ -19,16 +13,28 @@
"files": [
"lib"
],
+ "license": "Apache2.0",
"maintainers": [
{
"name": "Farmer Sun",
"email": "podpodiumapp@gmail.com"
},
+ {
+ "name": "Auxten",
+ "email": "auxtenwpc@gmail.com"
+ },
{
"name": "Lorenzo Mangani",
"email": "lorenzo.mangani@gmail.com"
}
],
- "author": "Lorenzo Mangani ",
- "license": "Apache2.0"
+ "scripts": {
+ "build:lib": "cd lib && ./update_libchdb.sh && ./build.sh",
+ "build:ts": "bun build index.ts --target=bun --outfile=lib/index.js --sourcemap=inline && tsc --declaration --emitDeclarationOnly --types bun-types --declarationDir lib index.ts",
+ "build": "bun run build:ts && bun run build:lib"
+ },
+ "type": "module",
+ "types": "lib/index.d.ts",
+ "dependencies": {
+ }
}