Skip to content

Commit ffbfc33

Browse files
Support raw JSON query (#7364) (#7365)
Co-authored-by: Steve Gordon <sgordon@hotmail.co.uk>
1 parent dd0aa42 commit ffbfc33

File tree

8 files changed

+137
-16
lines changed

8 files changed

+137
-16
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Licensed to Elasticsearch B.V under one or more agreements.
2+
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System.Diagnostics.CodeAnalysis;
6+
7+
namespace Elastic.Clients.Elasticsearch.QueryDsl;
8+
9+
public partial class Query
10+
{
11+
public bool TryGet<T>([NotNullWhen(true)]out T? query)
12+
{
13+
query = default(T);
14+
15+
if (Variant is T variant)
16+
{
17+
query = variant;
18+
return true;
19+
}
20+
21+
return false;
22+
}
23+
}
24+

src/Elastic.Clients.Elasticsearch/Types/QueryDsl/QueryDescriptor.cs

+10
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ namespace Elastic.Clients.Elasticsearch.QueryDsl;
99

1010
public sealed partial class QueryDescriptor<TDocument>
1111
{
12+
/// <summary>
13+
/// A query defined as a raw JSON string. This can be useful when support for a built-in query is not yet available.
14+
/// </summary>
15+
public QueryDescriptor<TDocument> RawJson(string rawJson) => Set(new RawJsonQuery(rawJson), "raw_json");
16+
1217
public void MatchAll() =>
1318
Set<MatchAllQueryDescriptor>(_ => { }, "match_all");
1419

@@ -18,6 +23,11 @@ public void Term<TValue>(Expression<Func<TDocument, TValue>> field, object value
1823

1924
public sealed partial class QueryDescriptor
2025
{
26+
/// <summary>
27+
/// A query defined as a raw JSON string. This can be useful when support for a built-in query is not yet available.
28+
/// </summary>
29+
public QueryDescriptor RawJson(string rawJson) => Set(new RawJsonQuery(rawJson), "raw_json");
30+
2131
public void MatchAll() =>
2232
Set<MatchAllQueryDescriptor>(_ => { }, "match_all");
2333

src/Elastic.Clients.Elasticsearch/Types/QueryDsl/RangeQuery.cs

+2-16
Original file line numberDiff line numberDiff line change
@@ -10,26 +10,12 @@
1010

1111
namespace Elastic.Clients.Elasticsearch.QueryDsl;
1212

13-
public partial class Query
14-
{
15-
public bool TryGet<T>([NotNullWhen(true)]out T? query)
16-
{
17-
query = default(T);
18-
19-
if (Variant is T variant)
20-
{
21-
query = variant;
22-
return true;
23-
}
24-
25-
return false;
26-
}
27-
}
28-
2913
[JsonConverter(typeof(RangeQueryConverter))]
3014
public class RangeQuery : SearchQuery
3115
{
3216
internal RangeQuery() { }
17+
18+
public static implicit operator Query(RangeQuery rangeQuery) => QueryDsl.Query.Range(rangeQuery);
3319
}
3420

3521
internal sealed class RangeQueryConverter : JsonConverter<RangeQuery>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Licensed to Elasticsearch B.V under one or more agreements.
2+
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System;
6+
using System.Text.Json;
7+
using System.Text.Json.Serialization;
8+
9+
namespace Elastic.Clients.Elasticsearch.QueryDsl;
10+
11+
/// <summary>
12+
/// Allows a query represented as a string of JSON to be defined. This can be useful when support for a built-in query is not yet available.
13+
/// </summary>
14+
public sealed class RawJsonQuery : SearchQuery
15+
{
16+
public RawJsonQuery(string rawQuery) => Raw = rawQuery;
17+
18+
/// <summary>
19+
/// The raw JSON representing the query to be executed.
20+
/// </summary>
21+
public string Raw { get; }
22+
23+
public static implicit operator Query(RawJsonQuery rawJsonQuery) => Query.RawJson(rawJsonQuery);
24+
}
25+
26+
internal sealed class RawJsonQueryConverter : JsonConverter<RawJsonQuery>
27+
{
28+
public override RawJsonQuery? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => throw new NotImplementedException("We never expect to deserialize a raw query.");
29+
30+
public override void Write(Utf8JsonWriter writer, RawJsonQuery value, JsonSerializerOptions options) => writer.WriteRawValue(value.Raw);
31+
}

src/Elastic.Clients.Elasticsearch/_Generated/Types/QueryDsl/Query.g.cs

+31
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ internal Query(string variantName, object variant)
7373
public static Query QueryString(Elastic.Clients.Elasticsearch.QueryDsl.QueryStringQuery queryStringQuery) => new Query("query_string", queryStringQuery);
7474
public static Query Range(Elastic.Clients.Elasticsearch.QueryDsl.RangeQuery rangeQuery) => new Query("range", rangeQuery);
7575
public static Query RankFeature(Elastic.Clients.Elasticsearch.QueryDsl.RankFeatureQuery rankFeatureQuery) => new Query("rank_feature", rankFeatureQuery);
76+
public static Query RawJson(Elastic.Clients.Elasticsearch.QueryDsl.RawJsonQuery rawJsonQuery) => new Query("raw_json", rawJsonQuery);
7677
public static Query Regexp(Elastic.Clients.Elasticsearch.QueryDsl.RegexpQuery regexpQuery) => new Query("regexp", regexpQuery);
7778
public static Query Script(Elastic.Clients.Elasticsearch.QueryDsl.ScriptQuery scriptQuery) => new Query("script", scriptQuery);
7879
public static Query ScriptScore(Elastic.Clients.Elasticsearch.QueryDsl.ScriptScoreQuery scriptScoreQuery) => new Query("script_score", scriptScoreQuery);
@@ -312,6 +313,13 @@ public override Query Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSe
312313
return new Query(propertyName, variant);
313314
}
314315

316+
if (propertyName == "raw_json")
317+
{
318+
var variant = JsonSerializer.Deserialize<Elastic.Clients.Elasticsearch.QueryDsl.RawJsonQuery?>(ref reader, options);
319+
reader.Read();
320+
return new Query(propertyName, variant);
321+
}
322+
315323
if (propertyName == "regexp")
316324
{
317325
var variant = JsonSerializer.Deserialize<Elastic.Clients.Elasticsearch.QueryDsl.RegexpQuery?>(ref reader, options);
@@ -436,6 +444,12 @@ public override Query Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSe
436444

437445
public override void Write(Utf8JsonWriter writer, Query value, JsonSerializerOptions options)
438446
{
447+
if (value.VariantName == "raw_json" && value.TryGet<RawJsonQuery>(out var rawJsonQuery))
448+
{
449+
writer.WriteRawValue(rawJsonQuery.Raw);
450+
return;
451+
}
452+
439453
writer.WriteStartObject();
440454
writer.WritePropertyName(value.VariantName);
441455
switch (value.VariantName)
@@ -527,6 +541,9 @@ public override void Write(Utf8JsonWriter writer, Query value, JsonSerializerOpt
527541
case "rank_feature":
528542
JsonSerializer.Serialize<Elastic.Clients.Elasticsearch.QueryDsl.RankFeatureQuery>(writer, (Elastic.Clients.Elasticsearch.QueryDsl.RankFeatureQuery)value.Variant, options);
529543
break;
544+
case "raw_json":
545+
JsonSerializer.Serialize<Elastic.Clients.Elasticsearch.QueryDsl.RawJsonQuery>(writer, (Elastic.Clients.Elasticsearch.QueryDsl.RawJsonQuery)value.Variant, options);
546+
break;
530547
case "regexp":
531548
JsonSerializer.Serialize<Elastic.Clients.Elasticsearch.QueryDsl.RegexpQuery>(writer, (Elastic.Clients.Elasticsearch.QueryDsl.RegexpQuery)value.Variant, options);
532549
break;
@@ -676,6 +693,7 @@ private QueryDescriptor<TDocument> Set(object variant, string variantName)
676693
public QueryDescriptor<TDocument> Range(Action<RangeQueryDescriptor<TDocument>> configure) => Set(configure, "range");
677694
public QueryDescriptor<TDocument> RankFeature(RankFeatureQuery rankFeatureQuery) => Set(rankFeatureQuery, "rank_feature");
678695
public QueryDescriptor<TDocument> RankFeature(Action<RankFeatureQueryDescriptor<TDocument>> configure) => Set(configure, "rank_feature");
696+
public QueryDescriptor<TDocument> RawJson(Elastic.Clients.Elasticsearch.QueryDsl.RawJsonQuery rawJsonQuery) => Set(rawJsonQuery, "raw_json");
679697
public QueryDescriptor<TDocument> Regexp(RegexpQuery regexpQuery) => Set(regexpQuery, "regexp");
680698
public QueryDescriptor<TDocument> Regexp(Action<RegexpQueryDescriptor<TDocument>> configure) => Set(configure, "regexp");
681699
public QueryDescriptor<TDocument> Script(ScriptQuery scriptQuery) => Set(scriptQuery, "script");
@@ -718,6 +736,12 @@ protected override void Serialize(Utf8JsonWriter writer, JsonSerializerOptions o
718736
return;
719737
}
720738

739+
if (ContainedVariantName == "raw_json")
740+
{
741+
writer.WriteRawValue(((RawJsonQuery)Variant).Raw);
742+
return;
743+
}
744+
721745
writer.WriteStartObject();
722746
writer.WritePropertyName(ContainedVariantName);
723747
if (Variant is not null)
@@ -849,6 +873,7 @@ private QueryDescriptor Set(object variant, string variantName)
849873
public QueryDescriptor RankFeature(RankFeatureQuery rankFeatureQuery) => Set(rankFeatureQuery, "rank_feature");
850874
public QueryDescriptor RankFeature(Action<RankFeatureQueryDescriptor> configure) => Set(configure, "rank_feature");
851875
public QueryDescriptor RankFeature<TDocument>(Action<RankFeatureQueryDescriptor<TDocument>> configure) => Set(configure, "rank_feature");
876+
public QueryDescriptor RawJson(Elastic.Clients.Elasticsearch.QueryDsl.RawJsonQuery rawJsonQuery) => Set(rawJsonQuery, "raw_json");
852877
public QueryDescriptor Regexp(RegexpQuery regexpQuery) => Set(regexpQuery, "regexp");
853878
public QueryDescriptor Regexp(Action<RegexpQueryDescriptor> configure) => Set(configure, "regexp");
854879
public QueryDescriptor Regexp<TDocument>(Action<RegexpQueryDescriptor<TDocument>> configure) => Set(configure, "regexp");
@@ -906,6 +931,12 @@ protected override void Serialize(Utf8JsonWriter writer, JsonSerializerOptions o
906931
return;
907932
}
908933

934+
if (ContainedVariantName == "raw_json")
935+
{
936+
writer.WriteRawValue(((RawJsonQuery)Variant).Raw);
937+
return;
938+
}
939+
909940
writer.WriteStartObject();
910941
writer.WritePropertyName(ContainedVariantName);
911942
if (Variant is not null)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Licensed to Elasticsearch B.V under one or more agreements.
2+
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using Elastic.Clients.Elasticsearch.QueryDsl;
6+
using Tests.Core.ManagedElasticsearch.Clusters;
7+
using Tests.Domain;
8+
using Tests.Framework.EndpointTests.TestState;
9+
10+
namespace Tests.QueryDsl;
11+
12+
public class RawJsonQueryUsageTests : QueryDslUsageTestsBase
13+
{
14+
private static readonly string RawTermQuery = @"{""term"": { ""fieldname"":""value"" } }";
15+
16+
public RawJsonQueryUsageTests(ReadOnlyCluster cluster, EndpointUsage usage) : base(cluster, usage)
17+
{
18+
}
19+
20+
protected override Query QueryInitializer => new RawJsonQuery(RawTermQuery);
21+
22+
protected override QueryDescriptor<Project> QueryFluent(QueryDescriptor<Project> queryDescriptor) =>
23+
queryDescriptor
24+
.RawJson(RawTermQuery);
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
query: {
3+
term: {
4+
fieldname: value
5+
}
6+
}
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
query: {
3+
term: {
4+
fieldname: value
5+
}
6+
}
7+
}

0 commit comments

Comments
 (0)