/// <summary> /// Add keyword value matching to the query. /// </summary> /// <param name="fitsKeyword"></param> /// <param name="value"></param> /// <returns></returns> public IFitsQueryExpression KeywordMatching <T>(string fitsKeyword, T value) { var valueType = typeof(T); var headerType = typeof(FitsHeaderIndexedRow); var headerKeywordProps = headerType.GetProperties().Where(p => p.HasAttribute <FitsFieldAttribute>()); var matchingProp = headerKeywordProps.FirstOrDefault(p => p.GetCustomAttribute <FitsFieldAttribute>().Name == fitsKeyword); if (matchingProp == null) { throw new FitsDatabaseException($"Cannot add keyword matching for keyword '{fitsKeyword}' to the query, " + $"this keyword doesn't exist in the indexed keywords"); } if (matchingProp.PropertyType != valueType && matchingProp.PropertyType.ToNullableUnderlying() != valueType) { throw new FitsDatabaseException($"Cannot add keyword matching for keyword '{fitsKeyword}' to the query, " + $"the given value is not of type '{matchingProp.PropertyType.Name}'"); } // The expression works on FitsSearchResult, which combines all the related SQL tables. // Construct the expression dynamically from the property name linked to the FITS header name. var exprParamType = typeof(FitsSearchResult); // ... == targetValue var targetValue = Expression.Constant(value); // ((FitsSearchResult)x) => ... var parameter = Expression.Parameter(exprParamType, "x"); // ((FitsSearchResult)x) => x.HeaderData.property Expression property = Expression.PropertyOrField(parameter, nameof(FitsSearchResult.HeaderData)); property = Expression.PropertyOrField(property, matchingProp.Name); // Convert property from nullable to non-nullable type because expressions can't // really handle nullables (value gets always converted to non-nullable, and comparison // between nullables and non-nullables will throw). var nonNullableType = valueType.ToNullableUnderlying(); property = Expression.Convert(property, nonNullableType); // ((FitsSearchResult)x) => x.HeaderData.property == targetValue var body = Expression.Equal(property, targetValue); var lambda = Expression.Lambda <Func <FitsSearchResult, bool> >(body, parameter); var expr = new FitsQueryExpression() { Expression = lambda }; return(expr); }
/// <summary> /// Search for string inside a FITS keyword value. /// Both the fitsKeyword and the searchString must be strings. /// </summary> /// <param name="fitsKeyword"></param> /// <param name="searchString"></param> /// <returns></returns> public IFitsQueryExpression KeywordSearch(string fitsKeyword, string searchString) { var exprParamType = typeof(FitsSearchResult); var headerType = typeof(FitsHeaderIndexedRow); var headerKeywordProps = headerType.GetProperties().Where(p => p.HasAttribute <FitsFieldAttribute>()); var matchingProp = headerKeywordProps.FirstOrDefault(p => p.GetCustomAttribute <FitsFieldAttribute>().Name == fitsKeyword); if (matchingProp == null) { throw new FitsDatabaseException($"Cannot add keyword matching for keyword '{fitsKeyword}' to the query, " + $"this keyword doesn't exist in the indexed keywords"); } if (matchingProp.PropertyType != typeof(string)) { throw new FitsDatabaseException($"Cannot add keyword matching for keyword '{fitsKeyword}' to the query, " + $"the given value is not of type '{matchingProp.PropertyType.Name}'"); } var targetValue = Expression.Constant(searchString); var parameter = Expression.Parameter(exprParamType, "x"); Expression property = Expression.PropertyOrField(parameter, nameof(FitsSearchResult.HeaderData)); property = Expression.PropertyOrField(property, matchingProp.Name); MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) }); var body = Expression.Call(property, method, targetValue); var lambda = Expression.Lambda <Func <FitsSearchResult, bool> >(body, parameter); var expr = new FitsQueryExpression() { Expression = lambda }; return(expr); }
/// <summary> /// Does a comparison with the given operator to a numeric FITS keyword value. /// </summary> /// <param name="fitsKeyword"></param> /// <param name="value"></param> /// <param name="comparison"></param> /// <returns></returns> public IFitsQueryExpression NumericValueComparison(string fitsKeyword, double value, NumericComparison comparison) { var exprParamType = typeof(FitsSearchResult); var headerType = typeof(FitsHeaderIndexedRow); var headerKeywordProps = headerType.GetProperties().Where(p => p.HasAttribute <FitsFieldAttribute>()); var matchingProp = headerKeywordProps.FirstOrDefault(p => p.GetCustomAttribute <FitsFieldAttribute>().Name == fitsKeyword); if (matchingProp == null) { throw new FitsDatabaseException($"Cannot add keyword matching for keyword '{fitsKeyword}' to the query, " + $"this keyword doesn't exist in the indexed keywords"); } if (matchingProp.PropertyType != typeof(double)) { throw new FitsDatabaseException($"Cannot add keyword matching for keyword '{fitsKeyword}' to the query, " + $"the given value is not of type '{matchingProp.PropertyType.Name}'"); } var targetValue = Expression.Constant(value); var parameter = Expression.Parameter(exprParamType, "x"); Expression property = Expression.PropertyOrField(parameter, nameof(FitsSearchResult.HeaderData)); property = Expression.PropertyOrField(property, matchingProp.Name); Expression body = null; switch (comparison) { case NumericComparison.Eq: body = Expression.Equal(property, targetValue); break; case NumericComparison.Gt: body = Expression.GreaterThan(property, targetValue); break; case NumericComparison.Gte: body = Expression.GreaterThanOrEqual(property, targetValue); break; case NumericComparison.Lt: body = Expression.LessThan(property, targetValue); break; case NumericComparison.Lte: body = Expression.LessThanOrEqual(property, targetValue); break; } var lambda = Expression.Lambda <Func <FitsSearchResult, bool> >(body, parameter); var expr = new FitsQueryExpression() { Expression = lambda }; return(expr); }