mdcms/sample-sites/neuraldb-docs/pages/sdk-go.md
2026-05-18 14:30:49 +07:00

286 lines
6.4 KiB
Markdown

---
title: Go SDK
sort: 120
section-id: client-sdks
keywords: Go, Golang, SDK, client, connection pool, query builder, pgx
description: The NeuralDB Go SDK — installation, connection pooling, and vector query builder
language: en
---
# Go SDK
The NeuralDB Go SDK provides idiomatic Go bindings built on top of `pgx`, the high-performance PostgreSQL driver for Go.
## Installation
```bash
go get github.com/neuraldb/neuraldb-go
```
Requires Go 1.21+.
## Connecting
### Single Connection
```go
package main
import (
"context"
"fmt"
"log"
"github.com/neuraldb/neuraldb-go"
)
func main() {
ctx := context.Background()
client, err := neuraldb.Connect(ctx, "postgresql://neuraldb:password@localhost:5432/mydb")
if err != nil {
log.Fatal("connection failed:", err)
}
defer client.Close(ctx)
var count int64
err = client.QueryRow(ctx, "SELECT COUNT(*) FROM documents").Scan(&count)
if err != nil {
log.Fatal(err)
}
fmt.Println("Documents:", count)
}
```
### Connection Pool (Recommended)
```go
import (
"github.com/neuraldb/neuraldb-go"
"github.com/jackc/pgx/v5/pgxpool"
)
func NewPool(ctx context.Context) (*neuraldb.Pool, error) {
config, err := pgxpool.ParseConfig(os.Getenv("NEURALDB_URL"))
if err != nil {
return nil, err
}
config.MaxConns = 20
config.MinConns = 5
config.MaxConnIdleTime = 30 * time.Minute
config.MaxConnLifetime = time.Hour
return neuraldb.NewPool(ctx, config)
}
```
## Working with Vectors
### Defining Vector Types
```go
package main
import "github.com/neuraldb/neuraldb-go/types"
// Create a vector from a float32 slice
v := types.NewVector([]float32{0.023, -0.187, 0.412})
// Create from float64 (auto-converted)
v2 := types.NewVectorFromFloat64([]float64{0.023, -0.187, 0.412})
// Access the underlying data
floats := v.Slice() // []float32
dims := v.Dims() // int
```
### Inserting a Document with a Vector
```go
type Document struct {
ID string
Content string
Embedding types.Vector
}
func InsertDocument(ctx context.Context, pool *neuraldb.Pool, doc Document) error {
_, err := pool.Exec(ctx,
`INSERT INTO documents (id, content, embedding) VALUES ($1, $2, $3)`,
doc.ID, doc.Content, doc.Embedding,
)
return err
}
```
### Vector Similarity Search
```go
func SemanticSearch(ctx context.Context, pool *neuraldb.Pool, queryEmbedding []float32, limit int) ([]SearchResult, error) {
qv := types.NewVector(queryEmbedding)
rows, err := pool.Query(ctx, `
SELECT id, content, 1 - (embedding <=> $1) AS similarity
FROM documents
WHERE embedding IS NOT NULL
ORDER BY embedding <=> $1
LIMIT $2
`, qv, limit)
if err != nil {
return nil, fmt.Errorf("query failed: %w", err)
}
defer rows.Close()
var results []SearchResult
for rows.Next() {
var r SearchResult
err := rows.Scan(&r.ID, &r.Content, &r.Similarity)
if err != nil {
return nil, err
}
results = append(results, r)
}
return results, rows.Err()
}
```
## Query Builder
The SDK includes an optional query builder for type-safe query construction:
```go
import "github.com/neuraldb/neuraldb-go/qb"
// Build a hybrid query
query, args := qb.New().
Select("id", "name", "price").
Expr("1 - (embedding <=> $?) AS similarity", queryVector).
From("products").
Where(qb.Eq("category", "electronics")).
Where(qb.GTE("price", 50)).
Where(qb.LTE("price", 500)).
Where(qb.GT("stock", 0)).
OrderByExpr("embedding <=> $?", queryVector).
Limit(20).
Build()
rows, err := pool.Query(ctx, query, args...)
```
## Batch Operations
```go
import "github.com/jackc/pgx/v5"
func BatchInsert(ctx context.Context, pool *neuraldb.Pool, docs []Document) error {
batch := &pgx.Batch{}
for _, doc := range docs {
batch.Queue(
`INSERT INTO documents (content, embedding) VALUES ($1, $2)`,
doc.Content, doc.Embedding,
)
}
results := pool.SendBatch(ctx, batch)
defer results.Close()
for range docs {
_, err := results.Exec()
if err != nil {
return fmt.Errorf("batch insert error: %w", err)
}
}
return results.Close()
}
```
## Transactions
```go
func TransactionalInsert(ctx context.Context, pool *neuraldb.Pool, docs []Document) error {
return pool.BeginTxFunc(ctx, pgx.TxOptions{
IsoLevel: pgx.ReadCommitted,
}, func(tx pgx.Tx) error {
for _, doc := range docs {
_, err := tx.Exec(ctx,
`INSERT INTO documents (content, embedding) VALUES ($1, $2)`,
doc.Content, doc.Embedding,
)
if err != nil {
return err // auto-rolled back by BeginTxFunc
}
}
_, err := tx.Exec(ctx,
`UPDATE stats SET doc_count = doc_count + $1`,
len(docs),
)
return err
})
}
```
## Scanning Results into Structs
```go
import "github.com/jackc/pgx/v5/pgxscan"
type Product struct {
ID string `db:"id"`
Name string `db:"name"`
Price float64 `db:"price"`
Similarity float64 `db:"similarity"`
}
func SearchProducts(ctx context.Context, pool *neuraldb.Pool, qv types.Vector) ([]Product, error) {
var products []Product
err := pgxscan.Select(ctx, pool, &products, `
SELECT id, name, price, 1 - (embedding <=> $1) AS similarity
FROM products
WHERE available = true
ORDER BY embedding <=> $1
LIMIT 10
`, qv)
return products, err
}
```
## Context and Cancellation
All SDK methods accept a `context.Context`. Use it for timeout and cancellation:
```go
// Set a 5-second query deadline
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
rows, err := pool.Query(ctx, "SELECT ...", args...)
```
## Error Handling
```go
import (
"github.com/jackc/pgx/v5/pgconn"
"errors"
)
_, err := pool.Exec(ctx, "INSERT INTO ...", args...)
if err != nil {
var pgErr *pgconn.PgError
if errors.As(err, &pgErr) {
switch pgErr.Code {
case "23505": // unique_violation
return ErrDuplicate
case "23503": // foreign_key_violation
return ErrForeignKey
default:
return fmt.Errorf("database error %s: %s", pgErr.Code, pgErr.Message)
}
}
return err
}
```