Skip to content

Commit

Permalink
Implement ConstantKeyword property
Browse files Browse the repository at this point in the history
Relates: elastic/elasticsearch#49713

This commit adds the ConstantKeyword property to the client.
Value is exposed as type Object as it can be a string or numeric
value.
  • Loading branch information
russcam committed Apr 15, 2020
1 parent 33826ed commit cd63ece
Show file tree
Hide file tree
Showing 16 changed files with 196 additions and 2 deletions.
4 changes: 4 additions & 0 deletions src/Nest/Mapping/DynamicTemplate/SingleMapping.cs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,10 @@ public IProperty Generic(Func<GenericPropertyDescriptor<T>, IGenericProperty> se
public IProperty SearchAsYouType(Func<SearchAsYouTypePropertyDescriptor<T>, ISearchAsYouTypeProperty> selector) =>
selector?.Invoke(new SearchAsYouTypePropertyDescriptor<T>());

/// <inheritdoc />
public IProperty ConstantKeyword(Func<ConstantKeywordPropertyDescriptor<T>, IConstantKeywordProperty> selector) =>
selector?.Invoke(new ConstantKeywordPropertyDescriptor<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 @@ -141,6 +141,9 @@ public enum FieldType
Shape,

[EnumMember(Value = "histogram")]
Histogram
Histogram,

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

/// <inheritdoc cref="ISearchAsYouTypeProperty"/>
TReturnType SearchAsYouType(Func<SearchAsYouTypePropertyDescriptor<T>, ISearchAsYouTypeProperty> selector);

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

public partial class PropertiesDescriptor<T> where T : class
Expand Down Expand Up @@ -218,6 +221,10 @@ public PropertiesDescriptor<T> Object<TChild>(Func<ObjectTypeDescriptor<T, TChil
/// <inheritdoc cref="IHistogramProperty"/>
public PropertiesDescriptor<T> Histogram(Func<HistogramPropertyDescriptor<T>, IHistogramProperty> selector) => SetProperty(selector);

/// <inheritdoc cref="IConstantKeywordProperty"/>
public PropertiesDescriptor<T> ConstantKeyword(Func<ConstantKeywordPropertyDescriptor<T>, IConstantKeywordProperty> 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 @@ -95,6 +95,7 @@ public IProperty Deserialize(ref JsonReader reader, IJsonFormatterResolver forma
case FieldType.RankFeatures: return Deserialize<RankFeaturesProperty>(ref segmentReader, formatterResolver);
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.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 @@ -203,6 +204,9 @@ public void Serialize(ref JsonWriter writer, IProperty value, IJsonFormatterReso
case IHistogramProperty histogramProperty:
Serialize(ref writer, histogramProperty, formatterResolver);
break;
case IConstantKeywordProperty constantKeywordProperty:
Serialize(ref writer, constantKeywordProperty, formatterResolver);
break;
case IGenericProperty genericProperty:
Serialize(ref writer, genericProperty, formatterResolver);
break;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace Nest
{
/// <inheritdoc cref="IConstantKeywordProperty"/>
public class ConstantKeywordAttribute : ElasticsearchPropertyAttributeBase, IConstantKeywordProperty
{
public ConstantKeywordAttribute() : base(FieldType.ConstantKeyword) { }

/// <inheritdoc />
public object Value { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System.Diagnostics;
using System.Runtime.Serialization;
using Elasticsearch.Net.Utf8Json;

namespace Nest
{
/// <summary>
/// Constant keyword is a specialization of the keyword field for the case that all documents in the index have the same value.
/// <para />
/// Available in Elasticsearch 7.7.0+ with at least a basic license level
/// </summary>
[InterfaceDataContract]
public interface IConstantKeywordProperty : IProperty
{
/// <summary>
/// The value to associate with all documents in the index.
/// If this parameter is not provided, it is set based on the first document that gets indexed.
/// <para />
/// Value must be a string or a numeric value
/// </summary>
[DataMember(Name ="value")]
object Value { get; set; }
}

/// <inheritdoc cref="IConstantKeywordProperty" />
[DebuggerDisplay("{DebugDisplay}")]
public class ConstantKeywordProperty : PropertyBase, IConstantKeywordProperty
{
public ConstantKeywordProperty() : base(FieldType.ConstantKeyword) { }

/// <inheritdoc cref="IConstantKeywordProperty.Value" />
public object Value { get; set; }
}

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

object IConstantKeywordProperty.Value { get; set; }

/// <inheritdoc cref="IConstantKeywordProperty.Value" />
public ConstantKeywordPropertyDescriptor<T> Value(object value) => Assign(value, (a, v) => a.Value = v);
}
}
4 changes: 4 additions & 0 deletions src/Nest/Mapping/Visitor/IMappingVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ public interface IMappingVisitor
void Visit(IFlattenedProperty property);

void Visit(IHistogramProperty property);

void Visit(IConstantKeywordProperty property);
}

public class NoopMappingVisitor : IMappingVisitor
Expand Down Expand Up @@ -128,5 +130,7 @@ public virtual void Visit(ISearchAsYouTypeProperty property) { }
public virtual void Visit(IFlattenedProperty property) { }

public virtual void Visit(IHistogramProperty property) { }

public virtual void Visit(IConstantKeywordProperty property) { }
}
}
1 change: 1 addition & 0 deletions src/Nest/Mapping/Visitor/IPropertyVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ public interface IPropertyVisitor
void Visit(IFlattenedProperty type, PropertyInfo propertyInfo, ElasticsearchPropertyAttributeBase attribute);

void Visit(IHistogramProperty type, PropertyInfo propertyInfo, ElasticsearchPropertyAttributeBase attribute);
void Visit(IConstantKeywordProperty type, PropertyInfo propertyInfo, ElasticsearchPropertyAttributeBase attribute);

IProperty Visit(PropertyInfo propertyInfo, ElasticsearchPropertyAttributeBase attribute);

Expand Down
6 changes: 6 additions & 0 deletions src/Nest/Mapping/Visitor/MappingWalker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,12 @@ public void Accept(IProperties properties)
_visitor.Visit(t);
});
break;
case FieldType.ConstantKeyword:
Visit<IConstantKeywordProperty>(field, t =>
{
_visitor.Visit(t);
});
break;
case FieldType.None:
continue;
}
Expand Down
4 changes: 4 additions & 0 deletions src/Nest/Mapping/Visitor/NoopPropertyVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ public virtual void Visit(IKeywordProperty type, PropertyInfo propertyInfo, Elas
public virtual void Visit(IFlattenedProperty type, PropertyInfo propertyInfo, ElasticsearchPropertyAttributeBase attribute) { }

public virtual void Visit(IHistogramProperty type, PropertyInfo propertyInfo, ElasticsearchPropertyAttributeBase attribute) { }
public virtual void Visit(IConstantKeywordProperty type, PropertyInfo propertyInfo, ElasticsearchPropertyAttributeBase attribute) { }

public virtual IProperty Visit(PropertyInfo propertyInfo, ElasticsearchPropertyAttributeBase attribute) => null;

Expand Down Expand Up @@ -149,6 +150,9 @@ public void Visit(IProperty type, PropertyInfo propertyInfo, ElasticsearchProper
case IHistogramProperty histogram:
Visit(histogram, propertyInfo, attribute);
break;
case IConstantKeywordProperty constantKeyword:
Visit(constantKeyword, propertyInfo, attribute);
break;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,15 @@ public static PropertiesDescriptor<TProject> ProjectProperties<TProject>(Propert
.Enabled(false)
);

if (TestConfiguration.Instance.InRange(">=7.7.0"))
props.ConstantKeyword(f => f
.Name(p => p.VersionControl)
);
else
props.Keyword(f => f
.Name(p => p.VersionControl)
);

return props;
}

Expand Down
7 changes: 6 additions & 1 deletion tests/Tests.Domain/Project.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ public class Project
{
public static string TypeName = "project";

public static string VersionControlConstant = "git";

public IEnumerable<string> Branches { get; set; }
public IList<Tag> CuratedTags { get; set; }
public string DateString { get; set; }
Expand Down Expand Up @@ -66,6 +68,8 @@ public class Project
//the first applies when using internal source serializer the latter when using JsonNetSourceSerializer
public Visibility Visibility { get; set; }

public string VersionControl { get; set; }

// @formatter:off — enable formatter after this line
public static Faker<Project> Generator { get; } =
new Faker<Project>()
Expand Down Expand Up @@ -112,7 +116,8 @@ public class Project
Closed = closedDate.ToUnixTime()
}
};
});
})
.RuleFor(p => p.VersionControl, VersionControlConstant);

public static IList<Project> Projects { get; } = Generator.Clone().Generate(100);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,8 @@ internal class TestVisitor : IMappingVisitor

public void Visit(IHistogramProperty property) => Increment("histogram");

public void Visit(IConstantKeywordProperty property) => Increment("constant_keyword");

private void Increment(string key)
{
if (!Counts.ContainsKey(key)) Counts.Add(key, 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,10 @@ public PutMappingApiTests(WritableCluster cluster, EndpointUsage usage) : base(c
{
type = "flattened",
depth_limit = 4
},
versionControl = new
{
type = "keyword"
}
}
};
Expand Down Expand Up @@ -196,6 +200,9 @@ public PutMappingApiTests(WritableCluster cluster, EndpointUsage usage) : base(c
.Name(p => p.Labels)
.DepthLimit(4)
)
.Keyword(k => k
.Name(n => n.VersionControl)
)
);

protected override HttpMethod HttpMethod => HttpMethod.PUT;
Expand Down Expand Up @@ -314,6 +321,7 @@ public PutMappingApiTests(WritableCluster cluster, EndpointUsage usage) : base(c
{
DepthLimit = 4
} },
{ p => p.VersionControl, new KeywordProperty() }
}
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using Elastic.Xunit.XunitPlumbing;
using Nest;

namespace Tests.Mapping.Types.Specialized.ConstantKeyword
{
public class ConstantKeywordTest
{
[ConstantKeyword(Value = "constant_string")]
public string ConstantString { get; set; }

[ConstantKeyword(Value = 42)]
public int ConstantInt { get; set; }
}

[SkipVersion("<7.7.0", "introduced in 7.7.0")]
public class ConstantKeywordAttributeTests : AttributeTestsBase<ConstantKeywordTest>
{
protected override object ExpectJson => new
{
properties = new
{
constantString = new
{
type = "constant_keyword",
value = "constant_string"
},
constantInt = new
{
type = "constant_keyword",
value = 42
}
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using System;
using Elastic.Xunit.XunitPlumbing;
using Nest;
using Tests.Core.ManagedElasticsearch.Clusters;
using Tests.Domain;
using Tests.Framework.EndpointTests.TestState;

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

protected override object ExpectJson => new
{
properties = new
{
versionControl = new
{
type = "constant_keyword",
value = Project.VersionControlConstant,
}
}
};

protected override Func<PropertiesDescriptor<Project>, IPromise<IProperties>> FluentProperties => f => f
.ConstantKeyword(s => s
.Name(n => n.VersionControl)
.Value(Project.VersionControlConstant)
);

protected override IProperties InitializerProperties => new Properties
{
{
"versionControl", new ConstantKeywordProperty
{
Value = Project.VersionControlConstant
}
}
};
}
}

0 comments on commit cd63ece

Please sign in to comment.