Skip to content

feat(google-sheets): add row filtering to read with numeric operators#4822

Merged
waleedlatif1 merged 2 commits into
stagingfrom
waleedlatif1/google-sheets-read-filter
May 31, 2026
Merged

feat(google-sheets): add row filtering to read with numeric operators#4822
waleedlatif1 merged 2 commits into
stagingfrom
waleedlatif1/google-sheets-read-filter

Conversation

@waleedlatif1
Copy link
Copy Markdown
Collaborator

Summary

  • Add row filtering to the Google Sheets read (v2) operation — filter returned rows by a header column using text operators (contains, not_contains, exact, not_equals, starts_with, ends_with) and numeric/ordering operators (gt, gte, lt, lte)
  • Filtering lives in a pure, unit-tested helper (filterSheetRows); adds an optional filter output reporting whether the column was found and how many rows matched
  • Hardening: trim spreadsheetId in write/update/append URL builders, URL-encode the v1 read default range, expose valueInputOption for the update operation
  • Fully backwards compatible — with no filter requested, read output is byte-identical and the filter field is omitted

Type of Change

  • New feature

Testing

  • Added unit tests (filter helper + read transformResponse) — 19 passing
  • Registry-wide block validation (82), tsc, biome, and api-validation gate all green
  • Validated every endpoint and OAuth scope against the live Google Sheets API docs

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

Adds client-side row filtering to the Google Sheets read (v2) operation.
Filter the returned rows by a header column using text operators
(contains, not_contains, exact, not_equals, starts_with, ends_with) and
numeric/ordering operators (gt, gte, lt, lte). Filtering lives in a pure,
unit-tested helper (filterSheetRows) and runs over the fetched read range;
an optional `filter` output reports whether the column was found and how
many rows matched.

Also hardens the surrounding tools:
- trim spreadsheetId in write/update/append URL builders (matches read)
- URL-encode the v1 read default range
- expose valueInputOption for the update operation in the block

Backwards compatible: with no filter requested, read output is byte-
identical and the `filter` field is omitted. The filterMatchType union is
widened additively (4 -> 10 values).
@vercel
Copy link
Copy Markdown

vercel Bot commented May 31, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped May 31, 2026 3:01am

Request Review

@cursor
Copy link
Copy Markdown

cursor Bot commented May 31, 2026

PR Summary

Low Risk
Additive read filtering and optional output field; write paths only trim IDs and adjust append query params, with broad unit test coverage and no auth or data-store changes.

Overview
Google Sheets read (v2) gains optional client-side row filtering after the API fetch: match a header column with expanded text operators (not_contains, not_equals) and ordering operators (gt/gte/lt/lte), implemented in filterSheetRows and wired through readV2Tool.transformResponse. When a filter is requested, read output can include an optional filter object (applied, columnFound, matchedRows, totalRows); with no filter or empty filterValue, behavior stays the same and filter is omitted.

The Google Sheets v2 block UI and I/O docs mirror the new match types and filter output; update now shows value input option in the block. Small API fixes: trim spreadsheetId in write/update/append URLs, encode the v1 read default range, and only send insertDataOption on append when set (API default OVERWRITE). Unit tests cover the filter helper and read transform.

Reviewed by Cursor Bugbot for commit 9866c0b. Configure here.

Comment thread apps/sim/tools/google_sheets/filter.ts Outdated
Comment thread apps/sim/tools/google_sheets/filter.ts Outdated
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 31, 2026

Greptile Summary

This PR adds client-side row filtering to the Google Sheets read (v2) operation, supporting both text operators (contains, not_contains, exact, not_equals, starts_with, ends_with) and ordering operators (gt, gte, lt, lte). Filtering is extracted into a well-tested pure helper (filterSheetRows), and the filter output field is conditionally emitted only when a filter was explicitly requested.

  • New filter.ts helper: Pure, thoroughly tested function that handles numeric vs. lexicographic comparison, sparse rows, header-only sheets, and column-not-found gracefully.
  • read.ts refactor: Replaces the old inline filtering with filterSheetRows, adds the optional filter output field, and applies encodeURIComponent to the v1 default range URL.
  • Hardening: spreadsheetId?.trim() applied consistently to URL builders in append.ts, update.ts, and write.ts; valueInputOption dropdown now shown for the update operation in the block definition.

Confidence Score: 5/5

Safe to merge — the change is fully backwards compatible, filtering is isolated to a pure helper with good test coverage, and all URL builder hardening is defensive-only.

The core filtering logic is correct and well-tested across all operators, edge cases (sparse rows, header-only sheets, empty arrays), and the two bugs caught in the prior review round are addressed. The encodeURIComponent and spreadsheetId?.trim() hardening changes are low-risk. No regressions to existing read behaviour.

filter.ts has two minor correctness edges (early-return columnFound when filterValue is empty, and unpinned locale in compareLexicographic) that are benign for the current sole consumer but worth fixing before the function gains more callers.

Important Files Changed

Filename Overview
apps/sim/tools/google_sheets/filter.ts New pure filtering helper; logic is well-structured with correct handling of numeric operators, empty values, sparse rows, and edge cases from the previous thread.
apps/sim/tools/google_sheets/read.ts Refactored to delegate filtering to filterSheetRows; filterRequested gate correctly controls filter output field inclusion; v1 default range now URL-encoded.
apps/sim/tools/google_sheets/filter.test.ts Comprehensive test coverage (14 cases) covering all operators, edge cases, and the two bugs fixed in the previous round of review.
apps/sim/tools/google_sheets/read.test.ts Five transformResponse unit tests covering no-filter, empty filterValue, applied filter, column-not-found, and no-values-array scenarios.
apps/sim/tools/google_sheets/types.ts Adds GoogleSheetsFilterInfo interface and updates filterMatchType to use the imported SheetFilterMatchType union; clean, consistent change.
apps/sim/blocks/blocks/google_sheets.ts Adds six new dropdown options for filter match types, exposes valueInputOption for update operations, and updates schema descriptions to match new operators.
apps/sim/tools/google_sheets/append.ts Minor hardening: applies spreadsheetId?.trim() to both v1 and v2 URL builders; no functional impact on correct inputs.
apps/sim/tools/google_sheets/update.ts Applies spreadsheetId?.trim() to both v1 and v2 URL builders; safe defensive hardening.
apps/sim/tools/google_sheets/write.ts Applies spreadsheetId?.trim() to both v1 and v2 URL builders; consistent with append and update changes.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[readV2Tool.transformResponse] --> B[Parse response JSON]
    B --> C[rawValues = data.values ?? empty]
    C --> D{filterRequested?\nfilterColumn + filterValue set?}
    D -- No --> E[filterSheetRows returns\noriginal values unchanged]
    D -- Yes --> F[filterSheetRows called\nwith filter options]
    F --> G{filterColumn\nfound in header?}
    G -- No --> H[Return original values\ncolumnFound=false, matchedRows=0]
    G -- Yes --> I{values.length <= 1?\nheader-only / empty?}
    I -- Yes --> J[Return original values\ncolumnFound=true, matchedRows=0]
    I -- No --> K[Filter data rows\nvia matchesCell]
    K --> L{matchType}
    L -- gt/gte/lt/lte --> M{Both numeric?}
    M -- Yes --> N[Numeric compare]
    M -- Both non-numeric --> O[Lexicographic compare]
    M -- Mixed --> P[No match - return false]
    L -- text operators --> Q[Case-insensitive\nstring comparison]
    K --> R[Return header + matched rows\napplied=true]
    E --> S[Output: values only\nno filter field]
    H --> T[Output: original values\n+ filter field with columnFound=false]
    J --> T
    R --> U[Output: filtered values\n+ filter field with applied=true]
Loading

Reviews (2): Last reviewed commit: "fix(google-sheets): correct filter metad..." | Re-trigger Greptile

Comment thread apps/sim/tools/google_sheets/filter.ts Outdated
Comment thread apps/sim/tools/google_sheets/filter.ts Outdated
…ader-only sheets

- matchedRows is now 0 (not totalRows) when the filter column is not found,
  so it no longer contradicts applied=false / columnFound=false
- columnFound now reflects an actual header lookup for empty/header-only
  sheets instead of being hardcoded true
- add tests covering header-only and empty sheets with present/absent columns
@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@cursor review

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 9866c0b. Configure here.

@waleedlatif1 waleedlatif1 merged commit f6685cf into staging May 31, 2026
14 checks passed
@waleedlatif1 waleedlatif1 deleted the waleedlatif1/google-sheets-read-filter branch May 31, 2026 03:09
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.

1 participant