8.3 KiB
Search Criteria SQL Extraction Functions - Design
Purpose
Create SQL Server functions to extract values from the Search.Criteria JSON column, eliminating the need for C# to deserialize criteria and pass Table-Valued Parameters to SQL Server. The query builder will generate SQL that extracts filter values directly from the database.
Goals
- Create 11 SQL functions to extract scalar and table values from SearchCriteria JSON
- Remove Table Type dependencies (7 TVP types)
- Simplify C# query generation to pass only SearchId
- Add comprehensive Database.Tests for the new functions
- Update documentation and specifications
Architecture
SQL Server Version
- Target: SQL Server 2022
- JSON Functions:
OPENJSON(),JSON_VALUE(),ISJSON()
Function Types
Scalar Functions (3):
| Function | Returns | JSON Path |
|---|---|---|
dbo.fn_GetSearchMinimumDt |
DATETIME2(7) |
$.MinimumDt |
dbo.fn_GetSearchMaximumDt |
DATETIME2(7) |
$.MaximumDt |
dbo.fn_GetSearchExtractMisData |
BIT |
$.ExtractMisData |
Simple Table Functions (5):
| Function | Returns | JSON Path |
|---|---|---|
dbo.fn_GetSearchWorkOrders |
TABLE(WorkOrderNumber BIGINT) |
$.WorkOrderNumbers |
dbo.fn_GetSearchItemNumbers |
TABLE(ItemNumber VARCHAR(128)) |
$.ItemNumbers |
dbo.fn_GetSearchProfitCenters |
TABLE(Code VARCHAR(12)) |
$.ProfitCenters |
dbo.fn_GetSearchWorkCenters |
TABLE(Code VARCHAR(12)) |
$.WorkCenters |
dbo.fn_GetSearchOperatorIDs |
TABLE(OperatorID VARCHAR(128)) |
$.OperatorIDs |
Complex Table Functions (2):
| Function | Returns | JSON Path |
|---|---|---|
dbo.fn_GetSearchComponentLots |
TABLE(LotNumber VARCHAR(30), ItemNumber VARCHAR(128)) |
$.ComponentLotNumbers[*] |
dbo.fn_GetSearchPartOperations |
TABLE(ItemNumber VARCHAR(128), OperationNumber VARCHAR(10), MisNumber VARCHAR(10), MisRevision VARCHAR(10)) |
$.PartOperations[*] |
Error Handling
All functions validate inputs and throw errors for invalid conditions:
| Error Code | Condition | Message Pattern |
|---|---|---|
| 50001 | SearchId not found | Search ID {id} not found |
| 50002 | Criteria is NULL or empty | Search ID {id} has no criteria |
| 50003 | Criteria is invalid JSON | Search ID {id} has invalid JSON |
Normal empty results (no error):
- JSON valid but property missing
- JSON valid, property is
[]ornull
Multi-Statement TVF Pattern
Table functions use multi-statement TVFs for proper error handling:
CREATE FUNCTION dbo.fn_GetSearchWorkOrders(@SearchId INT)
RETURNS @Results TABLE (WorkOrderNumber BIGINT NOT NULL)
AS
BEGIN
DECLARE @Criteria VARCHAR(MAX);
DECLARE @ErrorMsg NVARCHAR(400);
-- Get criteria
SELECT @Criteria = Criteria
FROM dbo.Search
WHERE ID = @SearchId;
-- Validate search exists
IF @@ROWCOUNT = 0
BEGIN
SET @ErrorMsg = CONCAT('Search ID ', @SearchId, ' not found');
THROW 50001, @ErrorMsg, 1;
END
-- Validate criteria not null/empty
IF @Criteria IS NULL OR @Criteria = ''
BEGIN
SET @ErrorMsg = CONCAT('Search ID ', @SearchId, ' has no criteria');
THROW 50002, @ErrorMsg, 1;
END
-- Validate JSON
IF ISJSON(@Criteria) = 0
BEGIN
SET @ErrorMsg = CONCAT('Search ID ', @SearchId, ' has invalid JSON');
THROW 50003, @ErrorMsg, 1;
END
-- Extract values (returns empty if property missing/null/empty array)
INSERT INTO @Results (WorkOrderNumber)
SELECT CAST(value AS BIGINT)
FROM OPENJSON(@Criteria, '$.WorkOrderNumbers');
RETURN;
END
Migration Scripts
New Scripts
045_CreateScalarExtractionFunctions.sql
fn_GetSearchMinimumDtfn_GetSearchMaximumDtfn_GetSearchExtractMisData
046_CreateSimpleTableFunctions.sql
fn_GetSearchWorkOrdersfn_GetSearchItemNumbersfn_GetSearchProfitCentersfn_GetSearchWorkCentersfn_GetSearchOperatorIDs
047_CreateComplexTableFunctions.sql
fn_GetSearchComponentLotsfn_GetSearchPartOperations
Scripts to Delete
Remove obsolete Table Type scripts:
033_CreateWorkOrderFilterParameterType.sql034_CreateItemNumberFilterParameterType.sql035_CreateProfitCenterFilterParameterType.sql036_CreateWorkCenterFilterParameterType.sql037_CreateOperatorFilterParameterType.sql038_CreateComponentLotFilterParameterType.sql039_CreateItemOperationMisFilterParameterType.sql
C# Changes
Files to Delete
src/JdeScoping.DataAccess/
├── Extensions/
│ └── TableValuedParameterExtensions.cs
├── Models/FilterEntries/
│ ├── WorkOrderFilterEntry.cs
│ ├── ItemNumberFilterEntry.cs
│ ├── ProfitCenterFilterEntry.cs
│ ├── WorkCenterFilterEntry.cs
│ ├── OperatorFilterEntry.cs
│ ├── ComponentLotFilterEntry.cs
│ └── ItemOperationMisFilterEntry.cs
Files to Modify
ISearchQueryBuilder.cs - New signature:
SearchQueryResult BuildSearchQuery(int searchId);
SearchQueryResult BuildMisQuery(int searchId);
SearchQueryResult BuildMisNonMatchQuery(int searchId);
SqlKataSearchQueryBuilder.cs - Generate SQL using functions:
-- Instead of TVP temp table population:
INSERT INTO #P_WorkOrders SELECT * FROM dbo.fn_GetSearchWorkOrders(@SearchId)
SearchModel.cs - Simplify:
- Remove all
List<*FilterEntry>properties - Remove all
*FilterEnabledcomputed properties - Keep:
Id,UserName,Name, timestamps, results
SearchProcessor.cs - Pass searchId instead of filter lists
Test Structure
tests/JdeScoping.Database.Tests/
├── Infrastructure/
│ └── DatabaseTestBase.cs
├── Functions/
│ ├── ScalarFunctionTests.cs
│ ├── SimpleTableFunctionTests.cs
│ └── ComplexTableFunctionTests.cs
Test Categories
Happy Path: Valid JSON, correct extraction, empty arrays Error Tests: Non-existent SearchId, NULL criteria, invalid JSON Edge Cases: Large arrays, special characters, NULL values in arrays, Unicode
Test Infrastructure
Share with Api.IntegrationTests via TestWebApplicationFactory pattern.
Documentation Updates
OpenSpec Specifications
- Update
openspec/specs/data-access/spec.md- Remove TVP references, add function requirements - Update
openspec/specs/search-processing/spec.md- Update query generation - Update
openspec/specs/database-schema/spec.md- Document extraction functions
DOCUMENTATION Folder
- Update architecture diagrams
- Add
DOCUMENTATION/Database/ExtractionFunctions.md - Update testing documentation
Implementation Order
Phase 1: SQL Functions
- Create
045_CreateScalarExtractionFunctions.sql - Create
046_CreateSimpleTableFunctions.sql - Create
047_CreateComplexTableFunctions.sql - Delete obsolete Table Type scripts (033-039)
- Renumber remaining scripts (040-044 → 033-037)
Phase 2: Database Tests
- Set up
DatabaseTestBase.cs - Write
ScalarFunctionTests.cs - Write
SimpleTableFunctionTests.cs - Write
ComplexTableFunctionTests.cs - Verify all tests pass
Phase 3: C# Refactor
- Update
ISearchQueryBuilderinterface - Update
SqlKataSearchQueryBuilder - Update
SearchProcessor - Simplify
SearchModel - Delete
TableValuedParameterExtensions.cs - Delete
FilterEntries/*.cs - Update/delete related tests
Phase 4: Integration & Verification
- Run full test suite
- Fix broken tests
- Manual end-to-end verification
Phase 5: Documentation
- Update OpenSpec specifications
- Update architecture documentation
- Add Database.Tests documentation
- Create ExtractionFunctions.md reference
Acceptance Criteria
- All 11 SQL functions created and working
- Error codes 50001/50002/50003 thrown for invalid inputs
- Empty results returned for missing/null/empty properties
- Table Type scripts removed
- C# TVP code removed
- Query builder uses SearchId parameter only
- Database.Tests passing (all categories)
- Existing integration tests passing
- Documentation updated