1// Copyright 2017 Google LLC 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package firestore 16 17import ( 18 "context" 19 "math/rand" 20 "os" 21 "sync" 22 "time" 23) 24 25// A CollectionRef is a reference to Firestore collection. 26type CollectionRef struct { 27 c *Client 28 29 // The full resource path of the collection's parent. Typically Parent.Path, 30 // or c.path if Parent is nil. May be different if this CollectionRef was 31 // created from a stored reference to a different project/DB. Always 32 // includes /documents - that is, the parent is minimally considered to be 33 // "<db>/documents". 34 // 35 // For example, "projects/P/databases/D/documents/coll-1/doc-1". 36 parentPath string 37 38 // The shorter resource path of the collection. A collection "coll-2" in 39 // document "doc-1" in collection "coll-1" would be: "coll-1/doc-1/coll-2". 40 selfPath string 41 42 // Parent is the document of which this collection is a part. It is 43 // nil for top-level collections. 44 Parent *DocumentRef 45 46 // The full resource path of the collection: "projects/P/databases/D/documents..." 47 Path string 48 49 // ID is the collection identifier. 50 ID string 51 52 // Use the methods of Query on a CollectionRef to create and run queries. 53 Query 54} 55 56func newTopLevelCollRef(c *Client, dbPath, id string) *CollectionRef { 57 return &CollectionRef{ 58 c: c, 59 ID: id, 60 parentPath: dbPath + "/documents", 61 selfPath: id, 62 Path: dbPath + "/documents/" + id, 63 Query: Query{ 64 c: c, 65 collectionID: id, 66 path: dbPath + "/documents/" + id, 67 parentPath: dbPath + "/documents", 68 }, 69 } 70} 71 72func newCollRefWithParent(c *Client, parent *DocumentRef, id string) *CollectionRef { 73 selfPath := parent.shortPath + "/" + id 74 return &CollectionRef{ 75 c: c, 76 Parent: parent, 77 ID: id, 78 parentPath: parent.Path, 79 selfPath: selfPath, 80 Path: parent.Path + "/" + id, 81 Query: Query{ 82 c: c, 83 collectionID: id, 84 path: parent.Path + "/" + id, 85 parentPath: parent.Path, 86 }, 87 } 88} 89 90// Doc returns a DocumentRef that refers to the document in the collection with the 91// given identifier. 92func (c *CollectionRef) Doc(id string) *DocumentRef { 93 if c == nil { 94 return nil 95 } 96 return newDocRef(c, id) 97} 98 99// NewDoc returns a DocumentRef with a uniquely generated ID. 100func (c *CollectionRef) NewDoc() *DocumentRef { 101 return c.Doc(uniqueID()) 102} 103 104// Add generates a DocumentRef with a unique ID. It then creates the document 105// with the given data, which can be a map[string]interface{}, a struct or a 106// pointer to a struct. 107// 108// Add returns an error in the unlikely event that a document with the same ID 109// already exists. 110func (c *CollectionRef) Add(ctx context.Context, data interface{}) (*DocumentRef, *WriteResult, error) { 111 d := c.NewDoc() 112 wr, err := d.Create(ctx, data) 113 if err != nil { 114 return nil, nil, err 115 } 116 return d, wr, nil 117} 118 119// DocumentRefs returns references to all the documents in the collection, including 120// missing documents. A missing document is a document that does not exist but has 121// sub-documents. 122func (c *CollectionRef) DocumentRefs(ctx context.Context) *DocumentRefIterator { 123 return newDocumentRefIterator(ctx, c, nil) 124} 125 126const alphanum = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" 127 128var ( 129 rngMu sync.Mutex 130 rng = rand.New(rand.NewSource(time.Now().UnixNano() ^ int64(os.Getpid()))) 131) 132 133func uniqueID() string { 134 var b [20]byte 135 rngMu.Lock() 136 for i := 0; i < len(b); i++ { 137 b[i] = alphanum[rng.Intn(len(alphanum))] 138 } 139 rngMu.Unlock() 140 return string(b[:]) 141} 142