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
93 changes: 88 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,13 @@ jobs:

- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: wasm32-unknown-unknown

- name: Install uv
uses: astral-sh/setup-uv@v5
with:
enable-cache: true

- name: Cache cargo
uses: Swatinem/rust-cache@v2
Expand All @@ -122,13 +129,93 @@ jobs:
run: cargo fmt --check

- name: Run cargo clippy
run: cargo clippy -- -D warnings
run: cargo clippy --all-targets --all-features -- -D warnings

- name: Run cargo test
run: cargo test
env:
RUST_MIN_STACK: 16777216

- name: Check package metadata
run: cargo test --test package_metadata

- name: Check crate package dry run
run: cargo package --locked --no-verify

- name: Check standalone feature surfaces
run: |
cargo check --no-default-features --all-targets
cargo check --features python --lib
cargo check --features python-adbc --lib
cargo check --features mcp-server --bin sidemantic-mcp --test mcp_protocol
cargo check --features mcp-adbc --bin sidemantic-mcp
cargo check --features runtime-server --bin sidemantic-server --test http_server
cargo check --features runtime-server-adbc --bin sidemantic-server
cargo check --features runtime-lsp --bin sidemantic-lsp --test lsp_protocol_smoke
cargo check --features workbench-tui --bin sidemantic --bin sidemantic-workbench
cargo check --features workbench-adbc --bin sidemantic --bin sidemantic-workbench

- name: Install DuckDB ADBC driver
run: |
curl -L https://github.com/duckdb/duckdb/releases/download/v1.4.2/libduckdb-linux-amd64.zip -o /tmp/libduckdb.zip
unzip -q /tmp/libduckdb.zip -d /tmp/libduckdb
echo "SIDEMANTIC_TEST_ADBC_DUCKDB_DRIVER=/tmp/libduckdb/libduckdb.so" >> "$GITHUB_ENV"

- name: Install SQLite ADBC driver
run: |
uv run --no-project --with adbc-driver-sqlite python - <<'PY' >> "$GITHUB_ENV"
import adbc_driver_sqlite

print(f"SIDEMANTIC_TEST_ADBC_SQLITE_DRIVER={adbc_driver_sqlite._driver_path()}")
print("SIDEMANTIC_TEST_ADBC_SQLITE_URI=:memory:")
print("SIDEMANTIC_TEST_ADBC_REQUIRE=duckdb,sqlite")
PY

- name: Run standalone protocol and UI tests
run: |
cargo test --features mcp-server --test mcp_protocol
cargo test --features runtime-server --test http_server
cargo test --features runtime-lsp --test lsp_protocol_smoke
cargo test --features workbench-tui --test cli_smoke workbench
cargo test --features workbench-adbc --test cli_smoke workbench
cargo test --features workbench-tui --test workbench_pty_smoke
cargo test --features workbench-adbc --test workbench_pty_smoke
cargo test --features adbc-exec --test adbc_driver_matrix
cargo test --features mcp-adbc,runtime-server-adbc --test adbc_duckdb_e2e

- name: Smoke C ABI header and static library
run: |
cargo build --release --lib
cc -std=c11 -Wall -Wextra -I include tests/c_abi_smoke.c target/release/libsidemantic.a -lpthread -ldl -lm -lrt -o /tmp/sidemantic_c_abi_smoke
/tmp/sidemantic_c_abi_smoke

- name: Check WASM build
run: cargo check --no-default-features --features wasm --target wasm32-unknown-unknown --lib

- name: Install wasm-bindgen test runner
run: cargo install wasm-bindgen-cli --version 0.2.110

- name: Run WASM runtime tests
run: CARGO_TARGET_WASM32_UNKNOWN_UNKNOWN_RUNNER=wasm-bindgen-test-runner cargo test --target wasm32-unknown-unknown --features wasm --test wasm_bindgen_runtime

- name: Check Python extension build
run: uvx maturin build --out dist

- name: Smoke Python extension wheel
run: uv run --no-project --with dist/*.whl tests/python_wheel_smoke.py

- name: Check lightweight Python extension build
run: uvx maturin build --no-default-features --features python --out dist-python

- name: Smoke lightweight Python extension wheel
run: uv run --no-project --with dist-python/*.whl tests/python_wheel_python_smoke.py

- name: Check Python extension ADBC build
run: uvx maturin build --no-default-features --features python-adbc --out dist-adbc

- name: Smoke Python extension ADBC wheel
run: uv run --no-project --with dist-adbc/*.whl tests/python_wheel_adbc_smoke.py

duckdb-extension:
name: DuckDB Extension
needs: check-rust-changes
Expand Down Expand Up @@ -160,10 +247,6 @@ jobs:
- name: Install build dependencies
run: sudo apt-get update && sudo apt-get install -y ninja-build

- name: Build Rust library
working-directory: sidemantic-rs
run: cargo build --release

- name: Build DuckDB extension
working-directory: sidemantic-duckdb
run: make
Expand Down
65 changes: 63 additions & 2 deletions .github/workflows/integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,6 @@ jobs:
env:
CLICKHOUSE_DB: default
CLICKHOUSE_USER: default
CLICKHOUSE_PASSWORD: clickhouse
CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT: 1
ports:
- 8123:8123
Expand Down Expand Up @@ -221,6 +220,10 @@ jobs:
- name: Install ADBC driver (best effort)
run: |
DB="${{ matrix.db }}"
if [ "$DB" = "clickhouse" ]; then
uvx dbc install --pre clickhouse
exit 0
fi
PKG_DB="$DB"
if [ "$DB" = "postgres" ]; then
PKG_DB="postgresql"
Expand All @@ -237,6 +240,64 @@ jobs:
BIGQUERY_DATASET: "test_dataset"
CLICKHOUSE_HOST: "localhost"
CLICKHOUSE_PORT: "8123"
CLICKHOUSE_PASSWORD: "clickhouse"
SNOWFLAKE_TEST: "1"
run: uv run pytest -m integration tests/db/test_adbc_ci_smoke.py -v

- name: Install Rust for Rust ADBC probe
uses: dtolnay/rust-toolchain@stable

- name: Export Postgres ADBC driver for Rust
if: matrix.db == 'postgres'
run: |
uv pip install adbc-driver-postgresql
uv run python - <<'PY' >> "$GITHUB_ENV"
import adbc_driver_postgresql

print(f"SIDEMANTIC_TEST_ADBC_POSTGRES_DRIVER={adbc_driver_postgresql._driver_path()}")
PY
echo "SIDEMANTIC_TEST_ADBC_POSTGRES_URI=postgresql://test:test@localhost:5432/sidemantic_test" >> "$GITHUB_ENV"
echo "SIDEMANTIC_TEST_ADBC_REQUIRE=postgres" >> "$GITHUB_ENV"

- name: Export BigQuery ADBC driver for Rust
if: matrix.db == 'bigquery'
env:
BIGQUERY_ADBC_CREDENTIALS_JSON: ${{ secrets.BIGQUERY_ADBC_CREDENTIALS_JSON }}
BIGQUERY_ADBC_PROJECT: ${{ vars.BIGQUERY_ADBC_PROJECT }}
BIGQUERY_ADBC_DATASET: ${{ vars.BIGQUERY_ADBC_DATASET }}
run: |
if [ -z "$BIGQUERY_ADBC_CREDENTIALS_JSON" ] || [ -z "$BIGQUERY_ADBC_PROJECT" ] || [ -z "$BIGQUERY_ADBC_DATASET" ]; then
echo "Skipping Rust BigQuery ADBC probe; BIGQUERY_ADBC_CREDENTIALS_JSON secret plus BIGQUERY_ADBC_PROJECT/BIGQUERY_ADBC_DATASET vars are required."
exit 0
fi
uvx dbc install bigquery
CREDENTIALS_FILE="$(mktemp)"
printf '%s' "$BIGQUERY_ADBC_CREDENTIALS_JSON" > "$CREDENTIALS_FILE"
echo "::add-mask::$BIGQUERY_ADBC_CREDENTIALS_JSON"
echo "SIDEMANTIC_TEST_ADBC_BIGQUERY_DRIVER=bigquery" >> "$GITHUB_ENV"
echo "SIDEMANTIC_TEST_ADBC_BIGQUERY_DBOPTS=adbc.bigquery.sql.project_id=$BIGQUERY_ADBC_PROJECT,adbc.bigquery.sql.dataset_id=$BIGQUERY_ADBC_DATASET,adbc.bigquery.sql.auth_type=adbc.bigquery.sql.auth_type.json_credential_file,adbc.bigquery.sql.auth_credentials=$CREDENTIALS_FILE" >> "$GITHUB_ENV"
echo "SIDEMANTIC_TEST_ADBC_REQUIRE=bigquery" >> "$GITHUB_ENV"

- name: Export Snowflake ADBC driver for Rust
if: matrix.db == 'snowflake'
env:
SNOWFLAKE_ADBC_URI: ${{ secrets.SNOWFLAKE_ADBC_URI }}
run: |
if [ -z "$SNOWFLAKE_ADBC_URI" ]; then
echo "Skipping Rust Snowflake ADBC probe; SNOWFLAKE_ADBC_URI secret is required."
exit 0
fi
uvx dbc install snowflake
echo "::add-mask::$SNOWFLAKE_ADBC_URI"
echo "SIDEMANTIC_TEST_ADBC_SNOWFLAKE_DRIVER=snowflake" >> "$GITHUB_ENV"
echo "SIDEMANTIC_TEST_ADBC_SNOWFLAKE_URI=$SNOWFLAKE_ADBC_URI" >> "$GITHUB_ENV"
echo "SIDEMANTIC_TEST_ADBC_REQUIRE=snowflake" >> "$GITHUB_ENV"

- name: Export ClickHouse ADBC driver for Rust
if: matrix.db == 'clickhouse'
run: |
echo "SIDEMANTIC_TEST_ADBC_CLICKHOUSE_DRIVER=clickhouse" >> "$GITHUB_ENV"
echo "SIDEMANTIC_TEST_ADBC_CLICKHOUSE_URI=http://localhost:8123/" >> "$GITHUB_ENV"
echo "SIDEMANTIC_TEST_ADBC_REQUIRE=clickhouse" >> "$GITHUB_ENV"

- name: Run Rust ADBC probe
run: cargo test --manifest-path sidemantic-rs/Cargo.toml --features adbc-exec --test adbc_driver_matrix
40 changes: 39 additions & 1 deletion sidemantic-duckdb/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,44 @@ include_directories(src/include)

# Path to sidemantic-rs
set(SIDEMANTIC_RS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../sidemantic-rs")
set(SIDEMANTIC_LIB "${SIDEMANTIC_RS_DIR}/target/release/libsidemantic.a")
set(SIDEMANTIC_CARGO_TARGET_DIR "${SIDEMANTIC_RS_DIR}/target" CACHE PATH "Cargo target directory for sidemantic-rs")
set(SIDEMANTIC_CARGO_PROFILE "release" CACHE STRING "Cargo profile used for the sidemantic-rs static library")
set(SIDEMANTIC_INCLUDE "${SIDEMANTIC_RS_DIR}/include")

if(WIN32)
set(SIDEMANTIC_STATICLIB_NAME "sidemantic.lib")
else()
set(SIDEMANTIC_STATICLIB_NAME "libsidemantic.a")
endif()

set(SIDEMANTIC_LIB "${SIDEMANTIC_CARGO_TARGET_DIR}/${SIDEMANTIC_CARGO_PROFILE}/${SIDEMANTIC_STATICLIB_NAME}")

find_program(CARGO_EXECUTABLE cargo)
if(NOT CARGO_EXECUTABLE)
message(FATAL_ERROR "cargo is required to build the sidemantic DuckDB extension")
endif()

set(SIDEMANTIC_CARGO_BUILD_ARGS build --manifest-path "${SIDEMANTIC_RS_DIR}/Cargo.toml" --lib)
if(SIDEMANTIC_CARGO_PROFILE STREQUAL "release")
list(APPEND SIDEMANTIC_CARGO_BUILD_ARGS --release)
elseif(NOT SIDEMANTIC_CARGO_PROFILE STREQUAL "debug")
list(APPEND SIDEMANTIC_CARGO_BUILD_ARGS --profile "${SIDEMANTIC_CARGO_PROFILE}")
endif()

file(GLOB_RECURSE SIDEMANTIC_RUST_SOURCES
"${SIDEMANTIC_RS_DIR}/src/*.rs"
"${SIDEMANTIC_RS_DIR}/include/*.h")

add_custom_command(
OUTPUT "${SIDEMANTIC_LIB}"
COMMAND ${CMAKE_COMMAND} -E env "CARGO_TARGET_DIR=${SIDEMANTIC_CARGO_TARGET_DIR}" "${CARGO_EXECUTABLE}" ${SIDEMANTIC_CARGO_BUILD_ARGS}
WORKING_DIRECTORY "${SIDEMANTIC_RS_DIR}"
DEPENDS "${SIDEMANTIC_RS_DIR}/Cargo.toml" "${SIDEMANTIC_RS_DIR}/Cargo.lock" ${SIDEMANTIC_RUST_SOURCES}
COMMENT "Building sidemantic-rs static library"
VERBATIM)

add_custom_target(sidemantic_rust_staticlib DEPENDS "${SIDEMANTIC_LIB}")

# Include Rust library headers
include_directories(${SIDEMANTIC_INCLUDE})

Expand All @@ -22,6 +57,9 @@ set(EXTENSION_SOURCES src/sidemantic_extension.cpp)
build_static_extension(${TARGET_NAME} ${EXTENSION_SOURCES})
build_loadable_extension(${TARGET_NAME} " " ${EXTENSION_SOURCES})

add_dependencies(${EXTENSION_NAME} sidemantic_rust_staticlib)
add_dependencies(${LOADABLE_EXTENSION_NAME} sidemantic_rust_staticlib)

# Link the Rust static library
target_link_libraries(${EXTENSION_NAME} ${SIDEMANTIC_LIB})
target_link_libraries(${LOADABLE_EXTENSION_NAME} ${SIDEMANTIC_LIB})
Expand Down
4 changes: 2 additions & 2 deletions sidemantic-duckdb/Makefile
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
PROJ_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))

# Configuration of extension
EXT_NAME=quack
EXT_NAME=sidemantic
EXT_CONFIG=${PROJ_DIR}extension_config.cmake

# Include the Makefile from extension-ci-tools
include extension-ci-tools/makefiles/duckdb_extension.Makefile
include extension-ci-tools/makefiles/duckdb_extension.Makefile
12 changes: 11 additions & 1 deletion sidemantic-duckdb/src/include/sidemantic_extension.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ ParserExtensionParseResult sidemantic_parse(ParserExtensionInfo *,
ParserExtensionPlanResult sidemantic_plan(ParserExtensionInfo *, ClientContext &,
unique_ptr<ParserExtensionParseData>);

struct SidemanticParserInfo : ParserExtensionInfo {
SidemanticParserInfo(string db_path, string context_key)
: db_path(std::move(db_path)), context_key(std::move(context_key)) {}

string db_path;
string context_key;
};

// Operator extension: handles binding after parsing
struct SidemanticOperatorExtension : public OperatorExtension {
SidemanticOperatorExtension() : OperatorExtension() { Bind = sidemantic_bind; }
Expand All @@ -36,9 +44,11 @@ struct SidemanticOperatorExtension : public OperatorExtension {

// Parser extension: intercepts query strings
struct SidemanticParserExtension : public ParserExtension {
SidemanticParserExtension() : ParserExtension() {
SidemanticParserExtension(string db_path, string context_key) : ParserExtension() {
parse_function = sidemantic_parse;
plan_function = sidemantic_plan;
parser_info =
make_shared_ptr<SidemanticParserInfo>(std::move(db_path), std::move(context_key));
}
};

Expand Down
Loading
Loading