Skip to content

fix: Remove validation error handler option error from various methods of Parse.Object #2445

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

Merged
merged 4 commits into from
Feb 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion integration/test/ParseACLTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ describe('Parse.ACL', () => {

it('acl must be valid', () => {
const user = new Parse.User();
assert.equal(user.setACL(`Ceci n'est pas un ACL.`), false);
expect(() => user.setACL(`Ceci n'est pas un ACL.`)).toThrow(
new Parse.Error(Parse.Error.OTHER_CAUSE, 'ACL must be a Parse ACL.')
);
});

it('can refresh object with acl', async () => {
Expand Down
63 changes: 45 additions & 18 deletions integration/test/ParseObjectTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -546,24 +546,20 @@ describe('Parse Object', () => {
});
});

it('cannot create invalid key names', done => {
it('cannot create invalid key names', async () => {
const error = new Parse.Error(Parse.Error.INVALID_KEY_NAME, `Invalid key name: "foo^bar"`);
const item = new Parse.Object('Item');
assert(!item.set({ 'foo^bar': 'baz' }));
item.save({ 'foo^bar': 'baz' }).catch(e => {
assert.equal(e.code, Parse.Error.INVALID_KEY_NAME);
done();
});
expect(() => {
item.set({ 'foo^bar': 'baz' });
}).toThrow(error);
await expectAsync(item.save({ 'foo^bar': 'baz' })).toBeRejectedWith(error);
});

it('cannot use invalid key names in multiple sets', () => {
const item = new Parse.Object('Item');
assert(
!item.set({
foobar: 'baz',
'foo^bar': 'baz',
})
);
assert(!item.get('foobar'));
expect(() => {
item.set({ foobar: 'baz', 'foo^bar': 'baz' });
}).toThrow(new Parse.Error(Parse.Error.INVALID_KEY_NAME, `Invalid key name: "foo^bar"`));
});

it('can unset fields', done => {
Expand Down Expand Up @@ -1135,12 +1131,43 @@ describe('Parse Object', () => {
parent.set('children', [child1, child2]);
parent.set('bastard', child3);

expect(parent.save).toThrow();
let results = await new Parse.Query(Child).find();
assert.equal(results.length, 0);

await parent.save(null, { cascadeSave: true });
results = await new Parse.Query(Child).find();
const results = await new Parse.Query(Child).find();
assert.equal(results.length, 3);

parent.set('dead', true);
child1.set('dead', true);
await parent.save(null);
const rob = await new Parse.Query(Child).equalTo('name', 'rob').first();
expect(rob.get('dead')).toBe(true);

parent.set('lastname', 'stark');
child3.set('lastname', 'stark');
await parent.save(null, { cascadeSave: false });
const john = await new Parse.Query(Child).doesNotExist('lastname').first();
expect(john.get('lastname')).toBeUndefined();
});

it('can skip cascade (default true) saving as per request', async () => {
const Parent = Parse.Object.extend('Parent');
const Child = Parse.Object.extend('Child');

const parent = new Parent();
const child1 = new Child();
const child2 = new Child();
const child3 = new Child();

child1.set('name', 'rob');
child2.set('name', 'sansa');
child3.set('name', 'john');
parent.set('children', [child1, child2]);
parent.set('bastard', child3);

// cascadeSave option default true
await parent.save(null, {
/* cascadeSave: true */
});
const results = await new Parse.Query(Child).find();
assert.equal(results.length, 3);

parent.set('dead', true);
Expand Down
4 changes: 3 additions & 1 deletion src/ParseInstallation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ class ParseInstallation extends ParseObject {
constructor(attributes?: AttributeMap) {
super('_Installation');
if (attributes && typeof attributes === 'object') {
if (!this.set(attributes)) {
try {
this.set(attributes || {});
} catch (_) {
throw new Error("Can't create an invalid Installation");
}
}
Expand Down
83 changes: 39 additions & 44 deletions src/ParseObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,12 @@ class ParseObject {
options = attributes as any;
}
}
if (toSet && !this.set(toSet, options)) {
throw new Error("Can't create an invalid Parse Object");
if (toSet) {
try {
this.set(toSet, options);
} catch (_) {
throw new Error("Can't create an invalid Parse Object");
}
}
}

Expand Down Expand Up @@ -733,9 +737,9 @@ class ParseObject {
* @param {(string|object)} value The value to give it.
* @param {object} options A set of options for the set.
* The only supported option is <code>error</code>.
* @returns {(ParseObject|boolean)} true if the set succeeded.
* @returns {Parse.Object} Returns the object, so you can chain this call.
*/
set(key: any, value?: any, options?: any): ParseObject | boolean {
set(key: any, value?: any, options?: any): this {
let changes = {};
const newOps = {};
if (key && typeof key === 'object') {
Expand Down Expand Up @@ -804,12 +808,9 @@ class ParseObject {

// Validate changes
if (!options.ignoreValidation) {
const validation = this.validate(newValues);
if (validation) {
if (typeof options.error === 'function') {
options.error(this, validation);
}
return false;
const validationError = this.validate(newValues);
if (validationError) {
throw validationError;
}
}

Expand All @@ -831,9 +832,9 @@ class ParseObject {
*
* @param {string} attr The string name of an attribute.
* @param options
* @returns {(ParseObject | boolean)}
* @returns {Parse.Object} Returns the object, so you can chain this call.
*/
unset(attr: string, options?: { [opt: string]: any }): ParseObject | boolean {
unset(attr: string, options?: { [opt: string]: any }): this {
options = options || {};
options.unset = true;
return this.set(attr, null, options);
Expand All @@ -845,9 +846,9 @@ class ParseObject {
*
* @param attr {String} The key.
* @param amount {Number} The amount to increment by (optional).
* @returns {(ParseObject|boolean)}
* @returns {Parse.Object} Returns the object, so you can chain this call.
*/
increment(attr: string, amount?: number): ParseObject | boolean {
increment(attr: string, amount?: number): this {
if (typeof amount === 'undefined') {
amount = 1;
}
Expand All @@ -863,9 +864,9 @@ class ParseObject {
*
* @param attr {String} The key.
* @param amount {Number} The amount to decrement by (optional).
* @returns {(ParseObject | boolean)}
* @returns {Parse.Object} Returns the object, so you can chain this call.
*/
decrement(attr: string, amount?: number): ParseObject | boolean {
decrement(attr: string, amount?: number): this {
if (typeof amount === 'undefined') {
amount = 1;
}
Expand All @@ -881,9 +882,9 @@ class ParseObject {
*
* @param attr {String} The key.
* @param item {} The item to add.
* @returns {(ParseObject | boolean)}
* @returns {Parse.Object} Returns the object, so you can chain this call.
*/
add(attr: string, item: any): ParseObject | boolean {
add(attr: string, item: any): this {
return this.set(attr, new AddOp([item]));
}

Expand All @@ -893,9 +894,9 @@ class ParseObject {
*
* @param attr {String} The key.
* @param items {Object[]} The items to add.
* @returns {(ParseObject | boolean)}
* @returns {Parse.Object} Returns the object, so you can chain this call.
*/
addAll(attr: string, items: Array<any>): ParseObject | boolean {
addAll(attr: string, items: Array<any>): this {
return this.set(attr, new AddOp(items));
}

Expand All @@ -906,9 +907,9 @@ class ParseObject {
*
* @param attr {String} The key.
* @param item {} The object to add.
* @returns {(ParseObject | boolean)}
* @returns {Parse.Object} Returns the object, so you can chain this call.
*/
addUnique(attr: string, item: any): ParseObject | boolean {
addUnique(attr: string, item: any): this {
return this.set(attr, new AddUniqueOp([item]));
}

Expand All @@ -919,9 +920,9 @@ class ParseObject {
*
* @param attr {String} The key.
* @param items {Object[]} The objects to add.
* @returns {(ParseObject | boolean)}
* @returns {Parse.Object} Returns the object, so you can chain this call.
*/
addAllUnique(attr: string, items: Array<any>): ParseObject | boolean {
addAllUnique(attr: string, items: Array<any>): this {
return this.set(attr, new AddUniqueOp(items));
}

Expand All @@ -931,9 +932,9 @@ class ParseObject {
*
* @param attr {String} The key.
* @param item {} The object to remove.
* @returns {(ParseObject | boolean)}
* @returns {Parse.Object} Returns the object, so you can chain this call.
*/
remove(attr: string, item: any): ParseObject | boolean {
remove(attr: string, item: any): this {
return this.set(attr, new RemoveOp([item]));
}

Expand All @@ -943,9 +944,9 @@ class ParseObject {
*
* @param attr {String} The key.
* @param items {Object[]} The object to remove.
* @returns {(ParseObject | boolean)}
* @returns {Parse.Object} Returns the object, so you can chain this call.
*/
removeAll(attr: string, items: Array<any>): ParseObject | boolean {
removeAll(attr: string, items: Array<any>): this {
return this.set(attr, new RemoveOp(items));
}

Expand Down Expand Up @@ -1099,7 +1100,7 @@ class ParseObject {
}
for (const key in attrs) {
if (!/^[A-Za-z][0-9A-Za-z_.]*$/.test(key)) {
return new ParseError(ParseError.INVALID_KEY_NAME);
return new ParseError(ParseError.INVALID_KEY_NAME, `Invalid key name: "${key}"`);
}
}
return false;
Expand All @@ -1124,10 +1125,10 @@ class ParseObject {
*
* @param {Parse.ACL} acl An instance of Parse.ACL.
* @param {object} options
* @returns {(ParseObject | boolean)} Whether the set passed validation.
* @returns {Parse.Object} Returns the object, so you can chain this call.
* @see Parse.Object#set
*/
setACL(acl: ParseACL, options?: any): ParseObject | boolean {
setACL(acl: ParseACL, options?: any): this {
return this.set('ACL', acl, options);
}

Expand All @@ -1154,9 +1155,9 @@ class ParseObject {
/**
* Clears all attributes on a model
*
* @returns {(ParseObject | boolean)}
* @returns {Parse.Object} Returns the object, so you can chain this call.
*/
clear(): ParseObject | boolean {
clear(): this {
const attributes = this.attributes;
const erasable = {};
let readonly = ['createdAt', 'updatedAt'];
Expand Down Expand Up @@ -1320,7 +1321,7 @@ class ParseObject {
* @returns {Promise} A promise that is fulfilled when the save
* completes.
*/
save(
async save(
arg1: undefined | string | { [attr: string]: any } | null,
arg2: SaveOptions | any,
arg3?: SaveOptions
Expand All @@ -1337,17 +1338,9 @@ class ParseObject {
attrs[arg1] = arg2;
options = arg3;
}

options = options || {};
if (attrs) {
let validationError;
options.error = (_, validation) => {
validationError = validation;
};
const success = this.set(attrs, options);
if (!success) {
return Promise.reject(validationError);
}
this.set(attrs, options);
}
const saveOptions = ParseObject._getRequestOptions(options);
const controller = CoreManager.getObjectController();
Expand Down Expand Up @@ -1985,7 +1978,9 @@ class ParseObject {
}

if (attributes && typeof attributes === 'object') {
if (!this.set(attributes || {}, options)) {
try {
this.set(attributes || {}, options);
} catch (_) {
throw new Error("Can't create an invalid Parse Object");
}
}
Expand Down
4 changes: 3 additions & 1 deletion src/ParseSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ class ParseSession extends ParseObject {
constructor(attributes?: any) {
super('_Session');
if (attributes && typeof attributes === 'object') {
if (!this.set(attributes || {})) {
try {
this.set(attributes || {});
} catch (_) {
throw new Error("Can't create an invalid Session");
}
}
Expand Down
4 changes: 3 additions & 1 deletion src/ParseUser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ class ParseUser extends ParseObject {
constructor(attributes?: AttributeMap) {
super('_User');
if (attributes && typeof attributes === 'object') {
if (!this.set(attributes || {})) {
try {
this.set(attributes || {});
} catch (_) {
throw new Error("Can't create an invalid Parse User");
}
}
Expand Down
Loading