updated datastore
Juan Batiz-Benet committed
Oct 21, 2014 at 03:30 UTC
4cb48da228d9464d814042d6ac8198649ce5c4b9
13 files changed
+475
-110
Godeps/Godeps.json
+1
-1
@@ -68,7 +68,7 @@
68
},
69
{
70
"ImportPath": "github.com/jbenet/datastore.go",
71
- "Rev": "60ebc56447b5a8264cfed3ae3ff48deb984d7cf1"
71
+ "Rev": "da593f5071b3ce60bf45b548193863bc3c885c3c"
72
},
73
{
74
"ImportPath": "github.com/jbenet/go-base58",
Godeps/_workspace/src/github.com/jbenet/datastore.go/basic_ds_test.go
deleted
-13
@@ -1,13 +0,0 @@
1
-package datastore_test
2
-
3
-import (
4
- . "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/datastore.go"
5
- . "launchpad.net/gocheck"
6
-)
7
-
8
-// Hook up gocheck into the "go test" runner.
9
-func Test(t *testing.T) { TestingT(t) }
10
-
11
-type BasicSuite struct{}
12
-
13
-var _ = Suite(&BasicSuite{})
Godeps/_workspace/src/github.com/jbenet/datastore.go/key.go
+97
-45
@@ -1,9 +1,10 @@
1
package datastore
2
3
import (
4
- "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go-uuid/uuid"
4
"path"
5
"strings"
6
+
7
+ "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go-uuid/uuid"
8
)
9
10
/*
@@ -30,93 +31,126 @@ type Key struct {
31
string
32
}
33
34
+// NewKey constructs a key from string. it will clean the value.
35
func NewKey(s string) Key {
36
k := Key{s}
37
k.Clean()
38
return k
39
}
40
39
-// Cleans up a Key, using path.Clean.
41
+// KeyWithNamespaces constructs a key out of a namespace slice.
42
+func KeyWithNamespaces(ns []string) Key {
43
+ return NewKey(strings.Join(ns, "/"))
44
+}
45
+
46
+// Clean up a Key, using path.Clean.
47
func (k *Key) Clean() {
48
k.string = path.Clean("/" + k.string)
49
}
50
44
-// Returns the string value of Key
51
+// Strings is the string value of Key
52
func (k Key) String() string {
53
return k.string
54
}
55
49
-// Returns the bytes value of Key
56
+// Bytes returns the string value of Key as a []byte
57
func (k Key) Bytes() []byte {
58
return []byte(k.string)
59
}
60
54
-// Returns the `list` representation of this Key.
55
-// NewKey("/Comedy/MontyPython/Actor:JohnCleese").List()
56
-// ["Comedy", "MontyPythong", "Actor:JohnCleese"]
61
+// Equal checks equality of two keys
62
+func (k Key) Equal(k2 Key) bool {
63
+ return k.string == k2.string
64
+}
65
+
66
+// Less checks whether this key is sorted lower than another.
67
+func (k Key) Less(k2 Key) bool {
68
+ list1 := k.List()
69
+ list2 := k2.List()
70
+ for i, c1 := range list1 {
71
+ if len(list2) < (i + 1) {
72
+ return false
73
+ }
74
+
75
+ c2 := list2[i]
76
+ if c1 < c2 {
77
+ return true
78
+ } else if c1 > c2 {
79
+ return false
80
+ }
81
+ // c1 == c2, continue
82
+ }
83
+
84
+ // list1 is shorter or exactly the same.
85
+ return len(list1) < len(list2)
86
+}
87
+
88
+// List returns the `list` representation of this Key.
89
+// NewKey("/Comedy/MontyPython/Actor:JohnCleese").List()
90
+// ["Comedy", "MontyPythong", "Actor:JohnCleese"]
91
func (k Key) List() []string {
92
return strings.Split(k.string, "/")[1:]
93
}
94
61
-// Returns the reverse of this Key.
62
-// NewKey("/Comedy/MontyPython/Actor:JohnCleese").Reverse()
63
-// NewKey("/Actor:JohnCleese/MontyPython/Comedy")
95
+// Reverse returns the reverse of this Key.
96
+// NewKey("/Comedy/MontyPython/Actor:JohnCleese").Reverse()
97
+// NewKey("/Actor:JohnCleese/MontyPython/Comedy")
98
func (k Key) Reverse() Key {
99
l := k.List()
100
r := make([]string, len(l), len(l))
101
for i, e := range l {
102
r[len(l)-i-1] = e
103
}
70
- return NewKey(strings.Join(r, "/"))
104
+ return KeyWithNamespaces(r)
105
}
106
73
-// Returns the `namespaces` making up this Key.
74
-// NewKey("/Comedy/MontyPython/Actor:JohnCleese").List()
75
-// ["Comedy", "MontyPythong", "Actor:JohnCleese"]
107
+// Namespaces returns the `namespaces` making up this Key.
108
+// NewKey("/Comedy/MontyPython/Actor:JohnCleese").List()
109
+// ["Comedy", "MontyPythong", "Actor:JohnCleese"]
110
func (k Key) Namespaces() []string {
111
return k.List()
112
}
113
80
-// Returns the "base" namespace of this key (like path.Base(filename))
81
-// NewKey("/Comedy/MontyPython/Actor:JohnCleese").BaseNamespace()
82
-// "Actor:JohnCleese"
114
+// BaseNamespace returns the "base" namespace of this key (path.Base(filename))
115
+// NewKey("/Comedy/MontyPython/Actor:JohnCleese").BaseNamespace()
116
+// "Actor:JohnCleese"
117
func (k Key) BaseNamespace() string {
118
n := k.Namespaces()
119
return n[len(n)-1]
120
}
121
88
-// Returns the "type" of this key (value of last namespace).
89
-// NewKey("/Comedy/MontyPython/Actor:JohnCleese").List()
90
-// "Actor"
122
+// Type returns the "type" of this key (value of last namespace).
123
+// NewKey("/Comedy/MontyPython/Actor:JohnCleese").List()
124
+// "Actor"
125
func (k Key) Type() string {
126
return NamespaceType(k.BaseNamespace())
127
}
128
95
-// Returns the "name" of this key (field of last namespace).
96
-// NewKey("/Comedy/MontyPython/Actor:JohnCleese").List()
97
-// "Actor"
129
+// Name returns the "name" of this key (field of last namespace).
130
+// NewKey("/Comedy/MontyPython/Actor:JohnCleese").List()
131
+// "Actor"
132
func (k Key) Name() string {
133
return NamespaceValue(k.BaseNamespace())
134
}
135
102
-// Returns an "instance" of this type key (appends value to namespace).
103
-// NewKey("/Comedy/MontyPython/Actor:JohnCleese").List()
104
-// "JohnCleese"
136
+// Instance returns an "instance" of this type key (appends value to namespace).
137
+// NewKey("/Comedy/MontyPython/Actor:JohnCleese").List()
138
+// "JohnCleese"
139
func (k Key) Instance(s string) Key {
140
return NewKey(k.string + ":" + s)
141
}
142
109
-// Returns the "path" of this key (parent + type).
110
-// NewKey("/Comedy/MontyPython/Actor:JohnCleese").Path()
111
-// NewKey("/Comedy/MontyPython/Actor")
143
+// Path returns the "path" of this key (parent + type).
144
+// NewKey("/Comedy/MontyPython/Actor:JohnCleese").Path()
145
+// NewKey("/Comedy/MontyPython/Actor")
146
func (k Key) Path() Key {
147
s := k.Parent().string + "/" + NamespaceType(k.BaseNamespace())
148
return NewKey(s)
149
}
150
117
-// Returns the `parent` Key of this Key.
118
-// NewKey("/Comedy/MontyPython/Actor:JohnCleese").Parent()
119
-// NewKey("/Comedy/MontyPython")
151
+// Parent returns the `parent` Key of this Key.
152
+// NewKey("/Comedy/MontyPython/Actor:JohnCleese").Parent()
153
+// NewKey("/Comedy/MontyPython")
154
func (k Key) Parent() Key {
155
n := k.List()
156
if len(n) == 1 {
@@ -125,16 +159,23 @@ func (k Key) Parent() Key {
159
return NewKey(strings.Join(n[:len(n)-1], "/"))
160
}
161
128
-// Returns the `child` Key of this Key.
129
-// NewKey("/Comedy/MontyPython").Child("Actor:JohnCleese")
130
-// NewKey("/Comedy/MontyPython/Actor:JohnCleese")
131
-func (k Key) Child(s string) Key {
162
+// Child returns the `child` Key of this Key.
163
+// NewKey("/Comedy/MontyPython").Child("Actor:JohnCleese")
164
+// NewKey("/Comedy/MontyPython/Actor:JohnCleese")
165
+func (k Key) Child(k2 Key) Key {
166
+ return NewKey(k.string + "/" + k2.string)
167
+}
168
+
169
+// ChildString returns the `child` Key of this Key -- string helper.
170
+// NewKey("/Comedy/MontyPython").Child("Actor:JohnCleese")
171
+// NewKey("/Comedy/MontyPython/Actor:JohnCleese")
172
+func (k Key) ChildString(s string) Key {
173
return NewKey(k.string + "/" + s)
174
}
175
135
-// Returns whether this key is an ancestor of `other`
136
-// NewKey("/Comedy").IsAncestorOf("/Comedy/MontyPython")
137
-// true
176
+// IsAncestorOf returns whether this key is a prefix of `other`
177
+// NewKey("/Comedy").IsAncestorOf("/Comedy/MontyPython")
178
+// true
179
func (k Key) IsAncestorOf(other Key) bool {
180
if other.string == k.string {
181
return false
@@ -142,9 +183,9 @@ func (k Key) IsAncestorOf(other Key) bool {
183
return strings.HasPrefix(other.string, k.string)
184
}
185
145
-// Returns whether this key is a descendent of `other`
146
-// NewKey("/Comedy/MontyPython").IsDescendantOf("/Comedy")
147
-// true
186
+// IsDescendantOf returns whether this key contains another as a prefix.
187
+// NewKey("/Comedy/MontyPython").IsDescendantOf("/Comedy")
188
+// true
189
func (k Key) IsDescendantOf(other Key) bool {
190
if other.string == k.string {
191
return false
@@ -152,13 +193,14 @@ func (k Key) IsDescendantOf(other Key) bool {
193
return strings.HasPrefix(k.string, other.string)
194
}
195
196
+// IsTopLevel returns whether this key has only one namespace.
197
func (k Key) IsTopLevel() bool {
198
return len(k.List()) == 1
199
}
200
159
-// Returns a randomly (uuid) generated key.
160
-// RandomKey()
161
-// NewKey("/f98719ea086343f7b71f32ea9d9d521d")
201
+// RandomKey returns a randomly (uuid) generated key.
202
+// RandomKey()
203
+// NewKey("/f98719ea086343f7b71f32ea9d9d521d")
204
func RandomKey() Key {
205
return NewKey(strings.Replace(uuid.New(), "-", "", -1))
206
}
@@ -175,6 +217,7 @@ A namespace can optionally include a type (delimited by ':')
217
Music:Song
218
*/
219
220
+// NamespaceType is the first component of a namespace. `foo` in `foo:bar`
221
func NamespaceType(namespace string) string {
222
parts := strings.Split(namespace, ":")
223
if len(parts) < 2 {
@@ -183,7 +226,16 @@ func NamespaceType(namespace string) string {
226
return strings.Join(parts[0:len(parts)-1], ":")
227
}
228
229
+// NamespaceValue returns the last component of a namespace. `baz` in `f:b:baz`
230
func NamespaceValue(namespace string) string {
231
parts := strings.Split(namespace, ":")
232
return parts[len(parts)-1]
233
}
234
+
235
+// KeySlice attaches the methods of sort.Interface to []Key,
236
+// sorting in increasing order.
237
+type KeySlice []Key
238
+
239
+func (p KeySlice) Len() int { return len(p) }
240
+func (p KeySlice) Less(i, j int) bool { return p[i].Less(p[j]) }
241
+func (p KeySlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
Godeps/_workspace/src/github.com/jbenet/datastore.go/key_test.go
+32
-3
@@ -54,14 +54,24 @@ func (ks *KeySuite) SubtestKey(s string, c *C) {
54
c.Check(NewKey(s).Path().String(), Equals, kpath)
55
c.Check(NewKey(s).Instance("inst").String(), Equals, kinstance)
56
57
- c.Check(NewKey(s).Child("cchildd").String(), Equals, kchild)
58
- c.Check(NewKey(s).Child("cchildd").Parent().String(), Equals, fixed)
57
+ c.Check(NewKey(s).Child(NewKey("cchildd")).String(), Equals, kchild)
58
+ c.Check(NewKey(s).Child(NewKey("cchildd")).Parent().String(), Equals, fixed)
59
+ c.Check(NewKey(s).ChildString("cchildd").String(), Equals, kchild)
60
+ c.Check(NewKey(s).ChildString("cchildd").Parent().String(), Equals, fixed)
61
c.Check(NewKey(s).Parent().String(), Equals, kparent)
62
c.Check(len(NewKey(s).List()), Equals, len(namespaces))
63
c.Check(len(NewKey(s).Namespaces()), Equals, len(namespaces))
64
for i, e := range NewKey(s).List() {
65
c.Check(namespaces[i], Equals, e)
66
}
67
+
68
+ c.Check(NewKey(s), Equals, NewKey(s))
69
+ c.Check(NewKey(s).Equal(NewKey(s)), Equals, true)
70
+ c.Check(NewKey(s).Equal(NewKey("/fdsafdsa/"+s)), Equals, false)
71
+
72
+ // less
73
+ c.Check(NewKey(s).Less(NewKey(s).Parent()), Equals, false)
74
+ c.Check(NewKey(s).Less(NewKey(s).ChildString("foo")), Equals, true)
75
}
76
77
func (ks *KeySuite) TestKeyBasic(c *C) {
@@ -100,7 +110,8 @@ func (ks *KeySuite) TestKeyAncestry(c *C) {
110
CheckTrue(c, !k1.IsAncestorOf(NewKey("/A")))
111
CheckTrue(c, !k2.IsAncestorOf(k2))
112
CheckTrue(c, !k1.IsAncestorOf(k1))
103
- c.Check(k1.Child("D").String(), Equals, k2.String())
113
+ c.Check(k1.Child(NewKey("D")).String(), Equals, k2.String())
114
+ c.Check(k1.ChildString("D").String(), Equals, k2.String())
115
c.Check(k1.String(), Equals, k2.Parent().String())
116
c.Check(k1.Path().String(), Equals, k2.Parent().Path().String())
117
}
@@ -126,3 +137,21 @@ func (ks *KeySuite) TestRandom(c *C) {
137
}
138
CheckTrue(c, len(keys) == 1000)
139
}
140
+
141
+func (ks *KeySuite) TestLess(c *C) {
142
+
143
+ checkLess := func(a, b string) {
144
+ ak := NewKey(a)
145
+ bk := NewKey(b)
146
+ c.Check(ak.Less(bk), Equals, true)
147
+ c.Check(bk.Less(ak), Equals, false)
148
+ }
149
+
150
+ checkLess("/a/b/c", "/a/b/c/d")
151
+ checkLess("/a/b", "/a/b/c/d")
152
+ checkLess("/a", "/a/b/c/d")
153
+ checkLess("/a/a/c", "/a/b/c")
154
+ checkLess("/a/a/d", "/a/b/c")
155
+ checkLess("/a/b/c/d/e/f/g/h", "/b")
156
+ checkLess("/", "/a")
157
+}
Godeps/_workspace/src/github.com/jbenet/datastore.go/keytransform/doc.go
new
+25
@@ -0,0 +1,25 @@
1
+// Package keytransform introduces a Datastore Shim that transforms keys before
2
+// passing them to its child. It can be used to manipulate what keys look like
3
+// to the user, for example namespacing keys, reversing them, etc.
4
+//
5
+// Use the Wrap function to wrap a datastore with any KeyTransform.
6
+// A KeyTransform is simply an interface with two functions, a conversion and
7
+// its inverse. For example:
8
+//
9
+// import (
10
+// ktds "github.com/jbenet/datastore.go/keytransform"
11
+// ds "github.com/jbenet/datastore.go"
12
+// )
13
+//
14
+// func reverseKey(k ds.Key) ds.Key {
15
+// return k.Reverse()
16
+// }
17
+//
18
+// func invertKeys(d ds.Datastore) {
19
+// return ktds.Wrap(d, &ktds.Pair{
20
+// Convert: reverseKey,
21
+// Invert: reverseKey, // reverse is its own inverse.
22
+// })
23
+// }
24
+//
25
+package keytransform
Godeps/_workspace/src/github.com/jbenet/datastore.go/keytransform/interface.go
new
+34
@@ -0,0 +1,34 @@
1
+package keytransform
2
+
3
+import ds "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/datastore.go"
4
+
5
+// KeyMapping is a function that maps one key to annother
6
+type KeyMapping func(ds.Key) ds.Key
7
+
8
+// KeyTransform is an object with a pair of functions for (invertibly)
9
+// transforming keys
10
+type KeyTransform interface {
11
+ ConvertKey(ds.Key) ds.Key
12
+ InvertKey(ds.Key) ds.Key
13
+}
14
+
15
+// Datastore is a keytransform.Datastore
16
+type Datastore interface {
17
+ ds.Shim
18
+ KeyTransform
19
+}
20
+
21
+// Wrap wraps a given datastore with a KeyTransform function.
22
+// The resulting wrapped datastore will use the transform on all Datastore
23
+// operations.
24
+func Wrap(child ds.Datastore, t KeyTransform) Datastore {
25
+ if t == nil {
26
+ panic("t (KeyTransform) is nil")
27
+ }
28
+
29
+ if child == nil {
30
+ panic("child (ds.Datastore) is nil")
31
+ }
32
+
33
+ return &ktds{child: child, KeyTransform: t}
34
+}
Godeps/_workspace/src/github.com/jbenet/datastore.go/keytransform/keytransform.go
+15
-40
@@ -2,49 +2,24 @@ package keytransform
2
3
import ds "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/datastore.go"
4
5
-// KeyTransform is a function that transforms one key into another.
6
-type KeyTransform func(ds.Key) ds.Key
7
-
8
-// Datastore is a keytransform.Datastore
9
-type Datastore interface {
10
- ds.Shim
5
+type Pair struct {
6
+ Convert KeyMapping
7
+ Invert KeyMapping
8
+}
9
12
- // Transform runs the transformation function
13
- Transform(ds.Key) ds.Key
10
+func (t *Pair) ConvertKey(k ds.Key) ds.Key {
11
+ return t.Convert(k)
12
+}
13
15
- // TransformFunc returns the KeyTransform function
16
- TransformFunc() KeyTransform
14
+func (t *Pair) InvertKey(k ds.Key) ds.Key {
15
+ return t.Invert(k)
16
}
17
18
// ktds keeps a KeyTransform function
19
type ktds struct {
20
child ds.Datastore
22
- xform KeyTransform
23
-}
24
-
25
-// WrapDatastore wraps a given datastore with a KeyTransform function.
26
-// The resulting wrapped datastore will use the transform on all Datastore
27
-// operations.
28
-func WrapDatastore(child ds.Datastore, f KeyTransform) Datastore {
29
- if f == nil {
30
- panic("f (KeyTransform) is nil")
31
- }
32
-
33
- if child == nil {
34
- panic("child (ds.Datastore) is nil")
35
- }
36
-
37
- return &ktds{child, f}
38
-}
39
-
40
-// TransformFunc returns the KeyTransform function
41
-func (d *ktds) TransformFunc() KeyTransform {
42
- return d.xform
43
-}
21
45
-// Transform runs the KeyTransform function
46
-func (d *ktds) Transform(k ds.Key) ds.Key {
47
- return d.xform(k)
22
+ KeyTransform
23
}
24
25
// Children implements ds.Shim
@@ -54,23 +29,23 @@ func (d *ktds) Children() []ds.Datastore {
29
30
// Put stores the given value, transforming the key first.
31
func (d *ktds) Put(key ds.Key, value interface{}) (err error) {
57
- return d.child.Put(d.Transform(key), value)
32
+ return d.child.Put(d.ConvertKey(key), value)
33
}
34
35
// Get returns the value for given key, transforming the key first.
36
func (d *ktds) Get(key ds.Key) (value interface{}, err error) {
62
- return d.child.Get(d.Transform(key))
37
+ return d.child.Get(d.ConvertKey(key))
38
}
39
40
// Has returns whether the datastore has a value for a given key, transforming
41
// the key first.
42
func (d *ktds) Has(key ds.Key) (exists bool, err error) {
68
- return d.child.Has(d.Transform(key))
43
+ return d.child.Has(d.ConvertKey(key))
44
}
45
46
// Delete removes the value for given key
47
func (d *ktds) Delete(key ds.Key) (err error) {
73
- return d.child.Delete(d.Transform(key))
48
+ return d.child.Delete(d.ConvertKey(key))
49
}
50
51
// KeyList returns a list of all keys in the datastore, transforming keys out.
@@ -82,7 +57,7 @@ func (d *ktds) KeyList() ([]ds.Key, error) {
57
}
58
59
for i, k := range keys {
85
- keys[i] = d.Transform(k)
60
+ keys[i] = d.InvertKey(k)
61
}
62
return keys, nil
63
}
Godeps/_workspace/src/github.com/jbenet/datastore.go/keytransform/keytransform_test.go
+34
-8
@@ -2,6 +2,7 @@ package keytransform_test
2
3
import (
4
"bytes"
5
+ "sort"
6
"testing"
7
8
ds "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/datastore.go"
@@ -12,19 +13,28 @@ import (
13
// Hook up gocheck into the "go test" runner.
14
func Test(t *testing.T) { TestingT(t) }
15
15
-type DSSuite struct {
16
- dir string
17
- ds ds.Datastore
18
-}
16
+type DSSuite struct{}
17
18
var _ = Suite(&DSSuite{})
19
20
func (ks *DSSuite) TestBasic(c *C) {
21
22
+ pair := &kt.Pair{
23
+ Convert: func(k ds.Key) ds.Key {
24
+ return ds.NewKey("/abc").Child(k)
25
+ },
26
+ Invert: func(k ds.Key) ds.Key {
27
+ // remove abc prefix
28
+ l := k.List()
29
+ if l[0] != "abc" {
30
+ panic("key does not have prefix. convert failed?")
31
+ }
32
+ return ds.KeyWithNamespaces(l[1:])
33
+ },
34
+ }
35
+
36
mpds := ds.NewMapDatastore()
25
- ktds := kt.WrapDatastore(mpds, func(k ds.Key) ds.Key {
26
- return k.Reverse()
27
- })
37
+ ktds := kt.Wrap(mpds, pair)
38
39
keys := strsToKeys([]string{
40
"foo",
@@ -45,10 +55,26 @@ func (ks *DSSuite) TestBasic(c *C) {
55
c.Check(err, Equals, nil)
56
c.Check(bytes.Equal(v1.([]byte), []byte(k.String())), Equals, true)
57
48
- v2, err := mpds.Get(k.Reverse())
58
+ v2, err := mpds.Get(ds.NewKey("abc").Child(k))
59
c.Check(err, Equals, nil)
60
c.Check(bytes.Equal(v2.([]byte), []byte(k.String())), Equals, true)
61
}
62
+
63
+ listA, errA := mpds.KeyList()
64
+ listB, errB := ktds.KeyList()
65
+ c.Check(errA, Equals, nil)
66
+ c.Check(errB, Equals, nil)
67
+ c.Check(len(listA), Equals, len(listB))
68
+
69
+ // sort them cause yeah.
70
+ sort.Sort(ds.KeySlice(listA))
71
+ sort.Sort(ds.KeySlice(listB))
72
+
73
+ for i, kA := range listA {
74
+ kB := listB[i]
75
+ c.Check(pair.Invert(kA), Equals, kB)
76
+ c.Check(kA, Equals, pair.Convert(kB))
77
+ }
78
}
79
80
func strsToKeys(strs []string) []ds.Key {
Godeps/_workspace/src/github.com/jbenet/datastore.go/namespace/doc.go
new
+24
@@ -0,0 +1,24 @@
1
+// Package namespace introduces a namespace Datastore Shim, which basically
2
+// mounts the entire child datastore under a prefix.
3
+//
4
+// Use the Wrap function to wrap a datastore with any Key prefix. For example:
5
+//
6
+// import (
7
+// "fmt"
8
+//
9
+// ds "github.com/jbenet/datastore.go"
10
+// nsds "github.com/jbenet/datastore.go/namespace"
11
+// )
12
+//
13
+// func main() {
14
+// mp := ds.NewMapDatastore()
15
+// ns := nsds.Wrap(mp, ds.NewKey("/foo/bar"))
16
+//
17
+// // in the Namespace Datastore:
18
+// ns.Put(ds.NewKey("/beep"), "boop")
19
+// v2, _ := ns.Get(ds.NewKey("/beep")) // v2 == "boop"
20
+//
21
+// // and, in the underlying MapDatastore:
22
+// v3, _ := mp.Get(ds.NewKey("/foo/bar/beep")) // v3 == "boop"
23
+// }
24
+package namespace
Godeps/_workspace/src/github.com/jbenet/datastore.go/namespace/example_test.go
new
+30
@@ -0,0 +1,30 @@
1
+package namespace_test
2
+
3
+import (
4
+ "fmt"
5
+
6
+ ds "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/datastore.go"
7
+ nsds "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/datastore.go/namespace"
8
+)
9
+
10
+func Example() {
11
+ mp := ds.NewMapDatastore()
12
+ ns := nsds.Wrap(mp, ds.NewKey("/foo/bar"))
13
+
14
+ k := ds.NewKey("/beep")
15
+ v := "boop"
16
+
17
+ ns.Put(k, v)
18
+ fmt.Printf("ns.Put %s %s\n", k, v)
19
+
20
+ v2, _ := ns.Get(k)
21
+ fmt.Printf("ns.Get %s -> %s\n", k, v2)
22
+
23
+ k3 := ds.NewKey("/foo/bar/beep")
24
+ v3, _ := mp.Get(k3)
25
+ fmt.Printf("mp.Get %s -> %s\n", k3, v3)
26
+ // Output:
27
+ // ns.Put /beep -> boop
28
+ // ns.Get /beep -> boop
29
+ // mp.Get /foo/bar/beep -> boop
30
+}
Godeps/_workspace/src/github.com/jbenet/datastore.go/namespace/namespace.go
new
+44
@@ -0,0 +1,44 @@
1
+package namespace
2
+
3
+import (
4
+ "fmt"
5
+ "strings"
6
+
7
+ ds "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/datastore.go"
8
+ ktds "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/datastore.go/keytransform"
9
+)
10
+
11
+// PrefixTransform constructs a KeyTransform with a pair of functions that
12
+// add or remove the given prefix key.
13
+//
14
+// Warning: will panic if prefix not found when it should be there. This is
15
+// to avoid insidious data inconsistency errors.
16
+func PrefixTransform(prefix ds.Key) ktds.KeyTransform {
17
+ return &ktds.Pair{
18
+
19
+ // Convert adds the prefix
20
+ Convert: func(k ds.Key) ds.Key {
21
+ return prefix.Child(k)
22
+ },
23
+
24
+ // Invert removes the prefix. panics if prefix not found.
25
+ Invert: func(k ds.Key) ds.Key {
26
+ if !prefix.IsAncestorOf(k) {
27
+ fmt.Errorf("Expected prefix (%s) in key (%s)", prefix, k)
28
+ panic("expected prefix not found")
29
+ }
30
+
31
+ s := strings.TrimPrefix(k.String(), prefix.String())
32
+ return ds.NewKey(s)
33
+ },
34
+ }
35
+}
36
+
37
+// Wrap wraps a given datastore with a key-prefix.
38
+func Wrap(child ds.Datastore, prefix ds.Key) ktds.Datastore {
39
+ if child == nil {
40
+ panic("child (ds.Datastore) is nil")
41
+ }
42
+
43
+ return ktds.Wrap(child, PrefixTransform(prefix))
44
+}
Godeps/_workspace/src/github.com/jbenet/datastore.go/namespace/namespace_test.go
new
+72
@@ -0,0 +1,72 @@
1
+package namespace_test
2
+
3
+import (
4
+ "bytes"
5
+ "sort"
6
+ "testing"
7
+
8
+ ds "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/datastore.go"
9
+ ns "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/datastore.go/namespace"
10
+ . "launchpad.net/gocheck"
11
+)
12
+
13
+// Hook up gocheck into the "go test" runner.
14
+func Test(t *testing.T) { TestingT(t) }
15
+
16
+type DSSuite struct{}
17
+
18
+var _ = Suite(&DSSuite{})
19
+
20
+func (ks *DSSuite) TestBasic(c *C) {
21
+
22
+ mpds := ds.NewMapDatastore()
23
+ nsds := ns.Wrap(mpds, ds.NewKey("abc"))
24
+
25
+ keys := strsToKeys([]string{
26
+ "foo",
27
+ "foo/bar",
28
+ "foo/bar/baz",
29
+ "foo/barb",
30
+ "foo/bar/bazb",
31
+ "foo/bar/baz/barb",
32
+ })
33
+
34
+ for _, k := range keys {
35
+ err := nsds.Put(k, []byte(k.String()))
36
+ c.Check(err, Equals, nil)
37
+ }
38
+
39
+ for _, k := range keys {
40
+ v1, err := nsds.Get(k)
41
+ c.Check(err, Equals, nil)
42
+ c.Check(bytes.Equal(v1.([]byte), []byte(k.String())), Equals, true)
43
+
44
+ v2, err := mpds.Get(ds.NewKey("abc").Child(k))
45
+ c.Check(err, Equals, nil)
46
+ c.Check(bytes.Equal(v2.([]byte), []byte(k.String())), Equals, true)
47
+ }
48
+
49
+ listA, errA := mpds.KeyList()
50
+ listB, errB := nsds.KeyList()
51
+ c.Check(errA, Equals, nil)
52
+ c.Check(errB, Equals, nil)
53
+ c.Check(len(listA), Equals, len(listB))
54
+
55
+ // sort them cause yeah.
56
+ sort.Sort(ds.KeySlice(listA))
57
+ sort.Sort(ds.KeySlice(listB))
58
+
59
+ for i, kA := range listA {
60
+ kB := listB[i]
61
+ c.Check(nsds.InvertKey(kA), Equals, kB)
62
+ c.Check(kA, Equals, nsds.ConvertKey(kB))
63
+ }
64
+}
65
+
66
+func strsToKeys(strs []string) []ds.Key {
67
+ keys := make([]ds.Key, len(strs))
68
+ for i, s := range strs {
69
+ keys[i] = ds.NewKey(s)
70
+ }
71
+ return keys
72
+}
Godeps/_workspace/src/github.com/jbenet/datastore.go/panic/panic.go
new
+67
@@ -0,0 +1,67 @@
1
+package sync
2
+
3
+import (
4
+ "fmt"
5
+ "os"
6
+
7
+ ds "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/datastore.go"
8
+)
9
+
10
+type datastore struct {
11
+ child ds.Datastore
12
+}
13
+
14
+// Wrap shims a datastore such than _any_ operation failing triggers a panic
15
+// This is useful for debugging invariants.
16
+func Wrap(d ds.Datastore) ds.Shim {
17
+ return &datastore{child: d}
18
+}
19
+
20
+func (d *datastore) Children() []ds.Datastore {
21
+ return []ds.Datastore{d.child}
22
+}
23
+
24
+func (d *datastore) Put(key ds.Key, value interface{}) error {
25
+ err := d.child.Put(key, value)
26
+ if err != nil {
27
+ fmt.Fprintf(os.Stdout, "panic datastore: %s", err)
28
+ panic("panic datastore: Put failed")
29
+ }
30
+ return nil
31
+}
32
+
33
+func (d *datastore) Get(key ds.Key) (interface{}, error) {
34
+ val, err := d.child.Get(key)
35
+ if err != nil {
36
+ fmt.Fprintf(os.Stdout, "panic datastore: %s", err)
37
+ panic("panic datastore: Get failed")
38
+ }
39
+ return val, nil
40
+}
41
+
42
+func (d *datastore) Has(key ds.Key) (bool, error) {
43
+ e, err := d.child.Has(key)
44
+ if err != nil {
45
+ fmt.Fprintf(os.Stdout, "panic datastore: %s", err)
46
+ panic("panic datastore: Has failed")
47
+ }
48
+ return e, nil
49
+}
50
+
51
+func (d *datastore) Delete(key ds.Key) error {
52
+ err := d.child.Delete(key)
53
+ if err != nil {
54
+ fmt.Fprintf(os.Stdout, "panic datastore: %s", err)
55
+ panic("panic datastore: Delete failed")
56
+ }
57
+ return nil
58
+}
59
+
60
+func (d *datastore) KeyList() ([]ds.Key, error) {
61
+ kl, err := d.child.KeyList()
62
+ if err != nil {
63
+ fmt.Fprintf(os.Stdout, "panic datastore: %s", err)
64
+ panic("panic datastore: KeyList failed")
65
+ }
66
+ return kl, nil
67
+}