From 840307fe4ab0efb6056a656c0e39186d5572b105 Mon Sep 17 00:00:00 2001 From: Hinton Date: Thu, 13 Nov 2025 11:45:11 +0100 Subject: [PATCH] Document queries and scenes --- util/Seeder/IQuery.cs | 45 ++++++++++++ util/Seeder/IScene.cs | 68 ++++++++++++++++++- .../Queries/EmergencyAccessInviteQuery.cs | 3 + util/Seeder/Scenes/SingleUserScene.cs | 3 + 4 files changed, 118 insertions(+), 1 deletion(-) diff --git a/util/Seeder/IQuery.cs b/util/Seeder/IQuery.cs index 7405208a40..adbcd8e59d 100644 --- a/util/Seeder/IQuery.cs +++ b/util/Seeder/IQuery.cs @@ -1,15 +1,60 @@ namespace Bit.Seeder; +/// +/// Base interface for query operations in the seeding system. The base interface should not be used directly, rather use `IQuery<TRequest, TResult>`. +/// +/// +/// Queries are synchronous, read-only operations that retrieve data from the seeding context. +/// Unlike scenes which create data, queries fetch existing data based on request parameters. +/// They follow a type-safe pattern using generics to ensure proper request/response handling +/// while maintaining a common non-generic interface for dynamic invocation. +/// public interface IQuery { + /// + /// Gets the type of request this query expects. + /// + /// The request type that this query can process. Type GetRequestType(); + + /// + /// Executes the query based on the provided request object. + /// + /// The request object containing parameters for the query operation. + /// The query result data as an object. object Execute(object request); } +/// +/// Generic query interface for synchronous, read-only operations with specific request and result types. +/// +/// The type of request object this query accepts. +/// The type of data this query returns. +/// +/// Use this interface when you need to retrieve existing data from the seeding context based on +/// specific request parameters. Queries are synchronous and do not modify data - they only read +/// and return information. The explicit interface implementations allow dynamic invocation while +/// maintaining type safety in the implementation. +/// public interface IQuery : IQuery where TRequest : class where TResult : class { + /// + /// Executes the query based on the provided strongly-typed request and returns typed result data. + /// + /// The request object containing parameters for the query operation. + /// The typed query result data. TResult Execute(TRequest request); + /// + /// Gets the request type for this query. + /// + /// The type of TRequest. Type IQuery.GetRequestType() => typeof(TRequest); + + /// + /// Adapts the non-generic Execute to the strongly-typed version. + /// + /// The request object to cast and process. + /// The typed result cast to object. object IQuery.Execute(object request) => Execute((TRequest)request); } diff --git a/util/Seeder/IScene.cs b/util/Seeder/IScene.cs index 257f475409..6f513973ba 100644 --- a/util/Seeder/IScene.cs +++ b/util/Seeder/IScene.cs @@ -1,19 +1,59 @@ namespace Bit.Seeder; +/// +/// Base interface for seeding operations. The base interface should not be used directly, rather use `IScene<Request>`. +/// +/// +/// Scenes are components in the seeding system that create and configure test data. They follow +/// a type-safe pattern using generics to ensure proper request/response handling while maintaining +/// a common non-generic interface for dynamic invocation. +/// public interface IScene { + /// + /// Gets the type of request this scene expects. + /// + /// The request type that this scene can process. Type GetRequestType(); + + /// + /// Seeds data based on the provided request object. + /// + /// The request object containing parameters for the seeding operation. + /// A scene result containing any returned data, mangle map, and entity tracking information. Task> SeedAsync(object request); } /// /// Generic scene interface for seeding operations with a specific request type. Does not return a value beyond tracking entities and a mangle map. /// -/// +/// The type of request object this scene accepts. +/// +/// Use this interface when your scene needs to process a specific request type but doesn't need to +/// return any data beyond the standard mangle map for ID transformations and entity tracking. +/// The explicit interface implementations allow this scene to be invoked dynamically through the +/// base IScene interface while maintaining type safety in the implementation. +/// public interface IScene : IScene where TRequest : class { + /// + /// Seeds data based on the provided strongly-typed request. + /// + /// The request object containing parameters for the seeding operation. + /// A scene result containing the mangle map and entity tracking information. Task SeedAsync(TRequest request); + + /// + /// Gets the request type for this scene. + /// + /// The type of TRequest. Type IScene.GetRequestType() => typeof(TRequest); + + /// + /// Adapts the non-generic SeedAsync to the strongly-typed version. + /// + /// The request object to cast and process. + /// A scene result wrapped as an object result. async Task> IScene.SeedAsync(object request) { var result = await SeedAsync((TRequest)request); @@ -21,10 +61,36 @@ public interface IScene : IScene where TRequest : class } } +/// +/// Generic scene interface for seeding operations with a specific request type that returns typed data. +/// +/// The type of request object this scene accepts. Must be a reference type. +/// The type of data this scene returns. Must be a reference type. +/// +/// Use this interface when your scene needs to return specific data that can be used by subsequent +/// scenes or test logic. The result is wrapped in a SceneResult that also includes the mangle map +/// and entity tracking information. The explicit interface implementations allow dynamic invocation +/// while preserving type safety in the implementation. +/// public interface IScene : IScene where TRequest : class where TResult : class { + /// + /// Seeds data based on the provided strongly-typed request and returns typed result data. + /// + /// The request object containing parameters for the seeding operation. + /// A scene result containing the typed result data, mangle map, and entity tracking information. Task> SeedAsync(TRequest request); + /// + /// Gets the request type for this scene. + /// + /// The type of TRequest. Type IScene.GetRequestType() => typeof(TRequest); + + /// + /// Adapts the non-generic SeedAsync to the strongly-typed version. + /// + /// The request object to cast and process. + /// A scene result with the typed result cast to object. async Task> IScene.SeedAsync(object request) => (SceneResult)await SeedAsync((TRequest)request); } diff --git a/util/Seeder/Queries/EmergencyAccessInviteQuery.cs b/util/Seeder/Queries/EmergencyAccessInviteQuery.cs index d96840b56e..95d96a9a50 100644 --- a/util/Seeder/Queries/EmergencyAccessInviteQuery.cs +++ b/util/Seeder/Queries/EmergencyAccessInviteQuery.cs @@ -5,6 +5,9 @@ using Bit.Infrastructure.EntityFramework.Repositories; namespace Bit.Seeder.Queries; +/// +/// Retrieves all emergency access invite urls for the provided email. +/// public class EmergencyAccessInviteQuery( DatabaseContext db, IDataProtectorTokenFactory dataProtectorTokenizer) diff --git a/util/Seeder/Scenes/SingleUserScene.cs b/util/Seeder/Scenes/SingleUserScene.cs index 793c475c8f..df941c7f59 100644 --- a/util/Seeder/Scenes/SingleUserScene.cs +++ b/util/Seeder/Scenes/SingleUserScene.cs @@ -4,6 +4,9 @@ using Bit.Seeder.Factories; namespace Bit.Seeder.Scenes; +/// +/// Creates a single user using the provided account details. +/// public class SingleUserScene(UserSeeder userSeeder, IUserRepository userRepository) : IScene { public class Request