gospice v8 is a major version update that introduces:
- New cleaner API with
Sql()andSqlWithParams()methods - Health check methods
IsSpiceHealthy()andIsSpiceReady() - Upgraded to Apache Arrow v18 and Go 1.24
Good news: v8 is fully backward compatible with v7. Your existing Query() and QueryWithParams() calls will continue to work!
go get github.com/spiceai/gospice/v8@latest
go mod tidyUpdate all imports in your Go files:
// Before (v7)
import "github.com/spiceai/gospice/v7"
// After (v8)
import "github.com/spiceai/gospice/v8"Find and replace:
# On Linux/macOS
find . -name "*.go" -type f -exec sed -i 's|github.com/spiceai/gospice/v7|github.com/spiceai/gospice/v8|g' {} +
# On macOS with BSD sed
find . -name "*.go" -type f -exec sed -i '' 's|github.com/spiceai/gospice/v7|github.com/spiceai/gospice/v8|g' {} +go build ./...
go test ./...That's it! Your code should work without any other changes.
gospice v8 introduces cleaner method names:
// Old way (still works for backward compatibility)
reader, err := spice.Query(ctx, "SELECT * FROM users")
reader, err := spice.QueryWithParams(ctx, "SELECT * FROM users WHERE id = $1", userId)
// New way (recommended)
reader, err := spice.Sql(ctx, "SELECT * FROM users")
reader, err := spice.SqlWithParams(ctx, "SELECT * FROM users WHERE id = $1", userId)Why the change?
- Shorter, cleaner method names
- Better alignment with SQL standard naming
- Your old code continues to work -
Query()andQueryWithParams()are maintained for backward compatibility
Automatic type inference for common Go types:
- 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:
v8 introduces typed parameter constructors for precise control over Arrow types:
// Example: Using typed parameters for decimal and timestamp
reader, err := spice.SqlWithParams(
ctx,
"SELECT * FROM trades WHERE price >= $1 AND trade_time > $2",
gospice.Decimal128Param(priceBytes, 19, 4),
gospice.TimestampParam(timestamp, arrow.Microsecond, "UTC"),
)See params.go for the complete list of typed constructors including Int64Param, Float64Param, StringParam, TimestampParam, Decimal128Param, and many more.
Check Spice instance health before making queries:
ctx := context.Background()
// Check if instance is healthy (no auth required)
if !spice.IsSpiceHealthy(ctx) {
log.Println("Spice instance is not healthy")
return
}
// Check if instance is ready (requires API key for cloud)
if !spice.IsSpiceReady(ctx) {
log.Println("Spice instance is not ready")
return
}
// Proceed with queries...Use cases:
- Application startup validation
- Health monitoring and alerting
- Graceful test skipping in CI/CD
- Connection readiness checks
gospice v8 uses ADBC under the hood for better performance:
- Lazy initialization - ADBC client initializes when first used
- Automatic retries - Built-in retry logic for transient failures
- Better error handling - More detailed error messages
- Native Arrow integration - Improved performance with Arrow data
No code changes needed - it works automatically!
Before (v7):
import "github.com/spiceai/gospice/v7"
spice := gospice.NewSpiceClient()
defer spice.Close()
spice.Init(gospice.WithApiKey(apiKey), gospice.WithSpiceCloudAddress())
reader, err := spice.Query(ctx, "SELECT * FROM table LIMIT 10")After (v8):
import "github.com/spiceai/gospice/v8"
spice := gospice.NewSpiceClient()
defer spice.Close()
spice.Init(gospice.WithApiKey(apiKey), gospice.WithSpiceCloudAddress())
// Same code works! Or use new parameterized queries:
reader, err := spice.QueryWithParams(ctx, "SELECT * FROM table LIMIT 10")Before (v7) - Vulnerable:
import "github.com/spiceai/gospice/v7"
// ⚠️ SQL injection risk!
userId := request.GetUserId()
sql := fmt.Sprintf("SELECT * FROM users WHERE id = %s", userId)
reader, err := spice.Query(ctx, sql)After (v8) - Secure:
import "github.com/spiceai/gospice/v8"
// ✅ Protected from SQL injection
userId := request.GetUserId()
reader, err := spice.QueryWithParams(ctx,
"SELECT * FROM users WHERE id = $1",
userId,
)Before (v7):
import "github.com/spiceai/gospice/v7"
func TestQueryData(t *testing.T) {
spice := gospice.NewSpiceClient()
defer spice.Close()
spice.Init()
// Test might fail if Spice is not running
reader, err := spice.Query(ctx, "SELECT * FROM data")
if err != nil {
t.Fatalf("Query failed: %v", err)
}
}After (v8) - Graceful:
import "github.com/spiceai/gospice/v8"
func TestQueryData(t *testing.T) {
spice := gospice.NewSpiceClient()
defer spice.Close()
spice.Init()
// Skip gracefully if Spice is not available
ctx := context.Background()
if !spice.IsSpiceHealthy(ctx) {
t.Skip("Spice instance not available")
}
reader, err := spice.Query(ctx, "SELECT * FROM data")
if err != nil {
t.Fatalf("Query failed: %v", err)
}
}If you directly use Apache Arrow types, update imports:
// Before (v17)
import "github.com/apache/arrow/go/v17/arrow"
import "github.com/apache/arrow/go/v17/arrow/array"
// After (v18)
import "github.com/apache/arrow-go/v18/arrow"
import "github.com/apache/arrow-go/v18/arrow/array"Update command:
go get github.com/apache/arrow-go/v18@latestgospice v8 requires Go 1.24+
Check your Go version:
go versionUpdate if needed:
# Download from https://go.dev/dl/
# Or use your package managerMake sure you've updated go.mod:
go get github.com/spiceai/gospice/v8@latest
go mod tidyThis can happen if ADBC initialization fails. The client will retry automatically. If the error persists:
- Check your network connection
- Verify API key (if using Spice Cloud)
- Ensure Spice runtime is running (if using local)
- Check firewall rules
If you see errors like cannot find package "github.com/apache/arrow/go/v17":
# Update Arrow to v18
go get github.com/apache/arrow-go/v18@latest
go mod tidy
# Update imports in your code
# Change: github.com/apache/arrow/go/v17
# To: github.com/apache/arrow-go/v18Use health checks to skip tests when Spice is not available:
if !spice.IsSpiceHealthy(ctx) {
t.Skip("Skipping - Spice instance not available")
}Or set up environment-specific test suites:
# Run only unit tests (no Spice required)
go test -run TestUnit ./...
# Run integration tests (requires Spice)
go test -run TestIntegration ./...// ❌ Don't do this with user input
userId := getUserInput()
sql := fmt.Sprintf("SELECT * FROM users WHERE id = %s", userId)
reader, err := spice.Query(ctx, sql)
// ✅ Do this instead
reader, err := spice.QueryWithParams(ctx,
"SELECT * FROM users WHERE id = $1",
userId,
)func main() {
spice := gospice.NewSpiceClient()
defer spice.Close()
if err := spice.Init(...); err != nil {
log.Fatal(err)
}
// Wait for Spice to be ready
ctx := context.Background()
for i := 0; i < 30; i++ {
if spice.IsSpiceHealthy(ctx) {
log.Println("Spice is ready!")
break
}
log.Println("Waiting for Spice...")
time.Sleep(2 * time.Second)
}
// Start application...
}ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
reader, err := spice.QueryWithParams(ctx, sql, params...)reader, err := spice.QueryWithParams(ctx, sql, param1, param2)
if err != nil {
log.Printf("Query failed: %v", err)
// Handle error appropriately
return
}
defer reader.Release()
for reader.Next() {
record := reader.RecordBatch()
defer record.Release()
// Process record...
}
// Check for errors during iteration
if err := reader.Err(); err != nil {
log.Printf("Error reading results: %v", err)
}- 📖 Documentation: docs.spice.ai/sdks/go
- 💬 Discord: spice.ai/discord
- 🐛 Issues: github.com/spiceai/gospice/issues
- 📚 Examples: See
cmd/main.goin the repository
- Run
go get github.com/spiceai/gospice/v8@latest - Update imports from
v7tov8 - Run
go mod tidy - Update Arrow imports if using Arrow types directly
- Verify build with
go build ./... - Run tests with
go test ./... - Consider using
SqlWithParams()for queries with user input - Add health checks to tests and applications
- Update CI/CD pipelines if needed
Welcome to gospice v8! 🚀