gel

package module
v0.18.0-alpha.1 Latest Latest
Warning

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

Go to latest
Published: Feb 24, 2025 License: Apache-2.0 Imports: 4 Imported by: 1

README

The Go driver for Gel

Build Status Join GitHub discussions

Installation

In your module directory, run the following command.

$ go get github.com/geldata/gel-go

Basic Usage

Follow the Gel tutorial to get Gel installed and minimally configured.

package main

import (
	"context"
	"fmt"
	"log"

	gel "github.com/geldata/gel-go"
	"github.com/geldata/gel-go/gelcfg"
)

func main() {
	ctx := context.Background()
	client, err := gel.CreateClient(ctx, gelcfg.Options{})
	if err != nil {
		log.Fatal(err)
	}
	defer client.Close()

	var result string
	err = client.QuerySingle(ctx, "SELECT 'hello Gel!'", &result)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(result)
}

Development

A local installation of Gel is required to run tests. Download Gel from here or build it manually.

To run the test suite run make test. To run lints make lint.

License

gel-go is developed and distributed under the Apache 2.0 license.

Documentation

Overview

Package gel is the official Go driver for Gel. Additionally, github.com/geldata/gel-go/cmd/edgeql-go is a code generator that generates go functions from edgeql files.

Typical client usage looks like this:

package main

import (
    "context"
    "log"

    "github.com/geldata/gel-go"
    "github.com/geldata/gel-go/gelcfg"
)

func main() {
    ctx := context.Background()
    client, err := gel.CreateClient(ctx, gelcfg.Options{})
    if err != nil {
        log.Fatal(err)
    }
    defer client.Close()

    var (
        age   int64 = 21
        users []struct {
            ID   geltypes.UUID `gel:"id"`
            Name string   `gel:"name"`
        }
    )

    query := "SELECT User{name} FILTER .age = <int64>$0"
    err = client.Query(ctx, query, &users, age)
    ...
}

We recommend using environment variables for connection parameters. See the client connection docs for more information.

You may also connect to a database using a DSN:

url := "gel://edgedb@localhost/edgedb"
client, err := gel.CreateClientDSN(ctx, url, opts)

Or you can use Option fields.

opts := gelcfg.Options{
    Database:    "edgedb",
    User:        "edgedb",
    Concurrency: 4,
}

client, err := gel.CreateClient(ctx, opts)

Errors

gel never returns underlying errors directly. If you are checking for things like context expiration use errors.Is() or errors.As().

err := client.Query(...)
if errors.Is(err, context.Canceled) { ... }

Most errors returned by the gel package will satisfy the gelerr.Error interface which has methods for introspecting.

err := client.Query(...)

var gelErr gelerr.Error
if errors.As(err, &gelErr) && gelErr.Category(gelcfg.NoDataError){
    ...
}

Datatypes

The following list shows the marshal/unmarshal mapping between Gel types and go types:

Gel                      Go
---------                ---------
Set                      []anytype
array<anytype>           []anytype
tuple                    struct
named tuple              struct
Object                   struct
bool                     bool, geltypes.OptionalBool
bytes                    []byte, geltypes.OptionalBytes
str                      string, geltypes.OptionalStr
anyenum                  string, geltypes.OptionalStr
datetime                 time.Time, geltypes.OptionalDateTime
cal::local_datetime      geltypes.LocalDateTime,
                         geltypes.OptionalLocalDateTime
cal::local_date          geltypes.LocalDate, geltypes.OptionalLocalDate
cal::local_time          geltypes.LocalTime, geltypes.OptionalLocalTime
duration                 geltypes.Duration, geltypes.OptionalDuration
cal::relative_duration   geltypes.RelativeDuration,
                         geltypes.OptionalRelativeDuration
float32                  float32, geltypes.OptionalFloat32
float64                  float64, geltypes.OptionalFloat64
int16                    int16, geltypes.OptionalFloat16
int32                    int32, geltypes.OptionalInt16
int64                    int64, geltypes.OptionalInt64
uuid                     geltypes.UUID, geltypes.OptionalUUID
json                     []byte, geltypes.OptionalBytes
bigint                   *big.Int, geltypes.OptionalBigInt

decimal                  user defined (see Custom Marshalers)

Note that Gel's std::duration type is represented in int64 microseconds while go's time.Duration type is int64 nanoseconds. It is incorrect to cast one directly to the other.

Shape fields that are not required must use optional types for receiving query results. The gelcfg.Optional struct can be embedded to make structs optional.

type User struct {
    gelcfg.Optional
    Email string `gel:"email"`
}

var result User
err := client.QuerySingle(ctx, `SELECT User { email } LIMIT 0`, $result)
fmt.Println(result.Missing())
// Output: true

err := client.QuerySingle(ctx, `SELECT User { email } LIMIT 1`, $result)
fmt.Println(result.Missing())
// Output: false

Not all types listed above are valid query parameters. To pass a slice of scalar values use array in your query. Gel doesn't currently support using sets as parameters.

query := `select User filter .id in array_unpack(<array<uuid>>$1)`
client.QuerySingle(ctx, query, $user, []geltypes.UUID{...})

Nested structures are also not directly allowed but you can use json instead.

By default Gel will ignore embedded structs when marshaling/unmarshaling. To treat an embedded struct's fields as part of the parent struct's fields, tag the embedded struct with `gel:"$inline"`.

type Object struct {
    ID geltypes.UUID
}

type User struct {
    Object `gel:"$inline"`
    Name string
}

Custom Marshalers

Interfaces for user defined marshaler/unmarshalers are documented in the internal/marshal package.

Example
// This source file is part of the EdgeDB open source project.
//
// Copyright EdgeDB Inc. and the EdgeDB authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-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.

package main

import (
	"context"
	"fmt"
	"log"
	"time"

	gel "github.com/geldata/gel-go"
	"github.com/geldata/gel-go/gelcfg"
	"github.com/geldata/gel-go/geltypes"
)

type User struct {
	ID   geltypes.UUID `gel:"id"`
	Name string        `gel:"name"`
	DOB  time.Time     `gel:"dob"`
}

func main() {
	opts := gelcfg.Options{Concurrency: 4}
	ctx := context.Background()
	db, err := gel.CreateClientDSN(ctx, "gel://edgedb@localhost/test", opts)
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	// create a user object type.
	err = db.Execute(ctx, `
		CREATE TYPE User {
			CREATE REQUIRED PROPERTY name -> str;
			CREATE PROPERTY dob -> datetime;
		}
	`)
	if err != nil {
		log.Fatal(err)
	}

	// Insert a new user.
	var inserted struct{ id geltypes.UUID }
	err = db.QuerySingle(ctx, `
		INSERT User {
			name := <str>$0,
			dob := <datetime>$1
		}
	`, &inserted, "Bob", time.Date(1984, 3, 1, 0, 0, 0, 0, time.UTC))
	if err != nil {
		log.Fatal(err)
	}

	// Select users.
	var users []User
	args := map[string]interface{}{"name": "Bob"}
	query := "SELECT User {name, dob} FILTER .name = <str>$name"
	err = db.Query(ctx, query, &users, args)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(users)
}
Example (LinkProperty)

Link properties are treated as fields in the linked to struct, and the @ is omitted from the field's tag.

package main

import (
	"context"

	gel "github.com/geldata/gel-go"
	"github.com/geldata/gel-go/geltypes"
)

var (
	ctx    context.Context
	client *gel.Client
)

func main() {
	var result []struct {
		Name    string `gel:"name"`
		Friends []struct {
			Name     string                   `gel:"name"`
			Strength geltypes.OptionalFloat64 `gel:"strength"`
		} `gel:"friends"`
	}

	_ = client.Query(
		ctx,
		`select Person {
		name,
		friends: {
			name,
			@strength,
		}
	}`,
		&result,
	)
}

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Client

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

Client is a connection pool and is safe for concurrent use.

func CreateClient

func CreateClient(ctx context.Context, opts gelcfg.Options) (*Client, error)

CreateClient returns a new client. The client connects lazily. Call Client.EnsureConnected() to force a connection.

func CreateClientDSN

func CreateClientDSN(_ context.Context, dsn string, opts gelcfg.Options) (*Client, error)

CreateClientDSN returns a new client. See also CreateClient.

dsn is either an instance name https://www.edgedb.com/docs/clients/connection or it specifies a single string in the following format:

gel://user:password@host:port/database?option=value.

The following options are recognized: host, port, user, database, password.

func (*Client) Close

func (c *Client) Close() error

Close closes all connections in the client. Calling close blocks until all acquired connections have been released, and returns an error if called more than once.

func (*Client) EnsureConnected

func (c *Client) EnsureConnected(ctx context.Context) error

EnsureConnected forces the client to connect if it hasn't already.

func (*Client) Execute

func (c *Client) Execute(
	ctx context.Context,
	cmd string,
	args ...interface{},
) error

Execute an EdgeQL command (or commands).

func (*Client) ExecuteSQL

func (c *Client) ExecuteSQL(
	ctx context.Context,
	cmd string,
	args ...interface{},
) error

ExecuteSQL executes a SQL command (or commands).

func (*Client) Query

func (c *Client) Query(
	ctx context.Context,
	cmd string,
	out interface{},
	args ...interface{},
) error

Query runs a query and returns the results.

func (*Client) QueryJSON

func (c *Client) QueryJSON(
	ctx context.Context,
	cmd string,
	out *[]byte,
	args ...interface{},
) error

QueryJSON runs a query and return the results as JSON.

func (*Client) QuerySQL

func (c *Client) QuerySQL(
	ctx context.Context,
	cmd string,
	out interface{},
	args ...interface{},
) error

QuerySQL runs a SQL query and returns the results.

func (*Client) QuerySingle

func (c *Client) QuerySingle(
	ctx context.Context,
	cmd string,
	out interface{},
	args ...interface{},
) error

QuerySingle runs a singleton-returning query and returns its element. If the query executes successfully but doesn't return a result a NoDataError is returned. If the out argument is an optional type the out argument will be set to missing instead of returning a NoDataError.

func (*Client) QuerySingleJSON

func (c *Client) QuerySingleJSON(
	ctx context.Context,
	cmd string,
	out interface{},
	args ...interface{},
) error

QuerySingleJSON runs a singleton-returning query. If the query executes successfully but doesn't have a result a NoDataError is returned.

func (*Client) Tx

func (c *Client) Tx(ctx context.Context, action geltypes.TxBlock) error

Tx runs an action in a transaction retrying failed actions if they might succeed on a subsequent attempt.

Retries are governed by retry rules. The default rule can be set with WithRetryRule(). For more fine grained control a retry rule can be set for each defined RetryCondition using WithRetryCondition(). When a transaction fails but is retryable the rule for the failure condition is used to determine if the transaction should be tried again based on RetryRule.Attempts and the amount of time to wait before retrying is determined by RetryRule.Backoff. If either field is unset (see RetryRule) then the default rule is used. If the object's default is unset the fall back is 3 attempts and exponential backoff.

func (Client) WithConfig

func (c Client) WithConfig(
	cfg map[string]interface{},
) *Client

WithConfig sets configuration values for the returned client.

func (Client) WithGlobals

func (c Client) WithGlobals(
	globals map[string]interface{},
) *Client

WithGlobals sets values for global variables for the returned client.

func (Client) WithModuleAliases

func (c Client) WithModuleAliases(
	aliases ...gelcfg.ModuleAlias,
) *Client

WithModuleAliases sets module name aliases for the returned client.

func (Client) WithQueryOptions

func (c Client) WithQueryOptions(
	options gelcfg.QueryOptions,
) *Client

WithQueryOptions sets the gelcfg.Queryoptions for the returned Client.

func (Client) WithRetryOptions

func (c Client) WithRetryOptions(
	opts gelcfg.RetryOptions,
) *Client

WithRetryOptions returns a shallow copy of the client with the RetryOptions set to opts.

func (Client) WithTxOptions

func (c Client) WithTxOptions(
	opts gelcfg.TxOptions,
) *Client

WithTxOptions returns a shallow copy of the client with the TxOptions set to opts.

func (Client) WithWarningHandler

func (c Client) WithWarningHandler(
	warningHandler gelcfg.WarningHandler,
) *Client

WithWarningHandler sets the warning handler for the returned client. If warningHandler is nil gelcfg.LogWarnings is used.

func (Client) WithoutConfig

func (c Client) WithoutConfig(key ...string) *Client

WithoutConfig unsets configuration values for the returned client.

func (Client) WithoutGlobals

func (c Client) WithoutGlobals(globals ...string) *Client

WithoutGlobals unsets values for global variables for the returned client.

func (Client) WithoutModuleAliases

func (c Client) WithoutModuleAliases(
	aliases ...string,
) *Client

WithoutModuleAliases unsets module name aliases for the returned client.

Directories

Path Synopsis
cmd
edgeql-go command
edgeql-go is a tool to generate go functions from edgeql queries.
edgeql-go is a tool to generate go functions from edgeql queries.
cmd/generrtype command
marshal
Package marshal documents marshaling interfaces.
Package marshal documents marshaling interfaces.
snc
soc
Package soc has utilities for working with sockets.
Package soc has utilities for working with sockets.

Jump to

Keyboard shortcuts

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