Ir al contenido principal

Reference

Referencia​

Ambas sobrecargas están en Vali_Flow.NoSql.Elasticsearch.Extensions.ValiFlowElasticsearchExtensions.

ToElasticsearch<T>(this ValiFlow<T> flow, Func<object?, FieldValue?>? customConverter = null)​

Traduce las condiciones acumuladas en un constructor ValiFlow<T> en una Query de Elasticsearch.

ParámetroTipoRequeridoDescripción
flowValiFlow<T>SíEl constructor que contiene las condiciones.
customConverterFunc<object?, FieldValue?>?NoHook para mapear tipos CLR no manejados por el switch incorporado. Retornar null para caer al conversor por defecto.

Retorna: Query — pásalo directamente a Search, Count, DeleteByQuery, etc.

ToElasticsearch<T>(this Expression<Func<T, bool>> expression, Func<object?, FieldValue?>? customConverter = null)​

Misma traducción para una Expression<Func<T, bool>> ya construida.

Expression<Func<Product, bool>> expr = p => p.Category == "Electronics" && p.Price < 500m;
Query filter = expr.ToElasticsearch();

Operaciones soportadas​

Método ValiFlowNodo IRConsulta Elasticsearch
.EqualTo(x => x.Field, v)EqualNode(IsNegated: false)term { field: value }
.NotEqualTo(x => x.Field, v)EqualNode(IsNegated: true)bool { must_not: [term { field: value }] }
.GreaterThan(x => x.Field, v)ComparisonNode(GT)range { field: { gt: value } }
.GreaterThanOrEqualTo(x => x.Field, v)ComparisonNode(GTE)range { field: { gte: value } }
.LessThan(x => x.Field, v)ComparisonNode(LT)range { field: { lt: value } }
.LessThanOrEqualTo(x => x.Field, v)ComparisonNode(LTE)range { field: { lte: value } }
.Contains(x => x.Field, "txt")LikeNode(Contains)wildcard { field: "*txt*", case_insensitive: true }
.StartsWith(x => x.Field, "pre")LikeNode(StartsWith)wildcard { field: "pre*", case_insensitive: true }
.EndsWith(x => x.Field, "suf")LikeNode(EndsWith)wildcard { field: "*suf", case_insensitive: true }
.In(x => x.Field, list)InNodeterms { field: [...] }
.IsNull(x => x.Field)NullNode(IsNull)bool { must_not: [exists { field }] }
.IsNotNull(x => x.Field)NullNode(IsNotNull)exists { field }
.And(a, b)AndNodebool { must: [a, b] }
.Or(a, b)OrNodebool { should: [a, b], minimum_should_match: 1 }
.Not(inner)NotNodebool { must_not: [inner] }

Las consultas de rango usan NumberRangeQuery, que requiere un campo numérico. El valor se convierte a double mediante Convert.ToDouble. Pasar un valor no numérico a una comparación de rango lanza NotSupportedException.

Los caracteres especiales de comodín (*, ?, \) en las cadenas de patrón se escapan antes de construir el patrón de Elasticsearch.

Mapeo de tipos​

El switch ToFieldValue incorporado maneja estos tipos CLR para consultas term y terms:

Tipo CLRFieldValue producido
nullFieldValue.Null
boolFieldValue.Boolean(b)
intFieldValue.Long(i)
longFieldValue.Long(l)
doubleFieldValue.Double(d)
floatFieldValue.Double(f)
decimalFieldValue.Double((double)dec)
stringFieldValue.String(s)
EnumFieldValue.Long(Convert.ToInt64(e))
cualquier otroFieldValue.String(v.ToString())

Conversor de valores personalizado​

Usa customConverter cuando tus tipos de dominio no están en la tabla anterior, o cuando necesitas una representación FieldValue diferente a la por defecto.

El conversor se llama antes del switch incorporado. Retorna null para dejar que el default maneje el valor.

// Tipo de dominio
record Money(decimal Amount, string Currency);

// Conversor: representar Money como FieldValue de double
Query filter = new ValiFlow<Product>()
.LessThan(x => x.Price, new Money(500m, "USD"))
.ToElasticsearch(value =>
{
if (value is Money m)
return FieldValue.Double((double)m.Amount);
return null;
});

Forzar que decimal use representación de cadena en un campo keyword:

Query filter = new ValiFlow<Invoice>()
.EqualTo(x => x.TaxRate, 0.21m)
.ToElasticsearch(value =>
{
if (value is decimal d)
return FieldValue.String(d.ToString("G", CultureInfo.InvariantCulture));
return null;
});

Ejemplo avanzado​

var query = new ValiFlow<Order>()
.GreaterThan(x => x.Total, 100m)
.ToElasticsearch();