-
-
Notifications
You must be signed in to change notification settings - Fork 4.8k
feat: Add a new beforeLiveQueryEvent
trigger
#9445
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?
Changes from all commits
2a82525
a17e22c
f3a6ed4
82ea402
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -1308,4 +1308,128 @@ describe('ParseLiveQuery', function () { | |||||||||||||||||||||||||
await new Promise(resolve => setTimeout(resolve, 100)); | ||||||||||||||||||||||||||
expect(createSpy).toHaveBeenCalledTimes(1); | ||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
it('test beforeLiveQueryEvent ran while creating an object', async function () { | ||||||||||||||||||||||||||
await reconfigureServer({ | ||||||||||||||||||||||||||
liveQuery: { | ||||||||||||||||||||||||||
classNames: ['TestObject'], | ||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||
startLiveQueryServer: true, | ||||||||||||||||||||||||||
verbose: false, | ||||||||||||||||||||||||||
silent: true, | ||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
Parse.Cloud.beforeLiveQueryEvent('TestObject', req => { | ||||||||||||||||||||||||||
expect(req.user).toBeUndefined(); | ||||||||||||||||||||||||||
expect(req.object.get('foo')).toBe('bar'); | ||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
const query = new Parse.Query(TestObject); | ||||||||||||||||||||||||||
const subscription = await query.subscribe(); | ||||||||||||||||||||||||||
subscription.on('create', object => { | ||||||||||||||||||||||||||
expect(object.get('foo')).toBe('bar'); | ||||||||||||||||||||||||||
done(); | ||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
const object = new TestObject(); | ||||||||||||||||||||||||||
object.set('foo', 'bar'); | ||||||||||||||||||||||||||
await object.save(); | ||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
it('test beforeLiveQueryEvent ran while updating an object', async function (done) { | ||||||||||||||||||||||||||
await reconfigureServer({ | ||||||||||||||||||||||||||
liveQuery: { | ||||||||||||||||||||||||||
classNames: ['TestObject'], | ||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||
startLiveQueryServer: true, | ||||||||||||||||||||||||||
verbose: false, | ||||||||||||||||||||||||||
silent: true, | ||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||
const object = new TestObject(); | ||||||||||||||||||||||||||
object.set('foo', 'bar'); | ||||||||||||||||||||||||||
await object.save(); | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
Parse.Cloud.afterSave('TestObject', async req => { | ||||||||||||||||||||||||||
expect(req.object.get('foo')).toBe('baz'); | ||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||
Parse.Cloud.beforeLiveQueryEvent('TestObject', async req => { | ||||||||||||||||||||||||||
expect(req.object.get('foo')).toBe('baz'); | ||||||||||||||||||||||||||
req.object.set('foo', 'rebaz'); | ||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||
Parse.Cloud.afterLiveQueryEvent('TestObject', req => { | ||||||||||||||||||||||||||
expect(req.event).toBe('update'); | ||||||||||||||||||||||||||
expect(req.user).toBeUndefined(); | ||||||||||||||||||||||||||
expect(req.object.get('foo')).toBe('rebaz'); | ||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
const query = new Parse.Query(TestObject); | ||||||||||||||||||||||||||
const subscription = await query.subscribe(); | ||||||||||||||||||||||||||
subscription.on('update', object => { | ||||||||||||||||||||||||||
expect(object.get('foo')).toBe('rebaz'); | ||||||||||||||||||||||||||
done(); | ||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
object.set('foo', 'baz') | ||||||||||||||||||||||||||
await object.save(); | ||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
it('test beforeLiveQueryEvent should filter specific object creation', async function () { | ||||||||||||||||||||||||||
await reconfigureServer({ | ||||||||||||||||||||||||||
liveQuery: { | ||||||||||||||||||||||||||
classNames: ['TestObject'], | ||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||
startLiveQueryServer: true, | ||||||||||||||||||||||||||
verbose: false, | ||||||||||||||||||||||||||
silent: true, | ||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
Parse.Cloud.beforeLiveQueryEvent('TestObject', req => { | ||||||||||||||||||||||||||
expect(req.object.get('foo')).toBe('bar'); | ||||||||||||||||||||||||||
if (req.object.get('foo') === 'bar') { | ||||||||||||||||||||||||||
req.context.preventLiveQuery === true; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||
Comment on lines
+1388
to
+1393
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix critical bug in preventLiveQuery logic. You're using a comparison operator ( - if (req.object.get('foo') === 'bar') {
- req.context.preventLiveQuery === true;
+ if (req.object.get('foo') === 'bar') {
+ req.context.preventLiveQuery = true;
} 📝 Committable suggestion
Suggested change
🧰 Tools🪛 ESLint[error] 1389-1389: 'expect' is not defined. (no-undef) 🤖 Prompt for AI Agents (early access)
|
||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
const query = new Parse.Query(TestObject).equalTo('foo', 'bar'); | ||||||||||||||||||||||||||
const subscription = await query.subscribe(); | ||||||||||||||||||||||||||
subscription.on('create', () => { | ||||||||||||||||||||||||||
fail('create should not have been called.'); | ||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
const object = new TestObject(); | ||||||||||||||||||||||||||
object.set('foo', 'bar'); | ||||||||||||||||||||||||||
await object.save(); | ||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
it('test beforeLiveQueryEvent should filter specific object update', async function () { | ||||||||||||||||||||||||||
await reconfigureServer({ | ||||||||||||||||||||||||||
liveQuery: { | ||||||||||||||||||||||||||
classNames: ['TestObject'], | ||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||
startLiveQueryServer: true, | ||||||||||||||||||||||||||
verbose: false, | ||||||||||||||||||||||||||
silent: true, | ||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||
const object = new TestObject(); | ||||||||||||||||||||||||||
object.set('foo', 'bar'); | ||||||||||||||||||||||||||
await object.save(); | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
Parse.Cloud.beforeLiveQueryEvent('TestObject', async req => { | ||||||||||||||||||||||||||
expect(req.object.get('foo')).toBe('baz'); | ||||||||||||||||||||||||||
if (req.object.get('foo') === 'baz') { | ||||||||||||||||||||||||||
req.context.preventLiveQuery === true; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||
Comment on lines
+1419
to
+1424
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix critical bug in preventLiveQuery logic. Same issue as in the previous test - you're using a comparison operator ( - if (req.object.get('foo') === 'baz') {
- req.context.preventLiveQuery === true;
+ if (req.object.get('foo') === 'baz') {
+ req.context.preventLiveQuery = true;
} 📝 Committable suggestion
Suggested change
🧰 Tools🪛 ESLint[error] 1420-1420: 'expect' is not defined. (no-undef) 🤖 Prompt for AI Agents (early access)
|
||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
const query = new Parse.Query(TestObject).equalTo('foo', 'baz'); | ||||||||||||||||||||||||||
const subscription = await query.subscribe(); | ||||||||||||||||||||||||||
subscription.on('update', object => { | ||||||||||||||||||||||||||
fail('update should not have been called.'); | ||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
object.set('foo', 'baz') | ||||||||||||||||||||||||||
await object.save(); | ||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||
}); |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -1645,7 +1645,7 @@ RestWrite.prototype.runDatabaseOperation = function () { | |||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
// Returns nothing - doesn't wait for the trigger. | ||||||||||||||||||||||||||||||||||||||||
RestWrite.prototype.runAfterSaveTrigger = function () { | ||||||||||||||||||||||||||||||||||||||||
RestWrite.prototype.runAfterSaveTrigger = async function () { | ||||||||||||||||||||||||||||||||||||||||
if (!this.response || !this.response.response || this.runOptions.many) { | ||||||||||||||||||||||||||||||||||||||||
return; | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
|
@@ -1660,21 +1660,31 @@ RestWrite.prototype.runAfterSaveTrigger = function () { | |||||||||||||||||||||||||||||||||||||||
if (!hasAfterSaveHook && !hasLiveQuery) { | ||||||||||||||||||||||||||||||||||||||||
return Promise.resolve(); | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
const { originalObject, updatedObject } = this.buildParseObjects(); | ||||||||||||||||||||||||||||||||||||||||
updatedObject._handleSaveResponse(this.response.response, this.response.status || 200); | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
if (hasLiveQuery) { | ||||||||||||||||||||||||||||||||||||||||
this.config.database.loadSchema().then(schemaController => { | ||||||||||||||||||||||||||||||||||||||||
// Notify LiveQueryServer if possible | ||||||||||||||||||||||||||||||||||||||||
const perms = schemaController.getClassLevelPermissions(updatedObject.className); | ||||||||||||||||||||||||||||||||||||||||
this.config.liveQueryController.onAfterSave( | ||||||||||||||||||||||||||||||||||||||||
updatedObject.className, | ||||||||||||||||||||||||||||||||||||||||
updatedObject, | ||||||||||||||||||||||||||||||||||||||||
originalObject, | ||||||||||||||||||||||||||||||||||||||||
perms | ||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||
const hasBeforeEventHook = triggers.triggerExists( | ||||||||||||||||||||||||||||||||||||||||
this.className, | ||||||||||||||||||||||||||||||||||||||||
triggers.Types.beforeEvent, | ||||||||||||||||||||||||||||||||||||||||
this.config.applicationId | ||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||
const publishedObject = updatedObject.clone(); | ||||||||||||||||||||||||||||||||||||||||
if (hasBeforeEventHook) { | ||||||||||||||||||||||||||||||||||||||||
await triggers.maybeRunTrigger(triggers.Types.beforeEvent, this.auth, publishedObject, originalObject, this.config, this.context); | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
if (this.context.preventLiveQuery !== true) { | ||||||||||||||||||||||||||||||||||||||||
this.config.database.loadSchema().then(schemaController => { | ||||||||||||||||||||||||||||||||||||||||
// Notify LiveQueryServer if possible | ||||||||||||||||||||||||||||||||||||||||
const perms = schemaController.getClassLevelPermissions(publishedObject.className); | ||||||||||||||||||||||||||||||||||||||||
this.config.liveQueryController.onAfterSave( | ||||||||||||||||||||||||||||||||||||||||
publishedObject.className, | ||||||||||||||||||||||||||||||||||||||||
publishedObject, | ||||||||||||||||||||||||||||||||||||||||
originalObject, | ||||||||||||||||||||||||||||||||||||||||
perms | ||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||
Comment on lines
+1677
to
+1686
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Await the schema call to avoid silent LiveQuery failures
- this.config.database.loadSchema().then(schemaController => {
- // Notify LiveQueryServer if possible
- const perms = schemaController.getClassLevelPermissions(publishedObject.className);
- this.config.liveQueryController.onAfterSave(
- publishedObject.className,
- publishedObject,
- originalObject,
- perms
- );
- });
+ const schemaController = await this.config.database.loadSchema();
+ // Notify LiveQueryServer if possible
+ const perms = schemaController.getClassLevelPermissions(publishedObject.className);
+ this.config.liveQueryController.onAfterSave(
+ publishedObject.className,
+ publishedObject,
+ originalObject,
+ perms
+ ); This keeps the method “fire-and-forget” semantics for LiveQuery success but still propagates unexpected errors up the promise chain for proper logging / retries. 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents (early access)
|
||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
if (!hasAfterSaveHook) { | ||||||||||||||||||||||||||||||||||||||||
return Promise.resolve(); | ||||||||||||||||||||||||||||||||||||||||
|
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 callback handling.
This test is using
done()
on line 1332, but the function doesn't receive thedone
parameter. The test should either:done
as a parameter and call it at the end, orasync/await
properly📝 Committable suggestion
🧰 Tools
🪛 ESLint
[error] 1312-1312: 'it' is not defined.
(no-undef)
[error] 1313-1313: 'reconfigureServer' is not defined.
(no-undef)
[error] 1324-1324: 'expect' is not defined.
(no-undef)
[error] 1325-1325: 'expect' is not defined.
(no-undef)
[error] 1328-1328: 'TestObject' is not defined.
(no-undef)
[error] 1331-1331: 'expect' is not defined.
(no-undef)
[error] 1332-1332: 'done' is not defined.
(no-undef)
[error] 1335-1335: 'TestObject' is not defined.
(no-undef)
🤖 Prompt for AI Agents (early access)