From fdc05287bf559615dff06370ad0fd9678b706d99 Mon Sep 17 00:00:00 2001 From: Heath Stewart Date: Wed, 27 May 2020 16:16:05 -0700 Subject: [PATCH] Define public APIs for FieldBuilder Define the public APIs for #11166 --- sdk/search/Azure.Search.Documents/README.md | 1 + .../Azure.Search.Documents.netstandard2.0.cs | 94 ++++++++++++------- .../samples/Sample01a_HelloWorld.md | 1 + .../samples/Sample01b_HelloWorldAsync.md | 1 + .../src/Indexes/FieldBuilder.cs | 91 ++++++++++++++++++ .../src/Indexes/ISearchFieldAttribute.cs | 20 ++++ .../src/Indexes/Models/SearchableField.cs | 17 +++- .../src/Indexes/SearchIndexClient.cs | 2 +- .../src/Indexes/SearchIndexerClient.cs | 2 +- .../src/Indexes/SearchableFieldAttribute.cs | 67 +++++++++++++ .../src/Indexes/SimpleFieldAttribute.cs | 78 +++++++++++++++ .../src/SearchClient.cs | 1 + .../tests/FieldBuilderTests.cs | 35 +++++++ .../tests/Samples/HelloWorld.cs | 1 + .../tests/Samples/Readme.cs | 1 + .../tests/SearchIndexClientTests.cs | 1 + .../tests/SearchIndexerClientTests.cs | 1 + .../tests/SearchableFieldAttributeTests.cs | 71 ++++++++++++++ .../tests/SimpleFieldAttributeTests.cs | 45 +++++++++ .../tests/Utilities/SearchResources.cs | 2 +- 20 files changed, 496 insertions(+), 36 deletions(-) create mode 100644 sdk/search/Azure.Search.Documents/src/Indexes/FieldBuilder.cs create mode 100644 sdk/search/Azure.Search.Documents/src/Indexes/ISearchFieldAttribute.cs create mode 100644 sdk/search/Azure.Search.Documents/src/Indexes/SearchableFieldAttribute.cs create mode 100644 sdk/search/Azure.Search.Documents/src/Indexes/SimpleFieldAttribute.cs create mode 100644 sdk/search/Azure.Search.Documents/tests/FieldBuilderTests.cs create mode 100644 sdk/search/Azure.Search.Documents/tests/SearchableFieldAttributeTests.cs create mode 100644 sdk/search/Azure.Search.Documents/tests/SimpleFieldAttributeTests.cs diff --git a/sdk/search/Azure.Search.Documents/README.md b/sdk/search/Azure.Search.Documents/README.md index 14374bb533191..a6e0116cb914b 100644 --- a/sdk/search/Azure.Search.Documents/README.md +++ b/sdk/search/Azure.Search.Documents/README.md @@ -174,6 +174,7 @@ Let's start by importing our namespaces. ```C# Snippet:Azure_Search_Tests_Samples_Readme_Namespace using Azure; using Azure.Search.Documents; +using Azure.Search.Documents.Indexes; ``` We'll then create a `SearchClient` to access our hotels search index. diff --git a/sdk/search/Azure.Search.Documents/api/Azure.Search.Documents.netstandard2.0.cs b/sdk/search/Azure.Search.Documents/api/Azure.Search.Documents.netstandard2.0.cs index 2202f325a6eb6..359aa67121015 100644 --- a/sdk/search/Azure.Search.Documents/api/Azure.Search.Documents.netstandard2.0.cs +++ b/sdk/search/Azure.Search.Documents/api/Azure.Search.Documents.netstandard2.0.cs @@ -65,6 +65,59 @@ public static partial class SearchFilter public static string Create(System.FormattableString filter) { throw null; } public static string Create(System.FormattableString filter, System.IFormatProvider formatProvider) { throw null; } } + public partial class SearchOptions + { + public SearchOptions() { } + public SearchOptions(string continuationToken) { } + public System.Collections.Generic.IList Facets { get { throw null; } } + public string Filter { get { throw null; } set { } } + public System.Collections.Generic.IList HighlightFields { get { throw null; } } + public string HighlightPostTag { get { throw null; } set { } } + public string HighlightPreTag { get { throw null; } set { } } + public bool? IncludeTotalCount { get { throw null; } set { } } + public double? MinimumCoverage { get { throw null; } set { } } + public System.Collections.Generic.IList OrderBy { get { throw null; } } + public Azure.Search.Documents.Models.SearchQueryType? QueryType { get { throw null; } set { } } + public System.Collections.Generic.IList ScoringParameters { get { throw null; } } + public string ScoringProfile { get { throw null; } set { } } + public System.Collections.Generic.IList SearchFields { get { throw null; } } + public Azure.Search.Documents.Models.SearchMode? SearchMode { get { throw null; } set { } } + public System.Collections.Generic.IList Select { get { throw null; } } + public int? Size { get { throw null; } set { } } + public int? Skip { get { throw null; } set { } } + } + public partial class SuggestOptions + { + public SuggestOptions() { } + public string Filter { get { throw null; } set { } } + public string HighlightPostTag { get { throw null; } set { } } + public string HighlightPreTag { get { throw null; } set { } } + public double? MinimumCoverage { get { throw null; } set { } } + public System.Collections.Generic.IList OrderBy { get { throw null; } } + public System.Collections.Generic.IList SearchFields { get { throw null; } } + public System.Collections.Generic.IList Select { get { throw null; } } + public int? Size { get { throw null; } set { } } + public bool? UseFuzzyMatching { get { throw null; } set { } } + } +} +namespace Azure.Search.Documents.Indexes +{ + public static partial class FieldBuilder + { + public static System.Collections.Generic.IList Build(System.Type type) { throw null; } + public static System.Collections.Generic.IList Build(System.Type type, System.Text.Json.JsonNamingPolicy namingPolicy) { throw null; } + public static System.Collections.Generic.IList Build() { throw null; } + public static System.Collections.Generic.IList Build(System.Text.Json.JsonNamingPolicy namingPolicy) { throw null; } + } + [System.AttributeUsageAttribute(System.AttributeTargets.Field | System.AttributeTargets.Property, AllowMultiple=false, Inherited=true)] + public partial class SearchableFieldAttribute : Azure.Search.Documents.Indexes.SimpleFieldAttribute + { + public SearchableFieldAttribute(bool collection = false) : base (default(Azure.Search.Documents.Indexes.Models.SearchFieldDataType), default(bool)) { } + public Azure.Search.Documents.Indexes.Models.LexicalAnalyzerName? AnalyzerName { get { throw null; } set { } } + public Azure.Search.Documents.Indexes.Models.LexicalAnalyzerName? IndexAnalyzerName { get { throw null; } set { } } + public Azure.Search.Documents.Indexes.Models.LexicalAnalyzerName? SearchAnalyzerName { get { throw null; } set { } } + public string[] SynonymMapNames { get { throw null; } set { } } + } public partial class SearchIndexClient { protected SearchIndexClient() { } @@ -164,39 +217,16 @@ public SearchIndexerClient(System.Uri endpoint, Azure.AzureKeyCredential credent public virtual Azure.Response RunIndexer(string indexerName, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual System.Threading.Tasks.Task RunIndexerAsync(string indexerName, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } } - public partial class SearchOptions - { - public SearchOptions() { } - public SearchOptions(string continuationToken) { } - public System.Collections.Generic.IList Facets { get { throw null; } } - public string Filter { get { throw null; } set { } } - public System.Collections.Generic.IList HighlightFields { get { throw null; } } - public string HighlightPostTag { get { throw null; } set { } } - public string HighlightPreTag { get { throw null; } set { } } - public bool? IncludeTotalCount { get { throw null; } set { } } - public double? MinimumCoverage { get { throw null; } set { } } - public System.Collections.Generic.IList OrderBy { get { throw null; } } - public Azure.Search.Documents.Models.SearchQueryType? QueryType { get { throw null; } set { } } - public System.Collections.Generic.IList ScoringParameters { get { throw null; } } - public string ScoringProfile { get { throw null; } set { } } - public System.Collections.Generic.IList SearchFields { get { throw null; } } - public Azure.Search.Documents.Models.SearchMode? SearchMode { get { throw null; } set { } } - public System.Collections.Generic.IList Select { get { throw null; } } - public int? Size { get { throw null; } set { } } - public int? Skip { get { throw null; } set { } } - } - public partial class SuggestOptions + [System.AttributeUsageAttribute(System.AttributeTargets.Field | System.AttributeTargets.Property, AllowMultiple=false, Inherited=true)] + public partial class SimpleFieldAttribute : System.Attribute { - public SuggestOptions() { } - public string Filter { get { throw null; } set { } } - public string HighlightPostTag { get { throw null; } set { } } - public string HighlightPreTag { get { throw null; } set { } } - public double? MinimumCoverage { get { throw null; } set { } } - public System.Collections.Generic.IList OrderBy { get { throw null; } } - public System.Collections.Generic.IList SearchFields { get { throw null; } } - public System.Collections.Generic.IList Select { get { throw null; } } - public int? Size { get { throw null; } set { } } - public bool? UseFuzzyMatching { get { throw null; } set { } } + public SimpleFieldAttribute(Azure.Search.Documents.Indexes.Models.SearchFieldDataType type, bool collection = false) { } + public bool IsFacetable { get { throw null; } set { } } + public bool IsFilterable { get { throw null; } set { } } + public bool IsHidden { get { throw null; } set { } } + public bool IsKey { get { throw null; } set { } } + public bool IsSortable { get { throw null; } set { } } + public Azure.Search.Documents.Indexes.Models.SearchFieldDataType Type { get { throw null; } } } } namespace Azure.Search.Documents.Indexes.Models diff --git a/sdk/search/Azure.Search.Documents/samples/Sample01a_HelloWorld.md b/sdk/search/Azure.Search.Documents/samples/Sample01a_HelloWorld.md index 31c8ac7bdef3d..1c839013a8ad9 100644 --- a/sdk/search/Azure.Search.Documents/samples/Sample01a_HelloWorld.md +++ b/sdk/search/Azure.Search.Documents/samples/Sample01a_HelloWorld.md @@ -3,6 +3,7 @@ ## Import the namespaces ```C# Snippet:Azure_Search_Tests_Samples_Namespaces using Azure.Search.Documents; +using Azure.Search.Documents.Indexes; using Azure.Search.Documents.Indexes.Models; ``` diff --git a/sdk/search/Azure.Search.Documents/samples/Sample01b_HelloWorldAsync.md b/sdk/search/Azure.Search.Documents/samples/Sample01b_HelloWorldAsync.md index 48cb37505f41e..ba9cbf41882e1 100644 --- a/sdk/search/Azure.Search.Documents/samples/Sample01b_HelloWorldAsync.md +++ b/sdk/search/Azure.Search.Documents/samples/Sample01b_HelloWorldAsync.md @@ -3,6 +3,7 @@ ## Import the namespaces ```C# Snippet:Azure_Search_Tests_Samples_Namespaces using Azure.Search.Documents; +using Azure.Search.Documents.Indexes; using Azure.Search.Documents.Indexes.Models; ``` diff --git a/sdk/search/Azure.Search.Documents/src/Indexes/FieldBuilder.cs b/sdk/search/Azure.Search.Documents/src/Indexes/FieldBuilder.cs new file mode 100644 index 0000000000000..40cd3ff3299dd --- /dev/null +++ b/sdk/search/Azure.Search.Documents/src/Indexes/FieldBuilder.cs @@ -0,0 +1,91 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Text.Json; +using System.Text.Json.Serialization; +using Azure.Core; +using Azure.Search.Documents.Indexes.Models; + +namespace Azure.Search.Documents.Indexes +{ + /// + /// Builds a list of given a model type for use in a . + /// + /// + /// + public static class FieldBuilder + { + private static readonly DefaultNamingPolicy s_defaultNamingPolicy = new DefaultNamingPolicy(); + + /// + /// Builds a list of given a model type for use in a . + /// By default, all public properties and fields of that model type will generate a ; + /// however, you can ignore them using or . + /// You can further customize the generated using the + /// and attributes. + /// + /// The type of model from which to build fields. + /// A list of from model type . + public static IList Build() => Build(typeof(T), s_defaultNamingPolicy); + + /// + /// Builds a list of given a model type for use in a . + /// By default, all public properties and fields of that model type will generate a ; + /// however, you can ignore them using or . + /// You can further customize the generated using the + /// and attributes. + /// + /// The type of model from which to build fields. + /// + /// The to use for converting property names if not already attributed with . + /// + /// A list of from model type . + /// is null. + public static IList Build(JsonNamingPolicy namingPolicy) => Build(typeof(T), namingPolicy); + + /// + /// Builds a list of given a model for use in a . + /// By default, all public properties and fields of that model type will generate a ; + /// however, you can ignore them using or . + /// You can further customize the generated using the + /// and attributes. + /// + /// The type of model from which to build fields. + /// A list of from model . + /// is null. + public static IList Build(Type type) => Build(type, s_defaultNamingPolicy); + + /// + /// Builds a list of given a model for use in a . + /// By default, all public properties and fields of that model type will generate a ; + /// however, you can ignore them using or . + /// You can further customize the generated using the + /// and attributes. + /// + /// The type of model from which to build fields. + /// + /// The to use for converting property names if not already attributed with . + /// + /// A list of from model . + /// or is null. + public static IList Build(Type type, JsonNamingPolicy namingPolicy) + { + Argument.AssertNotNull(type, nameof(type)); + Argument.AssertNotNull(namingPolicy, nameof(namingPolicy)); + + throw new NotImplementedException(); + } + + private class DefaultNamingPolicy : JsonNamingPolicy + { + /// + /// Returns the as is. + /// + /// The property name to convert. + /// The as is. + public override string ConvertName(string name) => name; + } + } +} diff --git a/sdk/search/Azure.Search.Documents/src/Indexes/ISearchFieldAttribute.cs b/sdk/search/Azure.Search.Documents/src/Indexes/ISearchFieldAttribute.cs new file mode 100644 index 0000000000000..158bc54882b56 --- /dev/null +++ b/sdk/search/Azure.Search.Documents/src/Indexes/ISearchFieldAttribute.cs @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Azure.Search.Documents.Indexes.Models; + +namespace Azure.Search.Documents.Indexes +{ + /// + /// Represents an attribute that creates a . + /// + internal interface ISearchFieldAttribute + { + /// + /// Creates a from the implementing attribute. + /// + /// The name of the attributed field or property. + /// A created from the implementing attribute. + SearchField CreateField(string name); + } +} diff --git a/sdk/search/Azure.Search.Documents/src/Indexes/Models/SearchableField.cs b/sdk/search/Azure.Search.Documents/src/Indexes/Models/SearchableField.cs index 4102c7d64e56b..5a3797fd3b71d 100644 --- a/sdk/search/Azure.Search.Documents/src/Indexes/Models/SearchableField.cs +++ b/sdk/search/Azure.Search.Documents/src/Indexes/Models/SearchableField.cs @@ -11,6 +11,8 @@ namespace Azure.Search.Documents.Indexes.Models /// public class SearchableField : SimpleField { + private readonly List _synonymMapNames; + /// /// Initializes a new instance of the class. /// @@ -21,6 +23,7 @@ public class SearchableField : SimpleField public SearchableField(string name, bool collection = false) : base(name, collection ? SearchFieldDataType.Collection(SearchFieldDataType.String) : SearchFieldDataType.String) { // NOTE: Types other than string may be searchable one day. Could add an overload in the future. + _synonymMapNames = new List(); } /// @@ -51,7 +54,19 @@ public SearchableField(string name, bool collection = false) : base(name, collec /// Assigning a synonym map to a field ensures that query terms targeting that field are expanded at query-time using the rules in the synonym map. /// This attribute can be changed on existing fields. /// - public IList SynonymMapNames { get; } = new List(); + public IList SynonymMapNames + { + get => _synonymMapNames; + internal set + { + _synonymMapNames.Clear(); + + if (value != null) + { + _synonymMapNames.AddRange(value); + } + } + } /// private protected override void Save(SearchField field) diff --git a/sdk/search/Azure.Search.Documents/src/Indexes/SearchIndexClient.cs b/sdk/search/Azure.Search.Documents/src/Indexes/SearchIndexClient.cs index ec1b4a7fd170f..bbd0ce054faea 100644 --- a/sdk/search/Azure.Search.Documents/src/Indexes/SearchIndexClient.cs +++ b/sdk/search/Azure.Search.Documents/src/Indexes/SearchIndexClient.cs @@ -10,7 +10,7 @@ using Azure.Core.Pipeline; using Azure.Search.Documents.Indexes.Models; -namespace Azure.Search.Documents +namespace Azure.Search.Documents.Indexes { /// /// Azure Cognitive Search client that can be used to manage indexes on a Search service. diff --git a/sdk/search/Azure.Search.Documents/src/Indexes/SearchIndexerClient.cs b/sdk/search/Azure.Search.Documents/src/Indexes/SearchIndexerClient.cs index c0db6e0f4485c..f86858805d3ff 100644 --- a/sdk/search/Azure.Search.Documents/src/Indexes/SearchIndexerClient.cs +++ b/sdk/search/Azure.Search.Documents/src/Indexes/SearchIndexerClient.cs @@ -10,7 +10,7 @@ using System.Linq; using Azure.Search.Documents.Indexes.Models; -namespace Azure.Search.Documents +namespace Azure.Search.Documents.Indexes { /// /// Azure Cognitive Search client that can be used to manage and query diff --git a/sdk/search/Azure.Search.Documents/src/Indexes/SearchableFieldAttribute.cs b/sdk/search/Azure.Search.Documents/src/Indexes/SearchableFieldAttribute.cs new file mode 100644 index 0000000000000..ac24cee3d2d53 --- /dev/null +++ b/sdk/search/Azure.Search.Documents/src/Indexes/SearchableFieldAttribute.cs @@ -0,0 +1,67 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Azure.Search.Documents.Indexes.Models; + +namespace Azure.Search.Documents.Indexes +{ + /// + /// Attributes a simple field using a primitive type or a collection of a primitive type. + /// + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)] + public class SearchableFieldAttribute : SimpleFieldAttribute, ISearchFieldAttribute + { + /// + /// Gets the data type of the field. + /// + /// Whether the field is a collection of strings. + public SearchableFieldAttribute(bool collection = false) : base(SearchFieldDataType.String, collection) + { + } + + /// + /// Gets or sets the name of the language analyzer. This property cannot be set when either or are set. + /// Once the analyzer is chosen, it cannot be changed for the field in the index. + /// + public LexicalAnalyzerName? AnalyzerName { get; set; } + + /// + /// Gets or sets the name of the language analyzer for searching. This property must be set together with , and cannot be set when is set. + /// This property cannot be set to the name of a language analyzer; use the property instead if you need a language analyzer. + /// Once the analyzer is chosen, it cannot be changed for the field in the index. + /// + public LexicalAnalyzerName? SearchAnalyzerName { get; set; } + + /// + /// Gets or sets the name of the language analyzer for indexing. This property must be set together with , and cannot be set when is set. + /// This property cannot be set to the name of a language analyzer; use the property instead if you need a language analyzer. + /// Once the analyzer is chosen, it cannot be changed for the field in the index. + /// + public LexicalAnalyzerName? IndexAnalyzerName { get; set; } + + /// + /// Gets or sets a list of names of synonym maps to associate with this field. + /// Currently, only one synonym map per field is supported. + /// + /// + /// Assigning a synonym map to a field ensures that query terms targeting that field are expanded at query-time using the rules in the synonym map. + /// This attribute can be changed on existing fields. + /// + public string[] SynonymMapNames { get; set; } + + /// + SearchField ISearchFieldAttribute.CreateField(string name) => new SearchableField(name, Type.IsCollection) + { + IsKey = IsKey, + IsHidden = IsHidden, + IsFilterable = IsFilterable, + IsFacetable = IsFacetable, + IsSortable = IsSortable, + AnalyzerName = AnalyzerName, + SearchAnalyzerName = SearchAnalyzerName, + IndexAnalyzerName = IndexAnalyzerName, + SynonymMapNames = SynonymMapNames, + }; + } +} diff --git a/sdk/search/Azure.Search.Documents/src/Indexes/SimpleFieldAttribute.cs b/sdk/search/Azure.Search.Documents/src/Indexes/SimpleFieldAttribute.cs new file mode 100644 index 0000000000000..e16da8415d29c --- /dev/null +++ b/sdk/search/Azure.Search.Documents/src/Indexes/SimpleFieldAttribute.cs @@ -0,0 +1,78 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Azure.Search.Documents.Indexes.Models; + +namespace Azure.Search.Documents.Indexes +{ + /// + /// Attributes a simple field using a primitive type or a collection of a primitive type. + /// + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)] + public class SimpleFieldAttribute : Attribute, ISearchFieldAttribute + { + /// + /// Gets the data type of the field. + /// + /// The field data type. + /// Whether the field is a collection of . + public SimpleFieldAttribute(SearchFieldDataType type, bool collection = false) + { + Type = collection ? SearchFieldDataType.Collection(type) : type; + } + + /// + /// Gets the field data type. + /// + public SearchFieldDataType Type { get; } + + /// + /// Gets or sets whether the field is the key field. The default is false. + /// A must have exactly one key field of type . + /// + public bool IsKey { get; set; } + + /// + /// Gets or sets whether the field is returned in search results. The default is false. + /// A key field where is true must have this property set to false. + /// + public bool IsHidden { get; set; } + + /// + /// Gets or sets a value indicating whether the field can be referenced in $filter queries. The default is false. + /// + /// + /// Filterable differs from searchable in how strings are handled. Fields of type or "Collection(DataType.String)" that are filterable do not undergo word-breaking, so comparisons are for exact matches only. + /// For example, if you set such a field f to "sunny day", $filter=f eq 'sunny' will find no matches, but $filter=f eq 'sunny day' will. + /// + public bool IsFilterable { get; set; } + + /// + /// Gets or sets a value indicating whether the field can be retrieved in facet queries. The default is false. + /// + /// + /// Facets are used in presentation of search results that include hit counts by categories. + /// For example, in a search for digital cameras, facets might include branch, megapixels, price, etc. + /// + public bool IsFacetable { get; set; } + + /// + /// Gets or sets a value indicating whether to enable the field can be referenced in $orderby expressions. The default is false. + /// + /// + /// By default Azure Cognitive Search sorts results by score, but in many experiences users may want to sort by fields in the documents. + /// + public bool IsSortable { get; set; } + + /// + SearchField ISearchFieldAttribute.CreateField(string name) => new SimpleField(name, Type) + { + IsKey = IsKey, + IsHidden = IsHidden, + IsFilterable = IsFilterable, + IsFacetable = IsFacetable, + IsSortable = IsSortable, + }; + } +} diff --git a/sdk/search/Azure.Search.Documents/src/SearchClient.cs b/sdk/search/Azure.Search.Documents/src/SearchClient.cs index a99bdeaede74b..9b79551c95c48 100644 --- a/sdk/search/Azure.Search.Documents/src/SearchClient.cs +++ b/sdk/search/Azure.Search.Documents/src/SearchClient.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using Azure.Core; using Azure.Core.Pipeline; +using Azure.Search.Documents.Indexes; using Azure.Search.Documents.Models; namespace Azure.Search.Documents diff --git a/sdk/search/Azure.Search.Documents/tests/FieldBuilderTests.cs b/sdk/search/Azure.Search.Documents/tests/FieldBuilderTests.cs new file mode 100644 index 0000000000000..6e699c48d6ecd --- /dev/null +++ b/sdk/search/Azure.Search.Documents/tests/FieldBuilderTests.cs @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Azure.Search.Documents.Indexes; +using NUnit.Framework; + +namespace Azure.Search.Documents.Tests +{ + public class FieldBuilderTests + { + [Test] + public void BuildTThrowsTypeNull() + { + ArgumentNullException ex = Assert.Throws(() => FieldBuilder.Build(null)); + Assert.AreEqual("namingPolicy", ex.ParamName); + } + + [Test] + public void BuildThrowsTypeNull() + { + ArgumentNullException ex = Assert.Throws(() => FieldBuilder.Build(null)); + Assert.AreEqual("type", ex.ParamName); + } + + [Test] + public void BuildThrowsNamingPolicyNull() + { + ArgumentNullException ex = Assert.Throws(() => FieldBuilder.Build(typeof(FieldBuilderTests), null)); + Assert.AreEqual("namingPolicy", ex.ParamName); + } + + // TODO: Add more tests when FieldBuilder is implemented thoroughly. + } +} diff --git a/sdk/search/Azure.Search.Documents/tests/Samples/HelloWorld.cs b/sdk/search/Azure.Search.Documents/tests/Samples/HelloWorld.cs index 1ff972f06d41d..c999d1efaff9a 100644 --- a/sdk/search/Azure.Search.Documents/tests/Samples/HelloWorld.cs +++ b/sdk/search/Azure.Search.Documents/tests/Samples/HelloWorld.cs @@ -6,6 +6,7 @@ using Azure.Core.TestFramework; #region Snippet:Azure_Search_Tests_Samples_Namespaces using Azure.Search.Documents; +using Azure.Search.Documents.Indexes; using Azure.Search.Documents.Indexes.Models; #endregion Snippet:Azure_Search_Tests_Samples_Namespaces using NUnit.Framework; diff --git a/sdk/search/Azure.Search.Documents/tests/Samples/Readme.cs b/sdk/search/Azure.Search.Documents/tests/Samples/Readme.cs index 7f5a1a0a7fb5b..6ec452d2f365b 100644 --- a/sdk/search/Azure.Search.Documents/tests/Samples/Readme.cs +++ b/sdk/search/Azure.Search.Documents/tests/Samples/Readme.cs @@ -12,6 +12,7 @@ #region Snippet:Azure_Search_Tests_Samples_Readme_Namespace using Azure; using Azure.Search.Documents; +using Azure.Search.Documents.Indexes; #endregion Snippet:Azure_Search_Tests_Samples_Readme_Namespace namespace Azure.Search.Documents.Tests.Samples diff --git a/sdk/search/Azure.Search.Documents/tests/SearchIndexClientTests.cs b/sdk/search/Azure.Search.Documents/tests/SearchIndexClientTests.cs index 5a7040c051771..f492c83749213 100644 --- a/sdk/search/Azure.Search.Documents/tests/SearchIndexClientTests.cs +++ b/sdk/search/Azure.Search.Documents/tests/SearchIndexClientTests.cs @@ -8,6 +8,7 @@ using Azure.Core; using Azure.Core.Pipeline; using Azure.Core.TestFramework; +using Azure.Search.Documents.Indexes; using Azure.Search.Documents.Indexes.Models; using NUnit.Framework; diff --git a/sdk/search/Azure.Search.Documents/tests/SearchIndexerClientTests.cs b/sdk/search/Azure.Search.Documents/tests/SearchIndexerClientTests.cs index ece0257da76e9..a1082c811140b 100644 --- a/sdk/search/Azure.Search.Documents/tests/SearchIndexerClientTests.cs +++ b/sdk/search/Azure.Search.Documents/tests/SearchIndexerClientTests.cs @@ -7,6 +7,7 @@ using System.Threading; using System.Threading.Tasks; using Azure.Core.TestFramework; +using Azure.Search.Documents.Indexes; using Azure.Search.Documents.Indexes.Models; using NUnit.Framework; diff --git a/sdk/search/Azure.Search.Documents/tests/SearchableFieldAttributeTests.cs b/sdk/search/Azure.Search.Documents/tests/SearchableFieldAttributeTests.cs new file mode 100644 index 0000000000000..144990379ced5 --- /dev/null +++ b/sdk/search/Azure.Search.Documents/tests/SearchableFieldAttributeTests.cs @@ -0,0 +1,71 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Azure.Search.Documents.Indexes; +using Azure.Search.Documents.Indexes.Models; +using NUnit.Framework; + +namespace Azure.Search.Documents.Tests +{ + public class SearchableFieldAttributeTests + { + [Test] + public void CreatesEquivalentField( + [Values] bool collection, + [Values] bool key, + [Values] bool hidden, + [Values] bool filterable, + [Values] bool facetable, + [Values] bool sortable, + [Values(null, "AnalyzerName")] string analyzerName, + [Values(null, "SearchAnalyzerName")] string searchAnalyzerName, + [Values(null, "IndexAnalyzerName")] string indexAnalyzerName, + [Values(null, new[] { "synonynMapName" })] string[] synonymMapNames) + { + SearchableFieldAttribute sut = new SearchableFieldAttribute(collection) + { + IsKey = key, + IsHidden = hidden, + IsFilterable = filterable, + IsFacetable = facetable, + IsSortable = sortable, + }; + + if (analyzerName != null) + { + sut.AnalyzerName = analyzerName; + } + + if (searchAnalyzerName != null) + { + sut.SearchAnalyzerName = searchAnalyzerName; + } + + if (indexAnalyzerName != null) + { + sut.IndexAnalyzerName = indexAnalyzerName; + } + + if (synonymMapNames != null) + { + sut.SynonymMapNames = synonymMapNames; + } + + SearchFieldDataType actualType = collection ? SearchFieldDataType.Collection(SearchFieldDataType.String) : SearchFieldDataType.String; + Assert.AreEqual(actualType, sut.Type); + + SearchField field = ((ISearchFieldAttribute)sut).CreateField("test"); + Assert.AreEqual("test", field.Name); + Assert.AreEqual(actualType, field.Type); + Assert.AreEqual(key, field.IsKey); + Assert.AreEqual(hidden, field.IsHidden); + Assert.AreEqual(filterable, field.IsFilterable); + Assert.AreEqual(facetable, field.IsFacetable); + Assert.AreEqual(sortable, field.IsSortable); + Assert.AreEqual(analyzerName, field.AnalyzerName?.ToString()); + Assert.AreEqual(searchAnalyzerName, field.SearchAnalyzerName?.ToString()); + Assert.AreEqual(indexAnalyzerName, field.IndexAnalyzerName?.ToString()); + Assert.AreEqual(synonymMapNames, field.SynonymMapNames); + } + } +} diff --git a/sdk/search/Azure.Search.Documents/tests/SimpleFieldAttributeTests.cs b/sdk/search/Azure.Search.Documents/tests/SimpleFieldAttributeTests.cs new file mode 100644 index 0000000000000..f925f1de6b741 --- /dev/null +++ b/sdk/search/Azure.Search.Documents/tests/SimpleFieldAttributeTests.cs @@ -0,0 +1,45 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Azure.Core.TestFramework; +using Azure.Search.Documents.Indexes; +using Azure.Search.Documents.Indexes.Models; +using NUnit.Framework; + +namespace Azure.Search.Documents.Tests +{ + public class SimpleFieldAttributeTests + { + [Test] + public void CreatesEquivalentField( + [EnumValues] SearchFieldDataType type, + [Values] bool collection, + [Values] bool key, + [Values] bool hidden, + [Values] bool filterable, + [Values] bool facetable, + [Values] bool sortable) + { + SimpleFieldAttribute sut = new SimpleFieldAttribute(type, collection) + { + IsKey = key, + IsHidden = hidden, + IsFilterable = filterable, + IsFacetable = facetable, + IsSortable = sortable, + }; + + SearchFieldDataType actualType = collection ? SearchFieldDataType.Collection(type) : type; + Assert.AreEqual(actualType, sut.Type); + + SearchField field = ((ISearchFieldAttribute)sut).CreateField("test"); + Assert.AreEqual("test", field.Name); + Assert.AreEqual(actualType, field.Type); + Assert.AreEqual(key, field.IsKey); + Assert.AreEqual(hidden, field.IsHidden); + Assert.AreEqual(filterable, field.IsFilterable); + Assert.AreEqual(facetable, field.IsFacetable); + Assert.AreEqual(sortable, field.IsSortable); + } + } +} diff --git a/sdk/search/Azure.Search.Documents/tests/Utilities/SearchResources.cs b/sdk/search/Azure.Search.Documents/tests/Utilities/SearchResources.cs index 6c978992f8de3..d9a41f6088423 100644 --- a/sdk/search/Azure.Search.Documents/tests/Utilities/SearchResources.cs +++ b/sdk/search/Azure.Search.Documents/tests/Utilities/SearchResources.cs @@ -9,10 +9,10 @@ using System.Threading; using System.Threading.Tasks; using Azure.Core.TestFramework; +using Azure.Search.Documents.Indexes; using Azure.Search.Documents.Models; using Azure.Storage.Blobs; using NUnit.Framework; -using NUnit.Framework.Internal; namespace Azure.Search.Documents.Tests {