Skip to content

Commit d4b0321

Browse files
Mpdreamzrusscam
authored andcommitted
Feature/custom implementation of interfaces (#3060)
* started on documentation on how to extend or implement custom NEST types for serialization purposes * Renamed RenameAttribute to PropertyNameAttribute, added tests that custom IProperty implementations serialize to fix #3049 * updated tests and documentation
1 parent 7d99e0e commit d4b0321

20 files changed

+288
-81
lines changed

docs/client-concepts/certificates/working-with-certificates.asciidoc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,7 @@ If your client application has access to the public CA certificate locally, Elas
8181
that can assert that a certificate the server presents is one that came from the local CA.
8282

8383
If you use X-Pack's {ref_current}/certutil.html[+certutil+ tool] to generate SSL certificates, the generated node certificate
84-
does not include the CA in the certificate chain, in order to cut down on SSL handshake size. In those case you can use
85-
`CertificateValidations.AuthorityIsRoot` and pass it your local copy of the CA public key to assert that
84+
does not include the CA in the certificate chain, in order to cut down on SSL handshake size. In those case you can use`CertificateValidations.AuthorityIsRoot` and pass it your local copy of the CA public key to assert that
8685
the certificate the server presented was generated using it
8786

8887
[source,csharp]
@@ -151,8 +150,11 @@ public class PkiCluster : CertgenCaCluster
151150
}
152151
----
153152
<1> Set the client certificate on `ConnectionSettings`
153+
154154
<2> The path to the `.cer` file
155+
155156
<3> The path to the `.key` file
157+
156158
<4> The password for the private key
157159

158160
Or per request on `RequestConfiguration` which will take precedence over the ones defined on `ConnectionConfiguration`

docs/client-concepts/high-level/inference/field-inference.asciidoc

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ the `JsonPropertyAttribute` into account
346346
----
347347
public class SerializerSpecific
348348
{
349-
[Rename("nameInJson"), JsonProperty("nameInJson")]
349+
[PropertyName("nameInJson"), JsonProperty("nameInJson")]
350350
public string Name { get; set; }
351351
}
352352
@@ -361,7 +361,7 @@ If both a NEST property attribute and a serializer specific attribute are presen
361361
public class Both
362362
{
363363
[Text(Name = "naam")]
364-
[Rename("nameInJson"), JsonProperty("nameInJson")]
364+
[PropertyName("nameInJson"), JsonProperty("nameInJson")]
365365
public string Name { get; set; }
366366
}
367367
@@ -455,31 +455,31 @@ The following example class will demonstrate this precedence
455455
class Precedence
456456
{
457457
[Text(Name = "renamedIgnoresNest")]
458-
[Rename("renamedIgnoresJsonProperty"),JsonProperty("renamedIgnoresJsonProperty")]
458+
[PropertyName("renamedIgnoresJsonProperty"),JsonProperty("renamedIgnoresJsonProperty")]
459459
public string RenamedOnConnectionSettings { get; set; } <1>
460460
461461
[Text(Name = "nestAtt")]
462-
[Rename("jsonProp"),JsonProperty("jsonProp")]
462+
[PropertyName("nestProp"),JsonProperty("jsonProp")]
463463
public string NestAttribute { get; set; } <2>
464464
465-
[Rename("jsonProp"),JsonProperty("jsonProp")]
466-
public string JsonProperty { get; set; } <3>
465+
[PropertyName("nestProp"),JsonProperty("jsonProp")]
466+
public string NestProperty { get; set; } <3>
467467
468-
[Rename("dontaskme"),JsonProperty("dontaskme")]
469-
public string AskSerializer { get; set; } <4>
468+
[JsonProperty("jsonProp")]
469+
public string JsonProperty { get; set; } <4>
470470
471-
public string DefaultFieldNameInferrer { get; set; } <5>
471+
[PropertyName("dontaskme"),JsonProperty("dontaskme")]
472+
public string AskSerializer { get; set; } <5>
473+
474+
public string DefaultFieldNameInferrer { get; set; } <6>
472475
}
473476
----
474477
<1> Even though this property has a NEST property mapping _and_ a `JsonProperty` attribute, We are going to provide a hard rename for it on ConnectionSettings later that should win.
475-
476-
<2> This property has both a NEST attribute and a `JsonProperty`, NEST should win.
477-
478-
<3> We should take the json property into account by itself
479-
480-
<4> This property we are going to special case in our custom serializer to resolve to ask
481-
482-
<5> We are going to register a DefaultFieldNameInferrer on ConnectionSettings that will uppercase all properties.
478+
<2> This property has both a NEST attribute and property and a `JsonProperty`, NEST should win.
479+
<3> This property has both a NEST property and a `JsonProperty`, NEST should win.
480+
<4> We should take the json property into account by itself
481+
<5> This property we are going to hard code in our custom serializer to resolve to ask.
482+
<6> We are going to register a DefaultFieldNameInferrer on ConnectionSettings that will uppercase all properties.
483483

484484
Here we create a custom serializer that renames any property named `AskSerializer` to `ask`
485485

@@ -511,6 +511,7 @@ var usingSettings = WithConnectionSettings(s => s
511511
512512
usingSettings.Expect("renamed").ForField(Field<Precedence>(p => p.RenamedOnConnectionSettings));
513513
usingSettings.Expect("nestAtt").ForField(Field<Precedence>(p => p.NestAttribute));
514+
usingSettings.Expect("nestProp").ForField(Field<Precedence>(p => p.NestProperty));
514515
usingSettings.Expect("jsonProp").ForField(Field<Precedence>(p => p.JsonProperty));
515516
usingSettings.Expect("ask").ForField(Field<Precedence>(p => p.AskSerializer));
516517
usingSettings.Expect("DEFAULTFIELDNAMEINFERRER").ForField(Field<Precedence>(p => p.DefaultFieldNameInferrer));
@@ -525,12 +526,14 @@ usingSettings.Expect(new []
525526
"ask",
526527
"DEFAULTFIELDNAMEINFERRER",
527528
"jsonProp",
529+
"nestProp",
528530
"nestAtt",
529531
"renamed"
530532
}).AsPropertiesOf(new Precedence
531533
{
532534
RenamedOnConnectionSettings = "renamed on connection settings",
533535
NestAttribute = "using a nest attribute",
536+
NestProperty = "using a nest property",
534537
JsonProperty = "the default serializer resolves json property attributes",
535538
AskSerializer = "serializer fiddled with this one",
536539
DefaultFieldNameInferrer = "shouting much?"

docs/client-concepts/high-level/inference/indices-paths.asciidoc

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,6 @@ singleIndexFromIndexName.Match(
8888
);
8989
----
9090
<1> `_all` will override any specific index names here
91-
9291
<2> The `Project` type has been mapped to a specific index name using <<index-name-type-mapping,`.DefaultMappingFor<Project>`>>
9392

9493
[[nest-indices]]
@@ -121,9 +120,7 @@ ISearchRequest singleTypedRequest = new SearchDescriptor<Project>().Index(single
121120
var invalidSingleString = Index("name1, name2"); <3>
122121
----
123122
<1> specifying a single index using a string
124-
125123
<2> specifying a single index using a type
126-
127124
<3> an **invalid** single index name
128125

129126
===== Multiple indices
@@ -149,9 +146,7 @@ manyStringRequest = new SearchDescriptor<Project>().Type(new[] { "name1", "name2
149146
((IUrlParameter)manyStringRequest.Type).GetString(this.Client.ConnectionSettings).Should().Be("name1,name2");
150147
----
151148
<1> specifying multiple indices using strings
152-
153149
<2> specifying multiple indices using types
154-
155150
<3> The index names here come from the Connection Settings passed to `TestClient`. See the documentation on <<index-name-inference, Index Name Inference>> for more details.
156151

157152
===== All Indices

docs/client-concepts/high-level/mapping/attribute-mapping.asciidoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public class Employee
6565
public bool IsManager { get; set; }
6666
6767
[Nested]
68-
[Rename("empl"), JsonProperty("empl")]
68+
[PropertyName("empl"), JsonProperty("empl")]
6969
public List<Employee> Employees { get; set; }
7070
}
7171
----

docs/client-concepts/high-level/mapping/fluent-mapping.asciidoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ public class EmployeeWithAttributes
231231
public bool IsManager { get; set; }
232232
233233
[Nested]
234-
[Rename("empl"), JsonProperty("empl")]
234+
[PropertyName("empl"), JsonProperty("empl")]
235235
public List<Employee> Employees { get; set; }
236236
}
237237
----

docs/client-concepts/high-level/mapping/parent-child-relationships.asciidoc

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,8 @@ var createIndexResponse = client.CreateIndex("index", c => c
9999
);
100100
----
101101
<1> recommended to make the routing field mandatory so you can not accidentally forget
102-
103102
<2> Map all of the `MyParent` properties
104-
105103
<3> Map all of the `MyChild` properties
106-
107104
<4> Additionally map the `JoinField` since it is not automatically mapped by `AutoMap()`
108105

109106
We call `AutoMap()` for both types to discover properties of both .NET types. `AutoMap()` won't automatically setup the
@@ -179,7 +176,6 @@ parentDocument = new MyParent
179176
var indexParent = client.IndexDocument<MyDocument>(parentDocument);
180177
----
181178
<1> this lets the join data type know this is a root document of type `myparent`
182-
183179
<2> this lets the join data type know this is a root document of type `myparent`
184180

185181
[source,javascript]
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
:ref_current: https://www.elastic.co/guide/en/elasticsearch/reference/6.1
2+
3+
:github: https://github.com/elastic/elasticsearch-net
4+
5+
:nuget: https://www.nuget.org/packages
6+
7+
////
8+
IMPORTANT NOTE
9+
==============
10+
This file has been generated from https://github.com/elastic/elasticsearch-net/tree/master/src/Tests/ClientConcepts/HighLevel/Serialization/ExtendingNestTypes.doc.cs.
11+
If you wish to submit a PR for any spelling mistakes, typos or grammatical errors for this file,
12+
please modify the original csharp file found at the link and submit the PR with that change. Thanks!
13+
////
14+
15+
[[extending-nest-types]]
16+
=== Extending NEST types
17+
18+
Although of course NEST should always be up to date with a 100% API coverage of the Elasticsearch API, sometimes you might want to work around a bug
19+
or maybe use types from a third party plugin that NEST does not support.
20+
21+
[source,csharp]
22+
----
23+
public class MyPluginProperty : IProperty
24+
{
25+
IDictionary<string, object> IProperty.LocalMetadata { get; set; }
26+
public string Type { get; set; } = "my_plugin_property";
27+
public PropertyName Name { get; set; }
28+
29+
public MyPluginProperty(string name, string language)
30+
{
31+
this.Name = name;
32+
this.Language = language;
33+
this.Numeric = true;
34+
}
35+
36+
[PropertyName("language")]
37+
public string Language { get; set; }
38+
39+
[PropertyName("numeric")]
40+
public bool Numeric { get; set; }
41+
}
42+
----
43+
44+
`PropertyNameAttribute` can be used to mark properties that should be serialized. Without this attribute,
45+
NEST won't pick up the property for serialization.
46+
47+
Now that we have our own `IProperty` implementation we can add it to our propertes mapping when creating an index
48+
49+
[source,csharp]
50+
----
51+
var createIndexResponse = client.CreateIndex("myindex", c => c
52+
.Mappings(ms => ms
53+
.Map<Project>(m => m
54+
.Properties(props => props
55+
.Custom(new MyPluginProperty("fieldName", "dutch"))
56+
)
57+
)
58+
)
59+
);
60+
----
61+
62+
which will serialize to the following JSON request
63+
64+
[source,javascript]
65+
----
66+
{
67+
"mappings": {
68+
"doc": {
69+
"properties": {
70+
"fieldName": {
71+
"type": "my_plugin_property",
72+
"language": "dutch",
73+
"numeric": true
74+
}
75+
}
76+
}
77+
}
78+
}
79+
----
80+
81+
Whilst NEST can serialize our `my_plugin_property`, it does not know how to deserialize it;
82+
We plan to make this more pluggable in the future
83+

docs/high-level.asciidoc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ own serializer, or by modifying how NEST's serializer behaves.
9696

9797
* <<custom-serialization,Custom Serialization>>
9898

99+
* <<extending-nest-types,Extending Nest Types>>
100+
99101
* <<modifying-default-serializer,Modifying Default Serializer>>
100102

101103
:includes-from-dirs: client-concepts/high-level/serialization
@@ -104,6 +106,8 @@ include::client-concepts/high-level/serialization/changing-serializers.asciidoc[
104106

105107
include::client-concepts/high-level/serialization/custom-serialization.asciidoc[]
106108

109+
include::client-concepts/high-level/serialization/extending-nest-types.asciidoc[]
110+
107111
include::client-concepts/high-level/serialization/modifying-default-serializer.asciidoc[]
108112

109113
[[mapping]]
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
using System;
2+
3+
namespace Nest
4+
{
5+
[AttributeUsage(AttributeTargets.Property)]
6+
public class IgnoreAttribute : Attribute { }
7+
}

src/Nest/CommonAbstractions/SerializationBehavior/Attributes/MachineLearningDateTimeConverter.cs renamed to src/Nest/CommonAbstractions/SerializationBehavior/Attributes/MachineLearningDateTimeAttribute.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@
44

55
namespace Nest
66
{
7+
/// <summary>
8+
/// Signals that this date time property is used in Machine learning API's some of which will always return the date as epoch.
9+
/// </summary>
10+
[AttributeUsage(AttributeTargets.Property)]
11+
public class MachineLearningDateTimeAttribute : Attribute { }
12+
713
internal class MachineLearningDateTimeConverter : IsoDateTimeConverter
814
{
915
private static readonly DateTimeOffset Epoch = new DateTimeOffset(1970, 1, 1, 0, 0, 0, 0, TimeSpan.Zero);

0 commit comments

Comments
 (0)