-
-
Notifications
You must be signed in to change notification settings - Fork 596
Parse.Query.subscribe() and Parse.Query.first() don't work in Parse v3.5.0 #1596
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
Comments
Thanks for opening this issue!
|
What version of Parse Server are you using? |
See #1593 (comment) |
I am using back4app. I'm not quite sure how to check the current server version but based on the other relevant reports, I would assume it's 4.5.0 |
I encountered the same problem. const query = new Parse.Query('Person').addAscending('createdAt');
const firstPerson = await query.first(); This code makes the following error. I can avoid this error by writing: const query = new Parse.Query('Person').addAscending('createdAt');
const [firstPerson] = await query.limit(1).find(); This problem occurs even after changing to v3.4.4 or v3.0.0, so I suspect that it is not a problem with Parse itself, may be caused by a dependent library or back4app etc. |
What is the last version that works for you, where the problem is not occurring? |
When I changed to JS SDK v3.4.4, both first, and subscribe worked for me |
Oh, really?
I'm not sure because I haven't used Parse in the past. Sorry I can't help you. |
Parse.Query.first() error reason and repairRelevant code from each version for query.first:Parse JS JDK v3.4.4:{
key: "first",
value: function (options
/*:: ?: FullOptions*/
)
/*: Promise<ParseObject | void>*/
{
var _this4 = this;
options = options || {};
var findOptions = {};
if (options.hasOwnProperty('useMasterKey')) {
findOptions.useMasterKey = options.useMasterKey;
}
if (options.hasOwnProperty('sessionToken')) {
findOptions.sessionToken = options.sessionToken;
}
if (options.hasOwnProperty('context') && (0, _typeof2.default)(options.context) === 'object') {
findOptions.context = options.context;
}
this._setRequestTask(findOptions);
var controller = _CoreManager.default.getQueryController();
var params = this.toJSON();
params.limit = 1;
var select = this._select;
if (this._queriesLocalDatastore) {
return this._handleOfflineQuery(params).then(function (objects) {
if (!objects[0]) {
return undefined;
}
return objects[0];
});
}
return (0, _find.default)(controller).call(controller, this.className, params, findOptions).then(function (response) {
var objects = response.results;
if (!objects[0]) {
return undefined;
}
if (!objects[0].className) {
objects[0].className = _this4.className;
} // Make sure the data object contains keys for all objects that
// have been requested with a select, so that our cached state
// updates correctly.
if (select) {
handleSelectResult(objects[0], select);
}
if (options.json) {
return objects[0];
} else {
return _ParseObject.default.fromJSON(objects[0], !select);
}
});
}
/**
*Comment describing eachBatch function here
*/
} Parse JS JDK v3.5.0:{
key: "first",
value: function (options
/*:: ?: FullOptions*/
)
/*: Promise<ParseObject | void>*/
{
options = options || {};
var findOptions = {};
if (options.hasOwnProperty('useMasterKey')) {
findOptions.useMasterKey = options.useMasterKey;
}
if (options.hasOwnProperty('sessionToken')) {
findOptions.sessionToken = options.sessionToken;
}
if (options.hasOwnProperty('context') && (0, _typeof2.default)(options.context) === 'object') {
findOptions.context = options.context;
}
this._setRequestTask(findOptions);
var controller = _CoreManager.default.getQueryController();
var params = this.toJSON();
params.limit = 1;
var select = this._select;
if (this._queriesLocalDatastore) {
return this._handleOfflineQuery(params).then(function (objects) {
if (!objects[0]) {
return undefined;
}
return objects[0];
});
}
return (0, _find.default)(controller).call(controller, this.className, params, findOptions).then(function (response) {
var objects = response.results;
if (!objects[0]) {
return undefined;
}
if (!objects[0].className) {
objects[0].className = this.className;
} // Make sure the data object contains keys for all objects that
// have been requested with a select, so that our cached state
// updates correctly.
if (select) {
handleSelectResult(objects[0], select);
}
if (options.json) {
return objects[0];
} else {
return _ParseObject.default.fromJSON(objects[0], !select);
}
});
}
/**
*Comment describing eachBatch function here
*/
} Important changesv3.4.4:Start of query.first function: var _this4 = this; within return value.then(): if (!objects[0].className) {
objects[0].className = _this4.className;
} 3.5.0start of query.first function removes _this4 variable within return value.then(): if (!objects[0].className) {
objects[0].className = this.className;
} Reason for error:the return value of the first() function is: return (0, _find.default)(controller).call(controller, this.className, params, findOptions).then(function (response) {...}) It is important to note that the function within the then call will be run with this set to undefined, due to strict mode; while _this4 in v3.4.4 is a Parse.Query object. Due to this variation, while at first it seems to have the same result upon the removal of the _this4 variable in favor of directly using the this value, due to the use of the variable in a seperate scope, the this value resolves to undefined and this is trying to access undefined.className which (understandably) results in a typeError. this change was likely made to save memory by the removal of a seemingly unnecessary variable, but due to the global scope of the then function, actually causes an error upon calling. Solution:The readdition of the _this4 variable to the top of the first function, and the modification of the assignment line to the code seen in v3.4.4 will resolve the error and return the correct ParseObject value. the corrected code will be (identical to the v3.4.4 code): {
key: "first",
value: function (options
/*:: ?: FullOptions*/
)
/*: Promise<ParseObject | void>*/
{
var _this4 = this;
options = options || {};
var findOptions = {};
if (options.hasOwnProperty('useMasterKey')) {
findOptions.useMasterKey = options.useMasterKey;
}
if (options.hasOwnProperty('sessionToken')) {
findOptions.sessionToken = options.sessionToken;
}
if (options.hasOwnProperty('context') && (0, _typeof2.default)(options.context) === 'object') {
findOptions.context = options.context;
}
this._setRequestTask(findOptions);
var controller = _CoreManager.default.getQueryController();
var params = this.toJSON();
params.limit = 1;
var select = this._select;
if (this._queriesLocalDatastore) {
return this._handleOfflineQuery(params).then(function (objects) {
if (!objects[0]) {
return undefined;
}
return objects[0];
});
}
return (0, _find.default)(controller).call(controller, this.className, params, findOptions).then(function (response) {
var objects = response.results;
if (!objects[0]) {
return undefined;
}
if (!objects[0].className) {
objects[0].className = _this4.className;
} // Make sure the data object contains keys for all objects that
// have been requested with a select, so that our cached state
// updates correctly.
if (select) {
handleSelectResult(objects[0], select);
}
if (options.json) {
return objects[0];
} else {
return _ParseObject.default.fromJSON(objects[0], !select);
}
});
}
/**
*Comment describing eachBatch function here
*/
} I have so far only looked at the code differences for Parse.Query.first(), but I will soon look at Parse.Query.subscribe() and see if I can find the issue(s) that result in that error. My suspicion is that it is a similar or the same issue. |
Parse.Query.subscribe() Error Reason and SolutionQuick warning, this comment is nearly identical to the comment above. To save reading, the v3.5.0 update removed a _this2 variable that captures the this context at the beginning of the subscribe function, which is then referenced within a then statement, whose this value is equal to undefined due to running in strict mode. Relevant code from each version for query.first:Parse JS JDK v3.4.4:{
key: "subscribe",
value: function (query
/*: Object*/
, sessionToken
/*: ?string*/
)
/*: LiveQuerySubscription*/
{
var _this2 = this;
if (!query) {
return;
}
var className = query.className;
var queryJSON = query.toJSON();
var where = queryJSON.where;
var fields = (0, _keys.default)(queryJSON) ? (0, _keys.default)(queryJSON).split(',') : undefined;
var subscribeRequest = {
op: OP_TYPES.SUBSCRIBE,
requestId: this.requestId,
query: {
className: className,
where: where,
fields: fields
}
};
if (sessionToken) {
subscribeRequest.sessionToken = sessionToken;
}
var subscription = new _LiveQuerySubscription.default(this.requestId, query, sessionToken);
this.subscriptions.set(this.requestId, subscription);
this.requestId += 1;
this.connectPromise.then(function () {
_this2.socket.send((0, _stringify.default)(subscribeRequest));
});
return subscription;
}
/**
* After calling unsubscribe you'll stop receiving events from the subscription object.
*
* @param {object} subscription - subscription you would like to unsubscribe from.
*/
} Parse JS JDK v3.5.0:{
key: "subscribe",
value: function (query
/*: Object*/
, sessionToken
/*: ?string*/
)
/*: LiveQuerySubscription*/
{
if (!query) {
return;
}
var className = query.className;
var queryJSON = query.toJSON();
var where = queryJSON.where;
var fields = (0, _keys.default)(queryJSON) ? (0, _keys.default)(queryJSON).split(',') : undefined;
var subscribeRequest = {
op: OP_TYPES.SUBSCRIBE,
requestId: this.requestId,
query: {
className: className,
where: where,
fields: fields
}
};
if (sessionToken) {
subscribeRequest.sessionToken = sessionToken;
}
var subscription = new _LiveQuerySubscription.default(this.requestId, query, sessionToken);
this.subscriptions.set(this.requestId, subscription);
this.requestId += 1;
this.connectPromise.then(function () {
this.socket.send((0, _stringify.default)(subscribeRequest));
});
return subscription;
}
/**
* After calling unsubscribe you'll stop receiving events from the subscription object.
*
* @param {object} subscription - subscription you would like to unsubscribe from.
*/
},{
key: "subscribe",
value: function (query
/*: Object*/
, sessionToken
/*: ?string*/
)
/*: LiveQuerySubscription*/
{
if (!query) {
return;
}
var className = query.className;
var queryJSON = query.toJSON();
var where = queryJSON.where;
var fields = (0, _keys.default)(queryJSON) ? (0, _keys.default)(queryJSON).split(',') : undefined;
var subscribeRequest = {
op: OP_TYPES.SUBSCRIBE,
requestId: this.requestId,
query: {
className: className,
where: where,
fields: fields
}
};
if (sessionToken) {
subscribeRequest.sessionToken = sessionToken;
}
var subscription = new _LiveQuerySubscription.default(this.requestId, query, sessionToken);
this.subscriptions.set(this.requestId, subscription);
this.requestId += 1;
this.connectPromise.then(function () {
this.socket.send((0, _stringify.default)(subscribeRequest));
});
return subscription;
}
/**
* After calling unsubscribe you'll stop receiving events from the subscription object.
*
* @param {object} subscription - subscription you would like to unsubscribe from.
*/
} Important changesv3.4.4:Start of query.subscribe function: var _this2 = this; just before return(error thrown in v4.5.0) this.connectPromise.then(function () {
_this2.socket.send((0, _stringify.default)(subscribeRequest));
}); v3.5.0start of Query.subscribe function removes _this2 variable just before return(error thrown in v4.5.0): this.connectPromise.then(function () {
this.socket.send((0, _stringify.default)(subscribeRequest));
}); Reason for error:the v3.5.0 code uses this line: this.connectPromise.then(function () {
this.socket.send((0, _stringify.default)(subscribeRequest));
}); Similarly to the Parse.Query.first() issue, it is important to note that the function within the then call will be run with this set to undefined due to strict mode; while _this2 in v3.4.4 is a Parse.Query object. Due to this variation, while at first it seems to have the same result upon the removal of the _this2 variable in favor of directly using the this value, due to the use of the variable in a seperate scope, the this value resolves to undefined and this is trying to access undefined.socket which (understandably) results in a typeError. this change was likely made to save memory by the removal of a seemingly unnecessary variable, but due to the global scope of the then function, actually causes an error upon calling. Solution:The readdition of the _this2 variable to the top of the subscribe function, and the modification of the code to the code seen in v3.4.4 will resolve the error and return the correct LiveQuerySubscription value. the corrected code will be (identical to the v3.4.4 code): {
key: "subscribe",
value: function (query
/*: Object*/
, sessionToken
/*: ?string*/
)
/*: LiveQuerySubscription*/
{
var _this2 = this;
if (!query) {
return;
}
var className = query.className;
var queryJSON = query.toJSON();
var where = queryJSON.where;
var fields = (0, _keys.default)(queryJSON) ? (0, _keys.default)(queryJSON).split(',') : undefined;
var subscribeRequest = {
op: OP_TYPES.SUBSCRIBE,
requestId: this.requestId,
query: {
className: className,
where: where,
fields: fields
}
};
if (sessionToken) {
subscribeRequest.sessionToken = sessionToken;
}
var subscription = new _LiveQuerySubscription.default(this.requestId, query, sessionToken);
this.subscriptions.set(this.requestId, subscription);
this.requestId += 1;
this.connectPromise.then(function () {
_this2.socket.send((0, _stringify.default)(subscribeRequest));
});
return subscription;
}
/**
* After calling unsubscribe you'll stop receiving events from the subscription object.
*
* @param {object} subscription - subscription you would like to unsubscribe from.
*/
} |
🎉 This change has been released in version 3.5.1-alpha.2 |
Closing via #1600 |
This should be fixed with https://github.com/parse-community/Parse-SDK-JS/releases/tag/3.5.1-alpha.2, could you try it out and let us know? |
It fixed the problem for me. I was on 3.5.0 and was seeing the same issue. Upgrading to 3.5.1-alpha2 makes the problem go away. |
🎉 This change has been released in version 3.5.1-beta.2 |
🎉 This change has been released in version 3.5.1 |
New Issue Checklist
Issue Description
Parse.Query.subscribe() and Parse.Query.first() throw errors upon calling
Query.first() is also recorded here
Steps to reproduce
Here is a Github Repository that includes files for use in testing this bug.
Create a Parse.Query and call subscribe() on it
alternatively create a LiveQueryClient and call subscribe() on it with a Parse.Query
Actual Outcome
throws error "Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'socket')" upon calling.
Expected Outcome
Expected a subscription object
Environment
Client
The text was updated successfully, but these errors were encountered: