1
2
3
4
5
6
7
8
9
10
11
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
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
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
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
125 func (c *client) Version(_ context.Context) (*driver.Version, error) {
126 return c.version, nil
127 }
128
View as plain text