Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion src/Core/Queries/GremlinQuery.ProjectBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,29 @@ IProjectMapBuilder<GremlinQuery<T1, T2, T3, T4>, T1, TItem1> IProjectMapBuilder<
.Push(new ProjectStep.ByTraversalStep(_outer
.Continue()
.With(projection)
.Build(static (_, traversal) => traversal))),
.Build(static (_, traversal) =>
{
// by() takes the first result of its traversal for the one element it is given, so a map() or
// a local() that is all of that traversal changes nothing about it. A lone values('key') keeps
// what is around it: TinkerPop turns by(__.values('key')) into by('key'), which fails on more
// than one value.
while (true)
{
Traversal innerTraversal;

if (traversal is [MapStep mapStep])
innerTraversal = mapStep.Traversal;
else if (traversal is [LocalStep localStep])
innerTraversal = localStep.Traversal;
else
return traversal;

if (innerTraversal is [] or [ValuesStep { Keys.Length: 1 }])
return traversal;

traversal = innerTraversal;
}
}))),
_emptyProjectionProtectionDecoratorSteps);

private ProjectBuilder<TNewItem1, TNewItem2, TNewItem3, TNewItem4, TNewItem5, TNewItem6, TNewItem7, TNewItem8, TNewItem9, TNewItem10, TNewItem11, TNewItem12, TNewItem13, TNewItem14, TNewItem15, TNewItem16> ByExpression<TNewItem1, TNewItem2, TNewItem3, TNewItem4, TNewItem5, TNewItem6, TNewItem7, TNewItem8, TNewItem9, TNewItem10, TNewItem11, TNewItem12, TNewItem13, TNewItem14, TNewItem15, TNewItem16>(Expression projection, string? name = null) => projection is LambdaExpression lambdaExpression && lambdaExpression.IsIdentityExpression()
Expand Down
10 changes: 1 addition & 9 deletions src/Core/Serialization/Serializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -544,15 +544,7 @@ private static ITransformer AddDefaultStepConverters(this ITransformer serialize
return CreateInstruction("property", recurse, env, parameters);
})
.Add<ProjectStep>((step, env, _, recurse) => CreateInstruction("project", recurse, env, step.Projections))
.Add<ProjectStep.ByTraversalStep>((step, env, _, recurse) =>
{
var traversal = step.Traversal;

if (traversal is [LocalStep localStep])
traversal = localStep.Traversal;

return CreateInstruction("by", recurse, env, traversal);
})
.Add<ProjectStep.ByTraversalStep>((step, env, _, recurse) => CreateInstruction("by", recurse, env, step.Traversal))
.Add<ProjectStep.ByKeyStep>((step, env, _, recurse) => CreateInstruction("by", recurse, env, step.Key))
.Add<RangeStep>((step, env, _, recurse) => step.Scope.Equals(Scope.Local)
? CreateInstruction("range", recurse, env, step.Scope, step.Lower, step.Upper)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
g.V().hasLabel('Person').project('Item1','Item2').by(__.out('WorksFor').count()).by(__.id())
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
g.V().hasLabel('Person').project('Item1','Item2').by(__.out('WorksFor').count()).by(__.id())
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
g.V().hasLabel('Person').project('Item1','Item2').by(__.out('WorksFor').count().limit(1).fold()).by(__.id().limit(1).fold()).map(__.unfold().group().by(__.select(keys)).by(__.select(values).unfold()))
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
g.V().hasLabel('Person').project('Item1','Item2').by(__.local(__.values('Name'))).by(__.id())
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
g.V().hasLabel('Person').project('Item1','Item2').by(__.local(__.values('Name'))).by(__.id())
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
g.V().hasLabel('Person').project('Item1','Item2').by(__.out('WorksFor').count()).by(__.id())
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
g.V().hasLabel('Person').project('Item1','Item2').by(__.out('WorksFor')).by(__.id()).project('Item1','Item2').by(__.select('Item1').project('id','label','properties').by(id).by(label).by(__.properties().group().by(label).by(__.project('id','label','value','properties').by(id).by(label).by(value).by(__.valueMap()).fold()))).by(__.select('Item2'))
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
g.V().hasLabel('Person').project('Item1','Item2').by(__.out('WorksFor').count()).by(__.id())
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
g.V().hasLabel('Person').project('count','id').by(__.out('WorksFor').count()).by(__.id())
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
g.V().hasLabel('Person').project('Item1','Item2').by(__.map(__.out('WorksFor').count()).fold()).by(__.id())
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
g.V().hasLabel('Person').project('Item1','Item2').by(__.out('WorksFor').count().limit(1).fold()).by(__.id().limit(1).fold()).map(__.unfold().group().by(__.select(keys)).by(__.select(values).unfold()))
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
g.V().hasLabel('Person').project('Item1','Item2').by(__.map(__.values('Name'))).by(__.id())
1 change: 1 addition & 0 deletions test/Core.Tests/Issues/Github/Issue2464.Repro.verified.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
g.V().hasLabel('Person').project('Item1','Item2').by(__.values('Name').limit(1)).by(__.id())
196 changes: 196 additions & 0 deletions test/Core.Tests/Issues/Github/Issue2464.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
using ExRam.Gremlinq.Core.Models;
using ExRam.Gremlinq.Tests.Entities;
using ExRam.Gremlinq.Tests.Infrastructure;
using static ExRam.Gremlinq.Core.GremlinQuerySource;

namespace ExRam.Gremlinq.Core.Tests
{
public class Issue2464 : GremlinqTestBase
{
private readonly IGremlinQuerySource _g;

public Issue2464() : base(new DebugGremlinQueryVerifier())
{
_g = g
.ConfigureEnvironment(env => env
.UseModel(GraphModel
.FromBaseTypes<Vertex, Edge>()));
}

[Fact]
public Task Repro() => _g
.V<Person>()
.Project(__ => __
.ToTuple()
.By(__ => __
.Map(__ => __
.Values(x => x.Name!)
.Limit(1)))
.By(__ => __
.Map(__ => __
.Id())))
.Verify();

[Fact]
public Task Map_Out_Count() => _g
.V<Person>()
.Project(__ => __
.ToTuple()
.By(__ => __
.Map(__ => __
.Out<WorksFor>()
.Count()))
.By(__ => __
.Id()))
.Verify();

[Fact]
public Task Map_Map_Out_Count() => _g
.V<Person>()
.Project(__ => __
.ToTuple()
.By(__ => __
.Map(__ => __
.Map(__ => __
.Out<WorksFor>()
.Count())))
.By(__ => __
.Id()))
.Verify();

[Fact]
public Task Map_Values() => _g
.V<Person>()
.Project(__ => __
.ToTuple()
.By(__ => __
.Map(__ => __
.Values(x => x.Name!)))
.By(__ => __
.Id()))
.Verify();

[Fact]
public Task Map_Out() => _g
.V<Person>()
.Project(__ => __
.ToTuple()
.By(__ => __
.Map(__ => __
.Out<WorksFor>()))
.By(__ => __
.Id()))
.Verify();

[Fact]
public Task Local_Out_Count() => _g
.V<Person>()
.Project(__ => __
.ToTuple()
.By(__ => __
.Local(__ => __
.Out<WorksFor>()
.Count()))
.By(__ => __
.Id()))
.Verify();

[Fact]
public Task Local_Out_Count_with_empty_projection_value_protection() => _g
.ConfigureEnvironment(env => env
.ConfigureOptions(options => options
.SetValue(GremlinqOption.EnableEmptyProjectionValueProtection, true)))
.V<Person>()
.Project(__ => __
.ToTuple()
.By(__ => __
.Local(__ => __
.Out<WorksFor>()
.Count()))
.By(__ => __
.Id()))
.Verify();

[Fact]
public Task Local_Values() => _g
.V<Person>()
.Project(__ => __
.ToTuple()
.By(__ => __
.Local(__ => __
.Values(x => x.Name!)))
.By(__ => __
.Id()))
.Verify();

[Fact]
public Task Map_Local_Values() => _g
.V<Person>()
.Project(__ => __
.ToTuple()
.By(__ => __
.Map(__ => __
.Local(__ => __
.Values(x => x.Name!))))
.By(__ => __
.Id()))
.Verify();

[Fact]
public Task Local_Map_Out_Count() => _g
.V<Person>()
.Project(__ => __
.ToTuple()
.By(__ => __
.Local(__ => __
.Map(__ => __
.Out<WorksFor>()
.Count())))
.By(__ => __
.Id()))
.Verify();

[Fact]
public Task Map_Out_Count_followed_by_step() => _g
.V<Person>()
.Project(__ => __
.ToTuple()
.By(__ => __
.Map(__ => __
.Out<WorksFor>()
.Count())
.Fold())
.By(__ => __
.Id()))
.Verify();

[Fact]
public Task Map_Out_Count_with_empty_projection_value_protection() => _g
.ConfigureEnvironment(env => env
.ConfigureOptions(options => options
.SetValue(GremlinqOption.EnableEmptyProjectionValueProtection, true)))
.V<Person>()
.Project(__ => __
.ToTuple()
.By(__ => __
.Map(__ => __
.Out<WorksFor>()
.Count()))
.By(__ => __
.Id()))
.Verify();

[Fact]
public Task Map_Out_Count_by_name() => _g
.V<Person>()
.Project(__ => __
.ToDynamic()
.By("count", __ => __
.Map(__ => __
.Out<WorksFor>()
.Count()))
.By("id", __ => __
.Id()))
.Verify();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,9 @@
{
StepInstructions: [
{
OperatorName: local,
OperatorName: constant,
Arguments: [
{
StepInstructions: [
{
OperatorName: constant,
Arguments: [
item2
]
}
]
}
item2
]
},
{
Expand Down
Loading