Skip to content

Commit 8bcfb0a

Browse files
committed
Add Attachment type
Closes #2085
1 parent b446314 commit 8bcfb0a

File tree

10 files changed

+524
-86
lines changed

10 files changed

+524
-86
lines changed

src/Nest/Mapping/AttributeBased/ElasticsearchPropertyAttributeBase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,4 @@ public static ElasticsearchPropertyAttributeBase From(MemberInfo memberInfo)
4343
return memberInfo.GetCustomAttribute<ElasticsearchPropertyAttributeBase>(true);
4444
}
4545
}
46-
}
46+
}
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using Newtonsoft.Json;
4+
5+
namespace Nest
6+
{
7+
[JsonConverter(typeof(AttachmentConverter))]
8+
public class Attachment
9+
{
10+
/// <summary>
11+
/// The author.
12+
/// </summary>
13+
[JsonProperty("author")]
14+
public string Author { get; set; }
15+
16+
/// <summary>
17+
/// The base64 encoded content. Can be explicitly set
18+
/// </summary>
19+
[JsonProperty("content")]
20+
public string Content { get; set; }
21+
22+
/// <summary>
23+
/// The length of the content before text extraction.
24+
/// </summary>
25+
[JsonProperty("content_length")]
26+
public long? ContentLength { get; set; }
27+
28+
/// <summary>
29+
/// The content type of the attachment. Can be explicitly set
30+
/// </summary>
31+
[JsonProperty("content_type")]
32+
public string ContentType { get; set; }
33+
34+
/// <summary>
35+
/// The date of the attachment.
36+
/// </summary>
37+
[JsonProperty("date")]
38+
public DateTime? Date { get; set; }
39+
40+
/// <summary>
41+
/// The keywords in the attachment.
42+
/// </summary>
43+
[JsonProperty("keywords")]
44+
public string Keywords { get; set; }
45+
46+
/// <summary>
47+
/// The language of the attachment. Can be explicitly set. This requires
48+
/// <see cref="DetectLanguage"/> to be set to <c>true</c>
49+
/// </summary>
50+
[JsonProperty("language")]
51+
public string Language { get; set; }
52+
53+
/// <summary>
54+
/// Detect the language of the attachment. Language detection is
55+
/// disabled by default.
56+
/// </summary>
57+
[JsonProperty("detect_language")]
58+
public bool? DetectLanguage { get; set; }
59+
60+
/// <summary>
61+
/// The name of the attachment. Can be explicitly set
62+
/// </summary>
63+
[JsonProperty("name")]
64+
public string Name { get; set; }
65+
66+
/// <summary>
67+
/// The title of the attachment.
68+
/// </summary>
69+
[JsonProperty("title")]
70+
public string Title { get; set; }
71+
72+
/// <summary>
73+
/// Determines how many characters are extracted when indexing the content.
74+
/// By default, 100000 characters are extracted when indexing the content.
75+
/// -1 can be set to extract all text, but note that all the text needs to be
76+
/// allowed to be represented in memory
77+
/// </summary>
78+
[JsonProperty("indexed_chars")]
79+
public long? IndexedCharacters { get; set; }
80+
81+
/// <summary>
82+
/// Whether the attachment contains explicit metadata in addition to the
83+
/// content. Used at indexing time to determine the serialized form of the
84+
/// attachment.
85+
/// </summary>
86+
[JsonIgnore]
87+
public bool ContainsMetadata => !Name.IsNullOrEmpty() ||
88+
!ContentType.IsNullOrEmpty() ||
89+
!Language.IsNullOrEmpty() ||
90+
DetectLanguage.HasValue ||
91+
IndexedCharacters.HasValue;
92+
}
93+
94+
internal class AttachmentConverter : JsonConverter
95+
{
96+
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
97+
{
98+
var attachment = (Attachment)value;
99+
if (!attachment.ContainsMetadata)
100+
{
101+
writer.WriteValue(attachment.Content);
102+
}
103+
else
104+
{
105+
writer.WriteStartObject();
106+
writer.WritePropertyName("_content");
107+
writer.WriteValue(attachment.Content);
108+
109+
if (!string.IsNullOrEmpty(attachment.Name))
110+
{
111+
writer.WritePropertyName("_name");
112+
writer.WriteValue(attachment.Name);
113+
}
114+
115+
if (!string.IsNullOrEmpty(attachment.ContentType))
116+
{
117+
writer.WritePropertyName("_content_type");
118+
writer.WriteValue(attachment.ContentType);
119+
}
120+
121+
if (!string.IsNullOrEmpty(attachment.Language))
122+
{
123+
writer.WritePropertyName("_language");
124+
writer.WriteValue(attachment.Language);
125+
}
126+
127+
if (attachment.DetectLanguage.HasValue)
128+
{
129+
writer.WritePropertyName("_detect_language");
130+
writer.WriteValue(attachment.DetectLanguage.Value);
131+
}
132+
133+
if (attachment.IndexedCharacters.HasValue)
134+
{
135+
writer.WritePropertyName("_indexed_chars");
136+
writer.WriteValue(attachment.IndexedCharacters.Value);
137+
}
138+
139+
writer.WriteEndObject();
140+
}
141+
}
142+
143+
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
144+
{
145+
if (reader.TokenType == JsonToken.String)
146+
{
147+
return new Attachment { Content = (string)reader.Value };
148+
}
149+
150+
if (reader.TokenType == JsonToken.StartObject)
151+
{
152+
var attachment = new Attachment();
153+
while (reader.Read())
154+
{
155+
if (reader.TokenType == JsonToken.PropertyName)
156+
{
157+
var propertyName = (string)reader.Value;
158+
switch (propertyName)
159+
{
160+
case "_content":
161+
attachment.Content = reader.ReadAsString();
162+
break;
163+
case "_name":
164+
attachment.Name = reader.ReadAsString();
165+
break;
166+
case "_content_type":
167+
attachment.ContentType = reader.ReadAsString();
168+
break;
169+
case "_language":
170+
attachment.Language = reader.ReadAsString();
171+
break;
172+
case "_detect_language":
173+
attachment.DetectLanguage = reader.ReadAsBoolean();
174+
break;
175+
case "_indexed_chars":
176+
reader.Read();
177+
attachment.IndexedCharacters = (long?)reader.Value;
178+
break;
179+
}
180+
}
181+
if (reader.TokenType == JsonToken.EndObject)
182+
{
183+
break;
184+
}
185+
}
186+
return attachment;
187+
}
188+
return null;
189+
}
190+
191+
public override bool CanConvert(Type objectType) => objectType == typeof(Attachment);
192+
}
193+
}

src/Nest/Mapping/Visitor/PropertyWalker.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,9 @@ private IProperty InferProperty(Type type)
131131
if (type.IsGeneric() && type.GetGenericTypeDefinition() == typeof(CompletionField<>))
132132
return new CompletionProperty();
133133

134+
if (type == typeof(Attachment))
135+
return new AttachmentProperty();
136+
134137
return new ObjectProperty();
135138
}
136139

src/Nest/Nest.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -825,6 +825,7 @@
825825
<Compile Include="Mapping\Types\PropertyBase.cs" />
826826
<Compile Include="Mapping\Types\PropertyDescriptorBase.cs" />
827827
<Compile Include="Mapping\Types\PropertyJsonConverter.cs" />
828+
<Compile Include="Mapping\Types\Specialized\Attachment\Attachment.cs" />
828829
<Compile Include="Mapping\Types\Specialized\Attachment\AttachmentAttribute.cs" />
829830
<Compile Include="Mapping\Types\Specialized\Attachment\AttachmentProperty.cs" />
830831
<Compile Include="Mapping\Types\Specialized\Completion\CompletionAttribute.cs" />

src/Tests/Document/Single/Attachment/AttachmentApiTests.cs

Lines changed: 316 additions & 48 deletions
Large diffs are not rendered by default.
Binary file not shown.

src/Tests/Framework/MockData/Attachment.cs

Lines changed: 0 additions & 25 deletions
This file was deleted.

src/Tests/Mapping/Types/Specialized/Attachment/AttachmentMappingTests.cs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@
88

99
namespace Tests.Mapping.Types.Specialized.Attachment
1010
{
11-
public class AttachmentMappingTests : TypeMappingTestBase<Tests.Framework.MockData.Attachment>
11+
public class AttachmentMappingTests : TypeMappingTestBase<Nest.Attachment>
1212
{
1313
protected override object ExpectJson => new
1414
{
1515
properties = new
1616
{
17-
file = new
17+
content = new
1818
{
1919
type = "attachment",
2020
fields = new
@@ -67,17 +67,16 @@ protected override void AttributeBasedSerializes()
6767
// TODO: Implement
6868
}
6969

70-
protected override Func<PropertiesDescriptor<Framework.MockData.Attachment>, IPromise<IProperties>> FluentProperties => p => p
70+
protected override Func<PropertiesDescriptor<Nest.Attachment>, IPromise<IProperties>> FluentProperties => p => p
7171
.Attachment(a => a
72-
//.Fields(s => s)
73-
.Name(n => n.File)
72+
.Name(n => n.Content)
7473
.AuthorField(d => d
7574
.Name(n => n.Author)
7675
)
7776
.FileField(d => d
78-
.Name(n => n.File)
77+
.Name(n => n.Content)
7978
)
80-
.ContentLengthField((NumberPropertyDescriptor<Framework.MockData.Attachment> d) => d
79+
.ContentLengthField((NumberPropertyDescriptor<Nest.Attachment> d) => d
8180
.Name(n => n.ContentLength)
8281
)
8382
.ContentTypeField(d => d
@@ -89,7 +88,7 @@ protected override void AttributeBasedSerializes()
8988
.KeywordsField(d => d
9089
.Name(n => n.Keywords)
9190
)
92-
.LanguageField((StringPropertyDescriptor<Framework.MockData.Attachment> d) => d
91+
.LanguageField((StringPropertyDescriptor<Nest.Attachment> d) => d
9392
.Name(n => n.Language)
9493
.DocValues()
9594
.NotAnalyzed()

src/Tests/Tests.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,6 @@
241241
<Compile Include=".\Framework\Integration\Process\ElasticsearchNode.cs" />
242242
<Compile Include=".\Framework\Integration\Process\MapperAttachmentPlugin.cs" />
243243
<Compile Include=".\Framework\Integration\Process\ObservableProcess.cs" />
244-
<Compile Include=".\Framework\MockData\Attachment.cs" />
245244
<Compile Include=".\Framework\MockData\CommitActivity.cs" />
246245
<Compile Include=".\Framework\MockData\Developer.cs" />
247246
<Compile Include=".\Framework\MockData\Gender.cs" />

src/Tests/tests.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# mode either u (unit test), i (integration test) or m (mixed mode)
2-
mode: u
2+
mode: m
33
# the elasticsearch version that should be started
4-
elasticsearch_version: 2.3.0
4+
elasticsearch_version: 2.3.1
55
# whether we want to forcefully reseed on the node, if you are starting the tests with a node already running
66
force_reseed: true
77
# do not spawn nodes as part of the test setup but rely on a manually started es node being up
8-
do_not_spawn: true
8+
do_not_spawn: false

0 commit comments

Comments
 (0)