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

feat: update DAGLink and DAGNode to have an immutable API #6

Merged
merged 13 commits into from
Nov 24, 2016
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
178 changes: 141 additions & 37 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

[![Sauce Test Status](https://saucelabs.com/browser-matrix/ipld-js-dag-pb.svg)](https://saucelabs.com/u/ipld-js-dag-pb)

> JavaScript Implementation of the IPLD Format MerkleDAG Node in Protobuf.
> JavaScript Implementation of the IPLD Format MerkleDAG Node in Protobuf. In addition to the IPLD Format methods, this module also provides an API for creating the nodes and manipulating them (adding and removing links, etc).

## Table of Contents

Expand All @@ -28,89 +28,193 @@
## Install

```bash
> npm i ipld-dag-pb
> npm install ipld-dag-pb --save
```

## Usage

```js
```JavaScript
const dagPB = require('ipld-dag-pb')

// then, to access each of the components
dagPB.DAGNode
dagPB.DAGNode.create // create a DAGNode
dagPB.DAGNode.clone // clone a DAGNode
dagPB.DAGNode.addLink // add a Link to a DAGNode, creating a new one
dagPB.DAGNode.rmLinkq // remove a Link to a DAGNode, creating a new one
dagPB.DAGLink.create // create a DAGLink

// IPLD Format specifics
dagPB.resolver
dagPB.util
```

### Examples

#### Create a DAGNode

```JavaScript
// TODO
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: please fill or remove before merge

```

#### Add and remove a Link

```JavaScript
// TODO
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: please fill or remove before merge

```

## API

### DAGNode Class
### DAGNode functions

DAGNodes are immutable objects, in order to manipulate them you have to follow a function approach of applying function and getting new instances of the given DAGNode.

You can incude it in your project with:

```JavaScript
const dagPB = require('ipld-dag-pb')
const DAGNode = dagPB.DAGNode
```

#### DAGNode.create(data, links, hashAlg, callback)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please document the argument types


Create a DAGNode.

```JavaScript
DAGNode.create("data", links, (err, dagNode) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

quotes

})
```

links can be a single or an array of DAGLinks instances or objects with the following pattern

```JavaScript
{
name: '<some name>',
hash: '<some multihash>', // can also be `multihash: <some multihash>`
size: <sizeInBytes>
}
```

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please document the argument types


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

Create a new DAGNode
Creates a new DAGNode instance with the union of node.links plus the new link.

`link` can be:
- DAGLink instance
- DAGNode instance
- Object with the following properties:

```JavaScript
var node = new dagPB.DAGNode([<data>, <[links]>])
{
name: '<some string>', // optional
size: <size in bytes>,
multihash: <multihash> // can be a String multihash or multihash buffer
}
```

#### `addNodeLink`

> creates a link on node A to node B by using node B to get its multihash
#### rmLink(node, nameOrMultihash, callback)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please document the argument types


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

> creates a link on node A to node B by using directly node B multihash
```JavaScript
DAGNode.rmLink(node, "Link1" (err, dagNode) => ...)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

single quotes

```

#### `updateNodeLink`
#### clone(node, callback)

> updates a link on the node. *caution* this method returns a copy of the MerkleDAG node
Creates a clone of the DAGNode instance passed
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please document the argument types


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

> removes a link from the node by name
### DAGNode instance methods and properties

#### `removeNodeLinkByHash`
You have the following methods and properties available in every DAGNode instance.

> removes a link from the node by the hash of the linked node
#### `node.data`

#### `node.links`

#### `clone`
An array of `DAGLinks`

> creates a clone of the MerkleDAG Node
#### `node.size`

#### `size`
Size of the node, in bytes

> (property) size of the node, in bytes
#### `node.multihash`

#### `links`
#### `node.serialized`

> (property) an array of `DAGLink`s belonging to the node
#### `node.toJSON()`

#### `multihash(callback)`
#### `node.toString()`

> returns the multihash (default: sha2-256)

#### `getPBNode`
### DAGLink functions

> used internally
Following the same pattern as [`DAGNode functions`]() above, DAGLink also offers a function for its creation.

#### `makeLink`
You can incude it in your project with:

> used internally
```JavaScript
const dagPB = require('ipld-dag-pb')
const DAGLink = dagPB.DAGLink
```

### DAGLink Class
#### DAGLink.create(name, size, multihash, callback)

```JavaScript
DAGLink.create('link-to-file', // name of the link (can be empty)
10, // size in bytes
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please use the same indentation that we use elsewhere:

DAGLink.create(
  'link-to-file',
  10,
  ...
)

'QmSomeHash...', // can be multihash buffer or string
(err, link) => {
if (err) {
throw err
}
// link is a DAGLink instance
})
```

Create a new DAGLink
Note: DAGLinks are simpler objects and can be instantiated directly:

```JavaScript
var link = new dagPB.DAGLink(<name>, <size>, <hash>)
const link = new DAGLink(name, size, multihash)
```

### Local Resolver (to be used by the IPLD Resolver)
### DAGLink instance methods and properties

#### `link.name`

#### `link.size`

#### `link.multihash`

#### `link.toJSON()`

#### `link.toString()`

### [IPLD Format Specifics](https://github.com/ipld/interface-ipld-format) - Local (node/block scope) resolver

> See: https://github.com/ipld/interface-ipld-format#local-resolver-methods


#### `dagPB.resolver.resolve`

#### `dagPB.resolver.tree`

#### `dagPB.resolver.patch`

### [IPLD Format Specifics](https://github.com/ipld/interface-ipld-format) - util

> See: https://github.com/ipld/interface-ipld-format#ipld-format-utils

#### `resolver.resolve`
### `dagPB.util.cid`

#### `resolver.tree`
### `dagPB.util.serialize`

#### `resolver.patch`
### `dagPB.util.deserialize`

## License

Expand Down
16 changes: 9 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,33 +34,35 @@
"url": "https://github.com/ipld/js-ipld-dag-pb.git"
},
"engines": {
"node": ">=4.0.0"
"node": ">=4.0.0",
"npm": ">=3.0.0"
},
"dependencies": {
"async": "^2.1.2",
"buffer-loader": "0.0.1",
"cids": "^0.2.0",
"ipfs-block": "^0.5.0",
"is-ipfs": "^0.2.1",
"multihashes": "^0.2.2",
"multihashing-async": "^0.2.0",
"protocol-buffers": "^3.1.6",
"protocol-buffers": "^3.1.8",
"pull-stream": "^3.5.0",
"pull-traverse": "^1.0.3",
"stable": "^0.1.5"
},
"devDependencies": {
"aegir": "^9.1.0",
"aegir": "^9.1.2",
"bs58": "^3.0.0",
"buffer-loader": "0.0.1",
"chai": "^3.5.0",
"chai-checkmark": "^1.0.1",
"fs-pull-blob-store": "^0.4.1",
"idb-pull-blob-store": "^0.5.1",
"ipfs-block-service": "^0.6.0",
"ipfs-repo": "^0.11.0",
"lodash": "^4.16.6",
"ipfs-block-service": "^0.7.0",
"ipfs-repo": "^0.11.1",
"lodash": "^4.17.0",
"ncp": "^2.0.0",
"pre-commit": "^1.1.3",
"rimraf": "^2.5.4"
}
}
}
30 changes: 0 additions & 30 deletions src/dag-link.js

This file was deleted.

10 changes: 10 additions & 0 deletions src/dag-link/create.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
'use strict'

const DAGLink = require('./index.js')

function create (name, size, multihash, callback) {
const link = new DAGLink(name, size, multihash)
callback(null, link)
}

module.exports = create
61 changes: 61 additions & 0 deletions src/dag-link/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
'use strict'

const mh = require('multihashes')
const assert = require('assert')

// Link represents an IPFS Merkle DAG Link between Nodes.
class DAGLink {
constructor (name, size, multihash) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are you not asserting for name but the other two?

Copy link
Member Author

@daviddias daviddias Nov 23, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

names are not mandatory. See files in unixfs, a file has N chunks, but no names.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But that is not handled properly as new DAGLink(123, 'myhash') throws at the moment

assert(multihash, 'A link requires a multihash to point to')
assert(size, 'A link requires a size')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

assert it's a number while you are at it


this._name = name
this._size = size

if (typeof multihash === 'string') {
this._multihash = mh.fromB58String(multihash)
} else if (Buffer.isBuffer(multihash)) {
this._multihash = multihash
}
}

toString () {
const mhStr = mh.toB58String(this.multihash)
return `DAGLink <${mhStr} - name: "${this.name}", size: ${this.size}>`
}

toJSON () {
return {
name: this.name,
size: this.size,
hash: this.multihash ? mh.toB58String(this.multihash) : undefined
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for this check, you assert the existence of multihash in the constructor

}
}

get name () {
return this._name
}

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

get size () {
return this._size
}

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

get multihash () {
return this._multihash
}

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

exports = module.exports = DAGLink
exports.create = require('./create')
Loading