github.com/SaurabhDubey-Groww/go-cloud@v0.0.0-20221124105541-b26c29285fd8/docstore/memdocstore/urls.go (about) 1 // Copyright 2019 The Go Cloud Development Kit Authors 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 // https://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 15 package memdocstore 16 17 import ( 18 "context" 19 "fmt" 20 "net/url" 21 "strings" 22 "sync" 23 24 "gocloud.dev/docstore" 25 ) 26 27 func init() { 28 docstore.DefaultURLMux().RegisterCollection(Scheme, &URLOpener{}) 29 } 30 31 // Scheme is the URL scheme memdocstore registers its URLOpener under on 32 // docstore.DefaultMux. 33 const Scheme = "mem" 34 35 // URLOpener opens URLs like "mem://collection/_id". 36 // 37 // The URL's host is the name of the collection. 38 // The URL's path is used as the keyField. 39 // 40 // The following query parameters are supported: 41 // 42 // - revision_field (optional): the name of the revision field. 43 // - filename (optional): the filename to store the collection in. 44 type URLOpener struct { 45 mu sync.Mutex 46 collections map[string]urlColl 47 } 48 49 type urlColl struct { 50 keyName string 51 coll *docstore.Collection 52 } 53 54 // OpenCollectionURL opens a docstore.Collection based on u. 55 func (o *URLOpener) OpenCollectionURL(ctx context.Context, u *url.URL) (*docstore.Collection, error) { 56 q := u.Query() 57 collName := u.Host 58 if collName == "" { 59 return nil, fmt.Errorf("open collection %v: empty collection name", u) 60 } 61 keyName := u.Path 62 if strings.HasPrefix(keyName, "/") { 63 keyName = keyName[1:] 64 } 65 if keyName == "" || strings.ContainsRune(keyName, '/') { 66 return nil, fmt.Errorf("open collection %v: invalid key name %q (must be non-empty and have no slashes)", u, keyName) 67 } 68 69 options := &Options{ 70 RevisionField: q.Get("revision_field"), 71 Filename: q.Get("filename"), 72 onClose: func() { 73 o.mu.Lock() 74 delete(o.collections, collName) 75 o.mu.Unlock() 76 }, 77 } 78 q.Del("revision_field") 79 q.Del("filename") 80 for param := range q { 81 return nil, fmt.Errorf("open collection %v: invalid query parameter %q", u, param) 82 } 83 84 o.mu.Lock() 85 defer o.mu.Unlock() 86 if o.collections == nil { 87 o.collections = map[string]urlColl{} 88 } 89 ucoll, ok := o.collections[collName] 90 if !ok { 91 coll, err := OpenCollection(keyName, options) 92 if err != nil { 93 return nil, err 94 } 95 o.collections[collName] = urlColl{keyName, coll} 96 return coll, nil 97 } 98 if ucoll.keyName != keyName { 99 return nil, fmt.Errorf("open collection %v: key name %q does not equal existing key name %q", 100 u, keyName, ucoll.keyName) 101 } 102 return ucoll.coll, nil 103 }