Ошибки использования Gremlin DSL в шаге `repeat` - PullRequest
3 голосов
/ 05 февраля 2020

Мы используем 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;

1 Ответ

2 голосов
/ 06 февраля 2020

Я предполагаю, что проблема в том, что вы начинаете свой обход с __, который является стандартным порождением TinkerPop для анонимных обходов. В результате вы получите GraphTraversal, а не CustomDSLTraversalSource. Документация TinkerPop gremlin- ​​javascript гласит, что:

шагов, которые доступны в GraphTraversal, также должны быть доступны в качестве порождений для анонимных обходов

Так что вы, вероятно, должны иметь свою собственную версию __, которая возвращает CustomDSLTraversalSource. Если вы хотите более четко увидеть, где что-то идет не так, посмотрите в коде , который callOnEmptyTraversal() возвращает GraphTraversal, и, очевидно, ваши DSL-методы не будут доступны в этом классе.

...