Skip to content

Write a map() that is all of a project().by() as the traversal it wraps - #2475

Merged
danielcweber merged 4 commits into
14.xfrom
optimize/unwrap-map-in-project-by
Sep 30, 2026
Merged

danielcweber merged 4 commits into
14.xfrom
optimize/unwrap-map-in-project-by

Conversation

@danielcweber

@danielcweber danielcweber commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Project(...).By(...) no longer writes a map() that is all of the by() traversal: By(__ => __.Map(__ => __.Out<WorksFor>().Count())) is emitted as by(__.out('WorksFor').count()) instead of by(__.map(__.out('WorksFor').count())). by() only takes the first result of its traversal for the one element it is given, which is all that map() does, so the step only added length and one more step to evaluate per element. The shape comes up with helpers like "the first value of a property per element", which need the map() in the middle of a query and not once they end up in a by(). A local() in the same position was already left out. Both are now handled in one place, in any nesting: By(__ => __.Local(__ => __.Map(...))) and By(__ => __.Map(__ => __.Map(...))) end up without either.

Changes

  • Core, Project(...).By(...): when the traversal of a by() is nothing but a map() or a local(), the traversal inside it takes its place, repeatedly. This happens where the by() is built.
  • Core, serialization: the by() of a project() is written as it is. Leaving out a local() there has moved to the operator above.
  • Core.Tests: the first commit records what these shapes were written as before, so every following commit shows as changes to those snapshots.

Notes

  • Closes Unwrap map() as the only step of a project().by() traversal #2464.
  • A lone values('key') with a single key keeps the map() or local() around it. TinkerPop's ByModulatorOptimizationStrategy turns by(__.values('key')) into by('key'), which fails on a property with more than one value, while by(__.map(__.values('key'))) takes the first one. This now holds for local() as well: By(__ => __.Local(__ => __.Values(x => x.Name))) was emitted as by(__.values('Name')) and is now emitted as by(__.local(__.values('Name'))). It is a commit of its own.
  • The rule lives in the operator, where Gremlinq's other optimizations are. A ProjectStep.ByTraversalStep pushed directly via ConfigureSteps is written as pushed, including a local() inside it, which the serializer used to leave out.
  • With EnableEmptyProjectionValueProtection, the map() or local() is now gone before limit(1).fold() is appended, so by(__.local(t).limit(1).fold()) becomes by(t.limit(1).fold()). The value is the same: the first result of t, folded. One existing snapshot changes for this reason.
  • The equivalences rest on how TinkerPop runs a by() of project() (one element, bulk 1, first result), read in the 3.4 and 3.7 sources, not on a run against a server. The new tests are serialization tests only.
  • No public API change.

🤖 Generated with Claude Code

@codecov

codecov Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.59%. Comparing base (059d72d) to head (59a435a).

Additional details and impacted files
@@            Coverage Diff             @@
##             14.x    #2475      +/-   ##
==========================================
+ Coverage   93.57%   93.59%   +0.01%     
==========================================
  Files         279      279              
  Lines        7880     7894      +14     
  Branches      885      885              
==========================================
+ Hits         7374     7388      +14     
  Misses        313      313              
  Partials      193      193              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

danielcweber and others added 4 commits September 30, 2026 13:44
…n as

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… built, not where it is written

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@danielcweber
danielcweber force-pushed the optimize/unwrap-map-in-project-by branch from aca13c8 to 59a435a Compare September 30, 2026 12:53
@danielcweber danielcweber changed the title Unwrap map() as the only step of a project().by() traversal Write a map() that is all of a project().by() as the traversal it wraps Sep 30, 2026
@danielcweber
danielcweber merged commit 59a435a into 14.x Sep 30, 2026
6 checks passed
@danielcweber
danielcweber deleted the optimize/unwrap-map-in-project-by branch September 30, 2026 13:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unwrap map() as the only step of a project().by() traversal

1 participant