Skip to content

Commit

Permalink
Merge branch 'master' into keep-dependencies-up-to-date
Browse files Browse the repository at this point in the history
  • Loading branch information
mtrezza authored Nov 25, 2021
2 parents 9fbe204 + b065eff commit 5a482ba
Show file tree
Hide file tree
Showing 10 changed files with 220 additions and 11 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# [2.1.0](https://github.com/parse-community/Parse-SDK-Android/compare/2.0.6...2.1.0) (2021-11-21)


### Features

* add support for custom objectId ([#1088](https://github.com/parse-community/Parse-SDK-Android/issues/1088)) ([d420371](https://github.com/parse-community/Parse-SDK-Android/commit/d420371e761b07fac02f8ad747de0191817db5fa))

## [2.0.6](https://github.com/parse-community/Parse-SDK-Android/compare/2.0.5...2.0.6) (2021-11-16)


Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
version = 2.0.6
version = 2.1.0
android.enableJetifier = true
android.useAndroidX = true
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "parse-sdk-android",
"version": "2.0.6",
"version": "2.1.0",
"repository": {
"type": "git",
"url": "git+https://github.com/parse-community/Parse-SDK-Android.git"
Expand Down
29 changes: 29 additions & 0 deletions parse/src/main/java/com/parse/Parse.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public class Parse {
private static final Object MUTEX_CALLBACKS = new Object();
static ParseEventuallyQueue eventuallyQueue = null;
private static boolean isLocalDatastoreEnabled;
private static boolean allowCustomObjectId = false;

// endregion
private static OfflineStore offlineStore;
Expand Down Expand Up @@ -110,6 +111,14 @@ public static boolean isLocalDatastoreEnabled() {
return isLocalDatastoreEnabled;
}

/**
* @return {@code True} if {@link Configuration.Builder#allowCustomObjectId()} has been called,
* otherwise {@code false}.
*/
public static boolean isAllowCustomObjectId() {
return allowCustomObjectId;
}

/**
* Authenticates this client as belonging to your application. This must be called before your
* application can use the Parse library. The recommended way is to put a call to {@code
Expand Down Expand Up @@ -140,6 +149,8 @@ static void initialize(Configuration configuration, ParsePlugins parsePlugins) {
// isLocalDataStoreEnabled() to perform additional behavior.
isLocalDatastoreEnabled = configuration.localDataStoreEnabled;

allowCustomObjectId = configuration.allowCustomObjectId;

if (parsePlugins == null) {
ParsePlugins.initialize(configuration.context, configuration);
} else {
Expand Down Expand Up @@ -271,6 +282,7 @@ public static void destroy() {
ParsePlugins.reset();

setLocalDatastore(null);
allowCustomObjectId = false;
}

/** @return {@code True} if {@link #initialize} has been called, otherwise {@code false}. */
Expand Down Expand Up @@ -564,6 +576,7 @@ public static final class Configuration {
final String clientKey;
final String server;
final boolean localDataStoreEnabled;
final boolean allowCustomObjectId;
final OkHttpClient.Builder clientBuilder;
final int maxRetries;

Expand All @@ -573,6 +586,7 @@ private Configuration(Builder builder) {
this.clientKey = builder.clientKey;
this.server = builder.server;
this.localDataStoreEnabled = builder.localDataStoreEnabled;
this.allowCustomObjectId = builder.allowCustomObjectId;
this.clientBuilder = builder.clientBuilder;
this.maxRetries = builder.maxRetries;
}
Expand All @@ -584,6 +598,7 @@ public static final class Builder {
private String clientKey;
private String server;
private boolean localDataStoreEnabled;
private boolean allowCustomObjectId;
private OkHttpClient.Builder clientBuilder;
private int maxRetries = DEFAULT_MAX_RETRIES;

Expand Down Expand Up @@ -648,6 +663,20 @@ private Builder setLocalDatastoreEnabled(boolean enabled) {
return this;
}

/**
* Allow to set a custom objectId for ParseObjects.
*
* @return The same builder, for easy chaining.
*/
public Builder allowCustomObjectId() {
return this.setAllowCustomObjectId(true);
}

private Builder setAllowCustomObjectId(boolean enabled) {
allowCustomObjectId = enabled;
return this;
}

/**
* Set the {@link okhttp3.OkHttpClient.Builder} to use when communicating with the Parse
* REST API
Expand Down
8 changes: 8 additions & 0 deletions parse/src/main/java/com/parse/ParseObject.java
Original file line number Diff line number Diff line change
Expand Up @@ -2250,6 +2250,10 @@ Task<Void> saveAsync(final String sessionToken, final Task<Void> toAwait) {
return Task.forResult(null);
}

if (Parse.isAllowCustomObjectId() && getObjectId() == null) {
return Task.forError(new ParseException(104, "ObjectId must not be null"));
}

final ParseOperationSet operations;
synchronized (mutex) {
updateBeforeSave();
Expand Down Expand Up @@ -2357,6 +2361,10 @@ public final Task<Void> saveEventually() {
return Task.forResult(null);
}

if (Parse.isAllowCustomObjectId() && getObjectId() == null) {
return Task.forError(new ParseException(104, "ObjectId must not be null"));
}

final ParseOperationSet operationSet;
final ParseRESTCommand command;
final Task<JSONObject> runEventuallyTask;
Expand Down
14 changes: 12 additions & 2 deletions parse/src/main/java/com/parse/ParseRESTObjectCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,18 @@ public static ParseRESTObjectCommand saveObjectCommand(
return ParseRESTObjectCommand.createObjectCommand(
state.className(), operations, sessionToken);
} else {
return ParseRESTObjectCommand.updateObjectCommand(
state.objectId(), state.className(), operations, sessionToken);
if (Parse.isAllowCustomObjectId()) {
if (state.createdAt() == -1) {
return ParseRESTObjectCommand.createObjectCommand(
state.className(), operations, sessionToken);
} else {
return ParseRESTObjectCommand.updateObjectCommand(
state.objectId(), state.className(), operations, sessionToken);
}
} else {
return ParseRESTObjectCommand.updateObjectCommand(
state.objectId(), state.className(), operations, sessionToken);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,14 @@ public void testBuilder() {
builder.applicationId("foo");
builder.clientKey("bar");
builder.enableLocalDataStore();
builder.allowCustomObjectId();
Parse.Configuration configuration = builder.build();

assertNull(configuration.context);
assertEquals(configuration.applicationId, "foo");
assertEquals(configuration.clientKey, "bar");
assertTrue(configuration.localDataStoreEnabled);
assertEquals(configuration.allowCustomObjectId, true);
}

@Test
Expand Down
126 changes: 121 additions & 5 deletions parse/src/test/java/com/parse/ParseObjectTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@
*/
package com.parse;

import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Matchers.any;
Expand Down Expand Up @@ -46,7 +49,7 @@
import org.robolectric.RuntimeEnvironment;

@RunWith(RobolectricTestRunner.class)
public class ParseObjectTest {
public class ParseObjectTest extends ResetPluginsParseTest {

@Rule public final ExpectedException thrown = ExpectedException.none();

Expand Down Expand Up @@ -80,16 +83,17 @@ private static TaskCompletionSource<Void> mockObjectControllerForDelete() {
}

@Before
public void setUp() {
public void setUp() throws Exception {
super.setUp();
ParseFieldOperations.registerDefaultDecoders(); // to test JSON / Parcel decoding
}

// region testRevert

@After
public void tearDown() {
ParseCorePlugins.getInstance().reset();
ParsePlugins.reset();
public void tearDown() throws Exception {
super.tearDown();
Parse.destroy();
}

@Test
Expand Down Expand Up @@ -159,6 +163,118 @@ public void testFromJsonWithLdsStackOverflow() throws JSONException {

// endregion

@Test
public void testSaveCustomObjectIdMissing() {
// Mocked to let save work
mockCurrentUserController();

Parse.Configuration configuration =
new Parse.Configuration.Builder(RuntimeEnvironment.application)
.applicationId(BuildConfig.LIBRARY_PACKAGE_NAME)
.server("https://api.parse.com/1")
.enableLocalDataStore()
.allowCustomObjectId()
.build();
ParsePlugins plugins = mock(ParsePlugins.class);
when(plugins.configuration()).thenReturn(configuration);
when(plugins.applicationContext()).thenReturn(RuntimeEnvironment.application);
Parse.initialize(configuration, plugins);

ParseObject object = new ParseObject("TestObject");
try {
object.save();
} catch (ParseException e) {
assertEquals(e.getCode(), 104);
assertThat(e.getMessage(), is("ObjectId must not be null"));
}
}

@Test
public void testSaveCustomObjectIdNotMissing() {
// Mocked to let save work
mockCurrentUserController();

Parse.Configuration configuration =
new Parse.Configuration.Builder(RuntimeEnvironment.application)
.applicationId(BuildConfig.LIBRARY_PACKAGE_NAME)
.server("https://api.parse.com/1")
.enableLocalDataStore()
.allowCustomObjectId()
.build();
ParsePlugins plugins = mock(ParsePlugins.class);
when(plugins.configuration()).thenReturn(configuration);
when(plugins.applicationContext()).thenReturn(RuntimeEnvironment.application);
Parse.initialize(configuration, plugins);

ParseObject object = new ParseObject("TestObject");
object.setObjectId("ABCDEF123456");

ParseException exception = null;
try {
object.save();
} catch (ParseException e) {
exception = e;
}
assertNull(exception);
}

@Test
public void testSaveEventuallyCustomObjectIdMissing() {
// Mocked to let save work
mockCurrentUserController();

Parse.Configuration configuration =
new Parse.Configuration.Builder(RuntimeEnvironment.application)
.applicationId(BuildConfig.LIBRARY_PACKAGE_NAME)
.server("https://api.parse.com/1")
.enableLocalDataStore()
.allowCustomObjectId()
.build();
ParsePlugins plugins = ParseTestUtils.mockParsePlugins(configuration);
Parse.initialize(configuration, plugins);

ParseObject object = new ParseObject("TestObject");
object.saveEventually(
new SaveCallback() {
@Override
public void done(ParseException e) {
assertNotNull(e);
assertEquals(e.getCode(), 104);
assertThat(e.getMessage(), is("ObjectId must not be null"));
}
});

Parse.setLocalDatastore(null);
}

@Test
public void testSaveEventuallyCustomObjectIdNotMissing() throws ParseException {
// Mocked to let save work
mockCurrentUserController();

Parse.Configuration configuration =
new Parse.Configuration.Builder(RuntimeEnvironment.application)
.applicationId(BuildConfig.LIBRARY_PACKAGE_NAME)
.server("https://api.parse.com/1")
.enableLocalDataStore()
.allowCustomObjectId()
.build();
ParsePlugins plugins = ParseTestUtils.mockParsePlugins(configuration);
Parse.initialize(configuration, plugins);

ParseObject object = new ParseObject("TestObject");
object.setObjectId("ABCDEF123456");
object.saveEventually(
new SaveCallback() {
@Override
public void done(ParseException e) {
assertNull(e);
}
});

Parse.setLocalDatastore(null);
}

// region testGetter

@Test
Expand Down
Loading

0 comments on commit 5a482ba

Please sign in to comment.