fauna

package module
v3.0.0 Latest Latest
Warning

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

Go to latest
Published: Nov 12, 2024 License: MPL-2.0 Imports: 23 Imported by: 0

README

Official Golang Driver for Fauna v10 (current)

Go Report Card Go Reference License

This driver can only be used with FQL v10, and is not compatible with earlier versions of FQL. To query your databases with earlier API versions, see the faunadb version.

See the Fauna Documentation for additional information how to configure and query your databases.

Supported Go Versions

Currently, the driver is tested on:

  • 1.19
  • 1.20
  • 1.21
  • 1.22
  • 1.23

API reference

API reference documentation for the driver is available on pkg.go.dev.

Using the Driver

For FQL templates, denote variables with ${} and pass variables as map[string]any to FQL(). You can escape a variable with by prepending an additional $.

Basic Usage
package main

import (
	"fmt"

	"github.com/fauna/fauna-go/v3"
)

func main() {
	client, clientErr := fauna.NewDefaultClient()
	if clientErr != nil {
		panic(clientErr)
	}

	createColl, _ := fauna.FQL(`Collection.create({ name: "Dogs" })`, nil)
	if _, err := client.Query(createColl); err != nil {
		panic(err)
	}

	createDog, _ := fauna.FQL(`Dogs.create({ name: ${name}})`, map[string]any{"name": "Scout"})
	res, err := client.Query(createDog)
	if err != nil {
		panic(err)
	}

	fmt.Println(res.Data.(*fauna.Document).Data["name"])
}
Using Structs
package main

import (
	"fmt"

	"github.com/fauna/fauna-go/v3"
)

type Dog struct {
	Name string `fauna:"name"`
}

func main() {
	client, clientErr := fauna.NewDefaultClient()
	if clientErr != nil {
		panic(clientErr)
	}

	createColl, _ := fauna.FQL(`Collection.create({ name: "Dogs" })`, nil)
	if _, err := client.Query(createColl); err != nil {
		panic(err)
	}

	newDog := Dog{"Scout"}
	createDog, _ := fauna.FQL(`Dogs.create(${dog})`, map[string]any{"dog": newDog})
	res, err := client.Query(createDog)
	if err != nil {
		panic(err)
	}

	var scout Dog
	if err := res.Unmarshal(&scout); err != nil {
		panic(err)
	}

	fmt.Println(scout.Name)
}
Composing Multiple Queries
package main

import (
	"fmt"

	"github.com/fauna/fauna-go/v3"
)

func addTwo(x int) *fauna.Query {
	q, _ := fauna.FQL(`${x} + 2`, map[string]any{"x": x})
	return q
}

func main() {
	client, clientErr := fauna.NewDefaultClient()
	if clientErr != nil {
		panic(clientErr)
	}

	q, _ := fauna.FQL(`${y} + 4`, map[string]any{"y": addTwo(2)})
	res, err := client.Query(q)
	if err != nil {
		panic(err)
	}

	data := res.Data.(int64)
	fmt.Println(data) // 8
}

Pagination

Use the Paginate() method to iterate sets that contain more than one page of results.

Paginate() accepts the same query options as Query().

Change the default items per page using FQL's pageSize() method.

package main

import (
	"fmt"

	"github.com/fauna/fauna-go/v3"
)

type Product struct {
	Description string `fauna:"description"`
}

func main() {
	client, clientErr := fauna.NewDefaultClient()
	if clientErr != nil {
		panic(clientErr)
	}

	// Adjust `pageSize()` size as needed.
	query, _ := fauna.FQL(`
		Product
			.byName("limes")
			.pageSize(2) { description }`, nil)

	paginator := client.Paginate(query)
	for {
		page, _ := paginator.Next()

		var pageItems []Product
		page.Unmarshal(&pageItems)

		for _, item := range pageItems {
			fmt.Println(item)
		}

		if !paginator.HasNext() {
			break
		}
	}
}

Client Configuration

Timeouts
Query Timeout

The timeout of each query. This controls the maximum amount of time Fauna will execute your query before marking it failed.

package main

import "github.com/fauna/fauna-go/v3"

func main() {
	client := fauna.NewClient("mysecret", fauna.Timeouts{QueryTimeout: 20 * time.Second})
}
Client Buffer Timeout

Time beyond QueryTimeout at which the client will abort a request if it has not received a response. The default is 5s, which should account for network latency for most clients. The value must be greater than zero. The closer to zero the value is, the more likely the client is to abort the request before the server can report a legitimate response or error.

package main

import "github.com/fauna/fauna-go/v3"

func main() {
	client := fauna.NewClient("mysecret", fauna.Timeouts{ClientBufferTimeout: 20 * time.Second})
}
Connection Timeout

The amount of time to wait for the connection to complete.

package main

import "github.com/fauna/fauna-go/v3"

func main() {
	client := fauna.NewClient("mysecret", fauna.Timeouts{ConnectionTimeout: 10 * time.Second})
}
Idle Connection Timeout

The maximum amount of time an idle (keep-alive) connection will remain idle before closing itself.

package main

import "github.com/fauna/fauna-go/v3"

func main() {
	client := fauna.NewClient("mysecret", fauna.Timeouts{IdleConnectionTimeout: 10 * time.Second})
}
Retries

By default the client will automatically retry a query if the request results in an HTTP status code 429. Retries use an exponential backoff. The maximum number of retries and maximum wait time before a retry can be configured on the client.

Maximum Attempts

The maximum number of times the client will try a query. The default is 3.

package main

import "github.com/fauna/fauna-go/v3"

func main() {
	client := fauna.NewClient("mysecret", fauna.DefaultTimeouts(), fauna.MaxAttempts(1))
}
Maximum Backoff Time

The maximum amount of time to wait before retrying a query. Retries will use an exponential backoff up to this value. The default is 20 seconds.

package main

import (
	"time"

	"github.com/fauna/fauna-go/v3"
)

func main() {
	client := fauna.NewClient("mysecret", fauna.DefaultTimeouts(), fauna.MaxBackoff(10 * time.Second))
}

Event Streaming

The driver supports Event Streaming.

Start a stream

An Event Stream lets you consume events from an event source as a real-time subscription.

To get an event source, append eventSource() or eventsOn() to a supported Set.

To start and subscribe to the stream, pass a query that produces an event source to StreamFromQuery():

type Product struct {
	Name			string	`fauna:"name"`
	Description		string	`fauna:"description"`
	Price			float64	`fauna:"price"`
}

func main() {
	client, clientErr := fauna.NewDefaultClient()
	if clientErr != nil {
		panic(clientErr)
	}

	streamQuery, _ := fauna.FQL("Product.all().eventSource()", nil)
	events, err := client.StreamFromQuery(streamQuery)
	if err != nil {
		panic(err)
	}
	defer events.Close()

	var event fauna.Event
	for {
		err := events.Next(&event)
		if err != nil {
			panic(err)
		}

		switch event.Type {
		case fauna.AddEvent, fauna.UpdateEvent, fauna.RemoveEvent:
			var product Product
			if err = event.Unmarshal(&product); err != nil {
				panic(err)
			}
			fmt.Println(product)
		}
	}
}

In query results, the driver represents an event source as an EventSource value.

To start a stream from a query result, call Stream() and pass the EventSource. This lets you output a stream alongside normal query results:

type Product struct {
	Name			string	`fauna:"name"`
	Description		string	`fauna:"description"`
	Price			float64	`fauna:"price"`
}

func main() {
	client, clientErr := fauna.NewDefaultClient()
	if clientErr != nil {
		panic(clientErr)
	}

	dataLoad, _ := fauna.FQL(`
		let products = Product.all()
		{
			Products: products.toArray(),
			Source: products.eventSource()
		}
	`, nil)

	data, err := client.Query(dataLoad)
	if err != nil {
		panic(err)
	}

	queryResult := struct {
		Products []Product
		Source fauna.EventSource
	}{}

	if err := data.Unmarshal(&queryResult); err != nil {
		panic(err)
	}

	fmt.Println("Existing products:")
	for _, product := range queryResult.Products {
		fmt.Println(product)
	}

	events, err := client.Stream(queryResult.Source)
	if err != nil {
		panic(err)
	}
	defer events.Close()

	fmt.Println("Products from streaming:")
	var event fauna.Event
	for {
		err := events.Next(&event)
		if err != nil {
			panic(err)
		}
		switch event.Type {
		case fauna.AddEvent, fauna.UpdateEvent, fauna.RemoveEvent:
			var product Product
			if err = event.Unmarshal(&product); err != nil {
				panic(err)
			}
			fmt.Println(product)
		}
	}
}
Stream options

The client configuration sets default query options for StreamFromQuery() and Stream(). To override these options, see query options.

The StreamFromQuery() and Stream() methods accept StreamOptFn functions as arguments.

Use StreamStartTime() to restart a stream at a specific timestamp:

streamQuery, _ := fauna.FQL(`Product.all().eventSource()`, nil)
tenMinutesAgo := time.Now().Add(-10 * time.Minute)

client.StreamFromQuery(streamQuery, fauna.StreamOptFn{
    fauna.StreamStartTime(tenMinutesAgo),
})

Use EventCursor() to resume a stream from an event cursor after a disconnect:

client.StreamFromQuery(streamQuery, fauna.StreamOptFn{
    fauna.EventCursor("<cursor>"),
})

For supported functions, see StreamOptFn in the API reference.

Event Feeds (beta)

The driver supports Event Feeds. See example.

Debug logging

To enable debug logging set the FAUNA_DEBUG environment variable to an integer for the value of the desired slog.Level. For Go versions 1.21 and earlier, the driver uses a log.Logger. For 1.22+, the driver uses the slog.Logger. You can optionally define your own Logger. For an example, see CustomLogger in logging_slog_test.go.

[!NOTE] The value of the Authorization header is redacted when logging.

Contributing

GitHub pull requests are very welcome.

LICENSE

Copyright 2023 Fauna, Inc.

Licensed under the Mozilla Public License, Version 2.0 (the "License"); you may not use this software except in compliance with the License. You may obtain a copy of the License at

http://mozilla.org/MPL/2.0/

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Documentation

Overview

Package fauna provides a driver for Fauna v10

Index

Examples

Constants

View Source
const (
	// EndpointDefault constant for Fauna Production endpoint
	EndpointDefault = "https://db.fauna.com"
	// EndpointLocal constant for local (Docker) endpoint
	EndpointLocal = "http://localhost:8443"

	// EnvFaunaEndpoint environment variable for Fauna Client HTTP endpoint
	EnvFaunaEndpoint = "FAUNA_ENDPOINT"
	// EnvFaunaSecret environment variable for Fauna Client authentication
	EnvFaunaSecret = "FAUNA_SECRET"
	// EnvFaunaDebug environment variable for Fauna Client logging
	EnvFaunaDebug = "FAUNA_DEBUG"

	HeaderLastTxnTs            = "X-Last-Txn-Ts"
	HeaderLinearized           = "X-Linearized"
	HeaderMaxContentionRetries = "X-Max-Contention-Retries"
	HeaderTags                 = "X-Query-Tags"
	HeaderQueryTimeoutMs       = "X-Query-Timeout-Ms"
	HeaderTraceparent          = "Traceparent"
	HeaderTypecheck            = "X-Typecheck"
)

Variables

This section is empty.

Functions

This section is empty.

Types

type Client

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

Client is the Fauna Client.

func NewClient

func NewClient(secret string, timeouts Timeouts, configFns ...ClientConfigFn) *Client

NewClient initialize a new fauna.Client with custom settings

Example

ExampleNewClient query fauna running in a local Docker instance:

docker run --rm -p 8443:8443 fauna/faunadb:latest
client := fauna.NewClient(
	// IMPORTANT: just for the purpose of example, don't actually hardcode secret
	"secret",
	fauna.DefaultTimeouts(),
	fauna.HTTPClient(http.DefaultClient),
	fauna.URL(fauna.EndpointLocal),
	fauna.Context(context.Background()),
	fauna.QueryTimeout(time.Minute*3),
)

query, qErr := fauna.FQL(`Math.abs(12e5)`, nil)
if qErr != nil {
	log.Fatalf("query failed: %s", qErr)
}

res, queryErr := client.Query(query)
if queryErr != nil {
	log.Fatalf("request failed: %s", queryErr)
}

var result float32
if err := res.Unmarshal(&result); err != nil {
	log.Fatalf("%s", queryErr)
}

fmt.Printf("%0.f", result)
Output:

1200000

func NewDefaultClient

func NewDefaultClient() (*Client, error)

NewDefaultClient initialize a fauna.Client with recommended default settings

Example

ExampleNewDefaultClient query fauna running in a local Docker instance:

docker run --rm -p 8443:8443 fauna/faunadb:latest
// IMPORTANT: just for the purpose of example, don't actually hardcode secret
_ = os.Setenv(fauna.EnvFaunaSecret, "secret")
_ = os.Setenv(fauna.EnvFaunaEndpoint, fauna.EndpointLocal)

client, clientErr := fauna.NewDefaultClient()
if clientErr != nil {
	log.Fatalf("client should have been initialized: %s", clientErr)
}

query, qErr := fauna.FQL(`Math.abs(12e5)`, nil)
if qErr != nil {
	log.Fatalf("query failed: %s", qErr)
}

res, queryErr := client.Query(query)
if queryErr != nil {
	log.Fatalf("request failed: %s", queryErr)
}

var result float32
if err := res.Unmarshal(&result); err != nil {
	log.Fatalf("%s", err)
}

fmt.Printf("%0.f", result)
Output:

1200000

func (*Client) Feed

func (c *Client) Feed(stream EventSource, opts ...FeedOptFn) (*EventFeed, error)

Feed opens an event feed from the event source

func (*Client) FeedFromQuery

func (c *Client) FeedFromQuery(query *Query, opts ...FeedOptFn) (*EventFeed, error)

FeedFromQuery opens an event feed from a query

func (*Client) GetLastTxnTime

func (c *Client) GetLastTxnTime() int64

GetLastTxnTime gets the last txn timestamp seen by the fauna.Client

func (*Client) Paginate

func (c *Client) Paginate(fql *Query, opts ...QueryOptFn) *QueryIterator

Paginate invoke fql with pagination optionally set multiple QueryOptFn

Example
// IMPORTANT: just for the purpose of example, don't actually hardcode secret
_ = os.Setenv(fauna.EnvFaunaSecret, "secret")
_ = os.Setenv(fauna.EnvFaunaEndpoint, fauna.EndpointLocal)

client, clientErr := fauna.NewDefaultClient()
if clientErr != nil {
	log.Fatalf("client should have been initialized: %s", clientErr)
}

collectionName := "pagination_sandbox"

// create a collection
deleteQuery, deleteQueryErr := fauna.FQL(`Collection.byName(${coll})?.delete()`, map[string]any{"coll": collectionName})
if deleteQueryErr != nil {
	log.Fatalf("failed to construct delete query")
}

if _, deleteErr := client.Query(deleteQuery); deleteErr != nil {
	log.Fatalf("failed to clean up collection: %t", deleteErr)
}

createQuery, createQueryErr := fauna.FQL(`Collection.create({ name: ${name} })`, map[string]any{"name": collectionName})
if createQueryErr != nil {
	log.Fatalf("failed to construct create query")
}
if _, createErr := client.Query(createQuery); createErr != nil {
	log.Fatalf("failed to create collection: %t", createErr)
}

// seed collection
collectionModule := &fauna.Module{Name: collectionName}
// update Output comment at the bottom if you change this
totalTestItems := 20

for i := 0; i < totalTestItems; i++ {
	createCollectionQuery, createItemQueryErr := fauna.FQL(`${mod}.create({ value: ${i} })`, map[string]any{
		"mod": collectionModule,
		"i":   i,
	})
	if createItemQueryErr != nil {
		log.Fatalf("failed to construct create item query: %t", createItemQueryErr)
	}

	if _, createItemErr := client.Query(createCollectionQuery); createItemErr != nil {
		log.Fatalf("failed to create seed item: %t", createItemErr)
	}
}

// paginate collection
paginationQuery, paginationQueryErr := fauna.FQL(`${mod}.all()`, map[string]any{"mod": collectionModule})
if paginationQueryErr != nil {
	log.Fatalf("failed to construct pagination query: %t", paginationQueryErr)
}

type Item struct {
	Value int `fauna:"value"`
}

var items []Item

paginator := client.Paginate(paginationQuery)
for {
	page, pageErr := paginator.Next()
	if pageErr != nil {
		log.Fatalf("pagination failed: %t", pageErr)
	}

	var pageItems []Item
	if marshalErr := page.Unmarshal(&pageItems); marshalErr != nil {
		log.Fatalf("failed to unmarshal page: %t", marshalErr)
	}

	items = append(items, pageItems...)

	if !paginator.HasNext() {
		break
	}
}

fmt.Printf("%d", len(items))
Output:

20

func (*Client) Query

func (c *Client) Query(fql *Query, opts ...QueryOptFn) (*QuerySuccess, error)

Query invoke fql optionally set multiple QueryOptFn

func (*Client) SetLastTxnTime

func (c *Client) SetLastTxnTime(txnTime time.Time)

SetLastTxnTime update the last txn time for the fauna.Client This has no effect if earlier than stored timestamp.

WARNING: This should be used only when coordinating timestamps across multiple clients. Moving the timestamp arbitrarily forward into the future will cause transactions to stall.

func (*Client) Stream

func (c *Client) Stream(stream EventSource, opts ...StreamOptFn) (*EventStream, error)

Stream initiates a stream subscription for the given stream value.

Example
// IMPORTANT: just for the purpose of example, don't actually hardcode secret
_ = os.Setenv(fauna.EnvFaunaSecret, "secret")
_ = os.Setenv(fauna.EnvFaunaEndpoint, fauna.EndpointLocal)

client, err := fauna.NewDefaultClient()
if err != nil {
	log.Fatalf("client should have been initialized: %s", err)
}

// setup a collection
setupQuery, _ := fauna.FQL(`
		if (!Collection.byName('StreamingSandbox').exists()) {
			Collection.create({ name: 'StreamingSandbox' })
        } else {
			StreamingSandbox.all().forEach(.delete())
        }
	`, nil)
if _, err := client.Query(setupQuery); err != nil {
	log.Fatalf("failed to setup the collection: %s", err)
}

// create a stream
streamQuery, _ := fauna.FQL(`StreamingSandbox.all().eventSource()`, nil)
result, err := client.Query(streamQuery)
if err != nil {
	log.Fatalf("failed to create a stream: %s", err)
}

var stream fauna.EventSource
if err := result.Unmarshal(&stream); err != nil {
	log.Fatalf("failed to unmarshal the stream value: %s", err)
}

// initiate the stream subscription
events, err := client.Stream(stream)
if err != nil {
	log.Fatalf("failed to subscribe to the stream value: %s", err)
}
defer func() {
	_ = events.Close()
}()

// produce some events while the subscription is open
createQuery, _ := fauna.FQL(`StreamingSandbox.create({ foo: 'bar' })`, nil)
updateQuery, _ := fauna.FQL(`StreamingSandbox.all().forEach(.update({ foo: 'baz' }))`, nil)
deleteQuery, _ := fauna.FQL(`StreamingSandbox.all().forEach(.delete())`, nil)

queries := []*fauna.Query{createQuery, updateQuery, deleteQuery}
for _, query := range queries {
	if _, err := client.Query(query); err != nil {
		log.Fatalf("failed execute CRUD query: %s", err)
	}
}

// fetch the produced events
type Data struct {
	Foo string `fauna:"foo"`
}

var event fauna.Event

expect := 3
for expect > 0 {
	err := events.Next(&event)
	if err != nil {
		log.Fatalf("failed to receive next event: %s", err)
	}
	switch event.Type {
	case fauna.AddEvent, fauna.UpdateEvent, fauna.RemoveEvent:
		var data Data
		if err := event.Unmarshal(&data); err != nil {
			log.Fatalf("failed to unmarshal event data: %s", err)
		}
		fmt.Printf("Event: %s Data: %+v\n", event.Type, data)
		expect--
	}
}
Output:

Event: add Data: {Foo:bar}
Event: update Data: {Foo:baz}
Event: remove Data: {Foo:baz}

func (*Client) StreamFromQuery

func (c *Client) StreamFromQuery(fql *Query, streamOpts []StreamOptFn, opts ...QueryOptFn) (*EventStream, error)

StreamFromQuery initiates a stream subscription for the fauna.Query.

This is a syntax sugar for fauna.Client.Query and fauna.Client.Subscribe.

Note that the query provided MUST return fauna.EventSource value. Otherwise, this method returns an error.

Example
// IMPORTANT: just for the purpose of example, don't actually hardcode secret
_ = os.Setenv(fauna.EnvFaunaSecret, "secret")
_ = os.Setenv(fauna.EnvFaunaEndpoint, fauna.EndpointLocal)

client, err := fauna.NewDefaultClient()
if err != nil {
	log.Fatalf("client should have been initialized: %s", err)
}

// setup a collection
setupQuery, _ := fauna.FQL(`
		if (!Collection.byName('StreamingSandbox').exists()) {
			Collection.create({ name: 'StreamingSandbox' })
        } else {
			StreamingSandbox.all().forEach(.delete())
        }
	`, nil)
if _, err := client.Query(setupQuery); err != nil {
	log.Fatalf("failed to setup the collection: %s", err)
}

// create a stream
streamQuery, _ := fauna.FQL(`StreamingSandbox.all().eventSource()`, nil)
events, err := client.StreamFromQuery(streamQuery, nil)
if err != nil {
	log.Fatalf("failed to subscribe to the stream value: %s", err)
}
defer func() {
	_ = events.Close()
}()

// produce some events while the subscription is open
createQuery, _ := fauna.FQL(`StreamingSandbox.create({ foo: 'bar' })`, nil)
updateQuery, _ := fauna.FQL(`StreamingSandbox.all().forEach(.update({ foo: 'baz' }))`, nil)
deleteQuery, _ := fauna.FQL(`StreamingSandbox.all().forEach(.delete())`, nil)

queries := []*fauna.Query{createQuery, updateQuery, deleteQuery}
for _, query := range queries {
	if _, err := client.Query(query); err != nil {
		log.Fatalf("failed execute CRUD query: %s", err)
	}
}

// fetch the produced events
type Data struct {
	Foo string `fauna:"foo"`
}

var event fauna.Event

expect := 3
for expect > 0 {
	err := events.Next(&event)
	if err != nil {
		log.Fatalf("failed to receive next event: %s", err)
	}
	switch event.Type {
	case fauna.AddEvent, fauna.UpdateEvent, fauna.RemoveEvent:
		var data Data
		if err := event.Unmarshal(&data); err != nil {
			log.Fatalf("failed to unmarshal event data: %s", err)
		}
		fmt.Printf("Event: %s Data: %+v\n", event.Type, data)
		expect--
	}
}
Output:

Event: add Data: {Foo:bar}
Event: update Data: {Foo:baz}
Event: remove Data: {Foo:baz}

func (*Client) String

func (c *Client) String() string

String fulfil Stringify interface for the fauna.Client only returns the URL to prevent logging potentially sensitive headers.

type ClientConfigFn

type ClientConfigFn func(*Client)

ClientConfigFn configuration options for the fauna.Client

func AdditionalHeaders

func AdditionalHeaders(headers map[string]string) ClientConfigFn

AdditionalHeaders specify headers for the fauna.Client

func Context

func Context(ctx context.Context) ClientConfigFn

Context specify the context to be used for the fauna.Client

func DefaultTypecheck

func DefaultTypecheck(enabled bool) ClientConfigFn

DefaultTypecheck set header on the fauna.Client Enable or disable typechecking of the query before evaluation. If not set, Fauna will use the value of the "typechecked" flag on the database configuration.

func HTTPClient

func HTTPClient(client *http.Client) ClientConfigFn

HTTPClient set the http.Client for the fauna.Client

func Linearized

func Linearized(enabled bool) ClientConfigFn

Linearized set header on the fauna.Client If true, unconditionally run the query as strictly serialized. This affects read-only transactions. Transactions which write will always be strictly serialized.

func MaxAttempts

func MaxAttempts(attempts int) ClientConfigFn

MaxAttempts sets the maximum number of times the fauna.Client will attempt to run a query, retrying if appropriate.

func MaxBackoff

func MaxBackoff(backoff time.Duration) ClientConfigFn

MaxBackoff sets the maximum duration the fauna.Client will wait before retrying.

func MaxContentionRetries

func MaxContentionRetries(i int) ClientConfigFn

MaxContentionRetries set header on the fauna.Client The max number of times to retry the query if contention is encountered.

func QueryTags

func QueryTags(tags map[string]string) ClientConfigFn

QueryTags sets header on the fauna.Client Set tags to associate with the query. See logging

func QueryTimeout

func QueryTimeout(d time.Duration) ClientConfigFn

QueryTimeout set header on the fauna.Client

func URL

func URL(url string) ClientConfigFn

URL set the fauna.Client URL

func WithLogger

func WithLogger(logger Logger) ClientConfigFn

WithLogger set the fauna.Client Logger

type ClientLogger

type ClientLogger struct {
	Logger
	// contains filtered or unexported fields
}

func (ClientLogger) Debug

func (d ClientLogger) Debug(msg string, args ...any)

func (ClientLogger) Error

func (d ClientLogger) Error(msg string, args ...any)

func (ClientLogger) Info

func (d ClientLogger) Info(msg string, args ...any)

func (ClientLogger) LogResponse

func (d ClientLogger) LogResponse(ctx context.Context, requestBody []byte, r *http.Response)

func (ClientLogger) Warn

func (d ClientLogger) Warn(msg string, args ...any)

type Document

type Document struct {
	ID   string         `fauna:"id"`
	Coll *Module        `fauna:"coll"`
	TS   *time.Time     `fauna:"ts"`
	Data map[string]any `fauna:"-"`
}

type ErrAbort

type ErrAbort struct {
	*ErrFauna
}

An ErrAbort is returned when the `abort()` function was called, which will return custom abort data in the error response.

func (*ErrAbort) Unmarshal

func (e *ErrAbort) Unmarshal(into any) error

Unmarshal decodes the Abort property into the provided object.

type ErrAuthentication

type ErrAuthentication struct {
	*ErrFauna
}

An ErrAuthentication is returned when Fauna is unable to authenticate the request due to an invalid or missing authentication token.

type ErrAuthorization

type ErrAuthorization struct {
	*ErrFauna
}

An ErrAuthorization is returned when a query attempts to access data the secret is not allowed to access.

type ErrConstraintFailure

type ErrConstraintFailure struct {
	Message string `json:"message"`
	Name    string `json:"name,omitempty"`
	Paths   []any  `json:"paths,omitempty"`
}

type ErrContendedTransaction

type ErrContendedTransaction struct {
	*ErrFauna
}

ErrContendedTransaction is returned when a transaction is aborted due to concurrent modification.

type ErrEvent

type ErrEvent struct {
	// Code is the error's code.
	Code string `json:"code"`

	// Message is the error's message.
	Message string `json:"message"`

	// Abort is the error's abort data, present if [fauna.ErrEvent.Code] is
	// equals to "abort".
	Abort any `json:"abort,omitempty"`
}

ErrEvent contains error information present in error events.

Error events with "abort" code contain its aborting value present in the fauna.ErrEvent.Abort. The aborting values can be unmarshaled with the fauna.ErrEvent.Unmarshal method.

func (*ErrEvent) Error

func (e *ErrEvent) Error() string

Error provides the underlying error message.

func (*ErrEvent) Unmarshal

func (e *ErrEvent) Unmarshal(into any) error

Unmarshal will unmarshal the raw fauna.ErrEvent.Abort (if present) into the known type provided as `into`. `into` must be a pointer to a map or struct.

type ErrFauna

type ErrFauna struct {
	*QueryInfo
	StatusCode         int                    `json:"-"`
	Code               string                 `json:"code"`
	Message            string                 `json:"message"`
	Abort              any                    `json:"abort"`
	ConstraintFailures []ErrConstraintFailure `json:"constraint_failures"`
}

An ErrFauna is the base of all errors and provides the underlying `code`, `message`, and any fauna.QueryInfo.

func (ErrFauna) Error

func (e ErrFauna) Error() string

Error provides the underlying error message.

type ErrInvalidRequest

type ErrInvalidRequest struct {
	*ErrFauna
}

An ErrInvalidRequest is returned when the request body is not valid JSON, or does not conform to the API specification

type ErrNetwork

type ErrNetwork error

An ErrNetwork is returned when an unknown error is encountered when attempting to send a request to Fauna.

type ErrQueryCheck

type ErrQueryCheck struct {
	*ErrFauna
}

An ErrQueryCheck is returned when the query fails one or more validation checks.

type ErrQueryRuntime

type ErrQueryRuntime struct {
	*ErrFauna
}

An ErrQueryRuntime is returned when the query fails due to a runtime error. The `code` field will vary based on the specific error cause.

type ErrQueryTimeout

type ErrQueryTimeout struct {
	*ErrFauna
}

An ErrQueryTimeout is returned when the client specified timeout was exceeded, but the timeout was set lower than the query's expected processing time. This response is distinguished from fauna.ServiceTimeoutError by the fact that a fauna.QueryTimeoutError response is considered a successful response for the purpose of determining the service's availability.

type ErrServiceInternal

type ErrServiceInternal struct {
	*ErrFauna
}

An ErrServiceInternal is returned when an unexpected error occurs.

type ErrServiceTimeout

type ErrServiceTimeout struct {
	*ErrFauna
}

An ErrServiceTimeout is returned when an unexpected timeout occurs.

type ErrThrottling

type ErrThrottling struct {
	*ErrFauna
}

An ErrThrottling is returned when the query exceeded some capacity limit.

type Event

type Event struct {
	// Type is this event's type.
	Type EventType
	// TxnTime is the transaction time that produce this event.
	TxnTime int64
	// Cursor is the event's cursor, used for resuming streams after crashes.
	Cursor string
	// Data is the event's data.
	Data any
	// Stats contains the ops acquired to process the event.
	Stats Stats
}

Event represents a streaming event.

EventStream of type fauna.StatusEvent have its fauna.Event.Data field set to nil. Other event's fauna.Data can be unmarshaled via the fauna.Event.Unmarshal method.

func (*Event) Unmarshal

func (e *Event) Unmarshal(into any) error

Unmarshal will unmarshal the raw fauna.Event.Data (if present) into the known type provided as `into`. `into` must be a pointer to a map or struct.

type EventFeed

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

EventFeed represents an event feed subscription.

func (*EventFeed) Next

func (ef *EventFeed) Next(page *FeedPage) error

Next retrieves the next FeedPage from the fauna.EventFeed

Example
client := fauna.NewClient("secret", fauna.DefaultTimeouts(), fauna.URL(fauna.EndpointLocal))

query, queryErr := fauna.FQL(`Collection.byName("EventFeedTest")?.delete()
Collection.create({ name: "EventFeedTest" })
EventFeedTest.all().eventSource()`, nil)
if queryErr != nil {
	log.Fatal(queryErr.Error())
}

feed, feedErr := client.FeedFromQuery(query)
if feedErr != nil {
	log.Fatal(feedErr.Error())
}

addOne, _ := fauna.FQL(`EventFeedTest.create({ foo: 'bar' })`, nil)
_, addOneErr := client.Query(addOne)
if addOneErr != nil {
	log.Fatal(addOneErr.Error())
}

for {
	var page fauna.FeedPage
	eventErr := feed.Next(&page)
	if eventErr != nil {
		log.Fatal(eventErr.Error())
	}

	for _, event := range page.Events {
		fmt.Println(event.Type)
	}

	if !page.HasNext {
		break
	}
}
Output:

add

type EventSource

type EventSource string

type EventStream

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

EventStream is an iterator of Fauna events.

The next available event can be obtained by calling the fauna.EventStream.Next method. Note this method blocks until the next event is available or the events iterator is closed via the fauna.EventStream.Close method.

The events iterator wraps an http.Response.Body reader. As per Go's current http.Response implementation, environments using HTTP/1.x may not reuse its TCP connections for the duration of its "keep-alive" time if response body is not read to completion and closed. By default, Fauna's region groups use the HTTP/2.x protocol where this restriction doesn't apply. However, if connecting to Fauna via an HTTP/1.x proxy, be aware of the events iterator closing time.

func (*EventStream) Close

func (es *EventStream) Close() (err error)

Close gracefully closes the events iterator. See fauna.EventStream for details.

func (*EventStream) Next

func (es *EventStream) Next(event *Event) (err error)

Next blocks until the next event is available.

Note that network errors of type fauna.ErrEvent are considered fatal and close the underlying stream. Calling next after an error event occurs will return an error.

type EventType

type EventType string

EventType represents a Fauna's event type.

const (
	// AddEvent happens when a new value is added to the stream's watched set.
	AddEvent EventType = "add"
	// UpdateEvent happens when a value in the stream's watched set changes.
	UpdateEvent EventType = "update"
	// RemoveEvent happens when a value in the stream's watched set is removed.
	RemoveEvent EventType = "remove"
	// StatusEvent happens periodically and communicates the stream's latest
	// transaction time as well as ops acquired during its idle period.
	StatusEvent EventType = "status"
)

type FeedOptFn

type FeedOptFn func(req *feedOptions)

FeedOptFn function to set options on the fauna.EventFeed

func EventFeedCursor

func EventFeedCursor(cursor string) FeedOptFn

EventFeedCursor set the cursor for the fauna.EventFeed cannot be used with EventFeedStartTime or in fauna.Client.FeedFromQuery

func EventFeedPageSize

func EventFeedPageSize(ts int) FeedOptFn

EventFeedPageSize set the page size for the fauna.EventFeed

func EventFeedStartTime

func EventFeedStartTime(ts time.Time) FeedOptFn

EventFeedStartTime set the start time for the fauna.EventFeed cannot be used with EventFeedCursor

func EventFeedStartTimeUnixMicros

func EventFeedStartTimeUnixMicros(ts int64) FeedOptFn

EventFeedStartTimeUnixMicros set the start time for the fauna.EventFeed cannot be used with EventFeedCursor

type FeedPage

type FeedPage struct {
	Events  []Event `json:"events"`
	Cursor  string  `json:"cursor"`
	HasNext bool    `json:"has_next"`
	Stats   Stats   `json:"stats"`
}

FeedPage represents the response from fauna.EventFeed.Next

type Logger

type Logger interface {
	Debug(msg string, args ...any)
	Info(msg string, args ...any)
	Warn(msg string, args ...any)
	Error(msg string, args ...any)
	LogResponse(ctx context.Context, requestBody []byte, r *http.Response)
}

func DefaultLogger

func DefaultLogger() Logger

DefaultLogger returns the default logger

type Module

type Module struct {
	Name string
}

type NamedDocument

type NamedDocument struct {
	Name string         `fauna:"name"`
	Coll *Module        `fauna:"coll"`
	TS   *time.Time     `fauna:"ts"`
	Data map[string]any `fauna:"-"`
}

type NamedRef

type NamedRef struct {
	Name string  `fauna:"name"`
	Coll *Module `fauna:"coll"`
}

type NullDocument

type NullDocument struct {
	Ref   *Ref   `fauna:"ref"`
	Cause string `fauna:"cause"`
}

type NullNamedDocument

type NullNamedDocument struct {
	Ref   *NamedRef `fauna:"ref"`
	Cause string    `fauna:"cause"`
}

type Page

type Page struct {
	Data  []any  `fauna:"data"`
	After string `fauna:"after"`
}

func (Page) Unmarshal

func (p Page) Unmarshal(into any) error

type Query

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

Query represents a query to be sent to Fauna.

func FQL

func FQL(query string, args map[string]any) (*Query, error)

FQL creates a fauna.Query from an FQL string and set of arguments.

args are optional. If provided their keys must match with `${name}` sigils in the query. FQL `${value} + 1` must have an argument called "value" in the args map.

The values of args can be any type, including fauna.Query to allow for query composition.

Example

ExampleFQL query fauna running in a local Docker instance:

docker run --rm -p 8443:8443 fauna/faunadb:latest
// IMPORTANT: just for the purpose of example, don't actually hardcode secret
_ = os.Setenv(fauna.EnvFaunaSecret, "secret")
_ = os.Setenv(fauna.EnvFaunaEndpoint, fauna.EndpointLocal)

client, clientErr := fauna.NewDefaultClient()
if clientErr != nil {
	log.Fatalf("client should have been initialized: %s", clientErr)
}

query, fqlErr := fauna.FQL(`2 + 2`, nil)
if fqlErr != nil {
	log.Fatalf("query failed: %s", fqlErr)
}

res, queryErr := client.Query(query)
if queryErr != nil {
	log.Fatalf("request failed: %s", queryErr)
}

fmt.Printf("%d", res.Data)
Output:

4
Example (Arguments)
// IMPORTANT: just for the purpose of example, don't actually hardcode secret
_ = os.Setenv(fauna.EnvFaunaSecret, "secret")
_ = os.Setenv(fauna.EnvFaunaEndpoint, fauna.EndpointLocal)

client, clientErr := fauna.NewDefaultClient()
if clientErr != nil {
	log.Fatalf("client should have been initialized: %s", clientErr)
}

query, fqlErr := fauna.FQL(`${num} + 2`, map[string]any{"num": 2})
if fqlErr != nil {
	log.Fatalf("query failed: %s", fqlErr)
}

res, queryErr := client.Query(query)
if queryErr != nil {
	log.Fatalf("request failed: %s", queryErr)
}

fmt.Printf("%d", res.Data)
Output:

4
Example (Composed)
// IMPORTANT: just for the purpose of example, don't actually hardcode secret
_ = os.Setenv(fauna.EnvFaunaSecret, "secret")
_ = os.Setenv(fauna.EnvFaunaEndpoint, fauna.EndpointLocal)

client, clientErr := fauna.NewDefaultClient()
if clientErr != nil {
	log.Fatalf("client should have been initialized: %s", clientErr)
}

type myObj struct {
	Value int `fauna:"value"`
}

arg := &myObj{Value: 4}

// Build a query to pull a value from some object. This could be document already
// in Fauna.
getValQuery, gvqErr := fauna.FQL(`${obj}["value"]`, map[string]any{"obj": arg})
if gvqErr != nil {
	log.Fatalf("query failed: %s", gvqErr)
}

// Compose the value query with a multiplier to multiply the value we pulled by
// some number.
query, fqlErr := fauna.FQL("${multiplier} * ${value}", map[string]any{
	"value":      getValQuery,
	"multiplier": 4,
})
if fqlErr != nil {
	log.Fatalf("query failed: %s", fqlErr)
}

res, queryErr := client.Query(query, fauna.Typecheck(true))
if queryErr != nil {
	log.Fatalf("request failed: %s", queryErr)
}

fmt.Printf("%+v", res.Data)
Output:

16
Example (Structs)
// IMPORTANT: just for the purpose of example, don't actually hardcode secret
_ = os.Setenv(fauna.EnvFaunaSecret, "secret")
_ = os.Setenv(fauna.EnvFaunaEndpoint, fauna.EndpointLocal)

client, clientErr := fauna.NewDefaultClient()
if clientErr != nil {
	log.Fatalf("client should have been initialized: %s", clientErr)
}

type myObj struct {
	Value int `fauna:"value"`
}

arg := &myObj{Value: 2}

query, fqlErr := fauna.FQL(`${obj}["value"] + 2`, map[string]any{"obj": arg})
if fqlErr != nil {
	log.Fatalf("query failed: %s", fqlErr)
}

res, queryErr := client.Query(query)
if queryErr != nil {
	log.Fatalf("request failed: %s", queryErr)
}

fmt.Printf("%d", res.Data)
Output:

4
Example (Unmarshal)
// IMPORTANT: just for the purpose of example, don't actually hardcode secret
_ = os.Setenv(fauna.EnvFaunaSecret, "secret")
_ = os.Setenv(fauna.EnvFaunaEndpoint, fauna.EndpointLocal)

client, clientErr := fauna.NewDefaultClient()
if clientErr != nil {
	log.Fatalf("client should have been initialized: %s", clientErr)
}

type myObj struct {
	Value int `fauna:"value"`
}

// Mock out an object that looks like our struct `myObj`.
query, fqlErr := fauna.FQL(`{"value": 4}`, nil)
if fqlErr != nil {
	log.Fatalf("query failed: %s", fqlErr)
}

res, queryErr := client.Query(query)
if queryErr != nil {
	log.Fatalf("request failed: %s", queryErr)
}

// Unmarshal the resulting object into a `myObj` object.
var result myObj
if err := res.Unmarshal(&result); err != nil {
	log.Fatalf("unmarshal failed: %s", queryErr)
}

fmt.Printf("%+v", result)
Output:

{Value:4}

type QueryInfo

type QueryInfo struct {
	// TxnTime is the transaction commit time in micros since epoch. Used to
	// populate the x-last-txn-ts request header in order to get a consistent
	// prefix RYOW guarantee.
	TxnTime int64

	// SchemaVersion that was used for the query execution.
	SchemaVersion int64

	// Summary is a comprehensive, human readable summary of any errors, warnings
	// and/or logs returned from the query.
	Summary string

	// QueryTags is the value of [fauna.Tags] provided with the query, if there
	// were any.
	QueryTags map[string]string

	// Stats provides access to stats generated by the query.
	Stats *Stats
}

QueryInfo provides access to information about the query.

type QueryIterator

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

QueryIterator is a fauna.Client iterator for paginated queries

func (*QueryIterator) HasNext

func (q *QueryIterator) HasNext() bool

HasNext returns whether there is another page of results

func (*QueryIterator) Next

func (q *QueryIterator) Next() (*Page, error)

Next returns the next page of results

type QueryOptFn

type QueryOptFn func(req *queryRequest)

QueryOptFn function to set options on the Client.Query

func QueryContext

func QueryContext(ctx context.Context) QueryOptFn

QueryContext set the context.Context for a single Client.Query

func Tags

func Tags(tags map[string]string) QueryOptFn

Tags set the tags header on a single Client.Query

func Timeout

func Timeout(dur time.Duration) QueryOptFn

Timeout set the query timeout on a single Client.Query

func Traceparent

func Traceparent(id string) QueryOptFn

Traceparent sets the header on a single Client.Query

func Typecheck

func Typecheck(enabled bool) QueryOptFn

Typecheck sets the header on a single Client.Query

type QuerySuccess

type QuerySuccess struct {
	*QueryInfo

	// Data is the raw result returned by the query.
	Data any

	// StaticType is the query's inferred static result type, if the query was
	// typechecked.
	StaticType string
}

QuerySuccess is the response returned from fauna.Client.Query when the query runs successfully.

func (*QuerySuccess) Unmarshal

func (r *QuerySuccess) Unmarshal(into any) error

Unmarshal will unmarshal the raw fauna.QuerySuccess.Data value into a known type provided as `into`. `into` must be a pointer to a map or struct.

type Ref

type Ref struct {
	ID   string  `fauna:"id"`
	Coll *Module `fauna:"coll"`
}

type Stats

type Stats struct {
	// ComputeOps is the amount of Transactional Compute Ops consumed by the query.
	ComputeOps int `json:"compute_ops"`

	// ReadOps is the amount of Transactional Read Ops consumed by the query.
	ReadOps int `json:"read_ops"`

	// WriteOps is amount of Transactional Write Ops consumed by the query.
	WriteOps int `json:"write_ops"`

	// QueryTimeMs is the query run time in milliseconds.
	QueryTimeMs int `json:"query_time_ms"`

	// ContentionRetries is the number of times the transaction was retried due
	// to write contention.
	ContentionRetries int `json:"contention_retries"`

	// StorageBytesRead is the amount of data read from storage, in bytes.
	StorageBytesRead int `json:"storage_bytes_read"`

	// StorageBytesWrite is the amount of data written to storage, in bytes.
	StorageBytesWrite int `json:"storage_bytes_write"`

	// ProcessingTimeMs is the amount of time producing the event, only applies to events.
	ProcessingTimeMs *int `json:"processing_time_ms,omitempty"`

	// Attempts is the number of times the client attempted to run the query.
	Attempts int `json:"_"`
}

Stats provides access to stats generated by the query.

type StreamOptFn

type StreamOptFn func(req *streamRequest)

StreamOptFn function to set options on the Client.Stream

func EventCursor

func EventCursor(cursor string) StreamOptFn

EventCursor set the stream starting point based on a previously received event cursor.

Useful when resuming a stream after a failure.

func StreamStartTime

func StreamStartTime(ts time.Time) StreamOptFn

StreamStartTime set the streams starting timestamp.

Useful when resuming a stream at a given point in time.

func StreamStartTimeUnixMicros

func StreamStartTimeUnixMicros(ts int64) StreamOptFn

StreamStartTimeUnixMicros set the stream starting timestamp.

Useful when resuming a stream at a given point in time.

type Timeouts

type Timeouts struct {
	// The timeout of each query. This controls the maximum amount of time Fauna will
	// execute your query before marking it failed.
	QueryTimeout time.Duration

	// Time beyond `QueryTimeout` at which the client will abort a request if it has not received a response.
	// The default is 5s, which should account for network latency for most clients. The value must be greater
	// than zero. The closer to zero the value is, the more likely the client is to abort the request before the
	// server can report a legitimate response or error.
	ClientBufferTimeout time.Duration

	// ConnectionTimeout amount of time to wait for the connection to complete.
	ConnectionTimeout time.Duration

	// IdleConnectionTimeout is the maximum amount of time an idle (keep-alive) connection will
	// remain idle before closing itself.
	IdleConnectionTimeout time.Duration
}

func DefaultTimeouts

func DefaultTimeouts() Timeouts

DefaultTimeouts suggested timeouts for the default fauna.Client

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

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