feat: query, schema, table, udfs

This commit is contained in:
didierfranc
2024-10-21 14:04:22 +02:00
parent 1c444ba881
commit 975af6d7fb
20 changed files with 418 additions and 283 deletions

168
package-lock.json generated
View File

@@ -14,9 +14,9 @@
"devDependencies": {
"@sveltejs/adapter-static": "^3.0.1",
"@sveltejs/kit": "^2.0.0",
"@sveltejs/vite-plugin-svelte": "^3.0.0",
"@sveltejs/vite-plugin-svelte": "^4.0.0-next.7",
"@tauri-apps/cli": "^1",
"svelte": "^4.2.7",
"svelte": "^5.0.0-next.253",
"svelte-check": "^3.6.0",
"tslib": "^2.4.1",
"typescript": "^5.0.0",
@@ -756,43 +756,42 @@
}
},
"node_modules/@sveltejs/vite-plugin-svelte": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-3.1.2.tgz",
"integrity": "sha512-Txsm1tJvtiYeLUVRNqxZGKR/mI+CzuIQuc2gn+YCs9rMTowpNZ2Nqt53JdL8KF9bLhAf2ruR/dr9eZCwdTriRA==",
"version": "4.0.0-next.7",
"resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-4.0.0-next.7.tgz",
"integrity": "sha512-yMUnAqquoayvBDztk1rWUgdtvjv7YcHgopCAB7sWl9SQht8U/7lqwTlJU0ZTAY09pFFRe6bbakd7YoiyyIvJiA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@sveltejs/vite-plugin-svelte-inspector": "^2.1.0",
"debug": "^4.3.4",
"@sveltejs/vite-plugin-svelte-inspector": "^3.0.0-next.0||^3.0.0",
"debug": "^4.3.6",
"deepmerge": "^4.3.1",
"kleur": "^4.1.5",
"magic-string": "^0.30.10",
"svelte-hmr": "^0.16.0",
"vitefu": "^0.2.5"
"magic-string": "^0.30.11",
"vitefu": "^1.0.2"
},
"engines": {
"node": "^18.0.0 || >=20"
"node": "^18.0.0 || ^20.0.0 || >=22"
},
"peerDependencies": {
"svelte": "^4.0.0 || ^5.0.0-next.0",
"svelte": "^5.0.0-next.96 || ^5.0.0",
"vite": "^5.0.0"
}
},
"node_modules/@sveltejs/vite-plugin-svelte-inspector": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-2.1.0.tgz",
"integrity": "sha512-9QX28IymvBlSCqsCll5t0kQVxipsfhFFL+L2t3nTWfXnddYwxBuAEtTtlaVQpRz9c37BhJjltSeY4AJSC03SSg==",
"version": "3.0.0-next.3",
"resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-3.0.0-next.3.tgz",
"integrity": "sha512-kuGJ2CZ5lAw3gKF8Kw0AfKtUJWbwdlDHY14K413B0MCyrzvQvsKTorwmwZcky0+QqY6RnVIZ/5FttB9bQmkLXg==",
"dev": true,
"license": "MIT",
"dependencies": {
"debug": "^4.3.4"
"debug": "^4.3.5"
},
"engines": {
"node": "^18.0.0 || >=20"
"node": "^18.0.0 || ^20.0.0 || >=22"
},
"peerDependencies": {
"@sveltejs/vite-plugin-svelte": "^3.0.0",
"svelte": "^4.0.0 || ^5.0.0-next.0",
"@sveltejs/vite-plugin-svelte": "^4.0.0-next.0||^4.0.0",
"svelte": "^5.0.0-next.96 || ^5.0.0",
"vite": "^5.0.0"
}
},
@@ -1044,6 +1043,16 @@
"node": ">=0.4.0"
}
},
"node_modules/acorn-typescript": {
"version": "1.4.13",
"resolved": "https://registry.npmjs.org/acorn-typescript/-/acorn-typescript-1.4.13.tgz",
"integrity": "sha512-xsc9Xv0xlVfwp2o7sQ+GCQ1PgbkdcpWdTzrwXxO3xDMTAywVS3oXVOcOHuRjAPkS4P9b+yc/qNF15460v+jp4Q==",
"dev": true,
"license": "MIT",
"peerDependencies": {
"acorn": ">=8.9.0"
}
},
"node_modules/anymatch": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
@@ -1157,20 +1166,6 @@
"fsevents": "~2.3.2"
}
},
"node_modules/code-red": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/code-red/-/code-red-1.0.4.tgz",
"integrity": "sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.4.15",
"@types/estree": "^1.0.1",
"acorn": "^8.10.0",
"estree-walker": "^3.0.3",
"periscopic": "^3.1.0"
}
},
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -1188,20 +1183,6 @@
"node": ">= 0.6"
}
},
"node_modules/css-tree": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz",
"integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==",
"dev": true,
"license": "MIT",
"dependencies": {
"mdn-data": "2.0.30",
"source-map-js": "^1.0.1"
},
"engines": {
"node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0"
}
},
"node_modules/debug": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
@@ -1300,14 +1281,15 @@
"dev": true,
"license": "MIT"
},
"node_modules/estree-walker": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
"integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
"node_modules/esrap": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/esrap/-/esrap-1.2.2.tgz",
"integrity": "sha512-F2pSJklxx1BlQIQgooczXCPHmcWpn6EsP5oo73LQfonG9fIlIENQ8vMmfGXeojP9MrkzUNAfyU5vdFlR9shHAw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/estree": "^1.0.0"
"@jridgewell/sourcemap-codec": "^1.4.15",
"@types/estree": "^1.0.1"
}
},
"node_modules/fill-range": {
@@ -1514,13 +1496,6 @@
"@jridgewell/sourcemap-codec": "^1.5.0"
}
},
"node_modules/mdn-data": {
"version": "2.0.30",
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz",
"integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==",
"dev": true,
"license": "CC0-1.0"
},
"node_modules/min-indent": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
@@ -1643,18 +1618,6 @@
"node": ">=0.10.0"
}
},
"node_modules/periscopic": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz",
"integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/estree": "^1.0.0",
"estree-walker": "^3.0.0",
"is-reference": "^3.0.0"
}
},
"node_modules/picocolors": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz",
@@ -1855,29 +1818,28 @@
}
},
"node_modules/svelte": {
"version": "4.2.19",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.19.tgz",
"integrity": "sha512-IY1rnGr6izd10B0A8LqsBfmlT5OILVuZ7XsI0vdGPEvuonFV7NYEUK4dAkm9Zg2q0Um92kYjTpS1CAP3Nh/KWw==",
"version": "5.0.0-next.253",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-5.0.0-next.253.tgz",
"integrity": "sha512-s32X0g/yJJcada3+ZdQiirospMUSl4f8h8/hrMeJ7Oim6+bWccP4pZaKQY+x+LCqyzmBNMxVm3j7+SU5xOaAzg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@ampproject/remapping": "^2.2.1",
"@jridgewell/sourcemap-codec": "^1.4.15",
"@jridgewell/trace-mapping": "^0.3.18",
"@types/estree": "^1.0.1",
"acorn": "^8.9.0",
"aria-query": "^5.3.0",
"axobject-query": "^4.0.0",
"code-red": "^1.0.3",
"css-tree": "^2.3.1",
"estree-walker": "^3.0.3",
"is-reference": "^3.0.1",
"@ampproject/remapping": "^2.3.0",
"@jridgewell/sourcemap-codec": "^1.5.0",
"@types/estree": "^1.0.5",
"acorn": "^8.12.1",
"acorn-typescript": "^1.4.13",
"aria-query": "^5.3.1",
"axobject-query": "^4.1.0",
"esm-env": "^1.0.0",
"esrap": "^1.2.2",
"is-reference": "^3.0.2",
"locate-character": "^3.0.0",
"magic-string": "^0.30.4",
"periscopic": "^3.1.0"
"magic-string": "^0.30.11",
"zimmerframe": "^1.1.2"
},
"engines": {
"node": ">=16"
"node": ">=18"
}
},
"node_modules/svelte-check": {
@@ -1901,19 +1863,6 @@
"svelte": "^3.55.0 || ^4.0.0-next.0 || ^4.0.0 || ^5.0.0-next.0"
}
},
"node_modules/svelte-hmr": {
"version": "0.16.0",
"resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.16.0.tgz",
"integrity": "sha512-Gyc7cOS3VJzLlfj7wKS0ZnzDVdv3Pn2IuVeJPk9m2skfhcu5bq3wtIZyQGggr7/Iim5rH5cncyQft/kRLupcnA==",
"dev": true,
"license": "ISC",
"engines": {
"node": "^12.20 || ^14.13.1 || >= 16"
},
"peerDependencies": {
"svelte": "^3.19.0 || ^4.0.0"
}
},
"node_modules/svelte-preprocess": {
"version": "5.1.4",
"resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-5.1.4.tgz",
@@ -2093,11 +2042,15 @@
}
},
"node_modules/vitefu": {
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.2.5.tgz",
"integrity": "sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.0.2.tgz",
"integrity": "sha512-0/iAvbXyM3RiPPJ4lyD4w6Mjgtf4ejTK6TPvTNG3H32PLwuT0N/ZjJLiXug7ETE/LWtTeHw9WRv7uX/tIKYyKg==",
"dev": true,
"license": "MIT",
"workspaces": [
"tests/deps/*",
"tests/projects/*"
],
"peerDependencies": {
"vite": "^3.0.0 || ^4.0.0 || ^5.0.0"
},
@@ -2113,6 +2066,13 @@
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
"dev": true,
"license": "ISC"
},
"node_modules/zimmerframe": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.2.tgz",
"integrity": "sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==",
"dev": true,
"license": "MIT"
}
}
}

View File

@@ -18,12 +18,12 @@
"devDependencies": {
"@sveltejs/adapter-static": "^3.0.1",
"@sveltejs/kit": "^2.0.0",
"@sveltejs/vite-plugin-svelte": "^3.0.0",
"svelte": "^4.2.7",
"@sveltejs/vite-plugin-svelte": "^4.0.0-next.7",
"@tauri-apps/cli": "^1",
"svelte": "^5.0.0-next.253",
"svelte-check": "^3.6.0",
"tslib": "^2.4.1",
"tslib": "^2.4.1",
"typescript": "^5.0.0",
"vite": "^5.0.3",
"@tauri-apps/cli": "^1"
"vite": "^5.0.3"
}
}

42
src-tauri/Cargo.lock generated
View File

@@ -28,8 +28,6 @@ name = "agx"
version = "0.1.0"
dependencies = [
"bindgen",
"serde",
"serde_json",
"tauri",
"tauri-build",
"thiserror",
@@ -241,9 +239,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "bytes"
version = "1.7.1"
version = "1.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50"
checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3"
[[package]]
name = "cairo-rs"
@@ -281,9 +279,9 @@ dependencies = [
[[package]]
name = "cc"
version = "1.1.20"
version = "1.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45bcde016d64c21da4be18b655631e5ab6d3107607e71a73a9f53eb48aae23fb"
checksum = "07b1695e2c7e8fc85310cde85aeaab7e3097f593c91d209d3f9df76c928100f0"
dependencies = [
"shlex",
]
@@ -1490,9 +1488,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
version = "0.2.158"
version = "0.2.159"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
[[package]]
name = "libloading"
@@ -1999,9 +1997,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "pkg-config"
version = "0.3.30"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
[[package]]
name = "plist"
@@ -2216,9 +2214,9 @@ checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9"
[[package]]
name = "redox_syscall"
version = "0.5.4"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853"
checksum = "62871f2d65009c0256aed1b9cfeeb8ac272833c404e13d53d400cd0dad7a2ac0"
dependencies = [
"bitflags 2.6.0",
]
@@ -2963,18 +2961,18 @@ checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c"
[[package]]
name = "thiserror"
version = "1.0.63"
version = "1.0.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.63"
version = "1.0.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3"
dependencies = [
"proc-macro2",
"quote",
@@ -3078,7 +3076,7 @@ dependencies = [
"serde",
"serde_spanned",
"toml_datetime",
"toml_edit 0.22.21",
"toml_edit 0.22.22",
]
[[package]]
@@ -3105,15 +3103,15 @@ dependencies = [
[[package]]
name = "toml_edit"
version = "0.22.21"
version = "0.22.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b072cee73c449a636ffd6f32bd8de3a9f7119139aff882f44943ce2986dc5cf"
checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
dependencies = [
"indexmap 2.5.0",
"serde",
"serde_spanned",
"toml_datetime",
"winnow 0.6.18",
"winnow 0.6.19",
]
[[package]]
@@ -3793,9 +3791,9 @@ dependencies = [
[[package]]
name = "winnow"
version = "0.6.18"
version = "0.6.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f"
checksum = "c52ac009d615e79296318c1bcce2d422aaca15ad08515e344feeda07df67a587"
dependencies = [
"memchr",
]

View File

@@ -2,19 +2,16 @@
name = "agx"
version = "0.1.0"
description = "A Tauri App"
authors = ["you"]
authors = ["Didier Franc"]
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[build-dependencies]
tauri-build = { version = "1", features = [] }
bindgen = "0.70.1"
[dependencies]
tauri = { version = "1", features = ["shell-open"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
thiserror = "1"
[features]

View File

@@ -3,10 +3,10 @@ use std::path::PathBuf;
fn main() {
tauri_build::build();
// Tell cargo to look for shared libraries in the specified directory
// // Tell cargo to look for shared libraries in the specified directory
println!("cargo:rustc-link-search=./");
// Tell cargo to tell rustc to link the system chdb library.
// // Tell cargo to tell rustc to link the system chdb library.
println!("cargo:rustc-link-lib=chdb");
// Tell cargo to invalidate the built crate whenever the wrapper changes.

4
src-tauri/fix_dylib.sh Normal file
View File

@@ -0,0 +1,4 @@
#!/bin/bash
install_name_tool -change libchdb.so @executable_path/../Resources/libchdb.so src-tauri/target/release/agx
codesign --force --sign - src-tauri/target/release/agx

View File

@@ -21,6 +21,7 @@ pub const _DARWIN_FEATURE_ONLY_VERS_1050: u32 = 1;
pub const _DARWIN_FEATURE_ONLY_UNIX_CONFORMANCE: u32 = 1;
pub const _DARWIN_FEATURE_UNIX_CONFORMANCE: u32 = 3;
pub const __has_ptrcheck: u32 = 0;
pub const USE_CLANG_TYPES: u32 = 0;
pub const __PTHREAD_SIZE__: u32 = 8176;
pub const __PTHREAD_ATTR_SIZE__: u32 = 56;
pub const __PTHREAD_MUTEXATTR_SIZE__: u32 = 8;
@@ -330,19 +331,6 @@ pub type __darwin_pthread_once_t = _opaque_pthread_once_t;
pub type __darwin_pthread_rwlock_t = _opaque_pthread_rwlock_t;
pub type __darwin_pthread_rwlockattr_t = _opaque_pthread_rwlockattr_t;
pub type __darwin_pthread_t = *mut _opaque_pthread_t;
pub type u_int8_t = ::std::os::raw::c_uchar;
pub type u_int16_t = ::std::os::raw::c_ushort;
pub type u_int32_t = ::std::os::raw::c_uint;
pub type u_int64_t = ::std::os::raw::c_ulonglong;
pub type register_t = i64;
pub type user_addr_t = u_int64_t;
pub type user_size_t = u_int64_t;
pub type user_ssize_t = i64;
pub type user_long_t = i64;
pub type user_ulong_t = u_int64_t;
pub type user_time_t = i64;
pub type user_off_t = i64;
pub type syscall_arg_t = u_int64_t;
pub type intmax_t = ::std::os::raw::c_long;
pub type uintmax_t = ::std::os::raw::c_ulong;
#[repr(C)]

41
src-tauri/src/conf.rs Normal file
View File

@@ -0,0 +1,41 @@
use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;
pub fn gen_clickhouse_config<P: AsRef<Path>>(udfs_path: P) -> String {
let udfs_path = udfs_path.as_ref().to_string_lossy();
let xml_content = format!(
r#"<clickhouse>
<user_defined_executable_functions_config>{udfs_path}/user_defined/*.xml</user_defined_executable_functions_config>
<user_scripts_path>{udfs_path}/bin</user_scripts_path>
<user_defined_path>{udfs_path}/user_defined</user_defined_path>
</clickhouse>"#,
udfs_path = udfs_path
);
let mut temp_dir = env::temp_dir();
temp_dir.push("clickhouse_config.xml");
let config_file_path = match temp_dir.to_str() {
Some(path_str) => path_str.to_string(),
None => {
eprintln!("Failed to convert path to string");
return String::new(); // Return an empty string on failure
}
};
if let Ok(mut file) = File::create(&temp_dir) {
if let Err(e) = file.write_all(xml_content.as_bytes()) {
eprintln!("Error writing to ClickHouse config file: {}", e);
return String::new();
}
} else {
eprintln!("Error creating ClickHouse config file");
return String::new();
}
config_file_path
}

View File

@@ -1,13 +1,33 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
use serde_json;
use std::borrow::Cow;
use String;
use agx::arg::Arg;
use std::env;
mod conf;
#[tauri::command]
fn query(query: &str) -> String {
let result = agx::execute(query, None).unwrap_or(None);
fn query(query: &str, udfs: &str) -> String {
let config_path = conf::gen_clickhouse_config(udfs);
let args = if !udfs.is_empty() {
vec![
Arg::Custom("output-format".into(), Some("JSON".into())),
Arg::ConfigFilePath(Cow::Borrowed(&config_path)),
]
} else {
vec![Arg::Custom("output-format".into(), Some("JSON".into()))]
};
let result = agx::execute(query, Some(&args));
match result {
Some(query_result) => serde_json::to_string(&query_result).unwrap_or_default(),
None => "".to_string(),
Ok(Some(query_result)) => query_result
.data_utf8()
.unwrap_or_else(|_| String::from("invalid utf8 char")),
Ok(None) => String::from("No result"),
Err(e) => format!("Error: {:?}", e),
}
}

View File

@@ -6,9 +6,7 @@ use std::time::Duration;
use crate::bindings;
use crate::error::Error;
use serde::ser::{Serialize, SerializeStruct, Serializer};
#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct QueryResult(pub(crate) *mut bindings::local_result_v2);
impl QueryResult {
@@ -63,22 +61,3 @@ impl Drop for QueryResult {
unsafe { bindings::free_result_v2(self.0) };
}
}
impl Serialize for QueryResult {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut state = serializer.serialize_struct("QueryResult", 4)?;
state.serialize_field(
"data_utf8",
&self.data_utf8().unwrap_or_else(|_| String::from("")),
)?;
state.serialize_field("rows_read", &self.rows_read())?;
state.serialize_field("bytes_read", &self.bytes_read())?;
state.serialize_field("elapsed", &self.elapsed().as_secs_f64())?;
state.end()
}
}

View File

@@ -3,6 +3,7 @@
"build": {
"beforeDevCommand": "npm run dev",
"beforeBuildCommand": "npm run build",
"beforeBundleCommand": "sh src-tauri/fix_dylib.sh",
"devPath": "http://localhost:1420",
"distDir": "../build"
},
@@ -21,14 +22,18 @@
"windows": [
{
"title": "agx",
"width": 800,
"height": 600
"width": 1024,
"height": 768
}
],
"security": {
"csp": null
},
"bundle": {
"macOS": {
"hardenedRuntime": true,
"minimumSystemVersion": "10.13"
},
"active": true,
"targets": "all",
"identifier": "com.agx.app",
@@ -38,7 +43,8 @@
"icons/128x128@2x.png",
"icons/icon.icns",
"icons/icon.ico"
]
],
"resources": ["libchdb.so"]
}
}
}

View File

@@ -1,4 +1,3 @@
#!/bin/bash
set -e
cd $(dirname "${BASH_SOURCE[0]}")

35
src/global.css Normal file
View File

@@ -0,0 +1,35 @@
* {
box-sizing: border-box;
}
html,
body,
section {
padding: 0;
margin: 0;
}
body {
background-color: black;
}
:root {
font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
font-size: 16px;
line-height: 24px;
font-weight: 400;
color: #0f0f0f;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-text-size-adjust: 100%;
}
@media (prefers-color-scheme: dark) {
:root {
color: #f6f6f6;
}
}

41
src/lib/editor.svelte Normal file
View File

@@ -0,0 +1,41 @@
<script lang="ts">
import { onMount } from "svelte";
import { exec, type CHResponse } from "./query";
let { response = $bindable() }: { response: CHResponse } = $props();
let query = $state.raw("");
onMount(() => {
let handleKeyDown = async function (event: KeyboardEvent) {
if (event.code === "Enter" && event.metaKey) {
response = await exec(query);
console.log(response);
}
};
document.addEventListener("keydown", handleKeyDown);
return () => {
document.removeEventListener("keydown", handleKeyDown);
};
});
</script>
<textarea id="greet-input" placeholder="Enter a query..." bind:value={query}
></textarea>
<style>
textarea {
display: block;
width: 100%;
font-family: monospace;
height: 50vh;
background: black;
border: none;
resize: none;
padding: 2px;
color: white;
outline: none;
border: none;
}
</style>

19
src/lib/query.ts Normal file
View File

@@ -0,0 +1,19 @@
import { invoke } from "@tauri-apps/api/tauri";
export async function exec(query: string) {
try {
const r: string = await invoke("query", {
query,
udfs: "",
});
return JSON.parse(r);
} catch (e) {
console.error(e);
return {};
}
}
export type CHResponse = {
meta: [{ name: string; type: string }];
data: Array<{ [key: string]: any }>;
} | undefined

60
src/lib/schema.svelte Normal file
View File

@@ -0,0 +1,60 @@
<script lang="ts">
import { appWindow } from "@tauri-apps/api/window";
import { exec, type CHResponse } from "./query";
import { onMount } from "svelte";
let schema: CHResponse = $state.raw(undefined);
onMount(async () => {
schema = await exec(
`DESCRIBE TABLE s3('https://data.agnostic.dev/ethereum-mainnet-pq/logs/*.parquet', 'Parquet')`,
);
});
appWindow.onFileDropEvent(async (event) => {
if (event.payload.type === "drop") {
const path = event.payload.paths[0];
schema = await exec(`DESCRIBE '${path}'`);
}
});
</script>
<section>
{#if schema}
{#each schema.data as column}
<div class="column">
<span class="name">{column.name}</span>
<span class="type">{column.type}</span>
</div>
{/each}
{/if}
</section>
<style>
section {
padding: 10px;
width: 225px;
height: 100vh;
background: rgba(30, 30, 30, 1);
overflow: scroll;
font-size: 10px;
}
.column {
display: flex;
white-space: nowrap;
}
.name {
font-weight: 600;
width: 100px;
overflow: hidden;
text-overflow: ellipsis;
}
.type {
width: 100px;
overflow: hidden;
text-overflow: ellipsis;
}
</style>

66
src/lib/table.svelte Normal file
View File

@@ -0,0 +1,66 @@
<script lang="ts">
import type { CHResponse } from "./query";
let {
response,
}: {
response: CHResponse;
} = $props();
</script>
<section>
{#if response}
<table>
<thead>
<tr>
{#each response.meta as column, i (column.name)}
<th>{column.name} ({column.type})</th>
{/each}
</tr>
</thead>
<tbody>
{#each response.data as row, i (row)}
<tr>
{#each Object.entries(row) as [key, value], i (key)}
<td>{value}</td>
{/each}
</tr>
{/each}
</tbody>
</table>
{/if}
</section>
<style>
section {
background: rgba(40, 40, 40, 1);
height: 50vh;
overflow: scroll;
}
tr {
height: 30px;
}
table {
width: 100%;
border-collapse: collapse;
border: none;
}
th {
text-align: left;
font-size: 12px;
border-bottom: 1px solid rgba(75, 75, 75, 1);
}
td {
font-size: 12px;
}
th,
td {
padding: 0 5px;
width: 100px;
}
</style>

View File

@@ -0,0 +1,5 @@
<script>
import "../global.css";
</script>
<slot />

View File

@@ -1,113 +1,27 @@
<script lang="ts">
import { invoke } from "@tauri-apps/api/tauri";
import Table from "$lib/table.svelte";
import Schema from "$lib/schema.svelte";
import Editor from "$lib/editor.svelte";
import type { CHResponse } from "$lib/query";
let query = "";
let response = "";
async function greet() {
// Learn more about Tauri commands at https://tauri.app/v1/guides/features/command
response = await invoke("query", { query });
}
let response: CHResponse = $state.raw(undefined);
</script>
<div class="container">
<form class="row" on:submit|preventDefault={greet}>
<input
id="greet-input"
placeholder="Enter a query..."
bind:value={query}
/>
<button type="submit">Query</button>
</form>
<p>{response}</p>
</div>
<section class="screen">
<Schema />
<section class="right">
<Editor bind:response />
<Table {response} />
</section>
</section>
<style>
:root {
font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
font-size: 16px;
line-height: 24px;
font-weight: 400;
color: #0f0f0f;
background-color: #f6f6f6;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-text-size-adjust: 100%;
}
.container {
margin: 0;
padding-top: 10vh;
.screen {
display: flex;
flex-direction: column;
justify-content: center;
text-align: center;
height: 100vh;
}
.row {
display: flex;
justify-content: center;
}
a {
font-weight: 500;
color: #646cff;
text-decoration: inherit;
}
input,
button {
border-radius: 8px;
border: 1px solid transparent;
padding: 0.6em 1.2em;
font-size: 1em;
font-weight: 500;
font-family: inherit;
color: #0f0f0f;
background-color: #ffffff;
transition: border-color 0.25s;
box-shadow: 0 2px 2px rgba(0, 0, 0, 0.2);
}
button {
cursor: pointer;
}
button:hover {
border-color: #396cd8;
}
button:active {
border-color: #396cd8;
background-color: #e8e8e8;
}
input,
button {
outline: none;
}
#greet-input {
margin-right: 5px;
}
@media (prefers-color-scheme: dark) {
:root {
color: #f6f6f6;
background-color: #2f2f2f;
}
input,
button {
color: #ffffff;
background-color: #0f0f0f98;
}
button:active {
background-color: #0f0f0f69;
}
.right {
flex-grow: 1;
}
</style>

View File

@@ -10,6 +10,9 @@ const config = {
kit: {
adapter: adapter(),
},
compilerOptions: {
runes: true
}
};
export default config;