diff --git a/API/dag/README.md b/API/dag/README.md index 4d0dfe20..8568f634 100644 --- a/API/dag/README.md +++ b/API/dag/README.md @@ -13,14 +13,28 @@ dag API - `dagNode` - a DAG node that follows one of the supported IPLD formats. - `options` - a object that might contain the follwing values: - - `format` - The IPLD format multicodec. - - `hashAlg` - The hash algorithm to be used over the serialized dagNode. - - `cid` - the CID of the node passed. + - `format` - The IPLD format multicodec. + - `hashAlg` - The hash algorithm to be used over the serialized dagNode. + - or + - `cid` - the CID of the node passed. - **Note** - You should only pass the CID or the format + hashAlg pair and not both -- `callback` must follow `function (err) {}` signature, where `err` is an error if the operation was not successful. +- `callback` must follow `function (err, cid) {}` signature, where `err` is an error if the operation was not successful and CID is the CID generated through the process or the one that was passed If no `callback` is passed, a [promise][] is returned. +**Example:** + +```JavaScript +const obj = { simple: 'object' } + +ipfs.dag.put(obj, { format: 'dag-cbor', hashAlg: 'sha3-512' }, (err, cid) => { + console.log(cid.toBaseEncodedString()) + // zdpuAzE1oAAMpsfdoexcJv6PmL9UhE8nddUYGU32R98tzV5fv +}) +``` + +A great source of [examples][] can be found in the tests for this API. + #### `dag.get` > Retrieve an IPLD format node @@ -29,7 +43,10 @@ If no `callback` is passed, a [promise][] is returned. ##### `JavaScript` - ipfs.dag.get(cid [, path, options], callback) -- `cid` - a [CID][https://github.com/ipfs/js-cid] instance. +- `cid` - can be one of the following: + - a [CID](https://github.com/ipfs/js-cid) instance. + - a CID in its String format (i.e: zdpuAkxd9KzGwJFGhymCZRkPCXtBmBW7mB2tTuEH11HLbES9Y) + - a CID in its String format concatenated with the path to be resolved - `path` - the path to be resolved. Optional. - `options` - a object that might contain the following values: - `localResolve` - bool - if set to true, it will avoid resolving through different objects. @@ -38,3 +55,83 @@ If no `callback` is passed, a [promise][] is returned. - `value` - the value or node that was fetched during the get operation. - `remainderPath` - The remainder of the Path that the node was unable to resolve or what was left in a localResolve scenario. + +If no `callback` is passed, a [promise][] is returned. + +**Example:** + +```JavaScript +// example obj +const obj = { + a: 1, + b: [1, 2, 3], + c: { + ca: [5, 6, 7], + cb: 'foo"' + } +} + +ipfs.dag.put(obj, { format: 'dag-cbor', hashAlg: 'sha2-256' }, (err, cid) => { + console.log(cid.toBaseEncodedString()) + // zdpuAmtur968yprkhG9N5Zxn6MFVoqAWBbhUAkNLJs2UtkTq5 +}) + +function errOrLog(err, result) { + if (err) { + console.error('error: ' + err) + } else { + console.log(result.value) + } +} + +ipfs.dag.get('zdpuAmtur968yprkhG9N5Zxn6MFVoqAWBbhUAkNLJs2UtkTq5/a', errOrLog) +// Returns: +// 1 + +ipfs.dag.get('zdpuAmtur968yprkhG9N5Zxn6MFVoqAWBbhUAkNLJs2UtkTq5/b', errOrLog) +// Returns: +// [1, 2, 3] + +ipfs.dag.get('zdpuAmtur968yprkhG9N5Zxn6MFVoqAWBbhUAkNLJs2UtkTq5/c', errOrLog) +// Returns: +// { +// ca: [5, 6, 7], +// cb: 'foo' +// } + +ipfs.dag.get('zdpuAmtur968yprkhG9N5Zxn6MFVoqAWBbhUAkNLJs2UtkTq5/c/ca/1', errOrLog) +// Returns: +// 6 +``` + +A great source of [examples][] can be found in the tests for this API. + +#### `dag.tree` + +> Enumerate all the entries in a graph + +##### `Go` **WIP** + +##### `JavaScript` - ipfs.dag.tree(cid [, path, options], callback) + +- `cid` - can be one of the following: + - a [CID](https://github.com/ipfs/js-cid) instance. + - a CID in its String format (i.e: zdpuAkxd9KzGwJFGhymCZRkPCXtBmBW7mB2tTuEH11HLbES9Y) + - a CID in its String format concatenated with the path to be resolved +- `path` - the path to be resolved. Optional. +- `options` - a object that might contain the following values: + - `recursive` - bool - if set to true, it will follow the links and continuously run tree on them, returning all the paths in the graph. + +`callback` must follow `function (err, result) {}` signature, where `err` is an error if the operation was not successful and `result` is an Array with the paths passed. + +If no `callback` is passed, a [promise][] is returned. + +**Example:** + +```JavaScript +``` + +A great source of [examples][] can be found in the tests for this API. + + +[examples]: https://github.com/ipfs/interface-ipfs-core/blob/master/src/dag.js diff --git a/package.json b/package.json index 341ede9e..f7a575a4 100644 --- a/package.json +++ b/package.json @@ -26,19 +26,20 @@ }, "homepage": "https://github.com/ipfs/interface-ipfs-core#readme", "dependencies": { - "async": "^2.1.4", + "async": "^2.1.5", "bl": "^1.2.0", "bs58": "^4.0.0", "chai": "^3.5.0", + "cids": "^0.4.1", "concat-stream": "^1.6.0", "detect-node": "^2.0.3", - "ipfs-block": "^0.5.4", - "ipld-dag-cbor": "^0.9.0", - "ipld-dag-pb": "^0.9.4", - "multiaddr": "^2.2.0", - "multihashes": "^0.3.2", + "ipfs-block": "^0.5.5", + "ipld-dag-cbor": "^0.9.1", + "ipld-dag-pb": "^0.9.5", + "multiaddr": "^2.2.1", + "multihashes": "^0.4.3", "pull-stream": "^3.5.0", - "readable-stream": "2.2.2" + "readable-stream": "1.1.14" }, "devDependencies": { "aegir": "^10.0.0" @@ -54,4 +55,4 @@ "haad ", "nginnever " ] -} \ No newline at end of file +} diff --git a/src/dag.js b/src/dag.js index 3fb3bdeb..a431567b 100644 --- a/src/dag.js +++ b/src/dag.js @@ -9,9 +9,10 @@ const pull = require('pull-stream') const dagPB = require('ipld-dag-pb') const DAGNode = dagPB.DAGNode const dagCBOR = require('ipld-dag-cbor') +const CID = require('cids') module.exports = (common) => { - describe('.dag', () => { + describe.only('.dag', () => { let ipfs before(function (done) { @@ -28,9 +29,7 @@ module.exports = (common) => { }) }) - after((done) => { - common.teardown(done) - }) + after((done) => common.teardown(done)) describe('callback API', () => { let pbNode @@ -100,6 +99,24 @@ module.exports = (common) => { done() }) }) + + it('returns the cid', (done) => { + ipfs.dag.put(cborNode, { + format: 'dag-cbor', + hashAlg: 'sha3-512' + }, (err, cid) => { + expect(err).to.not.exist + expect(cid).to.exist + expect(CID.isCID(cid)).to.be.true + dagCBOR.util.cid(cborNode, (err, _cid) => { + expect(err).to.not.exist + expect(cid.buffer).to.eql(_cid.buffer) + done() + }) + }) + }) + + it.skip('pass the cid instead of format and hashAlg', (done) => {}) }) describe('.get', () => { @@ -175,16 +192,13 @@ module.exports = (common) => { ipfs.dag.put(pbNode, { format: 'dag-pb', hashAlg: 'sha2-256' - }, (err) => { + }, (err, cid) => { expect(err).to.not.exist - dagPB.util.cid(pbNode, (err, cid) => { + ipfs.dag.get(cid, (err, result) => { expect(err).to.not.exist - ipfs.dag.get(cid, (err, result) => { - expect(err).to.not.exist - const node = result.value - expect(pbNode.toJSON()).to.eql(node.toJSON()) - done() - }) + const node = result.value + expect(pbNode.toJSON()).to.eql(node.toJSON()) + done() }) }) }) @@ -193,17 +207,14 @@ module.exports = (common) => { ipfs.dag.put(cborNode, { format: 'dag-cbor', hashAlg: 'sha2-256' - }, (err) => { + }, (err, cid) => { expect(err).to.not.exist - dagCBOR.util.cid(cborNode, (err, cid) => { + ipfs.dag.get(cid, (err, result) => { expect(err).to.not.exist - ipfs.dag.get(cid, (err, result) => { - expect(err).to.not.exist - const node = result.value - expect(cborNode).to.eql(node) - done() - }) + const node = result.value + expect(cborNode).to.eql(node) + done() }) }) }) @@ -224,7 +235,7 @@ module.exports = (common) => { }) it('dag-pb local scope', (done) => { - ipfs.dag.get(cidPb, 'data', (err, result) => { + ipfs.dag.get(cidPb, 'Data', (err, result) => { expect(err).to.not.exist expect(result.value).to.eql(new Buffer('I am inside a Protobuf')) done() @@ -261,7 +272,33 @@ module.exports = (common) => { it.skip('from dag-pb to dag-cbor', (done) => {}) it('from dag-cbor to dag-pb', (done) => { - ipfs.dag.get(cidCbor, 'pb/data', (err, result) => { + ipfs.dag.get(cidCbor, 'pb/Data', (err, result) => { + expect(err).to.not.exist + expect(result.value).to.eql(new Buffer('I am inside a Protobuf')) + done() + }) + }) + + it('CID String', (done) => { + const cidCborStr = cidCbor.toBaseEncodedString() + + ipfs.dag.get(cidCborStr, (err, result) => { + expect(err).to.not.exist + + const node = result.value + + dagCBOR.util.cid(node, (err, cid) => { + expect(err).to.not.exist + expect(cid).to.eql(cidCbor) + done() + }) + }) + }) + + it('CID String + path', (done) => { + const cidCborStr = cidCbor.toBaseEncodedString() + + ipfs.dag.get(cidCborStr + '/pb/Data', (err, result) => { expect(err).to.not.exist expect(result.value).to.eql(new Buffer('I am inside a Protobuf')) done() @@ -269,11 +306,120 @@ module.exports = (common) => { }) }) }) + + describe('.tree', () => { + let nodePb + let nodeCbor + let cidPb + let cidCbor + + before((done) => { + series([ + (cb) => { + dagPB.DAGNode.create(new Buffer('I am inside a Protobuf'), (err, node) => { + expect(err).to.not.exist + nodePb = node + cb() + }) + }, + (cb) => { + dagPB.util.cid(nodePb, (err, cid) => { + expect(err).to.not.exist + cidPb = cid + cb() + }) + }, + (cb) => { + nodeCbor = { + someData: 'I am inside a Cbor object', + pb: { '/': cidPb.toBaseEncodedString() } + } + + dagCBOR.util.cid(nodeCbor, (err, cid) => { + expect(err).to.not.exist + cidCbor = cid + cb() + }) + } + ], store) + + function store () { + pull( + pull.values([ + { node: nodePb, multicodec: 'dag-pb', hashAlg: 'sha2-256' }, + { node: nodeCbor, multicodec: 'dag-cbor', hashAlg: 'sha2-256' } + ]), + pull.asyncMap((el, cb) => { + ipfs.dag.put(el.node, { + format: el.multicodec, + hashAlg: el.hashAlg + }, cb) + }), + pull.onEnd(done) + ) + } + }) + + it('.tree with CID', (done) => { + ipfs.dag.tree(cidCbor, (err, paths) => { + expect(err).to.not.exist + expect(paths).to.eql([ + 'pb', + 'someData' + ]) + done() + }) + }) + + it('.tree with CID and path', (done) => { + ipfs.dag.tree(cidCbor, 'someData', (err, paths) => { + expect(err).to.not.exist + expect(paths).to.eql([]) + done() + }) + }) + + it('.tree with CID and path as String', (done) => { + const cidCborStr = cidCbor.toBaseEncodedString() + + ipfs.dag.tree(cidCborStr + '/someData', (err, paths) => { + expect(err).to.not.exist + expect(paths).to.eql([]) + done() + }) + }) + + it('.tree with CID recursive (accross different formats)', (done) => { + ipfs.dag.tree(cidCbor, { recursive: true }, (err, paths) => { + expect(err).to.not.exist + expect(paths).to.eql([ + 'pb', + 'pb/Data', + 'pb/Links', + 'someData' + ]) + done() + }) + }) + + it('.tree with CID and path recursive', (done) => { + ipfs.dag.tree(cidCbor, 'pb', { recursive: true }, (err, paths) => { + expect(err).to.not.exist + expect(paths).to.eql([ + 'Data', + 'Links' + ]) + done() + }) + }) + }) }) describe('promise API', () => { describe('.put', () => {}) describe('.get', () => {}) + describe('.tree', () => {}) + describe('.ls', () => {}) }) }) }