Мы используем gremlin-javascript
и недавно начали определять DSL для упрощения наших запросов.
Я не уверен, пропустил ли я какое-то предупреждение, но при попытке использовать методы DSL внутри repeat
шаг, я последовательно получаю (...).someDslFunction is not a function
ошибок, но использование той же функции DSL за пределами repeat
работает без проблем.
Вот краткое (надуманное) определение 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
РЕДАКТИРОВАТЬ : Спасибо @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;
РЕШЕНИЕ: На всякий случай, если кто-то еще столкнется с этим сценарием. Вот как я решил проблему слияния наших анонимных вызовов 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;