Skip to content

Commit 68f3ff5

Browse files
authored
feat: generate Parse.Object.objectId automatically when allowCustomObjectId is enabled and no objectId is passed (#1540)
1 parent d3ca00d commit 68f3ff5

File tree

4 files changed

+140
-71
lines changed

4 files changed

+140
-71
lines changed

integration/test/ParseObjectTest.js

Lines changed: 121 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -2060,59 +2060,135 @@ describe('Parse Object', () => {
20602060
expect(obj.get('string')).toBeInstanceOf(String);
20612061
});
20622062

2063-
it('allowCustomObjectId', async () => {
2064-
await reconfigureServer({ allowCustomObjectId: true });
2065-
Parse.allowCustomObjectId = true;
2066-
const customId = `${Date.now()}`;
2067-
const object = new Parse.Object('TestObject');
2068-
try {
2063+
describe('allowCustomObjectId', () => {
2064+
it('can save without setting an objectId', async () => {
2065+
await reconfigureServer({ allowCustomObjectId: true });
2066+
Parse.allowCustomObjectId = true;
2067+
2068+
const object = new Parse.Object('TestObject');
20692069
await object.save();
2070-
fail();
2071-
} catch (error) {
2072-
expect(error.message).toBe('objectId must not be empty, null or undefined');
2073-
}
2074-
object.id = customId;
2075-
object.set('foo', 'bar');
2076-
await object.save();
2077-
expect(object.id).toBe(customId);
2070+
expect(object.id).toBeDefined();
2071+
2072+
Parse.allowCustomObjectId = false;
2073+
});
2074+
2075+
it('fails to save when objectId is empty', async () => {
2076+
await reconfigureServer({ allowCustomObjectId: true });
2077+
Parse.allowCustomObjectId = true;
2078+
2079+
const object = new Parse.Object('TestObject');
2080+
object.id = '';
2081+
await expectAsync(object.save()).toBeRejectedWith(
2082+
new Parse.Error(Parse.Error.MISSING_OBJECT_ID, 'objectId must not be empty or null')
2083+
);
2084+
2085+
Parse.allowCustomObjectId = false;
2086+
});
2087+
2088+
it('fails to save when objectId is null', async () => {
2089+
await reconfigureServer({ allowCustomObjectId: true });
2090+
Parse.allowCustomObjectId = true;
2091+
2092+
const object = new Parse.Object('TestObject');
2093+
object.id = null;
2094+
await expectAsync(object.save()).toBeRejectedWith(
2095+
new Parse.Error(Parse.Error.MISSING_OBJECT_ID, 'objectId must not be empty or null')
2096+
);
2097+
2098+
Parse.allowCustomObjectId = false;
2099+
});
2100+
2101+
it('can save with custom objectId', async () => {
2102+
await reconfigureServer({ allowCustomObjectId: true });
2103+
Parse.allowCustomObjectId = true;
2104+
2105+
const customId = `${Date.now()}`;
2106+
const object = new Parse.Object('TestObject');
2107+
object.id = customId;
2108+
object.set('foo', 'bar');
2109+
await object.save();
2110+
expect(object.id).toBe(customId);
2111+
2112+
const query = new Parse.Query('TestObject');
2113+
const result = await query.get(customId);
2114+
expect(result.get('foo')).toBe('bar');
2115+
expect(result.id).toBe(customId);
20782116

2079-
const query = new Parse.Query('TestObject');
2080-
const result = await query.get(customId);
2081-
expect(result.get('foo')).toBe('bar');
2082-
expect(result.id).toBe(customId);
2117+
result.set('foo', 'baz');
2118+
await result.save();
20832119

2084-
result.set('foo', 'baz');
2085-
await result.save();
2120+
const afterSave = await query.get(customId);
2121+
expect(afterSave.get('foo')).toBe('baz');
20862122

2087-
const afterSave = await query.get(customId);
2088-
expect(afterSave.get('foo')).toBe('baz');
2089-
Parse.allowCustomObjectId = false;
2123+
Parse.allowCustomObjectId = false;
2124+
});
20902125
});
20912126

2092-
it('allowCustomObjectId saveAll', async () => {
2093-
await reconfigureServer({ allowCustomObjectId: true });
2094-
Parse.allowCustomObjectId = true;
2095-
const customId1 = `${Date.now()}`;
2096-
const customId2 = `${Date.now()}`;
2097-
const obj1 = new TestObject({ foo: 'bar' });
2098-
const obj2 = new TestObject({ foo: 'baz' });
2099-
try {
2127+
describe('allowCustomObjectId saveAll', () => {
2128+
it('can save without setting an objectId', async () => {
2129+
await reconfigureServer({ allowCustomObjectId: true });
2130+
Parse.allowCustomObjectId = true;
2131+
2132+
const obj1 = new TestObject({ foo: 'bar' });
2133+
const obj2 = new TestObject({ foo: 'baz' });
21002134
await Parse.Object.saveAll([obj1, obj2]);
2101-
fail();
2102-
} catch (error) {
2103-
expect(error.message).toBe('objectId must not be empty, null or undefined');
2104-
}
2105-
obj1.id = customId1;
2106-
obj2.id = customId2;
2107-
await Parse.Object.saveAll([obj1, obj2]);
2108-
expect(obj1.id).toBe(customId1);
2109-
expect(obj2.id).toBe(customId2);
2135+
expect(obj1.id).toBeDefined();
2136+
expect(obj2.id).toBeDefined();
21102137

2111-
const query = new Parse.Query(TestObject);
2112-
const results = await query.find();
2113-
results.forEach(result => {
2114-
expect([customId1, customId2].includes(result.id));
2138+
Parse.allowCustomObjectId = false;
2139+
});
2140+
2141+
it('fails to save when objectId is empty', async () => {
2142+
await reconfigureServer({ allowCustomObjectId: true });
2143+
Parse.allowCustomObjectId = true;
2144+
2145+
const obj1 = new TestObject({ foo: 'bar' });
2146+
obj1.id = '';
2147+
const obj2 = new TestObject({ foo: 'baz' });
2148+
obj2.id = '';
2149+
await expectAsync(Parse.Object.saveAll([obj1, obj2])).toBeRejectedWith(
2150+
new Parse.Error(Parse.Error.MISSING_OBJECT_ID, 'objectId must not be empty or null')
2151+
);
2152+
2153+
Parse.allowCustomObjectId = false;
2154+
});
2155+
2156+
it('fails to save when objectId is null', async () => {
2157+
await reconfigureServer({ allowCustomObjectId: true });
2158+
Parse.allowCustomObjectId = true;
2159+
2160+
const obj1 = new TestObject({ foo: 'bar' });
2161+
obj1.id = null;
2162+
const obj2 = new TestObject({ foo: 'baz' });
2163+
obj2.id = null;
2164+
await expectAsync(Parse.Object.saveAll([obj1, obj2])).toBeRejectedWith(
2165+
new Parse.Error(Parse.Error.MISSING_OBJECT_ID, 'objectId must not be empty or null')
2166+
);
2167+
2168+
Parse.allowCustomObjectId = false;
2169+
});
2170+
2171+
it('can save with custom objectId', async () => {
2172+
await reconfigureServer({ allowCustomObjectId: true });
2173+
Parse.allowCustomObjectId = true;
2174+
2175+
const obj1 = new TestObject({ foo: 'bar' });
2176+
const customId1 = `${Date.now()}`;
2177+
obj1.id = customId1;
2178+
const obj2 = new TestObject({ foo: 'baz' });
2179+
const customId2 = `${Date.now()}`;
2180+
obj1.id = customId2;
2181+
await Parse.Object.saveAll([obj1, obj2]);
2182+
expect(obj1.id).toBeDefined();
2183+
expect(obj2.id).toBeDefined();
2184+
2185+
const query = new Parse.Query(TestObject);
2186+
const results = await query.find();
2187+
results.forEach(result => {
2188+
expect([customId1, customId2].includes(result.id));
2189+
});
2190+
2191+
Parse.allowCustomObjectId = false;
21152192
});
2116-
Parse.allowCustomObjectId = false;
21172193
});
21182194
});

integration/test/helper.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ const defaultConfiguration = {
7272
enableForAuthenticatedUser: true,
7373
},
7474
revokeSessionOnPasswordReset: false,
75+
allowCustomObjectId: false,
7576
};
7677

7778
const openConnections = {};

src/ParseObject.js

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2399,12 +2399,6 @@ const DefaultController = {
23992399
if (el instanceof ParseFile) {
24002400
filesSaved.push(el.save(options));
24012401
} else if (el instanceof ParseObject) {
2402-
if (allowCustomObjectId && !el.id) {
2403-
throw new ParseError(
2404-
ParseError.MISSING_OBJECT_ID,
2405-
'objectId must not be empty, null or undefined'
2406-
);
2407-
}
24082402
pending.push(el);
24092403
}
24102404
});
@@ -2419,6 +2413,13 @@ const DefaultController = {
24192413
const batch = [];
24202414
const nextPending = [];
24212415
pending.forEach(el => {
2416+
if (allowCustomObjectId && Object.prototype.hasOwnProperty.call(el, 'id') && !el.id) {
2417+
throw new ParseError(
2418+
ParseError.MISSING_OBJECT_ID,
2419+
'objectId must not be empty or null'
2420+
);
2421+
}
2422+
24222423
if (batch.length < batchSize && canBeSerialized(el)) {
24232424
batch.push(el);
24242425
} else {
@@ -2498,11 +2499,8 @@ const DefaultController = {
24982499
});
24992500
});
25002501
} else if (target instanceof ParseObject) {
2501-
if (allowCustomObjectId && !target.id) {
2502-
throw new ParseError(
2503-
ParseError.MISSING_OBJECT_ID,
2504-
'objectId must not be empty, null or undefined'
2505-
);
2502+
if (allowCustomObjectId && Object.prototype.hasOwnProperty.call(target, 'id') && !target.id) {
2503+
throw new ParseError(ParseError.MISSING_OBJECT_ID, 'objectId must not be empty or null');
25062504
}
25072505
// generate _localId in case if cascadeSave=false
25082506
target._getId();

src/__tests__/ParseObject-test.js

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3807,27 +3807,22 @@ describe('ParseObject pin', () => {
38073807
});
38083808
});
38093809

3810-
it('can allowCustomObjectId', async done => {
3810+
it('can allowCustomObjectId', async () => {
38113811
CoreManager.set('ALLOW_CUSTOM_OBJECT_ID', true);
38123812
const o = new ParseObject('Person');
3813+
o.id = '';
38133814
let params = o._getSaveParams();
38143815
expect(params).toEqual({
38153816
method: 'POST',
3816-
body: { objectId: undefined },
3817+
body: { objectId: '' },
38173818
path: 'classes/Person',
38183819
});
3819-
try {
3820-
await o.save();
3821-
done.fail();
3822-
} catch (error) {
3823-
expect(error.message).toBe('objectId must not be empty, null or undefined');
3824-
}
3825-
try {
3826-
await ParseObject.saveAll([o]);
3827-
done.fail();
3828-
} catch (error) {
3829-
expect(error.message).toBe('objectId must not be empty, null or undefined');
3830-
}
3820+
await expect(o.save()).rejects.toEqual(
3821+
new ParseError(ParseError.MISSING_OBJECT_ID, 'objectId must not be empty or null')
3822+
);
3823+
await expect(ParseObject.saveAll([o])).rejects.toEqual(
3824+
new ParseError(ParseError.MISSING_OBJECT_ID, 'objectId must not be empty or null')
3825+
);
38313826
o._finishFetch({
38323827
objectId: 'CUSTOM_ID',
38333828
createdAt: { __type: 'Date', iso: new Date().toISOString() },
@@ -3840,6 +3835,5 @@ describe('ParseObject pin', () => {
38403835
path: 'classes/Person/CUSTOM_ID',
38413836
});
38423837
CoreManager.set('ALLOW_CUSTOM_OBJECT_ID', false);
3843-
done();
38443838
});
38453839
});

0 commit comments

Comments
 (0)