github.com/go-kivik/kivik/v4@v4.3.2/x/memorydb/memory.go (about) 1 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 2 // use this file except in compliance with the License. You may obtain a copy of 3 // the License at 4 // 5 // http://www.apache.org/licenses/LICENSE-2.0 6 // 7 // Unless required by applicable law or agreed to in writing, software 8 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 // License for the specific language governing permissions and limitations under 11 // the License. 12 13 package memorydb 14 15 import ( 16 "context" 17 "encoding/json" 18 "errors" 19 "fmt" 20 "net/http" 21 "regexp" 22 "sync" 23 24 "github.com/go-kivik/kivik/v4" 25 "github.com/go-kivik/kivik/v4/driver" 26 ) 27 28 type memDriver struct{} 29 30 var _ driver.Driver = &memDriver{} 31 32 func init() { 33 kivik.Register("memory", &memDriver{}) 34 } 35 36 type client struct { 37 version *driver.Version 38 mutex sync.RWMutex 39 dbs map[string]*database 40 } 41 42 var _ driver.Client = &client{} 43 44 // Identifying constants 45 const ( 46 Version = "0.0.1" 47 Vendor = "Kivik Memory Adaptor" 48 ) 49 50 func (d *memDriver) NewClient(string, driver.Options) (driver.Client, error) { 51 return &client{ 52 version: &driver.Version{ 53 Version: Version, 54 Vendor: Vendor, 55 RawResponse: json.RawMessage(fmt.Sprintf(`{"version":"%s","vendor":{"name":"%s"}}`, Version, Vendor)), 56 }, 57 dbs: make(map[string]*database), 58 }, nil 59 } 60 61 func (c *client) AllDBs(context.Context, driver.Options) ([]string, error) { 62 dbs := make([]string, 0, len(c.dbs)) 63 for k := range c.dbs { 64 dbs = append(dbs, k) 65 } 66 return dbs, nil 67 } 68 69 func (c *client) DBExists(_ context.Context, dbName string, _ driver.Options) (bool, error) { 70 c.mutex.RLock() 71 defer c.mutex.RUnlock() 72 _, ok := c.dbs[dbName] 73 return ok, nil 74 } 75 76 // Copied verbatim from http://docs.couchdb.org/en/2.0.0/api/database/common.html#head--db 77 var ( 78 validDBName = regexp.MustCompile("^[a-z][a-z0-9_$()+/-]*$") 79 validNames = map[string]struct{}{ 80 "_users": {}, 81 "_replicator": {}, 82 } 83 ) 84 85 func (c *client) CreateDB(ctx context.Context, dbName string, options driver.Options) error { 86 if exists, _ := c.DBExists(ctx, dbName, options); exists { 87 return statusError{status: http.StatusPreconditionFailed, error: errors.New("database exists")} 88 } 89 if _, ok := validNames[dbName]; !ok { 90 if !validDBName.MatchString(dbName) { 91 return statusError{status: http.StatusBadRequest, error: errors.New("invalid database name")} 92 } 93 } 94 c.mutex.Lock() 95 defer c.mutex.Unlock() 96 c.dbs[dbName] = &database{ 97 docs: make(map[string]*document), 98 security: &driver.Security{}, 99 } 100 return nil 101 } 102 103 func (c *client) DestroyDB(ctx context.Context, dbName string, options driver.Options) error { 104 if exists, _ := c.DBExists(ctx, dbName, options); !exists { 105 return statusError{status: http.StatusNotFound, error: errors.New("database does not exist")} 106 } 107 c.mutex.Lock() 108 defer c.mutex.Unlock() 109 c.dbs[dbName].mu.Lock() 110 defer c.dbs[dbName].mu.Unlock() 111 c.dbs[dbName].deleted = true // To invalidate any outstanding db handles 112 delete(c.dbs, dbName) 113 return nil 114 } 115 116 func (c *client) DB(dbName string, _ driver.Options) (driver.DB, error) { 117 return &db{ 118 client: c, 119 dbName: dbName, 120 db: c.dbs[dbName], 121 }, nil 122 } 123 124 // Version returns the configured server info. 125 func (c *client) Version(_ context.Context) (*driver.Version, error) { 126 return c.version, nil 127 }