Skip to content

Commit b76a706

Browse files
committed
Merge remote-tracking branch 'origin/trunk' into phillip/adbc-reauth-on-session-expiry
# Conflicts: # adbc.go
2 parents 4b59acf + 7e40890 commit b76a706

14 files changed

Lines changed: 949 additions & 232 deletions

File tree

.github/workflows/go.yml

Lines changed: 76 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
fail-fast: false
1717
matrix:
1818
os: [ubuntu-latest, macos-latest, windows-latest]
19-
go-version: ['1.24', '1.25']
19+
go-version: ['1.25', '1.26']
2020
steps:
2121
- uses: actions/checkout@v5
2222

@@ -31,11 +31,18 @@ jobs:
3131
- name: golangci-lint
3232
uses: golangci/golangci-lint-action@v8
3333
with:
34-
version: v2.1
34+
version: v2.12
3535

3636
- name: Build
3737
run: go build -v ./...
3838

39+
# The Spice runtime cannot be installed or run natively on Windows, so the
40+
# Windows job runs the runtime-free unit tests natively and defers the
41+
# runtime install + integration tests to WSL (see the WSL steps below).
42+
- name: Unit tests (Windows native)
43+
if: matrix.os == 'windows-latest'
44+
run: go test -v -run 'TestUserAgent|TestPrependedUserAgent|TestInferArrowType|TestAppendValueToBuilder|TestComprehensiveArrowTypes|TestParamType|TestTypedParamInference|TestExtendedArrowTypes' ./...
45+
3946
- name: Install Spice (https://install.spiceai.org) (Linux)
4047
if: matrix.os == 'ubuntu-latest' || matrix.os == 'macos-latest'
4148
env:
@@ -45,17 +52,6 @@ jobs:
4552
echo "$HOME/.spice/bin" >> $GITHUB_PATH
4653
$HOME/.spice/bin/spice install
4754
48-
- name: install Spice (Windows)
49-
if: matrix.os == 'windows-latest'
50-
run: |
51-
curl -L "https://install.spiceai.org/Install.ps1" -o Install.ps1 && PowerShell -ExecutionPolicy Bypass -File ./Install.ps1
52-
53-
- name: add Spice bin to PATH (Windows)
54-
if: matrix.os == 'windows-latest'
55-
run: |
56-
Add-Content $env:GITHUB_PATH (Join-Path $HOME ".spice\bin")
57-
shell: pwsh
58-
5955
- name: Init and start spice app (Unix)
6056
if: matrix.os != 'windows-latest'
6157
run: |
@@ -74,82 +70,90 @@ jobs:
7470
sleep 1
7571
done
7672
77-
- name: Init and start spice app (Windows)
78-
if: matrix.os == 'windows-latest'
79-
run: |
80-
spice install
81-
spice init spice_qs
82-
cd spice_qs
83-
spice add spiceai/quickstart
84-
shell: pwsh
85-
8673
- name: Test
8774
if: matrix.os != 'windows-latest'
8875
env:
8976
SPICE_API_KEY: ${{ secrets.SPICE_CLOUD_API_KEY }}
9077
run: go test -v ./...
9178

92-
- name: Start runtime and test (Windows)
79+
# Native Windows local runtime is unsupported ("Open WSL and run the Linux
80+
# Spice CLI there instead"), so the integration tests run inside WSL against
81+
# a Linux Spice runtime.
82+
- name: Set up WSL (Windows)
83+
if: matrix.os == 'windows-latest'
84+
uses: Vampire/setup-wsl@v7
85+
with:
86+
# Ubuntu 24.04 (glibc 2.39) — the Spice binary requires glibc >= 2.38.
87+
distribution: Ubuntu-24.04
88+
additional-packages: curl ca-certificates git
89+
90+
# Forward the workspace path and API key into every wsl-bash step.
91+
- name: Configure WSLENV (Windows)
9392
if: matrix.os == 'windows-latest'
93+
shell: bash
94+
run: echo "WSLENV=GITHUB_WORKSPACE:SPICE_API_KEY" >> "$GITHUB_ENV"
95+
96+
- name: Install Spice and run integration tests in WSL (Windows)
97+
if: matrix.os == 'windows-latest'
98+
shell: wsl-bash {0}
9499
env:
95100
SPICE_API_KEY: ${{ secrets.SPICE_CLOUD_API_KEY }}
96101
run: |
97-
$spicedPath = Join-Path $HOME ".spice\bin\spiced"
98-
$spicedDir = Join-Path (Get-Location) "spice_qs"
99-
$logPath = Join-Path $spicedDir "spice.log"
100-
$errPath = Join-Path $spicedDir "spice.err.log"
101-
$proc = Start-Process -FilePath $spicedPath -WorkingDirectory $spicedDir -RedirectStandardOutput $logPath -RedirectStandardError $errPath -PassThru
102-
Write-Host "Started spiced PID=$($proc.Id)"
103-
# Wait for Spice HTTP to be ready
104-
Write-Host "Waiting for Spice HTTP to be ready..."
105-
for ($i = 1; $i -le 60; $i++) {
106-
try {
107-
$response = Invoke-WebRequest -Uri "http://127.0.0.1:8090/v1/ready" -UseBasicParsing -ErrorAction Stop
108-
if ($response.Content -match "ready") {
109-
Write-Host "Spice HTTP is ready!"
110-
break
111-
}
112-
} catch { }
113-
Write-Host "Waiting HTTP... ($i/60)"
114-
Start-Sleep -Seconds 1
115-
}
116-
# Wait for Spice Flight (gRPC) to be ready by checking the TCP port
117-
Write-Host "Waiting for Spice Flight to be ready..."
118-
for ($i = 1; $i -le 60; $i++) {
119-
$tcp = New-Object System.Net.Sockets.TcpClient
120-
try {
121-
$tcp.Connect("127.0.0.1", 50051)
122-
if ($tcp.Connected) {
123-
Write-Host "Spice Flight is ready!"
124-
$tcp.Close()
125-
break
126-
}
127-
} catch { }
128-
finally { $tcp.Close() }
129-
Write-Host "Waiting Flight... ($i/60)"
130-
Start-Sleep -Seconds 1
102+
# Retry helper for flaky network installs.
103+
retry() {
104+
local n
105+
for n in 1 2 3; do
106+
if "$@"; then return 0; fi
107+
echo "::warning::attempt ${n}/3 failed: $*"
108+
sleep 5
109+
done
110+
return 1
131111
}
132-
try {
133-
go test -v ./...
134-
$testExit = $LASTEXITCODE
135-
} finally {
136-
Write-Host "Stopping spiced PID=$($proc.Id)"
137-
Stop-Process -Id $proc.Id -Force -ErrorAction SilentlyContinue
138-
}
139-
exit $testExit
140-
shell: pwsh
112+
113+
# Install a current Go toolchain inside the WSL distribution.
114+
GO_VER="$(curl -fsSL --retry 3 'https://go.dev/VERSION?m=text' | head -1)"
115+
echo "Installing ${GO_VER} in WSL"
116+
curl -fsSL --retry 3 "https://go.dev/dl/${GO_VER}.linux-amd64.tar.gz" -o /tmp/go.tgz
117+
rm -rf /usr/local/go && tar -C /usr/local -xzf /tmp/go.tgz
118+
export PATH="/usr/local/go/bin:${HOME}/.spice/bin:${PATH}"
119+
go version
120+
121+
# Enter the checked-out repo (Windows workspace, mounted under /mnt).
122+
cd "$(wslpath -u "${GITHUB_WORKSPACE}")"
123+
124+
# Install the Spice CLI and runtime (downloads can be flaky, so retry).
125+
retry bash -c 'curl -sSL https://install.spiceai.org | /bin/bash'
126+
retry spice install
127+
128+
# Start a quickstart runtime.
129+
spice init spice_qs
130+
cd spice_qs
131+
retry spice add spiceai/quickstart
132+
nohup spice run > spice.log 2>&1 &
133+
cd ..
134+
135+
echo "Waiting for Spice to be ready..."
136+
for i in $(seq 1 90); do
137+
if curl -fs http://localhost:8090/v1/ready >/dev/null 2>&1; then
138+
echo "Spice is ready!"
139+
break
140+
fi
141+
echo "Waiting... ($i/90)"
142+
sleep 2
143+
done
144+
145+
go test -v ./...
141146
142147
- name: Print Spice logs (Unix)
143148
if: always() && matrix.os != 'windows-latest'
144149
run: |
145150
echo "=== Spice Runtime Logs ==="
146151
cat spice_qs/spice.log || echo "No log file found"
147152
148-
- name: Print Spice logs (Windows)
153+
- name: Print Spice logs (WSL) (Windows)
149154
if: always() && matrix.os == 'windows-latest'
155+
shell: wsl-bash {0}
150156
run: |
151-
Write-Host "=== Spice Runtime Logs (stdout) ==="
152-
Get-Content spice_qs\spice.log -ErrorAction SilentlyContinue
153-
Write-Host "=== Spice Runtime Logs (stderr) ==="
154-
Get-Content spice_qs\spice.err.log -ErrorAction SilentlyContinue
155-
shell: pwsh
157+
cd "$(wslpath -u "${GITHUB_WORKSPACE:-}" 2>/dev/null)" 2>/dev/null || true
158+
echo "=== Spice Runtime Logs (WSL) ==="
159+
cat spice_qs/spice.log 2>/dev/null || echo "No log file found"

README.md

Lines changed: 62 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
Golang SDK for Spice.ai
44

5-
See Go Docs at [pkg.go.dev/github.com/spiceai/gospice/v8](https://pkg.go.dev/github.com/spiceai/gospice/v8).
5+
See Go Docs at [pkg.go.dev/github.com/spiceai/gospice/v9](https://pkg.go.dev/github.com/spiceai/gospice/v9).
66

77
For full documentation visit [docs.spice.ai](https://docs.spice.ai/sdks/go).
88

@@ -11,13 +11,13 @@ For full documentation visit [docs.spice.ai](https://docs.spice.ai/sdks/go).
1111
1. Get the gospice package.
1212

1313
```go
14-
go get github.com/spiceai/gospice/v8@latest
14+
go get github.com/spiceai/gospice/v9@latest
1515
```
1616

1717
1. Import the package.
1818

1919
```go
20-
import "github.com/spiceai/gospice/v8"
20+
import "github.com/spiceai/gospice/v9"
2121
```
2222

2323
1. Create a SpiceClient passing in your API key. Get your free API key at [spice.ai](https://spice.ai).
@@ -41,7 +41,7 @@ if err := spice.Init(
4141
1. Execute a query and get back an Apache Arrow Reader.
4242

4343
```go
44-
reader, err := spice.Query(context.Background(), "SELECT 1")
44+
reader, err := spice.Sql(context.Background(), "SELECT 1")
4545
if err != nil {
4646
panic(fmt.Errorf("error querying: %w", err))
4747
}
@@ -60,7 +60,7 @@ if err := spice.Init(
6060

6161
### Using Parameterized Queries (Recommended)
6262

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

6565
```go
6666
// Query with a single parameter
@@ -110,7 +110,7 @@ defer reader.Release()
110110
For precise control over Arrow types, use typed parameter constructors:
111111

112112
```go
113-
import "github.com/spiceai/gospice/v8"
113+
import "github.com/spiceai/gospice/v9"
114114

115115
// Explicit type control for complex scenarios
116116
reader, err := spice.SqlWithParams(
@@ -161,9 +161,54 @@ if err := spice.Init(
161161
}
162162
```
163163

164+
## Async Queries
165+
166+
`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).
167+
168+
```go
169+
// Submit a query for async execution
170+
query, err := spice.Query(context.Background(), "SELECT * FROM taxi_trips")
171+
if err != nil {
172+
panic(fmt.Errorf("error submitting query: %w", err))
173+
}
174+
fmt.Println("query id:", query.ID())
175+
176+
// Wait for completion and fetch results as an Apache Arrow reader
177+
reader, err := query.Results(context.Background())
178+
if err != nil {
179+
panic(fmt.Errorf("error fetching results: %w", err))
180+
}
181+
defer reader.Release()
182+
183+
for reader.Next() {
184+
fmt.Println(reader.RecordBatch())
185+
}
186+
```
187+
188+
Parameterized async queries bind positional parameters (`$1`, `$2`, ...):
189+
190+
```go
191+
query, err := spice.QueryWithParams(
192+
context.Background(),
193+
"SELECT * FROM taxi_trips WHERE trip_distance > $1 LIMIT $2",
194+
5.0,
195+
100,
196+
)
197+
```
198+
199+
The `*AsyncQuery` handle provides:
200+
201+
- `ID()` - the server-assigned query ID
202+
- `Status(ctx)` - poll the current status once (`PENDING`, `RUNNING`, `SUCCEEDED`, `FAILED`, `CANCELLED`, `CLOSED`)
203+
- `Wait(ctx)` - block until the query reaches a terminal status
204+
- `Results(ctx)` - wait for completion and return results as an `array.RecordReader`
205+
- `Cancel(ctx)` - request cancellation
206+
207+
For synchronous, real-time streaming queries, use `Sql` / `SqlWithParams` instead.
208+
164209
## Health Checks
165210

166-
gospice v8 provides health check methods to verify Spice instance status before executing queries:
211+
gospice v9 provides health check methods to verify Spice instance status before executing queries:
167212

168213
```go
169214
// Check if Spice instance is healthy (unauthenticated)
@@ -202,32 +247,32 @@ spice.SetMaxRetries(5) // Setting to 0 will disable retries
202247
Retries are performed for connection and system internal errors. It is the SDK user's responsibility to properly
203248
handle other errors, for example RESOURCE_EXHAUSTED (HTTP 429).
204249

205-
## Upgrading from v7 to v8
250+
## Upgrading from v8 to v9
206251

207-
gospice v8 is fully backward compatible with v7. To upgrade:
252+
gospice v9 is a new major version with breaking changes. To upgrade:
208253

209254
```bash
210-
go get github.com/spiceai/gospice/v8@latest
255+
go get github.com/spiceai/gospice/v9@latest
211256
go mod tidy
212257
```
213258

214259
Update your imports:
215260

216261
```go
217262
// Before
218-
import "github.com/spiceai/gospice/v7"
263+
import "github.com/spiceai/gospice/v8"
219264

220265
// After
221-
import "github.com/spiceai/gospice/v8"
266+
import "github.com/spiceai/gospice/v9"
222267
```
223268

224-
**What's new in v8:**
269+
**Breaking changes in v9:**
225270

226-
- New `Sql()` and `SqlWithParams()` methods for cleaner API (`.Query()` methods still work for backward compatibility)
227-
- `IsSpiceHealthy()` and `IsSpiceReady()` health check methods
228-
- Apache Arrow v18 and Go 1.24 support
271+
- `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](#async-queries)), or switch to the synchronous `Sql()` / `SqlWithParams()` methods.
272+
- Minimum Go version is now **1.25** (was 1.24).
273+
- Upgraded to Apache Arrow v18.6.0 and ADBC v1.11.0, matching the Spice.ai runtime's DataFusion 54.
229274

230-
See [UPGRADE_V7_TO_V8.md](UPGRADE_V7_TO_V8.md) for detailed migration guide.
275+
See [UPGRADE_V8_TO_V9.md](UPGRADE_V8_TO_V9.md) for the detailed migration guide.
231276

232277
## Testing and Benchmarking
233278

0 commit comments

Comments
 (0)