Skip to content

Instantly share code, notes, and snippets.

@tinnou
Created February 11, 2022 01:21
Show Gist options
  • Select an option

  • Save tinnou/9e52df013687c97f51c12e9fff62b6cc to your computer and use it in GitHub Desktop.

Select an option

Save tinnou/9e52df013687c97f51c12e9fff62b6cc to your computer and use it in GitHub Desktop.
NeptuneTypeTranslator adapted from GroovyTranslator
package com.netflix.dragnet.sync.session
import org.apache.commons.configuration.ConfigurationConverter
import org.apache.commons.lang.StringEscapeUtils
import org.apache.tinkerpop.gremlin.process.traversal.Bytecode
import org.apache.tinkerpop.gremlin.process.traversal.P
import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions
import org.apache.tinkerpop.gremlin.process.traversal.Traversal
import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy
import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent
import org.apache.tinkerpop.gremlin.process.traversal.strategy.TraversalStrategyProxy
import org.apache.tinkerpop.gremlin.process.traversal.translator.GroovyTranslator
import org.apache.tinkerpop.gremlin.structure.Edge
import org.apache.tinkerpop.gremlin.structure.T
import org.apache.tinkerpop.gremlin.structure.Vertex
import org.apache.tinkerpop.gremlin.structure.VertexProperty
import org.apache.tinkerpop.gremlin.util.function.Lambda
import java.sql.Timestamp
import java.util.*
import java.util.stream.Collectors
/**
* Copy paste of GroovyTranslator.DefaultTypeTranslator.
* Neptune has some oddities when receiving gremlin scripts:
* - multi-line strings. (i.e """)
* - int values must be sent as is, no casting (e.g (int)) allowed
* - "new Date()" doesn't work
* - fully qualified class names (i.e with package names) are not allowed.
* (e.g single works but VertexProperty.Cardinality.single doesn't)
*/
class NeptuneTypeTranslator : GroovyTranslator.DefaultTypeTranslator() {
override fun convertToString(obj: Any?): String {
return when (obj) {
is Bytecode.Binding<*> -> obj.variable()
is Bytecode -> internalTranslate("__", obj as Bytecode?)
is Traversal<*, *> -> convertToString(obj.asAdmin().bytecode)
is String -> {
// Neptune / Tinkerpop doesn't deal well with multi-line strings so instead of using them we just
// escape double quotes within single quotes
// if (obj.contains("\"")) {
// "\"\"\"" + StringEscapeUtils.escapeJava(obj as String?) + "\"\"\""
// } else {
"\"" + StringEscapeUtils.escapeJava(obj as String?) + "\""
.replace("$", "\\$")
}
is Set<*> -> {
val set: MutableSet<String> = HashSet(obj.size)
for (item in obj) {
set.add(convertToString(item))
}
//"$set as Set"
set.joinToString(separator = ",")
}
is List<*> -> {
val list: MutableList<String> = ArrayList(obj.size)
for (item in obj) {
list.add(convertToString(item))
}
list.toString()
}
is Map<*, *> -> {
val map = StringBuilder("[")
for ((key, value) in obj) {
map.append("(").append(convertToString(key)).append("):(").append(convertToString(value)).append("),")
}
// only need to remove this last bit if entries were added
if (!obj.isEmpty()) map.deleteCharAt(map.length - 1)
map.append("]").toString()
}
is Long -> obj.toString() + "L"
is Double -> obj.toString() + "d"
is Float -> obj.toString() + "f"
//is Int -> "(int) $obj"
is Int -> "$obj"
is Class<*> -> convertClassToString(obj as Class<*>?)
is Timestamp -> "new Timestamp(" + obj.time + ")"
is Date -> "new Date(" + obj.time + ")"
is UUID -> "UUID.fromString('$obj')"
is P<*> -> convertPToString(obj as P<*>?, StringBuilder()).toString()
is SackFunctions.Barrier -> "SackFunctions.Barrier.$obj"
is VertexProperty.Cardinality -> "$obj"
// is VertexProperty.Cardinality -> "VertexProperty.Cardinality.$obj"
is TraversalOptionParent.Pick -> "TraversalOptionParent.Pick.$obj"
is Enum<*> -> (obj as T).declaringClass.simpleName + "." + obj.toString()
is Vertex -> {
val vertex = obj
"new ReferenceVertex(" +
convertToString(vertex.id()) + "," +
convertToString(vertex.label()) + ")"
}
is Edge -> {
val edge = obj
"new ReferenceEdge(" +
convertToString(edge.id()) + "," +
convertToString(edge.label()) + "," +
"new ReferenceVertex(" + convertToString(edge.inVertex().id()) + "," +
convertToString(edge.inVertex().label()) + ")," +
"new ReferenceVertex(" + convertToString(edge.outVertex().id()) + "," +
convertToString(edge.outVertex().label()) + "))"
}
is VertexProperty<*> -> {
val vertexProperty = obj
"new ReferenceVertexProperty(" +
convertToString(vertexProperty.id()) + "," +
convertToString(vertexProperty.label()) + "," +
convertToString(vertexProperty.value()) + ")"
}
is Lambda -> {
val lambdaString = obj.lambdaScript.trim { it <= ' ' }
if (lambdaString.startsWith("{")) lambdaString else "{$lambdaString}"
}
is TraversalStrategyProxy<*> -> {
val proxy = obj
val className = convertClassToString(proxy.strategyClass)
if (proxy.configuration.isEmpty) className else String.format("new %s(%s)", className, convertMapToArguments(ConfigurationConverter.getMap(proxy.configuration)))
}
is TraversalStrategy<*> -> {
convertToString(TraversalStrategyProxy(obj as TraversalStrategy<*>?))
}
else -> obj?.toString() ?: "null"
}
}
private fun convertMapToArguments(map: Map<Any, Any>): String? {
return map.entries.stream().map { (key, value) -> String.format("%s: %s", key.toString(), convertToString(value)) }.collect(Collectors.joining(", "))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment