surrealdb

package module
v0.3.2 Latest Latest
Warning

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

Go to latest
Published: Dec 2, 2024 License: Apache-2.0 Imports: 12 Imported by: 44

README


 

The official SurrealDB SDK for Golang.


     

     

surrealdb.go

The official SurrealDB SDK for Golang.

Documentation

View the SDK documentation here.

How to install

go get github.com/surrealdb/surrealdb.go

Getting started

In the example provided below, we are going to connect and authenticate on a SurrealDB server, set the namespace and make several data manipulation requests.

This example requires SurrealDB to be installed and running on port 8000.

package main

import (
	"fmt"
	surrealdb "github.com/surrealdb/surrealdb.go"
	"github.com/surrealdb/surrealdb.go/pkg/models"
)

type Person struct {
	ID      	*models.RecordID `json:"id,omitempty"`
	Name    	string `json:"name"`
	Surname 	string `json:"surname"`
	Location 	models.GeometryPoint `json:"location"`
}

func main() {
	// Connect to SurrealDB
	db, err := surrealdb.New("ws://localhost:8000")
	if err != nil {
		panic(err)
	}

	// Set the namespace and database
	if err = db.Use("testNS", "testDB"); err != nil {
		panic(err)
	}

	// Sign in to authentication `db`
	authData := &surrealdb.Auth{
		Username: "root", // use your setup username
		Password: "root", // use your setup password
	}
	token, err := db.SignIn(authData)
	if err != nil {
		panic(err)
	}

	// Check token validity. This is not necessary if you called `SignIn` before. This authenticates the `db` instance too if sign in was
	// not previously called
	if err := db.Authenticate(token); err != nil {
		panic(err)
	}

	// And we can later on invalidate the token if desired
	defer func(token string) {
		if err := db.Invalidate(); err != nil {
			panic(err)
		}
	}(token)

	// Create an entry
	person1, err := surrealdb.Create[Person](db, models.Table("persons"), map[interface{}]interface{}{
		"Name":     "John",
		"Surname":  "Doe",
		"Location": models.NewGeometryPoint(-0.11, 22.00),
	})
	if err != nil {
		panic(err)
	}
	fmt.Printf("Created person with a map: %+v\n", person1)

	// Or use structs
	person2, err := surrealdb.Create[Person](db, models.Table("persons"), Person{
		Name:     "John",
		Surname:  "Doe",
		Location: models.NewGeometryPoint(-0.11, 22.00),
	})
	if err != nil {
		panic(err)
	}
	fmt.Printf("Created person with a struvt: %+v\n", person2)

	// Get entry by Record ID
	person, err := surrealdb.Select[Person, models.RecordID](db, *person1.ID)
	if err != nil {
		panic(err)
	}
	fmt.Printf("Selected a person by record id: %+v\n", person)

	// Or retrieve the entire table
	persons, err := surrealdb.Select[[]Person, models.Table](db, models.Table("persons"))
	if err != nil {
		panic(err)
	}
	fmt.Printf("Selected all in persons table: %+v\n", persons)

	// Delete an entry by ID
	if err = surrealdb.Delete[models.RecordID](db, *person2.ID); err != nil {
		panic(err)
	}

	// Delete all entries
	if err = surrealdb.Delete[models.Table](db, models.Table("persons")); err != nil {
		panic(err)
	}

	// Confirm empty table
	persons, err = surrealdb.Select[[]Person](db, models.Table("persons"))
	if err != nil {
		panic(err)
	}
	fmt.Printf("No Selected person: %+v\n", persons)
}
Doing it your way

All Data manipulation methods are handled by an undelying send function. This function is exposed via db.Send function if you want to create requests yourself but limited to a selected set of methods. Theses methods are:

  • select
  • create
  • insert
  • upsert
  • update
  • patch
  • delete
  • query
type UserSelectResult struct {
	Result []Users
}

var res UserSelectResult
// or var res surrealdb.Result[[]Users]

err := db.Send(&res, "query", user.ID)
if err != nil {
	panic(err)
}
	
Instructions for running the example
  • In a new folder, create a file called main.go and paste the above code
  • Run go mod init github.com/<github-username>/<project-name> to initialise a go.mod file
  • Run go mod tidy to download the surrealdb.go dependency
  • Run go run main.go to run the example.

Connection Engines

There are 2 different connection engines you can use to connect to SurrealDb backend. You can do so via Websocket or through HTTP connections

Via Websocket
db, err := surrealdb.New("ws://localhost:8000")

or for a secure connection

db, err := surrealdb.New("wss://localhost:8000")
Via HTTP

There are some functions that are not available on RPC when using HTTP but on Websocket. All these except the "live" endpoint are effectively implemented in the HTTP library and provides the same result as though it is natively available on HTTP. While using the HTTP connection engine, note that live queries will still use a websocket connection if the backend supports it

db, err := surrealdb.New("http://localhost:8000")

or for a secure connection

db, err := surrealdb.New("https://localhost:8000")
Using SurrealKV and Memory

SurrealKV and Memory also do not support live notifications at this time. This would be updated in the next release.

For Surreal KV

db, err := surrealdb.New("surrealkv://path/to/dbfile.kv")

For Memory

db, err := surrealdb.New("mem://")
db, err := surrealdb.New("memory://")

Data Models

This package facilitates communication between client and the backend service using the Concise Binary Object Representation (CBOR) format. It streamlines data serialization and deserialization while ensuring efficient and lightweight communication. The library also provides custom models tailored to specific Data models recognised by SurrealDb, which cannot be covered by idiomatic go, enabling seamless interaction between the client and the backend.

See the documetation on data models on support data types

CBOR Type Go Representation Example
Null nil var x interface{} = nil
None surrealdb.None map[string]interface{}{"customer": surrealdb.None}
Boolean bool true, false
Array []interface{} []MyStruct{item1, item2}
Date/Time time.Time time.Now()
Duration time.Duration time.Duration(8821356)
UUID (string representation) surrealdb.UUID(string) surrealdb.UUID("123e4567-e89b-12d3-a456-426614174000")
UUID (binary representation) surrealdb.UUIDBin([]bytes) surrealdb.UUIDBin([]byte{0x01, 0x02, ...})`
Integer uint, uint64, int, int64 42, uint64(100000), -42, int64(-100000)
Floating Point float32, float64 3.14, float64(2.71828)
Byte String, Binary Encoded Data []byte []byte{0x01, 0x02}
Text String string "Hello, World!"
Map map[interface{}]interface{} map[string]float64{"one": 1.0}
Table name surrealdb.Table(name) surrealdb.Table("users")
Record ID surrealdb.RecordID{Table: string, ID: interface{}} surrealdb.RecordID{Table: "customers", ID: 1}, surrealdb.NewRecordID("customers", 1)
Geometry Point surrealdb.GeometryPoint{Latitude: float64, Longitude: float64} surrealdb.GeometryPoint{Latitude: 11.11, Longitude: 22.22
Geometry Line surrealdb.GeometryLine{GeometricPoint1, GeometricPoint2,... }
Geometry Polygon surrealdb.GeometryPolygon{GeometryLine1, GeometryLine2,... }
Geometry Multipoint surrealdb.GeometryMultiPoint{GeometryPoint1, GeometryPoint2,... }
Geometry MultiLine surrealdb.GeometryMultiLine{GeometryLine1, GeometryLine2,... }
Geometry MultiPolygon surrealdb.GeometryMultiPolygon{GeometryPolygon1, GeometryPolygon2,... }
Geometry Collection surrealdb.GeometryMultiPolygon{GeometryPolygon1, GeometryLine2, GeometryPoint3, GeometryMultiPoint4,... }

Helper Types

surrealdb.O

For some methods like create, insert, update, you can pass a map instead of an struct value. An example:

person, err := surrealdb.Create[Person](db, models.Table("persons"), map[interface{}]interface{}{
	"Name":     "John",
	"Surname":  "Doe",
	"Location": models.NewGeometryPoint(-0.11, 22.00),
})

This can be simplified to:

person, err := surrealdb.Create[Person](db, models.Table("persons"), surrealdb.O{
	"Name":     "John",
	"Surname":  "Doe",
	"Location": models.NewGeometryPoint(-0.11, 22.00),
})

Where surrealdb.O is defined below. There is no special advantage in using this other than simplicity/legibility.

type surrealdb.O map[interface{}]interface{}
surrealdb.Result[T]

This is useful for the Send function where T is the expected response type for a request. An example:

var res surrealdb.Result[[]Users]
err := db.Send(&res, "select", model.Table("users"))
if err != nil {
	panic(err)
}
fmt.Printf("users: %+v\n", users.R)

Contributing

You can run the Makefile commands to run and build the project

make build
make test
make lint

You also need to be running SurrealDB alongside the tests. We recommend using the nightly build, as development may rely on the latest functionality.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Create added in v0.3.0

func Create[TResult any, TWhat TableOrRecord](db *DB, what TWhat, data interface{}) (*TResult, error)

func Delete added in v0.3.0

func Delete[TResult any, TWhat TableOrRecord](db *DB, what TWhat) (*TResult, error)

func Insert added in v0.3.0

func Insert[TResult any](db *DB, what models.Table, data interface{}) (*[]TResult, error)

Insert a table or a row from the database like a POST request.

func InsertRelation added in v0.3.0

func InsertRelation(db *DB, relationship *Relationship) error

func Kill added in v0.3.0

func Kill(db *DB, id string) error

func Live added in v0.3.0

func Live(db *DB, table models.Table, diff bool) (*models.UUID, error)

func Merge added in v0.3.0

func Merge[TResult any, TWhat TableOrRecord](db *DB, what TWhat, data interface{}) (*TResult, error)

Merge a table or record in the database like a PATCH request.

func Patch added in v0.2.0

func Patch(db *DB, what interface{}, patches []PatchData) (*[]PatchData, error)

func Query added in v0.3.0

func Query[TResult any](db *DB, sql string, vars map[string]interface{}) (*[]QueryResult[TResult], error)

func QueryRaw added in v0.3.0

func QueryRaw(db *DB, queries *[]QueryStmt) error

func Relate added in v0.3.0

func Relate(db *DB, rel *Relationship) error

func Select added in v0.3.0

func Select[TResult any, TWhat TableOrRecord](db *DB, what TWhat) (*TResult, error)

func Update added in v0.3.0

func Update[TResult any, TWhat TableOrRecord](db *DB, what TWhat, data interface{}) (*TResult, error)

Update a table or record in the database like a PUT request.

func Upsert added in v0.3.0

func Upsert[TResult any, TWhat TableOrRecord](db *DB, what TWhat, data interface{}) (*TResult, error)

Types

type Auth added in v0.3.0

type Auth struct {
	Namespace string `json:"NS,omitempty"`
	Database  string `json:"DB,omitempty"`
	Scope     string `json:"SC,omitempty"`
	Access    string `json:"AC,omitempty"`
	Username  string `json:"user,omitempty"`
	Password  string `json:"pass,omitempty"`
}

Auth is a struct that holds surrealdb auth data for login.

type DB

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

DB is a client for the SurrealDB database that holds the connection.

func New

func New(connectionURL string) (*DB, error)

New creates a new SurrealDB client.

func (*DB) Authenticate

func (db *DB) Authenticate(token string) error

func (*DB) Close

func (db *DB) Close() error

Close closes the underlying WebSocket connection.

func (*DB) Info

func (db *DB) Info() (map[string]interface{}, error)

func (*DB) Invalidate

func (db *DB) Invalidate() error

func (*DB) Let

func (db *DB) Let(key string, val interface{}) error

func (*DB) LiveNotifications added in v0.3.0

func (db *DB) LiveNotifications(liveQueryID string) (chan connection.Notification, error)

func (*DB) Send added in v0.3.0

func (db *DB) Send(res interface{}, method string, params ...interface{}) error

func (*DB) SignIn added in v0.3.0

func (db *DB) SignIn(authData *Auth) (string, error)

SignIn is a helper method for signing in a user.

func (*DB) SignUp added in v0.3.0

func (db *DB) SignUp(authData *Auth) (string, error)

SignUp is a helper method for signing up a new user.

func (*DB) Unset added in v0.3.0

func (db *DB) Unset(key string) error

func (*DB) Use

func (db *DB) Use(ns, database string) error

Use is a method to select the namespace and table to use.

func (*DB) Version added in v0.3.0

func (db *DB) Version() (*VersionData, error)

func (*DB) WithContext added in v0.3.0

func (db *DB) WithContext(ctx context.Context) *DB

WithContext

type Obj added in v0.3.0

type Obj map[interface{}]interface{}

type PatchData added in v0.3.0

type PatchData struct {
	Op    string `json:"op"`
	Path  string `json:"path"`
	Value any    `json:"value"`
}

Patch represents a patch object set to MODIFY a record

type QueryResult added in v0.3.0

type QueryResult[T any] struct {
	Status string `json:"status"`
	Time   string `json:"time"`
	Result T      `json:"result"`
}

type QueryStmt added in v0.3.0

type QueryStmt struct {
	SQL    string
	Vars   map[string]interface{}
	Result QueryResult[cbor.RawMessage]
	// contains filtered or unexported fields
}

func (*QueryStmt) GetResult added in v0.3.0

func (q *QueryStmt) GetResult(dest interface{}) error

type Relationship added in v0.3.0

type Relationship struct {
	ID       *models.RecordID `json:"id"`
	In       models.RecordID  `json:"in"`
	Out      models.RecordID  `json:"out"`
	Relation models.Table     `json:"relation"`
	Data     map[string]any   `json:"data"`
}

type Result added in v0.3.0

type Result[T any] struct {
	T any
}

type TableOrRecord added in v0.3.0

type TableOrRecord interface {
	string | models.Table | models.RecordID | []models.Table | []models.RecordID
}

type VersionData added in v0.3.0

type VersionData struct {
	Version   string `json:"version"`
	Build     string `json:"build"`
	Timestamp string `json:"timestamp"`
}

Directories

Path Synopsis
internal
pkg

Jump to

Keyboard shortcuts

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