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
- Variables
- func NewWithScope(ctx context.Context, f func(client *Client) error) error
- type Client
- func (c *Client) Close() error
- func (c *Client) Create(ctx context.Context, o any) (*firestore.WriteResult, error)
- func (c *Client) Delete(ctx context.Context, o any, opts ...firestore.Precondition) (*firestore.WriteResult, error)
- func (c *Client) Get(ctx context.Context, o any) error
- func (c *Client) GetAll(ctx context.Context, os any) (any, error)
- func (c *Client) GetDocumentRef(o any) *firestore.DocumentRef
- func (c *Client) GetDocumentRefListSafe(os any) ([]*firestore.DocumentRef, error)
- func (c *Client) GetDocumentRefSafe(o any) (*firestore.DocumentRef, error)
- func (c *Client) Query(target any) *Query
- func (c *Client) QueryGroup(target any) *Query
- func (c *Client) QueryGroupSafe(target any) (*Query, error)
- func (c *Client) QueryNested(parent any, target any) (*Query, error)
- func (c *Client) QuerySafe(target any) (*Query, error)
- func (c *Client) RunTransaction(ctx context.Context, f func(ctx context.Context, client *Client) error, ...) error
- func (c *Client) Set(ctx context.Context, o any, opts ...firestore.SetOption) (*firestore.WriteResult, error)
- type ProgrammingError
- type Query
- func (q *Query) EndAt(docSnapshotOrFieldValues ...interface{}) *Query
- func (q *Query) EndBefore(docSnapshotOrFieldValues ...interface{}) *Query
- func (q *Query) GetAll(ctx context.Context) error
- func (q *Query) Iter(ctx context.Context, f func(o any) error) error
- func (q *Query) Limit(n int) *Query
- func (q *Query) LimitToLast(n int) *Query
- func (q *Query) Offset(n int) *Query
- func (q *Query) OrderBy(path string, dir firestore.Direction) *Query
- func (q *Query) StartAfter(docSnapshotOrFieldValues ...interface{}) *Query
- func (q *Query) StartAt(docSnapshotOrFieldValues ...interface{}) *Query
- func (q *Query) Where(path, op string, value interface{}) *Query
- type TypeSafedClient
- func (c *TypeSafedClient[T, P]) Create(ctx context.Context, o *T) (*firestore.WriteResult, error)
- func (c *TypeSafedClient[T, P]) Delete(ctx context.Context, o *T, opts ...firestore.Precondition) (*firestore.WriteResult, error)
- func (c *TypeSafedClient[T, P]) Get(ctx context.Context, o *T) error
- func (c *TypeSafedClient[T, P]) GetAll(ctx context.Context, os []*T) ([]*T, error)
- func (c *TypeSafedClient[T, P]) GetDocumentRef(o *T) *firestore.DocumentRef
- func (c *TypeSafedClient[T, P]) Query(target *[]*T) *TypeSafedQuery[T]
- func (c *TypeSafedClient[T, P]) QueryGroup(target *[]*T) *TypeSafedQuery[T]
- func (c *TypeSafedClient[T, P]) QueryNested(parent *P, target *[]*T) (*TypeSafedQuery[T], error)
- func (c *TypeSafedClient[T, P]) Set(ctx context.Context, o *T, opts ...firestore.SetOption) (*firestore.WriteResult, error)
- type TypeSafedQuery
- func (q *TypeSafedQuery[T]) EndAt(docSnapshotOrFieldValues ...interface{}) *TypeSafedQuery[T]
- func (q *TypeSafedQuery[T]) EndBefore(docSnapshotOrFieldValues ...interface{}) *TypeSafedQuery[T]
- func (q *TypeSafedQuery[T]) GetAll(ctx context.Context) error
- func (q *TypeSafedQuery[T]) Iter(ctx context.Context, f func(o *T) error) error
- func (q *TypeSafedQuery[T]) Limit(n int) *TypeSafedQuery[T]
- func (q *TypeSafedQuery[T]) LimitToLast(n int) *TypeSafedQuery[T]
- func (q *TypeSafedQuery[T]) Offset(n int) *TypeSafedQuery[T]
- func (q *TypeSafedQuery[T]) OrderBy(path string, dir firestore.Direction) *TypeSafedQuery[T]
- func (q *TypeSafedQuery[T]) StartAfter(docSnapshotOrFieldValues ...interface{}) *TypeSafedQuery[T]
- func (q *TypeSafedQuery[T]) StartAt(docSnapshotOrFieldValues ...interface{}) *TypeSafedQuery[T]
- func (q *TypeSafedQuery[T]) Where(path, op string, value interface{}) *TypeSafedQuery[T]
Constants ¶
const ( IDFieldName = "ID" ParentFieldName = "Parent" )
Variables ¶
var KnownProjectIDEnvs = []string{
"CLOUDSDK_CORE_PROJECT",
"GOOGLE_CLOUD_PROJECT",
}
KnownProjectIDEnvs is environment variables to specify project ID
Functions ¶
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 ¶
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) Create ¶
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 ¶
Get retrieves a document from firestore o must be a pointer to a struct. Fill o with the found document.
func (*Client) GetAll ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 (*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) GetAll ¶
GetAll runs query and retrieve all results results are stored to `target` passed in `Query()`, `QueryGroup()` or `QueryNested()`
func (*Query) Iter ¶
Iter runs query and calls callback for each document A pointer to a struct is passed.
func (*Query) LimitToLast ¶
LimitToLast sets the max count of documents of the query
func (*Query) StartAfter ¶
StartAt sets the start position of the query
type TypeSafedClient ¶
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