Skip to content

feat: generate Parse.Object.objectId automatically when allowCustomObjectId is enabled and no objectId is passed #1540

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 25 commits into from
Sep 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
78729bb
feat: Update conditions for `MISSING_OBJECT_ID` error when allowCusto…
musthafa1996 Sep 4, 2022
a88e8ae
Update `MISSING_OBJECT_ID` error message
musthafa1996 Sep 4, 2022
ec80a44
Update tests
musthafa1996 Sep 4, 2022
2298855
Update integration/test/ParseObjectTest.js
musthafa1996 Sep 5, 2022
b3b3365
Update integration/test/ParseObjectTest.js
musthafa1996 Sep 5, 2022
91e425f
Fix tests
musthafa1996 Sep 6, 2022
2455fcb
Fix tests for custom object ID
musthafa1996 Sep 6, 2022
9f53d1a
Merge branch 'alpha' into allow-custom-id
mtrezza Sep 8, 2022
872aadb
Remove unnecessary id existence check from ParseObject in case allowC…
musthafa1996 Sep 9, 2022
43e96b3
Fix tests for allowCustomObjectId
musthafa1996 Sep 9, 2022
e8971a4
Merge branch 'alpha' into allow-custom-id
musthafa1996 Sep 10, 2022
55ecd1b
Add custom objectId validation back to ParseObject
musthafa1996 Sep 11, 2022
79fcf83
Fix ParseObject-test.js
musthafa1996 Sep 11, 2022
0399ee6
Fix package-lock.json
musthafa1996 Sep 12, 2022
b443f84
Cleanup ParseObjectTest.js
musthafa1996 Sep 12, 2022
ee5498e
Merge branch 'alpha' into allow-custom-id
mtrezza Sep 14, 2022
51f6678
Merge branch 'allow-custom-id' of github.com:musthafa1996/Parse-SDK-J…
musthafa1996 Sep 16, 2022
41e61b5
Merge branch 'alpha' into allow-custom-id
mtrezza Sep 16, 2022
2d6ffb7
Fix ParseObject-test.js
musthafa1996 Sep 19, 2022
7155872
Merge branch 'allow-custom-id' of github.com:musthafa1996/Parse-SDK-J…
musthafa1996 Sep 19, 2022
6bbb054
Merge branch 'alpha' into allow-custom-id
mtrezza Sep 19, 2022
7e3b18f
Split ParseOnject allowCustomObjectId integration tests
musthafa1996 Sep 21, 2022
04748d6
Merge branch 'allow-custom-id' of github.com:musthafa1996/Parse-SDK-J…
musthafa1996 Sep 21, 2022
7362468
Merge branch 'alpha' into allow-custom-id
mtrezza Sep 21, 2022
c5cc568
Merge branch 'alpha' into allow-custom-id
musthafa1996 Sep 21, 2022
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
166 changes: 121 additions & 45 deletions integration/test/ParseObjectTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -2060,59 +2060,135 @@ describe('Parse Object', () => {
expect(obj.get('string')).toBeInstanceOf(String);
});

it('allowCustomObjectId', async () => {
await reconfigureServer({ allowCustomObjectId: true });
Parse.allowCustomObjectId = true;
const customId = `${Date.now()}`;
const object = new Parse.Object('TestObject');
try {
describe('allowCustomObjectId', () => {
it('can save without setting an objectId', async () => {
await reconfigureServer({ allowCustomObjectId: true });
Parse.allowCustomObjectId = true;

const object = new Parse.Object('TestObject');
await object.save();
fail();
} catch (error) {
expect(error.message).toBe('objectId must not be empty, null or undefined');
}
object.id = customId;
object.set('foo', 'bar');
await object.save();
expect(object.id).toBe(customId);
expect(object.id).toBeDefined();

Parse.allowCustomObjectId = false;
});

it('fails to save when objectId is empty', async () => {
await reconfigureServer({ allowCustomObjectId: true });
Parse.allowCustomObjectId = true;

const object = new Parse.Object('TestObject');
object.id = '';
await expectAsync(object.save()).toBeRejectedWith(
new Parse.Error(Parse.Error.MISSING_OBJECT_ID, 'objectId must not be empty or null')
);

Parse.allowCustomObjectId = false;
});

it('fails to save when objectId is null', async () => {
await reconfigureServer({ allowCustomObjectId: true });
Parse.allowCustomObjectId = true;

const object = new Parse.Object('TestObject');
object.id = null;
await expectAsync(object.save()).toBeRejectedWith(
new Parse.Error(Parse.Error.MISSING_OBJECT_ID, 'objectId must not be empty or null')
);

Parse.allowCustomObjectId = false;
});

it('can save with custom objectId', async () => {
await reconfigureServer({ allowCustomObjectId: true });
Parse.allowCustomObjectId = true;

const customId = `${Date.now()}`;
const object = new Parse.Object('TestObject');
object.id = customId;
object.set('foo', 'bar');
await object.save();
expect(object.id).toBe(customId);

const query = new Parse.Query('TestObject');
const result = await query.get(customId);
expect(result.get('foo')).toBe('bar');
expect(result.id).toBe(customId);

const query = new Parse.Query('TestObject');
const result = await query.get(customId);
expect(result.get('foo')).toBe('bar');
expect(result.id).toBe(customId);
result.set('foo', 'baz');
await result.save();

result.set('foo', 'baz');
await result.save();
const afterSave = await query.get(customId);
expect(afterSave.get('foo')).toBe('baz');

const afterSave = await query.get(customId);
expect(afterSave.get('foo')).toBe('baz');
Parse.allowCustomObjectId = false;
Parse.allowCustomObjectId = false;
});
});

it('allowCustomObjectId saveAll', async () => {
await reconfigureServer({ allowCustomObjectId: true });
Parse.allowCustomObjectId = true;
const customId1 = `${Date.now()}`;
const customId2 = `${Date.now()}`;
const obj1 = new TestObject({ foo: 'bar' });
const obj2 = new TestObject({ foo: 'baz' });
try {
describe('allowCustomObjectId saveAll', () => {
it('can save without setting an objectId', async () => {
await reconfigureServer({ allowCustomObjectId: true });
Parse.allowCustomObjectId = true;

const obj1 = new TestObject({ foo: 'bar' });
const obj2 = new TestObject({ foo: 'baz' });
await Parse.Object.saveAll([obj1, obj2]);
fail();
} catch (error) {
expect(error.message).toBe('objectId must not be empty, null or undefined');
}
obj1.id = customId1;
obj2.id = customId2;
await Parse.Object.saveAll([obj1, obj2]);
expect(obj1.id).toBe(customId1);
expect(obj2.id).toBe(customId2);
expect(obj1.id).toBeDefined();
expect(obj2.id).toBeDefined();

const query = new Parse.Query(TestObject);
const results = await query.find();
results.forEach(result => {
expect([customId1, customId2].includes(result.id));
Parse.allowCustomObjectId = false;
});

it('fails to save when objectId is empty', async () => {
await reconfigureServer({ allowCustomObjectId: true });
Parse.allowCustomObjectId = true;

const obj1 = new TestObject({ foo: 'bar' });
obj1.id = '';
const obj2 = new TestObject({ foo: 'baz' });
obj2.id = '';
await expectAsync(Parse.Object.saveAll([obj1, obj2])).toBeRejectedWith(
new Parse.Error(Parse.Error.MISSING_OBJECT_ID, 'objectId must not be empty or null')
);

Parse.allowCustomObjectId = false;
});

it('fails to save when objectId is null', async () => {
await reconfigureServer({ allowCustomObjectId: true });
Parse.allowCustomObjectId = true;

const obj1 = new TestObject({ foo: 'bar' });
obj1.id = null;
const obj2 = new TestObject({ foo: 'baz' });
obj2.id = null;
await expectAsync(Parse.Object.saveAll([obj1, obj2])).toBeRejectedWith(
new Parse.Error(Parse.Error.MISSING_OBJECT_ID, 'objectId must not be empty or null')
);

Parse.allowCustomObjectId = false;
});

it('can save with custom objectId', async () => {
await reconfigureServer({ allowCustomObjectId: true });
Parse.allowCustomObjectId = true;

const obj1 = new TestObject({ foo: 'bar' });
const customId1 = `${Date.now()}`;
obj1.id = customId1;
const obj2 = new TestObject({ foo: 'baz' });
const customId2 = `${Date.now()}`;
obj1.id = customId2;
await Parse.Object.saveAll([obj1, obj2]);
expect(obj1.id).toBeDefined();
expect(obj2.id).toBeDefined();

const query = new Parse.Query(TestObject);
const results = await query.find();
results.forEach(result => {
expect([customId1, customId2].includes(result.id));
});

Parse.allowCustomObjectId = false;
});
Parse.allowCustomObjectId = false;
});
});
1 change: 1 addition & 0 deletions integration/test/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ const defaultConfiguration = {
enableForAuthenticatedUser: true,
},
revokeSessionOnPasswordReset: false,
allowCustomObjectId: false,
};

const openConnections = {};
Expand Down
20 changes: 9 additions & 11 deletions src/ParseObject.js
Original file line number Diff line number Diff line change
Expand Up @@ -2399,12 +2399,6 @@ const DefaultController = {
if (el instanceof ParseFile) {
filesSaved.push(el.save(options));
} else if (el instanceof ParseObject) {
if (allowCustomObjectId && !el.id) {
throw new ParseError(
ParseError.MISSING_OBJECT_ID,
'objectId must not be empty, null or undefined'
);
}
pending.push(el);
}
});
Expand All @@ -2419,6 +2413,13 @@ const DefaultController = {
const batch = [];
const nextPending = [];
pending.forEach(el => {
if (allowCustomObjectId && Object.prototype.hasOwnProperty.call(el, 'id') && !el.id) {
throw new ParseError(
ParseError.MISSING_OBJECT_ID,
'objectId must not be empty or null'
);
}

if (batch.length < batchSize && canBeSerialized(el)) {
batch.push(el);
} else {
Expand Down Expand Up @@ -2498,11 +2499,8 @@ const DefaultController = {
});
});
} else if (target instanceof ParseObject) {
if (allowCustomObjectId && !target.id) {
throw new ParseError(
ParseError.MISSING_OBJECT_ID,
'objectId must not be empty, null or undefined'
);
if (allowCustomObjectId && Object.prototype.hasOwnProperty.call(target, 'id') && !target.id) {
throw new ParseError(ParseError.MISSING_OBJECT_ID, 'objectId must not be empty or null');
}
// generate _localId in case if cascadeSave=false
target._getId();
Expand Down
24 changes: 9 additions & 15 deletions src/__tests__/ParseObject-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3807,27 +3807,22 @@ describe('ParseObject pin', () => {
});
});

it('can allowCustomObjectId', async done => {
it('can allowCustomObjectId', async () => {
CoreManager.set('ALLOW_CUSTOM_OBJECT_ID', true);
const o = new ParseObject('Person');
o.id = '';
let params = o._getSaveParams();
expect(params).toEqual({
method: 'POST',
body: { objectId: undefined },
body: { objectId: '' },
path: 'classes/Person',
});
try {
await o.save();
done.fail();
} catch (error) {
expect(error.message).toBe('objectId must not be empty, null or undefined');
}
try {
await ParseObject.saveAll([o]);
done.fail();
} catch (error) {
expect(error.message).toBe('objectId must not be empty, null or undefined');
}
await expect(o.save()).rejects.toEqual(
new ParseError(ParseError.MISSING_OBJECT_ID, 'objectId must not be empty or null')
);
await expect(ParseObject.saveAll([o])).rejects.toEqual(
new ParseError(ParseError.MISSING_OBJECT_ID, 'objectId must not be empty or null')
);
o._finishFetch({
objectId: 'CUSTOM_ID',
createdAt: { __type: 'Date', iso: new Date().toISOString() },
Expand All @@ -3840,6 +3835,5 @@ describe('ParseObject pin', () => {
path: 'classes/Person/CUSTOM_ID',
});
CoreManager.set('ALLOW_CUSTOM_OBJECT_ID', false);
done();
});
});