-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathstorage_firestore.go
128 lines (105 loc) · 3.08 KB
/
storage_firestore.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package main
import (
"cloud.google.com/go/firestore"
"context"
"fmt"
"log"
"os"
"time"
)
const createdKey = "usa-internal-created"
type firestoreStorage struct {
client *firestore.Client
collectionPrefix string
}
func CreateFirestoreStorage() (*firestoreStorage, error) {
googleProjectIdEnv := "GOOGLE_PROJECT_ID"
googleProjectId := os.Getenv(googleProjectIdEnv)
if googleProjectId == "" {
return nil, fmt.Errorf("could not find environment variable %q for firestore configuration", googleProjectIdEnv)
}
ctx := context.Background()
client, err := firestore.NewClient(ctx, googleProjectId)
if value := os.Getenv("FIRESTORE_EMULATOR_HOST"); value != "" {
log.Printf("Using Firestore Emulator: %s", value)
}
if err != nil {
return nil, fmt.Errorf("could not connect to firestore: %w", err)
}
return &firestoreStorage{
client: client,
collectionPrefix: os.Getenv("GOOGLE_FIRESTORE_COLLECTION_PREFIX"),
}, nil
}
func (fs *firestoreStorage) Add(serviceName string, payload interface{}) (Entity, error) {
e, err := createEntity(payload)
if err != nil {
return e, err
}
// store created value as part of payload
data, _ := payload.(map[string]interface{})
data[createdKey] = e.Created
cn := fs.getCollectionName(serviceName)
ctx := context.Background()
_, err = fs.client.Collection(cn).Doc(e.Id).Set(ctx, payload)
if err != nil {
return Entity{}, fmt.Errorf("could not write data to firestore: %w", err)
}
return e, nil
}
func (fs *firestoreStorage) List(serviceName string) ([]Entity, error) {
ctx := context.Background()
cn := fs.getCollectionName(serviceName)
docs, err := fs.client.Collection(cn).
Documents(ctx).
GetAll()
if err != nil {
return []Entity{}, fmt.Errorf("could not list items from firestore: %w", err)
}
entities := []Entity{}
for _, doc := range docs {
data := doc.Data()
created, ok := data[createdKey].(time.Time)
if !ok {
return []Entity{}, fmt.Errorf("could not decode created value")
}
delete(data, createdKey)
entities = append(entities, Entity{
Id: doc.Ref.ID,
Created: created,
Payload: doc.Data(),
})
}
return entities, nil
}
func (fs *firestoreStorage) Get(serviceName, id string) (Entity, error) {
ctx := context.Background()
cn := fs.getCollectionName(serviceName)
doc, err := fs.client.Collection(cn).Doc(id).Get(ctx)
if err != nil {
return Entity{}, fmt.Errorf("could not find entity %q: %w", id, err)
}
data := doc.Data()
created, ok := data[createdKey].(time.Time)
if !ok {
return Entity{}, fmt.Errorf("could not decode created value")
}
delete(data, createdKey)
return Entity{
Id: doc.Ref.ID,
Created: created,
Payload: data,
}, nil
}
func (fs *firestoreStorage) Delete(serviceName, id string) error {
ctx := context.Background()
cn := fs.getCollectionName(serviceName)
_, err := fs.client.Collection(cn).Doc(id).Delete(ctx)
if err != nil {
return fmt.Errorf("could not delele entity %s: %w", id, err)
}
return nil
}
func (fs *firestoreStorage) getCollectionName(serviceName string) string {
return fmt.Sprintf("%s%s", fs.collectionPrefix, serviceName)
}