我们正在使用gremlin-javascript
,并且最近开始定义DSL以简化查询。
[我不确定是否忽略了一些警告,但是当尝试在repeat
步骤中使用DSL方法时,我始终收到(...).someDslFunction is not a function
错误,但是在repeat
之外使用相同的DSL功能可以正常工作。
这里是一个简短的(人为的)DSL定义,它会产生此问题:
class CustomDSLTraversal extends GraphTraversal {
constructor(graph, traversalStrategies, bytecode) {
super(graph, traversalStrategies, bytecode);
}
hasNotLabel(...args) {
return this.not(__.hasLabel(...args));
}
filterNotLabel(...args) {
return this.filter(__.hasNotLabel(...args));
}
}
class CustomDSLTraversalSource extends GraphTraversalSource {
constructor(graph, traversalStrategies, bytecode) {
super(graph, traversalStrategies, bytecode, CustomDSLTraversalSource, CustomDSLTraversal);
}
}
const statics = {
hasNotLabel: (...args) => callOnEmptyTraversal('hasNotLabel', args),
...gremlin.process.statics
};
const __ = statics;
const g = traversal(CustomDSLTraversalSource).withRemote(connection);
这是它的两个用途,第一个没有问题,第二个导致__.outE().(...).filterNotLabel is not a function
错误。
g.V('foo').outE().filterNotLabel('x', 'y').otherV(); // No errors
g.V('foo').repeat(__.outE().filterNotLabel('x', 'y').otherV()).times(1); // Error
// __.outE(...).filterNotLabel is not a function
EDIT:感谢@stephen指出了现在如此明显的问题:
我已经重新定义了callOnEmptyTraversal
以用于我们的DSL,并且愚蠢地将标准TinkerPop匿名遍历结构分解为我们的自定义遍历结构。这些显然是在调用原始callOnEmptyTraversal
,该确确实使用了基GraphTraversal
的实例。
function callOnEmptyTraversal(fn, args) {
const g = new CustomDSLTraversal(null, null, new Bytecode());
return g[fn].apply(g, args);
}
const statics = {
hasNotLabel: (...args) => callOnEmptyTraversal('hasNotLabel', args),
mapToObject: (...args) => callOnEmptyTraversal('mapToObject', args),
...gremlin.process.statics // Whoops
};
const __ = statics;
SOLUTION:以防万一其他人遇到这种情况。这就是我解决了将DSL匿名遍历生成物与标准TinkerPop生成物合并的问题:
function callOnEmptyTraversal(fn, args) {
const g = new CustomDSLTraversal(null, null, new Bytecode());
return g[fn].apply(g, args);
}
function mapToCallOnEmptyTraversal(s, fn) {
s[fn] = (...args) => callOnEmptyTraversal(fn, args);
return s;
}
const statics = ['hasNotLabel', 'mapToObject']
.concat(Object.keys(gremlin.process.statics))
.reduce(mapToCallOnEmptyTraversal, {});
const __ = statics;
我认为问题是因为您以__
开始遍历,这是匿名遍历的标准TinkerPop生成。结果,您将创建一个GraphTraversal
,而不是您的CustomDSLTraversalSource
。 TinkerPop gremlin-javascript documentation指出:
在GraphTraversal上可用的步骤也应该作为匿名遍历的生成物可用
因此您可能应该拥有自己的返回__
的CustomDSLTraversalSource
版本。如果您想更清楚地了解问题出在哪里,请参阅in the code,callOnEmptyTraversal()
返回GraphTraversal
,显然,您的DSL方法在该类上不可用。