sdbc

package module
v0.9.4 Latest Latest
Warning

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

Go to latest
Published: Jul 15, 2025 License: MIT Imports: 19 Imported by: 2

README


logo

An independent SurrealDB client for Go


release   go version   go report card   tests   codecov   discord   contributors

SDBC (SurrealDB Client) is an independent Go client for the innovative SurrealDB multi-model database system.

DISCLAIMER: SDBC is not the official Go client for SurrealDB but rather an independent implementation. You can find the repository for the official implementation here. Currently, SDBC is designed for direct use with SOM. It's important to note that SDBC is in the early stages of development and is not yet stable or ready for production use.

Table of Contents

What is SurrealDB?

SurrealDB is a cutting-edge database system that offers a SQL-style query language with real-time queries
and efficient related data retrieval. It supports both schema-full and schema-less data handling. With its full graph database functionality, SurrealDB enables advanced querying and analysis by allowing records (or vertices) to be connected with edges, each with its own properties and metadata. This facilitates multi-table, multi-depth document retrieval without complex JOINs, all within the database.

(Information extracted from the official homepage).

Why SDBC instead of the official client?

The official client can be found here.

  • The official Go client for SurrealDB is currently not in a really usable state.
  • Inconsistencies exist in the codebase, such as the unused url parameter in the New function.
  • It lacks essential features, particularly after both the 1.0 (first stable) and 2.0 releases of SurrealDB.
  • The SurrealDB team has other priorities, and it seems as if they are currently not actively maintaining the Go client.
  • Future versions of the official client may require CGO for direct bindings to an underlying driver, whereas SDBC will always be pure Go.
  • Writing this custom client was and is an enjoyable endeavor 😉

SDBC is a practical choice until the official client becomes stable, actively maintained, and supports all the features required by SOM. It also maintains purity in Go and avoids CGO dependencies.

It is still open whether this project will be maintained after the official client becomes stable and usable for SOM.

Features

  • Pure Go implementation without CGO dependencies.
  • Supports schema-full and schema-less data handling.
  • Enables advanced querying and analysis with full graph database functionality.
  • Designed for direct use with SOM.

Details

Supported operations

This client implements the RPC (websocket) interface of SurrealDB. The following operations are supported:

Function Description Supported
use [ ns, db ] Specifies or unsets the namespace and/or database for the current connection
info Returns the record of an authenticated record user ❌ (no need)
version Returns version information about the database/server
signup [ NS, DB, AC, … ] Signup a user using the SIGNUP query defined in a record access method ❌ (no need)
signin [NS, DB, AC, … ] Signin a root, NS, DB or record user against SurrealDB
authenticate [ token ] Authenticate a user against SurrealDB with a token ❌ (no need)
invalidate Invalidate a user’s session for the current connection ❌ (no need)
let [ name, value ] Define a variable on the current connection
unset [ name ] Remove a variable from the current connection
live [ table, diff ] Initiate a live query
kill [ queryUuid ] Kill an active live query
query [ sql, vars ] Execute a custom query with optional variables
graphql [ query, options? ] Execute GraphQL queries against the database ⚠️ (not yet)
run [ func_name, version, args ] Execute built-in functions, custom functions, or machine learning models with optional arguments.
select [ thing ] Select either all records in a table or a single record
create [ thing, data ] Create a record with a random or specified ID
insert [ thing, data ] Insert one or multiple records in a table
insert_relation [ table, data ] Insert a new relation record into a specified table or infer the table from the data
update [ thing, data ] Modify either all records in a table or a single record with specified data if the record already exists
upsert [ thing, data ] Replace either all records in a table or a single record with specified data
relate [ in, relation, out, data? ] Create graph relationships between created records
merge [ thing, data ] Merge specified data into either all records in a table or a single record
patch [ thing, patches, diff ] Patch either all records in a table or a single record with specified patches
delete [ thing ] Delete either all records in a table or a single record
Supported data types

This client supports the following data types as defined by SurrealDB:

Type Description Definition Supported Go type
any The field will allow any data type supported by SurrealDB. (see others) any
array An array of items. Content and length can be defined. array, array, array<int, 10> []any
bool Describes whether something is truthy or not. true, false bool
bytes Stores a value in a byte array. bytes, value []byte
datetime An ISO 8601 compliant data type that stores a date with time and time zone. (ISO 8601) time.Time
decimal Uses BigDecimal for storing any real number with arbitrary precision. - float64
duration Store a value representing a length of time. 1h, 1m, 1h1m1s time.Duration
float Store a value in a 64 bit float. 1.5, 100.3 float32, float64
geometry RFC 7946 compliant data type for storing geometry in the GeoJson format. (see below) ⚠️ not yet (see below)
int Store a value in a 64 bit integer. 1, 2, 3, 4 int
number Store numbers without specifying the type. SurrealDB will store it using the minimal number of bytes. - int, float, ...
none ? - -
object Store formatted objects containing values of any supported type with no limit to object depth or nesting. - struct{ ... }, map[comparable]any
literal A value that may have multiple representations or formats, similar to an enum or a union type.
Can be composed of strings, numbers, objects, arrays, or durations.
"a" | "b", [number, “abc”], 123 | 456 | string | 1y1m1d ⚠️ kind of (any)
option Makes types optional and guarantees the field to be either empty (NULL) or a value. option<...> * (pointer)
range A range of possible values. Lower and upper bounds can be set, in the absence of which the range
becomes open-ended. A range of integers can be used in a FOR loop.
0..10, 0..=10, ..10, 'a'..'z'
record Store a reference to another record. The value must be a Record ID. record, record, record<user | administrator> *sdbc.ID
set A set of items. Similar to array, but items are automatically deduplicated. set, set, set<int, 10> []any
string Describes a text-like value. "some", "value" string
Supported geometry types

These types are not yet implemented.

Getting Started

Installation

To install SDBC, run the following command:

go get github.com/go-surreal/sdbc

Usage

To use SDBC, import it in your Go code:

import (
	"github.com/go-surreal/sdbc"
)

Then, create a new client:

func main() {
	client, err := sdbc.NewClient(ctx, sdbc.Config{
		Address:   "ws://localhost:8000/rpc", 
		Username:  "root", 
		Password:  "root", 
		Namespace: "test",
		Database:  "test",
	})
	
	if err != nil {
        log.Fatal(err)
    }
		
    // ...
}

Contributing

We welcome contributions! If you'd like to contribute to SDBC, please read our Contributing Guidelines for instructions on how to get started.

License

SDBC is licensed under the MIT License.

Documentation

Index

Constants

View Source
const (
	// CBORTagNone represents a NONE value.
	// The value passed to the tagged value is null, as it cannot be empty.
	CBORTagNone = 6

	// CBORTagUUID represents a UUID in binary form.
	// It is adopted from the IANA specification.
	// It is preferred by SurrealDB over custom tag 9 (string).
	//
	// Please note: This const is exposed and not implemented by this package.
	// This decision was made to minimize the number of dependencies.
	// There is no UUID type in the standard library.
	// As a third-party package, github.com/google/uuid is recommended.
	CBORTagUUID = 37
)
View Source
const (
	CborMinNestedLevels = 4
	CborMaxNestedLevels = 65535

	CborMinArrayElements = 16
	CborMaxArrayElements = 2147483647

	CborMinMapPairs = 16
	CborMaxMapPairs = 2147483647
)

Variables

View Source
var (
	ErrInvalidNamespaceName = errors.New("invalid namespace name")
	ErrInvalidDatabaseName  = errors.New("invalid database name")

	ErrContextNil = errors.New("context is nil")
)
View Source
var (
	ErrChannelClosed               = errors.New("channel closed")
	ErrCouldNotGetLiveQueryChannel = errors.New("could not get live query channel")
	ErrCouldNotSelectDatabase      = errors.New("could not select database")
	ErrEmptyResponse               = errors.New("empty response")
	ErrExpectedTextMessage         = fmt.Errorf("expected message of type text (%d)", websocket.MessageBinary)
	ErrResponseNotOkay             = errors.New("response status is not OK")
	ErrResultWithError             = errors.New("result contains error")
	ErrTimeoutWaitingForGoroutines = errors.New("internal goroutines did not finish in time")
)
View Source
var (
	ErrTableNameRequired     = errors.New("table name is required")
	ErrDataInvalid           = errors.New("data is invalid")
	ErrUnmarshalNotSupported = errors.New("unmarshal not supported")
)

Functions

This section is empty.

Types

type BigFloat added in v0.6.0

type BigFloat struct {
	big.Float
}

type BigInt added in v0.6.0

type BigInt struct {
	big.Int
}

type Client

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

func NewClient

func NewClient(ctx context.Context, conf Config, opts ...Option) (*Client, error)

NewClient creates a new client and connects to the database using a websocket connection.

func (*Client) Close

func (c *Client) Close() error

Close closes the client and the websocket connection. Furthermore, it cleans up all idle goroutines.

func (*Client) Create

func (c *Client) Create(ctx context.Context, id RecordID, data any) ([]byte, error)

Create a record with a random or specified ID.

func (*Client) Delete

func (c *Client) Delete(ctx context.Context, id *ID) ([]byte, error)

Delete either all records in a table or a single record.

func (*Client) GraphQL added in v0.8.0

func (c *Client) GraphQL(ctx context.Context, req GraphqlRequest) ([]byte, error)

GraphQL executes graphql queries against the database. Note: Requires SurrealDB v2.0.0 or later.

func (*Client) Insert added in v0.8.0

func (c *Client) Insert(ctx context.Context, table string, data []any) ([]byte, error)

Insert one or multiple records in a table. TODO: allow for fixed IDs.

func (*Client) InsertRelation added in v0.8.0

func (c *Client) InsertRelation(ctx context.Context, table *string, data any) ([]byte, error)

InsertRelation inserts a new relation record into the database. Data needs to specify both the in and out records. If table is nil, the relation table is inferred from the data record ID field.

func (*Client) Kill

func (c *Client) Kill(ctx context.Context, uuid string) ([]byte, error)

Kill an active live query.

func (*Client) Let added in v0.8.0

func (c *Client) Let(ctx context.Context, name string, value any) error

Let defines a variable on the current connection.

func (*Client) Live

func (c *Client) Live(ctx context.Context, query string, vars map[string]any) (<-chan []byte, error)

Live executes a live query request and returns a channel to receive the results.

NOTE: SurrealDB does not yet support proper variable handling for live queries. To circumvent this limitation, params are registered in the database before issuing the actual live query. Those params are given the values of the variables passed to this method. This way, the live query can be filtered by said params. Please note that this is a workaround and may not work as expected in all cases.

References: Bug: Using variables in filters does not emit live messages (https://github.com/surrealdb/surrealdb/issues/2623) Bug: LQ params should be evaluated before registering (https://github.com/surrealdb/surrealdb/issues/2641) Bug: parameters do not work with live queries (https://github.com/surrealdb/surrealdb/issues/3602) Feature: Live Query WHERE clause should process Params (https://github.com/surrealdb/surrealdb/issues/4026) Docs: https://surrealdb.com/docs/surrealql/statements/live_select (bottom "other notes")

TODO: prevent query from being more than one statement.

func (*Client) Marshal added in v0.6.0

func (c *Client) Marshal(val any) ([]byte, error)

func (*Client) Merge added in v0.8.0

func (c *Client) Merge(ctx context.Context, thing *ID, data any) ([]byte, error)

Merge specified data into either all records in a table or a single record. TODO: support "all" records.

func (*Client) Patch added in v0.8.0

func (c *Client) Patch(ctx context.Context, thing *ID, patches []Patch, diff bool) ([]byte, error)

Patch either all records in a table or a single record with specified patches. see: https://jsonpatch.com/

func (*Client) Query

func (c *Client) Query(ctx context.Context, query string, vars map[string]any) ([]byte, error)

Query executes a custom query with optional variables.

func (*Client) Relate added in v0.8.0

func (c *Client) Relate(ctx context.Context, in *ID, relation RecordID, out *ID, data any) ([]byte, error)

Relate creates a graph relationship between two records. Data is optional and only submitted if it is not nil.

func (*Client) Run added in v0.8.0

func (c *Client) Run(ctx context.Context, name string, version *string, args []any) ([]byte, error)

Run executes built-in functions, custom functions, or machine learning models with optional arguments.

func (*Client) Select

func (c *Client) Select(ctx context.Context, id *ID) ([]byte, error)

Select either all records in a table or a single record.

func (*Client) Unmarshal added in v0.6.0

func (c *Client) Unmarshal(data []byte, val any) error

func (*Client) Unset added in v0.8.0

func (c *Client) Unset(ctx context.Context, name string) error

Unset removes a variable from the current connection.

func (*Client) Update

func (c *Client) Update(ctx context.Context, id *ID, data any) ([]byte, error)

Update modifies either all records in a table or a single record with specified data if the record already exists.

func (*Client) Upsert added in v0.8.0

func (c *Client) Upsert(ctx context.Context, id RecordID, data any) ([]byte, error)

Upsert replaces either all records in a table or a single record with specified data. Note: Only supported by SurrealDB v2.0.0 and later.

func (*Client) Version added in v0.8.0

func (c *Client) Version(ctx context.Context) (string, error)

Version returns version information about the database/server.

type Config

type Config struct {
	// Host is the host address of the database.
	// It must not contain a protocol or sub path like /rpc.
	Host string

	// Secure indicates whether to use a secure connection (https, wss) or not.
	Secure bool

	// Username is the username to use for authentication.
	Username string

	// Password is the password to use for authentication.
	Password string

	// Namespace is the namespace to use.
	// It will automatically be created if it does not exist.
	Namespace string

	// Database is the database to use.
	// It will automatically be created if it does not exist.
	Database string

	// CborMaxNestedLevels specifies the max nested levels allowed for any combination of CBOR array, maps, and tags.
	// Default is 32 levels, minimum is 4, maximum is 65535. Note that higher maximum levels of nesting can
	// require larger amounts of stack to deserialize. Don't increase this higher than you require.
	CborMaxNestedLevels int

	// CborMaxArrayElements specifies the max number of elements for CBOR arrays.
	// Default is 128*1024=131072, minimum is 16, maximum is 2147483647.
	CborMaxArrayElements int

	// CborMaxMapPairs specifies the max number of key-value pairs for CBOR maps.
	// Default is 128*1024=131072, minimum is 16, maximum is 2147483647.
	CborMaxMapPairs int
}

Config is the configuration for the client.

type DateTime added in v0.6.0

type DateTime struct {
	time.Time
}

func (*DateTime) MarshalCBOR added in v0.6.0

func (dt *DateTime) MarshalCBOR() ([]byte, error)

func (*DateTime) UnmarshalCBOR added in v0.6.0

func (dt *DateTime) UnmarshalCBOR(data []byte) error

type Decimal added in v0.6.0

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

func (*Decimal) MarshalCBOR added in v0.6.0

func (d *Decimal) MarshalCBOR() ([]byte, error)

type Duration added in v0.6.0

type Duration struct {
	time.Duration
}

func (*Duration) MarshalCBOR added in v0.6.0

func (d *Duration) MarshalCBOR() ([]byte, error)

func (*Duration) UnmarshalCBOR added in v0.6.0

func (d *Duration) UnmarshalCBOR(data []byte) error

type GraphqlRequest added in v0.8.0

type GraphqlRequest struct {
	// Query contains the query string to execute (required).
	Query string `cbor:"query"`

	// Vars may contain variables to be used in the query (optional).
	Vars map[string]any `cbor:"vars"`

	// Operation is the name of the operation to execute (optional).
	Operation string `cbor:"operationName"`
}

type HTTPClient added in v0.9.2

type HTTPClient interface {
	Do(req *http.Request) (*http.Response, error)
}

type ID added in v0.6.0

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

func MakeID added in v0.6.0

func MakeID(table string, identifier any) *ID

func ParseRecord added in v0.6.0

func ParseRecord(record string) (*ID, bool)

func (*ID) MarshalCBOR added in v0.6.0

func (id *ID) MarshalCBOR() ([]byte, error)

func (*ID) String added in v0.6.0

func (id *ID) String() string

func (*ID) UnmarshalCBOR added in v0.6.0

func (id *ID) UnmarshalCBOR(data []byte) error

type Marshal added in v0.6.0

type Marshal func(val any) ([]byte, error)

type Operation added in v0.8.0

type Operation string
const (
	OpAdd     Operation = "add"
	OpRemove  Operation = "remove"
	OpReplace Operation = "replace"
	OpCopy    Operation = "copy"
	OpMove    Operation = "move"
	OpTest    Operation = "test"
)

type Option

type Option func(*options)

func WithHTTPClient added in v0.9.2

func WithHTTPClient(client HTTPClient) Option

WithHTTPClient sets a custom http client. If not set, the default http client is used.

func WithLogger

func WithLogger(logger *slog.Logger) Option

WithLogger sets the logger. If not set, no log output is created.

func WithReadLimit

func WithReadLimit(limit int64) Option

WithReadLimit sets a custom read limit (in bytes) for the websocket connection. If not set, the default read limit is 1 MB.

func WithTimeout

func WithTimeout(timeout time.Duration) Option

WithTimeout sets a custom timeout for requests. If not set, the default timeout is 1 minute.

type Patch added in v0.8.0

type Patch struct {
	Op    Operation `cbor:"op"`
	Path  string    `cbor:"path"`
	Value any       `cbor:"value"`
	From  string    `cbor:"from"`
}

type RecordID added in v0.6.0

type RecordID interface {
	// contains filtered or unexported methods
}

func NewID added in v0.6.0

func NewID(table string) RecordID

func NewULID added in v0.6.0

func NewULID(table string) RecordID

func NewUUID added in v0.6.0

func NewUUID(table string) RecordID

type Unmarshal added in v0.6.0

type Unmarshal func(buf []byte, val any) error

type ZeroAsNone added in v0.6.0

type ZeroAsNone[T comparable] struct {
	Value T
}

func (*ZeroAsNone[T]) MarshalCBOR added in v0.6.0

func (n *ZeroAsNone[T]) MarshalCBOR() ([]byte, error)

func (*ZeroAsNone[T]) UnmarshalCBOR added in v0.6.0

func (n *ZeroAsNone[T]) UnmarshalCBOR(data []byte) error

Jump to

Keyboard shortcuts

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