blob: a4064187137753244d31aa3c4a073567e8b79385 [file] [log] [blame]
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
"""
Class that can turn traversals back into Gremlin Groovy format text queries.
Those queries can then be run in the Gremlin console or using the GLV submit(<String>) API or
sent to any TinkerPop compliant HTTP endpoint.
"""
__author__ = 'Kelvin R. Lawrence (gfxman)'
from gremlin_python.process.graph_traversal import __
from gremlin_python.process.anonymous_traversal import traversal
from gremlin_python.process.traversal import *
from gremlin_python.driver.driver_remote_connection import DriverRemoteConnection
from gremlin_python.process.strategies import *
from datetime import datetime
class Translator:
"""
Turn a bytecode object back into a textual query (Gremlin Groovy script).
"""
# Dictionary used to reverse-map token IDs to strings
options = {
WithOptions.tokens: 'tokens',
WithOptions.none: 'none',
WithOptions.ids:'ids',
WithOptions.labels: 'labels',
WithOptions.keys: 'keys',
WithOptions.values: 'values',
WithOptions.all: 'all',
WithOptions.indexer: 'indexer',
WithOptions.list: 'list',
WithOptions.map: 'map'
}
def __init__(self, traversal_source=None):
self.traversal_source = traversal_source
def get_traversal_source(self):
return self.traversal_source
def get_target_language(self):
return "gremlin-groovy"
def of(self,traversal_source):
self.traversal_source = traversal_source
return self
# Do any needed special processing for the representation
# of strings and dates.
def fixup(self, v):
if isinstance(v, str):
return f'\'{v}\''
elif type(v) == datetime:
return self.process_date(v)
else:
return str(v)
# Turn a Python datetime into the equivalent new Date(...)
def process_date(self, date):
y = date.year - 1900
mo = date.month
d = date.day
h = date.hour
mi = date.minute
s = date.second
return f'new Date({y},{mo},{d},{h},{mi},{s})'
# Do special processing needed to format predicates that come in
# such as "gt(a)" correctly.
def process_predicate(self, p):
res = str(p).split('(')[0] + '('
if type(p.value) == list:
res += '['
for v in p.value:
res += self.fixup(v) + ','
res = res[0:-1] + ']'
else:
res += self.fixup(p.value)
if p.other is not None:
res+= ',' + self.fixup(p.other)
res += ')'
return res
# Special processing to handle strategies
def process_strategy(self, s):
c = 0
res = f'new {str(s)}('
for key in s.configuration:
res += ',' if c > 0 else ''
res += key + ':'
val = s.configuration[key]
if isinstance(val, Traversal):
res += self.translate(val.bytecode,child=True)
else:
res += self.fixup(val)
c += 1
res += ')'
return res
pass
# Main driver of the translation. Different parts of
# a Traversal are handled appropriately.
def do_translation(self, step):
script = ''
params = step[1:]
script += '.' + step[0] + '('
if len(params) > 0:
c = 0
with_opts = False
for p in params:
script += ',' if c > 0 else ''
if with_opts:
script += f'WithOptions.{self.options[p]}'
elif type(p) == Bytecode:
script += self.translate(p, True)
elif isinstance(p, P):
script += self.process_predicate(p)
elif type(p) in [Cardinality, Pop]:
tmp = str(p)
script += tmp[0:-1] if tmp.endswith('_') else tmp
elif type(p) in [ReadOnlyStrategy, SubgraphStrategy, VertexProgramStrategy,
OptionsStrategy, PartitionStrategy]:
script += self.process_strategy(p)
elif type(p) == datetime:
script += self.process_date(p)
elif p == WithOptions.tokens:
script += 'WithOptions.tokens'
with_opts = True
elif isinstance(p, str):
script += f'\'{p}\''
elif type(p) == bool:
script += 'true' if p else 'false'
elif p is None:
script += 'null'
else:
script += str(p)
c += 1
script += ')'
return script
# Translation starts here. There are two main parts to a
# traversal. Source instructions such as "withSideEffect"
# and "withStrategies", and step instructions such as
# "addV" and "repeat". If child is True we will generate
# anonymous traversal style syntax.
def translate(self, bytecode, child=False):
script = '__' if child else self.traversal_source
for step in bytecode.source_instructions:
script += self.do_translation(step)
for step in bytecode.step_instructions:
script += self.do_translation(step)
return script