diff --git a/src/Nest/DSL/PutMappingDescriptor.cs b/src/Nest/DSL/PutMappingDescriptor.cs index 6f7f29d1bc0..81f5bad16d6 100644 --- a/src/Nest/DSL/PutMappingDescriptor.cs +++ b/src/Nest/DSL/PutMappingDescriptor.cs @@ -99,11 +99,11 @@ public PutMappingDescriptor InitializeUsing(RootObjectMapping rootObjectMappi } /// - /// Convenience method to map from most of the object from the attributes/properties. - /// Later calls can override whatever is set is by this call. - /// This helps mapping all the ints as ints, floats as floats etcetera withouth having to be overly verbose in your fluent mapping + /// Convenience method to map as much as it can based on ElasticType attributes set on the type. + ///
This method also automatically sets up mappings for known values types (int, long, double, datetime, etcetera)
+ ///
Class types default to object and Enums to int
+ ///
Later calls can override whatever is set is by this call.
///
- /// public PutMappingDescriptor MapFromAttributes(int maxRecursion = 0) { //TODO no longer needed when we have an IPutMappingRequest diff --git a/src/Nest/Resolvers/Writers/TypeMappingWriter.cs b/src/Nest/Resolvers/Writers/TypeMappingWriter.cs index 1115cbfa411..15e848949e8 100644 --- a/src/Nest/Resolvers/Writers/TypeMappingWriter.cs +++ b/src/Nest/Resolvers/Writers/TypeMappingWriter.cs @@ -15,6 +15,10 @@ public class TypeMappingWriter private readonly Type _type; private readonly IConnectionSettingsValues _connectionSettings; private readonly NestSerializer _elasticSerializer; + + private readonly static string _noFieldTypeMessage = + "Property {0} on type {1} has an ElasticProperty attribute but its FieldType (Type = ) can not be inferred and is not set explicitly while calling MapFromAttributes"; + private ElasticInferrer Infer { get; set; } private int MaxRecursion { get; set; } @@ -136,7 +140,7 @@ internal void WriteProperties(JsonWriter jsonWriter) var propertyName = this.Infer.PropertyName(p); var type = GetElasticSearchType(att, p); - + if (type == null) //could not get type from attribute or infer from CLR type. continue; @@ -194,6 +198,11 @@ private string GetElasticSearchType(IElasticPropertyAttribute att, PropertyInfo if (fieldType == null || fieldType == FieldType.None) { fieldType = this.GetFieldTypeFromType(p.PropertyType); + if (fieldType == null && att != null) + { + var message = _noFieldTypeMessage.F(p.Name, this._type.Name); + throw new DslException(message); + } } return this.GetElasticSearchTypeFromFieldType(fieldType); @@ -234,8 +243,8 @@ private string GetElasticSearchTypeFromFieldType(FieldType? fieldType) return "boolean"; case FieldType.Completion: return "completion"; - case FieldType.Nested: - return "nested"; + case FieldType.Nested: + return "nested"; case FieldType.Object: return "object"; default: @@ -255,6 +264,9 @@ private string GetElasticSearchTypeFromFieldType(FieldType? fieldType) if (propertyType == typeof(string)) return FieldType.String; + if (propertyType.IsEnum) + return FieldType.Integer; + if (propertyType.IsValueType) { switch (propertyType.Name) @@ -284,7 +296,7 @@ private static Type GetUnderlyingType(Type type) if (type.IsArray) return type.GetElementType(); - if (type.IsGenericType && type.GetGenericArguments().Length == 1 && (type.GetInterface("IEnumerable") != null || Nullable.GetUnderlyingType(type) != null)) + if (type.IsGenericType && type.GetGenericArguments().Length == 1 && (type.GetInterface("IEnumerable") != null || Nullable.GetUnderlyingType(type) != null)) return type.GetGenericArguments()[0]; return type; diff --git a/src/Tests/Nest.Tests.Unit/Core/Map/Enums/EnumCanBeOverriddenAfterMapFromAttributes.json b/src/Tests/Nest.Tests.Unit/Core/Map/Enums/EnumCanBeOverriddenAfterMapFromAttributes.json new file mode 100644 index 00000000000..e5151783255 --- /dev/null +++ b/src/Tests/Nest.Tests.Unit/Core/Map/Enums/EnumCanBeOverriddenAfterMapFromAttributes.json @@ -0,0 +1,10 @@ +{ + "myclass": { + "properties": { + "myEnum": { + "index": "not_analyzed", + "type": "string" + } + } + } +} \ No newline at end of file diff --git a/src/Tests/Nest.Tests.Unit/Core/Map/Enums/EnumMappingTests.cs b/src/Tests/Nest.Tests.Unit/Core/Map/Enums/EnumMappingTests.cs new file mode 100644 index 00000000000..cc596783cfe --- /dev/null +++ b/src/Tests/Nest.Tests.Unit/Core/Map/Enums/EnumMappingTests.cs @@ -0,0 +1,49 @@ +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace Nest.Tests.Unit.Core.Map.Enums +{ + [TestFixture] + public class EnumMappingTests : BaseJsonTests + { + private class MyClass + { + public MyEnum MyEnum { get; set; } + } + + private enum MyEnum + { + Value1, + Value2 + } + + [Test] + public void EnumShouldMapToIntByDefault() + { + var result = this._client.Map(m => m.MapFromAttributes()); + this.JsonEquals(result.ConnectionStatus.Request, MethodBase.GetCurrentMethod()); + } + + [Test] + public void EnumCanBeOverriddenAfterMapFromAttributes() + { + var result = this._client.Map(m => m + .MapFromAttributes() + .Properties(props=>props + .String(s=>s + .Name(p=>p.MyEnum) + .Index(FieldIndexOption.NotAnalyzed) + ) + ) + ); + this.JsonEquals(result.ConnectionStatus.Request, MethodBase.GetCurrentMethod()); + } + + } + +} diff --git a/src/Tests/Nest.Tests.Unit/Core/Map/Enums/EnumShouldMapToIntByDefault.json b/src/Tests/Nest.Tests.Unit/Core/Map/Enums/EnumShouldMapToIntByDefault.json new file mode 100644 index 00000000000..3a03ed2f374 --- /dev/null +++ b/src/Tests/Nest.Tests.Unit/Core/Map/Enums/EnumShouldMapToIntByDefault.json @@ -0,0 +1,9 @@ +{ + "myclass": { + "properties": { + "myEnum": { + "type": "integer" + } + } + } +} \ No newline at end of file diff --git a/src/Tests/Nest.Tests.Unit/Core/Map/Structs/EnumMappingTests.cs b/src/Tests/Nest.Tests.Unit/Core/Map/Structs/EnumMappingTests.cs new file mode 100644 index 00000000000..2ba3e8ca6ce --- /dev/null +++ b/src/Tests/Nest.Tests.Unit/Core/Map/Structs/EnumMappingTests.cs @@ -0,0 +1,62 @@ +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using FluentAssertions; + +namespace Nest.Tests.Unit.Core.Map.Structs +{ + [TestFixture] + public class StructMappingTests : BaseJsonTests + { + private class MyClass + { + public MyStruct Struct { get; set; } + } + + private class MyClass2 + { + [ElasticProperty(Analyzer = "default")] + public MyStruct StructProperty { get; set; } + } + + private struct MyStruct + { + public string Object { get; set; } + } + + [Test] + public void StructWithNoAttributeSetIsIgnored() + { + //unknow value types are not handled by default by MapFromAttributes() + var result = this._client.Map(m => m.MapFromAttributes()); + this.JsonEquals(result.ConnectionStatus.Request, MethodBase.GetCurrentMethod()); + } + + [Test] + public void StructWithAttributeButNoTypeInformationThrows() + { + //unknown value types with missing FieldType information in the attribute should throw an exception + + //example + + //Nest.DslException : Property Struct on type MyClass2 + //has an ElasticProperty attribute but its FieldType (Type = ) can not be inferred + //and is not set explicitly while calling MapFromAttributes + + var e = Assert.Throws(() => + { + var result = this._client.Map(m => m.MapFromAttributes()); + this.JsonEquals(result.ConnectionStatus.Request, MethodBase.GetCurrentMethod()); + }); + + e.Message.Should().EndWith("while calling MapFromAttributes"); + e.Message.Should().Contain("StructProperty"); + } + + } + +} diff --git a/src/Tests/Nest.Tests.Unit/Core/Map/Structs/StructWithAttributeButNoTypeInformationThrows.json b/src/Tests/Nest.Tests.Unit/Core/Map/Structs/StructWithAttributeButNoTypeInformationThrows.json new file mode 100644 index 00000000000..5f7546d64d5 --- /dev/null +++ b/src/Tests/Nest.Tests.Unit/Core/Map/Structs/StructWithAttributeButNoTypeInformationThrows.json @@ -0,0 +1,6 @@ +{ + "myclass2": { + "properties": { + } + } +} \ No newline at end of file diff --git a/src/Tests/Nest.Tests.Unit/Core/Map/Structs/StructWithNoAttributeSetIsIgnored.json b/src/Tests/Nest.Tests.Unit/Core/Map/Structs/StructWithNoAttributeSetIsIgnored.json new file mode 100644 index 00000000000..f415f4b0271 --- /dev/null +++ b/src/Tests/Nest.Tests.Unit/Core/Map/Structs/StructWithNoAttributeSetIsIgnored.json @@ -0,0 +1,6 @@ +{ + "myclass": { + "properties": { + } + } +} \ No newline at end of file diff --git a/src/Tests/Nest.Tests.Unit/Nest.Tests.Unit.csproj b/src/Tests/Nest.Tests.Unit/Nest.Tests.Unit.csproj index dd688e7fe64..70817dffdbb 100644 --- a/src/Tests/Nest.Tests.Unit/Nest.Tests.Unit.csproj +++ b/src/Tests/Nest.Tests.Unit/Nest.Tests.Unit.csproj @@ -107,6 +107,7 @@ + @@ -176,6 +177,12 @@ Always + + Always + + + Always + Always @@ -392,7 +399,7 @@ - + @@ -819,6 +826,9 @@ Always + + Always + Always diff --git a/src/Tests/Nest.Tests.Unit/Reproduce/Reproduce991Tests.cs b/src/Tests/Nest.Tests.Unit/Reproduce/Reproduce901Tests.cs similarity index 92% rename from src/Tests/Nest.Tests.Unit/Reproduce/Reproduce991Tests.cs rename to src/Tests/Nest.Tests.Unit/Reproduce/Reproduce901Tests.cs index e47e0c67ece..803d06d6e4c 100644 --- a/src/Tests/Nest.Tests.Unit/Reproduce/Reproduce991Tests.cs +++ b/src/Tests/Nest.Tests.Unit/Reproduce/Reproduce901Tests.cs @@ -12,7 +12,7 @@ namespace Nest.Tests.Unit.Reproduce /// tests to reproduce reported errors /// [TestFixture] - public class Reproduce991Tests : BaseJsonTests + public class Reproduce901Tests : BaseJsonTests { private class MyClass { @@ -32,5 +32,6 @@ public void EnumQueryDefaultsToInt() .Query(q => q.Term(p => p.MyEnum, MyEnum.Value2)); this.JsonEquals(query, MethodBase.GetCurrentMethod()); } + } }