The official SurrealDB SDK for Golang.
View the SDK documentation here.
go get github.com/surrealdb/surrealdb.go
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)
}
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)
}
- 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 ago.mod
file - Run
go mod tidy
to download thesurrealdb.go
dependency - Run
go run main.go
to run the example.
There are 2 different connection engines you can use to connect to SurrealDb backend. You can do so via Websocket or through HTTP connections
db, err := surrealdb.New("ws://localhost:8000")
or for a secure connection
db, err := surrealdb.New("wss://localhost:8000")
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")
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://")
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,... } |
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{}
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)
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.