MappingPath and ObjectAccessor Enhancements

Feature ID: 004-mappingpath-accessor-enhancements
Status: Draft

itrond.net

Overview

Two enhancements to the path navigation system:

  1. Remove wildcard requirement

    • Allow MappingPath to work with any path
    • Not just paths containing wildcards [*]
  2. Automatic wildcard generation

    • Detect where wildcards should be placed
    • Based on data structure analysis

Business Value

  • Simplified API: Uniform usage regardless of wildcards
  • Reduced errors: Automatic wildcard detection
  • Faster development: No manual type structure analysis
  • Better maintainability: Paths stay correct when structures change

Feature 1: Optional Wildcards in MappingPath

Current Limitation

Currently, you must include at least one wildcard [*] when creating a MappingPath, or it throws an error.

Proposed Solution

Allow MappingPath to work with any valid path, with or without wildcards.

Scenario 1: Without Wildcards

Step Description
Given Path: "Person.Name"
When Create MappingPath
Then Created successfully
And Wildcard count is 0

Scenario 2: With Wildcards

Step Description
Given Path: "Person.Jobs[*].Title"
When Create MappingPath
Then Created successfully
And Wildcard count is 1

Scenario 3: Apply Indices - No Wildcards

Step Description
Given MappingPath: "A.B.C"
And Source: "X.Y[5].Z[3]"
When Apply source indices
Then Result: "A.B.C" (unchanged)

Scenario 4: Apply Indices - With Wildcards

Step Description
Given MappingPath: "A[*].B[*].C"
And Source: "X[3].Y[7].Z"
When Apply source indices
Then Result: "A[3].B[7].C"

Acceptance Criteria - Feature 1

✓ MappingPath accepts paths without wildcards
✓ WildcardCount returns 0 when no wildcards present
✓ ApplyIndices returns template unchanged when no wildcards
✓ ApplyIndices correctly substitutes wildcard positions
✓ Mixed scenarios work correctly

Feature 2: Generate MappingPath from Type Structure

Business Need

Developers must manually figure out where to place wildcards [*] by analyzing type structures.

This is error-prone and time-consuming.

Proposed Solution

Add method GenerateMappingPath that:

  • Automatically analyzes type structure
  • Places wildcards at every collection position

Key concept: Input is a class path (property names only)

How It Works

Input:  "Jobs.Projects.Name"
                ↓
Analyze type structure:
- Jobs: List<Job>      → Add wildcard
- Projects: List<Project> → Add wildcard
- Name: string         → No wildcard
                ↓
Output: "Jobs[*].Projects[*].Name"

Scenario 1: Simple Collection

Step Description
Given Jobs is List<Job>
And Class path: "Jobs.Title"
When Generate MappingPath
Then Result: "Jobs[*].Title"
And Wildcard count: 1

Scenario 2: Nested Collections

Step Description
Given Jobs is List<Job>
And Projects is List<Project>
And Class path: "Jobs.Projects.Name"
When Generate MappingPath
Then Result: "Jobs[*].Projects[*].Name"
And Wildcard count: 2

Scenario 3: No Collections

Step Description
Given Name is string
And Class path: "Name"
When Generate MappingPath
Then Result: "Name"
And Wildcard count: 0

Scenario 4: Mixed Types

Step Description
Given CurrentJob is single object
And PastProjects is List<Project>
And Class path: "CurrentJob.PastProjects.Description"
When Generate MappingPath
Then Result: "CurrentJob.PastProjects[*].Description"

Scenario 5: Three-Level Nesting

Step Description
Given Organization → Departments → Teams → Members
And All three are collections
And Class path: "Departments.Teams.Members.Name"
When Generate MappingPath
Then Result: "Departments[*].Teams[*].Members[*].Name"

Acceptance Criteria - Feature 2

✓ Correctly identifies collection types and adds wildcards
✓ Correctly identifies non-collection types and omits wildcards
✓ Handles nested collections at multiple levels
✓ Handles mixed scenarios
✓ Handles root path without errors
✓ Throws appropriate exception for invalid paths
✓ Works with at least 3 levels of nesting

Use Case 1: Flexible Mapping API

Before: Different code paths

if (hasCollections) {
    var mapping = MappingPath.Parse(path);
} else {
    var mapping = /* different approach */
}

After: Uniform API

var mapping = MappingPath.Parse(path);
if (mapping.WildcardCount > 0) {
    // Handle collections
}

Use Case 2: Data Transformation

Step Action Result
1 Define source "OldFormat.Items.SubItems.Value"
2 Generate mapping "OldFormat.Items[*].SubItems[*].Value"
3 Define target "NewFormat.Elements.SubElements.Data"
4 Generate mapping "NewFormat.Elements[*].SubElements[*].Data"

Benefit: No manual wildcard placement, fewer errors

Implementation Summary

Changes Required

  1. MappingPath class - Remove wildcard requirement
  2. ApplyIndices method - Handle zero-wildcard case
  3. ObjectAccessor class - Add GenerateMappingPath method
  4. Tests - 11 new test scenarios

Testing Strategy

Test Category Number of Tests Coverage
Optional wildcards 4 tests MappingPath without wildcards
GenerateMappingPath 7 tests Type analysis, nesting
Total 11 tests >95% coverage

Backward Compatibility

No breaking changes
✓ Existing code continues to work
✓ API is enhanced, not changed

Timeline & Dependencies

Prerequisites

  • Understanding of current MappingPath implementation
  • Access to ObjectAccessor codebase
  • Test infrastructure in place

Estimated Effort

  • Implementation: ~4-6 hours
  • Testing: ~3-4 hours
  • Code review: ~2 hours
  • Total: ~9-12 hours

Success Criteria

Criterion Status
MappingPath accepts paths without wildcards Target
WildcardCount returns 0 correctly Target
ApplyIndices handles zero wildcards Target
GenerateMappingPath analyzes correctly Target
All collection levels detected Target
All existing tests pass Target
>95% coverage for new code Target
Backward compatibility maintained Target

Key Concepts

Term Definition
MappingPath Path template with wildcards [*]
Class Path Property names without indices
Instance Path Path with specific indices
Wildcard [*] notation for collection position
Collection Type Type holding multiple items

Questions & Decisions

Question Decision
Keep backward compatibility? Yes, maintain full compatibility
Support nullable types? Yes, through existing type system
Arrays vs Lists? Treat both as collections
Cache generated paths? No, not in initial version

Summary

Two powerful enhancements:

  1. MappingPath works with or without wildcards
  2. Automatic wildcard generation from type structure

Result: Simpler API, fewer errors, faster development

Effort: ~9-12 hours
Risk: Low (no breaking changes)