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

Commit

Permalink
feat(package): backwards compatible pure data model API
Browse files Browse the repository at this point in the history
  • Loading branch information
Gozala authored and vmx committed Jul 9, 2020
1 parent 1012cad commit 0f11d5c
Show file tree
Hide file tree
Showing 10 changed files with 304 additions and 251 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
"aegir": "^22.0.0",
"chai": "^4.2.0",
"dirty-chai": "^2.0.1",
"chai-subset": "1.6.0",
"fs-extra": "^9.0.0",
"ipfs-block-service": "~0.17.0",
"ipfs-repo": "^3.0.0",
Expand All @@ -84,4 +85,4 @@
"multibase": "^0.7.0",
"multihashes": "~0.4.19"
}
}
}
38 changes: 8 additions & 30 deletions src/dag-link/dagLink.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,16 @@ class DAGLink {
// note - links should include size, but this assert is disabled
// for now to maintain consistency with go-ipfs pinset

this._name = name || ''
this._nameBuf = null
this._size = size
this._cid = new CID(cid)
Object.defineProperties(this, {
Name: { value: name || '', writable: false, enumerable: true },
Tsize: { value: size, writable: false, enumerable: true },
Hash: { value: new CID(cid), writable: false, enumerable: true },
_nameBuf: { value: null, writable: true, enumerable: false }
})
}

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

toJSON () {
Expand All @@ -37,10 +39,6 @@ class DAGLink {
return Object.assign({}, this._json)
}

get Name () {
return this._name
}

// Memoize the Buffer representation of name
// We need this to sort the links, otherwise
// we will reallocate new buffers every time
Expand All @@ -49,29 +47,9 @@ class DAGLink {
return this._nameBuf
}

this._nameBuf = Buffer.from(this._name)
this._nameBuf = Buffer.from(this.Name)
return this._nameBuf
}

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

get Tsize () {
return this._size
}

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

get Hash () {
return this._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' })
4 changes: 2 additions & 2 deletions src/dag-node/addLink.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ const asDAGLink = (link) => {

const addLink = (node, link) => {
const dagLink = asDAGLink(link)
node._links.push(dagLink)
node._links = sortLinks(node._links)
node.Links.push(dagLink)
sortLinks.inplace(node.Links)
}

module.exports = addLink
46 changes: 11 additions & 35 deletions src/dag-node/dagNode.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,24 +25,26 @@ class DAGNode {
throw new Error('Passed \'serializedSize\' must be a number!')
}

links = links.map((link) => {
links = links.map(link => {
return DAGLink.isDAGLink(link)
? link
: DAGLink.util.createDagLinkFromB58EncodedHash(link)
})
links = sortLinks(links)
sortLinks.inplace(links)

this._data = data
this._links = links
this._serializedSize = serializedSize
this._size = null
Object.defineProperties(this, {
Data: { value: data, writable: false, enumerable: true },
Links: { value: links, writable: false, enumerable: true },
_serializedSize: { value: serializedSize, writable: true, enumerable: false },
_size: { value: null, writable: true, enumerable: false }
})
}

toJSON () {
if (!this._json) {
this._json = Object.freeze({
data: this.Data,
links: this._links.map((l) => l.toJSON()),
links: this.Links.map((l) => l.toJSON()),
size: this.size
})
}
Expand Down Expand Up @@ -75,18 +77,15 @@ class DAGNode {
}

serialize () {
return serializeDAGNode({
Data: this._data,
Links: this._links
})
return serializeDAGNode(this)
}

get size () {
if (this._size === null) {
if (this._serializedSize === null) {
this._serializedSize = this.serialize().length
}
this._size = this._links.reduce((sum, l) => sum + l.Tsize, this._serializedSize)
this._size = this.Links.reduce((sum, l) => sum + l.Tsize, this._serializedSize)
}

return this._size
Expand All @@ -95,29 +94,6 @@ class DAGNode {
set size (size) {
throw new Error("Can't set property: 'size' is immutable")
}

// Getters for backwards compatible path resolving
get Data () {
return this._data
}

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

get Links () {
return this._links.map((link) => {
return {
Name: link.Name,
Tsize: link.Tsize,
Hash: link.Hash
}
})
}

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

exports = module.exports = withIs(DAGNode, { className: 'DAGNode', symbolName: '@ipld/js-ipld-dag-pb/dagnode' })
20 changes: 17 additions & 3 deletions src/dag-node/rmLink.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,26 @@ const CID = require('cids')
const { Buffer } = require('buffer')

const rmLink = (dagNode, nameOrCid) => {
let predicate = null

// It's a name
if (typeof nameOrCid === 'string') {
dagNode._links = dagNode._links.filter((link) => link.Name !== nameOrCid)
predicate = link => link.Name === nameOrCid
} else if (Buffer.isBuffer(nameOrCid) || CID.isCID(nameOrCid)) {
dagNode._links = dagNode._links.filter(
(link) => !link.Hash.equals(nameOrCid))
predicate = link => link.Hash.equals(nameOrCid)
}

if (predicate) {
const links = dagNode.Links
let index = 0
while (index < links.length) {
const link = links[index]
if (predicate(link)) {
links.splice(index, 1)
} else {
index++
}
}
} else {
throw new Error('second arg needs to be a name or CID')
}
Expand Down
13 changes: 12 additions & 1 deletion src/dag-node/sortLinks.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,23 @@ const linkSort = (a, b) => {
}

/**
*
* Returns new sorted links array.
* @param {Array} links
* @returns {Array}
*/
const sortLinks = (links) => {
return sort(links, linkSort)
}

/**
* Sorts links in place (mutating given array)
* @param {Array} links
* @returns {void}
*/
const sortLinksInPlace = (links) => {
sort.inplace(links, linkSort)
}

sortLinks.inplace = sortLinksInPlace

module.exports = sortLinks
24 changes: 21 additions & 3 deletions src/serialize.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ exports = module.exports
const toProtoBuf = (node) => {
const pbn = {}

if (node.Data && node.Data.length > 0) {
pbn.Data = node.Data
if (node.Data && node.Data.byteLength > 0) {
pbn.Data = asBuffer(node.Data)
} else {
// NOTE: this has to be null in order to match go-ipfs serialization
// `null !== new Buffer(0)`
Expand All @@ -20,7 +20,7 @@ const toProtoBuf = (node) => {
if (node.Links && node.Links.length > 0) {
pbn.Links = node.Links
.map((link) => ({
Hash: link.Hash.buffer,
Hash: asBuffer(link.Hash.buffer),
Name: link.Name,
Tsize: link.Tsize
}))
Expand All @@ -31,6 +31,24 @@ const toProtoBuf = (node) => {
return pbn
}

/**
* Takes bytes in various representations and returns `Buffer`
* view of the underyling data without copying.
* @param {Buffer|ArrayBuffer|ArrayBufferView} bytes
* @returns {Buffer}
*/
const asBuffer = (bytes) => {
if (Buffer.isBuffer(bytes)) {
return bytes
} else if (bytes instanceof ArrayBuffer) {
return Buffer.from(bytes, 0, bytes.byteLength)
} else if (ArrayBuffer.isView(bytes)) {
return Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength)
} else {
return bytes
}
}

/**
* Serialize internal representation into a binary PB block.
*
Expand Down
4 changes: 3 additions & 1 deletion test/dag-node-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
const chai = require('chai')
const { Buffer } = require('buffer')
const dirtyChai = require('dirty-chai')
const chaiSubset = require('chai-subset')
const expect = chai.expect
chai.use(dirtyChai)
chai.use(chaiSubset)

const dagPB = require('../src')
const DAGLink = dagPB.DAGLink
Expand Down Expand Up @@ -80,7 +82,7 @@ module.exports = (repo) => {
})

const node2 = new DAGNode(someData, l2)
expect(node2.Links).to.eql([l1[1], l1[0]])
expect(node2.Links).to.containSubset([l1[1], l1[0]])
expect(node1.toJSON()).to.eql(node2.toJSON())

// check sorting
Expand Down
Loading

0 comments on commit 0f11d5c

Please sign in to comment.