1
0
Fork 0

fun with custom visitors, cont.

This commit is contained in:
Jan Steemann 2015-01-29 01:57:03 +01:00
parent b4ba07f765
commit 699b7e76f6
2 changed files with 96 additions and 26 deletions

View File

@ -145,12 +145,32 @@ instead.
vertex only if *order* was set to *preorder-expander*. Otherwise, the value of this parameter vertex only if *order* was set to *preorder-expander*. Otherwise, the value of this parameter
will be *undefined*. will be *undefined*.
The following custom visitor functions are predefined and can be used by specifying the function
name in the *visitor* attribute:
- *"_AQL::PROJECTINGVISITOR"*: this visitor will produce an object with the attributes
specified in *data.attributes* for each visited vertex. This can be used to create a
projection of each visited vertex' document.
- *"_AQL::IDVISITOR"*: this visitor will return the _id attribute of each visited vertex.
- *"_AQL::KEYVISITOR"*: this visitor will return the _key attribute of each visited vertex.
- *"_AQL::COUNTINGVISITOR"*: this visitor will return a single number indicating the number
of vertices visited.
- *visitorReturnsResults*: only useful in combination with a custom AQL visitor function. If - *visitorReturnsResults*: only useful in combination with a custom AQL visitor function. If
set to *true*, the data returned by the visitor will be appended to the result. If set to set to *true*, the data returned by the visitor will be appended to the result. If set to
*false*, any return value of the visitor function will be ignored. Instead, the visitor *false*, any return value of the visitor function will be ignored. Instead, the visitor
function can modify its *result* parameter value in-place. At the end of the traversal, function can modify its *result* parameter value in-place. At the end of the traversal,
*result* is expected to be an array. *result* is expected to be an array.
- *data*: only useful in combination with a custom AQL visitor function. This attribute can
be used to pass arbitrary data into the custom visitor function. The value contained in the
*data* attribute will be made available to the *visitor* function in the *config.data*
attribute.
By default, the result of the TRAVERSAL function is an array of traversed points. Each point By default, the result of the TRAVERSAL function is an array of traversed points. Each point
is an object consisting of the following attributes: is an object consisting of the following attributes:
- *vertex*: The vertex at the traversal point - *vertex*: The vertex at the traversal point

View File

@ -51,6 +51,46 @@ var RegexCache = { };
var UserFunctions = { }; var UserFunctions = { };
////////////////////////////////////////////////////////////////////////////////
/// @brief prefab traversal visitors
////////////////////////////////////////////////////////////////////////////////
var DefaultVisitors = {
"_AQL::PROJECTINGVISITOR" : {
visitorReturnsResults: true,
func: function (config, result, vertex) {
var values = { };
if (typeof config.data === "object" && Array.isArray(config.data.attributes)) {
config.data.attributes.forEach(function (attribute) {
values[attribute] = vertex[attribute];
});
}
return values;
}
},
"_AQL::IDVISITOR" : {
visitorReturnsResults: true,
func: function (config, result, vertex) {
return vertex._id;
}
},
"_AQL::KEYVISITOR" : {
visitorReturnsResults: true,
func: function (config, result, vertex) {
return vertex._key;
}
},
"_AQL::COUNTINGVISITOR" : {
visitorReturnsResults: false,
func: function (config, result) {
if (result.length === 0) {
result.push(0);
}
result[0]++;
}
}
};
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief type weight used for sorting and comparing /// @brief type weight used for sorting and comparing
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -194,26 +234,35 @@ function reloadUserFunctions () {
/// @brief get a user-function by name /// @brief get a user-function by name
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
function GET_USERFUNCTION (name) { function GET_USERFUNCTION (name, config) {
var prefix = DB_PREFIX(), reloaded = false; var prefix = DB_PREFIX(), reloaded = false;
var key = name.toUpperCase(); var key = name.toUpperCase();
if (! UserFunctions.hasOwnProperty(prefix)) { var func;
reloadUserFunctions();
reloaded = true;
}
if (! UserFunctions[prefix].hasOwnProperty(key) && ! reloaded) { if (DefaultVisitors.hasOwnProperty(key)) {
// last chance var visitor = DefaultVisitors[key];
reloadUserFunctions(); func = visitor.func;
config.visitorReturnsResults = visitor.visitorReturnsResults;
} }
else {
if (! UserFunctions.hasOwnProperty(prefix)) {
reloadUserFunctions();
reloaded = true;
}
if (! UserFunctions[prefix].hasOwnProperty(key)) { if (! UserFunctions[prefix].hasOwnProperty(key) && ! reloaded) {
THROW(null, INTERNAL.errors.ERROR_QUERY_FUNCTION_NOT_FOUND, name); // last chance
reloadUserFunctions();
}
if (! UserFunctions[prefix].hasOwnProperty(key)) {
THROW(null, INTERNAL.errors.ERROR_QUERY_FUNCTION_NOT_FOUND, name);
}
func = UserFunctions[prefix][key].func;
} }
var func = UserFunctions[prefix][key].func;
if (typeof func !== "function") { if (typeof func !== "function") {
THROW(null, INTERNAL.errors.ERROR_QUERY_FUNCTION_NOT_FOUND, name); THROW(null, INTERNAL.errors.ERROR_QUERY_FUNCTION_NOT_FOUND, name);
} }
@ -225,8 +274,8 @@ function GET_USERFUNCTION (name) {
/// @brief create a user-defined visitor from a function name /// @brief create a user-defined visitor from a function name
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
function GET_VISITOR (name) { function GET_VISITOR (name, config) {
var func = GET_USERFUNCTION(name); var func = GET_USERFUNCTION(name, config);
return function (config, result, vertex, path) { return function (config, result, vertex, path) {
try { try {
@ -250,8 +299,8 @@ function GET_VISITOR (name) {
/// @brief create a user-defined filter from a function name /// @brief create a user-defined filter from a function name
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
function GET_FILTER (name) { function GET_FILTER (name, config) {
var func = GET_USERFUNCTION(name); var func = GET_USERFUNCTION(name, config);
return function (config, vertex, path) { return function (config, vertex, path) {
try { try {
@ -5059,7 +5108,8 @@ function TRAVERSAL_FUNC (func,
endVertex : endVertex, endVertex : endVertex,
weight : params.weight, weight : params.weight,
defaultWeight : params.defaultWeight, defaultWeight : params.defaultWeight,
prefill : params.prefill prefill : params.prefill,
data: params.data
}; };
if (typeof params.filter === "function") { if (typeof params.filter === "function") {
@ -5456,7 +5506,7 @@ function SHORTEST_PATH_PARAMS (params) {
// add user-defined visitor, if specified // add user-defined visitor, if specified
if (typeof params.visitor === "string") { if (typeof params.visitor === "string") {
params.visitor = GET_VISITOR(params.visitor); params.visitor = GET_VISITOR(params.visitor, params);
} }
else { else {
params.visitor = TRAVERSAL_VISITOR; params.visitor = TRAVERSAL_VISITOR;
@ -5464,7 +5514,7 @@ function SHORTEST_PATH_PARAMS (params) {
// add user-defined filter, if specified // add user-defined filter, if specified
if (typeof params.filter === "string") { if (typeof params.filter === "string") {
params.filter = GET_FILTER(params.filter); params.filter = GET_FILTER(params.filter, params);
} }
if (typeof params.distance === "string") { if (typeof params.distance === "string") {
@ -5686,7 +5736,7 @@ function TRAVERSAL_PARAMS (params) {
// add user-defined visitor, if specified // add user-defined visitor, if specified
if (typeof params.visitor === "string") { if (typeof params.visitor === "string") {
params.visitor = GET_VISITOR(params.visitor); params.visitor = GET_VISITOR(params.visitor, params);
} }
else { else {
params.visitor = TRAVERSAL_VISITOR; params.visitor = TRAVERSAL_VISITOR;
@ -5694,7 +5744,7 @@ function TRAVERSAL_PARAMS (params) {
// add user-defined filter, if specified // add user-defined filter, if specified
if (typeof params.filter === "string") { if (typeof params.filter === "string") {
params.filter = GET_FILTER(params.filter); params.filter = GET_FILTER(params.filter, params);
} }
return params; return params;
@ -6045,7 +6095,7 @@ function TRAVERSAL_TREE_PARAMS (params, connectName, func) {
// add user-defined visitor, if specified // add user-defined visitor, if specified
if (typeof params.visitor === "string") { if (typeof params.visitor === "string") {
params.visitor = GET_VISITOR(params.visitor); params.visitor = GET_VISITOR(params.visitor, params);
} }
else { else {
params.visitor = TRAVERSAL_TREE_VISITOR; params.visitor = TRAVERSAL_TREE_VISITOR;
@ -6053,7 +6103,7 @@ function TRAVERSAL_TREE_PARAMS (params, connectName, func) {
// add user-defined filter, if specified // add user-defined filter, if specified
if (typeof params.filter === "string") { if (typeof params.filter === "string") {
params.filter = GET_FILTER(params.filter); params.filter = GET_FILTER(params.filter, params);
} }
params.connect = AQL_TO_STRING(connectName); params.connect = AQL_TO_STRING(connectName);