simplestore

package module
v0.0.0-...-7b693aa Latest Latest
Warning

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

Go to latest
Published: Sep 24, 2023 License: MIT Imports: 7 Imported by: 0

Documentation

Overview

Package simplestore provides a wrapper for `cloud.google.com/go/firestore`. It handles collection names based on struct names.

Performance

simpleclient utilizes reflection, the performance is not so good.

Creating a Client

ctx := context.Background()
client, err := simplestore.NewClient(ctx)
if err != nil {
	// TODO: Handle error.
}

The Google Cloud project name can be specified via environment variables `CLOUDSDK_CORE_PROJECT`, `GOOGLE_CLOUD_PROJECT`, or determined from credentials. You can specify the project name explicitly with `NewWithProjectID` .

Struct for documents in simplestore

- simplestore treats a struct name as a collection name - simplestore requires `ID` field in structs. `ID` field is treated as document id - If a struct has a `Parent` field, it is treated as a parent document. - Mapping between structs and documents is described in [the document of `cloud.google.com/go/firestore`]:https://pkg.go.dev/cloud.google.com/go/firestore#DocumentRef.Create

Example:

type Document struct {
	ID    string
	Name  string
	Cache string `firestore:"-"`	// this field won't be stored in firestore.
}

// This document will be stored as /Document/123
doc := &Docuemnt {
	ID:   "123",
	Name: "Alice",
}

Example with parent:

type ParentDocument struct {
	ID   string
	Name string
}

type Document struct {
	Parent *ParentDocument
	ID     string
	Name   string
}

// This document will be stored as /ParentDocument/c/Document/123
doc := &Docuemnt {
	ParentDocument: &ParentDocument {
		ID:   "c",
		Name: "cryptography",
	},
	ID:   "123",
	Name: "Alice",
}

// This document will be stored as /Document/123
doc := &Docuemnt {
	ParentDocument: nil,
	ID: "123",
	Name: "Alice",
}

Reading

For a simple document:

// Retrieves document from /MyDocument/docid
doc := &MyDocument {
	ID: "docid",
}
err := client.Get(ctx, doc)	// doc must be a pointer to a struct
if err != nil {
	// TODO: Handle error.
}
fmt.Println(doc)

For multiple documents

// Retrieves document from /MyDocument/docid1 and /MyDocument/docid2
doc1 := &MyDocument {
	ID: "docid1",
}
doc2 := &MyDocument {
	ID: "docid2",
}
err := client.GetAll(ctx, []*MyDocument{doc1, doc2})
if err != nil {
	// TODO: Handle error.
}

Writing

`Create` creates a new document, and returns an error if the document already exists:

// ID is not set, and automatically generated.
// You can specify ID to use manually instead.
doc := &MyDocument {
	Name: "Alice",
}
_, err := client.Create(ctx, doc)
if err != nil {
	// TODO: Handle error.
}

`Set` creates a new document if not exist, or overwrite otherwise:

doc := &MyDocument {
	ID: "123"
	Name: "Bob",
}
_, err := client.Update(ctx, doc)
if err != nil {
	// TODO: Handle error.
}

`Delete` deletes a document.

_, err := client.Delete(ctx, doc)

Queries

You can use SQL to select documents from a collection. Begin with the collection, and build up a query using Select, Where and other methods of Query.

q := states.Where("pop", ">", 10).OrderBy("pop", firestore.Desc)

Supported operators include '<', '<=', '>', '>=', '==', 'in', 'array-contains', and 'array-contains-any'.

Call the Query's Documents method to get an iterator, and use it like the other Google Cloud Client iterators.

iter := q.Documents(ctx)
defer iter.Stop()
for {
	doc, err := iter.Next()
	if err == iterator.Done {
		break
	}
	if err != nil {
		// TODO: Handle error.
	}
	fmt.Println(doc.Data())
}

To get all the documents in a collection, you can use the collection itself as a query.

iter = client.Collection("States").Documents(ctx)

Collection Group Partition Queries

You can partition the documents of a Collection Group allowing for smaller subqueries.

collectionGroup = client.CollectionGroup("States")
partitions, err = collectionGroup.GetPartitionedQueries(ctx, 20)

You can also Serialize/Deserialize queries making it possible to run/stream the queries elsewhere; another process or machine for instance.

queryProtos := make([][]byte, 0)
for _, query := range partitions {
	protoBytes, err := query.Serialize()
	// handle err
	queryProtos = append(queryProtos, protoBytes)
	...
}

for _, protoBytes := range queryProtos {
	query, err := client.CollectionGroup("").Deserialize(protoBytes)
	...
}

Transactions

`RunTransaction` passes a new client for transaction. You can call methods just like outside of transaction.

err := client.RunTransaction(ctx, func(ctx context.Context, client *simplestore.Client) error {
	err := client.Get(ctx, doc)
	if err != nil {
		return err
	}
	doc.Name = "Bob"
	_, err = client.Set(ctx, doc)
	return err
})
if err != nil {
	// TODO: Handle error.
}

Type safed client

Many parameters of simpleclient.Client is typed `any`, and you can easily create runtime errors by passing unmached types. You can use TypeSafedClient to avoid type assertion errors:

doc := &MyDocument {
	ID: "docid",
}
err := TypeSafed[MyDocument](client).Get(ctx, doc)	// you can restrict to pass *MyDocument

Index

Constants

View Source
const (
	IDFieldName     = "ID"
	ParentFieldName = "Parent"
)

Variables

View Source
var KnownProjectIDEnvs = []string{
	"CLOUDSDK_CORE_PROJECT",
	"GOOGLE_CLOUD_PROJECT",
}

KnownProjectIDEnvs is environment variables to specify project ID

Functions

func NewWithScope

func NewWithScope(ctx context.Context, f func(client *Client) error) error

NewWithScope calls callback with new created client The client will be automatically closed.

Types

type Client

type Client struct {
	FirestoreClient      *firestore.Client
	FirestoreTransaction *firestore.Transaction
	// contains filtered or unexported fields
}

Client is a client for simplestore This wraps firestore client. You can get raw firestore client via `FirestoreClient`.

func New

func New(ctx context.Context, opts ...option.ClientOption) (*Client, error)

New returns a new client The project id can be configured via environment variables `CLOUDSDK_CORE_PROJECT`, `GOOGLE_CLOUD_PROJECT` or determined from credentials.

func NewWithProjectID

func NewWithProjectID(ctx context.Context, projectID string, opts ...option.ClientOption) (*Client, error)

NewWithProjectID returns a new client

func (*Client) Close

func (c *Client) Close() error

Close cleans resource of this client

func (*Client) Create

func (c *Client) Create(ctx context.Context, o any) (*firestore.WriteResult, error)

Create creates a new document in firestore o must be a pointer to a struct. Generates and sets ID if not set. WriteResult will be alwasys `nil` while transaction.

func (*Client) Delete

func (c *Client) Delete(ctx context.Context, o any, opts ...firestore.Precondition) (*firestore.WriteResult, error)

Delete deletes a document o must be a pointer to a struct. WriteResult will be alwasys `nil` while transaction.

func (*Client) Get

func (c *Client) Get(ctx context.Context, o any) error

Get retrieves a document from firestore o must be a pointer to a struct. Fill o with the found document.

func (*Client) GetAll

func (c *Client) GetAll(ctx context.Context, os any) (any, error)

GetAll retrieves multiple documents from firestore os must be a slice of a pointer to a struct. Fill os with found documents. Returns slice of found objects.

func (*Client) GetDocumentRef

func (c *Client) GetDocumentRef(o any) *firestore.DocumentRef

GetDocumentRef returns document ref of the object o must be a pointer to a struct. Returns nil if object is a nil. Panic if inappropriate value passed.

func (*Client) GetDocumentRefListSafe

func (c *Client) GetDocumentRefListSafe(os any) ([]*firestore.DocumentRef, error)

GetDocumentRefListSafe returns a list of document refs of the objects os must be a slice of a pointer to a struct. Be aware that return value may contain `nil`.

func (*Client) GetDocumentRefSafe

func (c *Client) GetDocumentRefSafe(o any) (*firestore.DocumentRef, error)

GetDocumentRefSafe returns document ref of the object o must be a pointer to a struct. Returns nil if object is a nil. Error if ID is not set.

func (*Client) Query

func (c *Client) Query(target any) *Query

Query starts a new query for target target must be a pointer to slice of pointers to structs. target is also used as destination of `GetAll()`. Panic if inappropriate target is specified.

func (*Client) QueryGroup

func (c *Client) QueryGroup(target any) *Query

QueryGroup starts a new query for target as collection group target must be a pointer to slice of pointers to structs. target is also used as destination of `GetAll()`. Panic if inappropriate target is specified.

func (*Client) QueryGroupSafe

func (c *Client) QueryGroupSafe(target any) (*Query, error)

QueryGroupSafe starts a new query for target as collection group target must be a pointer to slice of pointers to structs. target is also used as destination of `GetAll()`.

func (*Client) QueryNested

func (c *Client) QueryNested(parent any, target any) (*Query, error)

QueryNested starts a new query for target under the document specified by `parent` parent must be a pointer to a struct. target must be a pointer to slice of pointers to structs. target is also used as destination of `GetAll()`.

func (*Client) QuerySafe

func (c *Client) QuerySafe(target any) (*Query, error)

QuerySafe starts a new query for target target must be a pointer to slice of pointers to structs. target is also used as destination of `GetAll()`.

func (*Client) RunTransaction

func (c *Client) RunTransaction(ctx context.Context, f func(ctx context.Context, client *Client) error, opts ...firestore.TransactionOption) error

func (*Client) Set

func (c *Client) Set(ctx context.Context, o any, opts ...firestore.SetOption) (*firestore.WriteResult, error)

Set updates a document if exists nor create a new document o must be a pointer to a struct. Generates and sets ID if not set. WriteResult will be alwasys `nil` while transaction.

type ProgrammingError

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

ProgrammingError indicates an error caused by specifying inappropriate value

func NewProgrammingError

func NewProgrammingError(msg string) *ProgrammingError

NewProgrammingError returns a new ProgirammingError

func NewProgrammingErrorf

func NewProgrammingErrorf(format string, a ...any) *ProgrammingError

NewProgrammingErrorf returns a new ProgirammingError

func (*ProgrammingError) Error

func (e *ProgrammingError) Error() string

Error is an implementation for error

type Query

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

func (*Query) EndAt

func (q *Query) EndAt(docSnapshotOrFieldValues ...interface{}) *Query

EndAt sets the end position of the query

func (*Query) EndBefore

func (q *Query) EndBefore(docSnapshotOrFieldValues ...interface{}) *Query

EndBefore set the end position of the query

func (*Query) GetAll

func (q *Query) GetAll(ctx context.Context) error

GetAll runs query and retrieve all results results are stored to `target` passed in `Query()`, `QueryGroup()` or `QueryNested()`

func (*Query) Iter

func (q *Query) Iter(ctx context.Context, f func(o any) error) error

Iter runs query and calls callback for each document A pointer to a struct is passed.

func (*Query) Limit

func (q *Query) Limit(n int) *Query

Limit sets the max count of documents of the query

func (*Query) LimitToLast

func (q *Query) LimitToLast(n int) *Query

LimitToLast sets the max count of documents of the query

func (*Query) Offset

func (q *Query) Offset(n int) *Query

Offset sets the offset of the query

func (*Query) OrderBy

func (q *Query) OrderBy(path string, dir firestore.Direction) *Query

OrderBy sets the order of the query result

func (*Query) StartAfter

func (q *Query) StartAfter(docSnapshotOrFieldValues ...interface{}) *Query

StartAt sets the start position of the query

func (*Query) StartAt

func (q *Query) StartAt(docSnapshotOrFieldValues ...interface{}) *Query

StartAt sets the start position of the query

func (*Query) Where

func (q *Query) Where(path, op string, value interface{}) *Query

Where sets the condition for the query

type TypeSafedClient

type TypeSafedClient[T any, P any] struct {
	// contains filtered or unexported fields
}

TypeSafedClient is a type-restricting wrapper of Client

func TypeSafed

func TypeSafed[T any](c *Client) TypeSafedClient[T, any]

TypeSafed returns a TypeSafeClient of Client

func TypeSafedWithParent

func TypeSafedWithParent[T any, P any](c *Client) TypeSafedClient[T, P]

TypeSafedWithParent returns a TypeSafeClient of Client

func (*TypeSafedClient[T, P]) Create

func (c *TypeSafedClient[T, P]) Create(ctx context.Context, o *T) (*firestore.WriteResult, error)

Create creates a new document in firestore Generates and sets ID if not set. WriteResult will be alwasys `nil` while transaction.

func (*TypeSafedClient[T, P]) Delete

func (c *TypeSafedClient[T, P]) Delete(ctx context.Context, o *T, opts ...firestore.Precondition) (*firestore.WriteResult, error)

Delete deletes a document o must be a pointer to a struct. WriteResult will be alwasys `nil` while transaction.

func (*TypeSafedClient[T, P]) Get

func (c *TypeSafedClient[T, P]) Get(ctx context.Context, o *T) error

Get retrieves a document from firestore Fill o with the found document.

func (*TypeSafedClient[T, P]) GetAll

func (c *TypeSafedClient[T, P]) GetAll(ctx context.Context, os []*T) ([]*T, error)

GetAll retrieves multiple documents from firestore Fill os with found documents. Returns slice of found objects.

func (*TypeSafedClient[T, P]) GetDocumentRef

func (c *TypeSafedClient[T, P]) GetDocumentRef(o *T) *firestore.DocumentRef

GetDocumentRef returns document ref of the object Returns nil if object is a nil.

func (*TypeSafedClient[T, P]) Query

func (c *TypeSafedClient[T, P]) Query(target *[]*T) *TypeSafedQuery[T]

Query starts a new query for target target is also used as destination of `GetAll()`. Panic if inappropriate target is specified.

func (*TypeSafedClient[T, P]) QueryGroup

func (c *TypeSafedClient[T, P]) QueryGroup(target *[]*T) *TypeSafedQuery[T]

QueryGroupSafe starts a new query for target as collection group target is also used as destination of `GetAll()`.

func (*TypeSafedClient[T, P]) QueryNested

func (c *TypeSafedClient[T, P]) QueryNested(parent *P, target *[]*T) (*TypeSafedQuery[T], error)

QueryNested starts a new query for target under the document specified by `parent` parent must be a pointer to a struct. target is also used as destination of `GetAll()`.

func (*TypeSafedClient[T, P]) Set

func (c *TypeSafedClient[T, P]) Set(ctx context.Context, o *T, opts ...firestore.SetOption) (*firestore.WriteResult, error)

Set updates a document if exists nor create a new document Generates and sets ID if not set. WriteResult will be alwasys `nil` while transaction.

type TypeSafedQuery

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

TypeSafedQuery is a type-restricting wrapper of Query

func (*TypeSafedQuery[T]) EndAt

func (q *TypeSafedQuery[T]) EndAt(docSnapshotOrFieldValues ...interface{}) *TypeSafedQuery[T]

EndAt sets the end position of the query

func (*TypeSafedQuery[T]) EndBefore

func (q *TypeSafedQuery[T]) EndBefore(docSnapshotOrFieldValues ...interface{}) *TypeSafedQuery[T]

EndBefore set the end position of the query

func (*TypeSafedQuery[T]) GetAll

func (q *TypeSafedQuery[T]) GetAll(ctx context.Context) error

GetAll runs query and retrieve all results results are stored to `target` passed in `Query()`, `QueryGroup()` or `QueryNested()`

func (*TypeSafedQuery[T]) Iter

func (q *TypeSafedQuery[T]) Iter(ctx context.Context, f func(o *T) error) error

Iter runs query and calls callback for each document

func (*TypeSafedQuery[T]) Limit

func (q *TypeSafedQuery[T]) Limit(n int) *TypeSafedQuery[T]

Limit sets the max count of documents of the query

func (*TypeSafedQuery[T]) LimitToLast

func (q *TypeSafedQuery[T]) LimitToLast(n int) *TypeSafedQuery[T]

LimitToLast sets the max count of documents of the query

func (*TypeSafedQuery[T]) Offset

func (q *TypeSafedQuery[T]) Offset(n int) *TypeSafedQuery[T]

Offset sets the offset of the query

func (*TypeSafedQuery[T]) OrderBy

func (q *TypeSafedQuery[T]) OrderBy(path string, dir firestore.Direction) *TypeSafedQuery[T]

OrderBy sets the order of the query result

func (*TypeSafedQuery[T]) StartAfter

func (q *TypeSafedQuery[T]) StartAfter(docSnapshotOrFieldValues ...interface{}) *TypeSafedQuery[T]

StartAt sets the start position of the query

func (*TypeSafedQuery[T]) StartAt

func (q *TypeSafedQuery[T]) StartAt(docSnapshotOrFieldValues ...interface{}) *TypeSafedQuery[T]

StartAt sets the start position of the query

func (*TypeSafedQuery[T]) Where

func (q *TypeSafedQuery[T]) Where(path, op string, value interface{}) *TypeSafedQuery[T]

Where sets the condition for the query

Jump to

Keyboard shortcuts

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