Skip to content

Commit 749b656

Browse files
committed
fix: export key properly
1 parent 2059883 commit 749b656

File tree

4 files changed

+233
-48
lines changed

4 files changed

+233
-48
lines changed

packages/interface-datastore/README.md

+7-45
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,7 @@
1515
## Table of Contents <!-- omit in toc -->
1616

1717
- [Implementations](#implementations)
18-
- [Adapter](#adapter)
1918
- [Install](#install)
20-
- [Usage](#usage)
21-
- [Wrapping Stores](#wrapping-stores)
2219
- [Test suite](#test-suite)
2320
- [Aborting requests](#aborting-requests)
2421
- [Concurrency](#concurrency)
@@ -30,9 +27,10 @@
3027
## Implementations
3128

3229
- Backed Implementations
33-
- Memory: [`src/memory`](src/memory.js)
30+
- Memory: [`datastore-core/memory`](https://github.com/ipfs/js-datastore-core/tree/master/src/memory.js)
3431
- level: [`datastore-level`](https://github.com/ipfs/js-datastore-level) (supports any levelup compatible backend)
3532
- File System: [`datstore-fs`](https://github.com/ipfs/js-datastore-fs)
33+
- S3: [`datstore-s3`](https://github.com/ipfs/js-datastore-s3)
3634
- Wrapper Implementations
3735
- Mount: [`datastore-core/src/mount`](https://github.com/ipfs/js-datastore-core/tree/master/src/mount.js)
3836
- Keytransform: [`datstore-core/src/keytransform`](https://github.com/ipfs/js-datastore-core/tree/master/src/keytransform.js)
@@ -53,57 +51,21 @@ const fs = new FsStore('path/to/store')
5351
const flatfs = await ShardingStore.createOrOpen(fs, new NextToLast(2))
5452
```
5553

56-
## Adapter
57-
58-
An adapter is made available to make implementing your own datastore easier:
59-
60-
```javascript
61-
const { Adapter } from 'interface-datastore')
62-
63-
class MyDatastore extends Adapter {
64-
constructor () {
65-
super()
66-
}
67-
68-
async put (key, val) {
69-
// your implementation here
70-
}
71-
72-
async get (key) {
73-
// your implementation here
74-
}
75-
76-
// etc...
77-
}
78-
```
79-
80-
See the [MemoryDatastore](./src/memory.js) for an example of how it is used.
81-
8254
## Install
8355

8456
```sh
8557
$ npm install interface-datastore
8658
```
8759

88-
## Usage
89-
90-
### Wrapping Stores
91-
92-
```js
93-
const MemoryStore from 'interface-datastore').MemoryDatastore
94-
const MountStore from 'datastore-core').MountDatastore
95-
const Key from 'interface-datastore').Key
96-
97-
const store = new MountStore({ prefix: new Key('/a'), datastore: new MemoryStore() })
98-
```
99-
10060
### Test suite
10161

102-
Available under [`src/tests.js`](src/tests.js)
62+
Available via the [`interface-datastore-tests`](https://npmjs.com/package/interface-datastore-tests) module
10363

10464
```js
65+
import { interfaceDatastoreTests } from 'interface-datastore-tests'
66+
10567
describe('mystore', () => {
106-
require('interface-datastore/src/tests')({
68+
interfaceDatastoreTests({
10769
async setup () {
10870
return instanceOfMyStore
10971
},
@@ -179,4 +141,4 @@ MIT 2017 © IPFS
179141
[Array]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
180142
[Function]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function
181143
[Number]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number
182-
[Boolean]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean
144+
[Boolean]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean

packages/interface-datastore/package.json

+17-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,19 @@
55
"leadMaintainer": "Alex Potsides <alex.potsides@protocol.ai>",
66
"types": "types/src/index.d.ts",
77
"type": "module",
8+
"typesVersions": {
9+
"*": {
10+
"*": [
11+
"types/src/*"
12+
],
13+
"types/*": [
14+
"types/src/*"
15+
],
16+
"types/src/*": [
17+
"types/src/*"
18+
]
19+
}
20+
},
821
"exports": {
922
".": {
1023
"import": "./src/index.js"
@@ -22,7 +35,8 @@
2235
"lint": "aegir ts -p check && aegir lint",
2336
"coverage": "aegir test --cov",
2437
"dep-check": "aegir dep-check -i rimraf",
25-
"clean": "rimraf dist types"
38+
"clean": "rimraf dist types",
39+
"test": "aegir test"
2640
},
2741
"repository": {
2842
"type": "git",
@@ -41,7 +55,8 @@
4155
"homepage": "https://github.com/ipfs/js-ipfs-interfaces/tree/master/packages/interface-datastore#readme",
4256
"devDependencies": {
4357
"aegir": "^35.0.0",
44-
"rimraf": "^3.0.2"
58+
"rimraf": "^3.0.2",
59+
"util": "^0.12.4"
4560
},
4661
"dependencies": {
4762
"interface-store": "^2.0.1",
+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11

2-
export { Key } from './key'
2+
export { Key } from './key.js'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
/* eslint-env mocha */
2+
3+
import { expect } from 'aegir/utils/chai.js'
4+
import { Key } from 'interface-datastore/key'
5+
6+
const pathSep = '/'
7+
8+
describe('Key', () => {
9+
/**
10+
* @param {string} s
11+
*/
12+
const clean = (s) => {
13+
let fixed = s
14+
if (fixed.startsWith(pathSep + pathSep)) {
15+
fixed = fixed.slice(1)
16+
}
17+
if (fixed.length > 1 && fixed.endsWith(pathSep)) {
18+
fixed = fixed.slice(0, -1)
19+
}
20+
21+
return fixed
22+
}
23+
24+
describe('basic', () => {
25+
/**
26+
* @param {string} s
27+
*/
28+
const validKey = (s) => it(s, () => {
29+
const fixed = clean(pathSep + s)
30+
const namespaces = fixed.split(pathSep).slice(1)
31+
const lastNamespace = namespaces[namespaces.length - 1]
32+
const lnparts = lastNamespace.split(':')
33+
let ktype = ''
34+
if (lnparts.length > 1) {
35+
ktype = lnparts.slice(0, -1).join(':')
36+
}
37+
const kname = lnparts[lnparts.length - 1]
38+
const kchild = clean(fixed + '/cchildd')
39+
const kparent = pathSep + namespaces.slice(0, -1).join(pathSep)
40+
const kpath = clean(kparent + pathSep + ktype)
41+
const kinstance = fixed + ':inst'
42+
43+
const k = new Key(s)
44+
expect(k.toString()).to.eql(fixed)
45+
expect(k).to.eql(new Key(s))
46+
expect(k.toString()).to.eql(new Key(s).toString())
47+
expect(k.name()).to.eql(kname)
48+
expect(k.type()).to.eql(ktype)
49+
expect(k.path().toString()).to.eql(kpath)
50+
expect(k.instance('inst').toString()).to.eql(kinstance)
51+
52+
const child = new Key('cchildd')
53+
expect(k.child(child).toString()).to.eql(kchild)
54+
expect(k.child(child).parent().toString()).to.eql(fixed)
55+
expect(k.parent().toString()).to.eql(kparent)
56+
expect(k.list()).to.have.length(namespaces.length)
57+
expect(k.namespaces()).to.have.length(namespaces.length)
58+
k.list().forEach((e, i) => {
59+
expect(namespaces[i]).to.eql(e)
60+
})
61+
})
62+
63+
validKey('')
64+
validKey('abcde')
65+
validKey('disahfidsalfhduisaufidsail')
66+
validKey('/fdisahfodisa/fdsa/fdsafdsafdsafdsa/fdsafdsa/')
67+
validKey('4215432143214321432143214321')
68+
validKey('a/b/c/d/')
69+
validKey('abcde:fdsfd')
70+
validKey('disahfidsalfhduisaufidsail:fdsa')
71+
validKey('/fdisahfodisa/fdsa/fdsafdsafdsafdsa/fdsafdsa/:')
72+
validKey('4215432143214321432143214321:')
73+
})
74+
75+
it('ancestry', () => {
76+
const k1 = new Key('/A/B/C')
77+
const k2 = new Key('/A/B/C/D')
78+
79+
expect(k1.toString()).to.be.eql('/A/B/C')
80+
expect(k2.toString()).to.be.eql('/A/B/C/D')
81+
82+
const checks = [
83+
k1.isAncestorOf(k2),
84+
k2.isDecendantOf(k1),
85+
new Key('/A').isAncestorOf(k2),
86+
new Key('/A').isAncestorOf(k1),
87+
!new Key('/A').isDecendantOf(k2),
88+
!new Key('/A').isDecendantOf(k1),
89+
k2.isDecendantOf(new Key('/A')),
90+
k1.isDecendantOf(new Key('/A')),
91+
!k2.isAncestorOf(new Key('/A')),
92+
!k1.isAncestorOf(new Key('/A')),
93+
!k2.isAncestorOf(k2),
94+
!k1.isAncestorOf(k1)
95+
]
96+
97+
checks.forEach((check) => expect(check).to.equal(true))
98+
99+
expect(k1.child(new Key('D')).toString()).to.eql(k2.toString())
100+
expect(k1.toString()).to.eql(k2.parent().toString())
101+
expect(k1.path().toString()).to.eql(k2.parent().path().toString())
102+
})
103+
104+
it('type', () => {
105+
const k1 = new Key('/A/B/C:c')
106+
const k2 = new Key('/A/B/C:c/D:d')
107+
108+
expect(k1.isAncestorOf(k2)).to.eql(true)
109+
expect(k2.isDecendantOf(k1)).to.eql(true)
110+
111+
expect(k1.type()).to.eql('C')
112+
expect(k2.type()).to.eql('D')
113+
expect(k1.type()).to.eql(k2.parent().type())
114+
})
115+
116+
it('random', () => {
117+
/** @type {Record<string, boolean>} */
118+
const keys = {}
119+
const k = 100
120+
for (let i = 0; i < k; i++) {
121+
const r = Key.random()
122+
expect(keys).to.not.have.key(r.toString())
123+
keys[r.toString()] = true
124+
}
125+
126+
expect(Object.keys(keys)).to.have.length(k)
127+
})
128+
129+
it('less', () => {
130+
/**
131+
* @param {string | Uint8Array} a
132+
* @param {string | Uint8Array} b
133+
*/
134+
const checkLess = (a, b) => {
135+
const ak = new Key(a)
136+
const bk = new Key(b)
137+
138+
expect(ak.less(bk)).to.eql(true)
139+
expect(bk.less(ak)).to.eql(false)
140+
}
141+
142+
checkLess('/a/b/c', '/a/b/c/d')
143+
checkLess('/a/b', '/a/b/c/d')
144+
checkLess('/a', '/a/b/c/d')
145+
checkLess('/a/a/c', '/a/b/c')
146+
checkLess('/a/a/d', '/a/b/c')
147+
checkLess('/a/b/c/d/e/f/g/h', '/b')
148+
checkLess(pathSep, '/a')
149+
})
150+
151+
it('concat', () => {
152+
const originalKey = new Key('/a/b/c')
153+
154+
const concattedKey = originalKey.concat(new Key('/d/e/f'))
155+
expect(concattedKey.toString()).to.equal('/a/b/c/d/e/f')
156+
157+
// Original key is not changed
158+
expect(originalKey.toString()).to.equal('/a/b/c')
159+
160+
const concattedMultipleKeys = originalKey.concat(new Key('/d/e'), new Key('/f/g'))
161+
expect(concattedMultipleKeys.toString()).to.equal('/a/b/c/d/e/f/g')
162+
163+
// New instance of Key is always created
164+
expect(originalKey.concat()).to.not.equal(originalKey)
165+
// but has the same value
166+
expect(originalKey.concat().toString()).to.equal('/a/b/c')
167+
})
168+
169+
it('uint8Array', () => {
170+
const arr = Uint8Array.from(['/'.charCodeAt(0), 0, 1, 2, 3])
171+
const key = new Key(arr)
172+
const buf = key.uint8Array()
173+
174+
expect(buf).to.deep.equal(arr)
175+
})
176+
177+
it('uint8Array with surplus bytes', () => {
178+
const arr = Uint8Array.from(['/'.charCodeAt(0), 0, 1, 2, 3, 4])
179+
const view = new Uint8Array(arr.buffer, 0, arr.length - 1)
180+
181+
// should be same buffer
182+
expect(view.buffer).to.equal(arr.buffer)
183+
expect(view.buffer.byteLength).to.equal(arr.buffer.byteLength)
184+
185+
// view should be shorter than wrapped buffer
186+
expect(view.length).to.be.lessThan(arr.buffer.byteLength)
187+
expect(view.byteLength).to.be.lessThan(arr.buffer.byteLength)
188+
189+
const key = new Key(view)
190+
const buf = key.uint8Array()
191+
192+
expect(buf).to.deep.equal(view)
193+
})
194+
195+
it('uint8Array with trailing slashes', () => {
196+
const slash = '/'.charCodeAt(0)
197+
const arrWithSlashes = Uint8Array.from([slash, 0, 1, 2, 3, slash, slash, slash])
198+
const arrWithoutSlashes = Uint8Array.from([slash, 0, 1, 2, 3])
199+
const key = new Key(arrWithSlashes)
200+
const buf = key.uint8Array()
201+
202+
// slashes should have been stripped
203+
expect(buf).to.deep.equal(arrWithoutSlashes)
204+
205+
// should be a view on the original buffer
206+
expect(buf.buffer).to.equal(arrWithSlashes.buffer)
207+
})
208+
})

0 commit comments

Comments
 (0)