diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7b7b6cf9..7fc585d3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -104,7 +104,19 @@ jobs: strategy: fail-fast: false # Allow other jobs to continue if one fails matrix: - test_mode: [embedded, server, oceanbase] + include: + - test_mode: embedded + example_host: 127.0.0.1 + example_port: 2881 + example_tenant: sys + - test_mode: server + example_host: 127.0.0.1 + example_port: 2881 + example_tenant: sys + - test_mode: oceanbase + example_host: localhost + example_port: 10000 + example_tenant: mysql steps: - name: Free disk space @@ -162,3 +174,28 @@ jobs: uv run pytest tests/integration_tests/ -v --log-cli-level=${log_level} \ -k "${{ matrix.test_mode }}" | tee pytest.log bash .github/scripts/check-pytest-summary.sh pytest.log + + - name: Run examples for ${{ matrix.test_mode }} + env: + MODE: ${{ matrix.test_mode }} + HOST: ${{ matrix.example_host }} + PORT: ${{ matrix.example_port }} + TENANT: ${{ matrix.example_tenant }} + DATABASE: test + SEEKDB_USER: root + run: | + for example_file in examples/*_example.py; do + if [[ "$example_file" == "examples/namespace_example.py" ]]; then + echo "Skipping ${example_file}: requires LakeBase 4.6.1+" + continue + fi + + echo "Testing ${example_file} in ${MODE} mode" + if uv run python "$example_file"; then + echo "${example_file} passed" + else + status=$? + echo "${example_file} failed with exit code ${status}" + exit "$status" + fi + done diff --git a/examples/complete_example.py b/examples/complete_example.py index 2ae2da98..796d4ddf 100644 --- a/examples/complete_example.py +++ b/examples/complete_example.py @@ -13,6 +13,7 @@ """ import logging +import os import uuid import pyseekdb @@ -23,26 +24,35 @@ # PART 1: CLIENT CONNECTION # ============================================================================ +mode = os.getenv("MODE", "embedded") + # Option 1: Embedded mode (local seekdb) -client = pyseekdb.Client( - # path="./seekdb.db", - # database="test" -) +if mode == "embedded": + client = pyseekdb.Client() # Option 2: Server mode (remote seekdb server) -# client = pyseekdb.Client( -# host="127.0.0.1", port=2881, database="test", user="root", password="" -# ) +elif mode == "server": + client = pyseekdb.Client( + host=os.getenv("HOST", "127.0.0.1"), + port=int(os.getenv("PORT", "2881")), + tenant=os.getenv("TENANT", "sys"), + database=os.getenv("DATABASE", "test"), + user=os.getenv("SEEKDB_USER", "root"), + password=os.getenv("SEEKDB_PASSWORD", ""), + ) # Option 3: Remote server mode (OceanBase Server) -# client = pyseekdb.Client( -# host="127.0.0.1", -# port=2881, -# tenant="test", # OceanBase default tenant -# database="test", -# user="root", -# password="" -# ) +elif mode == "oceanbase": + client = pyseekdb.Client( + host=os.getenv("HOST", "127.0.0.1"), + port=int(os.getenv("PORT", "2881")), + tenant=os.getenv("TENANT", "test"), # OceanBase default tenant + database=os.getenv("DATABASE", "test"), + user=os.getenv("SEEKDB_USER", "root"), + password=os.getenv("SEEKDB_PASSWORD", ""), + ) +else: + raise ValueError(f"Unsupported MODE: {mode}") # ============================================================================ # PART 2: COLLECTION MANAGEMENT diff --git a/examples/hybrid_search_example.py b/examples/hybrid_search_example.py index e2d18da4..110125a3 100644 --- a/examples/hybrid_search_example.py +++ b/examples/hybrid_search_example.py @@ -8,10 +8,25 @@ - Handles complex scenarios that query() cannot """ +import os + import pyseekdb # Setup -client = pyseekdb.Client() +mode = os.getenv("MODE", "embedded") +if mode == "embedded": + client = pyseekdb.Client() +elif mode in {"server", "oceanbase"}: + client = pyseekdb.Client( + host=os.getenv("HOST", "127.0.0.1"), + port=int(os.getenv("PORT", "2881")), + tenant=os.getenv("TENANT", "sys" if mode == "server" else "test"), + database=os.getenv("DATABASE", "test"), + user=os.getenv("SEEKDB_USER", "root"), + password=os.getenv("SEEKDB_PASSWORD", ""), + ) +else: + raise ValueError(f"Unsupported MODE: {mode}") collection = client.get_or_create_collection(name="hybrid_search_demo") # Sample data diff --git a/examples/namespace_example.py b/examples/namespace_example.py index e22c1a39..f7f4f797 100644 --- a/examples/namespace_example.py +++ b/examples/namespace_example.py @@ -7,17 +7,26 @@ 3. Vector query inside the namespace """ +import os + import pyseekdb from pyseekdb import FulltextIndexConfig, IVFConfiguration, Schema, VectorIndexConfig # Connect to LakeBase / OceanBase (adjust host/port/credentials) -client = pyseekdb.Client( - host="127.0.0.1", - port=2881, - database="test", - user="root@test", - password="", -) +mode = os.getenv("MODE", "oceanbase") +if mode == "embedded": + client = pyseekdb.Client() +elif mode in {"server", "oceanbase"}: + client = pyseekdb.Client( + host=os.getenv("HOST", "127.0.0.1"), + port=int(os.getenv("PORT", "2881")), + tenant=os.getenv("TENANT", "sys" if mode == "server" else "test"), + database=os.getenv("DATABASE", "test"), + user=os.getenv("SEEKDB_USER", "root"), + password=os.getenv("SEEKDB_PASSWORD", ""), + ) +else: + raise ValueError(f"Unsupported MODE: {mode}") schema = Schema( vector_index=VectorIndexConfig( diff --git a/examples/simple_example.py b/examples/simple_example.py index 87cf036f..6a22928a 100644 --- a/examples/simple_example.py +++ b/examples/simple_example.py @@ -11,32 +11,41 @@ This is a minimal example to get you started quickly with embedding functions. """ +import os + import pyseekdb # ==================== Step 1: Create Client Connection ==================== # You can use embedded mode, server mode, or OceanBase mode -# For this example, we'll use server mode (you can change to embedded or OceanBase) +mode = os.getenv("MODE", "embedded") # Embedded mode (local seekdb) -client = pyseekdb.Client(path="./seekdb.db", database="test") +if mode == "embedded": + client = pyseekdb.Client(path="./seekdb.db", database="test") + # Alternative: Server mode (connecting to remote seekdb server) -# client = pyseekdb.Client( -# host="127.0.0.1", -# port=2881, -# database="test", -# user="root", -# password="" -# ) +elif mode == "server": + client = pyseekdb.Client( + host=os.getenv("HOST", "127.0.0.1"), + port=int(os.getenv("PORT", "2881")), + tenant=os.getenv("TENANT", "sys"), + database=os.getenv("DATABASE", "test"), + user=os.getenv("SEEKDB_USER", "root"), + password=os.getenv("SEEKDB_PASSWORD", ""), + ) # Alternative: Remote server mode (OceanBase Server) -# client = pyseekdb.Client( -# host="127.0.0.1", -# port=2881, -# tenant="test", # OceanBase default tenant -# database="test", -# user="root", -# password="" -# ) +elif mode == "oceanbase": + client = pyseekdb.Client( + host=os.getenv("HOST", "127.0.0.1"), + port=int(os.getenv("PORT", "2881")), + tenant=os.getenv("TENANT", "test"), # OceanBase default tenant + database=os.getenv("DATABASE", "test"), + user=os.getenv("SEEKDB_USER", "root"), + password=os.getenv("SEEKDB_PASSWORD", ""), + ) +else: + raise ValueError(f"Unsupported MODE: {mode}") # ==================== Step 2: Create a Collection with Embedding Function ==================== # A collection is like a table that stores documents with vector embeddings diff --git a/examples/sparse_vector_index_example.py b/examples/sparse_vector_index_example.py index 676275bf..bddd8869 100644 --- a/examples/sparse_vector_index_example.py +++ b/examples/sparse_vector_index_example.py @@ -10,6 +10,7 @@ from __future__ import annotations import contextlib +import os from typing import Any, Literal from transformers.utils import logging as hf_logging @@ -19,8 +20,21 @@ hf_logging.set_verbosity_error() -# 1. Initialize client (Embedded mode; creates seekdb.db in the current directory) -client = Client() +# 1. Initialize client (Embedded mode by default; creates seekdb.db in the current directory) +mode = os.getenv("MODE", "embedded") +if mode == "embedded": + client = Client() +elif mode in {"server", "oceanbase"}: + client = Client( + host=os.getenv("HOST", "127.0.0.1"), + port=int(os.getenv("PORT", "2881")), + tenant=os.getenv("TENANT", "sys" if mode == "server" else "test"), + database=os.getenv("DATABASE", "test"), + user=os.getenv("SEEKDB_USER", "root"), + password=os.getenv("SEEKDB_PASSWORD", ""), + ) +else: + raise ValueError(f"Unsupported MODE: {mode}") # Clean up stale collections from previous runs for name in ["demo_sparse_collection", "hybrid_demo"]: