From b87bbd7e5cb18eee107f4dbb0404de741ac2cbaa Mon Sep 17 00:00:00 2001 From: Dewey Dunnington Date: Tue, 24 Sep 2024 13:05:22 -0500 Subject: [PATCH] more complete stubs --- .github/workflows/native-unix.yml | 4 ++ ci/scripts/cpp_recipe_driver.sh | 51 +++++++++++++++++++ docs/source/cpp/driver_example.rst | 23 +++++++++ docs/source/cpp/index.rst | 1 + .../CMakeLists.txt | 31 ++++++++++- .../driver_example.cc | 48 ++++++++++++++++- .../source/cpp/recipe_driver/driver_example.h | 21 ++++++++ .../cpp/recipe_driver/driver_example_test.cc | 45 ++++++++++++++++ 8 files changed, 222 insertions(+), 2 deletions(-) create mode 100644 ci/scripts/cpp_recipe_driver.sh create mode 100644 docs/source/cpp/driver_example.rst rename docs/source/cpp/{driver_example => recipe_driver}/CMakeLists.txt (58%) rename docs/source/cpp/{driver_example => recipe_driver}/driver_example.cc (62%) create mode 100644 docs/source/cpp/recipe_driver/driver_example.h create mode 100644 docs/source/cpp/recipe_driver/driver_example_test.cc diff --git a/.github/workflows/native-unix.yml b/.github/workflows/native-unix.yml index 6b5da7f294..7922ccb405 100644 --- a/.github/workflows/native-unix.yml +++ b/.github/workflows/native-unix.yml @@ -752,6 +752,10 @@ jobs: shell: bash -l {0} run: | ./ci/scripts/cpp_recipe.sh $(pwd) ~/local build/recipe + - name: Test Recipes (C++ driver) + shell: bash -l {0} + run: | + ./ci/scripts/cpp_recipe_driver.sh $(pwd) ~/local build/recipe_driver - name: Test Recipes (Python) shell: bash -l {0} run: | diff --git a/ci/scripts/cpp_recipe_driver.sh b/ci/scripts/cpp_recipe_driver.sh new file mode 100644 index 0000000000..548c23549a --- /dev/null +++ b/ci/scripts/cpp_recipe_driver.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env bash +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# Build and test the C++ recipes in the documentation. + +set -e + +: ${ADBC_CMAKE_ARGS:=""} +: ${CMAKE_BUILD_TYPE:=Debug} + +main() { + local -r source_dir="${1}" + local -r install_dir="${2}" + local -r build_dir="${3}" + + export DYLD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${install_dir}/lib" + export LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${install_dir}/lib" + + mkdir -p "${build_dir}" + pushd "${build_dir}" + + set -x + cmake "${source_dir}/docs/source/cpp/recipe/" \ + ${ADBC_CMAKE_ARGS} \ + -DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}" \ + -DCMAKE_INSTALL_LIBDIR=lib \ + -DCMAKE_PREFIX_PATH="${install_dir}" + set +x + + cmake --build . -j + ctest \ + --output-on-failure \ + --no-tests=error +} + +main "$@" diff --git a/docs/source/cpp/driver_example.rst b/docs/source/cpp/driver_example.rst new file mode 100644 index 0000000000..3e3964b030 --- /dev/null +++ b/docs/source/cpp/driver_example.rst @@ -0,0 +1,23 @@ +.. Licensed to the Apache Software Foundation (ASF) under one +.. or more contributor license agreements. See the NOTICE file +.. distributed with this work for additional information +.. regarding copyright ownership. The ASF licenses this file +.. to you under the Apache License, Version 2.0 (the +.. "License"); you may not use this file except in compliance +.. with the License. You may obtain a copy of the License at +.. +.. http://www.apache.org/licenses/LICENSE-2.0 +.. +.. Unless required by applicable law or agreed to in writing, +.. software distributed under the License is distributed on an +.. "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +.. KIND, either express or implied. See the License for the +.. specific language governing permissions and limitations +.. under the License. + +============== +Driver Example +============== + +.. recipe:: recipe_driver/driver_example.cc + :language: cpp diff --git a/docs/source/cpp/index.rst b/docs/source/cpp/index.rst index add0e29efe..29bbfc9202 100644 --- a/docs/source/cpp/index.rst +++ b/docs/source/cpp/index.rst @@ -25,4 +25,5 @@ C and C++ quickstart driver_manager concurrency + driver_example api/index diff --git a/docs/source/cpp/driver_example/CMakeLists.txt b/docs/source/cpp/recipe_driver/CMakeLists.txt similarity index 58% rename from docs/source/cpp/driver_example/CMakeLists.txt rename to docs/source/cpp/recipe_driver/CMakeLists.txt index ef73465783..85b00619a1 100644 --- a/docs/source/cpp/driver_example/CMakeLists.txt +++ b/docs/source/cpp/recipe_driver/CMakeLists.txt @@ -36,11 +36,40 @@ fetchcontent_declare(nanoarrow GIT_SHALLOW TRUE) fetchcontent_makeavailable(nanoarrow) +# TODO: We could allow this to be installed + linked to as a target; however, +# fetchcontent is a little nicer for this kind of thing (statically linked +# pinned version of something that doesn't rely on a system libraray). add_library(adbc_driver_framework ../../../../c/driver/framework/utility.cc ../../../../c/driver/framework/objects.cc) -target_include_directories(adbc_driver_framework PRIVATE ../../../../c ../../../../c/include) +target_include_directories(adbc_driver_framework PRIVATE ../../../../c + ../../../../c/include) target_link_libraries(adbc_driver_framework PRIVATE nanoarrow::nanoarrow) +# TODO: Do we want any symbol visiblity presets here to ensure that the only one exposed +# is the init function? add_library(driver_example SHARED driver_example.cc) target_include_directories(driver_example PRIVATE ../../../../c ../../../../c/include) target_link_libraries(driver_example PRIVATE adbc_driver_framework nanoarrow::nanoarrow) + +# TODO: Do we want to have this as part of the example? We could make the validation library +# available but I am not sure it is ready to promise that kind of stability (e.g., C++ +# helpers to manage database/connection/statement lifecycle might make it much nicer +# to write tests). +if(ADBC_DRIVER_EXAMPLE_BUILD_TESTS) + fetchcontent_declare(googletest + URL https://github.com/google/googletest/archive/refs/tags/v1.15.1.tar.gz + URL_HASH SHA256=5052e088b16bdd8c6f0c7f9cafc942fd4f7c174f1dac6b15a8dd83940ed35195 + ) + fetchcontent_makeavailable(googletest) + + find_package(AdbcDriverManager REQUIRED) + + add_executable(driver_example_test driver_example_test.cc) + target_link_libraries(driver_example_test + PRIVATE gtest_main driver_example + AdbcDriverManager::adbc_driver_manager_static) + + include(GoogleTest) + gtest_discover_tests(driver_example_test) + +endif() diff --git a/docs/source/cpp/driver_example/driver_example.cc b/docs/source/cpp/recipe_driver/driver_example.cc similarity index 62% rename from docs/source/cpp/driver_example/driver_example.cc rename to docs/source/cpp/recipe_driver/driver_example.cc index 5888e97a62..bd299294c7 100644 --- a/docs/source/cpp/driver_example/driver_example.cc +++ b/docs/source/cpp/recipe_driver/driver_example.cc @@ -15,6 +15,52 @@ // specific language governing permissions and limitations // under the License. +// RECIPE STARTS HERE + +/// Here we'll show the structure of building an ADBC driver in C++ using +/// the ADBC driver framework library. This is the same library that ADBC +/// uses to build its SQLite and PostgreSQL drivers and abstracts away +/// the details of C callables and catalog/metadata functions that can be +/// difficult to implement but are essential for efficiently leveraging +// the rest of the ADBC ecosystem. + + +/// Installation +/// ============ +/// +/// This quickstart is actually a literate C++ file. You can clone +/// the repository, build the sample, and follow along. +/// +/// We'll assume you're using conda-forge_ for dependencies. CMake, a +/// C++17 compiler, and the ADBC libraries are required. They can be +/// installed as follows: +/// +/// .. code-block:: shell +/// +/// mamba install cmake compilers libadbc-driver-manager +/// +/// .. _conda-forge: https://conda-forge.org/ + +/// Building +/// ======== +/// +/// We'll use CMake_ here. From a source checkout of the ADBC repository: +/// +/// .. code-block:: shell +/// +/// mkdir build +/// cd build +/// cmake ../docs/source/cpp/recipe_driver +/// cmake --build . +/// ctest +/// +/// .. _CMake: https://cmake.org/ + +/// Building an ADBC Driver using C++ +/// ================================= +/// +/// Let's start with some includes: + #include "driver/framework/connection.h" #include "driver/framework/database.h" #include "driver/framework/statement.h" @@ -63,7 +109,7 @@ class DriverExampleStatement : public adbc::driver::Statement + +extern "C" AdbcStatusCode ExampleDriverInitFunc(int version, void* raw_driver, + AdbcError* error); diff --git a/docs/source/cpp/recipe_driver/driver_example_test.cc b/docs/source/cpp/recipe_driver/driver_example_test.cc new file mode 100644 index 0000000000..5ec8a0a09b --- /dev/null +++ b/docs/source/cpp/recipe_driver/driver_example_test.cc @@ -0,0 +1,45 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +#include "driver_example.h" + +#include "arrow-adbc/adbc_driver_manager.h" +#include "gtest/gtest.h" + +TEST(DriverExample, TestLifecycle) { + struct AdbcDriver driver; + ASSERT_EQ(AdbcLoadDriverFromInitFunc(&ExampleDriverInitFunc, ADBC_VERSION_1_1_0, + &driver, nullptr), + ADBC_STATUS_OK); + + struct AdbcDatabase database; + ASSERT_EQ(AdbcDatabaseNew(&database, nullptr), ADBC_STATUS_OK); + ASSERT_EQ(AdbcDatabaseInit(&database, nullptr), ADBC_STATUS_OK); + + struct AdbcConnection connection; + ASSERT_EQ(AdbcConnectionNew(&connection, nullptr), ADBC_STATUS_OK); + ASSERT_EQ(AdbcConnectionInit(&connection, &database, nullptr), ADBC_STATUS_OK); + + struct AdbcStatement statement; + ASSERT_EQ(AdbcStatementNew(&connection, &statement, nullptr), ADBC_STATUS_OK); + + ASSERT_EQ(AdbcStatementRelease(&statement, nullptr), ADBC_STATUS_OK); + ASSERT_EQ(AdbcConnectionRelease(&connection, nullptr), ADBC_STATUS_OK); + ASSERT_EQ(AdbcDatabaseRelease(&database, nullptr), ADBC_STATUS_OK); + + ASSERT_EQ(driver.release(&driver, nullptr), ADBC_STATUS_OK); +}