{"id":13413671,"url":"https://github.com/jschoedt/go-firestorm","last_synced_at":"2025-04-09T00:30:35.277Z","repository":{"id":45436891,"uuid":"160373717","full_name":"jschoedt/go-firestorm","owner":"jschoedt","description":"Simple Go ORM for Google/Firebase Cloud Firestore","archived":false,"fork":false,"pushed_at":"2021-12-13T23:52:18.000Z","size":98,"stargazers_count":52,"open_issues_count":0,"forks_count":9,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-09-15T06:24:25.254Z","etag":null,"topics":["firebase","firestore","go","go-module","golang","google","orm","orm-framework"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jschoedt.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-12-04T14:53:53.000Z","updated_at":"2024-09-04T05:56:37.000Z","dependencies_parsed_at":"2022-09-03T02:10:23.167Z","dependency_job_id":null,"html_url":"https://github.com/jschoedt/go-firestorm","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jschoedt%2Fgo-firestorm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jschoedt%2Fgo-firestorm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jschoedt%2Fgo-firestorm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jschoedt%2Fgo-firestorm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jschoedt","download_url":"https://codeload.github.com/jschoedt/go-firestorm/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247949655,"owners_count":21023362,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["firebase","firestore","go","go-module","golang","google","orm","orm-framework"],"created_at":"2024-07-30T20:01:46.011Z","updated_at":"2025-04-09T00:30:34.963Z","avatar_url":"https://github.com/jschoedt.png","language":"Go","funding_links":[],"categories":["ORM","网络相关库","Relational Databases"],"sub_categories":["HTTP Clients","ORM","HTTP客户端","OpenGL"],"readme":"[![pipeline status](https://gitlab.com/jens.schoedt/go-firestorm/badges/master/pipeline.svg)](https://gitlab.com/jens.schoedt/go-firestorm/commits/master)\n[![coverage report](https://gitlab.com/jens.schoedt/go-firestorm/badges/master/coverage.svg)](https://gitlab.com/jens.schoedt/go-firestorm/commits/master)\n[![Go Report Card](https://goreportcard.com/badge/github.com/jschoedt/go-firestorm)](https://goreportcard.com/report/github.com/jschoedt/go-firestorm)\n[![GoDoc](https://godoc.org/github.com/jschoedt/go-firestorm?status.svg)](https://godoc.org/github.com/jschoedt/go-firestorm)\n[![GitHub](https://img.shields.io/github/license/jschoedt/go-firestorm)](https://github.com/jschoedt/go-firestorm/blob/master/LICENSE)\n\n# go-firestorm\nGo ORM ([Object-relational mapping](https://en.wikipedia.org/wiki/Object-relational_mapping)) for [Google Cloud Firestore](https://cloud.google.com/firestore/).\n\n#### Goals\n1. Easy to use\n2. Non-intrusive\n4. Non-exclusive\n3. Fast\n\n#### Features\n- Basic CRUD operations\n- Search\n- Concurrent requests support (except when run in transactions)\n- Transactions\n- Nested transactions will reuse the first transaction (reads before writes as required by firestore)\n- Configurable auto load of references\n- Handles cyclic references\n- Sub collections\n- Supports embedded/anonymous structs\n- Supports unexported fields\n- Custom mappers between fields and types\n- Caching (session + second level)\n- Supports Google App Engine - 2. Gen (go version \u003e= 1.11)\n\n\n## Getting Started\n\n* [Prerequisites](#prerequisites)\n* [Basic CRUD example](#basic-crud-example)\n* [Search](#search)\n* [Concurrent requests](#concurrent-requests)\n* [Transactions](#transactions)\n* [Cache](#cache)\n* [Configurable auto load of references](#configurable-auto-load-of-references)\n* [Customize data mapping](#customize-data-mapping)\n* [Help](#help)\n\n\n#### Prerequisites\n\nThis library only supports Firestore Native mode and not the old [Datastore](https://cloud.google.com/datastore/docs/firestore-or-datastore) mode.\n```\ngo get -u github.com/jschoedt/go-firestorm\n```\n\n#### Setup\n\n1. [Setup a Firestore client](https://firebase.google.com/docs/firestore/quickstart#set_up_your_development_environment)\n2. Create a firestorm client and supply the names of the id and parent fields of your model structs.\nParent is optional. The id field must be a string but can be called anything.\n```go\n...\nclient, _ := app.Firestore(ctx)\nfsc := firestorm.New(client, \"ID\", \"\")\n```\n3. Optional. For optimal caching to work consider adding the [CacheHandler](#cache).\n\n\n#### Basic CRUD example\n\n**Note:** Recursive Create/Delete is not supported and must be called on every entity. So to create an A-\u003eB relation. Create B first so the B.ID has been created and then create A.\n\n```go\ntype Car struct {\n\tID         string\n\tMake       string\n\tYear       time.Time\n}\n```\n```go\ncar := \u0026Car{}\ncar.Make = \"Toyota\"\ncar.Year, _ = time.Parse(time.RFC3339, \"2001-01-01T00:00:00.000Z\")\n\n// Create the entity\nfsc.NewRequest().CreateEntities(ctx, car)()\n\nif car.ID == \"\" {\n    t.Errorf(\"car should have an auto generated ID\")\n}\n\n// Read the entity by ID\notherCar := \u0026Car{ID:car.ID}\nfsc.NewRequest().GetEntities(ctx, otherCar)()\nif otherCar.Make != \"Toyota\" {\n    t.Errorf(\"car should have name: Toyota but was: %s\", otherCar.Make)\n}\nif otherCar.Year != car.Year {\n    t.Errorf(\"car should have same year: %s\", otherCar.Year)\n}\n\n// Update the entity\ncar.Make = \"Jeep\"\nfsc.NewRequest().UpdateEntities(ctx, car)()\n\notherCar := \u0026Car{ID:car.ID}\nfsc.NewRequest().GetEntities(ctx, otherCar)()\nif otherCar.Make != \"Jeep\" {\n    t.Errorf(\"car should have name: Jeep but was: %s\", otherCar.Make)\n}\n\n// Delete the entity\nfsc.NewRequest().DeleteEntities(ctx, car)()\n\notherCar = \u0026Car{ID:car.ID}\nif err := fsc.NewRequest().GetEntities(ctx, otherCar)(); err == nil {\n    t.Errorf(\"We expect a NotFoundError\")\n}\n```\n[More examples](https://github.com/jschoedt/go-firestorm/blob/master/tests/integration_test.go)\n\n#### Search\nCreate a query using the firebase client\n\n```go\ncar := \u0026Car{}\ncar.ID = \"testID\"\ncar.Make = \"Toyota\"\n\nfsc.NewRequest().CreateEntities(ctx, car)()\n\nquery := fsc.Client.Collection(\"Car\").Where(\"make\", \"==\", \"Toyota\")\n\nresult := make([]Car, 0)\nif err := fsc.NewRequest().QueryEntities(ctx, query, \u0026result)(); err != nil {\n    t.Errorf(\"car was not found by search: %v\", car)\n}\n\nif result[0].ID != car.ID || result[0].Make != car.Make {\n    t.Errorf(\"entity did not match original entity : %v\", result)\n}\n```\n[More examples](https://github.com/jschoedt/go-firestorm/blob/master/tests/integration_test.go)\n\n#### Concurrent requests\nAll CRUD operations are asynchronous and return a future func that when called will block until the operation is done.\n\n**NOTE:** the state of the entities is undefined until the future func returns.\n```go\ncar := \u0026Car{Make:\"Toyota\"}\n\n// Create the entity which returns a future func\nfuture := fsc.NewRequest().CreateEntities(ctx, car)\n\n// ID is not set\nif car.ID != \"\" {\n\tt.Errorf(\"car ID should not have been set yet\")\n}\n\n// do some more work\n\n// blocks and waits for the database to finish\nfuture()\n\n// now the car has been saved and the ID has been set\nif car.ID == \"\" {\n    t.Errorf(\"car should have an auto generated ID now\")\n}\n```\n[More examples](https://github.com/jschoedt/go-firestorm/blob/master/tests/integration_test.go)\n\n#### Transactions\nTransactions are simply done in a function using the transaction context\n\n```go\ncar := \u0026Car{Make: \"Toyota\"}\n\nfsc.DoInTransaction(ctx, func(transCtx context.Context) error {\n\n    // Create the entity in the transaction using the transCtx\n    fsc.NewRequest().CreateEntities(transCtx, car)()\n\n    // Using the transCtx we can load the entity as it is saved in the session context\n    otherCar := \u0026Car{ID:car.ID}\n    fsc.NewRequest().GetEntities(transCtx, otherCar)()\n    if otherCar.Make != car.Make {\n        t.Errorf(\"The car should have been saved in the transaction context\")\n    }\n\n    // Loading using an other context (request) will fail as the car is not created until the func returns successfully\n    if err := fsc.NewRequest().GetEntities(ctx, \u0026Car{ID:car.ID})(); err == nil {\n        t.Errorf(\"We expect a NotFoundError\")\n    }\n})\n\n// Now we can load the car as the transaction has been committed\notherCar := \u0026Car{ID:car.ID}\nfsc.NewRequest().GetEntities(ctx, otherCar)()\nif otherCar.Make != \"Toyota\" {\n    t.Errorf(\"car should have name: Toyota but was: %s\", otherCar.Make)\n}\n\n```\n\n[More examples](https://github.com/jschoedt/go-firestorm/blob/master/tests/integration_test.go)\n\n#### Cache\nFirestorm supports adding a session cache to the context.\nThe session cache only caches entities that are loaded within the same request.\n```go\n# add it to a single handler:\nhttp.HandleFunc(\"/\", firestorm.CacheHandler(otherHandler))\n# or add it to the routing chain (for gorilla/mux, go-chi etc.):\nr.Use(firestorm.CacheMiddleware)\n```\n\nTo add a second level cache (such as Redis or memcache) the Cache interface needs to be implemented and added to the client:\n```go\nfsc.SetCache(c)\n```\n\nFirestore will first try to fetch an entity from the session cache. If it is not found it will try the second level cache.\n\n#### Configurable auto load of references\n\nUse the ```req.SetLoadPaths(\"fieldName\")``` to auto load a particular field or ```req.SetLoadPaths(firestorm.AllEntities)``` to load all fields.\n\nLoad an entity path by adding multiple paths eg.: path-\u003eto-\u003efield\n\n```go\nfsc.NewRequest().SetLoadPaths(\"path\", \"path.to\", \"path.to.field\").GetEntities(ctx, car)()\n```\n\n[More examples](https://github.com/jschoedt/go-firestorm/blob/master/tests/integration_test.go)\n\n#### Customize data mapping\nThis library uses [go-structmapper](https://github.com/jschoedt/go-structmapper) for mapping values between Firestore and structs. The mapping can be customized by setting the\nmappers:\n\n```go\nfsc.MapToDB = mapper.New()\nfsc.MapFromDB = mapper.New()\n```\n\n#### Help\n\nHelp is provided in the [go-firestorm User Group](https://groups.google.com/forum/?fromgroups#!forum/go-firestorm)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjschoedt%2Fgo-firestorm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjschoedt%2Fgo-firestorm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjschoedt%2Fgo-firestorm/lists"}