Description
References: #8485
Let me know if this format works best or you'd like new issues for each. I just got started as it was a busy weekend. Anything logged here is feedback addressing 9.0.
1. Query logical operators compiler errors.
Error CS0201 : Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement
public record MyType
{
public string Id { get; set; }
public string Field1 { get; set; }
public string Field2 { get; set; }
public string Field3 { get; set; }
public int Field4 { get; set; }
public DateTime Field5 { get; set; }
public string MultiWord { get; set; }
public Dictionary<string, object> Data { get; set; } = new Dictionary<string, object>();
}
await Client.SearchAsync<MyType>(d => d
.Indices("blah").Query(f => f.Term(m => m.Field(tf => tf.Field1).Value("value1")) || !f.Term(m => m.Field(tf => tf.Field2).Value("value2"))));
2. Query.TryGet<>(out)
This method seems to be missing on query we used this to do some parent child behavior in our query visitors.
Query container = query;
if (query.TryGet<NestedQuery>(out var nested) && node.Parent != null)
container = null;
3. ExtendedBounds conversion to DateHistogramAggregation.ExtendedBounds
We might need an implicit conversion here?
Cannot convert source type 'Elastic.Clients.Elasticsearch.Aggregations.ExtendedBounds<System.DateTime>' to target type 'Elastic.Clients.Elasticsearch.Aggregations.ExtendedBounds<Elastic.Clients.Elasticsearch.Aggregations.FieldDateMath>?'
var bounds = new ExtendedBounds<DateTime> { Min = start.Value, Max = end.Value };
var agg = new DateHistogramAggregation
{
Field = field,
ExtendedBounds = bounds
};
4. SortOptions.Field usage
Constructor 'FieldSort' has 1 parameter(s) but is invoked with 0 argument(s)
This was working in 8.0 but not mentioned in release notes.
return SortOptions.Field(field, new FieldSort
{
UnmappedType = fieldType == FieldType.None ? FieldType.Keyword : fieldType,
Order = node.IsNodeOrGroupNegated() ? SortOrder.Desc : SortOrder.Asc
});
converted to
return new SortOptions
{
Field = new FieldSort(field)
{
UnmappedType = fieldType == FieldType.None ? FieldType.Keyword : fieldType,
Order = node.IsNodeOrGroupNegated() ? SortOrder.Desc : SortOrder.Asc
}
};
5. GetMappingResponse.Indicies
I'm logging this one as I didn't see anything in the previous release notes and this was compiling in 8 to my knowledge. Previously we were calling
public static ElasticMappingResolver Create<T>(ElasticsearchClient client)
{
return Create(() =>
{
client.Indices.Refresh(Indices.Index<T>());
var response = client.Indices.GetMapping(new GetMappingRequest(Indices.Index<T>()));
// use first returned mapping because index could have been an index alias
var mapping = response.Indices.Values.FirstOrDefault()?.Mappings;
return mapping;
}, client.Infer, logger);
}
Seems like this might need to change to:
var mapping = response.Mappings.FirstOrDefault().Value?.Mappings;
6. GeohashPrecision (constructor overloads)
Previous we passed a double to GeohashPrecision which now only takes a long or a string. I think this is now the correct behavior but just wanted to double check.
var precision = new GeohashPrecision(1);
if (!String.IsNullOrEmpty(node.UnescapedProximity) && Double.TryParse(node.UnescapedProximity, out double parsedPrecision))
{
if (parsedPrecision is < 1 or > 12)
throw new ArgumentOutOfRangeException(nameof(node.UnescapedProximity), "Precision must be between 1 and 12");
precision = new GeohashPrecision(parsedPrecision);
}
7. CountAsync requires parameters.
This seems like it should be allowed by default to get the count of everything in a repository. This is a breaking change from 8.
var total = await Client.CountAsync<InvertTest>();
8. Range Queries breaking change.
Undocumented breaking change with TermRange and DateRange
.Query(f => f.Range(r => r.DateRange(dr => dr.Field()))
to
.Query(f => f.Range(r => r.Date(dr => dr.Field()))
9. Nested Mappings Breaking Changes
This was undocumented, really like this change for consistency but it might break a lot of people.
Error CS0308 : The non-generic method 'PropertiesDescriptor.Nested(PropertyName, NestedProperty)' cannot be used with type arguments
string index = await CreateRandomIndexAsync<MyNestedType>(d => d.Properties(p => p
.Text(e => e.Field1, o => o.Index())
.Nested<MyType>(r => r.Name(n => n.Nested.First()).Properties(p1 => p1
.Text(e => e.Field1, o => o.Index())
.IntegerNumber(e => e.Field4)
))
));
to
string index = await CreateRandomIndexAsync<MyNestedType>(d => d.Properties(p => p
.Text(e => e.Field1, o => o.Index())
.Text(e => e.Field2, o => o.Index())
.Text(e => e.Field3, o => o.Index())
.IntegerNumber(e => e.Field4)
.Nested(e => e.Nested, o => o.Properties(p1 => p1
.Text(e1 => e1.Field1, o1 => o1.Index())
.Text(e1 => e1.Field2, o1 => o1.Index())
.Text(e1 => e1.Field3, o1 => o1.Index())
.IntegerNumber(e => e.Field4)
))
));
However the dictionary case might be breaking intellisense as I'm getting auto completion for the top level fields..
string index = await CreateRandomIndexAsync<MyType>(m => m.Properties(p => p
.Object<Dictionary<string, object>>(f => f.Name(e => e.Data).Properties(p2 => p2
.Text(e => e.Name("@browser_version"))
.FieldAlias(a => a.Name("browser.version").Path("data.@browser_version"))))));
to
string index = await CreateRandomIndexAsync<MyType>(m => m.Properties(p => p
.Object(f => f.Data, o => o.Properties(p2 => p2
.Text("@browser_version")
.FieldAlias("browser.version", o1 => o1.Path("data.@browser_version"))))));
10. GeoDistanceQuery, GeoBoundingBoxQuery, TopLeftBottomRightGeoBounds parameter order.
I typed field in wrong which feels like what most of the api surface accepts as the first parameter. Feels like this should be looked over to make it feel more uniform.
for TopLeftBottomRightGeoBounds, it seems like the order should match the method name.
11. Query Generics for easier query generation.
We have the generic query client which gives us field inference/autocomplete. Any chance this can be brought back? Or a great solution for it?
public class CompanyQueryBuilder : IElasticQueryBuilder
{
public Task BuildAsync<T>(QueryBuilderContext<T> ctx) where T : class, new()
{
var companyIds = ctx.Source.GetCompanies();
if (companyIds.Count <= 0)
return Task.CompletedTask;
if (companyIds.Count == 1)
ctx.Filter &= Query<Employee>.Term(f => f.CompanyId, companyIds.Single());
else
ctx.Filter &= Query<Employee>.Terms(d => d.Field(f => f.CompanyId).Terms(companyIds));
return Task.CompletedTask;
}
}