Skip to content

Commit

Permalink
Mapping preview (#729)
Browse files Browse the repository at this point in the history
Record to object mapping added
  • Loading branch information
RichardIrons-neo4j authored Sep 27, 2023
1 parent 7b8ef91 commit 9854066
Show file tree
Hide file tree
Showing 25 changed files with 2,230 additions and 15 deletions.
14 changes: 7 additions & 7 deletions Neo4j.Driver/.editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -369,11 +369,11 @@ dotnet_naming_symbols.types_and_namespaces_symbols.applicable_kinds = namespace,
dotnet_naming_symbols.type_parameters_symbols.applicable_accessibilities = *
dotnet_naming_symbols.type_parameters_symbols.applicable_kinds = type_parameter
dotnet_naming_symbols.unity_serialized_field_symbols.applicable_accessibilities = *
dotnet_naming_symbols.unity_serialized_field_symbols.applicable_kinds =
dotnet_naming_symbols.unity_serialized_field_symbols.applicable_kinds =
dotnet_naming_symbols.unity_serialized_field_symbols.resharper_applicable_kinds = unity_serialised_field
dotnet_naming_symbols.unity_serialized_field_symbols.resharper_required_modifiers = instance
dotnet_naming_symbols.unity_serialized_field_symbols_1.applicable_accessibilities = *
dotnet_naming_symbols.unity_serialized_field_symbols_1.applicable_kinds =
dotnet_naming_symbols.unity_serialized_field_symbols_1.applicable_kinds =
dotnet_naming_symbols.unity_serialized_field_symbols_1.resharper_applicable_kinds = unity_serialised_field
dotnet_naming_symbols.unity_serialized_field_symbols_1.resharper_required_modifiers = instance
dotnet_separate_import_directive_groups = false
Expand Down Expand Up @@ -663,8 +663,8 @@ resharper_line_break_before_requires_clause = do_not_change
resharper_linkage_specification_braces = end_of_line
resharper_linkage_specification_indentation = none
resharper_local_function_body = block_body
resharper_macro_block_begin =
resharper_macro_block_end =
resharper_macro_block_begin =
resharper_macro_block_end =
resharper_max_array_initializer_elements_on_line = 10000
resharper_max_attribute_length_for_same_line = 38
resharper_max_enum_members_on_line = 1
Expand Down Expand Up @@ -698,7 +698,7 @@ resharper_parentheses_non_obvious_operations = none, shift, bitwise_and, bitwise
resharper_parentheses_redundancy_style = remove_if_not_clarifies_precedence
resharper_parentheses_same_type_operations = false
resharper_pi_attributes_indent = align_by_first_attribute
resharper_place_accessorholder_attribute_on_same_line = if_owner_is_single_line
resharper_place_accessorholder_attribute_on_same_line = false
resharper_place_accessor_attribute_on_same_line = if_owner_is_single_line
resharper_place_comments_at_first_column = false
resharper_place_constructor_initializer_on_same_line = true
Expand Down Expand Up @@ -734,7 +734,7 @@ resharper_resx_attribute_indent = single_indent
resharper_resx_blank_line_after_pi = true
resharper_resx_indent_text = OneIndent
resharper_resx_keep_user_linebreaks = true
resharper_resx_linebreak_before_elements =
resharper_resx_linebreak_before_elements =
resharper_resx_max_blank_lines_between_tags = 0
resharper_resx_pi_attribute_style = do_not_touch
resharper_resx_space_before_self_closing = false
Expand Down Expand Up @@ -963,7 +963,7 @@ resharper_xml_attribute_indent = align_by_first_attribute
resharper_xml_blank_line_after_pi = true
resharper_xml_indent_text = OneIndent
resharper_xml_keep_user_linebreaks = true
resharper_xml_linebreak_before_elements =
resharper_xml_linebreak_before_elements =
resharper_xml_max_blank_lines_between_tags = 2
resharper_xml_pi_attribute_style = do_not_touch
resharper_xml_space_before_self_closing = true
Expand Down
16 changes: 8 additions & 8 deletions Neo4j.Driver/Neo4j.Driver.Tests/.editorconfig
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[*]
[*]
charset = utf-8-bom
end_of_line = crlf
indent_size = 4
Expand Down Expand Up @@ -369,11 +369,11 @@ dotnet_naming_symbols.types_and_namespaces_symbols.applicable_kinds = namespace,
dotnet_naming_symbols.type_parameters_symbols.applicable_accessibilities = *
dotnet_naming_symbols.type_parameters_symbols.applicable_kinds = type_parameter
dotnet_naming_symbols.unity_serialized_field_symbols.applicable_accessibilities = *
dotnet_naming_symbols.unity_serialized_field_symbols.applicable_kinds =
dotnet_naming_symbols.unity_serialized_field_symbols.applicable_kinds =
dotnet_naming_symbols.unity_serialized_field_symbols.resharper_applicable_kinds = unity_serialised_field
dotnet_naming_symbols.unity_serialized_field_symbols.resharper_required_modifiers = instance
dotnet_naming_symbols.unity_serialized_field_symbols_1.applicable_accessibilities = *
dotnet_naming_symbols.unity_serialized_field_symbols_1.applicable_kinds =
dotnet_naming_symbols.unity_serialized_field_symbols_1.applicable_kinds =
dotnet_naming_symbols.unity_serialized_field_symbols_1.resharper_applicable_kinds = unity_serialised_field
dotnet_naming_symbols.unity_serialized_field_symbols_1.resharper_required_modifiers = instance
dotnet_separate_import_directive_groups = false
Expand Down Expand Up @@ -663,8 +663,8 @@ resharper_line_break_before_requires_clause = do_not_change
resharper_linkage_specification_braces = end_of_line
resharper_linkage_specification_indentation = none
resharper_local_function_body = block_body
resharper_macro_block_begin =
resharper_macro_block_end =
resharper_macro_block_begin =
resharper_macro_block_end =
resharper_max_array_initializer_elements_on_line = 10000
resharper_max_attribute_length_for_same_line = 38
resharper_max_enum_members_on_line = 1
Expand Down Expand Up @@ -698,7 +698,7 @@ resharper_parentheses_non_obvious_operations = none, shift, bitwise_and, bitwise
resharper_parentheses_redundancy_style = remove_if_not_clarifies_precedence
resharper_parentheses_same_type_operations = false
resharper_pi_attributes_indent = align_by_first_attribute
resharper_place_accessorholder_attribute_on_same_line = if_owner_is_single_line
resharper_place_accessorholder_attribute_on_same_line = false
resharper_place_accessor_attribute_on_same_line = if_owner_is_single_line
resharper_place_comments_at_first_column = false
resharper_place_constructor_initializer_on_same_line = true
Expand Down Expand Up @@ -734,7 +734,7 @@ resharper_resx_attribute_indent = single_indent
resharper_resx_blank_line_after_pi = true
resharper_resx_indent_text = OneIndent
resharper_resx_keep_user_linebreaks = true
resharper_resx_linebreak_before_elements =
resharper_resx_linebreak_before_elements =
resharper_resx_max_blank_lines_between_tags = 0
resharper_resx_pi_attribute_style = do_not_touch
resharper_resx_space_before_self_closing = false
Expand Down Expand Up @@ -963,7 +963,7 @@ resharper_xml_attribute_indent = align_by_first_attribute
resharper_xml_blank_line_after_pi = true
resharper_xml_indent_text = OneIndent
resharper_xml_keep_user_linebreaks = true
resharper_xml_linebreak_before_elements =
resharper_xml_linebreak_before_elements =
resharper_xml_max_blank_lines_between_tags = 2
resharper_xml_pi_attribute_style = do_not_touch
resharper_xml_space_before_self_closing = true
Expand Down
49 changes: 49 additions & 0 deletions Neo4j.Driver/Neo4j.Driver.Tests/Mapping/DictAsRecordTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright (c) "Neo4j"
// Neo4j Sweden AB [http://neo4j.com]
//
// This file is part of Neo4j.
//
// Licensed under the Apache License, Version 2.0 (the "License").
// You may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System.Collections.Generic;
using FluentAssertions;
using Neo4j.Driver.Preview.Mapping;
using Xunit;
using Record = Neo4j.Driver.Internal.Result.Record;

namespace Neo4j.Driver.Tests.Mapping
{
public class DictAsRecordTests
{
[Fact]
public void ShouldReturnCorrectValues()
{
var originalRecord = new Record(new[] {"name", "age"}, new object[] {"Bob", 42});
var dict = new Dictionary<string, object>
{
{"key1", "value1"},
{"key2", "value2"}
};

var subject = new DictAsRecord(dict, originalRecord);

subject.Record.Should().BeSameAs(originalRecord);
subject.Keys.Should().BeEquivalentTo(dict.Keys);
subject.Values.Should().BeEquivalentTo(dict);
subject[0].Should().Be("value1");
subject[1].Should().Be("value2");
subject["key1"].Should().Be("value1");
subject["key2"].Should().Be("value2");
}
}
}
130 changes: 130 additions & 0 deletions Neo4j.Driver/Neo4j.Driver.Tests/Mapping/LabelCaptureTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
// Copyright (c) "Neo4j"
// Neo4j Sweden AB [http://neo4j.com]
//
// This file is part of Neo4j.
//
// Licensed under the Apache License, Version 2.0 (the "License").
// You may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System.Collections.Generic;
using System.Linq;
using FluentAssertions;
using Neo4j.Driver.Internal.Types;
using Neo4j.Driver.Preview.Mapping;
using Xunit;
using Record = Neo4j.Driver.Internal.Result.Record;

namespace Neo4j.Driver.Tests.Mapping
{
public class LabelCaptureTests
{
public class TestMappedClass
{
[MappingSource("Person", EntityMappingSource.NodeLabel)]
public string Label { get; set; }

[MappingSource("Person", EntityMappingSource.NodeLabel)]
public List<string> Labels { get; set; }

[MappingSource("Relationship", EntityMappingSource.RelationshipType)]
public string RelationshipType { get; set; }
}

public LabelCaptureTests()
{
RecordObjectMapping.Reset();
}

[Fact]
public void ShouldCaptureSingleNodeLabel()
{
var node = new Node(1, new[] { "Test" }, new Dictionary<string, object>());
var record = new Record(new[] { "Person" }, new object[] { node });

var mapped = record.AsObject<TestMappedClass>();

mapped.Label.Should().Be("Test");
}

[Fact]
public void ShouldCaptureMultipleNodeLabelsIntoString()
{
var node = new Node(1, new[] { "Alpha", "Bravo", "Charlie" }, new Dictionary<string, object>());
var record = new Record(new[] { "Person" }, new object[] { node });

var mapped = record.AsObject<TestMappedClass>();

mapped.Label.Should().Be("Alpha,Bravo,Charlie");
}

[Fact]
public void ShouldCaptureRelationshipType()
{
var node = new Relationship(1, 2, 3, "ACTED_IN", new Dictionary<string, object>());
var record = new Record(new[] { "Relationship" }, new object[] { node });

var mapped = record.AsObject<TestMappedClass>();

mapped.RelationshipType.Should().Be("ACTED_IN");
}

class CustomMapper : IMappingProvider
{
/// <inheritdoc />
public void CreateMappers(IMappingRegistry registry)
{
registry.RegisterMapping<TestMappedClass>(
b => b
.Map(
x => x.Label,
"Person",
EntityMappingSource.NodeLabel,
x => string.Join("|", ((string[])x).Select(y => y.ToUpper())))
.Map(
x => x.Labels,
"Person",
EntityMappingSource.NodeLabel,
x => ((string[])x).Select(y => y.Replace("a", "x")).ToList())
.Map(
x => x.RelationshipType,
"Relationship",
EntityMappingSource.RelationshipType,
x => x?.ToString()?.ToLower()));
}
}

[Fact]
public void ShouldCaptureAndConvertLabels()
{
RecordObjectMapping.RegisterProvider<CustomMapper>();
var node = new Node(1, new[] { "Alpha", "Bravo", "Charlie" }, new Dictionary<string, object>());
var record = new Record(new[] { "Person" }, new object[] { node });

var mapped = record.AsObject<TestMappedClass>();

mapped.Label.Should().Be("ALPHA|BRAVO|CHARLIE");
mapped.Labels.Should().BeEquivalentTo(new[] { "Alphx", "Brxvo", "Chxrlie" });
}

[Fact]
public void ShouldCaptureAndConvertRelationshipType()
{
RecordObjectMapping.RegisterProvider<CustomMapper>();
var node = new Relationship(1, 2, 3, "ACTED_IN", new Dictionary<string, object>());
var record = new Record(new[] { "Relationship" }, new object[] { node });

var mapped = record.AsObject<TestMappedClass>();

mapped.RelationshipType.Should().Be("acted_in");
}
}
}
58 changes: 58 additions & 0 deletions Neo4j.Driver/Neo4j.Driver.Tests/Mapping/MappingBuilderTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright (c) "Neo4j"
// Neo4j Sweden AB [http://neo4j.com]
//
// This file is part of Neo4j.
//
// Licensed under the Apache License, Version 2.0 (the "License").
// You may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System;
using FluentAssertions;
using Neo4j.Driver.Preview.Mapping;
using Xunit;

namespace Neo4j.Driver.Tests.Mapping
{
public class MappingBuilderTests
{
private class TestClass
{
public int Settable { get; set; }
public int NotSettable { get; } = -1;
public int NotAProperty = 0x6060B017;
}

[Fact]
public void ShouldThrowIfNotAMemberExpression()
{
var subject = new MappingBuilder<TestClass>();
var act = () => subject.Map(x => "something", "foo");
act.Should().Throw<ArgumentException>();
}

[Fact]
public void ShouldThrowIfNotAPropertyExpression()
{
var subject = new MappingBuilder<TestClass>();
var act = () => subject.Map(x => x.NotAProperty, "foo");
act.Should().Throw<ArgumentException>();
}

[Fact]
public void ShouldThrowIfPropertyDoesNotHaveASetter()
{
var subject = new MappingBuilder<TestClass>();
var act = () => subject.Map(x => x.NotSettable, "foo");
act.Should().Throw<ArgumentException>();
}
}
}
Loading

0 comments on commit 9854066

Please sign in to comment.