diff --git a/src/Umbraco.Examine.Lucene/DependencyInjection/ConfigureIndexOptions.cs b/src/Umbraco.Examine.Lucene/DependencyInjection/ConfigureIndexOptions.cs index 2b5bc771f1..1dd2ed3e25 100644 --- a/src/Umbraco.Examine.Lucene/DependencyInjection/ConfigureIndexOptions.cs +++ b/src/Umbraco.Examine.Lucene/DependencyInjection/ConfigureIndexOptions.cs @@ -10,7 +10,7 @@ using Umbraco.Cms.Core.Configuration.Models; namespace Umbraco.Cms.Infrastructure.Examine.DependencyInjection; /// -/// Configures the index options to construct the Examine indexes +/// Configures the index options to construct the Examine indexes. /// public sealed class ConfigureIndexOptions : IConfigureNamedOptions { @@ -18,6 +18,9 @@ public sealed class ConfigureIndexOptions : IConfigureNamedOptions + /// Initializes a new instance of the class. + /// public ConfigureIndexOptions( IUmbracoIndexConfig umbracoIndexConfig, IOptions settings, @@ -28,24 +31,27 @@ public sealed class ConfigureIndexOptions : IConfigureNamedOptions public void Configure(string? name, LuceneDirectoryIndexOptions options) { + // When creating FieldDefinitions with Umbraco defaults, pass in any already defined to avoid overwriting + // those added via a package or custom code. switch (name) { case Constants.UmbracoIndexes.InternalIndexName: options.Analyzer = new CultureInvariantWhitespaceAnalyzer(); options.Validator = _umbracoIndexConfig.GetContentValueSetValidator(); - options.FieldDefinitions = new UmbracoFieldDefinitionCollection(); + options.FieldDefinitions = new UmbracoFieldDefinitionCollection(options.FieldDefinitions); break; case Constants.UmbracoIndexes.ExternalIndexName: options.Analyzer = new StandardAnalyzer(LuceneInfo.CurrentVersion); options.Validator = _umbracoIndexConfig.GetPublishedContentValueSetValidator(); - options.FieldDefinitions = new UmbracoFieldDefinitionCollection(); + options.FieldDefinitions = new UmbracoFieldDefinitionCollection(options.FieldDefinitions); break; case Constants.UmbracoIndexes.MembersIndexName: options.Analyzer = new CultureInvariantWhitespaceAnalyzer(); options.Validator = _umbracoIndexConfig.GetMemberValueSetValidator(); - options.FieldDefinitions = new UmbracoFieldDefinitionCollection(); + options.FieldDefinitions = new UmbracoFieldDefinitionCollection(options.FieldDefinitions); break; case Constants.UmbracoIndexes.DeliveryApiContentIndexName: options.Analyzer = new StandardAnalyzer(LuceneInfo.CurrentVersion); @@ -64,6 +70,7 @@ public sealed class ConfigureIndexOptions : IConfigureNamedOptions public void Configure(LuceneDirectoryIndexOptions options) => throw new NotImplementedException("This is never called and is just part of the interface"); } diff --git a/src/Umbraco.Infrastructure/Examine/UmbracoFieldDefinitionCollection.cs b/src/Umbraco.Infrastructure/Examine/UmbracoFieldDefinitionCollection.cs index f2c6236a2e..75a1cfe197 100644 --- a/src/Umbraco.Infrastructure/Examine/UmbracoFieldDefinitionCollection.cs +++ b/src/Umbraco.Infrastructure/Examine/UmbracoFieldDefinitionCollection.cs @@ -30,11 +30,29 @@ public class UmbracoFieldDefinitionCollection : FieldDefinitionCollection new(UmbracoExamineFieldNames.VariesByCultureFieldName, FieldDefinitionTypes.Raw), }; + /// + /// Initializes a new instance of the class containing + /// the default Umbraco field definitions. + /// public UmbracoFieldDefinitionCollection() : base(UmbracoIndexFieldDefinitions) { } + /// + /// Initializes a new instance of the class containing the containing + /// the default Umbraco field definitions, augmented or overridden by the provided definitions. + /// + /// Existing collection of field definitions. + public UmbracoFieldDefinitionCollection(FieldDefinitionCollection definitions) + : base(UmbracoIndexFieldDefinitions) + { + foreach (FieldDefinition definition in definitions) + { + AddOrUpdate(definition); + } + } + /// /// Overridden to dynamically add field definitions for culture variations /// diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Examine/UmbracoFieldDefinitionCollectionTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Examine/UmbracoFieldDefinitionCollectionTests.cs new file mode 100644 index 0000000000..98832e2bf1 --- /dev/null +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Examine/UmbracoFieldDefinitionCollectionTests.cs @@ -0,0 +1,75 @@ +using Examine; +using NUnit.Framework; +using Umbraco.Cms.Infrastructure.Examine; + +namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Examine; + +[TestFixture] +internal class UmbracoFieldDefinitionCollectionTests +{ + [Test] + public void Create_Contains_Expected_Fields() + { + var collection = new UmbracoFieldDefinitionCollection(); + AssertDefaultField(collection); + } + + [Test] + public void Create_New_Contains_Expected_Fields() + { + var collection = new UmbracoFieldDefinitionCollection(); + collection.AddOrUpdate(new FieldDefinition("customField", "string")); + var collectionCount = collection.Count; + + collection = new UmbracoFieldDefinitionCollection(); + Assert.AreEqual(collectionCount - 1, collection.Count); + AssertDefaultField(collection); + AssertCustomField(collection, expectExists: false); + } + + [Test] + public void Create_With_Existing_Contains_Expected_Fields() + { + var collection = new UmbracoFieldDefinitionCollection(); + collection.AddOrUpdate(new FieldDefinition("customField", "string")); + var collectionCount = collection.Count; + + collection = new UmbracoFieldDefinitionCollection(collection); + Assert.AreEqual(collectionCount, collection.Count); + AssertDefaultField(collection); + AssertCustomField(collection, expectExists: true); + } + + [Test] + public void Create_With_Existing_Retains_Override_Of_DefaultField() + { + var collection = new UmbracoFieldDefinitionCollection(); + collection.AddOrUpdate(new FieldDefinition("parentID", "string")); + + collection = new UmbracoFieldDefinitionCollection(collection); + AssertDefaultField(collection, "string"); + } + + private static void AssertDefaultField(UmbracoFieldDefinitionCollection collection, string expectedType = "int") + { + var field = collection.SingleOrDefault(x => x.Name == "parentID"); + Assert.IsNotNull(field); + Assert.AreEqual("parentID", field.Name); + Assert.AreEqual(expectedType, field.Type); + } + + private static void AssertCustomField(UmbracoFieldDefinitionCollection collection, bool expectExists) + { + var field = collection.SingleOrDefault(x => x.Name == "customField"); + if (expectExists is false) + { + Assert.IsNull(field.Name); + Assert.IsNull(field.Type); + return; + } + + Assert.IsNotNull(field); + Assert.AreEqual("customField", field.Name); + Assert.AreEqual("string", field.Type); + } +}