From f7d5c171f7a1c5608a9ae48ec070083de5619ad5 Mon Sep 17 00:00:00 2001 From: Michael Iwersen Date: Thu, 7 Jan 2016 00:24:46 +0100 Subject: [PATCH 1/3] Added tests and sorting of children based on priority --- .babelrc | 3 ++- package.json | 1 + src/node.js | 5 +++++ src/tree.js | 17 ++++++++++++----- test/node.js | 44 ++++++++++++++++++++++++++++++++------------ test/tree.js | 52 ++++++++++++++++++++++++++++++++++++---------------- 6 files changed, 88 insertions(+), 34 deletions(-) diff --git a/.babelrc b/.babelrc index ce107e4..8ed2d65 100644 --- a/.babelrc +++ b/.babelrc @@ -8,6 +8,7 @@ "babel-plugin-transform-es2015-block-scoping", "babel-plugin-check-es2015-constants", "babel-plugin-transform-es2015-classes", - "babel-plugin-transform-es2015-template-literals" + "babel-plugin-transform-es2015-template-literals", + "babel-plugin-transform-es2015-arrow-functions" ] } \ No newline at end of file diff --git a/package.json b/package.json index b51786d..b5c059f 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "devDependencies": { "babel-cli": "^6.3.17", "babel-plugin-check-es2015-constants": "^6.3.13", + "babel-plugin-transform-es2015-arrow-functions": "^6.4.0", "babel-plugin-transform-es2015-block-scoping": "^6.3.13", "babel-plugin-transform-es2015-classes": "^6.3.15", "babel-plugin-transform-es2015-modules-commonjs": "^6.3.16", diff --git a/src/node.js b/src/node.js index 5863d2c..03d8929 100644 --- a/src/node.js +++ b/src/node.js @@ -12,6 +12,7 @@ export class Node { append(node) { this.children.push(node) + this.sort() } remove(node) { @@ -23,6 +24,10 @@ export class Node { this.children.splice(position, 1) } + + sort() { + this.children.sort((a, b) => b.priority - a.priority) + } } Node.DEFAULT = 0 diff --git a/src/tree.js b/src/tree.js index 853b0b5..195010c 100644 --- a/src/tree.js +++ b/src/tree.js @@ -16,6 +16,8 @@ export class Tree { const fullPath = path let node = this.root + node.priority++ + node_loop: while (node) { path = path.substr(node.path.length) @@ -30,8 +32,6 @@ export class Tree { return this } - node.priority++ - if (node.children.length) { for (let nodeIndex = 0; nodeIndex < node.children.length; nodeIndex++) { if ( node.children[nodeIndex].path[0] === path[0] ) { @@ -44,30 +44,38 @@ export class Tree { } } + // go further down the tree if (pathCompareIndex >= selectedNode.path.length) { + node.children[nodeIndex].priority++ + node.sort() + node = selectedNode continue node_loop + // we inject a new node, cause the new path is part of this one } else if (pathCompareIndex >= path.length) { let newChild = new Node(path, fullPath, data) selectedNode.path = selectedNode.path.replace(path, '') node.remove(selectedNode) - node.append(newChild) newChild.priority = selectedNode.priority + 1 newChild.append(selectedNode) + node.append(newChild) + return this + // we match partly, generate a new edge } else if (pathCompareIndex > 0) { let newEdge = new Node(path.substr(0, pathCompareIndex), '', null) selectedNode.path = selectedNode.path.substr(pathCompareIndex) + newEdge.priority = selectedNode.priority + 1 + node.remove(selectedNode) node.append(newEdge) - newEdge.priority = selectedNode.priority + 1 newEdge.append(selectedNode) node = newEdge @@ -84,7 +92,6 @@ export class Tree { return this } - return this } diff --git a/test/node.js b/test/node.js index 7f66599..bb2cd2f 100644 --- a/test/node.js +++ b/test/node.js @@ -33,20 +33,40 @@ describe('Node', function() { expect(parent.children.length).to.be.equal(1) }) - it.skip('updatePriority should increase priority for every child', function () { + it('appending should order children based by their priority', function () { let parent = new Node('/parent', '/parent') - let child = new Node('/child', '/parent/child') - let grandChild = new Node('/grandchild', '/parent/child/grandchild') + let child1 = new Node('/child1', '/parent/child1') + let child2 = new Node('/child2', '/parent/child2') - expect(parent.priority).to.be.equal(1) - parent.append(child) - parent.updatePriority() - expect(parent.priority).to.be.equal(1) - child.append(grandChild) - child.updatePriority() - parent.updatePriority() - expect(child.priority).to.be.equal(1) - expect(parent.priority).to.be.equal(2) + child1.priority = 1 + child2.priority = 2 + + parent.append(child1) + parent.append(child2) + + expect(parent.children).to.deep.equal([child2, child1]) }) + it('sort should order children based by their priority', function () { + let parent = new Node('/parent', '/parent') + let child1 = new Node('/child1', '/parent/child1') + let child2 = new Node('/child2', '/parent/child2') + + child1.priority = 1 + child2.priority = 1 + + parent.append(child1) + parent.append(child2) + + expect(parent.children).to.deep.equal([child1, child2]) + + child2.priority = 2 + + parent.sort() + + expect(parent.children).to.deep.equal([child2, child1]) + }) + + + }) diff --git a/test/tree.js b/test/tree.js index a46e859..11e5e39 100644 --- a/test/tree.js +++ b/test/tree.js @@ -36,22 +36,6 @@ describe('Tree', function() { expect(instance.root.priority).to.be.equal(4) }) - it('should be possible to add new plain entries', function () { - let instance = new Tree() - - instance.add('/account') - instance.add('/account/users') - instance.add('/account/users/add') - instance.add('/account/users/change') - instance.add('/account/users/delete') - instance.add('/account/addresses') - instance.add('/account/addresses/add') - instance.add('/account/addresses/change') - instance.add('/account/addresses/delete') - - expect(instance.root.priority).to.be.equal(10) - }) - it('should be possible to add new plain entries', function () { let instance = new Tree() @@ -69,6 +53,42 @@ describe('Tree', function() { expect(instance.root.priority).to.be.equal(11) }) + it('the order should be based on the priority', function () { + let instance = new Tree() + + instance.add('/path2') + instance.add('/path1') + instance.add('/path1/subpath') + + expect(instance.root.priority).to.be.equal(4) + expect(instance.root.children[0].children[0].fullPath).to.be.equal('/path1') + expect(instance.root.children[0].children[1].fullPath).to.be.equal('/path2') + }) + + it('the order should be based on the priority, even when splitting and adding an edge', function () { + let instance = new Tree() + + instance.add('/path2') + instance.add('/path1/subpath') + instance.add('/path1') + + expect(instance.root.priority).to.be.equal(4) + expect(instance.root.children[0].children[0].fullPath).to.be.equal('/path1') + expect(instance.root.children[0].children[1].fullPath).to.be.equal('/path2') + }) + + it('the order should be based on the priority, even when adding a longer path', function () { + let instance = new Tree() + + instance.add('/path2') + instance.add('/path1/subpath') + + expect(instance.root.priority).to.be.equal(3) + expect(instance.root.children[0].children[0].fullPath).to.be.equal('/path2') + expect(instance.root.children[0].children[1].fullPath).to.be.equal('/path1/subpath') + }) + + it('should return the node on exact match of the path', function () { let instance = new Tree() From 38336d1f7b9651bc7f2b075e0e17701ce00d7788 Mon Sep 17 00:00:00 2001 From: Michael Iwersen Date: Thu, 7 Jan 2016 12:48:22 +0100 Subject: [PATCH 2/3] Increased version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b5c059f..78d00af 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "radix-tree", - "version": "0.1.4", + "version": "0.2.0", "description": "Node.js version of a radix tree usable for routers or url path based storage.", "main": "index.js", "engines": { From 672cc97e8de9e2de738118d5148cefb8796da1ac Mon Sep 17 00:00:00 2001 From: Michael Iwersen Date: Thu, 7 Jan 2016 12:55:55 +0100 Subject: [PATCH 3/3] Explination of priority sorting --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/README.md b/README.md index 7c8b170..cfe4288 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,20 @@ console.log(instance.find('/my_path').data) // will output "data" The second parameter in `Tree.add()` can be anything, a string, a function or an object. The stored path, data and contained parameters will be returned via `Tree.find()`. +### Priority + +With version 0.2.0 routes are internally sorted by priority and no longer handled FIFO, routes with many childs have a higher priority and are scanned earlier. + +Adding first `/users` and then `/cart/add` and `/cart/remove` will result in reordering of the children and place cart before users.Expl + +``` +(3) / +(2) cart/ +(1) add +(1) remove +(1) users +``` + ### Static routes A static route can be any type of endpoint of a service, valid examples are: