Skip to content

feat: add generic key-path convenience API for structured collections#8

Draft
kielgillard wants to merge 1 commit intoordo-one:mainfrom
kielgillard:main
Draft

feat: add generic key-path convenience API for structured collections#8
kielgillard wants to merge 1 commit intoordo-one:mainfrom
kielgillard:main

Conversation

@kielgillard
Copy link

@kielgillard kielgillard commented Feb 18, 2026

Description

Add ItemMatchResult and key-path overloads of topMatches/matches so users can search collections of structured items (e.g., [Instrument]) by a string property (e.g., .name) without manually extracting and reassociating strings.

I am opening this for feedback, I do not intend to submit for merging just yet.

let instruments = [
    Instrument(ticker: "AAPL", name: "Apple Inc"),
    Instrument(ticker: "MSFT", name: "Microsoft Corporation"),
    Instrument(ticker: "GOOG", name: "Alphabet Inc"),
]
let matcher = FuzzyMatcher()
let query = matcher.prepare("inc")
let all = matcher.matches(instruments, by: \.name, against: query)

How Has This Been Tested?

Claude generated a handful of tests that are passing.

Checklist

  • I have performed a self-review of my own code
  • I have added DocC documentation (/// comments) for any new public APIs
  • I have added tests that prove my fix is effective or that my feature works
  • All tests pass (swift test)
  • If this is a performance-related change, I have included benchmark results (before/after)

Add ItemMatchResult<Item> and key-path overloads of topMatches/matches
so users can search collections of structured items (e.g., [Instrument])
by a string property (e.g., \.name) without manually extracting and
reassociating strings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gemini-code-assist
Copy link

Summary of Changes

Hello @kielgillard, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request enhances the fuzzy matching library by introducing a generic key-path based API. This allows users to perform fuzzy searches directly on specific string properties of custom data structures, eliminating the need for manual string extraction and reassociation. The change significantly improves the usability and type safety when working with structured collections, making the fuzzy matching process more streamlined and intuitive.

Highlights

  • New Key-Path Convenience API: Introduced new topMatches and matches overloads in FuzzyMatcher that accept a KeyPath<Item, String>, allowing fuzzy matching on a specific string property within a collection of structured items (e.g., Instrument by \.name).
  • New ItemMatchResult Struct: Added a new generic struct ItemMatchResult<Item> to pair the original matched item with its ScoredMatch, providing a more convenient way to handle results from structured collections.
  • String Query Overloads: Provided convenience overloads for the new key-path matching functions that directly accept a String query, handling the internal query preparation for simpler usage.
  • Comprehensive Unit Tests: Added a dedicated test file (KeyPathConvenienceTests.swift) with extensive unit tests to validate the functionality, sorting, limits, and equivalence of the new key-path convenience APIs against existing string-based APIs.
Changelog
  • Sources/FuzzyMatch/FuzzyMatch.docc/FuzzyMatch.md
    • Updated documentation to include the new ItemMatchResult type.
  • Sources/FuzzyMatch/FuzzyMatcher+KeyPathConvenience.swift
    • Added a new file containing extensions to FuzzyMatcher for key-path based topMatches and matches functions.
    • Implemented logic for fuzzy matching on Sequence<Item> using a KeyPath<Item, String>.
  • Sources/FuzzyMatch/ScoredMatch.swift
    • Introduced the ItemMatchResult<Item> struct to encapsulate a matched item and its ScoredMatch.
    • Added Sendable, Equatable, Hashable, Comparable, and CustomStringConvertible conformance to ItemMatchResult.
  • Tests/FuzzyMatchTests/KeyPathConvenienceTests.swift
    • Added a new test file to thoroughly test the new key-path convenience APIs for FuzzyMatcher.
    • Included tests for correct item return, sorting, limit adherence, empty cases, string query overloads, different key paths, and equivalence with the string API.
Activity
  • The pull request was opened for feedback, indicating that it is not yet ready for merging.
  • The author confirmed that tests generated by Claude are passing.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a valuable convenience API for fuzzy matching on collections of structured items using key paths. The implementation is well-structured and accompanied by a comprehensive set of tests. My review includes feedback on a potential crash for an edge case (limit: 0) and a suggestion to improve the performance of the topMatches function. Overall, this is a great addition to the library.

by keyPath: KeyPath<Item, String>,
against query: FuzzyQuery,
limit: Int = 10
) -> [ItemMatchResult<Item>] {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

This function will crash if called with limit: 0. When limit is 0, the results array remains empty. The condition else if match.score > results[results.count - 1].match.score on line 71 will then attempt to access an index out of bounds, causing a fatal error.

Please add a guard at the beginning of the function to handle this edge case, for example:

guard limit > 0 else { return [] }

}
} else if match.score > results[results.count - 1].match.score {
results[results.count - 1] = result
results.sort { $0.match.score > $1.match.score }

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Re-sorting the results array on every insertion after the limit is reached is inefficient. For a large number of candidates, this can become a performance bottleneck.

A more efficient approach is to replace the last element and then "bubble up" the new element to its correct sorted position. This changes the complexity of an insertion from O(L log L) to O(L), where L is the limit.

You could replace the sort with something like this:

var i = results.count - 1
while i > 0 && results[i].match.score > results[i - 1].match.score {
    results.swapAt(i, i - 1)
    i -= 1
}

@hassila
Copy link
Contributor

hassila commented Feb 18, 2026

Would be nice with benchmarks for these too, also perhaps support for providing the matching buffer (just skimming on my phone). But overall interesting direction - will have a more proper look a bit later - away on a trip for a week now.

@codecov
Copy link

codecov bot commented Feb 18, 2026

Codecov Report

❌ Patch coverage is 97.60479% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 98.84%. Comparing base (eaa9997) to head (b3f181d).
⚠️ Report is 11 commits behind head on main.

Files with missing lines Patch % Lines
Sources/FuzzyMatch/ScoredMatch.swift 42.86% 4 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main       #8      +/-   ##
==========================================
- Coverage   98.87%   98.84%   -0.02%     
==========================================
  Files          39       41       +2     
  Lines        8315     8482     +167     
==========================================
+ Hits         8221     8384     +163     
- Misses         94       98       +4     
Files with missing lines Coverage Δ
...s/FuzzyMatch/FuzzyMatcher+KeyPathConvenience.swift 100.00% <100.00%> (ø)
...ests/FuzzyMatchTests/KeyPathConvenienceTests.swift 100.00% <100.00%> (ø)
Sources/FuzzyMatch/ScoredMatch.swift 80.95% <42.86%> (-19.05%) ⬇️
Files with missing lines Coverage Δ
...s/FuzzyMatch/FuzzyMatcher+KeyPathConvenience.swift 100.00% <100.00%> (ø)
...ests/FuzzyMatchTests/KeyPathConvenienceTests.swift 100.00% <100.00%> (ø)
Sources/FuzzyMatch/ScoredMatch.swift 80.95% <42.86%> (-19.05%) ⬇️

Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update eaa9997...b3f181d. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants