Skip to content
claudespicePublic
forked from spiceai/gospice

About

Golang SDK for Spice.ai

Resources

Stars

0 stars

Watchers

0 watching

Forks

 
 

Latest commit

 

History

59 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

gospice

Golang SDK for Spice.ai

See Go Docs at pkg.go.dev/github.com/spiceai/gospice/v9.

For full documentation visit docs.spice.ai.

Usage

  1. Get the gospice package.
go get github.com/spiceai/gospice/v9@latest
  1. Import the package.
import "github.com/spiceai/gospice/v9"
  1. Create a SpiceClient passing in your API key. Get your free API key at spice.ai.
spice := NewSpiceClient()
defer spice.Close()
  1. Initialize the SpiceClient with spice.ai cloud.
if err := spice.Init(
    spice.WithApiKey(ApiKey),
    spice.WithSpiceCloudAddress()
); err != nil {
    panic(fmt.Errorf("error initializing SpiceClient: %w", err))
}
  1. Execute a query and get back an Apache Arrow Reader.
    reader, err := spice.Sql(context.Background(), "SELECT 1")
    if err != nil {
        panic(fmt.Errorf("error querying: %w", err))
    }
    defer reader.Release()
  1. Iterate through the reader to access the records.
    for reader.Next() {
        record := reader.RecordBatch()
        defer record.Release()
        fmt.Println(record)
    }

Using Parameterized Queries (Recommended)

gospice v9 supports parameterized queries using ADBC (Arrow Database Connectivity), which is the recommended approach for queries with parameters to prevent SQL injection:

// Query with a single parameter
reader, err := spice.SqlWithParams(
    context.Background(),
    "SELECT * FROM tpch.customer WHERE c_custkey > $1 LIMIT 10",
    100,
)
if err != nil {
    panic(fmt.Errorf("error querying: %w", err))
}
defer reader.Release()

for reader.Next() {
    record := reader.RecordBatch()
    defer record.Release()
    fmt.Println(record)
}

Query with multiple parameters:

reader, err := spice.SqlWithParams(
    context.Background(),
    "SELECT * FROM taxi_trips WHERE trip_distance > $1 AND fare_amount > $2 LIMIT 100",
    5.0,
    20.0,
)
if err != nil {
    panic(fmt.Errorf("error querying: %w", err))
}
defer reader.Release()

Supported parameter types with automatic type inference:

  • Integers: int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64
  • Floating point: float32, float64
  • String: string
  • Boolean: bool
  • Binary: []byte
  • Null values: nil

Typed Parameters for Advanced Use Cases:

For precise control over Arrow types, use typed parameter constructors:

import "github.com/spiceai/gospice/v9"

// Explicit type control for complex scenarios
reader, err := spice.SqlWithParams(
    ctx,
    "SELECT * FROM data WHERE id = $1 AND amount = $2 AND active = $3",
    gospice.Int64Param(12345),           // Explicitly int64
    gospice.Decimal128Param(...),        // Decimal with precision
    gospice.BoolParam(true),             // Explicitly boolean
)

Available typed parameter constructors:

  • Integers: Int8Param, Int16Param, Int32Param, Int64Param, Uint8Param, Uint16Param, Uint32Param, Uint64Param
  • Floating point: Float16Param, Float32Param, Float64Param
  • Strings: StringParam, LargeStringParam
  • Binary: BinaryParam, LargeBinaryParam, FixedSizeBinaryParam
  • Boolean: BoolParam
  • Date/Time: Date32Param, Date64Param, Time32Param, Time64Param, TimestampParam, DurationParam
  • Intervals: MonthIntervalParam, DayTimeIntervalParam, MonthDayNanoIntervalParam
  • Decimals: Decimal128Param, Decimal256Param
  • Null: NullParam

Or use the generic constructors:

  • NewParam(value) - Creates a parameter with automatic type inference
  • NewTypedParam(value, arrowType) - Creates a parameter with explicit Arrow type

Using local spice runtime

Follow the quickstart guide to install and run spice locally

Initialize the SpiceClient to use local runtime connection:

if err := spice.Init(); err != nil {
    panic(fmt.Errorf("error initializing SpiceClient: %w", err))
}

Configure with a custom flight address:

if err := spice.Init(
    spice.WithFlightAddress("grpc://localhost:50052")
); err != nil {
    panic(fmt.Errorf("error initializing SpiceClient: %w", err))
}

Async Queries

Query and QueryWithParams submit SQL for asynchronous execution and return an *AsyncQuery handle. Async queries run in the background on the Spice runtime and are designed for long-running analytical and batch workloads. They require the runtime to be running in distributed/scheduler mode (spiced --role scheduler with runtime.scheduler.state_location configured).

// Submit a query for async execution
query, err := spice.Query(context.Background(), "SELECT * FROM taxi_trips")
if err != nil {
    panic(fmt.Errorf("error submitting query: %w", err))
}
fmt.Println("query id:", query.ID())

// Wait for completion and fetch results as an Apache Arrow reader
reader, err := query.Results(context.Background())
if err != nil {
    panic(fmt.Errorf("error fetching results: %w", err))
}
defer reader.Release()

for reader.Next() {
    fmt.Println(reader.RecordBatch())
}

Parameterized async queries bind positional parameters ($1, $2, ...):

query, err := spice.QueryWithParams(
    context.Background(),
    "SELECT * FROM taxi_trips WHERE trip_distance > $1 LIMIT $2",
    5.0,
    100,
)

The *AsyncQuery handle provides:

  • ID() - the server-assigned query ID
  • Status(ctx) - poll the current status once (PENDING, RUNNING, SUCCEEDED, FAILED, CANCELLED, CLOSED)
  • Wait(ctx) - block until the query reaches a terminal status
  • Results(ctx) - wait for completion and return results as an array.RecordReader
  • Cancel(ctx) - request cancellation

For synchronous, real-time streaming queries, use Sql / SqlWithParams instead.

Health Checks

gospice v9 provides health check methods to verify Spice instance status before executing queries:

// Check if Spice instance is healthy (unauthenticated)
ctx := context.Background()
if !spice.IsSpiceHealthy(ctx) {
    log.Println("Spice instance is not healthy")
    return
}

// Check if Spice Cloud is ready (requires API key)
if !spice.IsSpiceReady(ctx) {
    log.Println("Spice Cloud is not ready or API key is invalid")
    return
}
  • IsSpiceHealthy(ctx) - Calls /health endpoint (unauthenticated)
  • IsSpiceReady(ctx) - Calls /v1/ready endpoint (requires API key)

Example

Run go run . to execute a sample query and print the results to the console.

See query_test.go for examples on querying TPC-H and taxi trips datasets.

Connection retry

The SpiceClient implements connection retry mechanism (3 attempts by default). The number of attempts can be configured via SetMaxRetries:

spice := NewSpiceClient()
spice.SetMaxRetries(5) // Setting to 0 will disable retries

Retries are performed for connection and system internal errors. It is the SDK user's responsibility to properly handle other errors, for example RESOURCE_EXHAUSTED (HTTP 429).

Upgrading from v8 to v9

gospice v9 is a new major version with breaking changes. To upgrade:

go get github.com/spiceai/gospice/v9@latest
go mod tidy

Update your imports:

// Before
import "github.com/spiceai/gospice/v8"

// After
import "github.com/spiceai/gospice/v9"

Breaking changes in v9:

  • Query() and QueryWithParams() are now asynchronous and return an *AsyncQuery handle instead of an array.RecordReader. Use the handle's Wait() / Results() methods (see Async Queries), or switch to the synchronous Sql() / SqlWithParams() methods.
  • Minimum Go version is now 1.25 (was 1.24).
  • Upgraded to Apache Arrow v18.6.0 and ADBC v1.11.0, matching the Spice.ai runtime's DataFusion 54.

See UPGRADE_V8_TO_V9.md for the detailed migration guide.

Testing and Benchmarking

Running Tests

Run all tests:

go test ./...

Run tests with verbose output:

go test -v ./...

Run specific test suites:

# Local runtime tests only
go test -v -run="TestLocal"

# Cloud tests only
go test -v -run="TestCloud"

# ADBC tests only
go test -v -run="TestADBC"

Running Benchmarks

Run all benchmarks:

go test -bench=. -benchmem

Run specific benchmarks:

# Benchmark query performance
go test -bench=BenchmarkQuery -benchmem

# Benchmark parameterized queries
go test -bench=BenchmarkQueryWithParams -benchmem

# Benchmark health checks
go test -bench=BenchmarkHealthChecks -benchmem

# Benchmark client initialization
go test -bench=BenchmarkClientInitialization -benchmem

Run benchmarks with custom settings:

# Run for 10 seconds each
go test -bench=. -benchtime=10s

# Run with CPU profiling
go test -bench=. -cpuprofile=cpu.prof

# Run with memory profiling
go test -bench=. -memprofile=mem.prof

Available benchmarks:

  • BenchmarkCloudQuery - Basic query performance against Spice Cloud
  • BenchmarkCloudQueryWithParams - Parameterized query performance (Cloud)
  • BenchmarkLocalQuery - Query performance against local runtime
  • BenchmarkLocalQueryWithParams - Parameterized query performance (Local)
  • BenchmarkParameterBinding - Parameter binding overhead with varying parameter counts
  • BenchmarkClientInitialization - Client initialization overhead
  • BenchmarkHealthChecks - Health check endpoint performance
  • BenchmarkRecordProcessing - Different record processing patterns

About

Golang SDK for Spice.ai

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages