Skip to content

Commit cd63ece

Browse files
committed
Implement ConstantKeyword property
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.
1 parent 33826ed commit cd63ece

File tree

16 files changed

+196
-2
lines changed

16 files changed

+196
-2
lines changed

src/Nest/Mapping/DynamicTemplate/SingleMapping.cs

+4
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,10 @@ public IProperty Generic(Func<GenericPropertyDescriptor<T>, IGenericProperty> se
133133
public IProperty SearchAsYouType(Func<SearchAsYouTypePropertyDescriptor<T>, ISearchAsYouTypeProperty> selector) =>
134134
selector?.Invoke(new SearchAsYouTypePropertyDescriptor<T>());
135135

136+
/// <inheritdoc />
137+
public IProperty ConstantKeyword(Func<ConstantKeywordPropertyDescriptor<T>, IConstantKeywordProperty> selector) =>
138+
selector?.Invoke(new ConstantKeywordPropertyDescriptor<T>());
139+
136140
#pragma warning disable CS3001 // Argument type is not CLS-compliant
137141
public IProperty Scalar(Expression<Func<T, int>> field, Func<NumberPropertyDescriptor<T>, INumberProperty> selector = null) =>
138142
selector.InvokeOrDefault(new NumberPropertyDescriptor<T>().Name(field).Type(NumberType.Integer));

src/Nest/Mapping/Types/FieldType.cs

+4-1
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,9 @@ public enum FieldType
141141
Shape,
142142

143143
[EnumMember(Value = "histogram")]
144-
Histogram
144+
Histogram,
145+
146+
[EnumMember(Value = "constant_keyword")]
147+
ConstantKeyword
145148
}
146149
}

src/Nest/Mapping/Types/Properties.cs

+7
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,9 @@ TReturnType Nested<TChild>(Func<NestedPropertyDescriptor<T, TChild>, INestedProp
138138

139139
/// <inheritdoc cref="ISearchAsYouTypeProperty"/>
140140
TReturnType SearchAsYouType(Func<SearchAsYouTypePropertyDescriptor<T>, ISearchAsYouTypeProperty> selector);
141+
142+
/// <inheritdoc cref="IConstantKeywordProperty"/>
143+
TReturnType ConstantKeyword(Func<ConstantKeywordPropertyDescriptor<T>, IConstantKeywordProperty> selector);
141144
}
142145

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

224+
/// <inheritdoc cref="IConstantKeywordProperty"/>
225+
public PropertiesDescriptor<T> ConstantKeyword(Func<ConstantKeywordPropertyDescriptor<T>, IConstantKeywordProperty> selector) =>
226+
SetProperty(selector);
227+
221228
public PropertiesDescriptor<T> Custom(IProperty customType) => SetProperty(customType);
222229

223230
private PropertiesDescriptor<T> SetProperty<TDescriptor, TInterface>(Func<TDescriptor, TInterface> selector)

src/Nest/Mapping/Types/PropertyFormatter.cs

+4
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ public IProperty Deserialize(ref JsonReader reader, IJsonFormatterResolver forma
9595
case FieldType.RankFeatures: return Deserialize<RankFeaturesProperty>(ref segmentReader, formatterResolver);
9696
case FieldType.Flattened: return Deserialize<FlattenedProperty>(ref segmentReader, formatterResolver);
9797
case FieldType.Histogram: return Deserialize<HistogramProperty>(ref segmentReader, formatterResolver);
98+
case FieldType.ConstantKeyword: return Deserialize<ConstantKeywordProperty>(ref segmentReader, formatterResolver);
9899
case FieldType.None:
99100
// no "type" field in the property mapping, or FieldType enum could not be parsed from typeString
100101
return Deserialize<ObjectProperty>(ref segmentReader, formatterResolver);
@@ -203,6 +204,9 @@ public void Serialize(ref JsonWriter writer, IProperty value, IJsonFormatterReso
203204
case IHistogramProperty histogramProperty:
204205
Serialize(ref writer, histogramProperty, formatterResolver);
205206
break;
207+
case IConstantKeywordProperty constantKeywordProperty:
208+
Serialize(ref writer, constantKeywordProperty, formatterResolver);
209+
break;
206210
case IGenericProperty genericProperty:
207211
Serialize(ref writer, genericProperty, formatterResolver);
208212
break;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
namespace Nest
2+
{
3+
/// <inheritdoc cref="IConstantKeywordProperty"/>
4+
public class ConstantKeywordAttribute : ElasticsearchPropertyAttributeBase, IConstantKeywordProperty
5+
{
6+
public ConstantKeywordAttribute() : base(FieldType.ConstantKeyword) { }
7+
8+
/// <inheritdoc />
9+
public object Value { get; set; }
10+
}
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
using System.Diagnostics;
2+
using System.Runtime.Serialization;
3+
using Elasticsearch.Net.Utf8Json;
4+
5+
namespace Nest
6+
{
7+
/// <summary>
8+
/// Constant keyword is a specialization of the keyword field for the case that all documents in the index have the same value.
9+
/// <para />
10+
/// Available in Elasticsearch 7.7.0+ with at least a basic license level
11+
/// </summary>
12+
[InterfaceDataContract]
13+
public interface IConstantKeywordProperty : IProperty
14+
{
15+
/// <summary>
16+
/// The value to associate with all documents in the index.
17+
/// If this parameter is not provided, it is set based on the first document that gets indexed.
18+
/// <para />
19+
/// Value must be a string or a numeric value
20+
/// </summary>
21+
[DataMember(Name ="value")]
22+
object Value { get; set; }
23+
}
24+
25+
/// <inheritdoc cref="IConstantKeywordProperty" />
26+
[DebuggerDisplay("{DebugDisplay}")]
27+
public class ConstantKeywordProperty : PropertyBase, IConstantKeywordProperty
28+
{
29+
public ConstantKeywordProperty() : base(FieldType.ConstantKeyword) { }
30+
31+
/// <inheritdoc cref="IConstantKeywordProperty.Value" />
32+
public object Value { get; set; }
33+
}
34+
35+
/// <inheritdoc cref="IConstantKeywordProperty" />
36+
[DebuggerDisplay("{DebugDisplay}")]
37+
public class ConstantKeywordPropertyDescriptor<T>
38+
: PropertyDescriptorBase<ConstantKeywordPropertyDescriptor<T>, IConstantKeywordProperty, T>, IConstantKeywordProperty
39+
where T : class
40+
{
41+
public ConstantKeywordPropertyDescriptor() : base(FieldType.ConstantKeyword) { }
42+
43+
object IConstantKeywordProperty.Value { get; set; }
44+
45+
/// <inheritdoc cref="IConstantKeywordProperty.Value" />
46+
public ConstantKeywordPropertyDescriptor<T> Value(object value) => Assign(value, (a, v) => a.Value = v);
47+
}
48+
}

src/Nest/Mapping/Visitor/IMappingVisitor.cs

+4
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ public interface IMappingVisitor
6363
void Visit(IFlattenedProperty property);
6464

6565
void Visit(IHistogramProperty property);
66+
67+
void Visit(IConstantKeywordProperty property);
6668
}
6769

6870
public class NoopMappingVisitor : IMappingVisitor
@@ -128,5 +130,7 @@ public virtual void Visit(ISearchAsYouTypeProperty property) { }
128130
public virtual void Visit(IFlattenedProperty property) { }
129131

130132
public virtual void Visit(IHistogramProperty property) { }
133+
134+
public virtual void Visit(IConstantKeywordProperty property) { }
131135
}
132136
}

src/Nest/Mapping/Visitor/IPropertyVisitor.cs

+1
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ public interface IPropertyVisitor
6161
void Visit(IFlattenedProperty type, PropertyInfo propertyInfo, ElasticsearchPropertyAttributeBase attribute);
6262

6363
void Visit(IHistogramProperty type, PropertyInfo propertyInfo, ElasticsearchPropertyAttributeBase attribute);
64+
void Visit(IConstantKeywordProperty type, PropertyInfo propertyInfo, ElasticsearchPropertyAttributeBase attribute);
6465

6566
IProperty Visit(PropertyInfo propertyInfo, ElasticsearchPropertyAttributeBase attribute);
6667

src/Nest/Mapping/Visitor/MappingWalker.cs

+6
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,12 @@ public void Accept(IProperties properties)
257257
_visitor.Visit(t);
258258
});
259259
break;
260+
case FieldType.ConstantKeyword:
261+
Visit<IConstantKeywordProperty>(field, t =>
262+
{
263+
_visitor.Visit(t);
264+
});
265+
break;
260266
case FieldType.None:
261267
continue;
262268
}

src/Nest/Mapping/Visitor/NoopPropertyVisitor.cs

+4
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ public virtual void Visit(IKeywordProperty type, PropertyInfo propertyInfo, Elas
6161
public virtual void Visit(IFlattenedProperty type, PropertyInfo propertyInfo, ElasticsearchPropertyAttributeBase attribute) { }
6262

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

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

@@ -149,6 +150,9 @@ public void Visit(IProperty type, PropertyInfo propertyInfo, ElasticsearchProper
149150
case IHistogramProperty histogram:
150151
Visit(histogram, propertyInfo, attribute);
151152
break;
153+
case IConstantKeywordProperty constantKeyword:
154+
Visit(constantKeyword, propertyInfo, attribute);
155+
break;
152156
}
153157
}
154158
}

tests/Tests.Core/ManagedElasticsearch/NodeSeeders/DefaultSeeder.cs

+9
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,15 @@ public static PropertiesDescriptor<TProject> ProjectProperties<TProject>(Propert
377377
.Enabled(false)
378378
);
379379

380+
if (TestConfiguration.Instance.InRange(">=7.7.0"))
381+
props.ConstantKeyword(f => f
382+
.Name(p => p.VersionControl)
383+
);
384+
else
385+
props.Keyword(f => f
386+
.Name(p => p.VersionControl)
387+
);
388+
380389
return props;
381390
}
382391

tests/Tests.Domain/Project.cs

+6-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ public class Project
2828
{
2929
public static string TypeName = "project";
3030

31+
public static string VersionControlConstant = "git";
32+
3133
public IEnumerable<string> Branches { get; set; }
3234
public IList<Tag> CuratedTags { get; set; }
3335
public string DateString { get; set; }
@@ -66,6 +68,8 @@ public class Project
6668
//the first applies when using internal source serializer the latter when using JsonNetSourceSerializer
6769
public Visibility Visibility { get; set; }
6870

71+
public string VersionControl { get; set; }
72+
6973
// @formatter:off — enable formatter after this line
7074
public static Faker<Project> Generator { get; } =
7175
new Faker<Project>()
@@ -112,7 +116,8 @@ public class Project
112116
Closed = closedDate.ToUnixTime()
113117
}
114118
};
115-
});
119+
})
120+
.RuleFor(p => p.VersionControl, VersionControlConstant);
116121

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

tests/Tests/Indices/MappingManagement/GetMapping/GetMappingApiTest.cs

+2
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,8 @@ internal class TestVisitor : IMappingVisitor
213213

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

216+
public void Visit(IConstantKeywordProperty property) => Increment("constant_keyword");
217+
216218
private void Increment(string key)
217219
{
218220
if (!Counts.ContainsKey(key)) Counts.Add(key, 0);

tests/Tests/Indices/MappingManagement/PutMapping/PutMappingApiTest.cs

+8
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,10 @@ public PutMappingApiTests(WritableCluster cluster, EndpointUsage usage) : base(c
132132
{
133133
type = "flattened",
134134
depth_limit = 4
135+
},
136+
versionControl = new
137+
{
138+
type = "keyword"
135139
}
136140
}
137141
};
@@ -196,6 +200,9 @@ public PutMappingApiTests(WritableCluster cluster, EndpointUsage usage) : base(c
196200
.Name(p => p.Labels)
197201
.DepthLimit(4)
198202
)
203+
.Keyword(k => k
204+
.Name(n => n.VersionControl)
205+
)
199206
);
200207

201208
protected override HttpMethod HttpMethod => HttpMethod.PUT;
@@ -314,6 +321,7 @@ public PutMappingApiTests(WritableCluster cluster, EndpointUsage usage) : base(c
314321
{
315322
DepthLimit = 4
316323
} },
324+
{ p => p.VersionControl, new KeywordProperty() }
317325
}
318326
};
319327

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using Elastic.Xunit.XunitPlumbing;
2+
using Nest;
3+
4+
namespace Tests.Mapping.Types.Specialized.ConstantKeyword
5+
{
6+
public class ConstantKeywordTest
7+
{
8+
[ConstantKeyword(Value = "constant_string")]
9+
public string ConstantString { get; set; }
10+
11+
[ConstantKeyword(Value = 42)]
12+
public int ConstantInt { get; set; }
13+
}
14+
15+
[SkipVersion("<7.7.0", "introduced in 7.7.0")]
16+
public class ConstantKeywordAttributeTests : AttributeTestsBase<ConstantKeywordTest>
17+
{
18+
protected override object ExpectJson => new
19+
{
20+
properties = new
21+
{
22+
constantString = new
23+
{
24+
type = "constant_keyword",
25+
value = "constant_string"
26+
},
27+
constantInt = new
28+
{
29+
type = "constant_keyword",
30+
value = 42
31+
}
32+
}
33+
};
34+
}
35+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
using System;
2+
using Elastic.Xunit.XunitPlumbing;
3+
using Nest;
4+
using Tests.Core.ManagedElasticsearch.Clusters;
5+
using Tests.Domain;
6+
using Tests.Framework.EndpointTests.TestState;
7+
8+
namespace Tests.Mapping.Types.Specialized.ConstantKeyword
9+
{
10+
[SkipVersion("<7.7.0", "introduced in 7.7.0")]
11+
public class ConstantKeywordPropertyTests : PropertyTestsBase
12+
{
13+
public ConstantKeywordPropertyTests(WritableCluster cluster, EndpointUsage usage) : base(cluster, usage) { }
14+
15+
protected override object ExpectJson => new
16+
{
17+
properties = new
18+
{
19+
versionControl = new
20+
{
21+
type = "constant_keyword",
22+
value = Project.VersionControlConstant,
23+
}
24+
}
25+
};
26+
27+
protected override Func<PropertiesDescriptor<Project>, IPromise<IProperties>> FluentProperties => f => f
28+
.ConstantKeyword(s => s
29+
.Name(n => n.VersionControl)
30+
.Value(Project.VersionControlConstant)
31+
);
32+
33+
protected override IProperties InitializerProperties => new Properties
34+
{
35+
{
36+
"versionControl", new ConstantKeywordProperty
37+
{
38+
Value = Project.VersionControlConstant
39+
}
40+
}
41+
};
42+
}
43+
}

0 commit comments

Comments
 (0)