TINKERPOP-3247 Convert request bindings to gremlin-lang string format#3402
TINKERPOP-3247 Convert request bindings to gremlin-lang string format#3402
Conversation
316e283 to
8bed359
Compare
The visitor treated all keyword map keys as their text representation, so a null key in [null:"value"] was parsed as the String "null" instead of Java null. This broke round-tripping maps with null keys through GremlinLang serialization and ANTLR parsing.
Moving parameters from binary-serialized maps to string representations makes the request side pure text, decoupling Gremlin language evolution from GraphBinary versioning. New types can be introduced in minor/patch versions without touching GraphBinary, eliminating the need for a major version bump across the ecosystem for every new request-side type. The asParameter() fallback is replaced with an unsupportedType flag that records the class name and falls back to toString(). A flag is used rather than throwing because embedded Traversals build GremlinLang as a side effect but never send it, so unknown types must not break execution. All other GLVs throw immediately since they have no embedded mode and the early throw gives better errors. Client APIs accept both map and string bindings (but not both at the same time) because users who use the Client directly with raw Gremlin strings shouldn't need to hand-craft gremlin-lang map literals. Mixing both throws immediately to prevent silent loss where one set of bindings would be discarded. Edge and VertexProperty tests that relied on the old asParameter fallback were removed because they aren't supported in gremlin-lang.
| final GremlinParser.GenericMapLiteralContext mapCtx = parser.genericMapLiteral(); | ||
|
|
||
| final ParameterMapVisitor visitor = new ParameterMapVisitor(new GremlinAntlrToJava()); | ||
| final Map<Object, Object> rawMap = (Map<Object, Object>) visitor.visitGenericMapLiteral(mapCtx); |
There was a problem hiding this comment.
Do we need some error handling here? Am I right in assuming mapCtx will be null if the parameterMapString is not actually a gremlin-lang map? How would such an error propagate if the user provides a bad parameter string?
| if (value instanceof Traversal) { | ||
| throw new GremlinParserException("Traversals are not allowed as parameter values"); | ||
| } | ||
| if (value instanceof Map) { |
There was a problem hiding this comment.
Should we also recurse through map keys?
| */ | ||
| private static void validateParameterValue(final Object value) { | ||
| if (value instanceof Traversal) { | ||
| throw new GremlinParserException("Traversals are not allowed as parameter values"); |
There was a problem hiding this comment.
I think this should be kept out of scope from this work, but I'm curious if there may be demand to parameterize something like CardinalityValueTraversal in the future. That's a funky case which generally acts as a static value but is technically a Traversal.
| throw new GremlinParserException("Parameter map nesting depth exceeds maximum of " + maxNestingDepth); | ||
| } | ||
| try { | ||
| return super.visitGenericCollectionLiteral(ctx); |
There was a problem hiding this comment.
Am I right in understanding that this will result in all objects contained in the collection to be parsed by GenericLiteralVisitor.visitGenericLiteral() instead of ParameterMapVisitor.visitGenericLiteral()? Do we need more careful handling of collections and any composite types to ensure that they are recursively parsed through this class and not handed off to the unguarded GenericLiteralVisitor?
|
|
||
| @Test(expected = GremlinParserException.class) | ||
| public void shouldRejectTerminatedTraversalInValue() { | ||
| GremlinQueryParser.parseParameters("[\"x\":g.V().drop().iterate()]"); |
There was a problem hiding this comment.
I think it might be worth a few more cases which try to bury a terminatedTraversal deeper inside other collections/composite types.
https://issues.apache.org/jira/browse/TINKERPOP-3247
Moving parameters from binary-serialized maps to string representations
makes the request side pure text, decoupling Gremlin language evolution
from GraphBinary versioning. New types can be introduced in minor/patch
versions without touching GraphBinary, eliminating the need for a major
version bump across the ecosystem for every new request-side type.
The asParameter() fallback is replaced with an unsupportedType flag that
records the class name and falls back to toString(). A flag is used
rather than throwing because embedded Traversals build GremlinLang as a
side effect but never send it, so unknown types must not break
execution. All other GLVs throw immediately since they have no embedded
mode and the early throw gives better errors.
Client APIs accept both map and string bindings (but not both at the
same time) because users who use the Client directly with raw Gremlin
strings shouldn't need to hand-craft gremlin-lang map literals. Mixing
both throws immediately to prevent silent loss where one set of bindings
would be discarded.
Edge and VertexProperty tests that relied on the old asParameter
fallback were removed because they aren't supported in gremlin-lang.