/* SPDX-License-Identifier: Apache-2.0 * * The OpenSearch Contributors require contributions made to * this file be licensed under the Apache-2.0 license or a * compatible open source license. */ /* * Modifications Copyright OpenSearch Contributors. See * GitHub history for details. * * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright * ownership. Elasticsearch B.V. licenses this file to you under * the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ using System; using System.Collections.Generic; using System.Linq.Expressions; using OpenSearch.Net.Utf8Json; namespace OpenSearch.Client { [JsonFormatter(typeof(PropertiesFormatter))] public interface IProperties : IIsADictionary { } public class Properties : IsADictionaryBase, IProperties { private readonly IConnectionSettingsValues _settings; public Properties() { } public Properties(IDictionary container) : base(container) { } public Properties(Dictionary container) : base(container) { } internal Properties(IConnectionSettingsValues values) => _settings = values; public void Add(PropertyName name, IProperty property) => BackingDictionary.Add(Sanitize(name), property); protected override PropertyName Sanitize(PropertyName key) => _settings?.Inferrer.PropertyName(key) ?? key; } public class Properties : IsADictionaryBase, IProperties { public Properties() { } public Properties(IDictionary container) : base(container) { } public Properties(IProperties properties) : base(properties) { } public Properties(Dictionary container) : base(container) { } public void Add(PropertyName name, IProperty property) => BackingDictionary.Add(name, property); public void Add(Expression> name, IProperty property) => BackingDictionary.Add(name, property); } public partial interface IPropertiesDescriptor where T : class where TReturnType : class { /// TReturnType Text(Func, ITextProperty> selector); /// TReturnType Keyword(Func, IKeywordProperty> selector); /// /// Number introduces a numeric mapping that defaults to `float`. Use .Type() to set the right type if needed or use /// Scalar instead of /// TReturnType Number(Func, INumberProperty> selector); /// TReturnType TokenCount(Func, ITokenCountProperty> selector); /// TReturnType Date(Func, IDateProperty> selector); /// TReturnType DateNanos(Func, IDateNanosProperty> selector); /// TReturnType Boolean(Func, IBooleanProperty> selector); /// TReturnType Binary(Func, IBinaryProperty> selector); /// TReturnType Object(Func, IObjectProperty> selector) where TChild : class; /// TReturnType Nested(Func, INestedProperty> selector) where TChild : class; /// TReturnType Ip(Func, IIpProperty> selector); /// TReturnType GeoPoint(Func, IGeoPointProperty> selector); /// TReturnType GeoShape(Func, IGeoShapeProperty> selector); /// TReturnType Completion(Func, ICompletionProperty> selector); /// TReturnType Murmur3Hash(Func, IMurmur3HashProperty> selector); /// TReturnType Percolator(Func, IPercolatorProperty> selector); /// TReturnType DateRange(Func, IDateRangeProperty> selector); /// TReturnType DoubleRange(Func, IDoubleRangeProperty> selector); /// TReturnType FloatRange(Func, IFloatRangeProperty> selector); /// TReturnType IntegerRange(Func, IIntegerRangeProperty> selector); /// TReturnType LongRange(Func, ILongRangeProperty> selector); /// TReturnType IpRange(Func, IIpRangeProperty> selector); /// TReturnType Join(Func, IJoinProperty> selector); /// TReturnType FieldAlias(Func, IFieldAliasProperty> selector); /// TReturnType RankFeature(Func, IRankFeatureProperty> selector); /// TReturnType RankFeatures(Func, IRankFeaturesProperty> selector); /// TReturnType SearchAsYouType(Func, ISearchAsYouTypeProperty> selector); /// TReturnType KnnVector(Func, IKnnVectorProperty> selector); } public partial class PropertiesDescriptor where T : class { public PropertiesDescriptor() : base(new Properties()) { } public PropertiesDescriptor(IProperties properties) : base(properties ?? new Properties()) { } /// public PropertiesDescriptor Binary(Func, IBinaryProperty> selector) => SetProperty(selector); /// public PropertiesDescriptor Boolean(Func, IBooleanProperty> selector) => SetProperty(selector); /// public PropertiesDescriptor Completion(Func, ICompletionProperty> selector) => SetProperty(selector); /// public PropertiesDescriptor Date(Func, IDateProperty> selector) => SetProperty(selector); /// public PropertiesDescriptor DateNanos(Func, IDateNanosProperty> selector) => SetProperty(selector); /// public PropertiesDescriptor DateRange(Func, IDateRangeProperty> selector) => SetProperty(selector); /// public PropertiesDescriptor DoubleRange(Func, IDoubleRangeProperty> selector) => SetProperty(selector); /// public PropertiesDescriptor FloatRange(Func, IFloatRangeProperty> selector) => SetProperty(selector); /// public PropertiesDescriptor GeoPoint(Func, IGeoPointProperty> selector) => SetProperty(selector); /// public PropertiesDescriptor GeoShape(Func, IGeoShapeProperty> selector) => SetProperty(selector); /// public PropertiesDescriptor IntegerRange(Func, IIntegerRangeProperty> selector) => SetProperty(selector); /// public PropertiesDescriptor Ip(Func, IIpProperty> selector) => SetProperty(selector); /// public PropertiesDescriptor IpRange(Func, IIpRangeProperty> selector) => SetProperty(selector); /// public PropertiesDescriptor Join(Func, IJoinProperty> selector) => SetProperty(selector); /// public PropertiesDescriptor Keyword(Func, IKeywordProperty> selector) => SetProperty(selector); /// public PropertiesDescriptor LongRange(Func, ILongRangeProperty> selector) => SetProperty(selector); /// public PropertiesDescriptor Murmur3Hash(Func, IMurmur3HashProperty> selector) => SetProperty(selector); /// public PropertiesDescriptor Nested(Func, INestedProperty> selector) where TChild : class => SetProperty(selector); /// /// Number introduces a numeric mapping that defaults to float. use /// to set the right type if needed, or use .Scalar() /// instead of /// public PropertiesDescriptor Number(Func, INumberProperty> selector) => SetProperty(selector); /// public PropertiesDescriptor Object(Func, IObjectProperty> selector) where TChild : class => SetProperty(selector); /// public PropertiesDescriptor Percolator(Func, IPercolatorProperty> selector) => SetProperty(selector); /// public PropertiesDescriptor Text(Func, ITextProperty> selector) => SetProperty(selector); /// public PropertiesDescriptor SearchAsYouType(Func, ISearchAsYouTypeProperty> selector) => SetProperty(selector); /// public PropertiesDescriptor TokenCount(Func, ITokenCountProperty> selector) => SetProperty(selector); /// public PropertiesDescriptor FieldAlias(Func, IFieldAliasProperty> selector) => SetProperty(selector); /// public PropertiesDescriptor RankFeature(Func, IRankFeatureProperty> selector) => SetProperty(selector); /// public PropertiesDescriptor RankFeatures(Func, IRankFeaturesProperty> selector) => SetProperty(selector); /// public PropertiesDescriptor KnnVector(Func, IKnnVectorProperty> selector) => SetProperty(selector); /// /// Map a custom property. /// public PropertiesDescriptor Custom(IProperty customType) => SetProperty(customType); private PropertiesDescriptor SetProperty(Func selector) where TDescriptor : class, TInterface, new() where TInterface : IProperty { selector.ThrowIfNull(nameof(selector)); var type = selector(new TDescriptor()); return SetProperty(type); } private PropertiesDescriptor SetProperty(IProperty type) { type.ThrowIfNull(nameof(type)); var typeName = type.GetType().Name; if (type.Name.IsConditionless()) throw new ArgumentException($"Could not get field name for {typeName} mapping"); return Assign(type, (a, v) => a[v.Name] = v); } } internal static class PropertiesExtensions { internal static IProperties AutoMap(this IProperties existingProperties, Type documentType, IPropertyVisitor visitor = null, int maxRecursion = 0 ) { var properties = new Properties(); var autoProperties = new PropertyWalker(documentType, visitor, maxRecursion).GetProperties(); foreach (var autoProperty in autoProperties) properties[autoProperty.Key] = autoProperty.Value; if (existingProperties == null) return properties; // Existing/manually mapped properties always take precedence foreach (var existing in existingProperties) properties[existing.Key] = existing.Value; return properties; } internal static IProperties AutoMap(this IProperties existingProperties, IPropertyVisitor visitor = null, int maxRecursion = 0) where T : class => existingProperties.AutoMap(typeof(T), visitor, maxRecursion); } }