Replace Bytecode with GremlinLang in JavaScript GLV#3307
Replace Bytecode with GremlinLang in JavaScript GLV#3307kirill-stepanishin wants to merge 1 commit intoapache:masterfrom
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #3307 +/- ##
============================================
- Coverage 77.87% 75.80% -2.07%
+ Complexity 13578 13271 -307
============================================
Files 1015 1020 +5
Lines 59308 59864 +556
Branches 6835 7034 +199
============================================
- Hits 46184 45379 -805
- Misses 10817 11815 +998
- Partials 2307 2670 +363 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Cole-Greer
left a comment
There was a problem hiding this comment.
Overall I think this looks really good. Most of my comments are just for context and not anything which needs action in this PR, the rest are all for minor clarifications and tweaks.
| 'materializeProperties', | ||
| 'bulkResults', | ||
| ]; | ||
| for (const strategy of strategies) { |
There was a problem hiding this comment.
I expect all of the strategy handling here will need to be adjusted in the future. I think this is good enough for now and we can revisit this as we get more pieces of the driver functioning and get more tests running.
| return this.withStrategies(new OptionsStrategy({ [key]: val })); | ||
| } | ||
| optionsStrategy[1].configuration[key] = val; | ||
| glStrategies[glStrategies.length - 1].configuration[key] = val; |
There was a problem hiding this comment.
I've got some questions around how OptionsStrategy needs to work as all the pieces of this driver come together. What you have here looks about right for now. It will become easier to reason about if any adjustments are needed here once more of the driver is complete.
| if (arg === null || arg === undefined) return 'null'; | ||
| if (typeof arg === 'boolean') return arg ? 'true' : 'false'; | ||
| if (arg instanceof Long) { | ||
| return String(arg.value); |
There was a problem hiding this comment.
I think we should probably append an L suffix on longs.
| return String(arg.value); | ||
| } | ||
| if (arg instanceof Date) { | ||
| const iso = arg.toISOString().replace('.000Z', 'Z'); |
There was a problem hiding this comment.
Was this added to be more consistent with Java, Python, and Go? I think it's ok to save a step here and keep .000Z as both are equivalent. Not sure if anyone has other opinions on this.
| return String(arg); | ||
| } | ||
| if (typeof arg === 'string') { | ||
| const escaped = JSON.stringify(arg).slice(1, -1).replace(/'/g, "\\'"); |
There was a problem hiding this comment.
I'm not understanding what the JSON.stringify() and slice() are doing here. Could we just do a replace() directly on arg itself?
| // #91 | ||
| [g.withStrategies(new SubgraphStrategy({vertices: __.has('region','US-TX'), vertexProperties: __.hasNot('runways')})).V().count(), "g.withStrategies(new SubgraphStrategy(vertices:__.has('region','US-TX'),vertexProperties:__.hasNot('runways'))).V().count()"], | ||
| // #92 | ||
| [g.withStrategies(new ReadOnlyStrategy(), new SubgraphStrategy({vertices: __.has('region','US-TX'), edges: __.hasLabel('route')})).V().count(), "g.withStrategies(ReadOnlyStrategy,new SubgraphStrategy(vertices:__.has('region','US-TX'),edges:__.hasLabel('route'))).V().count()"], |
There was a problem hiding this comment.
I'm noticing the new keyword is only used in the GremlinLang if the strategy has arguments (ReadOnlyStrategy does not use new in this case, but SubgraphStrategy does). That appears to be consistent with Java but it is odd. I think that's fine for now but might be worth a revisit later.
|
|
||
| describe('JS-specific tests', function () { | ||
| it('should handle Long values', function () { | ||
| assert.strictEqual(g.V(new Long('9007199254740993')).getGremlinLang().getGremlin(), 'g.V(9007199254740993)'); |
There was a problem hiding this comment.
I think this should result in 'g.V(9007199254740993L)'
| assert.strictEqual(bytecode.stepInstructions[2][2].elementName, 'desc'); | ||
| }); | ||
|
|
||
| it('should add steps with Direction aliases from_ and to properly mapped to OUT and IN', function () { |
There was a problem hiding this comment.
I think these test cases are still valuable, although they should just assert the final GremlinLang string matches the expected result instead of all of these assertions for the bytecode. The first 2 and final cases all appear to be adequately covered by gremlin-lang-test already, but this case is not. Could you restore the test here or add this case to gremlin-lang-test?
| assert.strictEqual(vStartBytecode.stepInstructions[0][2], 2); // ID should be extracted from Vertex | ||
|
|
||
| // Test V() step in the middle of a traversal | ||
| const vMid = g.inject('foo').V(1, new Vertex(2, 'person')); |
There was a problem hiding this comment.
Similar to my above comment, I don't see an equivalent mid-traversal V() case in gremlin-lang-test
| assert.strictEqual(fromToBytecode.stepInstructions[2][0], 'to'); | ||
| assert.strictEqual(fromToBytecode.stepInstructions[2][1], 2); // ID should be extracted from Vertex | ||
| }); | ||
| it('should extract ID from Vertex objects for mergeE()', function () { |
There was a problem hiding this comment.
Similar to above, I don't see an equivalent for this in gremlin-lang-test.
As part of the TP4 migration, the server no longer accepts Bytecode and only processes Gremlin queries in script form.. This PR replaces
Bytecode+Translatorwith a newGremlinLangclass.Changes
GremlinLangclass that incrementally builds Gremlin query strings as steps are addedGraphTraversalSource/GraphTraversalnow accumulate intoGremlinLanginstead ofBytecodeClient.submit()only accepts strings now; all queries sent asgremlin-langlanguage.OptionsStrategyextracted intoRequestOptions(timeout, batchSize, bulkResults, etc.)Bytecode,Translator,BytecodeSerializer, and their testsIntentionally out of scope for this PR