Skip to content
This repository has been archived by the owner on Aug 11, 2021. It is now read-only.

Commit

Permalink
feat: new IPLD Format API
Browse files Browse the repository at this point in the history
BREAKING CHANGE: The API is now async/await based

There are numerous changes, the most significant one is that the API
is no longer callback based, but it using async/await.

The properties of DAGNode and DAGLink are now in sync with the paths
that are used for resolving. This means that e.g. `name` is now called
`Name` and `size` is `Tsize`.

All return values from `resolve()` now conform to the [IPLD Data Model],
this means that e.g. links are no longer represented as
`{'/': "baseecodedcid"}`, but as [CID] instances instead.

For the full new API please see the [IPLD Formats spec].

[IPLD Data Model]: https://github.com/ipld/specs/blob/master/IPLD-Data-Model-v1.md
[CID]: https://github.com/multiformats/js-cid/
[IPLD Formats spec]: https://github.com/ipld/interface-ipld-format
  • Loading branch information
vmx committed May 8, 2019
1 parent 63b7986 commit 1de1bcc
Show file tree
Hide file tree
Showing 21 changed files with 745 additions and 1,149 deletions.
80 changes: 29 additions & 51 deletions README.md
Expand Up @@ -27,18 +27,18 @@
- [Add and remove a Link](#add-and-remove-a-link)
- [API](#api)
- [DAGNode functions](#dagnode-functions)
- [DAGNode.create(data, links, callback)](#dagnodecreatedata-links-callback)
- [addLink(node, link, callback)](#addlinknode-link-callback)
- [rmLink(node, nameOrCid, callback)](#rmlinknode-nameorcid-callback)
- [clone(node, callback)](#clonenode-callback)
- [DAGNode.create(data, links)](#dagnodecreatedata-links)
- [addLink(node, link)](#addlinknode-link)
- [rmLink(node, nameOrCid)](#rmlinknode-nameorcid)
- [clone(node)](#clonenode)
- [DAGNode instance methods and properties](#dagnode-instance-methods-and-properties)
- [`node.data`](#nodedata)
- [`node.links`](#nodelinks)
- [`node.size`](#nodesize)
- [`node.toJSON()`](#nodetojson)
- [`node.toString()`](#nodetostring)
- [DAGLink functions](#daglink-functions)
- [DAGLink.create(name, size, cid, callback)](#daglinkcreatename-size-cid-callback)
- [DAGLink.create(name, size, cid)](#daglinkcreatename-size-cid)
- [DAGLink instance methods and properties](#daglink-instance-methods-and-properties)
- [`link.name`](#linkname)
- [`link.size`](#linksize)
Expand Down Expand Up @@ -83,15 +83,10 @@ dagPB.util
#### Create a DAGNode

```JavaScript
DAGNode.create(new Buffer('some data'), (err, node1) => {
if (err) {
throw error
}
// node1 is your DAGNode instance.
})
const node1 = DAGNode.create(Buffer.from('some data'))

DAGNode.create('some data', (err, node2) => {
// node2 will have the same data as node1.
// node2 will have the same data as node1
const node2 = DAGNode.create('some data')
})
```

Expand All @@ -104,22 +99,13 @@ const link = {
size: 42
}

DAGNode.addLink(node, link, (err, nodeA) => {
if (err) {
throw err
}
// node - DAGNode instance with the link
console.log('with link', nodeA.toJSON())

DAGNode.rmLink(nodeA, 'I am a link', (err, nodeB) => {
if (err) {
throw err
}

// node - DAGNode instance without the link, equal to just node
console.log('without link', nodeB.toJSON())
})
})
const nodeA = await DAGNode.addLink(node, link)
// nodeA - DAGNode instance with the link
console.log('with link', nodeA.toJSON())

const nodeB = await DAGNode.rmLink(nodeA, 'I am a link')
// nodeB - DAGNode instance without the link, equal to just node
console.log('without link', nodeB.toJSON())
```

## API
Expand All @@ -135,18 +121,15 @@ const dagPB = require('ipld-dag-pb')
const DAGNode = dagPB.DAGNode
```

#### DAGNode.create(data, links, callback)
#### DAGNode.create(data, links)

- `data` - type: Buffer
- `links`- type: Array of DAGLink instances or Array of DAGLink instances in its json format (link.toJSON)
- `callback` - type: function with signature `function (err, node) {}`

Create a DAGNode.

```JavaScript
DAGNode.create('data', links, (err, dagNode) => {
// ...
})
const dagNode = DAGNode.create('data', links)
```

links can be a single or an array of DAGLinks instances or objects with the following pattern
Expand All @@ -159,11 +142,10 @@ links can be a single or an array of DAGLinks instances or objects with the foll
}
```

#### addLink(node, link, callback)
#### addLink(node, link)

- `node` - type: DAGNode
- `link` - type: DAGLink or DAGLink in its json format
- `callback` - type: function with signature `function (err, node) {}`

Creates a link on node A to node B by using node B to get its CID. Returns a *new* instance of DAGNode without modifying the old one.

Expand All @@ -175,34 +157,34 @@ Creates a new DAGNode instance with the union of node.links plus the new link.
- Object with the following properties:

```JavaScript
{
const link = {
name: '<some string>', // optional
size: <size in bytes>,
cid: <cid> // can be a String CID, CID buffer or CID object
}

const dagNode = await DAGNode.addLink(node, link)
```

#### rmLink(node, nameOrCid, callback)
#### rmLink(node, nameOrCid)

- `node` - type: DAGNode
- `nameOrCid` - type: String, CID object or CID buffer
- `callback` - type: function with signature `function (err, node) {}`

Removes a link from the node by name. Returns a *new* instance of DAGNode without modifying the old one.

```JavaScript
DAGNode.rmLink(node, 'Link1' (err, dagNode) => ...)
const dagNode = await DAGNode.rmLink(node, 'Link1')
```

#### clone(node, callback)
#### clone(node)

- `node` - type: DAGNode
- `callback` - type: function with signature `function (err, node) {}`

Creates a clone of the DAGNode instance passed

```JavaScript
DAGNode.clone(node, (err, nodeClone) => {})
const nodeClone = DAGNode.clone(node)
```

### DAGNode instance methods and properties
Expand Down Expand Up @@ -235,19 +217,15 @@ const dagPB = require('ipld-dag-pb')
const DAGLink = dagPB.DAGLink
```

#### DAGLink.create(name, size, cid, callback)
#### DAGLink.create(name, size, cid)

```JavaScript
DAGLink.create(
// link is a DAGLink instance
const link = DAGLink.create(
'link-to-file', // name of the link (can be empty)
10, // size in bytes
'QmSomeHash...', // can be CID object, CID buffer or string
(err, link) => {
if (err) {
throw err
}
// link is a DAGLink instance
})
)
```

Note: DAGLinks are simpler objects and can be instantiated directly:
Expand Down
7 changes: 4 additions & 3 deletions package.json
Expand Up @@ -62,25 +62,26 @@
"npm": ">=3.0.0"
},
"dependencies": {
"async": "^2.6.1",
"cids": "~0.5.4",
"class-is": "^1.1.0",
"multihashing-async": "~0.6.0",
"multicodec": "~0.5.0",
"multihashing-async": "~0.7.0",
"protons": "^1.0.1",
"stable": "~0.1.8"
},
"devDependencies": {
"aegir": "^18.2.0",
"async": "^2.6.2",
"bs58": "^4.0.1",
"chai": "^4.1.2",
"chai-checkmark": "^1.0.1",
"detect-node": "^2.0.4",
"dirty-chai": "^2.0.1",
"ipfs-block": "~0.8.0",
"ipfs-block-service": "~0.15.2",
"ipfs-repo": "~0.26.0",
"multihashes": "~0.4.14",
"ncp": "^2.0.0",
"promisify-es6": "^1.0.3",
"rimraf": "^2.6.2"
}
}
10 changes: 0 additions & 10 deletions src/dag-link/create.js

This file was deleted.

26 changes: 15 additions & 11 deletions src/dag-link/index.js
Expand Up @@ -3,6 +3,7 @@
const CID = require('cids')
const assert = require('assert')
const withIs = require('class-is')
const visibility = require('../visibility')

// Link represents an IPFS Merkle DAG Link between Nodes.
class DAGLink {
Expand All @@ -16,25 +17,29 @@ class DAGLink {
this._nameBuf = null
this._size = size
this._cid = new CID(cid)

// Make sure we have a nice public API that can be used by an IPLD resolver
visibility.hidePrivateFields(this)
visibility.addEnumerableGetters(this, ['Hash', 'Name', 'Tsize'])
}

toString () {
return `DAGLink <${this._cid.toBaseEncodedString()} - name: "${this.name}", size: ${this.size}>`
return `DAGLink <${this._cid.toBaseEncodedString()} - name: "${this.Name}", size: ${this.Tsize}>`
}

toJSON () {
if (!this._json) {
this._json = Object.freeze({
name: this.name,
size: this.size,
cid: this._cid.toBaseEncodedString()
name: this.Name,
size: this.Tsize,
cid: this.Hash.toBaseEncodedString()
})
}

return Object.assign({}, this._json)
}

get name () {
get Name () {
return this._name
}

Expand All @@ -50,27 +55,26 @@ class DAGLink {
return this._nameBuf
}

set name (name) {
set Name (name) {
throw new Error("Can't set property: 'name' is immutable")
}

get size () {
get Tsize () {
return this._size
}

set size (size) {
set Tsize (size) {
throw new Error("Can't set property: 'size' is immutable")
}

get cid () {
get Hash () {
return this._cid
}

set cid (cid) {
set Hash (cid) {
throw new Error("Can't set property: 'cid' is immutable")
}
}

exports = module.exports = withIs(DAGLink, { className: 'DAGLink', symbolName: '@ipld/js-ipld-dag-pb/daglink' })
exports.create = require('./create')
exports.util = require('./util')
2 changes: 1 addition & 1 deletion src/dag-link/util.js
Expand Up @@ -5,7 +5,7 @@ const DAGLink = require('./index')
function createDagLinkFromB58EncodedHash (link) {
return new DAGLink(
link.name ? link.name : link.Name,
link.size ? link.size : link.Size,
link.size ? link.size : link.Tsize,
link.hash || link.Hash || link.multihash || link.cid
)
}
Expand Down
26 changes: 8 additions & 18 deletions src/dag-node/addLink.js
Expand Up @@ -8,40 +8,30 @@ const DAGLink = require('../dag-link')
const DAGNode = require('./index')
const create = require('./create')

function asDAGLink (link, callback) {
const asDAGLink = async (link) => {
if (DAGLink.isDAGLink(link)) {
// It's a DAGLink instance
// no need to do anything

return callback(null, link)
return link
}

if (DAGNode.isDAGNode(link)) {
// It's a DAGNode instance
// convert to link
return toDAGLink(link, {}, callback)
return toDAGLink(link, {})
}

// It's a Object with name, multihash/hash/cid and size
try {
callback(null, new DAGLink(link.name, link.size, link.multihash || link.hash || link.cid))
} catch (err) {
return callback(err)
}
return new DAGLink(link.name, link.size, link.multihash || link.hash || link.cid)
}

function addLink (node, link, callback) {
const addLink = async (node, link) => {
const links = cloneLinks(node)
const data = cloneData(node)

asDAGLink(link, (error, link) => {
if (error) {
return callback(error)
}

links.push(link)
create(data, links, callback)
})
const dagLink = await asDAGLink(link)
links.push(dagLink)
return create(data, links)
}

module.exports = addLink
25 changes: 25 additions & 0 deletions src/dag-node/addNamedLink.js
@@ -0,0 +1,25 @@
'use strict'

/**
* Adds a link with its name as property to an object.
*
* The link won't be added if its name is empty or matches one of the existing
* properties.
*
* @param {Object} object - The object that contains an array of links
* @param {string} name - The name of the link to add
* @param {numner} position - The position within the array of links
*/
const addNamedLink = (object, name, position) => {
const skipNames = ['', ...Object.keys(this)]
if (skipNames.includes(name)) {
return
}
Object.defineProperty(object, name, {
enumerable: true,
configurable: true,
get: () => object._links[position]
})
}

module.exports = addNamedLink
4 changes: 2 additions & 2 deletions src/dag-node/clone.js
Expand Up @@ -5,10 +5,10 @@ const cloneLinks = dagNodeUtil.cloneLinks
const cloneData = dagNodeUtil.cloneData
const create = require('./create')

function clone (dagNode, callback) {
function clone (dagNode) {
const data = cloneData(dagNode)
const links = cloneLinks(dagNode)
create(data, links, callback)
return create(data, links)
}

module.exports = clone

0 comments on commit 1de1bcc

Please sign in to comment.