Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,16 @@
- Prefer var over explicit types.
- Employ dependency injection using the built-in DI container.
- Handle exceptions gracefully and use `Microsoft.Extensions.Logging` for logging.
- This is a Xperience By Kentico library, and as such should leverage built in api as much as possible.

## Testing Guidelnes

- Use the AAA paattern (Arrange, Act, Assert)
- Use the AAA pattern (Arrange, Act, Assert)
- Avoid infrastructure dependencies.
- Name tests clearly.
- Write minimally passing tests.
- Avoid magic strings.
- Avoid logic in tests.
- Prefer helper methods for setup and teardown.
- Avoid multiple acts in a single test.
- Write unit tests using **NUnit** and aim for high code coverage.

## Project-specific instructions

- Utilize Xperience by Kentico API for database interactions if applicable.
- Write unit tests using **NUnit** and aim for high code coverage.
6 changes: 3 additions & 3 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<DisableImplicitNuGetFallbackFolder>true</DisableImplicitNuGetFallbackFolder>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="SonarAnalyzer.CSharp" Version="[10.4.0.108396,)" />
<PackageVersion Include="SonarAnalyzer.CSharp" Version="10.5.0.109200" />
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="[8.0.0.0,)" />
<PackageVersion Include="Kentico.Xperience.Core" Version="[29.6.0,)" />
</ItemGroup>
Expand All @@ -15,9 +15,9 @@
<PackageVersion Include="NSubstitute" Version="[5.3.0,)" />
<PackageVersion Include="NSubstitute.Analyzers.CSharp" Version="[1.0.17,)" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="[17.12.0,)" />
<PackageVersion Include="coverlet.collector" Version="[6.0.3,)" />
<PackageVersion Include="coverlet.collector" Version="6.0.4" />
<PackageVersion Include="NUnit" Version="[4.3.2,)" />
<PackageVersion Include="NUnit.Analyzers" Version="[4.5.0,)" />
<PackageVersion Include="NUnit.Analyzers" Version="4.6.0" />
<PackageVersion Include="NUnit3TestAdapter" Version="[4.6.0,)" />
<PackageVersion Include="Kentico.Xperience.Core" Version="[29.6.0,)" />
</ItemGroup>
Expand Down
1 change: 0 additions & 1 deletion src/XperienceCommunity.DataRepository/BaseRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@ protected async Task<IEnumerable<T>> ExecutePageQuery<T>(ContentItemQueryBuilder
return result;
}


if (dependencyFunc is not null)
{
cs.CacheDependency = dependencyFunc.Invoke();
Expand Down
52 changes: 26 additions & 26 deletions src/XperienceCommunity.DataRepository/ContentTypeRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,10 @@ public async Task<IEnumerable<TEntity>> GetAllAsync(IEnumerable<Guid> nodeGuid,
var builder = new ContentItemQueryBuilder();

builder.ForContentType<TEntity>(config => config
.When(maxLinkedItems > 0, linkOptions => linkOptions.WithLinkedItems(maxLinkedItems))
.Where(where => where.WhereIn(nameof(IContentItemFieldsSource.SystemFields.ContentItemGUID),
guidList))).When(!string.IsNullOrEmpty(languageName), lang => lang.InLanguage(languageName));
.WithLinkedItemsAndWebPageData(maxLinkedItems)
.Where(where => where.WhereIn(nameof(IContentItemFieldsSource.SystemFields.ContentItemGUID),
guidList)))
.WithLanguage(languageName);

var result = await ExecuteContentQuery<TEntity>(builder, dependencyFunc,
cancellationToken, CachePrefix, nameof(GetAllAsync), guidList, maxLinkedItems);
Expand All @@ -69,9 +70,9 @@ public async Task<IEnumerable<TEntity>> GetAllAsync(IEnumerable<int> itemIds, st
var builder = new ContentItemQueryBuilder();

builder.ForContentType<TEntity>(config => config
.When(maxLinkedItems > 0, linkOptions => linkOptions.WithLinkedItems(maxLinkedItems))
.WithLinkedItemsAndWebPageData(maxLinkedItems)
.Where(where => where.WhereIn(nameof(IContentItemFieldsSource.SystemFields.ContentItemID), idList)))
.When(!string.IsNullOrEmpty(languageName), lang => lang.InLanguage(languageName));
.WithLanguage(languageName);

var result = await ExecuteContentQuery<TEntity>(builder, dependencyFunc,
cancellationToken, CachePrefix, nameof(GetAllAsync), idList, maxLinkedItems);
Expand All @@ -88,8 +89,9 @@ public async Task<IEnumerable<TEntity>> GetAllAsync(string? languageName, int ma
var builder = new ContentItemQueryBuilder();

builder.ForContentType<TEntity>(config =>
config.When(maxLinkedItems > 0, linkOptions => linkOptions.WithLinkedItems(maxLinkedItems)))
.When(!string.IsNullOrEmpty(languageName), lang => lang.InLanguage(languageName));
config
.WithLinkedItemsAndWebPageData(maxLinkedItems))
.WithLanguage(languageName);

var result = await ExecuteContentQuery<TEntity>(builder, dependencyFunc,
cancellationToken, CachePrefix, nameof(GetAllAsync), contentType, maxLinkedItems);
Expand All @@ -108,11 +110,10 @@ public async Task<IEnumerable<TSchema>> GetAllBySchema<TSchema>(string? language
var builder = new ContentItemQueryBuilder();

builder.ForContentTypes(parameters => parameters
.When(maxLinkedItems > 0, linkItemOptions => linkItemOptions.WithLinkedItems(maxLinkedItems))
.WithLinkedItemsAndWebPageData(maxLinkedItems)
.OfReusableSchema(schemaName)
.WithContentTypeFields())
.When(!string.IsNullOrEmpty(languageName),
lang => lang.InLanguage(languageName));
.WithLanguage(languageName);

var result = await ExecuteContentQuery<TSchema>(builder,
() => CacheHelper.GetCacheDependency($"{schemaName}|all"),
Expand All @@ -130,11 +131,11 @@ public async Task<IEnumerable<TSchema>> GetAllBySchema<TSchema>(string? language
var builder = new ContentItemQueryBuilder();

builder.ForContentType<TEntity>(config => config
.When(maxLinkedItems > 0, linkOptions => linkOptions.WithLinkedItems(maxLinkedItems))
.WithLinkedItemsAndWebPageData(maxLinkedItems)
.Where(where =>
where.WhereEquals(nameof(IContentItemFieldsSource.SystemFields.ContentItemGUID), itemGuid))
.TopN(1))
.When(!string.IsNullOrEmpty(languageName), lang => lang.InLanguage(languageName));
.WithLanguage(languageName);

var result = await ExecuteContentQuery<TEntity>(builder, dependencyFunc,
cancellationToken, CachePrefix, nameof(GetByIdAsync), itemGuid, maxLinkedItems);
Expand All @@ -150,11 +151,11 @@ public async Task<IEnumerable<TSchema>> GetAllBySchema<TSchema>(string? language
var builder = new ContentItemQueryBuilder();

builder.ForContentType<TEntity>(config => config
.When(maxLinkedItems > 0, linkOptions => linkOptions.WithLinkedItems(maxLinkedItems))
.WithLinkedItemsAndWebPageData(maxLinkedItems)
.Where(where =>
where.WhereEquals(nameof(IContentItemFieldsSource.SystemFields.ContentItemID), id))
.TopN(1))
.When(!string.IsNullOrEmpty(languageName), lang => lang.InLanguage(languageName));
.WithLanguage(languageName);

var result = await ExecuteContentQuery<TEntity>(builder, dependencyFunc,
cancellationToken, CachePrefix, nameof(GetByIdAsync), id, maxLinkedItems);
Expand All @@ -169,11 +170,11 @@ public async Task<IEnumerable<TSchema>> GetAllBySchema<TSchema>(string? language
var builder = new ContentItemQueryBuilder();

builder.ForContentType<TEntity>(config => config
.When(maxLinkedItems > 0, linkOptions => linkOptions.WithLinkedItems(maxLinkedItems))
.WithLinkedItemsAndWebPageData(maxLinkedItems)
.Where(where => where
.WhereEquals(nameof(IContentQueryDataContainer.ContentItemGUID), id))
.TopN(1))
.When(!string.IsNullOrEmpty(languageName), lang => lang.InLanguage(languageName));
.WithLanguage(languageName);

var result = await ExecuteContentQuery<TEntity>(builder, dependencyFunc,
cancellationToken, CachePrefix, nameof(GetByIdentifierAsync), id, maxLinkedItems);
Expand All @@ -189,11 +190,11 @@ public async Task<IEnumerable<TSchema>> GetAllBySchema<TSchema>(string? language

builder.ForContentType<TEntity>(query =>
query
.When(maxLinkedItems > 0, linkOptions => linkOptions.WithLinkedItems(maxLinkedItems))
.WithLinkedItemsAndWebPageData(maxLinkedItems)
.Where(where =>
where.WhereEquals(nameof(IContentItemFieldsSource.SystemFields.ContentItemName), name))
.TopN(1))
.When(!string.IsNullOrEmpty(languageName), lang => lang.InLanguage(languageName));
.WithLanguage(languageName);

var result = await ExecuteContentQuery<TEntity>(builder, dependencyFunc,
cancellationToken, CachePrefix, nameof(GetByNameAsync), name, maxLinkedItems);
Expand All @@ -210,7 +211,7 @@ public async Task<IEnumerable<TEntity>> GetBySmartFolderGuidAsync(Guid smartFold
var builder = new ContentItemQueryBuilder();

builder.ForContentTypes(config => config
.When(maxLinkedItems > 0, linkOptions => linkOptions.WithLinkedItems(maxLinkedItems))
.WithLinkedItemsAndWebPageData(maxLinkedItems)
.OfContentType(contentType)
.InSmartFolder(smartFolderId));

Expand All @@ -229,7 +230,7 @@ public async Task<IEnumerable<TEntity>> GetBySmartFolderIdAsync(int smartFolderI
var builder = new ContentItemQueryBuilder();

builder.ForContentTypes(config => config
.When(maxLinkedItems > 0, linkOptions => linkOptions.WithLinkedItems(maxLinkedItems))
.WithLinkedItemsAndWebPageData(maxLinkedItems)
.OfContentType(contentType)
.InSmartFolder(smartFolderId));

Expand All @@ -255,7 +256,7 @@ public async Task<IEnumerable<IContentItemFieldsSource>> GetBySmartFolderIdAsync
var builder = new ContentItemQueryBuilder();

builder.ForContentTypes(config => config
.When(maxLinkedItems > 0, linkOptions => linkOptions.WithLinkedItems(maxLinkedItems))
.WithLinkedItemsAndWebPageData(maxLinkedItems)
.OfContentType(contentTypes)
.InSmartFolder(smartFolderId));

Expand Down Expand Up @@ -284,7 +285,7 @@ public async Task<IEnumerable<IContentItemFieldsSource>> GetBySmartFolderIdAsync
var builder = new ContentItemQueryBuilder();

builder.ForContentTypes(config => config
.When(maxLinkedItems > 0, linkOptions => linkOptions.WithLinkedItems(maxLinkedItems))
.WithLinkedItemsAndWebPageData(maxLinkedItems)
.OfContentType(contentTypes)
.InSmartFolder(smartFolderId));

Expand Down Expand Up @@ -314,7 +315,7 @@ public async Task<IEnumerable<IContentItemFieldsSource>> GetBySmartFolderIdAsync
var builder = new ContentItemQueryBuilder();

builder.ForContentTypes(config => config
.When(maxLinkedItems > 0, linkOptions => linkOptions.WithLinkedItems(maxLinkedItems))
.WithLinkedItemsAndWebPageData(maxLinkedItems)
.OfContentType(contentTypes)
.InSmartFolder(smartFolderId));

Expand Down Expand Up @@ -344,7 +345,7 @@ public async Task<IEnumerable<IContentItemFieldsSource>> GetBySmartFolderIdAsync
var builder = new ContentItemQueryBuilder();

builder.ForContentTypes(config => config
.When(maxLinkedItems > 0, linkOptions => linkOptions.WithLinkedItems(maxLinkedItems))
.WithLinkedItemsAndWebPageData(maxLinkedItems)
.OfContentType(contentTypes)
.InSmartFolder(smartFolderId));

Expand Down Expand Up @@ -374,8 +375,7 @@ public async Task<IEnumerable<TEntity>> GetByTagsAsync(string columnName, IEnume

builder.ForContentType<TEntity>(config =>
config
.When(maxLinkedItems > 0, options => options.WithLinkedItems(maxLinkedItems,
linkOptions => linkOptions.IncludeWebPageData()))
.WithLinkedItemsAndWebPageData(maxLinkedItems)
.Where(where => where.WhereContainsTags(columnName, tagIdents)));

var result = await ExecuteContentQuery<TEntity>(builder, dependencyFunc,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,17 @@ public static ContentItemQueryBuilder When(this ContentItemQueryBuilder source,

return source;
}

/// <summary>
/// Configures the <see cref="ContentItemQueryBuilder"/> to filter by the specified language.
/// </summary>
/// <param name="source">The <see cref="ContentItemQueryBuilder"/> to apply the action to.</param>
/// <param name="language">The language name.</param>
/// <returns>The original <see cref="ContentItemQueryBuilder"/> with the action applied.</returns>
public static ContentItemQueryBuilder WithLanguage(this ContentItemQueryBuilder source, string? language)
{
source.When(!string.IsNullOrEmpty(language), q => q.InLanguage(language));

return source;
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,25 @@
using CMS.ContentEngine;
using CMS.DataEngine;
using CMS.Websites;

namespace XperienceCommunity.DataRepository.Extensions;

public static class ContentTypeParametersExtensions
{

/// <summary>
/// Orders the <see cref="ContentTypeQueryParameters"/> instance by the WebPageItemOrder field in ascending order.
/// </summary>
/// <param name="source">The <see cref="ContentTypeQueryParameters"/> instance.</param>
/// <returns>The <see cref="ContentTypeQueryParameters"/> instance ordered by WebPageItemOrder.</returns>
public static ContentTypeQueryParameters OrderByWebPageItemOrder(this ContentTypeQueryParameters source)
{
source
.OrderBy(OrderByColumn.Asc(nameof(IWebPageFieldsSource.SystemFields.WebPageItemOrder)));

return source;
}

/// <summary>
/// Conditionally applies an action to the <see cref="ContentTypeQueryParameters"/> instance.
/// </summary>
Expand Down Expand Up @@ -39,4 +55,32 @@ public static ContentTypesQueryParameters When(this ContentTypesQueryParameters

return source;
}

/// <summary>
/// Configures the <see cref="ContentTypesQueryParameters"/> instance to include linked items and web page data.
/// </summary>
/// <param name="source">The <see cref="ContentTypesQueryParameters"/> instance.</param>
/// <param name="maxLinkedItems">The maximum number of linked items to include.</param>
/// <returns>The <see cref="ContentTypesQueryParameters"/> instance.</returns>
public static ContentTypesQueryParameters WithLinkedItemsAndWebPageData(this ContentTypesQueryParameters source, int maxLinkedItems)
{
source.When(maxLinkedItems > 0, options => options.WithLinkedItems(maxLinkedItems,
linkOptions => linkOptions.IncludeWebPageData()));

return source;
}

/// <summary>
/// Configures the <see cref="ContentTypesQueryParameters"/> instance to include linked items and web page data.
/// </summary>
/// <param name="source">The <see cref="ContentTypesQueryParameters"/> instance.</param>
/// <param name="maxLinkedItems">The maximum number of linked items to include.</param>
/// <returns>The <see cref="ContentTypesQueryParameters"/> instance.</returns>
public static ContentTypeQueryParameters WithLinkedItemsAndWebPageData(this ContentTypeQueryParameters source, int maxLinkedItems)
{
source.When(maxLinkedItems > 0, options => options.WithLinkedItems(maxLinkedItems,
linkOptions => linkOptions.IncludeWebPageData()));

return source;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ public static class IContentItemFieldsSourceExtensions
/// <returns>An enumerable containing the content item IDs.</returns>
public static IEnumerable<int> GetContentItemIds(this IEnumerable<IContentItemFieldsSource>? source) => source?.Select(x => x.SystemFields.ContentItemID) ?? [];

/// <summary>
/// Gets the content item GUIDs from the specified collection of content item fields sources.
/// </summary>
/// <param name="source">The collection of content item fields sources.</param>
/// <returns>An enumerable containing the content item GUIDs.</returns>
public static IEnumerable<Guid> GetContentItemGUIDs(this IEnumerable<IContentItemFieldsSource>? source) => source?.Select(x => x.SystemFields.ContentItemGUID) ?? [];

/// <summary>
/// Gets the content types from the specified collection of content item fields sources.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,10 @@ public static class IWebPageFieldsSourceExtensions
/// <returns>An enumerable containing the web page item IDs.</returns>
public static IEnumerable<int> GetWebPageItemIds(this IEnumerable<IWebPageFieldsSource>? source) => source?.Select(x => x.SystemFields.WebPageItemID) ?? [];

/// <summary>
/// Gets the web page item GUIDs for the specified collection of <see cref="IWebPageFieldsSource"/>.
/// </summary>
/// <param name="source">The collection of sources to get the web page item GUIDs for.</param>
/// <returns>An enumerable containing the web page item GUIDs.</returns>
public static IEnumerable<Guid> GetWebPageItemGuids(this IEnumerable<IWebPageFieldsSource>? source) => source?.Select(x => x.SystemFields.WebPageItemGUID) ?? [];
}
Loading