Help us shape the future of Go! Take the 2026 Go Developer Survey

scopedb

package module
v0.7.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 23, 2026 License: Apache-2.0 Imports: 21 Imported by: 0

README

ScopeDB SDK for Go

Version Docs CI License

The official Go client for ScopeDB. Run ScopeQL queries, browse the catalog, and write rows with bounded asynchronous streams. For application writes, start with Table.AppendStream.

Upgrading from v0.6? Follow the v0.7 migration guide.

Runtime support

Requires Go 1.26 or later. Use the SDK in a trusted server-side process and keep API keys out of source control.

Installation

From your application module:

go get github.com/scopedb/goscopedb@latest

Quickstart

Set SCOPEDB_ENDPOINT and SCOPEDB_API_KEY using the connection guide. Save this program as main.go and run go run .:

package main

import (
	"context"
	"fmt"
	"log"
	"os"

	scopedb "github.com/scopedb/goscopedb"
)

func main() {
	if err := run(); err != nil {
		log.Fatal(err)
	}
}

func run() error {
	client, err := scopedb.NewClient(scopedb.Config{
		Endpoint: os.Getenv("SCOPEDB_ENDPOINT"),
		APIKey:   os.Getenv("SCOPEDB_API_KEY"),
	})
	if err != nil {
		return err
	}
	defer client.Close()

	result, err := client.Query(context.Background(), "SELECT 1 AS ready")
	if err != nil {
		return err
	}
	rows, err := result.ToObjects()
	if err != nil {
		return err
	}
	fmt.Println(rows)
	return nil
}

Documentation

The SDK executes ScopeQL but does not define the language. Start with the language documentation:

Client configuration

NewClient validates the endpoint and returns an error for invalid configuration. Set Config.HTTPClient when the application needs to own HTTP timeouts, proxies, TLS, or connection pooling. Client.Close closes idle connections only for the HTTP client created by the SDK; it never closes a caller-provided client. SDK-owned clients use Go's default redirect policy. To customize redirects, supply an http.Client with CheckRedirect through Config.HTTPClient.

Go's default redirect behavior changes POST requests to GET without a body for HTTP 301, 302, and 303; HTTP 307 and 308 preserve the method and body when the body can be recreated. Redirects happen within one SDK attempt; AppendRetryOptions does not control them and Stats().Retries does not count them.

Every table append or Catalog mutation HTTP request has a client timeout of 30 seconds by default. Config.WriteTimeout is a *time.Duration: nil uses the default, a pointer to zero disables the limit, and a pointer to a positive duration overrides it. Negative durations are invalid. NewClient copies the value, so changing the original variable does not change an existing client.

client, err := scopedb.NewClient(scopedb.Config{
    Endpoint:     "http://localhost:6543",
    WriteTimeout: new(2 * time.Minute), // Omit for 30 seconds; use new(time.Duration) to disable.
})

The write timeout starts after local encoding, compression, and request preparation and covers one HTTP attempt, including redirects and reading the complete response body. Caller context deadlines on direct appends and Catalog requests still apply, as do HTTP-client timeouts. Catalog dry runs use the same timeout but cannot commit, so they do not return WriteDetails or report an unknown commit.

Streams inherit the write timeout when AppendStreamOptions.AttemptTimeout is nil; a non-nil pointer overrides it, with zero disabling the per-attempt limit. The stream copies this value at construction. Its separate delivery/retry budget still applies. Admission, retry backoff, and an entire Flush/Shutdown barrier are outside the write timeout. Contexts passed to stream methods bound admission or waiting, without cancelling already accepted rows.

Client timeouts after an HTTP attempt begins preserve the existing *scopedb.Error kind and cause and add WriteDetails with Reason: scopedb.WriteErrorReasonTimeout and Outcome: scopedb.AppendStateUnknown; Error.Retryable is false. In-flight caller cancellation uses WriteErrorReasonCancelled; cancellation before sending preserves the original context error. These fields remain available on subsequent errors returned by the stream. A timeout does not roll back a write: reconcile a client-interrupted write before replaying it. A server HTTP 408 is still a server response; an explicitly rejected append follows the existing safe retry policy. Append streams do not retry unknown outcomes by default. AppendRetryOptions.RetryUnknown explicitly enables retries for other transient unknown outcomes; those retries may duplicate committed rows.

Statement and table append request bodies, including direct AppendNDJSON requests and AppendStream batches, use zstd compression by default. Set Config.Compression to CompressionGzip when gzip is required. Catalog requests use uncompressed JSON. Append limits are based on the uncompressed NDJSON body.

Query and results

Query submits a statement and waits for its result:

result, err := client.Query(ctx, "SELECT 1 AS ready")
if err != nil {
	return err
}

rows, err := result.ToObjects()
if err != nil {
	return err
}
fmt.Println(rows)

Use RawRows for unconverted wire values, ToValues for positional values, ToObjects for values keyed by column name, or First for an optional first row. Integers become int64/uint64 without passing through floating point; out-of-range values return an error with the row and column. Binary values become []byte, timestamps become time.Time, and intervals become time.Duration. Array, object, and any cells remain wire strings, preserving embedded numeric precision. Decode embedded JSON with json.Decoder.UseNumber when needed. Duplicate column names are rejected by keyed conversions; use positional values to retain them.

For a detached or long-running statement, keep its handle and choose between a local status snapshot, one remote status request, or waiting for the result:

handle, err := client.Statement("SELECT 1 AS ready").Submit(ctx)
if err != nil {
	return err
}

fmt.Println("statement ID:", handle.ID())
if cached := handle.Snapshot(); cached != nil {
	fmt.Println("cached status:", cached.Status) // No network request.
}

latest, err := handle.Refresh(ctx) // Fetches one remote snapshot while active.
if err != nil {
	return err
}
fmt.Println("latest status:", latest.Status)

result, err = handle.Wait(ctx) // Polls until the statement terminates.
if err != nil {
	return err
}

Snapshot() returns a complete local observation, or nil before the first response. Refresh(ctx) fetches one observation while active. Cancel(ctx) returns the same StatementSnapshot type: inspect Status, Progress, Error, and ResultSet together. Cancellation can race with completion, so a successful cancellation request may return a finished result or the original statement failure. Wait turns failed snapshots into errors and identifies confirmed server cancellation with errors.Is(err, scopedb.ErrStatementCancelled).

Handle methods are safe to call concurrently. Once a terminal response is cached, no further request is needed, and an older in-flight response cannot replace it. Each snapshot belongs to the caller; modifying it does not change the handle. Store handle.ID() and use client.StatementHandle(id) to resume in another process while the server retains the statement. There is no result cursor or response body to close.

A context deadline stops local requests or waiting; it does not cancel the server statement. Call Cancel with a fresh, bounded context when server cancellation is required. If submission loses its response, execution may still have started. Set Statement.ID before submission when the application needs a known ID for reconciliation. Statement.ID chooses the statement ID; otherwise ScopeDB generates one. StatementHandle.ID() returns the ID confirmed by ScopeDB. MaxElapsed limits server-side elapsed time, including queueing, and MaxEstimated limits the estimated execution duration. Both use time.Duration; zero omits the setting. The server defaults to one hour for elapsed time and no estimate limit. A context deadline limits local waiting independently:

statement := client.Statement("FROM events")
statementID := uuid.New()
statement.ID = &statementID // Optional.
statement.MaxElapsed = 30 * time.Second
statement.MaxEstimated = 10 * time.Second
handle, err := statement.Submit(ctx)
if err != nil {
	return err
}
fmt.Println("statement ID:", handle.ID())

When Wait or Execute returns a *scopedb.Error with kind ErrorKindStatementFailed, Message and Code expose the server's failure reason. StatementDetails also preserves the code-specific JSON details. HTTP errors expose their server code through the same Code field:

var scopeErr *scopedb.Error
if errors.As(err, &scopeErr) && scopeErr.StatementDetails != nil {
	fmt.Println("statement error code:", scopeErr.StatementDetails.Code)
	fmt.Println("statement error:", scopeErr.StatementDetails.Message)
	fmt.Println("details:", string(scopeErr.StatementDetails.Details))
}

Initialize a table

At application startup, apply the complete expected definition and start writing after it succeeds. Table defaults to database scopedb and schema public; set its Database and Schema fields to use another location. The parent database and schema must exist.

table := client.Table("events")
definition := &scopedb.CatalogTable{
    Name: table.Name,
    Columns: []scopedb.CatalogColumn{
        {Name: "id", DataType: scopedb.IntDataType},
        {Name: "message", DataType: scopedb.StringDataType},
    },
}
if _, err := table.Catalog().Apply(ctx, definition); err != nil {
    return err
}

_, err := table.AppendNDJSON(ctx, []byte("{\"id\":1,\"message\":\"service started\"}\n"))
if err != nil {
    return err
}

The default call applies immediately and rejects changes that may lose data. Applying the same definition again preserves existing rows. This is complete replacement: omitted fields and objects are cleared. If an older application version omits a physical column added by a newer version, its startup apply fails rather than deleting that column. Use table.Catalog().Get(ctx) to read the current definition and its ETag. Use table.Catalog().Delete(ctx, options) for conditional deletion with explicit destructive-change authorization.

Pass one CatalogOptions value when you need a dry run, an ETag precondition, or explicit authorization for destructive changes. The same optional options are accepted by Catalog Apply and Delete.

Manage the catalog

The declarative Catalog API reads complete definitions and replaces resources atomically. It requires a server with the declarative protocol; the old paginated catalog API is not supported.

catalog := client.Catalog().Table("scopedb", "public", "events")
snapshot, err := catalog.Get(ctx)
if err != nil {
    return err
}
definition := snapshot.Definition
retention := int32(30)
definition.RetentionDays = &retention
plan, err := catalog.Apply(ctx, definition, scopedb.CatalogOptions{DryRun: true, IfMatch: snapshot.ETag})
if err != nil {
    return err
}
// Review plan.Before, plan.After, and plan.Destructive before authorizing this write.
result, err := catalog.Apply(ctx, definition, scopedb.CatalogOptions{
    IfMatch: plan.ETag,
    AllowDestructive: plan.Destructive,
})
if err != nil {
    return err
}
fmt.Println(result.ETag)

client.Catalog() selects the entire tenant. Use Database(name), Schema(database, schema), Table(database, schema, table), or View(database, schema, view) to select an individual resource. Pass names directly; the SDK escapes each name for the HTTP path. Each resource includes its complete subtree.

Get returns a CatalogSnapshot[T] with a typed definition and an ETag. Pass that ETag to the first dry run or write after editing; otherwise a change between Get and preview can be overwritten. Apply accepts the same definition type and returns CatalogResult[T] with typed Before and After values. These definitions are pointers: Before is nil when creating a resource, and After is nil when deleting it.

Omitted fields and objects are cleared, and omitted collections are empty. Delete removes one database, schema, table, or view using the same options; clear the tenant by applying &scopedb.CatalogDocument{}, or clear children by editing their parent definition. IfMatch is optional, while potentially irreversible data loss requires AllowDestructive. Dry runs validate and roll back without requiring that authorization. Storage is a creation-only input omitted from exports, so keep the original definition when planning creation.

Typed reads reject unknown fields, including nested fields, instead of silently discarding them before a later replacement. For export and apply workflows that must preserve fields unknown to this SDK, select Raw(). Definitions and before/after states are then json.RawMessage; absent states are JSON null:

catalog := client.Catalog().Raw()
snapshot, err := catalog.Get(ctx)
if err != nil {
    return err
}
// Retain snapshot.Definition as raw JSON when saving or editing it.
plan, err := catalog.Apply(ctx, snapshot.Definition, scopedb.CatalogOptions{DryRun: true, IfMatch: snapshot.ETag})
if err != nil {
    return err
}
fmt.Println(string(plan.After))

Raw() is also available on each resource selector. Typed and raw resources share the same HTTP behavior, options, and errors.

Errors use *scopedb.Error, including the server Code, HTTP status, and request ID. Catalog writes are never automatically retried. If Code is catalog_commit_outcome_unknown, read the catalog and plan again before retrying; a lost response does not imply a rollback.

Streaming writes

Use AppendStream to write Go structs or maps to an existing table. The SDK encodes and batches the rows for you.

Append rows

Create a stream with the default options, add rows with Send, and call Shutdown when you are done. Struct fields use standard Go JSON tags.

type Event struct {
	ID   int    `json:"id"`
	Name string `json:"name"`
}

stream, err := table.AppendStream(scopedb.AppendStreamOptions{})
if err != nil {
	return err
}

for _, event := range []Event{
	{ID: 1, Name: "first"},
	{ID: 2, Name: "second"},
} {
	if err := stream.Send(ctx, event); err != nil {
		_, _ = stream.Shutdown(ctx)
		return err
	}
}

report, err := stream.Shutdown(ctx)
if err != nil {
	return err
}
fmt.Println("written rows:", report.CommittedRows)

Send adds a row to the SDK's queue. Shutdown sends any remaining rows, waits for writes to finish, and closes the stream. Check the errors returned by both calls.

For a long-running stream, call Flush when you need to wait for the rows sent so far without closing the stream:

report, err := stream.Flush(ctx)
if err != nil {
	_, _ = stream.Shutdown(ctx)
	return err
}
fmt.Println("written rows:", report.CommittedRows)
Continue after write errors

For logs and telemetry, set FailurePolicy to AppendFailureContinue to keep processing later rows after a write fails:

telemetry, err := table.AppendStream(scopedb.AppendStreamOptions{
	FailurePolicy: scopedb.AppendFailureContinue,
})
if err != nil {
	return err
}

if err := telemetry.TrySend(map[string]any{
	"name":   "request.completed",
	"status": 200,
}); err != nil {
	log.Printf("could not queue telemetry row: %v", err)
}

report, err := telemetry.Shutdown(ctx)
if err != nil {
	return err
}
if report.Outcome != scopedb.AppendDeliveryOK {
	log.Printf("some telemetry rows were not confirmed written: %+v", report)
}

TrySend adds a row without waiting for queue space. Check the report returned by Flush or Shutdown: CommittedRows counts confirmed writes, FailedRows counts failed rows, UnknownRows counts writes without a confirmed result, and DroppedRows counts rows rejected by TrySend. Each report covers activity since the previous completed barrier, including barriers whose caller stopped waiting. Stats() holds lifetime totals. Calling Shutdown repeatedly returns its original final report, so do not add it to totals twice.

Delivery and resource lifetime

Streams retry temporary errors only when the server explicitly confirms rejection. The default allows eight retries with bounded backoff and a five-minute elapsed budget per dispatched batch. Missing responses and unknown outcomes stop delivery under the default stop policy. If the application accepts possible duplicates, opt into at-least-once replay:

stream, err := table.AppendStream(scopedb.AppendStreamOptions{
    Retry: &scopedb.AppendRetryOptions{MaxRetries: 8, RetryUnknown: true},
})

A later successful acknowledgement confirms the logical rows were written at least once, not how many copies exist. A later rejection cannot resolve an earlier unknown attempt. Retry: &scopedb.AppendRetryOptions{MaxRetries: 0} disables all SDK retries. Client timeouts and cancellations are never retried, even with RetryUnknown enabled. Direct AppendNDJSON always makes one SDK attempt.

The default stream targets 4 MiB batches, accepts at most 200,000 rows per batch, and sends up to four batches concurrently. Set MaxConcurrentBatches: 1 for serial requests. MaxBufferedBytes bounds accepted encoded rows, including in-flight batches; it excludes temporary encoding/compression buffers and rows held by blocked Send callers. Limit producer concurrency when bounding total process memory.

Always call Shutdown to close admission and settle accepted rows. Cancelling a Send context before admission leaves that row unaccepted. Cancelling a Flush or Shutdown wait does not abandon accepted rows or roll back writes; use a live context to wait again, and inspect Stats() for cumulative delivery. Client.Close only releases idle HTTP connections and does not shut down streams.

Append NDJSON directly

If you already have NDJSON, use AppendNDJSON. Put one JSON object on each line:

ndjson := []byte("{\"id\":1,\"name\":\"first\"}\n{\"id\":2,\"name\":\"second\"}")
result, err := table.AppendNDJSON(ctx, ndjson)
if err != nil {
	return err
}
fmt.Println("committed rows:", result.NumRowsInserted)

One request supports up to 8 MiB of uncompressed NDJSON and 200,000 rows. ScopeDB parses NDJSON integer tokens as signed 64-bit integers, including values for uint columns and nested objects. Values above 9223372036854775807 are rejected; strings are not coerced into numeric columns. This input limit is independent of query results, which can contain the full uint64 range.

Send uses standard encoding/json, without schema-aware conversions. []byte encodes as the base64 string expected by binary columns and time.Time as RFC 3339. Encode interval columns as fixed-duration ISO 8601 strings (for example, "PT1.5S"), not Go's integer-encoded time.Duration. An integer-valued Go float may encode without a decimal point; for floats beyond the signed integer range, supply an explicit floating-point JSON token with json.RawMessage, such as 1e20.

See the examples for streaming writes, file imports, telemetry, and NDJSON.

Migrate from v0.6 to v0.7

Upgrade to Go 1.26 or later before updating the SDK. The module and import paths remain github.com/scopedb/goscopedb. These changes are relative to the published v0.6.3 SDK.

Write timeouts

Direct AppendNDJSON requests now have a default 30-second timeout, including reading the response body. Configure Config.WriteTimeout to change or disable this limit. Catalog mutations and dry runs use the same setting; queries and Catalog reads are governed by the caller's context and HTTP client.

client, err := scopedb.NewClient(scopedb.Config{
    Endpoint:     os.Getenv("SCOPEDB_ENDPOINT"),
    APIKey:       os.Getenv("SCOPEDB_API_KEY"),
    WriteTimeout: new(time.Duration), // Disable the SDK's write attempt timeout.
})

AppendStreamOptions.AttemptTimeout changes from time.Duration to *time.Duration. Omit it to inherit the client setting, replace a positive AttemptTimeout: duration with AttemptTimeout: new(duration), or set new(time.Duration) to disable the attempt limit. An explicit AttemptTimeout: 0 in old source must become an omitted field or nil to preserve the default. Negative values are invalid.

Caller context deadlines and HTTP-client timeouts still apply. Append streams also have a five-minute default delivery/retry budget per dispatched batch; disabling the attempt timeout does not disable that budget. See client configuration for timeout scope and interruption diagnostics.

Statements and Catalog
v0.6 API v0.7 replacement
handle.LastStatus(), Progress(), ResultSet() handle.Snapshot() and its Status, Progress, ResultSet, and Error fields
handle.Status(ctx) handle.Refresh(ctx), returning a complete *StatementSnapshot
StatementCancelResult *StatementSnapshot from Cancel; ID replaces StatementID, and Error holds the original failure
status.Finished() status == scopedb.StatementStatusFinished; Terminated() still covers all terminal states
table.Describe(ctx) table.Catalog().Get(ctx), retaining both Definition and ETag
table.Drop(ctx) table.Catalog().Delete(ctx, scopedb.CatalogOptions{IfMatch: etag, AllowDestructive: true})
Append result/error/last-failure .AppendState .Status; append JSON uses status, matching the service
Historical u_int type spelling uint

Replace ExecTimeout strings such as "30s" with MaxElapsed: 30 * time.Second; MaxEstimated independently limits estimated execution time. Zero omits the setting: the server defaults to one hour for elapsed time and no estimate limit. Negative durations are invalid, and elapsed time includes queueing. Replace StatementErrorCode and its constants with native string codes from Error.Code or StatementErrorDetails.Code; unknown codes remain available. ErrStatementCancelled identifies server cancellation independently of a local context.Canceled.

Replace paginated Catalog list/fetch/iterator methods with client.Catalog().Get(ctx) or a database/schema/table/view selector followed by .Get(ctx). Use Distinct and RetentionDays in the complete table definition. Typed reads reject unsupported fields; Raw() retains them without numeric conversion. Catalog writes are not retried.

Append and IngestStream

Appends use /v1/catalog/databases/{db}/schemas/{schema}/tables/{table}/ingest. The commit outcome is status on success and details.status on failure. The AppendState enum values and stream delivery/report types remain. Missing or unreadable outcomes are unknown. As in v0.6.3, unknown outcomes are not retried by default; the new RetryUnknown option enables explicit replay when the application accepts possible duplicates.

Client.IngestStream, IngestStream, IngestStreamOptions, and IngestResult have been removed. Select the destination with client.Table(name) and use Table.AppendStream for Go values or Table.AppendNDJSON for an existing NDJSON payload.

Append accepts rows matching the destination columns, not a ScopeQL statement. Move field renaming, type conversion, filtering, and routing into the producer before calling Send. For transformations that must run in ScopeQL, append the original event into an object column in a staging table, then execute a separate FROM ... SELECT ... INSERT INTO ... statement. Staging and transformation are separate commits; track processed batches before retrying the transformation.

Review these behavior changes when migrating:

  • Append batches allow up to 8 MiB of uncompressed NDJSON and 200,000 rows. Reduce an old ingest batch-byte target above 8 MiB.
  • Flush and Shutdown return an AppendDeliveryReport for activity since the previous report. Read CommittedRows instead of IngestResult.NumRowsInserted, and check Outcome when using the continue policy.
  • Append streams send up to four batches concurrently by default. Set MaxConcurrentBatches: 1 when the producer needs sequential requests; queries still require ORDER BY for ordered results.
  • Append streams retry confirmed temporary rejections by default. RetryUnknown: true opts into retrying transient unknown outcomes, which can duplicate rows. Set MaxRetries: 0 to disable all SDK retries. Client timeouts and cancellations are never retried. Direct AppendNDJSON makes one SDK attempt; HTTP redirects follow the configured HTTP client's policy.

Structured errors

scopedb.Error exposes the server message, code, and structured details without requiring applications to parse the message. Catalog errors redact the configured API key from messages and codes:

var scopeErr *scopedb.Error
if errors.As(err, &scopeErr) {
	log.Printf("kind=%s status=%d request_id=%s retryable=%t retry_after=%s",
		scopeErr.Kind,
		scopeErr.HTTPStatus,
		scopeErr.RequestID,
		scopeErr.Retryable,
		scopeErr.RetryAfter,
	)
}

The main kinds are ErrorKindConfigInvalid, ErrorKindStatementFailed, ErrorKindCatalogFailed, ErrorKindAppendRowsFailed, and ErrorKindUnexpected. Use errors.Is and errors.As to inspect the underlying cause. Append streams preserve the last attempt's Code and Details in returned errors and Stats().LastFailure; the delivery outcome remains unknown if an earlier attempt may have committed.

Examples

The examples guide contains query and write examples with runnable commands.

Development

Development tasks are defined in mise.toml; license tasks expect hawkeye on PATH.

mise install
mise run check
mise run build
mise run test

Release history and the maintainer runbook are in CHANGELOG.md and RELEASE.md.

License

Licensed under the Apache License, Version 2.0.

Live protocol validation

From a source checkout, set SCOPEDB_ENDPOINT and SCOPEDB_API_KEY for a disposable test workspace, then run:

mise run test-integration

The suite creates uniquely named resources and checks dry-run, ETag conflicts, conditional deletion, committed and rejected appends, statement errors, elapsed timeout, and a cancellation racing with completion. It also checks signed integer boundaries, precise nested integers, the server's NDJSON unsigned-input limit, and full-range unsigned query results. Tests delete their resources before returning. Running cancellation is covered separately with controlled HTTP responses in the unit tests.

With SCOPEDB_API_KEY set, Cloud authentication checks verify that missing, malformed, and incorrect credentials return 401 for Catalog, queries, and writes. Rejected stream writes must count as failed rather than unknown, without retries or committed rows. Optional SCOPEDB_EXPIRED_API_KEY and SCOPEDB_REVOKED_API_KEY extend these checks to expired and revoked credentials.

To verify tenant isolation through the Cloud Proxy, also set SCOPEDB_WORKSPACE_ID, SCOPEDB_SECONDARY_WORKSPACE_ID, and SCOPEDB_SECONDARY_API_KEY for two distinct workspaces served by the same endpoint. The test creates same-named tables with different definitions and rows, checks that authentication overrides a forged tenant header, denies cross-tenant Statement reads and cancellation, and confirms that deleting one tenant's table leaves the other's intact. Use disposable credentials with create/drop access to scopedb.public; the tests neither create nor revoke credentials.

Documentation

Overview

Package scopedb provides the official Go client for ScopeDB. It supports ScopeQL statements, declarative catalog management, and streaming writes.

Create and close one Client for the application's connection pool:

client, err := scopedb.NewClient(scopedb.Config{
	Endpoint: os.Getenv("SCOPEDB_ENDPOINT"),
	APIKey:   os.Getenv("SCOPEDB_API_KEY"),
})
if err != nil {
	return err
}
defer client.Close()

Query waits for a statement result, which can be converted to keyed objects:

result, err := client.Query(ctx, "SELECT 1 AS ready")
if err != nil {
	return err
}
rows, err := result.ToObjects()
if err != nil {
	return err
}
fmt.Println(rows)

Use Statement.Submit when an application needs the statement ID, a local Snapshot, an explicit Refresh, or a separate Wait. Cancel returns the same complete StatementSnapshot as Refresh; all handle methods are safe to call concurrently. Omit ID to let ScopeDB generate it. MaxElapsed and MaxEstimated set server-side duration limits. Failed statements expose the server message and code on Error, with structured details on Error.StatementDetails. Client.Catalog reads and replaces the complete tenant catalog. Its Database, Schema, Table, and View selectors provide typed Get, Apply, and Delete operations. Raw retains JSON definitions including fields unknown to the SDK. Apply supports dry runs, ETag preconditions, and authorization for destructive changes. Table.Catalog selects the table definition for Get, Apply, Delete, or Raw. Typed reads reject unsupported fields to prevent lossy replacements. Potentially destructive changes are rejected without explicit authorization.

For application writes, Table.AppendStream is the recommended path: it accepts typed rows and adds bounded asynchronous batching that is safe for concurrent producers. Table.AppendStream and Table.AppendNDJSON use the client's configured compression, which defaults to zstd. Table.AppendNDJSON is the low-level path for one caller-owned NDJSON request.

AppendStream.Send uses encoding/json and accepts typed structs and other values that encode as a top-level JSON object. Send does not validate the destination table schema. ScopeDB validation failures surface when Flush or Shutdown settles: the stop policy returns the error, while continue mode reports failed rows in the delivery report and failure details in Stats().LastFailure.

Stream Send methods confirm local admission only. Flush and Shutdown wait for the accepted prefix. AppendStream reports rejected and unknown outcomes. Unknown outcomes are not retried unless RetryUnknown is explicitly enabled; those retries may duplicate rows. Client timeouts are never retried.

ScopeQL is documented separately in the quickstart, query guide, and language reference.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrAppendStreamFull means TrySend could not reserve bounded local capacity.
	ErrAppendStreamFull = errors.New("append stream buffer is full")
	// ErrAppendStreamClosed means the stream no longer accepts rows.
	ErrAppendStreamClosed = errors.New("append stream is closed")
	// ErrAppendRetryExhausted means the configured retry count or elapsed budget
	// ended. The wrapped append error still describes the last attempt.
	ErrAppendRetryExhausted = errors.New("append retry budget exhausted")
	// ErrAppendRowInvalid means a row did not encode to one JSON object.
	ErrAppendRowInvalid = errors.New("append row must encode to a JSON object")
	// ErrAppendRowTooLarge means one encoded row exceeds the append stream request limit.
	ErrAppendRowTooLarge = errors.New("append row exceeds the protocol limit")
)
View Source
var ErrStatementCancelled = errors.New("statement was cancelled")

ErrStatementCancelled means the server confirmed cancellation. It is distinct from context.Canceled, which only describes a local request or wait.

Functions

This section is empty.

Types

type AppendDeliveryOutcome

type AppendDeliveryOutcome uint8

AppendDeliveryOutcome summarizes one completed delivery barrier.

const (
	// AppendDeliveryOK means the interval settled without failed, unknown, or dropped rows.
	AppendDeliveryOK AppendDeliveryOutcome = iota
	// AppendDeliveryPartial means some rows committed and some did not settle cleanly.
	AppendDeliveryPartial
	// AppendDeliveryFailed means no rows committed and at least one row failed or dropped.
	AppendDeliveryFailed
	// AppendDeliveryUnknown means no rows committed and at least one row may have committed.
	AppendDeliveryUnknown
)

func (AppendDeliveryOutcome) String

func (o AppendDeliveryOutcome) String() string

type AppendDeliveryReport

type AppendDeliveryReport struct {
	// Outcome summarizes delivery for this barrier interval.
	Outcome AppendDeliveryOutcome
	// AcceptedRows is the number of rows locally admitted in the interval.
	AcceptedRows uint64
	// CommittedRows is the number of rows confirmed committed.
	CommittedRows uint64
	// FailedRows is the number of rejected or unsent accepted rows.
	FailedRows uint64
	// UnknownRows is the number of rows whose commit outcome is unknown.
	UnknownRows uint64
	// DroppedRows is the number of TrySend calls rejected locally in the interval.
	DroppedRows      uint64
	CommittedBatches uint64
	FailedBatches    uint64
	UnknownBatches   uint64
	Retries          uint64
	Duration         time.Duration
}

AppendDeliveryReport contains settlement counters since the previous barrier.

type AppendDroppedRows

type AppendDroppedRows struct {
	// BufferFull counts rows rejected because immediate local admission was unavailable.
	BufferFull uint64
	// InvalidRow counts values that did not encode to a JSON object.
	InvalidRow uint64
	// RowTooLarge counts values over the single-request protocol limit.
	RowTooLarge uint64
	// Closed counts attempts after shutdown or a terminal failure.
	Closed uint64
}

AppendDroppedRows contains lifetime TrySend failures by reason.

type AppendErrorDetails

type AppendErrorDetails struct {
	Status             AppendState      `json:"status"`
	RowErrors          []AppendRowError `json:"row_errors"`
	RowErrorsTruncated bool             `json:"row_errors_truncated"`
}

AppendErrorDetails contains the structured outcome of a failed append.

type AppendFailurePolicy

type AppendFailurePolicy uint8

AppendFailurePolicy controls what a stream does after a remote batch fails.

const (
	// AppendFailureStop stops admission after the first failed batch.
	AppendFailureStop AppendFailurePolicy = iota
	// AppendFailureContinue accounts for the failed batch and processes later rows.
	AppendFailureContinue
)

func (AppendFailurePolicy) String

func (p AppendFailurePolicy) String() string

type AppendLastFailure

type AppendLastFailure struct {
	// At is when the client observed the failure.
	At time.Time
	// Message is the original error message.
	Message string
	// Code and Details preserve the last attempt's structured server error.
	Code    string
	Details json.RawMessage
	// Status is the aggregate rejected or unknown outcome across all attempts.
	Status AppendState
	// HTTPStatus is zero when no HTTP response was available.
	HTTPStatus int
	// RequestID is the request identifier reported by the service, when present.
	RequestID string
	// RetryAfter is the service-provided retry delay, when present.
	RetryAfter time.Duration
	// Retryable reports the underlying error's conservative retry classification;
	// it is false for unknown outcomes. RetryUnknown may opt into replaying such
	// outcomes, so this field is not the stream's retry decision.
	Retryable bool
	// WriteDetails identifies a client timeout or cancellation, when present.
	WriteDetails *WriteErrorDetails
	// RowErrors contains structured validation failures reported for the batch.
	RowErrors []AppendRowError
	// RowErrorsTruncated reports whether the service omitted additional row errors.
	RowErrorsTruncated bool
}

AppendLastFailure describes the last remotely failed batch.

type AppendRetryOptions added in v0.7.0

type AppendRetryOptions struct {
	MaxRetries int
	// RetryUnknown opts into retries after a transient failure that may have
	// committed. This can insert duplicate rows. It defaults to false and never
	// overrides the prohibition on retrying client timeouts or cancellations.
	RetryUnknown bool
	// Zero durations use defaults: 100 ms initial, 5 s maximum backoff, 5 min
	// elapsed budget per dispatched batch (including HTTP attempts).
	InitialBackoff time.Duration
	MaxBackoff     time.Duration
	MaxElapsedTime time.Duration
}

AppendRetryOptions configures retries of an exact encoded batch for temporary rejections. A nil Retry uses the defaults; a non-nil option with MaxRetries=0 disables retries. Client timeouts and cancellations are never retried.

type AppendRowError

type AppendRowError struct {
	RowIndex uint64 `json:"row_index"`
	Column   string `json:"column"`
	Message  string `json:"message"`
}

AppendRowError describes a validation error for one row in an append request.

type AppendRowsResult

type AppendRowsResult struct {
	Status          AppendState `json:"status"`
	NumRowsInserted int64       `json:"num_rows_inserted"`
}

AppendRowsResult is the result of a committed table append.

type AppendState

type AppendState string

AppendState describes a write's commit outcome. Table append responses and client-side interruption details use these values.

const (
	// AppendStateCommitted means all reported rows committed.
	AppendStateCommitted AppendState = "committed"
	// AppendStateRejected means no rows committed and the request is safe to correct and retry.
	AppendStateRejected AppendState = "rejected"
	// AppendStateUnknown means the client cannot determine whether rows committed.
	AppendStateUnknown AppendState = "unknown"
)

type AppendStream

type AppendStream struct {
	// contains filtered or unexported fields
}

AppendStream asynchronously batches rows into bounded NDJSON append requests. Send and TrySend are safe to call from concurrent producer goroutines.

func (*AppendStream) Flush

Flush dispatches all rows admitted before this barrier and waits for settlement. Canceling ctx stops only this wait; an already enqueued barrier keeps running. If ctx ends first, Flush returns a zero report and ctx.Err().

func (*AppendStream) Send

func (s *AppendStream) Send(ctx context.Context, row any) error

Send serializes row with encoding/json and admits it, waiting for bounded local capacity. Row may be a typed struct or any other value that encodes as one top-level JSON object. Success does not validate the destination table schema or confirm a remote commit.

func (*AppendStream) Shutdown

Shutdown permanently closes admission and settles every admitted row. It is idempotent; canceling ctx stops only the caller's wait. If ctx ends first, Shutdown returns a zero report and ctx.Err().

func (*AppendStream) Stats

func (s *AppendStream) Stats() AppendStreamStats

Stats returns a race-safe lifetime snapshot.

func (*AppendStream) TrySend

func (s *AppendStream) TrySend(row any) error

TrySend serializes row with encoding/json and attempts local admission without waiting for capacity. Row must encode as one top-level JSON object. Success does not validate the destination table schema or confirm a remote commit.

type AppendStreamOptions

type AppendStreamOptions struct {
	// FailurePolicy defaults to AppendFailureStop.
	FailurePolicy AppendFailurePolicy
	Retry         *AppendRetryOptions
	// TargetBatchBytes defaults to 4 MiB and cannot exceed the request limit.
	TargetBatchBytes int
	// MaxBatchRows defaults to 200,000 and cannot exceed the request limit.
	MaxBatchRows int
	// FlushInterval defaults to one second.
	FlushInterval time.Duration
	// MaxBufferedBytes bounds encoded pending rows. It defaults to 64 MiB.
	MaxBufferedBytes int
	// MaxConcurrentBatches defaults to four, cannot exceed 1024, and may be set
	// to one for serial request submission.
	MaxConcurrentBatches int
	// AttemptTimeout bounds each HTTP attempt. Nil inherits Config.WriteTimeout.
	// A pointer to zero disables this limit, but the delivery/retry budget still applies.
	// Negative values are invalid. The value is copied when the stream is created.
	// A timeout leaves that batch's commit outcome unknown.
	AttemptTimeout *time.Duration
}

AppendStreamOptions configures bounded asynchronous table appends. Zero-valued fields use SDK defaults.

type AppendStreamState

type AppendStreamState uint8

AppendStreamState is the lifecycle state of an AppendStream.

const (
	// AppendStreamOpen means the stream accepts rows.
	AppendStreamOpen AppendStreamState = iota
	// AppendStreamClosing means shutdown has closed admission and is settling rows.
	AppendStreamClosing
	// AppendStreamClosed means shutdown settled all accepted rows without a fatal error.
	AppendStreamClosed
	// AppendStreamFailed means strict delivery stopped after a batch failure.
	AppendStreamFailed
)

func (AppendStreamState) String

func (s AppendStreamState) String() string

type AppendStreamStats

type AppendStreamStats struct {
	// State is the current stream lifecycle state.
	State           AppendStreamState
	AcceptedRows    uint64
	CommittedRows   uint64
	FailedRows      uint64
	UnknownRows     uint64
	DroppedRows     uint64
	DroppedByReason AppendDroppedRows
	Retries         uint64
	PendingRows     uint64
	PendingBytes    int
	InFlightBatches int
	// LastFailure is nil until a remote batch fails.
	LastFailure *AppendLastFailure
	// LastReport is nil until a delivery barrier completes.
	LastReport *AppendDeliveryReport
}

AppendStreamStats is a race-safe lifetime snapshot.

type Catalog added in v0.7.0

type Catalog struct {
	// contains filtered or unexported fields
}

Catalog manages the complete user catalog of a tenant and selects individual resources.

func (*Catalog) Apply added in v0.7.0

func (c *Catalog) Apply(ctx context.Context, definition *CatalogDocument, options ...CatalogOptions) (CatalogResult[*CatalogDocument], error)

Apply replaces the complete tenant catalog. An empty document clears the tenant. Options may be omitted; by default, changes apply without an ETag precondition and potentially destructive changes are rejected.

func (*Catalog) Database added in v0.7.0

func (c *Catalog) Database(database string) *CatalogResource[*CatalogDatabase]

Database selects a database and its complete subtree.

func (*Catalog) Get added in v0.7.0

Get returns the complete tenant definition and its opaque version.

func (*Catalog) Raw added in v0.7.0

Raw selects the tenant catalog as JSON, preserving fields unknown to this SDK.

func (*Catalog) Schema added in v0.7.0

func (c *Catalog) Schema(database, schema string) *CatalogResource[*CatalogSchema]

Schema selects a schema and its tables and views.

func (*Catalog) Table added in v0.7.0

func (c *Catalog) Table(database, schema, table string) *CatalogResource[*CatalogTable]

Table selects a complete table definition.

func (*Catalog) View added in v0.7.0

func (c *Catalog) View(database, schema, view string) *CatalogResource[*CatalogView]

View selects a view definition.

type CatalogColumn added in v0.7.0

type CatalogColumn struct {
	Name       string               `json:"name"`
	DataType   DataType             `json:"data_type"`
	Expression *string              `json:"expression,omitempty"`
	Comment    *string              `json:"comment,omitempty"`
	Indexes    []CatalogColumnIndex `json:"indexes,omitempty"`
}

CatalogColumn defines a stored or computed column and its additional indexes.

type CatalogColumnIndex added in v0.7.0

type CatalogColumnIndex struct {
	Type     string `json:"type"`
	Analyzer string `json:"analyzer,omitempty"`
}

CatalogColumnIndex defines an additional column index. Only Type "search" is supported. Analyzer defaults to "log".

type CatalogDatabase added in v0.7.0

type CatalogDatabase struct {
	Name    string          `json:"name"`
	Comment *string         `json:"comment,omitempty"`
	Schemas []CatalogSchema `json:"schemas,omitempty"`
}

CatalogDatabase defines a database and its schemas.

type CatalogDistinct added in v0.7.0

type CatalogDistinct struct {
	On []string `json:"on,omitempty"`
	By []string `json:"by,omitempty"`
}

CatalogDistinct defines a table's distinct keys and ordering expressions.

type CatalogDocument added in v0.7.0

type CatalogDocument struct {
	Databases []CatalogDatabase `json:"databases,omitempty"`
}

CatalogDocument defines the complete user catalog of a tenant.

type CatalogOptions added in v0.7.0

type CatalogOptions struct {
	DryRun           bool
	AllowDestructive bool
	// IfMatch is optional. Use the ETag from Get or a dry-run result to reject concurrent changes.
	IfMatch string
}

CatalogOptions controls preview, concurrent updates, and data-loss authorization. Apply and Delete accept zero or one options value.

type CatalogResource added in v0.7.0

type CatalogResource[T any] struct {
	// contains filtered or unexported fields
}

CatalogResource manages a selected catalog definition. Obtain one through the Catalog resource selectors; T is a definition pointer, or json.RawMessage for Raw.

func (*CatalogResource[T]) Apply added in v0.7.0

func (c *CatalogResource[T]) Apply(ctx context.Context, definition T, options ...CatalogOptions) (CatalogResult[T], error)

Apply replaces the resource with definition. Omitted fields and objects are cleared. With no options, changes apply without an ETag precondition and potentially destructive changes are rejected. DryRun validates and rolls back. Catalog writes are never automatically retried.

func (*CatalogResource[T]) Delete added in v0.7.0

func (c *CatalogResource[T]) Delete(ctx context.Context, options ...CatalogOptions) (CatalogResult[T], error)

Delete removes a single database, schema, table, or view. With no options, potentially destructive changes are rejected.

func (*CatalogResource[T]) Get added in v0.7.0

func (c *CatalogResource[T]) Get(ctx context.Context) (CatalogSnapshot[T], error)

Get returns a complete definition, without pagination. Typed definitions reject unknown fields to prevent lossy read-modify-write cycles; use Raw to retain them.

func (*CatalogResource[T]) Raw added in v0.7.0

Raw selects the same resource as JSON, preserving fields unknown to this SDK.

type CatalogResult added in v0.7.0

type CatalogResult[T any] struct {
	Before      T    `json:"before"`
	After       T    `json:"after"`
	Destructive bool `json:"destructive"`
	// ETag comes from the response header; it is the base version for a dry run.
	ETag string `json:"-"`
}

CatalogResult contains the normalized states compared in one server transaction. Typed definitions are nil when absent; Raw resources represent absence as JSON null.

type CatalogSchema added in v0.7.0

type CatalogSchema struct {
	Name    string         `json:"name"`
	Comment *string        `json:"comment,omitempty"`
	Tables  []CatalogTable `json:"tables,omitempty"`
	Views   []CatalogView  `json:"views,omitempty"`
}

CatalogSchema defines a schema, including its tables and views.

type CatalogSnapshot added in v0.7.0

type CatalogSnapshot[T any] struct {
	Definition T
	ETag       string
}

CatalogSnapshot contains a complete resource definition and its opaque version.

type CatalogTable added in v0.7.0

type CatalogTable struct {
	Name          string          `json:"name"`
	Comment       *string         `json:"comment,omitempty"`
	Columns       []CatalogColumn `json:"columns,omitempty"`
	PartitionBy   []string        `json:"partition_by,omitempty"`
	ClusterBy     []string        `json:"cluster_by,omitempty"`
	Distinct      CatalogDistinct `json:"distinct"`
	RetentionDays *int32          `json:"retention_days,omitempty"`
	Storage       json.RawMessage `json:"storage,omitempty"`
}

CatalogTable defines a table. Omitted collections are empty; omitted optional fields are cleared. Storage is accepted at creation and omitted from exports.

type CatalogView added in v0.7.0

type CatalogView struct {
	Name      string  `json:"name"`
	Statement string  `json:"statement"`
	Comment   *string `json:"comment,omitempty"`
}

CatalogView defines a view.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client provides access to ScopeDB APIs.

func NewClient

func NewClient(config Config) (*Client, error)

NewClient creates a new ScopeDB client with the given configuration.

func (*Client) Catalog added in v0.7.0

func (c *Client) Catalog() *Catalog

Catalog selects the complete tenant catalog. Names passed to its resource selectors are unescaped database, schema, table, or view names.

func (*Client) Close

func (c *Client) Close()

Close releases idle connections owned by the client. It does not close a caller-provided HTTP client.

func (*Client) Query

func (c *Client) Query(ctx context.Context, scopeql string) (*ResultSet, error)

Query executes a ScopeQL statement and waits for all result rows.

func (*Client) Statement

func (c *Client) Statement(stmt string) *Statement

Statement creates a new statement with the given ScopeQL statement.

func (*Client) StatementHandle

func (c *Client) StatementHandle(id uuid.UUID) *StatementHandle

StatementHandle creates a new StatementHandle with the given ID.

func (*Client) Table

func (c *Client) Table(tableName string) *Table

Table creates a new Table object with the given name.

type Compression

type Compression string

Compression defines the compression used for request bodies.

const (
	// CompressionZstd uses Zstandard compression.
	CompressionZstd Compression = "zstd"
	// CompressionGzip uses gzip compression.
	CompressionGzip Compression = "gzip"
)

type Config

type Config struct {
	// Endpoint is the URL of the ScopeDB service.
	Endpoint string `json:"endpoint"`
	// APIKey is the API key used for authentication.
	//
	// When provided, the client sends it as the Authorization header using the
	// Bearer scheme.
	APIKey string `json:"api_key"`
	// Compression controls how request bodies are compressed, including direct
	// table appends and AppendStream batches.
	//
	// The default is CompressionZstd. CompressionGzip is also supported.
	Compression Compression `json:"compression"`
	// WriteTimeout bounds each table append or catalog mutation request,
	// including reading its response body. Nil uses the default of 30 seconds;
	// a pointer to zero disables this limit. Negative values are invalid.
	// NewClient copies the value.
	// Caller context deadlines and HTTPClient timeouts still apply.
	// The budget starts after local encoding, compression, and request preparation.
	// Non-nil stream AttemptTimeout settings override this limit. A timeout leaves
	// the commit outcome unknown; it does not roll back the write.
	WriteTimeout *time.Duration `json:"write_timeout"`
	// HTTPClient is the HTTP client used to send requests.
	//
	// When nil, the SDK creates and owns an independent HTTP client using Go's
	// default redirect policy. A supplied client retains its redirect policy,
	// remains owned by the caller, and is never closed by the SDK.
	HTTPClient *http.Client `json:"-"`
}

Config defines the configuration for the client.

type DataType

type DataType string

DataType is the type of field.

const (
	// StringDataType indicates the data is of string data type.
	StringDataType DataType = "string"
	// BinaryDataType indicates the data is of binary data type.
	BinaryDataType DataType = "binary"
	// IntDataType indicates the data is of int data type.
	IntDataType DataType = "int"
	// UIntDataType indicates the data is of uint data type.
	UIntDataType DataType = "uint"
	// FloatDataType indicates the data is of float data type.
	FloatDataType DataType = "float"
	// BooleanDataType indicates the data is of bool data type.
	BooleanDataType DataType = "boolean"
	// TimestampDataType indicates the data is of timestamp data type.
	TimestampDataType DataType = "timestamp"
	// IntervalDataType indicates the data is of interval data type.
	IntervalDataType DataType = "interval"
	// ArrayDataType indicates the data is of array data type.
	ArrayDataType DataType = "array"
	// ObjectDataType indicates the data is of object data type.
	ObjectDataType DataType = "object"
	// AnyDataType indicates the data is of any data type.
	AnyDataType DataType = "any"
	// NullDataType indicates the data is of null data type.
	NullDataType DataType = "null"
)

func (*DataType) UnmarshalJSON

func (d *DataType) UnmarshalJSON(data []byte) error

UnmarshalJSON accepts the canonical wire names and normalizes the historical unsigned-integer alias to UIntDataType.

type Error

type Error struct {
	// Details preserves code-specific HTTP or statement error information from the server.
	Details json.RawMessage
	Kind    ErrorKind
	// Code is the server error code, when provided, or catalog_commit_outcome_unknown
	// when a catalog mutation could not be confirmed. Unknown codes are retained.
	Code          string
	Message       string
	HTTPStatus    int
	RequestID     string
	RetryAfter    time.Duration
	Retryable     bool
	AppendDetails *AppendErrorDetails
	// WriteDetails identifies a client timeout or cancellation after sending began.
	// Existing error kinds, causes, and HTTP diagnostics remain available.
	WriteDetails *WriteErrorDetails
	// StatementDetails contains the structured server failure for a failed
	// statement, when available.
	StatementDetails *StatementErrorDetails
	// contains filtered or unexported fields
}

Error represents a ScopeDB client or API error.

func (*Error) Error

func (e *Error) Error() string

Error returns the human-readable error message.

func (*Error) Unwrap

func (e *Error) Unwrap() error

Unwrap returns the transport, decoding, or configuration error that caused this error.

type ErrorKind

type ErrorKind string

ErrorKind identifies the operation-level category of a ScopeDB error.

const (
	// ErrorKindUnexpected is an error that has no more specific classification.
	ErrorKindUnexpected ErrorKind = "Unexpected"
	// ErrorKindConfigInvalid indicates invalid client configuration or arguments.
	ErrorKindConfigInvalid ErrorKind = "ConfigInvalid"
	// ErrorKindStatementFailed indicates a failed or cancelled statement.
	ErrorKindStatementFailed ErrorKind = "StatementFailed"
	// ErrorKindCatalogFailed indicates a catalog request failure or unknown commit outcome.
	ErrorKindCatalogFailed ErrorKind = "CatalogFailed"
	// ErrorKindAppendRowsFailed indicates a rejected append or an unknown commit outcome.
	ErrorKindAppendRowsFailed ErrorKind = "AppendRowsFailed"
)

type FieldSchema

type FieldSchema struct {
	// Name is the field name.
	Name string
	// Type is the field data type.
	Type DataType
}

FieldSchema describes a single field.

type ResultSet

type ResultSet struct {
	// TotalRows is the total number of rows in the result set.
	TotalRows uint64
	// Schema is the schema of the result set.
	Schema Schema
	// contains filtered or unexported fields
}

ResultSet stores the result of a statement execution.

func (*ResultSet) First

func (rs *ResultSet) First() (map[string]Value, bool, error)

First returns the first row keyed by column name. The boolean is false when the result set is empty.

func (*ResultSet) RawRows

func (rs *ResultSet) RawRows() ([][]*string, error)

RawRows returns the string-or-null cells from the JSON wire response without converting them to ScopeDB value types.

func (*ResultSet) ToObjects

func (rs *ResultSet) ToObjects() ([]map[string]Value, error)

ToObjects returns rows keyed by result column name.

Duplicate output column names are rejected because representing them as a map would silently discard values.

func (*ResultSet) ToValues

func (rs *ResultSet) ToValues() ([][]Value, error)

ToValues reads the result set and returns the rows as a 2D array of values, i.e., rows of value lists.

Binary cells are returned as []byte, timestamps as time.Time, and intervals as time.Duration. Array, object, and any cells remain JSON strings, while null cells are returned as nil.

This method is only valid if the result set is of the JSON format.

type Schema

type Schema []*FieldSchema

Schema describes the fields in a table or query result.

type Statement

type Statement struct {

	// ID is an optional caller-provided statement ID.
	//
	// When nil, ScopeDB generates the statement ID.
	ID *uuid.UUID
	// MaxElapsed limits the server-side elapsed time, including queueing.
	// Zero uses the server default of one hour.
	MaxElapsed time.Duration
	// MaxEstimated limits the estimated total execution duration.
	// Zero leaves the estimate unrestricted.
	MaxEstimated time.Duration
	// contains filtered or unexported fields
}

Statement configures a ScopeQL statement before submission.

func (*Statement) Execute

func (s *Statement) Execute(ctx context.Context) (*ResultSet, error)

Execute submits the statement to ScopeDB for execution and waits for its completion.

func (*Statement) Submit

func (s *Statement) Submit(ctx context.Context) (*StatementHandle, error)

Submit submits the statement to ScopeDB for execution.

type StatementErrorCode

type StatementErrorCode string

StatementErrorCode identifies the reason a statement failed. Unknown values are preserved for forward compatibility.

const (
	// StatementErrorCodeFailed indicates that statement preparation or execution failed.
	StatementErrorCodeFailed StatementErrorCode = "statement_failed"
	// StatementErrorCodePendingTimeout indicates that the statement timed out before execution.
	StatementErrorCodePendingTimeout StatementErrorCode = "statement_pending_timeout"
	// StatementErrorCodeExecutionTimeout indicates that the statement exceeded its execution timeout.
	StatementErrorCodeExecutionTimeout StatementErrorCode = "statement_execution_timeout"
	// StatementErrorCodeEstimateLimitExceeded indicates that the estimated duration reached its limit.
	StatementErrorCodeEstimateLimitExceeded StatementErrorCode = "statement_estimate_limit_exceeded"
	// StatementErrorCodeHeartbeatLost indicates that the statement worker stopped reporting progress.
	StatementErrorCodeHeartbeatLost StatementErrorCode = "statement_heartbeat_lost"
)

type StatementErrorDetails

type StatementErrorDetails struct {
	Code    StatementErrorCode `json:"code"`
	Message string             `json:"message"`
	Details json.RawMessage    `json:"details,omitempty"`
}

StatementErrorDetails contains the structured failure returned for a failed statement. Details is code-specific JSON and is nil when the server did not provide additional details.

type StatementHandle

type StatementHandle struct {
	// contains filtered or unexported fields
}

StatementHandle tracks a submitted statement. Its methods are safe to call concurrently, including Cancel while another goroutine is waiting. A handle must not be copied after first use.

func (*StatementHandle) Cancel

Cancel requests server cancellation and returns the complete observation. Completion may win the race: inspect Status, ResultSet, and Error. A cached terminal observation is returned without making another request.

func (*StatementHandle) ID

func (h *StatementHandle) ID() uuid.UUID

ID returns the statement ID represented by this handle.

func (*StatementHandle) Refresh added in v0.7.0

Refresh fetches one complete observation. A cached terminal observation is returned without making another request. A failed request leaves the cache intact.

func (*StatementHandle) Snapshot added in v0.7.0

func (h *StatementHandle) Snapshot() *StatementSnapshot

Snapshot returns the latest local observation without making a request. It is nil until Submit, Refresh, or Cancel receives a response.

func (*StatementHandle) Wait

func (h *StatementHandle) Wait(ctx context.Context) (*ResultSet, error)

Wait polls until the statement is finished, failed, or cancelled.

A context error stops local waiting; it does not cancel the server statement. Use Cancel with a live context to request server cancellation. Terminal results remain cached even after the server expires its saved result.

type StatementProgress

type StatementProgress struct {
	// ComputeSeconds is cumulative server compute time, not elapsed wall time.
	ComputeSeconds float64 `json:"compute_seconds"`
	// TotalPercentage denotes the total progress in percentage: [0.0, 100.0].
	TotalPercentage float64 `json:"total_percentage"`
	// NanosFromSubmitted denotes the duration in nanoseconds since the statement is submitted.
	NanosFromSubmitted int64 `json:"nanos_from_submitted"`
	// NanosFromStarted denotes the duration in nanoseconds since the statement is started.
	NanosFromStarted int64 `json:"nanos_from_started"`
	// TotalStages denotes the total number of stages to execute.
	TotalStages int64 `json:"total_stages"`
	// TotalPartitions denotes the estimated total number of partitions to scan.
	TotalPartitions int64 `json:"total_partitions"`
	// TotalRows denotes the estimated total number of rows to scan.
	TotalRows int64 `json:"total_rows"`
	// TotalCompressedBytes denotes the estimated total number of compressed bytes to scan.
	TotalCompressedBytes int64 `json:"total_compressed_bytes"`
	// TotalUncompressedBytes denotes the estimated total number of uncompressed bytes to scan.
	TotalUncompressedBytes int64 `json:"total_uncompressed_bytes"`
	// ScannedStages denotes the total number of stages executed.
	ScannedStages int64 `json:"scanned_stages"`
	// ScannedPartitions denotes the number of partitions scanned.
	ScannedPartitions int64 `json:"scanned_partitions"`
	// ScannedRows denotes the number of rows scanned.
	ScannedRows int64 `json:"scanned_rows"`
	// ScannedCompressedBytes denotes the number of compressed bytes scanned.
	ScannedCompressedBytes int64 `json:"scanned_compressed_bytes"`
	// ScannedUncompressedBytes denotes the number of uncompressed bytes scanned.
	ScannedUncompressedBytes int64 `json:"scanned_uncompressed_bytes"`
	// SkippedPartitions denotes the number of partitions skipped by pruning.
	SkippedPartitions int64 `json:"skipped_partitions"`
	// SkippedRows denotes the number of rows skipped by pruning.
	SkippedRows int64 `json:"skipped_rows"`
	// SkippedCompressedBytes denotes the number of compressed bytes skipped by pruning.
	SkippedCompressedBytes int64 `json:"skipped_compressed_bytes"`
	// SkippedUncompressedBytes denotes the number of uncompressed bytes skipped by pruning.
	SkippedUncompressedBytes int64 `json:"skipped_uncompressed_bytes"`
}

StatementProgress is a struct that represents the progress of a statement.

type StatementSnapshot added in v0.7.0

type StatementSnapshot struct {
	ID        uuid.UUID
	CreatedAt time.Time
	Status    StatementStatus
	Progress  StatementProgress
	Error     *StatementErrorDetails
	ResultSet *ResultSet
}

StatementSnapshot is one observation of a statement. Error is present for a failed statement; ResultSet is present for a finished statement. Snapshots belong to the caller: modifying one does not change the handle's cache.

type StatementStatus

type StatementStatus string

StatementStatus is a string that represents the status of a statement.

const (
	// StatementStatusPending indicates the query is not started yet.
	StatementStatusPending StatementStatus = "pending"
	// StatementStatusRunning indicates the query is not finished yet.
	StatementStatusRunning StatementStatus = "running"
	// StatementStatusFinished indicates the query is finished.
	StatementStatusFinished StatementStatus = "finished"
	// StatementStatusFailed indicates the query is failed.
	StatementStatusFailed StatementStatus = "failed"
	// StatementStatusCancelled indicates the query is cancelled.
	StatementStatusCancelled StatementStatus = "cancelled"
)

func (StatementStatus) Terminated

func (s StatementStatus) Terminated() bool

Terminated returns true if the statement is finished, failed, or cancelled.

type Table

type Table struct {

	// Database is the database name. Empty uses "scopedb" for REST APIs.
	Database string
	// Schema is the schema name. Empty uses "public" for REST APIs.
	Schema string
	// Name is the name of the table.
	Name string
	// contains filtered or unexported fields
}

Table references a ScopeDB table.

func (*Table) AppendNDJSON

func (t *Table) AppendNDJSON(ctx context.Context, ndjson []byte) (AppendRowsResult, error)

AppendNDJSON sends one caller-encoded NDJSON request of at most 8 MiB uncompressed. The body contains one JSON object per non-empty line, not a JSON array.

func (*Table) AppendStream

func (t *Table) AppendStream(options AppendStreamOptions) (*AppendStream, error)

AppendStream creates a bounded asynchronous append stream for this table.

func (*Table) Catalog added in v0.7.0

func (t *Table) Catalog() *CatalogResource[*CatalogTable]

Catalog selects this table's complete definition for Get, Apply, Delete, or Raw. The selector captures the current database, schema, and name.

func (*Table) Identifier

func (t *Table) Identifier() string

Identifier returns the quoted table identifier.

type Value

type Value any

Value stores the contents of a single cell from a ScopeDB statement result.

type WriteErrorDetails added in v0.7.0

type WriteErrorDetails struct {
	Reason  WriteErrorReason `json:"reason"`
	Outcome AppendState      `json:"outcome"`
}

WriteErrorDetails describes an interrupted write. An unknown outcome may have committed and must not be automatically replayed.

type WriteErrorReason added in v0.7.0

type WriteErrorReason string

WriteErrorReason identifies why an in-flight write was interrupted.

const (
	// WriteErrorReasonTimeout means a client or transport deadline expired.
	WriteErrorReasonTimeout WriteErrorReason = "timeout"
	// WriteErrorReasonCancelled means the caller cancelled an in-flight write.
	WriteErrorReasonCancelled WriteErrorReason = "cancelled"
)

Directories

Path Synopsis
examples
append_ndjson command
Package main demonstrates one caller-encoded raw NDJSON table append.
Package main demonstrates one caller-encoded raw NDJSON table append.
append_stream command
Package main demonstrates strict bounded asynchronous table appends.
Package main demonstrates strict bounded asynchronous table appends.
catalog command
Package main demonstrates declarative catalog discovery.
Package main demonstrates declarative catalog discovery.
internal/exampleutil
Package exampleutil contains configuration shared by the runnable examples.
Package exampleutil contains configuration shared by the runnable examples.
patterns/bulk_append command
Package main imports NDJSON from standard input with bounded streaming writes.
Package main imports NDJSON from standard input with bounded streaming writes.
patterns/telemetry command
Package main demonstrates observable best-effort telemetry delivery.
Package main demonstrates observable best-effort telemetry delivery.
statement command
Package main demonstrates synchronous and asynchronous statement queries.
Package main demonstrates synchronous and asynchronous statement queries.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL