#6101 Let users define objectId (#6177)

* #6101 Let users define objectId

* Add `allowCustomObjectId` to PS Option

* Add checking in objectId creation

* Add test

* Update docs

* Update definition

* Change default to false

* throw on empty, null, undefined

* better tests

* unused async

* removed comment

* retain comment

* Linting fix according to contributing spec.
This commit is contained in:
Rhuan
2019-12-17 19:23:18 +01:00
committed by Diamond Lewis
parent 7944ef1435
commit 8bc201d228
5 changed files with 97 additions and 11 deletions

View File

@@ -44,6 +44,66 @@ describe('rest create', () => {
});
});
it('should use objectId from client when allowCustomObjectId true', async () => {
config.allowCustomObjectId = true;
// use time as unique custom id for test reusability
const customId = `${Date.now()}`;
const obj = {
objectId: customId,
};
const {
status,
response: { objectId },
} = await rest.create(config, auth.nobody(config), 'MyClass', obj);
expect(status).toEqual(201);
expect(objectId).toEqual(customId);
});
it('should throw on invalid objectId when allowCustomObjectId true', () => {
config.allowCustomObjectId = true;
const objIdNull = {
objectId: null,
};
const objIdUndef = {
objectId: undefined,
};
const objIdEmpty = {
objectId: '',
};
const err = 'objectId must not be empty, null or undefined';
expect(() =>
rest.create(config, auth.nobody(config), 'MyClass', objIdEmpty)
).toThrowError(err);
expect(() =>
rest.create(config, auth.nobody(config), 'MyClass', objIdNull)
).toThrowError(err);
expect(() =>
rest.create(config, auth.nobody(config), 'MyClass', objIdUndef)
).toThrowError(err);
});
it('should generate objectId when not set by client with allowCustomObjectId true', async () => {
config.allowCustomObjectId = true;
const {
status,
response: { objectId },
} = await rest.create(config, auth.nobody(config), 'MyClass', {});
expect(status).toEqual(201);
expect(objectId).toBeDefined();
});
it('is backwards compatible when _id size changes', done => {
rest
.create(config, auth.nobody(config), 'Foo', { size: 10 })

View File

@@ -17,6 +17,12 @@ module.exports.ParseServerOptions = {
action: parsers.booleanParser,
default: true,
},
allowCustomObjectId: {
env: 'PARSE_SERVER_ALLOW_CUSTOM_OBJECT_ID',
help: 'Enable (or disable) custom objectId, defaults to false',
action: parsers.booleanParser,
default: false,
},
allowHeaders: {
env: 'PARSE_SERVER_ALLOW_HEADERS',
help: 'Add headers to Access-Control-Allow-Headers',

View File

@@ -2,6 +2,7 @@
* @interface ParseServerOptions
* @property {Any} accountLockout account lockout policy for failed login attempts
* @property {Boolean} allowClientClassCreation Enable (or disable) client class creation, defaults to true
* @property {Boolean} allowCustomObjectId Enable (or disable) custom objectId, defaults to false
* @property {String[]} allowHeaders Add headers to Access-Control-Allow-Headers
* @property {Adapter<AnalyticsAdapter>} analyticsAdapter Adapter module for the analytics
* @property {String} appId Your Parse Application ID

View File

@@ -102,6 +102,10 @@ export interface ParseServerOptions {
:ENV: PARSE_SERVER_ALLOW_CLIENT_CLASS_CREATION
:DEFAULT: true */
allowClientClassCreation: ?boolean;
/* Enable (or disable) custom objectId
:ENV: PARSE_SERVER_ALLOW_CUSTOM_OBJECT_ID
:DEFAULT: false */
allowCustomObjectId: ?boolean;
/* Configuration for your authentication providers, as stringified JSON. See http://docs.parseplatform.org/parse-server/guide/#oauth-and-3rd-party-authentication
:ENV: PARSE_SERVER_AUTH_PROVIDERS */
auth: ?any;

View File

@@ -46,17 +46,32 @@ function RestWrite(
this.storage = {};
this.runOptions = {};
this.context = {};
if (!query && data.objectId) {
throw new Parse.Error(
Parse.Error.INVALID_KEY_NAME,
'objectId is an invalid field name.'
);
}
if (!query && data.id) {
throw new Parse.Error(
Parse.Error.INVALID_KEY_NAME,
'id is an invalid field name.'
);
if (!query) {
if (this.config.allowCustomObjectId) {
if (
Object.prototype.hasOwnProperty.call(data, 'objectId') &&
!data.objectId
) {
throw new Parse.Error(
Parse.Error.MISSING_OBJECT_ID,
'objectId must not be empty, null or undefined'
);
}
} else {
if (data.objectId) {
throw new Parse.Error(
Parse.Error.INVALID_KEY_NAME,
'objectId is an invalid field name.'
);
}
if (data.id) {
throw new Parse.Error(
Parse.Error.INVALID_KEY_NAME,
'id is an invalid field name.'
);
}
}
}
// When the operation is complete, this.response may have several