diff --git a/DEPRECATIONS.md b/DEPRECATIONS.md index a6477822104..56359c937e0 100644 --- a/DEPRECATIONS.md +++ b/DEPRECATIONS.md @@ -12,6 +12,7 @@ The following is a list of deprecations, according to the [Deprecation Policy](h | DEPPS6 | Auth providers disabled by default | [#7953](https://github.com/parse-community/parse-server/pull/7953) | 5.3.0 (2022) | 7.0.0 (2024) | deprecated | - | | DEPPS7 | Remove file trigger syntax `Parse.Cloud.beforeSaveFile((request) => {})` | [#7966](https://github.com/parse-community/parse-server/pull/7966) | 5.3.0 (2022) | 7.0.0 (2024) | deprecated | - | | DEPPS8 | Login with expired 3rd party authentication token defaults to `false` | [#7079](https://github.com/parse-community/parse-server/pull/7079) | 5.3.0 (2022) | 7.0.0 (2024) | deprecated | - | +| DEPPS9 | Rename LiveQuery `fields` option to `keys` | [#8389](https://github.com/parse-community/parse-server/issues/8389) | 6.0.0 (2023) | 7.0.0 (2024) | deprecated | - | [i_deprecation]: ## "The version and date of the deprecation." [i_removal]: ## "The version and date of the planned removal." diff --git a/spec/ParseLiveQueryServer.spec.js b/spec/ParseLiveQueryServer.spec.js index 47e90733a1b..5b4690ae854 100644 --- a/spec/ParseLiveQueryServer.spec.js +++ b/spec/ParseLiveQueryServer.spec.js @@ -294,7 +294,7 @@ describe('ParseLiveQueryServer', function () { where: { key: 'value', }, - fields: ['test'], + keys: ['test'], }; const requestId = 2; const request = { @@ -331,7 +331,7 @@ describe('ParseLiveQueryServer', function () { where: { key: 'value', }, - fields: ['test'], + keys: ['test'], }; const requestId = 2; const request = { @@ -378,7 +378,7 @@ describe('ParseLiveQueryServer', function () { where: { key: 'value', }, - fields: ['test'], + keys: ['test'], }; await addMockSubscription(parseLiveQueryServer, clientId, requestId, parseWebSocket, query); // Add subscription for mock client 2 @@ -390,7 +390,7 @@ describe('ParseLiveQueryServer', function () { where: { key: 'value', }, - fields: ['testAgain'], + keys: ['testAgain'], }; const requestIdAgain = 1; await addMockSubscription( @@ -1060,7 +1060,7 @@ describe('ParseLiveQueryServer', function () { where: { key: 'value', }, - fields: ['test'], + keys: ['test'], }; await addMockSubscription(parseLiveQueryServer, clientId, requestId, parseWebSocket, query); // Mock _matchesSubscription to return matching @@ -1087,6 +1087,62 @@ describe('ParseLiveQueryServer', function () { done(); }); + it('can deprecate fields', async () => { + const Deprecator = require('../lib/Deprecator/Deprecator'); + const spy = spyOn(Deprecator, 'logRuntimeDeprecation').and.callFake(() => {}); + jasmine.restoreLibrary('../lib/LiveQuery/Client', 'Client'); + const Client = require('../lib/LiveQuery/Client').Client; + const parseLiveQueryServer = new ParseLiveQueryServer({}); + // Make mock request message + const message = generateMockMessage(); + + const clientId = 1; + const parseWebSocket = { + clientId, + send: jasmine.createSpy('send'), + }; + const client = new Client(clientId, parseWebSocket); + spyOn(client, 'pushCreate').and.callThrough(); + parseLiveQueryServer.clients.set(clientId, client); + + // Add mock subscription + const requestId = 2; + const query = { + className: testClassName, + where: { + key: 'value', + }, + fields: ['test'], + }; + await addMockSubscription(parseLiveQueryServer, clientId, requestId, parseWebSocket, query); + // Mock _matchesSubscription to return matching + parseLiveQueryServer._matchesSubscription = function (parseObject) { + if (!parseObject) { + return false; + } + return true; + }; + parseLiveQueryServer._matchesACL = function () { + return Promise.resolve(true); + }; + + parseLiveQueryServer._onAfterSave(message); + + // Make sure we send create command to client + await timeout(); + + expect(client.pushCreate).toHaveBeenCalled(); + const args = parseWebSocket.send.calls.mostRecent().args; + const toSend = JSON.parse(args[0]); + expect(toSend.object).toBeDefined(); + expect(toSend.original).toBeUndefined(); + expect(spy).toHaveBeenCalledWith({ + usage: 'Subscribing using fields parameter', + solution: + `Subscribe using "keys" instead.`, + }); + }); + it('can handle create command with watch', async () => { jasmine.restoreLibrary('../lib/LiveQuery/Client', 'Client'); const Client = require('../lib/LiveQuery/Client').Client; @@ -1865,7 +1921,7 @@ describe('ParseLiveQueryServer', function () { where: { key: 'value', }, - fields: ['test'], + keys: ['test'], }; } const request = { diff --git a/src/LiveQuery/Client.js b/src/LiveQuery/Client.js index 56d1baedcd5..0ce629bd4e3 100644 --- a/src/LiveQuery/Client.js +++ b/src/LiveQuery/Client.js @@ -98,13 +98,13 @@ class Client { response['requestId'] = subscriptionId; } if (typeof parseObjectJSON !== 'undefined') { - let fields; + let keys; if (this.subscriptionInfos.has(subscriptionId)) { - fields = this.subscriptionInfos.get(subscriptionId).fields; + keys = this.subscriptionInfos.get(subscriptionId).keys; } - response['object'] = this._toJSONWithFields(parseObjectJSON, fields); + response['object'] = this._toJSONWithFields(parseObjectJSON, keys); if (parseOriginalObjectJSON) { - response['original'] = this._toJSONWithFields(parseOriginalObjectJSON, fields); + response['original'] = this._toJSONWithFields(parseOriginalObjectJSON, keys); } } Client.pushResponse(this.parseWebSocket, JSON.stringify(response)); diff --git a/src/LiveQuery/ParseLiveQueryServer.js b/src/LiveQuery/ParseLiveQueryServer.js index 1ecbda93724..934a556966f 100644 --- a/src/LiveQuery/ParseLiveQueryServer.js +++ b/src/LiveQuery/ParseLiveQueryServer.js @@ -23,6 +23,7 @@ import LRU from 'lru-cache'; import UserRouter from '../Routers/UsersRouter'; import DatabaseController from '../Controllers/DatabaseController'; import { isDeepStrictEqual } from 'util'; +import Deprecator from '../Deprecator/Deprecator'; class ParseLiveQueryServer { clients: Map; @@ -850,9 +851,6 @@ class ParseLiveQueryServer { await runTrigger(trigger, `beforeSubscribe.${className}`, request, auth); const query = request.query.toJSON(); - if (query.keys) { - query.fields = query.keys.split(','); - } request.query = query; } @@ -901,8 +899,17 @@ class ParseLiveQueryServer { subscription: subscription, }; // Add selected fields, sessionToken and installationId for this subscription if necessary + if (request.query.keys) { + subscriptionInfo.keys = Array.isArray(request.query.keys) + ? request.query.keys + : request.query.keys.split(','); + } if (request.query.fields) { - subscriptionInfo.fields = request.query.fields; + subscriptionInfo.keys = request.query.fields; + Deprecator.logRuntimeDeprecation({ + usage: `Subscribing using fields parameter`, + solution: `Subscribe using "keys" instead.`, + }); } if (request.query.watch) { subscriptionInfo.watch = request.query.watch; diff --git a/src/LiveQuery/RequestSchema.js b/src/LiveQuery/RequestSchema.js index 14cb2f046bd..3a88e9930d1 100644 --- a/src/LiveQuery/RequestSchema.js +++ b/src/LiveQuery/RequestSchema.js @@ -70,6 +70,22 @@ const subscribe = { minItems: 1, uniqueItems: true, }, + keys: { + type: 'array', + items: { + type: 'string', + }, + minItems: 1, + uniqueItems: true, + }, + watch: { + type: 'array', + items: { + type: 'string', + }, + minItems: 1, + uniqueItems: true, + }, }, required: ['where', 'className'], additionalProperties: false, @@ -108,6 +124,22 @@ const update = { minItems: 1, uniqueItems: true, }, + keys: { + type: 'array', + items: { + type: 'string', + }, + minItems: 1, + uniqueItems: true, + }, + watch: { + type: 'array', + items: { + type: 'string', + }, + minItems: 1, + uniqueItems: true, + }, }, required: ['where', 'className'], additionalProperties: false,