1package datastore
2
3import (
4	"log"
5
6	dsq "github.com/ipfs/go-datastore/query"
7)
8
9// Here are some basic datastore implementations.
10
11// MapDatastore uses a standard Go map for internal storage.
12type MapDatastore struct {
13	values map[Key][]byte
14}
15
16// NewMapDatastore constructs a MapDatastore. It is _not_ thread-safe by
17// default, wrap using sync.MutexWrap if you need thread safety (the answer here
18// is usually yes).
19func NewMapDatastore() (d *MapDatastore) {
20	return &MapDatastore{
21		values: make(map[Key][]byte),
22	}
23}
24
25// Put implements Datastore.Put
26func (d *MapDatastore) Put(key Key, value []byte) (err error) {
27	d.values[key] = value
28	return nil
29}
30
31// Sync implements Datastore.Sync
32func (d *MapDatastore) Sync(prefix Key) error {
33	return nil
34}
35
36// Get implements Datastore.Get
37func (d *MapDatastore) Get(key Key) (value []byte, err error) {
38	val, found := d.values[key]
39	if !found {
40		return nil, ErrNotFound
41	}
42	return val, nil
43}
44
45// Has implements Datastore.Has
46func (d *MapDatastore) Has(key Key) (exists bool, err error) {
47	_, found := d.values[key]
48	return found, nil
49}
50
51// GetSize implements Datastore.GetSize
52func (d *MapDatastore) GetSize(key Key) (size int, err error) {
53	if v, found := d.values[key]; found {
54		return len(v), nil
55	}
56	return -1, ErrNotFound
57}
58
59// Delete implements Datastore.Delete
60func (d *MapDatastore) Delete(key Key) (err error) {
61	delete(d.values, key)
62	return nil
63}
64
65// Query implements Datastore.Query
66func (d *MapDatastore) Query(q dsq.Query) (dsq.Results, error) {
67	re := make([]dsq.Entry, 0, len(d.values))
68	for k, v := range d.values {
69		e := dsq.Entry{Key: k.String(), Size: len(v)}
70		if !q.KeysOnly {
71			e.Value = v
72		}
73		re = append(re, e)
74	}
75	r := dsq.ResultsWithEntries(q, re)
76	r = dsq.NaiveQueryApply(q, r)
77	return r, nil
78}
79
80func (d *MapDatastore) Batch() (Batch, error) {
81	return NewBasicBatch(d), nil
82}
83
84func (d *MapDatastore) Close() error {
85	return nil
86}
87
88// NullDatastore stores nothing, but conforms to the API.
89// Useful to test with.
90type NullDatastore struct {
91}
92
93// NewNullDatastore constructs a null datastoe
94func NewNullDatastore() *NullDatastore {
95	return &NullDatastore{}
96}
97
98// Put implements Datastore.Put
99func (d *NullDatastore) Put(key Key, value []byte) (err error) {
100	return nil
101}
102
103// Sync implements Datastore.Sync
104func (d *NullDatastore) Sync(prefix Key) error {
105	return nil
106}
107
108// Get implements Datastore.Get
109func (d *NullDatastore) Get(key Key) (value []byte, err error) {
110	return nil, ErrNotFound
111}
112
113// Has implements Datastore.Has
114func (d *NullDatastore) Has(key Key) (exists bool, err error) {
115	return false, nil
116}
117
118// Has implements Datastore.GetSize
119func (d *NullDatastore) GetSize(key Key) (size int, err error) {
120	return -1, ErrNotFound
121}
122
123// Delete implements Datastore.Delete
124func (d *NullDatastore) Delete(key Key) (err error) {
125	return nil
126}
127
128// Query implements Datastore.Query
129func (d *NullDatastore) Query(q dsq.Query) (dsq.Results, error) {
130	return dsq.ResultsWithEntries(q, nil), nil
131}
132
133func (d *NullDatastore) Batch() (Batch, error) {
134	return NewBasicBatch(d), nil
135}
136
137func (d *NullDatastore) Close() error {
138	return nil
139}
140
141// LogDatastore logs all accesses through the datastore.
142type LogDatastore struct {
143	Name  string
144	child Datastore
145}
146
147// Shim is a datastore which has a child.
148type Shim interface {
149	Datastore
150
151	Children() []Datastore
152}
153
154// NewLogDatastore constructs a log datastore.
155func NewLogDatastore(ds Datastore, name string) *LogDatastore {
156	if len(name) < 1 {
157		name = "LogDatastore"
158	}
159	return &LogDatastore{Name: name, child: ds}
160}
161
162// Children implements Shim
163func (d *LogDatastore) Children() []Datastore {
164	return []Datastore{d.child}
165}
166
167// Put implements Datastore.Put
168func (d *LogDatastore) Put(key Key, value []byte) (err error) {
169	log.Printf("%s: Put %s\n", d.Name, key)
170	// log.Printf("%s: Put %s ```%s```", d.Name, key, value)
171	return d.child.Put(key, value)
172}
173
174// Sync implements Datastore.Sync
175func (d *LogDatastore) Sync(prefix Key) error {
176	log.Printf("%s: Sync %s\n", d.Name, prefix)
177	return d.child.Sync(prefix)
178}
179
180// Get implements Datastore.Get
181func (d *LogDatastore) Get(key Key) (value []byte, err error) {
182	log.Printf("%s: Get %s\n", d.Name, key)
183	return d.child.Get(key)
184}
185
186// Has implements Datastore.Has
187func (d *LogDatastore) Has(key Key) (exists bool, err error) {
188	log.Printf("%s: Has %s\n", d.Name, key)
189	return d.child.Has(key)
190}
191
192// GetSize implements Datastore.GetSize
193func (d *LogDatastore) GetSize(key Key) (size int, err error) {
194	log.Printf("%s: GetSize %s\n", d.Name, key)
195	return d.child.GetSize(key)
196}
197
198// Delete implements Datastore.Delete
199func (d *LogDatastore) Delete(key Key) (err error) {
200	log.Printf("%s: Delete %s\n", d.Name, key)
201	return d.child.Delete(key)
202}
203
204// DiskUsage implements the PersistentDatastore interface.
205func (d *LogDatastore) DiskUsage() (uint64, error) {
206	log.Printf("%s: DiskUsage\n", d.Name)
207	return DiskUsage(d.child)
208}
209
210// Query implements Datastore.Query
211func (d *LogDatastore) Query(q dsq.Query) (dsq.Results, error) {
212	log.Printf("%s: Query\n", d.Name)
213	log.Printf("%s: q.Prefix: %s\n", d.Name, q.Prefix)
214	log.Printf("%s: q.KeysOnly: %v\n", d.Name, q.KeysOnly)
215	log.Printf("%s: q.Filters: %d\n", d.Name, len(q.Filters))
216	log.Printf("%s: q.Orders: %d\n", d.Name, len(q.Orders))
217	log.Printf("%s: q.Offset: %d\n", d.Name, q.Offset)
218
219	return d.child.Query(q)
220}
221
222// LogBatch logs all accesses through the batch.
223type LogBatch struct {
224	Name  string
225	child Batch
226}
227
228func (d *LogDatastore) Batch() (Batch, error) {
229	log.Printf("%s: Batch\n", d.Name)
230	if bds, ok := d.child.(Batching); ok {
231		b, err := bds.Batch()
232
233		if err != nil {
234			return nil, err
235		}
236		return &LogBatch{
237			Name:  d.Name,
238			child: b,
239		}, nil
240	}
241	return nil, ErrBatchUnsupported
242}
243
244// Put implements Batch.Put
245func (d *LogBatch) Put(key Key, value []byte) (err error) {
246	log.Printf("%s: BatchPut %s\n", d.Name, key)
247	// log.Printf("%s: Put %s ```%s```", d.Name, key, value)
248	return d.child.Put(key, value)
249}
250
251// Delete implements Batch.Delete
252func (d *LogBatch) Delete(key Key) (err error) {
253	log.Printf("%s: BatchDelete %s\n", d.Name, key)
254	return d.child.Delete(key)
255}
256
257// Commit implements Batch.Commit
258func (d *LogBatch) Commit() (err error) {
259	log.Printf("%s: BatchCommit\n", d.Name)
260	return d.child.Commit()
261}
262
263func (d *LogDatastore) Close() error {
264	log.Printf("%s: Close\n", d.Name)
265	return d.child.Close()
266}
267
268func (d *LogDatastore) Check() error {
269	if c, ok := d.child.(CheckedDatastore); ok {
270		return c.Check()
271	}
272	return nil
273}
274
275func (d *LogDatastore) Scrub() error {
276	if c, ok := d.child.(ScrubbedDatastore); ok {
277		return c.Scrub()
278	}
279	return nil
280}
281
282func (d *LogDatastore) CollectGarbage() error {
283	if c, ok := d.child.(GCDatastore); ok {
284		return c.CollectGarbage()
285	}
286	return nil
287}
288