Skip to content

Conversation

EmpiDev
Copy link

@EmpiDev EmpiDev commented May 27, 2025

Pull Request

Issue

Closes: #8693

Approach

This PR continues and supersedes #8694 by @dblythy.
Adds ability to return objects (or an empty array) from a beforeFind trigger.

Tasks

  • Add tests

Summary by CodeRabbit

  • New Features
    • Enhanced support for advanced query triggers, allowing custom objects or arrays of objects to be returned directly from triggers, including for empty results.
  • Bug Fixes
    • Improved handling of objects returned from triggers to ensure correct processing and accessibility in subsequent operations.
  • Tests
    • Added comprehensive test cases to verify new trigger behaviors and ensure correct object handling in various scenarios.

Copy link

🚀 Thanks for opening this pull request!

Copy link

coderabbitai bot commented May 27, 2025

📝 Walkthrough

Walkthrough

The changes introduce support for short-circuiting the database query in Parse Server by allowing beforeFind triggers to return objects or arrays of objects directly. The control flow for both find and get operations is refactored to delegate trigger handling and query execution to a shared helper. Tests are added to verify the new behavior.

Changes

File(s) Change Summary
spec/CloudCode.spec.js Added tests verifying that beforeFind can return single or multiple objects (including unsaved and empty arrays), bypassing DB queries, and that afterFind receives the correct objects.
src/rest.js Refactored find and get to use new runFindTriggers helper; added logic to bypass DB queries if beforeFind returns objects directly.
src/triggers.js Enhanced trigger handling to recognize and propagate Parse.Object instances returned from beforeFind; normalized output for downstream use.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant REST API
    participant runFindTriggers
    participant beforeFindTrigger
    participant afterFindTrigger
    participant Database

    Client->>REST API: find/get request
    REST API->>runFindTriggers: call with query params
    runFindTriggers->>beforeFindTrigger: run beforeFind
    alt beforeFind returns objects/array
        runFindTriggers->>afterFindTrigger: run afterFind with objects
        afterFindTrigger-->>runFindTriggers: modified objects
        runFindTriggers-->>REST API: return objects as JSON
    else beforeFind returns nothing
        runFindTriggers->>Database: execute query
        Database-->>runFindTriggers: query results
        runFindTriggers->>afterFindTrigger: run afterFind with results
        afterFindTrigger-->>runFindTriggers: modified results
        runFindTriggers-->>REST API: return results as JSON
    end
    REST API-->>Client: response
Loading

Assessment against linked issues

Objective Addressed Explanation
Allow beforeFind to return objects, bypassing the inbuilt RestQuery (#8693)
Allow beforeFind to return an empty array, gracefully cancelling a query (#8693)
Ensure afterFind receives the correct objects when beforeFind returns objects/arrays (#8693)
Support for both find and get operations with beforeFind short-circuiting (#8693)

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

npm warn config production Use --omit=dev instead.
npm warn EBADENGINE Unsupported engine {
npm warn EBADENGINE package: 'parse@4.1.0',
npm warn EBADENGINE required: { node: '>=14.21.0 <17 || >=18 <20' },
npm warn EBADENGINE current: { node: 'v24.1.0', npm: '11.3.0' }
npm warn EBADENGINE }
npm error Exit handler never called!
npm error This is an error with npm itself. Please report this error at:
npm error https://github.com/npm/cli/issues
npm error A complete log of this run can be found in: /.npm/_logs/2025-05-27T08_58_18_647Z-debug-0.log


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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need 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)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (3)
src/triggers.js (1)

592-600: Consider stricter array validation for better type safety.

The logic correctly identifies when a beforeFind trigger returns objects to short-circuit the query. However, the array validation using some() could accept arrays with mixed types (Parse.Objects and plain objects), which might cause issues downstream.

Consider this more strict validation to ensure all array elements are Parse.Objects:

-        } else if (
-          Array.isArray(result) &&
-          (!result.length || result.some(obj => obj instanceof Parse.Object))
-        ) {
+        } else if (
+          Array.isArray(result) &&
+          (result.length === 0 || result.every(obj => obj instanceof Parse.Object))
+        ) {

This ensures that either the array is empty (valid empty result) or all elements are Parse.Objects, preventing potential type inconsistencies.

spec/CloudCode.spec.js (2)

231-244: Consider using a more realistic object ID in the get query test.

While this test correctly validates the get query scenario, using a hardcoded string 'objId' as the object ID parameter may not represent realistic usage patterns. Consider using a properly formatted object ID or documenting why this specific value is used.

-    const newObj = await new Parse.Query('beforeFind').get('objId');
+    const newObj = await new Parse.Query('beforeFind').get('validObjectIdFormat');

Alternatively, you could generate a valid object ID format or add a comment explaining the test scenario.


203-257: Consider more descriptive class names for better test clarity.

All four new tests use 'beforeFind' as the class name, which could be confusing since it's also the name of the trigger type being tested. Consider using more descriptive class names like 'TestObject', 'BeforeFindTestClass', or specific names for each test scenario to improve readability and reduce confusion.

Example for better clarity:

-Parse.Cloud.beforeFind('beforeFind', () => {
+Parse.Cloud.beforeFind('BeforeFindTestClass', () => {
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 40bad26 and d66fa48.

📒 Files selected for processing (3)
  • spec/CloudCode.spec.js (1 hunks)
  • src/rest.js (1 hunks)
  • src/triggers.js (2 hunks)
🔇 Additional comments (11)
src/triggers.js (2)

458-461: LGTM: Good optimization to prevent redundant object conversion.

The instance check prevents unnecessary re-conversion of objects that are already Parse.Object instances, improving performance and avoiding potential issues with redundant processing.


604-604: LGTM: Objects property correctly enables result short-circuiting.

The objects property allows the calling code to access the Parse.Objects returned by the beforeFind trigger, enabling the short-circuit behavior described in the PR objectives.

spec/CloudCode.spec.js (3)

203-216: Good test coverage for beforeFind returning a single object.

This test effectively validates that beforeFind can return a single Parse.Object instance that bypasses the database query. The test structure is solid and validates both the trigger behavior and that the returned object is a proper Parse object that can be saved.


217-230: Well-implemented test for beforeFind returning an array of objects.

This test properly validates the array return functionality and maintains consistency with the previous test pattern. The verification that afterFind receives the correct objects is particularly good.


245-257: Excellent test for empty array return scenario.

This test effectively validates the edge case where beforeFind returns an empty array, properly setting up a real object in the database to ensure the trigger actually bypasses the query. The expectation that newObj is undefined correctly validates the behavior.

src/rest.js (6)

26-35: LGTM: Well-structured function signature.

The function signature is clear and comprehensive, properly accepting all necessary parameters including the new isGet flag to distinguish between find and get operations.


36-47: LGTM: Proper trigger execution and parameter updates.

The beforeFind trigger is executed correctly, and the function properly updates restWhere and restOptions from the trigger result using fallback assignment.


63-74: LGTM: Fallback query execution is correct.

The fallback to normal RestQuery execution when no objects are returned by the trigger is implemented correctly, maintaining backward compatibility.


77-80: LGTM: Clean refactoring of find function.

The function is now properly focused on its core responsibilities: enforcing security and delegating to the shared helper. This reduces code duplication and improves maintainability.


85-94: LGTM: Consistent implementation of get function.

The get function correctly calls runFindTriggers with the appropriate parameters, including the isGet flag and the objectId constraint. This maintains the expected behavior while leveraging the shared logic.


48-62:

✅ Verification successful

Verify object type assumptions in trigger-returned objects.

The code assumes that objects returned by the beforeFind trigger have a _toFullJSON() method. While this should be handled by the trigger normalization mentioned in the AI summary, it would be good to verify this assumption.


🏁 Script executed:

#!/bin/bash
# Description: Verify that maybeRunQueryTrigger normalizes returned objects to Parse.Object instances
# Expected: Find evidence that the trigger system ensures returned objects are Parse.Object instances

# Search for maybeRunQueryTrigger implementation and object normalization
ast-grep --pattern 'maybeRunQueryTrigger($$$) {
  $$$
}'

# Search for object normalization or Parse.Object conversion in triggers
rg -A 10 -B 5 "Parse\.Object\.(fromJSON|new)" src/triggers.js

Length of output: 1217


Verified: Trigger-returned objects are Parse.Object instances

I confirmed that in src/triggers.js the afterFind pipeline runs each returned item through:

if (object instanceof Parse.Object) {
  return object;
}
return Parse.Object.fromJSON(object);

This guarantees that every object has the _toFullJSON() method. No further action is needed.

@EmpiDev EmpiDev closed this May 27, 2025
@parseplatformorg
Copy link
Contributor

⚠️ Snyk checks are incomplete.

⚠️ security/snyk check encountered an error. (View Details)

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.

Allow beforeFind to be short circuited

4 participants