Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #422 +/- ##
==========================================
Coverage 100.00% 100.00%
==========================================
Files 108 108
Lines 15061 15606 +545
Branches 766 812 +46
==========================================
+ Hits 15061 15606 +545
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
5d121ae to
aabff5d
Compare
aabff5d to
da0673d
Compare
75f7914 to
4be6e84
Compare
6164b63 to
fbce886
Compare
586186d to
806058c
Compare
29a3d8c to
0c6daeb
Compare
806058c to
11222bc
Compare
11222bc to
33e8e6f
Compare
0c6daeb to
64712a7
Compare
0b4f87d to
1218be7
Compare
quinlanj
left a comment
There was a problem hiding this comment.
lgtm, but will need to account for the tricky Date case in the future, if we want to support that
packages/entity-database-adapter-knex/src/internal/EntityKnexDataManager.ts
Outdated
Show resolved
Hide resolved
ide
left a comment
There was a problem hiding this comment.
Quin mentioned specifying an entity ID alone as a cursor. I think this is a pattern we will want to use often as it's compact and stable.
packages/entity-database-adapter-knex/src/AuthorizationResultBasedKnexEntityLoader.ts
Outdated
Show resolved
Hide resolved
packages/entity-database-adapter-knex/src/internal/EntityKnexDataManager.ts
Outdated
Show resolved
Hide resolved
e63584e to
3e7e550
Compare
1218be7 to
93efc2f
Compare
3e7e550 to
30fb9dc
Compare
93efc2f to
d216f87
Compare
d216f87 to
0829b03
Compare
30fb9dc to
56ec27d
Compare
351382a to
b43bb56
Compare
|
Updated to use ID alone as the opaque external cursor, and then a sub-query to derive the postgres cursor. A similar approach was already in progress for search trigram similarity so this makes them consistent. |
|
(requesting re-review, easiest to see the diff on graphite by using the versions compare. no tests needed to change which is a good sign) |
b43bb56 to
7f45f60
Compare
# Why This PR adds search capabilities to the existing cursor-based pagination system added in #422 which only supported orderBy ordering. This adds: 1. Case-insensitive pattern matching (ILIKE) - Useful for basic text search across entity fields 2. Trigram similarity search - Provides fuzzy matching capabilities for more advanced search use cases like handling typos or finding similar text This enables building user-facing search features while maintaining the benefits of cursor-based pagination (stable results, efficient queries). # How The implementation introduces a unified PaginationSpecification that supports three strategies: 1. Standard pagination - The existing orderBy-based pagination 2. ILIKE search - Pattern matching with automatic wildcard escaping 3. Trigram search - PostgreSQL trigram similarity with configurable threshold Key implementation details: - Search terms are properly parameterized to prevent SQL injection - ILIKE special characters (%, _, \) are escaped to prevent pattern injection - Results maintain stable cursor-based pagination with proper ordering: - ILIKE: Ordered by search fields, then ID - Trigram: Ordered by exact match priority, similarity score, optional extra fields, then ID # Test Plan The PR includes comprehensive test coverage: - Unit tests for both AuthorizationResultBasedKnexEntityLoader and EnforcingKnexEntityLoader - Integration tests covering: - Forward/backward pagination with search - Multi-field search - Case-insensitive matching - Trigram similarity with various thresholds - Cursor stability across pages - Edge cases (empty results, special characters) - Combined with WHERE clauses - Security validation ensuring proper escaping and parameterization All existing tests pass, confirming backward compatibility for standard pagination when using the new API.
…#453) # Why The one downside of using id-based cursor pagination and subqueries (added in #422, #431) is that it risks the row referenced by the cursor being deleted between pagination requests. It's an edge case though to be clear. Encoding the full cursor alleviates this, but has it's own downsides since trigram similarity isn't encodable and neither are things like Date objects. It is still preferable to use ID-based cursors for all pagination. But it becomes the library's responsibility to explicitly document what the behavior is when a row referenced by the cursor is no longer present. This PR does this. # How When the cursor row is no longer present, the tuple evaluates to `NULL`, which produces a empty page. The alternative to this behavior is to run an id check query ahead of the pagination query, and throw an error if it doesn't exist, or even return the first page of data if it doesn't exist. Both of these are less optimal since they cause unexpected behavior during results consumption. So we keep the behavior as is and explicitly document it. # Test Plan Run new tests.

Why
This is the main goal of the stack that started in #407. It adds a paginated loader for entities for applications that use the knex postgres database adapter.
How
Many many iterations of claude.
The general principle is hoisted from Expo server application code: fetch
limit + 1entities to know if there are more pages.This makes use of the sql loader added in #414 to do the actual page load. Exact implementation described in docblocks.
Next PRs:
includeTotaloption and use postgres windows if possibleSELECT *, COUNT(*) OVER() as total_countTest Plan
Full test coverage and example usage in tests.