“重复”步骤中的 Gremlin DSL 使用错误

Gremlin DSL usage errors within `repeat` step

我们正在使用 gremlin-javascript 并且最近开始定义 DSL 来简化我们的查询。

我不确定我是否忽略了一些注意事项,但是当尝试在 repeat 步骤中使用 DSL 方法时,我一直收到 (...).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;

我认为问题是因为您使用 __ 开始遍历,这是用于匿名遍历的标准 TinkerPop 生成。结果,您创建了 GraphTraversal 而不是 CustomDSLTraversalSource。 TinkerPop gremlin-javascript documentation 指出:

steps that are made available on a GraphTraversal should also be made available as spawns for anonymous traversals

所以您可能应该有自己的 __ 版本,即 returns 和 CustomDSLTraversalSource。如果你想更明确地看到哪里出了问题,请参阅 in the code that callOnEmptyTraversal() returns GraphTraversal 显然你的 DSL 方法在 class.