2026-01-22 13:04:52 +02:00

102 lines
2.4 KiB
Go

package rqlite
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
"go.uber.org/zap"
)
// RQLiteClient is a simple HTTP client for RQLite
type RQLiteClient struct {
baseURL string
httpClient *http.Client
logger *zap.Logger
}
// QueryResponse represents the RQLite query response
type QueryResponse struct {
Results []QueryResult `json:"results"`
}
// QueryResult represents a single query result
type QueryResult struct {
Columns []string `json:"columns"`
Types []string `json:"types"`
Values [][]interface{} `json:"values"`
Error string `json:"error"`
}
// NewRQLiteClient creates a new RQLite HTTP client
func NewRQLiteClient(dsn string, logger *zap.Logger) (*RQLiteClient, error) {
return &RQLiteClient{
baseURL: dsn,
httpClient: &http.Client{
Timeout: 10 * time.Second,
Transport: &http.Transport{
MaxIdleConns: 10,
MaxIdleConnsPerHost: 10,
IdleConnTimeout: 90 * time.Second,
},
},
logger: logger,
}, nil
}
// Query executes a SQL query and returns the results
func (c *RQLiteClient) Query(ctx context.Context, query string, args ...interface{}) ([][]interface{}, error) {
// Build parameterized query
queries := [][]interface{}{append([]interface{}{query}, args...)}
reqBody, err := json.Marshal(queries)
if err != nil {
return nil, fmt.Errorf("failed to marshal query: %w", err)
}
url := c.baseURL + "/db/query"
req, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewReader(reqBody))
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}
req.Header.Set("Content-Type", "application/json")
resp, err := c.httpClient.Do(req)
if err != nil {
return nil, fmt.Errorf("request failed: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
return nil, fmt.Errorf("query failed with status %d: %s", resp.StatusCode, string(body))
}
var queryResp QueryResponse
if err := json.NewDecoder(resp.Body).Decode(&queryResp); err != nil {
return nil, fmt.Errorf("failed to decode response: %w", err)
}
if len(queryResp.Results) == 0 {
return [][]interface{}{}, nil
}
result := queryResp.Results[0]
if result.Error != "" {
return nil, fmt.Errorf("query error: %s", result.Error)
}
return result.Values, nil
}
// Close closes the HTTP client
func (c *RQLiteClient) Close() error {
c.httpClient.CloseIdleConnections()
return nil
}