Popularity
2.9
Stable
Activity
1.8
Growing
47
2
9

Programming language: Go
License: MIT License
Tags: ORM    

go-firestorm alternatives and similar packages

Based on the "ORM" category.
Alternatively, view go-firestorm alternatives based on common mentions on social networks and blogs.

Do you think we are missing an alternative of go-firestorm or a related project?

Add another 'ORM' Package

README

pipeline status coverage report Go Report Card GoDoc

go-firestorm

Go ORM (Object-relational mapping) for Google Cloud Firestore.

Goals

  1. Easy to use
  2. Non intrusive
  3. Non exclusive
  4. Fast

Features

  • Basic CRUD operations
  • Search
  • Concurrent requests
  • Transactions
  • Configurable auto load of references
  • Handles cyclic references
  • Sub collections
  • Supports embedded/anonymous structs
  • Supports unexported fields
  • Custom mappers between fields and types
  • Caching
  • Supports Google App Engine - 2. Gen (go version >= 1.11)

Getting Started

Prerequisites

go get -u github.com/jschoedt/go-firestorm

Setup

  1. Setup a Firestore client
  2. Create a firestorm client and supply the names of the id and parent fields of your model structs. Parent is optional. The id field must be a string but can be called anything. go ... client, _ := app.Firestore(ctx) fsc := firestorm.New(client, "ID", "")
  3. Optional. For optimal caching to work consider adding the CacheHandler go http.HandleFunc("/", firestorm.CacheHandler(otherHandler)) #### Basic CRUD example Note: Recursive Create/Delete is not supported and must be called on every entity. So to create an A->B relation. Create B first so the B.ID has been created and the create A.
type Car struct {
    ID         string
    Make       string
    Year       time.Time
}
car := &Car{}
car.Make = "Toyota"
car.Year, _ = time.Parse(time.RFC3339, "2001-01-01T00:00:00.000Z")

// Create the entity
fsc.NewRequest().CreateEntities(ctx, car)()

if car.ID == "" {
    t.Errorf("car should have an auto generated ID")
}

// Read the entity by ID
otherCar := &Car{ID:car.ID}
fsc.NewRequest().GetEntities(ctx, otherCar)()
if otherCar.Make != "Toyota" {
    t.Errorf("car should have name: Toyota but was: %s", otherCar.Make)
}
if otherCar.Year != car.Year {
    t.Errorf("car should have same year: %s", otherCar.Year)
}

// Update the entity
car.Make = "Jeep"
fsc.NewRequest().UpdateEntities(ctx, car)()

otherCar := &Car{ID:car.ID}
fsc.NewRequest().GetEntities(ctx, otherCar)()
if otherCar.Make != "Jeep" {
    t.Errorf("car should have name: Jeep but was: %s", otherCar.Make)
}

// Delete the entity
fsc.NewRequest().DeleteEntities(ctx, car)()

otherCar = &Car{ID:car.ID}
if err := fsc.NewRequest().GetEntities(ctx, otherCar)(); err == nil {
    t.Errorf("We expect a NotFoundError")
}

More examples

Search

Create a query using the firebase client

car := &Car{}
car.ID = "testID"
car.Make = "Toyota"

fsc.NewRequest().CreateEntities(ctx, car)()

query := fsc.Client.Collection("Car").Where("make", "==", "Toyota")

result := make([]Car, 0)
if err := fsc.NewRequest().QueryEntities(ctx, query, &result)(); err != nil {
    t.Errorf("car was not found by search: %v", car)
}

if result[0].ID != car.ID || result[0].Make != car.Make {
    t.Errorf("entity did not match original entity : %v", result)
}

More examples

Concurrent requests

All CRUD operations are asynchronous and return a future func that when called will block until the operation is done.

NOTE: the state of the entities is undefined until the future func returns.

car := &Car{Make:"Toyota"}

// Create the entity which returns a future func
future := fsc.NewRequest().CreateEntities(ctx, car)

// ID is not set
if car.ID != "" {
    t.Errorf("car ID should not have been set yet")
}

// do some more work

// blocks and waits for the database to finish
future()

// now the car has been saved and the ID has been set
if car.ID == "" {
    t.Errorf("car should have an auto generated ID now")
}

More examples

Transactions

Transactions are simply done in a function using the transaction context

car := &Car{Make: "Toyota"}

fsc.DoInTransaction(ctx, func(transCtx context.Context) error {

    // Create the entity in the transaction using the transCtx
    fsc.NewRequest().CreateEntities(transCtx, car)()

    // Using the transCtx we can load the entity as it is saved in the session context
    otherCar := &Car{ID:car.ID}
    fsc.NewRequest().GetEntities(transCtx, otherCar)()
    if otherCar.Make != car.Make {
        t.Errorf("The car should have been saved in the transaction context")
    }

    // Loading using an other context (request) will fail as the car is not created until the func returns successfully
    if err := fsc.NewRequest().GetEntities(ctx, &Car{ID:car.ID})(); err == nil {
        t.Errorf("We expect a NotFoundError")
    }
})

// Now we can load the car as the transaction has been committed
otherCar := &Car{ID:car.ID}
fsc.NewRequest().GetEntities(ctx, otherCar)()
if otherCar.Make != "Toyota" {
    t.Errorf("car should have name: Toyota but was: %s", otherCar.Make)
}

More examples

Configurable auto load of references

Use the req.SetLoadPaths("fieldName") to auto load a particular field or req.SetLoadPaths(firestorm.AllEntities) to load all fields.

Load an entity path by adding multiple paths eg.: path->to->field

fsc.NewRequest().SetLoadPaths("path", "path.to", "path.to.field").GetEntities(ctx, car)()

More examples

Help

Help is provided in the go-firestorm User Group