diff --git a/examples/Example1.BasicCRUD/DocumentationSnippets.cs b/examples/Example1.BasicCRUD/DocumentationSnippets.cs index 40706c7c..4c2e82e9 100644 --- a/examples/Example1.BasicCRUD/DocumentationSnippets.cs +++ b/examples/Example1.BasicCRUD/DocumentationSnippets.cs @@ -25,6 +25,7 @@ private static async Task QueryAsync(IGraph graph) .Where(person => person.Department == "Engineering") .ToListAsync(); // snippet-end: query + Console.WriteLine($"Found {engineers.Count} engineer(s)."); } private static async Task UpdateAndDeleteAsync(IGraph graph, Person alice) diff --git a/examples/Example2.LINQAndTraversal/DocumentationSnippets.cs b/examples/Example2.LINQAndTraversal/DocumentationSnippets.cs index cf14c3d6..d9b129c5 100644 --- a/examples/Example2.LINQAndTraversal/DocumentationSnippets.cs +++ b/examples/Example2.LINQAndTraversal/DocumentationSnippets.cs @@ -17,6 +17,7 @@ private static async Task QueryRootsAsync(IGraph graph) .Where(person => person.Age >= 28 && person.Age <= 32) .ToListAsync(); // snippet-end: query-roots + Console.WriteLine($"Found {newYorkers.Count} New Yorker(s) and {ageRange.Count} person(s) in the age range."); } private static async Task TraverseAsync(IGraph graph) @@ -32,6 +33,8 @@ private static async Task TraverseAsync(IGraph graph) .Traverse(2) .ToListAsync(); // snippet-end: traversal + Console.WriteLine( + $"Found {directConnections.Count} direct connection(s) and {twoHopConnections.Count} two-hop connection(s)."); } private static async Task PathSegmentsAsync(IGraph graph) @@ -42,5 +45,6 @@ private static async Task PathSegmentsAsync(IGraph graph) .PathSegments() .ToListAsync(); // snippet-end: path-segments + Console.WriteLine($"Found {connections.Count} path segment(s)."); } } diff --git a/examples/Playground/DocumentationSnippets.cs b/examples/Playground/DocumentationSnippets.cs index ac7a636a..0327aceb 100644 --- a/examples/Playground/DocumentationSnippets.cs +++ b/examples/Playground/DocumentationSnippets.cs @@ -108,6 +108,7 @@ private static async Task SetBasedMutationAsync(IGraph graph) .Where(person => person.Email.EndsWith("@expired.example")) .DeleteAsync(cascadeDelete: true); // snippet-end: set-based-mutation + Console.WriteLine($"Updated {updated} and deleted {deleted} person(s)."); } private static async Task Neo4jQuickStartAsync() @@ -124,6 +125,7 @@ private static async Task Neo4jQuickStartAsync() .OrderBy(u => u.CreatedDate) .ToListAsync(); // snippet-end: neo4j-quick-start + Console.WriteLine($"Found {users.Count} active user(s)."); } private static async Task AgeQuickStartAsync() @@ -140,6 +142,7 @@ private static async Task AgeQuickStartAsync() .Where(user => user.IsActive) .ToListAsync(); // snippet-end: age-quick-start + Console.WriteLine($"Found {activeUsers.Count} active user(s)."); } private static async Task InMemoryQuickStartAsync() @@ -151,5 +154,6 @@ private static async Task InMemoryQuickStartAsync() await graph.CreateNodeAsync(new Person { Name = "Alice" }); var alice = await graph.Nodes().Where(p => p.Name == "Alice").SingleAsync(); // snippet-end: in-memory-quick-start + Console.WriteLine(alice.Name); } } diff --git a/src/Graph.Age/Querying/Cypher/Execution/CypherEngine.cs b/src/Graph.Age/Querying/Cypher/Execution/CypherEngine.cs index 527ca2d9..79630bdb 100644 --- a/src/Graph.Age/Querying/Cypher/Execution/CypherEngine.cs +++ b/src/Graph.Age/Querying/Cypher/Execution/CypherEngine.cs @@ -137,6 +137,8 @@ await DeleteNodesAsync( } else if (mutation.Kind == GraphMutationKind.Update) { + var updateComplexPlan = complexPlan ?? throw new InvalidOperationException( + "An update mutation must have a complex-property plan."); if (!constraintPlan.IsEmpty) { var rows = await ReadConstraintRowsAsync( @@ -153,7 +155,7 @@ await ValidateUnselectedConstraintsAsync( transaction, cancellationToken).ConfigureAwait(false); } - else if (complexPlan!.HasWork) + else if (updateComplexPlan.HasWork) { // Complex replacement spans multiple AGE statements. Lock every frozen parent in // the same global order as constrained and entity-manager updates before any scalar @@ -172,14 +174,14 @@ await transaction.Runner.AcquireElementLocksAsync( _ = await ExecuteStatementAsync(statement, transaction, cancellationToken).ConfigureAwait(false); } - if (complexPlan!.HasWork) + if (updateComplexPlan.HasWork) { await _complexPropertyManager.ReplaceGraphIdBoundComplexPropertiesAsync( transaction.Runner, nativeIdentities.Cast().ToArray(), - complexPlan.RelationshipTypesToClear, - complexPlan.PropertyNamesToClear, - complexPlan.ReplacementEntity, + updateComplexPlan.RelationshipTypesToClear, + updateComplexPlan.PropertyNamesToClear, + updateComplexPlan.ReplacementEntity, cancellationToken).ConfigureAwait(false); } } @@ -232,14 +234,15 @@ await transaction.Runner.AcquireElementLocksAsync( constraintPlan.Properties.Select(property => property.StorageName).ToArray(), acquireWriteLock: false); var records = await ExecuteStatementAsync(statement, transaction, cancellationToken).ConfigureAwait(false); - var rows = records.Select(record => new GraphMutationConstraintRow( - record["__nativeId"].As(), - constraintPlan.Properties.Select((property, index) => new + var rows = records.Select(record => + { + var values = constraintPlan.Properties.Select((property, index) => { - property.StorageName, - Value = (object?)record[CypherMutationPlanner.ConstraintValueColumn(index)].As(), - }) - .ToDictionary(item => item.StorageName, item => item.Value, StringComparer.Ordinal))) + object? value = record[CypherMutationPlanner.ConstraintValueColumn(index)].As(); + return new KeyValuePair(property.StorageName, value); + }).ToDictionary(item => item.Key, item => item.Value, StringComparer.Ordinal); + return new GraphMutationConstraintRow(record["__nativeId"].As(), values); + }) .ToArray(); GraphMutationConstraintPlan.ValidateTargetRows(nativeIdentities, rows); return rows; diff --git a/src/Graph.CompatibilityTests/IComplexObjectGraphSerializationTests.cs b/src/Graph.CompatibilityTests/IComplexObjectGraphSerializationTests.cs index fc91b4df..b8cdde54 100644 --- a/src/Graph.CompatibilityTests/IComplexObjectGraphSerializationTests.cs +++ b/src/Graph.CompatibilityTests/IComplexObjectGraphSerializationTests.cs @@ -254,7 +254,7 @@ public async Task ConcurrentCollectionUpdates_SeparateTransactions_OneWriterItem public async Task UpdateCleanup_RemovesOnlyComplexValue_DomainRelationshipAndNodeSurvive() { var cancellationToken = TestContext.Current.CancellationToken; - var (owner, domainNode, domainRelationship) = await SeedCollisionAsync( + var (owner, domainNode, _) = await SeedCollisionAsync( complexCity: "Complex Seattle", domainCity: "Domain Portland", cancellationToken); diff --git a/src/Graph.CompatibilityTests/IQueryTraversalTests.cs b/src/Graph.CompatibilityTests/IQueryTraversalTests.cs index b6cafb80..0604a48c 100644 --- a/src/Graph.CompatibilityTests/IQueryTraversalTests.cs +++ b/src/Graph.CompatibilityTests/IQueryTraversalTests.cs @@ -1656,8 +1656,8 @@ await Graph.ConnectAsync( .OptionalTraverse() .Select(result => new { - SourceId = ((Person)result.Source).TestKey, - TargetId = result.Target == null ? null : ((Person)result.Target).TestKey, + SourceId = ((Person)result.Source).TestKey, // lgtm[cs/useless-cast-to-self] + TargetId = result.Target == null ? null : result.Target.TestKey, }) .ToListAsync(TestContext.Current.CancellationToken); @@ -1668,7 +1668,7 @@ await Graph.ConnectAsync( Assert.Contains(results, result => ((Person)result.Source).TestKey == self.TestKey && ((Person?)result.Target)?.TestKey == self.TestKey); Assert.Equal( new[] { one.TestKey, many.TestKey }.Order().ToArray(), - incoming.Select(result => ((Person)result.Target!).TestKey).Order().ToArray()); + incoming.Select(result => result.Target!.TestKey).Order().ToArray()); Assert.Equal(unmatched.TestKey, Assert.Single(projected).SourceId); Assert.Null(projected[0].TargetId); } diff --git a/src/Graph.InMemory/Serialization/EntityReader.cs b/src/Graph.InMemory/Serialization/EntityReader.cs index 15c78276..52d8c8b3 100644 --- a/src/Graph.InMemory/Serialization/EntityReader.cs +++ b/src/Graph.InMemory/Serialization/EntityReader.cs @@ -100,7 +100,7 @@ public EntityInfo BuildEntityInfo(NodeRecord record, StoreState state, Type actu elementType, [.. children .OrderBy(item => item.SequenceNumber) - .Select(item => (EntityInfo?)item.Item2)]); + .Select(item => item.Item2)]); } complexProperties[name] = new Property( diff --git a/src/Graph.Neo4j/Querying/Cypher/Execution/CypherEngine.cs b/src/Graph.Neo4j/Querying/Cypher/Execution/CypherEngine.cs index fbc1c815..5d6d690e 100644 --- a/src/Graph.Neo4j/Querying/Cypher/Execution/CypherEngine.cs +++ b/src/Graph.Neo4j/Querying/Cypher/Execution/CypherEngine.cs @@ -214,14 +214,17 @@ private async Task> ReadConstraintRows constraintPlan.Properties.Select(property => property.StorageName).ToArray(), acquireWriteLock: true); var records = await ExecuteStatementAsync(statement, transaction, cancellationToken).ConfigureAwait(false); - var rows = records.Select(record => new GraphMutationConstraintRow( - global::Neo4j.Driver.ValueExtensions.As(record["__nativeId"]), - constraintPlan.Properties.Select((property, index) => new + var rows = records.Select(record => + { + var values = constraintPlan.Properties.Select((property, index) => { - property.StorageName, - Value = (object?)record[CypherMutationPlanner.ConstraintValueColumn(index)], - }) - .ToDictionary(item => item.StorageName, item => item.Value, StringComparer.Ordinal))) + object? value = record[CypherMutationPlanner.ConstraintValueColumn(index)]; + return new KeyValuePair(property.StorageName, value); + }).ToDictionary(item => item.Key, item => item.Value, StringComparer.Ordinal); + return new GraphMutationConstraintRow( + global::Neo4j.Driver.ValueExtensions.As(record["__nativeId"]), + values); + }) .ToArray(); GraphMutationConstraintPlan.ValidateTargetRows(nativeIdentities, rows); return rows; diff --git a/src/Graph.Serialization.CodeGen/CodeGenModelBuilder.cs b/src/Graph.Serialization.CodeGen/CodeGenModelBuilder.cs index fc7ba616..195d2981 100644 --- a/src/Graph.Serialization.CodeGen/CodeGenModelBuilder.cs +++ b/src/Graph.Serialization.CodeGen/CodeGenModelBuilder.cs @@ -458,8 +458,6 @@ private static bool ImplementsGraphInterface(INamedTypeSymbol type, string inter private static string FindPropertyNameForParameter(IParameterSymbol parameter) { - var parameterName = parameter.Name; - return Utils.GetPropertyNameFromParameter(parameter); } diff --git a/src/Graph.Serialization/RuntimeRepresentation/ComplexCollectionStorageCodec.cs b/src/Graph.Serialization/RuntimeRepresentation/ComplexCollectionStorageCodec.cs index 376a974a..49e25f52 100644 --- a/src/Graph.Serialization/RuntimeRepresentation/ComplexCollectionStorageCodec.cs +++ b/src/Graph.Serialization/RuntimeRepresentation/ComplexCollectionStorageCodec.cs @@ -94,7 +94,7 @@ internal static IReadOnlyList GetCompanionPropertyNames(string logicalNa // deployed-storage compatibility promise: every newly persisted collection has metadata. return new EntityCollection( expectedElementType, - [.. storedEntities.OrderBy(item => item.SequenceNumber).Select(item => (EntityInfo?)item.Entity)]); + [.. storedEntities.OrderBy(item => item.SequenceNumber).Select(item => item.Entity)]); } if (expectedElementType != typeof(object) && metadata.ElementType != expectedElementType) diff --git a/tests/Graph.Core.Tests/GraphMutationModelBuilderTests.cs b/tests/Graph.Core.Tests/GraphMutationModelBuilderTests.cs index 79918a9d..9d5cec6d 100644 --- a/tests/Graph.Core.Tests/GraphMutationModelBuilderTests.cs +++ b/tests/Graph.Core.Tests/GraphMutationModelBuilderTests.cs @@ -380,20 +380,23 @@ public void ConstraintPlan_RejectsCollectionConstraintBeforeSchemaAccess() { Expression>> invalidSelector = metadata => metadata.Values; + Expression, GraphPropertySetters>> setters = + builder => builder.SetProperty(person => person.Nicknames, Array.Empty()); var selection = GraphMutationModelBuilder.Build(UpdateCall( Root(), - (Expression, GraphPropertySetters>>)(builder => - builder.SetProperty(person => person.Nicknames, Array.Empty())))).Selection; + setters)).Selection; var property = typeof(InvalidCollectionConstraintMetadata).GetProperty( nameof(InvalidCollectionConstraintMetadata.Values))!; var scalarProperty = typeof(InvalidCollectionConstraintMetadata).GetProperty( nameof(InvalidCollectionConstraintMetadata.ScalarValue))!; + Expression> scalarSelector = + metadata => metadata.ScalarValue; var mutation = new GraphMutationModel( GraphMutationKind.Update, selection, [ new GraphConstantPropertyAssignment( - (Expression>)(metadata => metadata.ScalarValue), + scalarSelector, scalarProperty, nameof(InvalidCollectionConstraintMetadata.ScalarValue), dynamic: false, diff --git a/tests/Graph.Core.Tests/GraphQueryProviderBaseTests.cs b/tests/Graph.Core.Tests/GraphQueryProviderBaseTests.cs index f240581e..d35f6ff1 100644 --- a/tests/Graph.Core.Tests/GraphQueryProviderBaseTests.cs +++ b/tests/Graph.Core.Tests/GraphQueryProviderBaseTests.cs @@ -410,6 +410,7 @@ private static async Task ConsumeAsync(IAsyncEnumerable stream) { await foreach (var _ in stream) { + // Enumerating the stream is the behavior under test. } } diff --git a/tests/Graph.Neo4j.Translation.Tests/TraversalTranslationTests.cs b/tests/Graph.Neo4j.Translation.Tests/TraversalTranslationTests.cs index d581341a..a3e99cc6 100644 --- a/tests/Graph.Neo4j.Translation.Tests/TraversalTranslationTests.cs +++ b/tests/Graph.Neo4j.Translation.Tests/TraversalTranslationTests.cs @@ -28,7 +28,8 @@ public Task Traverse_NoDepthOrDirection() [Fact] public Task Traverse_WidenedToINodeBeforeLabelFilter_LeavesStartUnconstrained() { - var query = ((IGraphQueryable)Root.Nodes()) + IGraphQueryable nodes = Root.Nodes(); + var query = nodes .OfLabel("Person") .Traverse(); @@ -118,8 +119,8 @@ public Task OptionalTraverse_ComposesProjectionAndPaging() .OptionalTraverse() .Select(result => new { - SourceKey = ((Person)result.Source).TestKey, - TargetKey = result.Target == null ? null : ((Person)result.Target).TestKey, + SourceKey = ((Person)result.Source).TestKey, // lgtm[cs/useless-cast-to-self] + TargetKey = result.Target == null ? null : result.Target.TestKey, }) .Take(5);