surrealdb package - github.com/idevelopthings/surrealdb.go.unofficial - Go Packages

surrealdb

package module
v0.0.11 Latest Latest
Warning

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

Go to latest
Published: Oct 9, 2022 License: Apache-2.0 Imports: 13 Imported by: 0

README

surrealdb.go

Go Reference

Unofficial fork of the surrealdb package


Credit:

A lot of the underlying package was written by people in the community on the original package

I just wanted to have my modified version easily accessible to my self, and maybe others. So I take no credits for that( hopefully no one sees me as ripping there work and understands)

Features:

  • Contains my system for a "Query Resolver" using generics
  • Has options for auto context setup/timeouts(it's a pain in the ass to pass these around in go)
  • A little easier to set up for server usage only
  • Has a global DB instance

Installation:

go get github.com/idevelopthings/surrealdb.go.unofficial

Examples:

Setup:

import (
"github.com/idevelopthings/surrealdb.go.unofficial"
"github.com/idevelopthings/surrealdb.go.unofficial/config"
)
db, err := surrealdb.New(ctx, && Config.DbConfig{
Url:       "ws://localhost:8000/rpc",
Username:  "root",
Password:  "root",
Database:  "test",
Namespace: "test",
// This will call db.signin() with the supplied credentials
AutoLogin: true,
// This will call db.use() with the supplied credentials
AutoUse:   true,
// When using surrealdb.Query[MyModel](), timeouts will be configured
Timeouts:  &Config.DbTimeoutConfig{Timeout: time.Duration(10) * time.Second},
})

Query Resolver/Generics

Quick Overview:

A lot of the query resolver use a similar interface/resolver setup

These methods exist on pretty much all resolver responses:

result.HasError() // Check if there was an error
result.Error()     // Get the go error if there is one
result.First()     // If you expect only 1 user object for example, it will take the first out of the response and return it(so you don't have to play with arrays, it will be a "User" instance for example)
result.All()     // Get all the results(an array of Users)
result.Results() // Get the raw surreal response/results
result.IsEmpty() // Check if there is any items in the result

In some cases, for example, create, since only one record is ever expected(as we can only create one)

It will use a .Item() method instead of .First(), and will not contain .All()

Query

Run a query with parameters(parameters should be used to prevent injection)

result := surrealdb.Query[User]("select * from users where name = $name", map[string]any{
"name": "bob",
})

result.HasError() // Check if there was an error
result.Error()            // Get the go error if there is one
result.AllAreSuccessful() // Check if all queries were successful
result.TotalTimeTaken() // Calculate the total time of all queries
result.FirstQueryResult() // Get the first query result(surreal returns multiple results for a query, so if you run more than 1, this is useful)
result.First()            // If you expect only 1 user object for example, it will take the first out of the response and return it(so you don't have to play with arrays, it will be a "User" instance for example)
result.All()     // Get all the results(an array of Users)
result.Results() // Get the raw surreal response/results

Select

Select one or many records

If an id is supplied for the first arg, it will select the one record with that id Otherwise, it expects a table name, where it will then select all records from that table.

// Select one:
result := surrealdb.Select[User]("user:12345")
// Select all:
result := surrealdb.Select[User]("user")

// Refer to the above overview for the methods available on the result

Create

Create one record

// We can pass a map[string]any as the value
surrealdb.Create[User]("user", map[string]any {"username": "Bob"})
// Or a struct:
surrealdb.Create[User]("user", User{Username: "Bob"})
// Refer to the above overview for the methods available on the result

Update

Update one or many records

If an id is supplied for the first arg, it will update the one record with that id Otherwise, it expects a table name, where it will then update all records from that table.

This method will overwrite the entire record, if you want to update only a few fields, use the .Change() method

// We can pass a map[string]any as the value
surrealdb.Update[User]("user:12345", map[string]any {"username": "Bob"})
// Or a struct:
surrealdb.Update[User]("user:12345", User{Username: "Bob"})
// Refer to the above overview for the methods available on the result

Change

Update one or many records, but will use a MERGE operation, so it will only update the fields you specify

If an id is supplied for the first arg, it will update the one record with that id Otherwise, it expects a table name, where it will then update all records from that table.

// We can pass a map[string]any as the value
surrealdb.Change[User]("user:12345", map[string]any {"username": "Bob"})
// Or a struct:
surrealdb.Change[User]("user:12345", User{Username: "Bob"})
// Refer to the above overview for the methods available on the result

Delete

Delete one record, or all records in a table

If an id is supplied for the first arg, it will delete the one record with that id Otherwise, it expects a table name, where it will then delete all records from that table.

// We can pass a map[string]any as the value
surrealdb.Delete[User]("user:12345")
// Or a struct:
surrealdb.Delete[User]("user:12345")
// Refer to the above overview for the methods available on the result

WIP Query Builder

Example:

query := surrealdb.NewBuilder[User]("user").
    Where("username", "bob")

queryResult := query.First() // = *User{Username: "bob"}

query contains some "proxy" methods that the QueryResolvers above also have

So if you keep a reference to it, it can be used to check if there was an error and such.

For example, with the above

query := surrealdb.NewBuilder[User]("user").
Where("username", "bob")
user := query.First()

if query.HasError() {
log.Fatal(query.Error())
}
if query.IsEmpty() {
log.Fatal("No user found")
}
// Do something with user

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrInvalidLoginResponse = errors.New("invalid login response")
)
View Source
var (
	ErrInvalidToken = errors.New("token string is invalid")
)
View Source
var (
	// ErrResolvedQueryResultIsInvalid Need a better name :|
	ErrResolvedQueryResultIsInvalid = errors.New("the result from the database response is not valid, expected an array")
)
View Source
var Operators = OperatorTypes{

	Exact:           Operator{/* contains filtered or unexported fields */},
	NotEqual:        Operator{/* contains filtered or unexported fields */},
	AllEqual:        Operator{/* contains filtered or unexported fields */},
	AnyEqual:        Operator{/* contains filtered or unexported fields */},
	Equal:           Operator{/* contains filtered or unexported fields */},
	NotLike:         Operator{/* contains filtered or unexported fields */},
	AllLike:         Operator{/* contains filtered or unexported fields */},
	AnyLike:         Operator{/* contains filtered or unexported fields */},
	Like:            Operator{/* contains filtered or unexported fields */},
	LessThanOrEqual: Operator{/* contains filtered or unexported fields */},
	LessThan:        Operator{/* contains filtered or unexported fields */},
	MoreThanOrEqual: Operator{/* contains filtered or unexported fields */},
	MoreThan:        Operator{/* contains filtered or unexported fields */},
	Add:             Operator{/* contains filtered or unexported fields */},
	Sub:             Operator{/* contains filtered or unexported fields */},
	Mul:             Operator{/* contains filtered or unexported fields */},
	Div:             Operator{/* contains filtered or unexported fields */},

	And:         Operator{/* contains filtered or unexported fields */},
	Or:          Operator{/* contains filtered or unexported fields */},
	ContainAll:  Operator{/* contains filtered or unexported fields */},
	ContainAny:  Operator{/* contains filtered or unexported fields */},
	ContainNone: Operator{/* contains filtered or unexported fields */},
	NotContain:  Operator{/* contains filtered or unexported fields */},
	Contain:     Operator{/* contains filtered or unexported fields */},
	AllInside:   Operator{/* contains filtered or unexported fields */},
	AnyInside:   Operator{/* contains filtered or unexported fields */},
	NoneInside:  Operator{/* contains filtered or unexported fields */},
	NotInside:   Operator{/* contains filtered or unexported fields */},
	Inside:      Operator{/* contains filtered or unexported fields */},
	Outside:     Operator{/* contains filtered or unexported fields */},
	Intersects:  Operator{/* contains filtered or unexported fields */},
}

Functions

This section is empty.

Types

type AuthenticationResult

type AuthenticationResult struct {
	Success bool   `json:"success"`
	Token   string `json:"token"`

	TokenData
}

type ConditionType added in v0.0.8

type ConditionType string
const (
	RawCondition   ConditionType = "raw"
	BasicCondition ConditionType = "basic"
)

type DB

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

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

var Connection *DB

func New

func New(config *Config.DbConfig) (*DB, error)

New Creates a new DB instance given a WebSocket URL.

func (*DB) Authenticate

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

func (*DB) Close

func (db *DB) Close() error

Close closes the underlying WebSocket connection.

func (*DB) Info

func (db *DB) Info() (any, error)

func (*DB) Invalidate

func (db *DB) Invalidate() (any, error)

func (*DB) Kill

func (db *DB) Kill(query string) (any, error)

func (*DB) Let

func (db *DB) Let(key string, val any) (any, error)

func (*DB) Live

func (db *DB) Live(table string) (any, error)

func (*DB) Query

func (db *DB) Query(sql string, vars any) (any, error)

Query is a convenient method for sending a query to the database.

func (*DB) Signin

func (db *DB) Signin(vars UserInfo) (any, error)

Signin is a helper method for signing in a user.

func (*DB) SigninUser

func (db *DB) SigninUser(vars UserInfo) (*AuthenticationResult, error)

SigninUser is a helper method for signing in a user and returning a typed response Note: This will probably fail when signing in as a root user, but for a regular user(via a scope for example) we get a JWT response

func (*DB) Signup

func (db *DB) Signup(vars any) (any, error)

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

func (*DB) SignupUser

func (db *DB) SignupUser(vars UserInfo) (*AuthenticationResult, error)

SignupUser is a helper method for signing in a user and returning a typed response

func (*DB) Use

func (db *DB) Use(ns string, dbname string) (any, error)

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

type Model added in v0.0.8

type Model[T any] struct {
}

type Operator added in v0.0.8

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

func (*Operator) String added in v0.0.8

func (o *Operator) String() string

type OperatorTypes added in v0.0.8

type OperatorTypes struct {
	// Symbol Operators
	Exact           Operator
	NotEqual        Operator
	AllEqual        Operator
	AnyEqual        Operator
	Equal           Operator
	NotLike         Operator
	AllLike         Operator
	AnyLike         Operator
	Like            Operator
	LessThanOrEqual Operator
	LessThan        Operator
	MoreThanOrEqual Operator
	MoreThan        Operator
	Add             Operator
	Sub             Operator
	Mul             Operator
	Div             Operator

	// Phrase Operators
	And         Operator
	Or          Operator
	ContainAll  Operator
	ContainAny  Operator
	ContainNone Operator
	NotContain  Operator
	Contain     Operator
	AllInside   Operator
	AnyInside   Operator
	NoneInside  Operator
	NotInside   Operator
	Inside      Operator
	Outside     Operator
	Intersects  Operator
}

type OrderDirection added in v0.0.8

type OrderDirection string
const (
	OrderDirectionAsc  OrderDirection = "ASC"
	OrderDirectionDesc OrderDirection = "DESC"
)

type Patch

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

Patch represents a patch object set to MODIFY a record

type PermissionError

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

func (PermissionError) Error

func (pe PermissionError) Error() string

type QueryBuilder added in v0.0.8

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

func NewBuilder added in v0.0.8

func NewBuilder[T any](table ...string) *QueryBuilder[T]

func (*QueryBuilder[T]) Error added in v0.0.8

func (qb *QueryBuilder[T]) Error() error

func (*QueryBuilder[T]) Execute added in v0.0.8

func (qb *QueryBuilder[T]) Execute() *ResolvedQuery[T]

func (*QueryBuilder[T]) Fetch added in v0.0.8

func (qb *QueryBuilder[T]) Fetch(fields ...string) *QueryBuilder[T]

func (*QueryBuilder[T]) First added in v0.0.8

func (qb *QueryBuilder[T]) First() *T

func (*QueryBuilder[T]) FirstQueryResult added in v0.0.8

func (qb *QueryBuilder[T]) FirstQueryResult() *ResultQuery[T]

func (*QueryBuilder[T]) From added in v0.0.8

func (qb *QueryBuilder[T]) From(table string) *QueryBuilder[T]

From sets the table to query from(when only using one table)

func (*QueryBuilder[T]) FromMultiple added in v0.0.8

func (qb *QueryBuilder[T]) FromMultiple(tables ...string) *QueryBuilder[T]

FromMultiple sets the table to query from(when using multiple tables)

func (*QueryBuilder[T]) Get added in v0.0.8

func (qb *QueryBuilder[T]) Get() []T

func (*QueryBuilder[T]) GetParams added in v0.0.8

func (qb *QueryBuilder[T]) GetParams() map[string]any

func (*QueryBuilder[T]) GetQuery added in v0.0.8

func (qb *QueryBuilder[T]) GetQuery() string

GetQuery returns the query string

func (*QueryBuilder[T]) HasError added in v0.0.8

func (qb *QueryBuilder[T]) HasError() bool

func (*QueryBuilder[T]) IsEmpty added in v0.0.8

func (qb *QueryBuilder[T]) IsEmpty() bool

func (*QueryBuilder[T]) Limit added in v0.0.8

func (qb *QueryBuilder[T]) Limit(value int) *QueryBuilder[T]

func (*QueryBuilder[T]) OrderBy added in v0.0.8

func (qb *QueryBuilder[T]) OrderBy(field string, direction ...OrderDirection) *QueryBuilder[T]

OrderBy adds an order by clause

func (*QueryBuilder[T]) Results added in v0.0.8

func (qb *QueryBuilder[T]) Results() []ResultQuery[T]

func (*QueryBuilder[T]) Select added in v0.0.8

func (qb *QueryBuilder[T]) Select(field string, as ...string) *QueryBuilder[T]

Select adds a field to the selection

func (*QueryBuilder[T]) SelectMany added in v0.0.8

func (qb *QueryBuilder[T]) SelectMany(fields ...[]string) *QueryBuilder[T]

SelectMany adds a field to the selection This works like: .SelectMany([][]string{"FIELD NAME", "SELECT AS"}, [][]string{"USERNAME", "name"})

func (*QueryBuilder[T]) Start added in v0.0.8

func (qb *QueryBuilder[T]) Start(value int) *QueryBuilder[T]

func (*QueryBuilder[T]) TotalTimeTaken added in v0.0.8

func (qb *QueryBuilder[T]) TotalTimeTaken() time.Duration

func (*QueryBuilder[T]) Where added in v0.0.8

func (qb *QueryBuilder[T]) Where(field string, value any) *QueryBuilder[T]

Where adds a basic where x = y clause

type QueryBuilderBasicCondition added in v0.0.8

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

type QueryBuilderOrderClause added in v0.0.8

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

type QueryBuilderParam added in v0.0.8

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

func (*QueryBuilderParam) ForQuery added in v0.0.8

func (p *QueryBuilderParam) ForQuery() string

type QueryBuilderSelectField added in v0.0.8

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

type QueryConfig

type QueryConfig struct {
	Db     *DB
	Query  string
	Params any
}

type QueryGrammarBuilder added in v0.0.8

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

func BuildQueryGrammar added in v0.0.8

func BuildQueryGrammar[T any](builder *QueryBuilder[T]) *QueryGrammarBuilder[T]

func (*QueryGrammarBuilder[T]) Build added in v0.0.8

func (q *QueryGrammarBuilder[T]) Build() string

func (*QueryGrammarBuilder[T]) BuildConditions added in v0.0.8

func (q *QueryGrammarBuilder[T]) BuildConditions() string

func (*QueryGrammarBuilder[T]) BuildFetch added in v0.0.8

func (q *QueryGrammarBuilder[T]) BuildFetch() string

func (*QueryGrammarBuilder[T]) BuildOrderClauses added in v0.0.8

func (q *QueryGrammarBuilder[T]) BuildOrderClauses() string

func (*QueryGrammarBuilder[T]) BuildSelects added in v0.0.8

func (q *QueryGrammarBuilder[T]) BuildSelects() string

func (*QueryGrammarBuilder[T]) BuildTables added in v0.0.8

func (q *QueryGrammarBuilder[T]) BuildTables() string

type QueryResolver

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

type ResolvedCreateResult

type ResolvedCreateResult[T any] interface {
	HasError() bool
	Error() error
	Item() *T
}

ResolvedCreateResult Handles the results of database "create" responses Only returns one item in the response

func Create

func Create[T any, DType any | map[string]any](what string, data DType) ResolvedCreateResult[T]

Create This will create a new document It is the same as: https://surrealdb.com/docs/integration/http#create-all

type ResolvedCrudResult

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

ResolvedCrudResult Handles the results of database, create, update, delete etc responses

func NewResolvedCrudResult

func NewResolvedCrudResult[T any](response *internal.RPCRawResponse) *ResolvedCrudResult[T]

func Select added in v0.0.6

func Select[T any](what string) *ResolvedCrudResult[T]

Select this will select one or many documents It is the same as: https://surrealdb.com/docs/integration/http#select-all

func (*ResolvedCrudResult[T]) All

func (resolver *ResolvedCrudResult[T]) All() []T

All Get all the items from the query, Used when you expect > 1 result

func (*ResolvedCrudResult[T]) Error

func (resolver *ResolvedCrudResult[T]) Error() error

func (*ResolvedCrudResult[T]) First

func (resolver *ResolvedCrudResult[T]) First() *T

First Get the first item from the query Used when you expect only 1 item to be returned

func (*ResolvedCrudResult[T]) HasError

func (resolver *ResolvedCrudResult[T]) HasError() bool

func (*ResolvedCrudResult[T]) IsEmpty added in v0.0.7

func (resolver *ResolvedCrudResult[T]) IsEmpty() bool

IsEmpty Check if the response is empty

func (*ResolvedCrudResult[T]) Item

func (resolver *ResolvedCrudResult[T]) Item() *T

Item This is used for the ResolvedCreateResult interface

func (*ResolvedCrudResult[T]) Response

func (resolver *ResolvedCrudResult[T]) Response() []T

type ResolvedModifyResult

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

ResolvedModifyResult Handles the results of database, create, update, delete etc responses

func Modify

func Modify(what string, data []Patch) *ResolvedModifyResult

Modify applies a JSONPatch to the document

func NewResolvedModifyResult

func NewResolvedModifyResult(response *internal.RPCRawResponse) *ResolvedModifyResult

func (*ResolvedModifyResult) All

func (resolver *ResolvedModifyResult) All() [][]Patch

All Get all the items from the query, Used when you expect > 1 result

func (*ResolvedModifyResult) Error

func (resolver *ResolvedModifyResult) Error() error

func (*ResolvedModifyResult) First

func (resolver *ResolvedModifyResult) First() []Patch

First Get the first item from the query Used when you expect only 1 item to be returned

func (*ResolvedModifyResult) HasError

func (resolver *ResolvedModifyResult) HasError() bool

func (*ResolvedModifyResult) Response

func (resolver *ResolvedModifyResult) Response() [][]Patch

type ResolvedQuery

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

ResolvedQuery Handles the results of database "query" responses

func NewResolvedQuery

func NewResolvedQuery[T any](response *internal.RPCRawResponse) *ResolvedQuery[T]

func Query

func Query[T any](query string, params ...map[string]any) *ResolvedQuery[T]

Query creates a new query resolver Automatically uses the global db instance, ctx and uses ctx timeouts if configured

func QueryWithConfig

func QueryWithConfig[T any](config QueryConfig) *ResolvedQuery[T]

QueryWithConfig creates a new query resolver Uses a specific db instance and ctx, does not use auto ctx timeouts

func (*ResolvedQuery[T]) All

func (resolver *ResolvedQuery[T]) All() []T

All Get all the items from the query, Used when you expect > 1 result

func (*ResolvedQuery[T]) AllAreSuccessful

func (resolver *ResolvedQuery[T]) AllAreSuccessful() bool

AllAreSuccessful Check if all are results from the query have a status of "OK"

func (*ResolvedQuery[T]) Error

func (resolver *ResolvedQuery[T]) Error() error

func (*ResolvedQuery[T]) First

func (resolver *ResolvedQuery[T]) First() *T

First Get the first item from the query Used when you expect only 1 item to be returned

func (*ResolvedQuery[T]) FirstQueryResult

func (resolver *ResolvedQuery[T]) FirstQueryResult() *ResultQuery[T]

FirstQueryResult Get the first query result from the response

For clarity, our resolver.results holds something like: [{"result":[],"status":"OK","time":"29.375µs"}]

This method will return this first object: {"result":[],"status":"OK","time":"29.375µs"}

func (*ResolvedQuery[T]) HasError

func (resolver *ResolvedQuery[T]) HasError() bool

func (*ResolvedQuery[T]) IsEmpty added in v0.0.2

func (resolver *ResolvedQuery[T]) IsEmpty() bool

IsEmpty Check if the response is empty

func (*ResolvedQuery[T]) Results

func (resolver *ResolvedQuery[T]) Results() []ResultQuery[T]

func (*ResolvedQuery[T]) TotalTimeTaken

func (resolver *ResolvedQuery[T]) TotalTimeTaken() time.Duration

TotalTimeTaken Get the total time taken for all the queries to complete

type ResolvedUpdateResult

type ResolvedUpdateResult[T any] interface {
	HasError() bool
	Error() error
	First() *T
	All() []T
}

ResolvedUpdateResult Handles the results of database "create" responses Only returns one item in the response

func Change

func Change[T any, DType any | map[string]any](what string, data DType) ResolvedUpdateResult[T]

Change This will apply a "merge" change to the document It is the same as: https://surrealdb.com/docs/integration/http#modify-one

func Delete

func Delete[T any](what string) ResolvedUpdateResult[T]

Delete deletes a document or all documents

func Update

func Update[T any, DType any | map[string]any](what string, data DType) ResolvedUpdateResult[T]

Update This will apply a "replace" change to the document It is the same as: https://surrealdb.com/docs/integration/http#update-one

type ResultQuery

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

ResultQuery represents the result of a .Query() call

type SurrealModel added in v0.0.8

type SurrealModel interface {
	TableName() string
}

type TokenData

type TokenData struct {
	IssuedAt  int    `json:"iat"`
	NotBefore int    `json:"nbf"`
	ExpiresAt int    `json:"exp"`
	Issuer    string `json:"iss"`
	Namespace string `json:"ns"`
	Database  string `json:"db"`
	Scope     string `json:"sc"`
	Id        string `json:"id"`
}

func (TokenData) FromToken

func (token TokenData) FromToken(tokenString string) (TokenData, error)

type UserInfo

type UserInfo struct {
	User      string `json:"user"`
	Password  string `json:"pass"`
	Namespace string `json:"NS,omitempty"`
	Database  string `json:"DB,omitempty"`
	Scope     string `json:"SC,omitempty"`
}

UserInfo TODO: A way to make User and Password use different names via configuration This method only works if your scope is configured with those namings also, otherwise auth will fail

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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