-
-
Notifications
You must be signed in to change notification settings - Fork 4.8k
feat: Allow short circuit of beforeFind #9770
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: alpha
Are you sure you want to change the base?
Conversation
Signed-off-by: Manuel <[email protected]>
Signed-off-by: Manuel <[email protected]>
…-server into beforeFind-fix
🚀 Thanks for opening this pull request! |
📝 Walkthrough""" WalkthroughThe changes introduce a new helper function to centralize the handling of Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant API
participant Triggers
participant DB
Client->>API: find/get request
API->>Triggers: run beforeFind trigger
alt beforeFind returns objects/array
Triggers-->>API: objects/array
API->>Triggers: run afterFind trigger (if defined)
Triggers-->>API: possibly modified objects/array
API-->>Client: return objects/array
else
Triggers-->>API: possibly modified query
API->>DB: execute query
DB-->>API: query results
API->>Triggers: run afterFind trigger (if defined)
Triggers-->>API: possibly modified results
API-->>Client: return results
end
Assessment against linked issues
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
npm warn config production Use 📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
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
CodeRabbit Configuration File (
|
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: 6
🧹 Nitpick comments (1)
src/rest.js (1)
53-54
: Replace French comments with English for consistency.The codebase should maintain consistent language usage throughout.
- // Déclencher le trigger afterFind si des objets sont retournés + // Trigger afterFind if objects are returned- // Conserver la distinction entre get et find + // Maintain the distinction between get and findAlso applies to: 69-69
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
spec/CloudCode.spec.js
(1 hunks)src/rest.js
(2 hunks)src/triggers.js
(2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
spec/CloudCode.spec.js (1)
spec/CloudCode.Validator.spec.js (16)
Parse
(2-2)obj
(657-657)obj
(674-674)obj
(691-691)obj
(713-713)obj
(782-782)obj
(806-806)obj
(835-835)obj
(851-851)obj
(983-983)obj
(1148-1148)obj
(1169-1169)obj
(1181-1181)obj
(1206-1206)obj
(1229-1229)obj
(1247-1247)
🔇 Additional comments (7)
spec/CloudCode.spec.js (3)
204-216
: LGTM: Well-structured test for beforeFind short-circuit functionality.This test correctly validates that
beforeFind
can return a single object directly, bypassing the database query. The test properly:
- Sets up both
beforeFind
andafterFind
triggers- Validates the object properties and class name
- Confirms the returned object can be saved
218-230
: LGTM: Good test for array return from beforeFind.This test correctly validates that
beforeFind
can return an array of objects. The logic is sound and follows the same pattern as the previous test.
246-257
: LGTM: Proper test for empty array return.This test correctly validates that returning an empty array from
beforeFind
results in no objects being found, even when objects exist in the database.src/triggers.js (1)
475-477
: LGTM! Good optimization to avoid unnecessary conversions.This change efficiently prevents redundant JSON-to-Parse.Object conversions when the object is already a Parse.Object instance, improving performance for the short-circuit functionality.
src/rest.js (3)
26-82
: Excellent refactoring! The centralized trigger handling improves maintainability.The
runFindTriggers
function effectively centralizes the beforeFind/afterFind trigger logic and correctly implements the short-circuit functionality. The logic properly:
- Runs the beforeFind trigger first
- Checks for returned objects to enable short-circuiting
- Runs afterFind when objects are present
- Falls back to normal query execution when no objects are returned
The distinction between
get
andfind
operations is preserved through theisGet
parameter.
85-97
: Clean refactoring maintains existing functionality.Both
find
andget
functions are properly refactored to use the newrunFindTriggers
helper while preserving their original behavior through appropriate parameter passing.Also applies to: 100-112
65-65
:✅ Verification successful
Verify _toFullJSON() compatibility with Parse.Object instances.
Ensure that calling
_toFullJSON()
on Parse.Object instances returned from triggers works correctly and produces the expected serialization format.
🏁 Script executed:
#!/bin/bash # Description: Search for _toFullJSON usage and Parse.Object implementations to verify compatibility # Search for _toFullJSON method usage across the codebase rg -A 3 -B 3 "_toFullJSON" # Search for Parse.Object related implementations ast-grep --pattern 'Parse.Object.fromJSON($_)'Length of output: 5795
🏁 Script executed:
#!/bin/bash # Print the first 200 lines of src/rest.js to inspect the find handler sed -n '1,200p' src/rest.jsLength of output: 5761
🏁 Script executed:
#!/bin/bash sed -n '450,550p' src/triggers.js echo "----" sed -n '900,1050p' src/triggers.jsLength of output: 7099
_toFullJSON() Compatibility Confirmed
I’ve verified that any objects returned by triggers are always instances of Parse.Object—triggers wrap plain JSON via Parse.Object.fromJSON—and that parse.Object provides a _toFullJSON() method. Existing tests (e.g. ParseCloudCodePublisher.spec.js) already cover this serialization. No changes required.
spec/CloudCode.spec.js
Outdated
it('beforeFind can return object for get query without DB operation', async () => { | ||
Parse.Cloud.beforeFind('beforeFind', () => { | ||
return [new Parse.Object('TestObject', { foo: 'bar' })]; | ||
}); | ||
Parse.Cloud.afterFind('beforeFind', req => { | ||
expect(req.objects).toBeDefined(); | ||
expect(req.objects[0].get('foo')).toBe('bar'); | ||
}); | ||
const newObj = await new Parse.Query('beforeFind').get('objId'); | ||
expect(newObj.className).toBe('TestObject'); | ||
expect(newObj.toJSON()).toEqual({ foo: 'bar' }); | ||
await newObj.save(); | ||
}); |
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.
Fix test setup: get() query without existing object.
This test calls query.get('objId')
but doesn't create an object with that specific ID. The test should either:
- Create and save an object first, then use its ID
- Use a different approach that doesn't rely on a specific object ID
it('beforeFind can return object for get query without DB operation', async () => {
Parse.Cloud.beforeFind('beforeFind', () => {
return [new Parse.Object('TestObject', { foo: 'bar' })];
});
Parse.Cloud.afterFind('beforeFind', req => {
expect(req.objects).toBeDefined();
expect(req.objects[0].get('foo')).toBe('bar');
});
+ // Create an object first to get a valid ID
+ const testObj = new Parse.Object('beforeFind');
+ await testObj.save();
- const newObj = await new Parse.Query('beforeFind').get('objId');
+ const newObj = await new Parse.Query('beforeFind').get(testObj.id);
expect(newObj.className).toBe('TestObject');
expect(newObj.toJSON()).toEqual({ foo: 'bar' });
await newObj.save();
});
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
it('beforeFind can return object for get query without DB operation', async () => { | |
Parse.Cloud.beforeFind('beforeFind', () => { | |
return [new Parse.Object('TestObject', { foo: 'bar' })]; | |
}); | |
Parse.Cloud.afterFind('beforeFind', req => { | |
expect(req.objects).toBeDefined(); | |
expect(req.objects[0].get('foo')).toBe('bar'); | |
}); | |
const newObj = await new Parse.Query('beforeFind').get('objId'); | |
expect(newObj.className).toBe('TestObject'); | |
expect(newObj.toJSON()).toEqual({ foo: 'bar' }); | |
await newObj.save(); | |
}); | |
it('beforeFind can return object for get query without DB operation', async () => { | |
Parse.Cloud.beforeFind('beforeFind', () => { | |
return [new Parse.Object('TestObject', { foo: 'bar' })]; | |
}); | |
Parse.Cloud.afterFind('beforeFind', req => { | |
expect(req.objects).toBeDefined(); | |
expect(req.objects[0].get('foo')).toBe('bar'); | |
}); | |
+ // Create an object first to get a valid ID | |
+ const testObj = new Parse.Object('beforeFind'); | |
+ await testObj.save(); | |
- const newObj = await new Parse.Query('beforeFind').get('objId'); | |
+ const newObj = await new Parse.Query('beforeFind').get(testObj.id); | |
expect(newObj.className).toBe('TestObject'); | |
expect(newObj.toJSON()).toEqual({ foo: 'bar' }); | |
await newObj.save(); | |
}); |
🤖 Prompt for AI Agents
In spec/CloudCode.spec.js around lines 232 to 244, the test calls
query.get('objId') without creating an object with that ID, causing the test to
fail. Fix this by first creating and saving a Parse.Object, then use its
generated ID in the get() call to ensure the object exists before retrieval.
let objects = undefined; | ||
if (result instanceof Parse.Object) { | ||
objects = [result]; | ||
} else if ( | ||
Array.isArray(result) && | ||
(!result.length || result.some(obj => obj instanceof Parse.Object)) | ||
) { | ||
objects = result; | ||
} | ||
return { | ||
restWhere, | ||
restOptions, | ||
objects, | ||
}; |
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.
🛠️ Refactor suggestion
Review the array type checking logic for edge cases.
The short-circuit logic correctly handles single Parse.Objects and arrays, but the condition (!result.length || result.some(obj => obj instanceof Parse.Object))
could allow mixed arrays (e.g., [parseObject, plainObject]
) to pass through, which might cause issues downstream.
Consider strengthening the array validation to ensure all 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 || result.every(obj => obj instanceof Parse.Object))
+ ) {
objects = result;
}
This ensures that if any object in the array is not a Parse.Object, the short-circuit path is not taken, maintaining consistency.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
let objects = undefined; | |
if (result instanceof Parse.Object) { | |
objects = [result]; | |
} else if ( | |
Array.isArray(result) && | |
(!result.length || result.some(obj => obj instanceof Parse.Object)) | |
) { | |
objects = result; | |
} | |
return { | |
restWhere, | |
restOptions, | |
objects, | |
}; | |
let objects = undefined; | |
if (result instanceof Parse.Object) { | |
objects = [result]; | |
} else if ( | |
Array.isArray(result) && | |
(!result.length || result.every(obj => obj instanceof Parse.Object)) | |
) { | |
objects = result; | |
} | |
return { | |
restWhere, | |
restOptions, | |
objects, | |
}; |
🤖 Prompt for AI Agents
In src/triggers.js around lines 613 to 626, the current array type check allows
arrays with mixed types (Parse.Object and non-Parse.Object) to pass, which can
cause issues. Update the condition to verify that all elements in the array are
instances of Parse.Object by replacing the some() check with an every() check.
This ensures only arrays fully composed of Parse.Objects are accepted,
preventing mixed-type arrays from being processed incorrectly.
🎉 Snyk checks have passed. No issues have been found so far.✅ security/snyk check is complete. No issues have been found. (View Details) |
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
Summary by CodeRabbit