Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add per-field metadata #4376

Merged
merged 2 commits into from
Feb 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ public abstract class ElasticsearchPropertyAttributeBase : Attribute, IProperty,

IDictionary<string, object> IProperty.LocalMetadata { get; set; }

IDictionary<string, string> IProperty.Meta { get; set; }

PropertyName IProperty.Name { get; set; }
private IProperty Self => this;
string IProperty.Type { get; set; }
Expand Down
17 changes: 16 additions & 1 deletion src/Nest/Mapping/Types/PropertyBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,18 @@ public interface IProperty : IFieldMapping
[IgnoreDataMember]
IDictionary<string, object> LocalMetadata { get; set; }

/// <summary>
/// Metadata attached to the field. This metadata is stored in but opaque to Elasticsearch. It is
/// only useful for multiple applications that work on the same indices to share
/// meta information about fields such as units.
///<para></para>
/// Field metadata enforces at most 5 entries, that keys have a length that
/// is less than or equal to 20, and that values are strings whose length is less
/// than or equal to 50.
/// </summary>
[DataMember(Name = "meta")]
IDictionary<string, string> Meta { get; set; }

/// <summary>
/// The name of the property
/// </summary>
Expand Down Expand Up @@ -53,11 +65,14 @@ public abstract class PropertyBase : IProperty, IPropertyWithClrOrigin
/// <inheritdoc />
public IDictionary<string, object> LocalMetadata { get; set; }

/// <inheritdoc />
public IDictionary<string, string> Meta { get; set; }

/// <inheritdoc />
public PropertyName Name { get; set; }

protected string DebugDisplay => $"Type: {((IProperty)this).Type ?? "<empty>"}, Name: {Name.DebugDisplay} ";

public override string ToString() => DebugDisplay;

/// <summary>
Expand Down
5 changes: 5 additions & 0 deletions src/Nest/Mapping/Types/PropertyDescriptorBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ protected string TypeOverride

IDictionary<string, object> IProperty.LocalMetadata { get; set; }
PropertyName IProperty.Name { get; set; }
IDictionary<string, string> IProperty.Meta { get; set; }

string IProperty.Type
{
Expand All @@ -41,5 +42,9 @@ string IProperty.Type
/// <inheritdoc cref="IProperty.LocalMetadata" />
public TDescriptor LocalMetadata(Func<FluentDictionary<string, object>, FluentDictionary<string, object>> selector) =>
Assign(selector, (a, v) => a.LocalMetadata = v?.Invoke(new FluentDictionary<string, object>()));

/// <inheritdoc cref="IProperty.Meta" />
public TDescriptor Meta(Func<FluentDictionary<string, string>, FluentDictionary<string, string>> selector) =>
Assign(selector, (a, v) => a.Meta = v?.Invoke(new FluentDictionary<string, string>()));
}
}
1 change: 1 addition & 0 deletions src/Nest/Mapping/Types/PropertyFormatter.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using Elasticsearch.Net.Utf8Json;
using Elasticsearch.Net.Utf8Json.Internal;
using Elasticsearch.Net.Utf8Json.Resolvers;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,5 +88,8 @@ public class FieldCapabilities

[DataMember(Name = "searchable")]
public bool Searchable { get; internal set; }

[DataMember(Name = "meta")]
public IReadOnlyDictionary<string, string[]> Meta { get; internal set; } = EmptyReadOnly<string, string[]>.Dictionary;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public class ExtendingNestTypes
public class MyPluginProperty : IProperty
{
IDictionary<string, object> IProperty.LocalMetadata { get; set; }
IDictionary<string, string> IProperty.Meta { get; set; }
public string Type { get; set; } = "my_plugin_property";
public PropertyName Name { get; set; }

Expand Down
11 changes: 6 additions & 5 deletions tests/Tests/Mapping/LocalMetadata/LocalMetadataVisitorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
using Nest;
using Tests.Mapping.Types.Core.Text;

namespace Tests.Mapping.LocalMetadata {
namespace Tests.Mapping.LocalMetadata
{
public class LocalMetadataVisitorTests
{
[U]
Expand All @@ -17,7 +18,7 @@ public void CanAssignAndAccessLocalMetadataInitializer()
.AddTestLocalMetadata()
)) as ITypeMapping;

var visitor = new LocalMatadataVisitor();
var visitor = new LocalMetadataVisitor();
var walker = new MappingWalker(visitor);
walker.Accept(descriptor.Properties);

Expand All @@ -36,7 +37,7 @@ public void CanAssignAndAccessLocalMetadataFluent()
)
)) as ITypeMapping;

var visitor = new LocalMatadataVisitor();
var visitor = new LocalMetadataVisitor();
var walker = new MappingWalker(visitor);
walker.Accept(descriptor.Properties);

Expand All @@ -63,7 +64,7 @@ public static TDescriptor AddTestLocalMetadata<TDescriptor>(this TDescriptor des
}
}

public class LocalMatadataVisitor : NoopMappingVisitor
public class LocalMetadataVisitor : NoopMappingVisitor
{
public int MetadataCount { get; set; }

Expand All @@ -77,4 +78,4 @@ public override void Visit(ITextProperty property)
property.LocalMetadata.Should().Contain("Test", "TestValue");
}
}
}
}
62 changes: 62 additions & 0 deletions tests/Tests/Mapping/Meta/MetaMappingApiTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using Elastic.Xunit.XunitPlumbing;
using FluentAssertions;
using Nest;
using Tests.ClientConcepts.HighLevel.CovariantHits;
using Tests.Core.Extensions;
using Tests.Core.ManagedElasticsearch.Clusters;
using Tests.Domain;
using Tests.Framework.EndpointTests.TestState;
using Tests.Mapping.Types;

namespace Tests.Mapping.Meta
{
[SkipVersion("<7.6.0", "Meta added in Elasticsearch 7.6.0")]
public class MetaMappingApiTests
: PropertyTestsBase
{
public MetaMappingApiTests(WritableCluster cluster, EndpointUsage usage) : base(cluster, usage) { }

protected override Func<PropertiesDescriptor<Project>, IPromise<IProperties>> FluentProperties => p => p
.Number(n => n
.Name(nn => nn.Rank)
.Type(NumberType.Integer)
.Meta(m => m
.Add("unit", "popularity")
)
);
protected override IProperties InitializerProperties => new Properties<Project>
{
{ n => n.Rank, new NumberProperty(NumberType.Integer)
{
Meta = new Dictionary<string, string>
{
{ "unit", "popularity" }
}
}
}
};

protected override void ExpectResponse(PutMappingResponse response)
{
base.ExpectResponse(response);

// check the meta shows up in get mapping API
var getMappingResponse = Client.Indices.GetMapping<Project>(m => m.Index(CallIsolatedValue));
getMappingResponse.IsValid.Should().BeTrue();
var mappingMeta = getMappingResponse.Indices[CallIsolatedValue].Mappings.Properties["rank"].Meta;
mappingMeta.Should().NotBeNull().And.ContainKey("unit");
mappingMeta["unit"].Should().Be("popularity");

// check the meta shows up in field capabilities API
var fieldCapsResponse = Client.FieldCapabilities(CallIsolatedValue, f => f
.Fields<Project>(ff => ff.Rank)
);
fieldCapsResponse.IsValid.Should().BeTrue();
var meta = fieldCapsResponse.Fields["rank"].Integer.Meta;
meta.Should().NotBeNull().And.ContainKey("unit");
meta["unit"].Should().BeEquivalentTo("popularity");
}
}
}
25 changes: 0 additions & 25 deletions tests/Tests/Mapping/Metafields/MetafieldsMappingApiTestsBase.cs

This file was deleted.