Skip to content

Commit

Permalink
Add support for wildcard property (#4890) (#4900)
Browse files Browse the repository at this point in the history
Relates: elastic/elasticsearch#49993

Co-authored-by: Russ Cam <russ.cam@elastic.co>
  • Loading branch information
github-actions[bot] and russcam committed Jul 31, 2020
1 parent 7c11fa5 commit 20e4875
Show file tree
Hide file tree
Showing 8 changed files with 188 additions and 1 deletion.
4 changes: 4 additions & 0 deletions src/Nest/Mapping/DynamicTemplate/SingleMapping.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,10 @@ public IProperty Object<TChild>(Func<ObjectTypeDescriptor<T, TChild>, IObjectPro
public IProperty ConstantKeyword(Func<ConstantKeywordPropertyDescriptor<T>, IConstantKeywordProperty> selector) =>
selector?.Invoke(new ConstantKeywordPropertyDescriptor<T>());

/// <inheritdoc />
public IProperty Wildcard(Func<WildcardPropertyDescriptor<T>, IWildcardProperty> selector) =>
selector?.Invoke(new WildcardPropertyDescriptor<T>());

#pragma warning disable CS3001 // Argument type is not CLS-compliant
public IProperty Scalar(Expression<Func<T, int>> field, Func<NumberPropertyDescriptor<T>, INumberProperty> selector = null) =>
selector.InvokeOrDefault(new NumberPropertyDescriptor<T>().Name(field).Type(NumberType.Integer));
Expand Down
5 changes: 4 additions & 1 deletion src/Nest/Mapping/Types/FieldType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,9 @@ public enum FieldType
Histogram,

[EnumMember(Value = "constant_keyword")]
ConstantKeyword
ConstantKeyword,

[EnumMember(Value = "wildcard")]
Wildcard,
}
}
7 changes: 7 additions & 0 deletions src/Nest/Mapping/Types/Properties.cs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,9 @@ TReturnType Nested<TChild>(Func<NestedPropertyDescriptor<T, TChild>, INestedProp

/// <inheritdoc cref="IConstantKeywordProperty"/>
TReturnType ConstantKeyword(Func<ConstantKeywordPropertyDescriptor<T>, IConstantKeywordProperty> selector);

/// <inheritdoc cref="IWildcardProperty"/>
TReturnType Wildcard(Func<WildcardPropertyDescriptor<T>, IWildcardProperty> selector);
}

public partial class PropertiesDescriptor<T> where T : class
Expand Down Expand Up @@ -229,6 +232,10 @@ public PropertiesDescriptor<T> Object<TChild>(Func<ObjectTypeDescriptor<T, TChil
public PropertiesDescriptor<T> ConstantKeyword(Func<ConstantKeywordPropertyDescriptor<T>, IConstantKeywordProperty> selector) =>
SetProperty(selector);

/// <inheritdoc cref="IWildcardProperty"/>
public PropertiesDescriptor<T> Wildcard(Func<WildcardPropertyDescriptor<T>, IWildcardProperty> selector) =>
SetProperty(selector);

public PropertiesDescriptor<T> Custom(IProperty customType) => SetProperty(customType);

private PropertiesDescriptor<T> SetProperty<TDescriptor, TInterface>(Func<TDescriptor, TInterface> selector)
Expand Down
4 changes: 4 additions & 0 deletions src/Nest/Mapping/Types/PropertyFormatter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ public IProperty Deserialize(ref JsonReader reader, IJsonFormatterResolver forma
case FieldType.Flattened: return Deserialize<FlattenedProperty>(ref segmentReader, formatterResolver);
case FieldType.Histogram: return Deserialize<HistogramProperty>(ref segmentReader, formatterResolver);
case FieldType.ConstantKeyword: return Deserialize<ConstantKeywordProperty>(ref segmentReader, formatterResolver);
case FieldType.Wildcard: return Deserialize<WildcardProperty>(ref segmentReader, formatterResolver);
case FieldType.None:
// no "type" field in the property mapping, or FieldType enum could not be parsed from typeString
return Deserialize<ObjectProperty>(ref segmentReader, formatterResolver);
Expand Down Expand Up @@ -209,6 +210,9 @@ public void Serialize(ref JsonWriter writer, IProperty value, IJsonFormatterReso
case IConstantKeywordProperty constantKeywordProperty:
Serialize(ref writer, constantKeywordProperty, formatterResolver);
break;
case IWildcardProperty wildcardProperty:
Serialize(ref writer, wildcardProperty, formatterResolver);
break;
case IGenericProperty genericProperty:
Serialize(ref writer, genericProperty, formatterResolver);
break;
Expand Down
26 changes: 26 additions & 0 deletions src/Nest/Mapping/Types/Specialized/Wildcard/WildcardAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information

namespace Nest
{
/// <inheritdoc cref="IWildcardProperty"/>
public class WildcardAttribute : ElasticsearchPropertyAttributeBase, IWildcardProperty
{
public WildcardAttribute() : base(FieldType.Wildcard) { }

int? IWildcardProperty.IgnoreAbove { get; set; }

private IWildcardProperty Self => this;

/// <inheritdoc cref="IWildcardProperty.IgnoreAbove" />
public int IgnoreAbove
{
get => Self.IgnoreAbove.GetValueOrDefault(2147483647);
set => Self.IgnoreAbove = value;
}

/// <inheritdoc cref="IWildcardProperty.NullValue" />
public string NullValue { get; set; }
}
}
62 changes: 62 additions & 0 deletions src/Nest/Mapping/Types/Specialized/Wildcard/WildcardProperty.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information

using System.Diagnostics;
using System.Runtime.Serialization;
using Elasticsearch.Net.Utf8Json;

namespace Nest
{
/// <summary>
/// A wildcard field stores values optimised for wildcard grep-like queries.
/// <para />
/// Available in Elasticsearch 7.9.0+ with at least a basic license level
/// </summary>
[InterfaceDataContract]
public interface IWildcardProperty : IProperty
{
/// <summary>
/// Do not index any string longer than this value. Defaults to 2147483647 so that all values would be accepted.
/// </summary>
[DataMember(Name = "ignore_above")]
int? IgnoreAbove { get; set; }

/// <summary>
/// Accepts a string value which is substituted for any explicit null values. Defaults to null, which means the field is treated as missing.
/// </summary>
[DataMember(Name ="null_value")]
string NullValue { get; set; }
}

/// <inheritdoc cref="IWildcardProperty" />
[DebuggerDisplay("{DebugDisplay}")]
public class WildcardProperty : PropertyBase, IWildcardProperty
{
public WildcardProperty() : base(FieldType.Wildcard) { }

/// <inheritdoc cref="IWildcardProperty.IgnoreAbove" />
public int? IgnoreAbove { get; set; }

/// <inheritdoc cref="IWildcardProperty.NullValue" />
public string NullValue { get; set; }
}

/// <inheritdoc cref="IWildcardProperty" />
[DebuggerDisplay("{DebugDisplay}")]
public class WildcardPropertyDescriptor<T>
: PropertyDescriptorBase<WildcardPropertyDescriptor<T>, IWildcardProperty, T>, IWildcardProperty
where T : class
{
public WildcardPropertyDescriptor() : base(FieldType.Wildcard) { }

int? IWildcardProperty.IgnoreAbove { get; set; }
string IWildcardProperty.NullValue { get; set; }

/// <inheritdoc cref="IWildcardProperty.IgnoreAbove" />
public WildcardPropertyDescriptor<T> IgnoreAbove(int? ignoreAbove) => Assign(ignoreAbove, (a, v) => a.IgnoreAbove = v);

/// <inheritdoc cref="IWildcardProperty.NullValue" />
public WildcardPropertyDescriptor<T> NullValue(string nullValue) => Assign(nullValue, (a, v) => a.NullValue = v);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information

using Elastic.Elasticsearch.Xunit.XunitPlumbing;
using Nest;

namespace Tests.Mapping.Types.Specialized.Wildcard
{
public class WildcardTest
{
[Wildcard(IgnoreAbove = 512, NullValue = "foo")]
public string Full { get; set; }

[Wildcard]
public string Simple { get; set; }
}

[SkipVersion("<7.9.0", "introduced in 7.9.0")]
public class WildcardAttributeTests : AttributeTestsBase<WildcardTest>
{
protected override object ExpectJson => new
{
properties = new
{
full = new
{
type = "wildcard",
ignore_above = 512,
null_value = "foo"
},
simple = new
{
type = "wildcard"
}
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information

using System;
using Elastic.Elasticsearch.Xunit.XunitPlumbing;
using Nest;
using Tests.Core.ManagedElasticsearch.Clusters;
using Tests.Domain;
using Tests.Framework.EndpointTests.TestState;

namespace Tests.Mapping.Types.Specialized.Wildcard
{
[SkipVersion("<7.9.0", "introduced in 7.9.0")]
public class WildcardPropertyTests : PropertyTestsBase
{
public WildcardPropertyTests(WritableCluster cluster, EndpointUsage usage) : base(cluster, usage) { }

protected override object ExpectJson => new
{
properties = new
{
description = new
{
type = "wildcard"
}
}
};

protected override Func<PropertiesDescriptor<Project>, IPromise<IProperties>> FluentProperties => f => f
.Wildcard(s => s
.Name(n => n.Description)
);

protected override IProperties InitializerProperties => new Properties
{
{
"description", new WildcardProperty()
}
};
}
}

0 comments on commit 20e4875

Please sign in to comment.