@cryptotaxi247 / kubo / commits / 4cb48da22

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 +}