Set up repository with legacy .NET Framework 4.8 source (OLD/), new .NET 10 Blazor solution (NEW/), OpenSpec specifications, documentation, and project configuration.
9.0 KiB
Search Processing Specification Delta
Purpose
This document captures ADDED and MODIFIED requirements for the search processing subsystem specific to the .NET 10 migration. It supplements the base specification at openspec/specs/search-processing/spec.md.
ADDED Requirements
Requirement: SqlKata Query Builder Integration
The system SHALL use SqlKata fluent query builder instead of T4 text templates for dynamic SQL generation.
Inputs
SearchModelcontaining filter criteria and enriched filter entriesSqlServerCompilerfor T-SQL generation
Outputs
SearchQueryResultrecord containing:Sql: Parameterized T-SQL query stringParameters: Dictionary of named parameter valuesTempTableSetupSql: List of temp table creation/population statements
Business Rules
- SqlKata
SqlServerCompilerSHALL be registered as a singleton (thread-safe) - All queries SHALL use named parameters (not positional)
- Parameter names SHALL match legacy convention (
@p_*prefix) - Generated SQL SHALL produce equivalent results to legacy QueryTemplate.tt
Scenario: Build query with SqlKata
- WHEN
ISearchQueryBuilder.BuildSearchQuery(model)is called - THEN SqlKata generates parameterized SQL with named bindings
- AND the
SearchQueryResult.Sqlis executable via Dapper - AND
SearchQueryResult.Parameterscontains all TVP parameters
Requirement: Filter Handler Pattern
The system SHALL use a composable filter handler pattern for modular query building.
Inputs
SearchModelwith active filter criteriaSqlServerCompilerfor SQL compilation
Outputs
FilterResultrecord containing:SetupSql: List of temp table setup statementsParameters: Dictionary of parameters for this filter
Business Rules
- Each filter type SHALL have a dedicated
IFilterHandlerimplementation - Filter handlers SHALL be registered in dependency injection container
- Handlers SHALL execute in priority order (lower priority = earlier execution)
- Handler priorities SHALL ensure dependent temp tables exist before use:
- WorkOrder: 10
- ItemNumber: 20
- ComponentLot: 30
- ProfitCenter: 40
- WorkCenter: 50
- Operator: 60
- ItemOperationMis: 70
- Timespan: 80
Scenario: Execute filter handlers in order
- WHEN search criteria includes work orders, items, and operators
- THEN WorkOrderFilterHandler executes first (priority 10)
- AND ItemNumberFilterHandler executes second (priority 20)
- AND OperatorFilterHandler executes later (priority 60)
Requirement: IAsyncEnumerable Result Streaming
The system SHALL support streaming large result sets using IAsyncEnumerable<T>.
Inputs
SearchModelwith executed queryCancellationTokenfor cooperative cancellation
Outputs
IAsyncEnumerable<SearchResult>streaming results one at a time
Business Rules
- Streaming SHALL use Dapper's
QueryUnbufferedAsyncmethod - Cancellation SHALL be supported via
[EnumeratorCancellation]attribute - Memory allocation SHALL remain constant regardless of result set size
- Consumer MAY materialize results using
ToListAsync()when needed
Scenario: Stream large result set
- WHEN search returns 10,000 work orders
- THEN results stream via
IAsyncEnumerable<SearchResult> - AND memory usage remains constant during enumeration
- AND
await foreachconsumes results incrementally
Requirement: Async-First Design
The system SHALL use async methods throughout the search processing pipeline.
Business Rules
- All repository methods SHALL accept
CancellationTokenparameter - All database operations SHALL use async Dapper methods (
QueryAsync,ExecuteAsync) - Long-running operations SHALL respect cancellation tokens
ISearchProcessor.ExecuteSearchAsyncSHALL be the primary entry point
Scenario: Cancel long-running search
- WHEN a search is in progress and cancellation is requested
- THEN the operation throws
OperationCanceledException - AND database connections are properly disposed
Requirement: Configuration via IOptions Pattern
The system SHALL use IOptions<SearchProcessingOptions> for configuration.
Inputs
appsettings.jsonsection:SearchProcessing
Outputs
- Strongly-typed
SearchProcessingOptionsinjected via DI
Configuration Properties
| Property | Type | Default | Description |
|---|---|---|---|
QueryTimeoutSeconds |
int | 600 | SQL query timeout |
MaxTraversalIterations |
int | 20 | Downstream traversal limit |
EnableDebugSql |
bool | false | Write SQL to debug files |
DebugSqlPath |
string? | null | Path for debug SQL files |
Scenario: Configure query timeout
- WHEN
SearchProcessingOptions.QueryTimeoutSecondsis set to 900 - THEN Dapper queries use
commandTimeout: 900
Requirement: Service Registration Extension
The system SHALL provide an AddSearchProcessing extension method for DI registration.
Service Lifetimes
| Service | Lifetime | Rationale |
|---|---|---|
SqlServerCompiler |
Singleton | Thread-safe, stateless |
IFilterHandler implementations |
Scoped | Per-request state |
ISearchQueryBuilder |
Scoped | Uses scoped handlers |
ISearchProcessor |
Scoped | Uses scoped repositories |
IWorkOrderTraversalService |
Scoped | Uses connection factory |
Scenario: Register search processing services
- WHEN
services.AddSearchProcessing(configuration)is called - THEN all search processing services are registered
- AND
ISearchProcessorcan be resolved from service provider
MODIFIED Requirements
Requirement: Work Order Traversal
The system SHALL execute downstream work order traversal via stored procedure dbo.TraverseWorkOrders instead of inline WHILE loop in generated SQL.
Inputs
- Active database connection with
#Temp_WOtemporary table populated - Maximum iteration count (default 20)
Outputs
- Updated
#Temp_WOtable with downstream work orders flagged
Business Rules
IWorkOrderTraversalService.TraverseDownstreamAsyncSHALL call stored procedure- Stored procedure SHALL contain iterative WHILE loop logic
- Single stored procedure call SHALL replace 20 inline iterations
- Transaction scope SHALL be maintained within stored procedure
Scenario: Execute downstream traversal via stored procedure
- WHEN initial work orders are flagged in
#Temp_WO - THEN
dbo.TraverseWorkOrdersstored procedure is called - AND downstream work orders are added with PartsList and CARDEX flags
- AND split orders are detected and flagged
Requirement: Filter Entry Types
The system SHALL use C# record types for filter entry DTOs to provide immutability and value semantics.
Inputs
- Raw filter values from
SearchCriteria - Reference data lookups from
ILotFinderRepository
Outputs
- Immutable record instances with output attributes for Excel export
Business Rules
- All filter entry types SHALL be declared as C# records
- Records SHALL use primary constructor syntax
- Output attributes SHALL be applied using
[property:]target - Records SHALL provide value-based equality for testing
Scenario: Create immutable filter entry record
- WHEN a WorkOrderFilterEntry is created with WorkOrderNumber 12345 and ItemNumber "ITEM-001"
- THEN the record is immutable (properties are init-only)
- AND two records with same values are considered equal
Requirement: SQL Client Package
The system SHALL use Microsoft.Data.SqlClient instead of deprecated System.Data.SqlClient for SQL Server connectivity.
Business Rules
- All SQL Server connections SHALL use
Microsoft.Data.SqlClient.SqlConnection - All SQL commands SHALL use
Microsoft.Data.SqlClient.SqlCommand - NuGet package
Microsoft.Data.SqlClientversion 5.2+ SHALL be referenced - Code SHALL NOT reference
System.Data.SqlClientnamespace
Scenario: Create SQL connection with modern client
- WHEN
IDbConnectionFactory.CreateLotFinderConnectionAsyncis called - THEN a
Microsoft.Data.SqlClient.SqlConnectioninstance is returned - AND connection supports all modern SQL Server features
Migration Notes
| Legacy Pattern | New Pattern | Status |
|---|---|---|
| T4 Text Template | SqlKata fluent builder | ADDED |
| Inline WHILE loop | Stored procedure | MODIFIED |
| Filter entry classes | Record types | MODIFIED |
| Synchronous Dapper | Async Dapper | MODIFIED |
| System.Data.SqlClient | Microsoft.Data.SqlClient | MODIFIED |
| Static class methods | DI-registered services | MODIFIED |
| Newtonsoft.Json | System.Text.Json | Retained in domain models |
Open Questions
None - all design decisions resolved per base specification.