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>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();