-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Fix numeric comparisons for float custom tags #4116
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix numeric comparisons for float custom tags #4116
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hello @deluan, 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!
Summary of Changes
Hello team,
Gemini or gemini-code-assist here to provide a summary of this pull request. This PR aims to fix an issue where numeric comparisons on custom tags within smart playlist rules might not work correctly, especially for floating-point values. The core problem is that tag values are stored as text within a JSON structure, and direct comparison might treat them lexicographically rather than numerically.
The solution implemented involves modifying the SQL generation logic. When a comparison is performed on a custom tag and the argument provided for the comparison is detected as a number, the generated SQL is updated to explicitly cast the tag's value
to a REAL
number type using CAST(value AS REAL)
. This forces the database to perform a proper numeric comparison.
A new helper function, isNumber
, is introduced to reliably check if a given Go value is one of the standard integer or float types. Finally, a dedicated test case is added to the operators test suite to specifically verify that numeric comparisons on custom tags now correctly produce SQL that includes the necessary CAST
operation.
Highlights
- Fix Numeric Tag Comparisons: Addresses an issue preventing correct numeric comparisons (including floats) on custom tags in smart playlist rules.
- SQL Casting for Numeric Values: Modifies the SQL generation to include
CAST(value AS REAL)
for custom tag values when the comparison argument is numeric, ensuring proper numeric comparison. - Add
isNumber
Helper: Introduces a new utility function to check if a variable holds a numeric type (int, uint, float types). - Add Test Case: Includes a new test specifically validating that numeric comparisons on custom tags correctly generate SQL with the necessary casting.
Changelog
- model/criteria/fields.go
- Added logic in
tagCond.ToSql
to check if the comparison argument is numeric and, if so, modify the generated SQL to cast the tagvalue
toREAL
(lines 148-150). - Added the
isNumber
helper function to check for various integer and float types (lines 159-167).
- Added logic in
- model/criteria/operators_test.go
- Added a new test case within the "Operators" suite to specifically verify that numeric comparisons (using
Lt
in the example) on custom tags correctly generate SQL withCAST(value AS REAL)
(lines 80-86).
- Added a new test case within the "Operators" suite to specifically verify that numeric comparisons (using
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 in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command>
or @gemini-code-assist <command>
. Below is a summary of the supported commands.
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 issue 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 is currently in preview and 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 to provide feedback.
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.
Text becomes a number,
Casting makes the math work right,
Playlist rules now sing.
Footnotes
-
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. ↩
There was a problem hiding this 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 effectively addresses an issue with numeric comparisons for custom tags stored as text by introducing a CAST
to REAL
in the SQL query when the comparison involves a numeric argument. The addition of the isNumber
helper function and the corresponding test case are well-implemented. My main feedback point revolves around the behavior of the CAST
operation on non-numeric string values within tags, which could lead to unexpected query results in certain edge cases.
Summary of Findings
- Behavior of SQL CAST on Non-Numeric Tag Values: When a custom tag intended for numeric comparison contains a non-numeric string (e.g., 'N/A', 'Unknown'), SQLite's
CAST(value AS REAL)
operation will convert such strings to0.0
. This can lead to unexpected outcomes, such as non-numeric tags matching conditions liketag = 0
. This was raised as a medium severity issue requiring consideration for potential user impact or documentation. - Test Coverage for Float Types in Comparisons: The new test case
It("casts numeric comparisons")
uses an integer value (6
) for the comparison. While theisNumber
function correctly identifies float types andCAST(... AS REAL)
handles them, explicitly testing with a float literal (e.g.,Lt{"rate": 6.5}
) would offer slightly more direct confirmation for float value comparisons. This was deemed a low severity point and not formally commented on due to the configured review settings.
Merge Readiness
The core functionality of this PR is well-implemented and addresses the stated problem. There is one medium-severity consideration regarding the behavior of CAST
on non-numeric strings that I believe should be discussed or acknowledged before merging to ensure there are no unintended consequences for users. Once that point is addressed (e.g., through documentation, further testing of edge cases, or confirmation of acceptable behavior), the PR should be in good shape. As a reviewer, I am not authorized to approve pull requests.
model/criteria/fields.go
Outdated
if len(args) > 0 && isNumber(args[0]) { | ||
cond = strings.ReplaceAll(cond, "value", "CAST(value AS REAL)") | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change correctly casts the value
column to REAL
when the comparison argument is numeric. This is a good solution for enabling proper numeric comparisons on tags that are stored as text in JSON.
One aspect to consider is the behavior of CAST(value AS REAL)
in SQLite when the value
from the JSON tag is not a valid representation of a number (e.g., if a tag expected to be numeric accidentally contains text like "N/A" or "Unknown"). SQLite typically converts such non-numeric strings to 0.0
during the cast.
For example:
- If a tag
rate
has the string value"abc"
,CAST(value AS REAL)
for this tag would result in0.0
. - A condition like
rate > 5
would then evaluate as0.0 > 5
(false). - A condition like
rate = 0
would evaluate as0.0 = 0
(true), which might be surprising if "abc" was not intended to be equivalent to zero.
Could this behavior lead to any unexpected results for users, particularly for equality checks against 0
or when tags might contain such non-parseable strings?
While this PR correctly implements the casting mechanism for intended numeric comparisons, it might be beneficial to consider if this side-effect needs documentation or if there are any scenarios where this could be problematic for users relying on smart playlists.
/gemini review |
There was a problem hiding this 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 feature for handling numeric comparisons and sorting for custom tags, especially floats. The approach of adding a numeric
flag to mappedField
and using CAST AS REAL
in SQL queries is generally well-aligned with the goal, particularly for SQLite environments. The inclusion of tests for both sorting and filtering scenarios is a positive step.
I have identified one high-severity issue related to how the CAST
operation is applied in tagCond.ToSql
, which could lead to incorrect behavior for string-based operators on numeric tags. Additionally, there's a medium-severity consideration regarding database agnosticism for the CAST AS REAL
syntax.
Addressing the high-severity issue is recommended before merging.
Summary of Findings
- Broad Numeric Casting in Tag Conditions: In
model/criteria/fields.go
, theCAST(value AS REAL)
operation is applied to any tag markednumeric
withintagCond.ToSql()
, regardless of the specific comparison operator. This can cause issues with string-based operators (likeContains
,StartsWith
) by incorrectly casting the value to numeric before the string operation, potentially leading to errors or unexpected results. The cast should be conditional, applying only to numeric comparison operators. - Database-Specific Casting Syntax: The use of
CAST(... AS REAL)
is SQLite-specific. While appropriate for the current context if SQLite is the sole database target, it may require changes if support for other SQL databases is introduced in the future. This is a consideration for long-term maintainability and portability.
Merge Readiness
The pull request makes good progress in supporting numeric comparisons for custom tags. However, due to the high-severity issue identified with the broad application of numeric casting in tagCond.ToSql()
, I recommend addressing this before merging. The suggested change aims to make the casting more precise and avoid unintended side effects with string-based operators.
The medium-severity point about database-specific syntax is more of a long-term consideration and doesn't block the current functionality for SQLite.
As a reviewer, I am not authorized to approve pull requests. Please ensure further review and approval from authorized maintainers after addressing the feedback.
Signed-off-by: Deluan <deluan@navidrome.org>
5a3e285
to
9e1c19e
Compare
Summary
Testing
make test