1
0
Fork 0

GraphViewer: Added a further abstraction layer for the adapters, makes it much easier to write adapters for different sources like FOXX

This commit is contained in:
Michael Hackstein 2013-06-06 16:30:51 +02:00
parent fb33638b91
commit f719a32251
5 changed files with 809 additions and 201 deletions

View File

@ -124,10 +124,10 @@ function AbstractAdapter(nodes, edges) {
source = findNode(data._from);
target = findNode(data._to);
if (!source) {
throw "Unable to insert Edge, source node not existing " + edge._from;
throw "Unable to insert Edge, source node not existing " + data._from;
}
if (!target) {
throw "Unable to insert Edge, target node not existing " + edge._to;
throw "Unable to insert Edge, target node not existing " + data._to;
}
edge.source = source;
edge.target = target;
@ -323,9 +323,8 @@ function AbstractAdapter(nodes, edges) {
},
checkSizeOfInserted = function (inserted) {
var buckets;
if (_.size(inserted) > childLimit) {
buckets = reducer.bucketNodes(_.values(inserted), childLimit);
var buckets = reducer.bucketNodes(_.values(inserted), childLimit);
_.each(buckets, function(b) {
if (b.length > 1) {
var ids = _.map(b, function(n) {

View File

@ -367,7 +367,7 @@ function ArangoAdapter(nodes, edges, config) {
processData: false,
success: function() {
absAdapter.removeEdgesForNode(nodeToRemove);
permanentlyRemoveEdgesOfNode(nodeToRemove._id);
permanentlyRemoveEdgesOfNode(nodeToRemove._id);
absAdapter.removeNode(nodeToRemove);
if (callback !== undefined && _.isFunction(callback)) {
callback();

View File

@ -0,0 +1,725 @@
/*jslint indent: 2, nomen: true, maxlen: 100, white: true plusplus: true */
/*global beforeEach, afterEach */
/*global describe, it, expect, jasmine */
/*global runs, spyOn, waitsFor, waits */
/*global window, eb, loadFixtures, document */
/*global $, _, d3*/
/*global describeInterface*/
/*global AbstractAdapter*/
////////////////////////////////////////////////////////////////////////////////
/// @brief Graph functionality
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-2012 triagens GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Michael Hackstein
/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
(function () {
"use strict";
describe('Abstract Adapter', function () {
var nodes, edges,
getCommunityNodes = function() {
return _.filter(nodes, function(n) {
return String(n._id).match(/^\*community/);
});
},
getCommunityNodesIds = function() {
return _.pluck(getCommunityNodes(), "_id");
},
nodeWithID = function(id) {
return $.grep(nodes, function(e){
return e._id === id;
})[0];
},
edgeWithSourceAndTargetId = function(sourceId, targetId) {
return $.grep(edges, function(e){
return e.source._id === sourceId
&& e.target._id === targetId;
})[0];
},
existNode = function(id) {
var node = nodeWithID(id);
expect(node).toBeDefined();
expect(node._id).toEqual(id);
},
notExistNode = function(id) {
var node = nodeWithID(id);
expect(node).toBeUndefined();
},
existEdge = function(source, target) {
var edge = edgeWithSourceAndTargetId(source, target);
expect(edge).toBeDefined();
expect(edge.source._id).toEqual(source);
expect(edge.target._id).toEqual(target);
},
notExistEdge = function(source, target) {
var edge = edgeWithSourceAndTargetId(source, target);
expect(edge).toBeUndefined();
},
existNodes = function(ids) {
_.each(ids, existNode);
},
notExistNodes = function(ids) {
_.each(ids, notExistNode);
};
beforeEach(function() {
nodes = [];
edges = [];
});
describe('setup process', function() {
it('should throw an error if nodes are not given', function() {
expect(
function() {
var t = new AbstractAdapter();
}
).toThrow("The nodes have to be given.");
});
it('should throw an error if edges are not given', function() {
expect(
function() {
var t = new AbstractAdapter([]);
}
).toThrow("The edges have to be given.");
});
it('should not throw an error if setup correctly', function() {
expect(
function() {
var t = new AbstractAdapter([], []);
}
).not.toThrow();
});
});
describe('checking the interface', function() {
var testee;
beforeEach(function() {
testee = new AbstractAdapter([], []);
this.addMatchers({
toHaveFunction: function(func, argCounter) {
var obj = this.actual;
this.message = function(){
return testee.constructor.name
+ " should react to function "
+ func
+ " with at least "
+ argCounter
+ " arguments.";
};
if (typeof(obj[func]) !== "function") {
return false;
}
if (obj[func].length < argCounter) {
return false;
}
return true;
}
});
});
it('should offer a function to set the width', function() {
expect(testee).toHaveFunction("setWidth", 1);
});
it('should offer a function to set the height', function() {
expect(testee).toHaveFunction("setHeight", 1);
});
it('should offer a function to insert a node', function() {
expect(testee).toHaveFunction("insertNode", 1);
});
it('should offer a function to insert an edge', function() {
expect(testee).toHaveFunction("insertEdge", 1);
});
it('should offer a function to remove a node', function() {
expect(testee).toHaveFunction("removeNode", 1);
});
it('should offer a function to remove an edge', function() {
expect(testee).toHaveFunction("removeEdge", 1);
});
it('should offer a function to remove edges for a given node', function() {
expect(testee).toHaveFunction("removeEdgesForNode", 1);
});
it('should offer a function to expand a community', function() {
expect(testee).toHaveFunction("expandCommunity", 1);
});
it('should offer a function to set the node limit', function() {
expect(testee).toHaveFunction("setNodeLimit", 1);
});
it('should offer a function to set the child limit', function() {
expect(testee).toHaveFunction("setChildLimit", 1);
});
it('should offer a function to check the amount of freshly inserted nodes', function() {
expect(testee).toHaveFunction("checkSizeOfInserted", 1);
});
it('should offer a function to check the overall amount of nodes', function() {
expect(testee).toHaveFunction("checkNodeLimit", 1);
});
});
describe('checking nodes', function() {
var adapter;
beforeEach(function() {
adapter = new AbstractAdapter(nodes, []);
});
it('should be possible to insert a node', function() {
var newNode = {_id: 1};
adapter.insertNode(newNode);
existNode(1);
expect(nodes.length).toEqual(1);
});
it('should not add the same node twice', function() {
var newNode = {_id: 1};
adapter.insertNode(newNode);
adapter.insertNode(newNode);
existNode(1);
expect(nodes.length).toEqual(1);
});
it('should add x and y coordinates', function() {
var newNode = {_id: 1};
adapter.insertNode(newNode);
this.addMatchers({
toHaveCorrectCoordinates: function() {
var list = this.actual,
evil;
_.each(list, function(n) {
if (isNaN(n.x) || isNaN(n.y)) {
evil = n;
}
});
this.message = function() {
return "Expected " + JSON.stringify(evil) + " to contain Numbers as X and Y.";
};
return evil === undefined;
}
});
expect(nodes).toHaveCorrectCoordinates();
});
it('should set in- and outbound counters', function() {
var newNode = adapter.insertNode({_id: 1});
expect(newNode._outboundCounter).toEqual(0);
expect(newNode._inboundCounter).toEqual(0);
});
it('should set the x coordinate close to the center', function() {
var width = 200,
newNode;
adapter.setWidth(width);
newNode = adapter.insertNode({_id: 1});
expect(newNode.x).toBeGreaterThan(width / 4);
expect(newNode.x).toBeLessThan(3 * width / 4);
});
it('should set the y coordinate close to the center', function() {
var height = 200,
newNode;
adapter.setHeight(height);
newNode = adapter.insertNode({_id: 1});
expect(newNode.y).toBeGreaterThan(height / 4);
expect(newNode.y).toBeLessThan(3 * height / 4);
});
it('should be able to delete a node', function() {
var toDelete = {_id: 1},
nodeToDelete = adapter.insertNode(toDelete);
adapter.removeNode(nodeToDelete);
notExistNode(1);
expect(nodes.length).toEqual(0);
});
});
describe('checking edges', function() {
var adapter,
source,
target,
sourceid,
targetid;
beforeEach(function() {
adapter = new AbstractAdapter(nodes, edges);
source = adapter.insertNode({_id: 1});
target = adapter.insertNode({_id: 2});
sourceid = source._id;
targetid = target._id;
});
it('should be able to insert an edge', function() {
adapter.insertEdge({
_id: "1-2",
_from: sourceid,
_to: targetid
});
existEdge(sourceid, targetid);
expect(edges.length).toEqual(1);
});
it('should not insert the same edge twice', function() {
var toInsert = {
_id: "1-2",
_from: sourceid,
_to: targetid
};
adapter.insertEdge(toInsert);
adapter.insertEdge(toInsert);
existEdge(sourceid, targetid);
expect(edges.length).toEqual(1);
});
it('should throw an error if an edge is inserted with illeagal source', function() {
expect(
function() {
adapter.insertEdge({
_id: "1-3",
_from: 3,
_to: targetid
});
}
).toThrow("Unable to insert Edge, source node not existing 3");
notExistEdge(3, targetid);
expect(edges.length).toEqual(0);
});
it('should throw an error if an edge is inserted with illeagal target', function() {
expect(
function() {
adapter.insertEdge({
_id: "1-3",
_from: sourceid,
_to: 3
});
}
).toThrow("Unable to insert Edge, target node not existing 3");
notExistEdge(sourceid, 3);
expect(edges.length).toEqual(0);
});
it('should change the in- and outbound counters accordingly', function() {
var toInsert = {
_id: "1-2",
_from: sourceid,
_to: targetid
};
adapter.insertEdge(toInsert);
expect(source._outboundCounter).toEqual(1);
expect(source._inboundCounter).toEqual(0);
expect(target._outboundCounter).toEqual(0);
expect(target._inboundCounter).toEqual(1);
});
it('should be able to delete an edge', function() {
var toDelete = {
_id: "1-2",
_from: sourceid,
_to: targetid
},
edgeToDel = adapter.insertEdge(toDelete);
adapter.removeEdge(edgeToDel);
notExistEdge(sourceid, targetid);
expect(edges.length).toEqual(0);
});
it('should be able to remove all edges of a node', function() {
adapter.insertNode({_id: 3});
adapter.insertEdge({
_id: "3-1",
_from: 3,
_to: sourceid // This is nodes[0]
});
var edgeToKeep = adapter.insertEdge({
_id: "2-3",
_from: targetid, // This is nodes[1]
_to: 3
});
adapter.removeEdgesForNode(source);
existEdge(2, 3);
notExistEdge(1, 2);
notExistEdge(3, 1);
expect(edges.length).toEqual(1);
expect(edges[0]).toEqual(edgeToKeep);
});
it('should maintain in- and outboundcounter '
+ 'when removing all edges of a node', function() {
var thirdNode = adapter.insertNode({_id: 3});
adapter.insertEdge({
_id: "3-1",
_from: 3,
_to: sourceid // This is nodes[0]
});
adapter.insertEdge({
_id: "2-3",
_from: targetid, // This is nodes[1]
_to: 3
});
adapter.removeEdgesForNode(source);
expect(nodes.length).toEqual(3);
existNode(1);
existNode(2);
existNode(3);
expect(source._inboundCounter).toEqual(0);
expect(source._outboundCounter).toEqual(0);
expect(target._inboundCounter).toEqual(0);
expect(target._outboundCounter).toEqual(1);
expect(thirdNode._inboundCounter).toEqual(1);
expect(thirdNode._outboundCounter).toEqual(0);
});
});
describe('checking communities', function() {
var adapter, mockReducer;
beforeEach(function() {
mockReducer = {};
mockReducer.getCommunity = function() {};
mockReducer.bucketNodes = function() {};
spyOn(window, "NodeReducer").andCallFake(function(v, e) {
return {
getCommunity: function(limit, focus) {
if (focus !== undefined) {
return mockReducer.getCommunity(limit, focus);
}
return mockReducer.getCommunity(limit);
},
bucketNodes: function(toSort, numBuckets) {
return mockReducer.bucketNodes(toSort, numBuckets);
}
};
});
adapter = new AbstractAdapter(nodes, edges);
});
it('should not take any action if no limit is set', function() {
spyOn(mockReducer, "getCommunity");
adapter.insertNode({_id: 1});
adapter.insertNode({_id: 2});
adapter.insertNode({_id: 3});
adapter.insertNode({_id: 4});
adapter.insertNode({_id: 5});
adapter.checkNodeLimit();
expect(mockReducer.getCommunity).wasNotCalled();
});
it('should take a given focus into account', function() {
var n1, limit;
spyOn(mockReducer, "getCommunity").andCallFake(function() {
return [2, 4];
});
limit = 2;
adapter.setNodeLimit(limit);
n1 = adapter.insertNode({_id: 1});
adapter.insertNode({_id: 2});
adapter.insertNode({_id: 3});
adapter.insertNode({_id: 4});
adapter.insertNode({_id: 5});
adapter.checkNodeLimit(n1);
expect(mockReducer.getCommunity).toHaveBeenCalledWith(limit, n1);
});
it('should create a community if too many nodes are added', function() {
var n1, n2, commId;
spyOn(mockReducer, "getCommunity").andCallFake(function() {
return [1, 2];
});
adapter.setNodeLimit(2);
n1 = adapter.insertNode({_id: 1});
n2 = adapter.insertNode({_id: 2});
adapter.insertNode({_id: 3});
adapter.checkNodeLimit();
expect(mockReducer.getCommunity).wasCalledWith(2);
expect(getCommunityNodesIds().length).toEqual(1);
notExistNode([1, 2]);
existNode(3);
});
it('should create a community if limit is set to small', function() {
var n1, n2, commId;
spyOn(mockReducer, "getCommunity").andCallFake(function() {
return [1, 2];
});
n1 = adapter.insertNode({_id: 1});
n2 = adapter.insertNode({_id: 2});
adapter.insertNode({_id: 3});
adapter.setNodeLimit(2);
expect(mockReducer.getCommunity).wasCalledWith(2);
expect(getCommunityNodesIds().length).toEqual(1);
notExistNode([1, 2]);
existNode(3);
});
it('should connect edges to communities', function() {
var n1, n2, comm, e1, e2, e3;
spyOn(mockReducer, "getCommunity").andCallFake(function() {
return [1, 2];
});
n1 = adapter.insertNode({_id: 1});
n2 = adapter.insertNode({_id: 2});
adapter.insertNode({_id: 3});
e1 = adapter.insertEdge({
_id: "1-2",
_from: 1,
_to: 2
});
e2 = adapter.insertEdge({
_id: "2-3",
_from: 2,
_to: 3
});
e3 = adapter.insertEdge({
_id: "3-1",
_from: 3,
_to: 1
});
adapter.setNodeLimit(2);
comm = getCommunityNodes()[0];
notExistEdge(1, 2);
expect(e2.source).toEqual(comm);
expect(e3.target).toEqual(comm);
});
describe('if a community allready exists', function() {
var n1, n2, n3, n4,
e1, e2, e3, comm;
beforeEach(function() {
mockReducer.getCommunity = function() {
return [1, 2];
};
n1 = adapter.insertNode({_id: 1});
n2 = adapter.insertNode({_id: 2});
n3 = adapter.insertNode({_id: 3});
n4 = adapter.insertNode({_id: 4});
e1 = adapter.insertEdge({
_id: "1-2",
_from: 1,
_to: 2
});
e2 = adapter.insertEdge({
_id: "2-3",
_from: 2,
_to: 3
});
e3 = adapter.insertEdge({
_id: "3-1",
_from: 3,
_to: 1
});
adapter.setNodeLimit(3);
comm = getCommunityNodes()[0];
});
it('should be able to expand the community', function() {
adapter.setNodeLimit(10);
adapter.expandCommunity(comm);
expect(getCommunityNodes().length).toEqual(0);
expect(nodes.length).toEqual(4);
expect(edges.length).toEqual(3);
existEdge(1, 2);
existEdge(2, 3);
existEdge(3, 1);
existNodes([1,2,3,4]);
});
it('should collapse another community if limit is to small', function() {
spyOn(mockReducer, "getCommunity").andCallFake(function() {
return [3, 4];
});
adapter.expandCommunity(comm);
expect(getCommunityNodes().length).toEqual(1);
var comm2 = getCommunityNodes()[0];
expect(comm).not.toEqual(comm2);
expect(mockReducer.getCommunity).wasCalled();
expect(nodes.length).toEqual(3);
existNodes([1, 2]);
notExistNodes([3, 4]);
});
it('should collapse another community if limit is further reduced', function() {
spyOn(mockReducer, "getCommunity").andCallFake(function() {
return [3, 4];
});
adapter.setNodeLimit(2);
expect(getCommunityNodes().length).toEqual(2);
var comm2 = getCommunityNodes()[1];
expect(comm).not.toEqual(comm2);
expect(mockReducer.getCommunity).wasCalled();
expect(nodes.length).toEqual(2);
notExistNodes([1, 2, 3, 4]);
});
});
});
describe('checking many child nodes', function() {
var adapter, mockReducer;
beforeEach(function() {
mockReducer = {};
mockReducer.getCommunity = function() {};
mockReducer.bucketNodes = function() {};
spyOn(window, "NodeReducer").andCallFake(function(v, e) {
return {
getCommunity: function(limit, focus) {
if (focus !== undefined) {
return mockReducer.getCommunity(limit, focus);
}
return mockReducer.getCommunity(limit);
},
bucketNodes: function(toSort, numBuckets) {
return mockReducer.bucketNodes(toSort, numBuckets);
}
};
});
adapter = new AbstractAdapter(nodes, edges);
});
it('should not take any action if the limit is high enough', function() {
adapter.setChildLimit(5);
spyOn(mockReducer, "bucketNodes");
var n1, n2, n3, n4, n5,
inserted = {};
n1 = adapter.insertNode({_id: 1 });
n2 = adapter.insertNode({_id: 2 });
n3 = adapter.insertNode({_id: 3 });
n4 = adapter.insertNode({_id: 4 });
n5 = adapter.insertNode({_id: 5 });
_.each(nodes, function(n) {
inserted[n._id] = n;
});
adapter.checkSizeOfInserted(inserted);
expect(mockReducer.bucketNodes).wasNotCalled();
});
it('should bucket nodes if limit is to small', function() {
var n1, n2, n3, n4, n5,
inserted = [],
limit = 2;
spyOn(mockReducer, "bucketNodes").andCallFake(function() {
return [
[n1, n2],
[n3, n4, n5]
];
});
adapter.setChildLimit(limit);
n1 = adapter.insertNode({_id: 1 });
n2 = adapter.insertNode({_id: 2 });
n3 = adapter.insertNode({_id: 3 });
n4 = adapter.insertNode({_id: 4 });
n5 = adapter.insertNode({_id: 5 });
_.each(nodes, function(n) {
inserted.push(n);
});
adapter.checkSizeOfInserted(inserted);
expect(mockReducer.bucketNodes).wasCalledWith(inserted, limit);
expect(nodes.length).toEqual(2);
expect(getCommunityNodes().length).toEqual(2);
notExistNodes([1, 2, 3, 4, 5]);
});
it('should not display single nodes as buckets', function() {
var n1, n2, n3, n4, n5,
inserted = [],
limit = 3;
spyOn(mockReducer, "bucketNodes").andCallFake(function() {
return [
[n1],
[n3, n4, n5],
[n2]
];
});
adapter.setChildLimit(limit);
n1 = adapter.insertNode({_id: 1 });
n2 = adapter.insertNode({_id: 2 });
n3 = adapter.insertNode({_id: 3 });
n4 = adapter.insertNode({_id: 4 });
n5 = adapter.insertNode({_id: 5 });
_.each(nodes, function(n) {
inserted.push(n);
});
adapter.checkSizeOfInserted(inserted);
expect(mockReducer.bucketNodes).wasCalledWith(inserted, limit);
expect(nodes.length).toEqual(3);
expect(getCommunityNodes().length).toEqual(1);
notExistNodes([3, 4, 5]);
existNodes([1, 2]);
});
});
});
}());

View File

@ -5,7 +5,7 @@
/*global window, eb, loadFixtures, document */
/*global $, _, d3*/
/*global describeInterface*/
/*global ArangoAdapter*/
/*global FoxxAdapter*/
////////////////////////////////////////////////////////////////////////////////
/// @brief Graph functionality
@ -40,19 +40,16 @@
describe('Foxx Adapter', function () {
describeInterface(new FoxxAdapter([], [], {
nodeCollection: "",
edgeCollection: ""
}));
describeInterface(new FoxxAdapter([], [], "foxx/route"));
describeIntegeration(new FoxxAdapter([], [], "foxx/route"));
var adapter,
nodes,
edges,
arangodb = "http://localhost:8529",
nodesCollection,
altNodesCollection,
edgesCollection,
altEdgesCollection,
mockCollection,
callbackCheck,
checkCallbackFunction = function() {
@ -163,11 +160,6 @@
beforeEach(function() {
nodes = [];
edges = [];
mockCollection = {};
nodesCollection = "TestNodes321";
edgesCollection = "TestEdges321";
altNodesCollection = "TestNodes654";
altEdgesCollection = "TestEdges654";
this.addMatchers({
toHaveCorrectCoordinates: function() {
@ -193,7 +185,7 @@
it('should throw an error if no nodes are given', function() {
expect(
function() {
var t = new ArangoAdapter();
var t = new FoxxAdapter();
}
).toThrow("The nodes have to be given.");
});
@ -201,90 +193,61 @@
it('should throw an error if no edges are given', function() {
expect(
function() {
var t = new ArangoAdapter([]);
var t = new FoxxAdapter([]);
}
).toThrow("The edges have to be given.");
});
it('should throw an error if no nodeCollection is given', function() {
it('should throw an error if no route is given', function() {
expect(
function() {
var t = new ArangoAdapter([], [], {
var t = new FoxxAdapter([], [], {
edgeCollection: ""
});
}
).toThrow("The nodeCollection has to be given.");
).toThrow("The route has to be given.");
});
it('should throw an error if no edgeCollection is given', function() {
expect(
function() {
var t = new ArangoAdapter([], [], {
nodeCollection: ""
});
}
).toThrow("The edgeCollection has to be given.");
});
it('should not throw an error if everything is given', function() {
expect(
function() {
var t = new ArangoAdapter([], [], {
nodeCollection: "",
edgeCollection: ""
});
}
).not.toThrow();
});
it('should automatically determine the host of not given', function() {
var adapter = new ArangoAdapter(
it('should automatically determine the host of relative route is given', function() {
var route = "foxx/route"
adapter = new FoxxAdapter(
nodes,
edges,
{
nodeCollection: nodesCollection,
edgeCollection: edgesCollection,
width: 100,
height: 40
}
route
),
args,
host;
spyOn($, "ajax");
adapter.createNode({}, function() {});
args = $.ajax.mostRecentCall.args[0];
host = window.location.protocol + "//" + window.location.host;
host = window.location.protocol + "//" + window.location.host + "/" + route;
expect(args.url).toContain(host);
});
it('should create a nodeReducer instance', function() {
spyOn(window, "NodeReducer");
var adapter = new ArangoAdapter(
var adapter = new FoxxAdapter(
nodes,
edges,
{
nodeCollection: nodesCollection,
edgeCollection: edgesCollection,
width: 100,
height: 40
}
"foxx/route"
);
expect(window.NodeReducer).wasCalledWith(nodes, edges);
});
describe('setup correctly', function() {
var traversalQuery,
filterQuery,
childrenQuery,
var edgeRoute,
nodeRoute,
queryRoute,
loadGraph,
requests;
beforeEach(function() {
var self = this,
host = window.location.protocol + "//" + window.location.host,
apibase = host + "/_api/",
apiCursor = apibase + 'cursor';
route = "foxx/route"
host = window.location.protocol + "//"
+ window.location.host + "/"
+ route;
self.fakeReducerRequest = function() {};
self.fakeReducerBucketRequest = function() {};
spyOn(window, "NodeReducer").andCallFake(function(v, e) {
@ -300,73 +263,23 @@
}
};
});
adapter = new ArangoAdapter(
adapter = new FoxxAdapter(
nodes,
edges,
{
nodeCollection: nodesCollection,
edgeCollection: edgesCollection,
width: 100,
height: 40
}
route
);
traversalQuery = function(id, nods, edgs, undirected) {
var dir;
if (undirected === true) {
dir = "any";
} else {
dir = "outbound";
}
return JSON.stringify({
query: "RETURN TRAVERSAL(@@nodes, @@edges, @id, @dir,"
+ " {strategy: \"depthfirst\",maxDepth: 1,paths: true})",
bindVars: {
id: id,
"@nodes": nods,
dir: dir,
"@edges": edgs
}
});
};
filterQuery = function(v, nods, edgs, undirected) {
var dir;
if (undirected === true) {
dir = "any";
} else {
dir = "outbound";
}
return JSON.stringify({
query: "FOR n IN @@nodes FILTER n.id == @value"
+ " RETURN TRAVERSAL(@@nodes, @@edges, n._id, @dir,"
+ " {strategy: \"depthfirst\",maxDepth: 1,paths: true})",
bindVars: {
value: v,
"@nodes": nods,
dir: dir,
"@edges": edgs
}
});
};
childrenQuery = function(id, nods, edgs) {
return JSON.stringify({
query: "FOR u IN @@nodes FILTER u._id == @id"
+ " LET g = ( FOR l in @@edges FILTER l._from == u._id RETURN 1 )"
+ " RETURN length(g)",
bindVars: {
id: id,
"@nodes": nods,
"@edges": edgs
}
});
};
loadGraph = function(vars) {
var nid = vars.id,
ncol = vars["@nodes"],
ecol = vars["@edges"],
res = [],
inner = [],
first = {},
node1 = readNode(ncol, nid);
edgeRoute = host + "/edges";
nodeRoute = host + "/nodes";
queryRoute = host + "/query";
loadGraph = function(data) {
var res = [],
nid,
ncol = nodesCollection,
ecol = edgesCollection,
inner = [],
first = {},
node1 = readNode(ncol, nid);
res.push(inner);
first.vertex = node1;
first.path = {
@ -386,10 +299,10 @@
requests = {};
requests.cursor = function(data) {
requests.query = function(data) {
return {
type: 'POST',
url: apiCursor,
url: queryRoute,
data: data,
contentType: 'application/json',
dataType: 'json',
@ -398,98 +311,62 @@
processData: false
};
};
requests.node = function(col) {
var read = apibase + "document?collection=" + col,
write = apibase + "document/",
base = {
cache: false,
dataType: "json",
contentType: "application/json",
processData: false,
success: jasmine.any(Function),
error: jasmine.any(Function)
};
requests.node = function() {
var base = {
cache: false,
dataType: "json",
contentType: "application/json",
processData: false,
success: jasmine.any(Function),
error: jasmine.any(Function)
};
return {
create: function(data) {
return $.extend(base, {url: read, type: "POST", data: JSON.stringify(data)});
return $.extend(base, {url: nodeRoute, type: "POST", data: JSON.stringify(data)});
},
patch: function(id, data) {
return $.extend(base, {url: write + id, type: "PUT", data: JSON.stringify(data)});
return $.extend(base, {url: nodeRoute + "/" + id, type: "PUT", data: JSON.stringify(data)});
},
del: function(id) {
return $.extend(base, {url: write + id, type: "DELETE"});
return $.extend(base, {url: nodeRoute + "/" + id, type: "DELETE"});
}
};
};
requests.edge = function(col) {
var create = apibase + "edge?collection=" + col,
base = {
cache: false,
dataType: "json",
contentType: "application/json",
processData: false,
success: jasmine.any(Function),
error: jasmine.any(Function)
};
var base = {
cache: false,
dataType: "json",
contentType: "application/json",
processData: false,
success: jasmine.any(Function),
error: jasmine.any(Function)
};
return {
create: function(from, to, data) {
data = $.extend(data, {_from: from, _to: to});
return $.extend(base, {
url: create + "&from=" + from + "&to=" + to,
url: edgeRoute,
type: "POST",
data: JSON.stringify(data)
});
},
patch: function(id, data) {
return $.extend(base, {url: edgeRoute + "/" + id, type: "PUT", data: JSON.stringify(data)});
},
del: function(id) {
return $.extend(base, {url: edgeRoute + "/" + id, type: "DELETE"});
}
};
};
});
it('should offer lists of available collections', function() {
var collections = [],
sys1 = {id: "1", name: "_sys1", status: 3, type: 2},
sys2 = {id: "2", name: "_sys2", status: 2, type: 2},
doc1 = {id: "3", name: "doc1", status: 3, type: 2},
doc2 = {id: "4", name: "doc2", status: 2, type: 2},
doc3 = {id: "5", name: "doc3", status: 3, type: 2},
edge1 = {id: "6", name: "edge1", status: 3, type: 3},
edge2 = {id: "7", name: "edge2", status: 2, type: 3};
collections.push(sys1);
collections.push(sys2);
collections.push(doc1);
collections.push(doc2);
collections.push(doc3);
collections.push(edge1);
collections.push(edge2);
spyOn($, "ajax").andCallFake(function(request) {
request.success({collections: collections});
});
adapter.getCollections(function(docs, edge) {
expect(docs).toContain("doc1");
expect(docs).toContain("doc2");
expect(docs).toContain("doc3");
expect(docs.length).toEqual(3);
expect(edge).toContain("edge1");
expect(edge).toContain("edge2");
expect(edge.length).toEqual(2);
});
});
it('should be able to load a tree node from '
+ 'ArangoDB by internal _id attribute', function() {
it('should be able to load by internal _id attribute', function() {
var c0, c1, c2, c3, c4;
runs(function() {
spyOn($, "ajax").andCallFake(function(request) {
var vars = JSON.parse(request.data).bindVars;
if (vars !== undefined) {
request.success({result: loadGraph(vars)});
}
request.success({result: loadGraph(JSON.parse(request.data))});
});
c0 = insertNode(nodesCollection, 0);
@ -504,7 +381,7 @@
insertEdge(edgesCollection, c0, c4);
callbackCheck = false;
adapter.loadNodeFromTreeById(c0, checkCallbackFunction);
adapter.loadNode(c0, checkCallbackFunction);
});
waitsFor(function() {

View File

@ -1,5 +1,5 @@
/*jslint indent: 2, nomen: true, maxlen: 100, white: true plusplus: true */
/*global it, expect */
/*global it, expect, describe*/
////////////////////////////////////////////////////////////////////////////////
@ -33,6 +33,7 @@
var describeInterface = function (testee) {
"use strict";
describe('checking the interface', function() {
it('should comply to the Adapter Interface', function() {
this.addMatchers({
toHaveFunction: function(func, argCounter) {
@ -69,7 +70,13 @@ var describeInterface = function (testee) {
expect(testee).toHaveFunction("setNodeLimit", 2);
expect(testee).toHaveFunction("setChildLimit", 1);
expect(testee).toHaveFunction("expandCommunity", 2);
});
});
};
var describeIntegeration = function(testee) {
"use strict";
};