-
Notifications
You must be signed in to change notification settings - Fork 4.4k
Feat: Lazy-load relationships #9669
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
base: 1.7.x
Are you sure you want to change the base?
Conversation
WalkthroughThe changes implement conditional relationship traversal in database document queries, based on the presence of selection clauses. In the API controller, the code now checks for selection queries and disables recursive relationship loading when none are present. The request filter system is enhanced to support dependency injection of the project-specific database and route, allowing the filter for version 1.9 to access related collection keys and modify select queries for backward compatibility. Composer dependencies are updated to use a development branch for the database package and a new cache version. The abstract filter and V19 filter classes are extended with new methods and logic to support these features. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant API_Controller
participant Filter_V19
participant ProjectDB
Client->>API_Controller: Request documents (list/get)
API_Controller->>Filter_V19: Apply request filter (with db and route)
Filter_V19->>ProjectDB: Retrieve related collection keys (if needed)
Filter_V19-->>API_Controller: Return possibly modified queries
API_Controller->>ProjectDB: Fetch documents (skipRelationships if no selections)
ProjectDB-->>API_Controller: Return documents
API_Controller-->>Client: Respond with documents
Poem
✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
Documentation and Community
|
Security Scan Results for PRDocker Image Scan Results
Source Code Scan Results🎉 No vulnerabilities found! |
✨ Benchmark results
⚡ Benchmark Comparison
|
…zy-load-relationships
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.
Actionable comments posted: 2
🧹 Nitpick comments (3)
src/Appwrite/Utopia/Request/Filter.php (2)
10-12
: Consider giving typed properties an explicit default valueAlthough the constructor normally initialises
$route
and$dbForProject
, it is still possible for an extending class to forget callingparent::__construct()
, leaving the properties un-initialised and triggering aTyped property must not be accessed before initialization
error. Adding a= null
default makes the class more defensive at virtually zero cost.- private ?Route $route; - private ?Database $dbForProject; + private ?Route $route = null; + private ?Database $dbForProject = null;
47-56
: Broaden the caught throwable & remove redundant null-coalescing
Route::getParamValue()
may throw anyThrowable
, not onlyException
(e.g.Error
). Catching\Throwable
is safer.
Also, the null-coalescing operator already covers the route isnull
case, so the surroundingtry/catch
only needs to protect against the method throwing. This tiny refactor keeps the intent but avoids double work:- try { - $value = $this->route?->getParamValue($key) ?? $default; - } catch (\Exception $e) { - $value = $default; - } + try { + return $this->route?->getParamValue($key) ?? $default; + } catch (\Throwable) { + return $default; + } - - return $value;src/Appwrite/Utopia/Request/Filters/V19.php (1)
30-36
: Redundant prefix check
$isDatabaseModel
is always true when$model
equals eitherdatabases.listDocuments
ordatabases.getDocument
. Removing the extrastr_starts_with
simplifies the guard clause:- $isDatabaseModel = \str_starts_with($model, 'databases.'); - $isTargetOperation = \in_array($model, ['databases.listDocuments', 'databases.getDocument']); - - if (! $isDatabaseModel || ! $isTargetOperation) { + if (!\in_array($model, ['databases.listDocuments', 'databases.getDocument'], true)) { return $content; }
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
composer.lock
is excluded by!**/*.lock
📒 Files selected for processing (5)
app/controllers/api/databases.php
(2 hunks)app/controllers/general.php
(1 hunks)composer.json
(3 hunks)src/Appwrite/Utopia/Request/Filter.php
(2 hunks)src/Appwrite/Utopia/Request/Filters/V19.php
(1 hunks)
🔇 Additional comments (7)
app/controllers/general.php (1)
833-834
:✅ Verification successful
Dependency injection improves request filter capabilities for handling relationship queries.
The change injects the project database instance and route object into the RequestV19 filter, enabling it to access collection metadata and modify query selections to control relationship loading behavior. This aligns with the PR objective of implementing lazy loading for relationships, ensuring backward compatibility for versions before 1.7.0.
🏁 Script executed:
#!/bin/bash # Verify how the V19 filter class uses these dependencies # Look for the V19 filter class implementation echo "Searching for V19 filter implementation..." rg --type php -A 15 "class V19" src/Length of output: 3774
🏁 Script executed:
#!/bin/bash # Display the full V19 request filter implementation to verify constructor and manageSelectQueries usage rg --type php -A200 "class V19 extends Filter" src/Appwrite/Utopia/Request/Filters/V19.phpLength of output: 3500
🏁 Script executed:
#!/bin/bash # Verify Filter base class constructor signature and dependency handling rg --type php -A200 "class Filter" src/Appwrite/Utopia/Request/Filters/Filter.phpLength of output: 170
🏁 Script executed:
#!/bin/bash # Search for base Filter class definition across the src directory rg --type php -n "class Filter" src/Length of output: 165
🏁 Script executed:
#!/bin/bash # Show the Request Filter base class implementation sed -n '1,200p' src/Appwrite/Utopia/Request/Filter.php # Check for constructor definition in Filter rg --type php -n "__construct" src/Appwrite/Utopia/Request/Filter.phpLength of output: 1457
Dependency injection correctly enhances RequestV19 filter
Injecting the project’s Database instance and the Route into the RequestV19 filter aligns perfectly with how the base
Filter
constructor is defined (__construct(Database $dbForProject = null, Route $route = null)
). This grants the filter access to:
getDbForProject()
for resolving collection metadatagetParamValue()
for extractingdatabaseId
andcollectionId
from the routewhich it uses in
manageSelectQueries()
to preserve 1.6.x behavior (including related documents by default) while maintaining lazy-loading support for 1.7.x+. This change meets the PR’s goal of backward-compatible relationship loading.composer.json (3)
52-52
: Cache dependency updated.The
utopia-php/cache
package has been updated to version 0.13.*, which likely includes improvements or features needed to support the lazy-loading relationship functionality.
97-102
: Added custom repository source for the database package.This configuration directs Composer to fetch the
utopia-php/database
package directly from the GitHub repository instead of Packagist, which is necessary to use the development branch specified above.
56-56
:❓ Verification inconclusive
Using a development branch for database package.
The dependency on
utopia-php/database
has been changed from a stable version to a development branch specifically created for handling wildcards in queries. This branch is required for implementing the relationship lazy-loading functionality described in the PR.
🏁 Script executed:
#!/bin/bash # Check if there's a reference to a related PR for the database package # Look for references to the related database PR in the current repo echo "Searching for references to the utopia-php/database PR..." rg -i "utopia.*database.*PR" --type mdLength of output: 165
Please verify the “dev-manage-wildcards” alias for utopia-php/database
It looks like you’ve switched
utopia-php/database
to a development branch alias:• composer.json: line 56
"utopia-php/database": "dev-manage-wildcards as 0.66.0",Before we merge, confirm that:
- The
dev-manage-wildcards
branch exists and is up-to-date in the utopia-php/database repo.- That branch has been published (or is accessible) via Packagist under the correct version alias.
- Any consumers of this package in the repo will still resolve correctly to the expected API.
app/controllers/api/databases.php (2)
3513-3522
: Well-implemented optimization of database queries!This change implements the lazy-loading of relationships by checking for selection queries before deciding how to fetch documents. When no selections are present, the code skips loading relationships, which should significantly improve performance for documents with many relationships.
3673-3684
: Consistent implementation of lazy-loading in the getDocument endpoint.Similar to the change in listDocuments, this implements lazy-loading for single document retrieval. The conditional relationship loading is well-structured and mirrors the implementation in the list endpoint, ensuring consistent behavior throughout the API.
src/Appwrite/Utopia/Request/Filters/V19.php (1)
43-45
: Verify key used inQuery::groupByType()
resultYou access the grouped array via
['selections']
.
In Utopia Database, the key is usually derived from the constant (Query::TYPE_SELECT
), so it may be'selects'
. A mismatch yields an empty$selections
, making the wildcard-detection loop ineffective when explicit selects are supplied.Please double-check the constant name or update the index:
$groups = Query::groupByType($parsed); $selections = $groups[Query::TYPE_SELECT.'s'] ?? [];(Adjust if the library already uses the plural form you expect.)
What does this PR do?
Skips fetching related documents unless explicitly requested via
select
queries.Default behavior
GET
Response
With nested relationship selects
GET
PARAMS
Response
Test Plan
Manual.
Related PRs and Issues
Checklist
Summary by CodeRabbit