Path Relational Algebra
Relevant source files
The following files were used as context for generating this wiki page:
Path Relational Algebra in data-path refers to a set of mathematical and logical operations used to compare, manipulate, and compose object property paths. This system allows developers to treat paths not just as strings, but as structured entities that can be merged, subtracted, and checked for hierarchical relationships like parent-child or inclusion.
These operations are essential for complex state management, permission systems, and validation logic where determining the relationship between a specific data point (e.g., users.0.name) and a broader scope (e.g., users.*) is required.
Sources: README.md:154-159, src/types.ts:167-172
Relational Operations
Relational operations allow for the comparison of two paths to determine their structural relationship. This is handled primarily through the match() method and specialized boolean checks.
Relationship Types
The library identifies several distinct relationships between paths:
| Relation | Description |
|---|---|
equals | The paths have identical segments in the same order. |
parent | This path is a direct or indirect ancestor of the other path. |
child | This path is a direct or indirect descendant of the other path. |
includes | This path (often a template) encompasses the other path. |
included-by | This path is encompassed by the other path (often a template). |
null | No structural relationship exists between the paths. |
Sources: src/types.ts:12-21, skills/data-path/references/api.md:65-72
Logic Flow for Path Matching
The matching logic evaluates paths by comparing their internal segments arrays. The following diagram illustrates the decision process within the match() method:
This flow determines the hierarchical or pattern-based relationship between two paths.
Sources: src/impl/path-impl.ts:219-245
Algebraic Manipulation
Algebraic operations allow paths to be programmatically combined or dismantled. These operations are immutable, returning new path instances while leaving the originals unchanged.
Path Merging
The merge() operation appends one path to another. A key feature of merge() is longest suffix-prefix overlap deduplication. If the end of Path A matches the start of Path B, the overlapping segments are merged into one.
- Standard Concatenation:
path("a.b").merge("c.d")→"a.b.c.d" - Overlapping Merge:
path("users.0").merge("0.name")→"users.0.name"
Sources: src/impl/path-impl.ts:254-273, src/tests/algebra.spec.ts:23-32
Path Subtraction
The subtract() operation acts as the inverse of merging. It attempts to remove a prefix or a suffix from a path. If the provided path is neither a prefix nor a suffix, it returns null.
Subtraction is useful for converting absolute paths into relative paths within sub-components.
Sources: src/impl/path-impl.ts:282-299, src/tests/algebra.spec.ts:98-114
Slicing
The slice() method provides standard array-like slicing of path segments. It allows for the extraction of specific parts of a path hierarchy using start and end indices.
Sources: src/impl/path-impl.ts:307-310, src/tests/algebra.spec.ts:133-138
Implementation Details
The core logic for these operations resides in the PathImpl class, which stores paths as an array of Segment (strings or numbers).
Class Structure
Technical Constraints
- Immutability: Methods like
merge,subtract, andslicealways return a newPathImplinstance. - Type Safety: While the runtime uses raw segments, the TypeScript layer ensures that merged or subtracted paths remain consistent with the root data type
T. - Graceful Handling: Comparison methods like
startsWithandequalsare designed to handlenullorundefinedinputs without throwing, returningfalseinstead.
Sources: src/impl/path-impl.ts:254-310, src/tests/interactions.spec.ts:108-114
Summary
Path Relational Algebra provides the mathematical foundation for data-path. By implementing logic for hierarchical matching (match), intelligent composition (merge with overlap detection), and decomposition (subtract, slice), the library allows developers to treat property paths as robust, queryable structures rather than simple strings. This enables advanced use cases such as mapping global validation errors to local form fields or managing complex, nested immutable state updates.