Closed KayIlory closed 4 years ago
waitForSignIn: userState:SIGNED_IN
I/Output: UserTest {id=a236299d-efd1-43ac-aaac-508c2e24be9c, gender=Male}
After an update to try and change Gender to Female and doesnt work..
E/Delete Error:: GraphQLResponse.Error{message='Conflict resolver rejects mutation.', locations='[GraphQLLocation{line='1', column='56'}]', path='[GraphQLPathSegment{value='deleteUserTest'}]', extensions='{errorInfo=null, data={gender=Male, id=76253e92-b18d-4f1e-b364-a766e8e32ab0}, errorType=ConflictUnhandled}'}
When trying to deleted a newly created user..
public void createUser() {
UserTest userTest = UserTest.builder().gender(Gender.Male).build();
Amplify.API.mutate(ModelMutation.create(userTest),
response -> {
if(response.getData() != null) {
//updateUser(response.getData());
deleteUser(response.getData());
}
if(response.getErrors() != null)
{
for(GraphQLResponse.Error error : response.getErrors())
{
Log.e("Create Error:", error.toString());
}
}
}, error -> {
Log.e("MyAmplifyApp", "Create failed", error);
});
}
public void updateUser(UserTest userTest)
{
UserTest _userTest = userTest.copyOfBuilder().gender(Gender.Female).build();
Amplify.API.mutate(ModelMutation.update(_userTest),
response -> {
if(response.getData() != null) {
deleteUser(response.getData());
Log.i("Output", response.getData().toString());
}
if(response.getErrors() != null)
{
for(GraphQLResponse.Error error : response.getErrors())
{
Log.e("Update Error:", error.toString());
}
}
}, error -> {
Log.e("MyAmplifyApp", "Create failed", error);
});
}
public void deleteUser(UserTest userTest)
{
Amplify.API.mutate(ModelMutation.delete(userTest),
response -> {
if(response.getData() != null) {
Log.i("Output", response.getData().toString());
}
if(response.getErrors() != null)
{
for(GraphQLResponse.Error error : response.getErrors())
{
Log.e("Delete Error:", error.toString());
}
}
}, error -> {
Log.e("MyAmplifyApp", "Create failed", error);
});
}
I disabled DataStore for entire API to get this working. ? Please select from one of the below mentioned services: GraphQL ? Select from the options below Disable DataStore for entire API
Hi @Kayllory, there are some known issues with using Datastore
and API
in the same app. Essentially, there's not an easy way to specific special fields like _version
via Amplify.API
, which are needed for conflict resolution, and that is likely why you are getting errors. This is something we want to fix, but for now, as a workaround, I'd suggest using API
or Datastore
, but not both.
As @richardmcclellan notes, we do not currently support using GraphQL API and DataStore at the same time. It is recommended to use one or the other.
We can keep this as a feature request.
If you would like to see this functionality added, please add a 👍 or similar reaction.
hey @jamesonwilliams! just to clarify, as per today, can we use GraphQL API and DataStore at the same time using 1.3.0 library?
@Scarlett13 Nope, still not possible in 1.3.0.
My original design and implementation of the DataStore did actually account for this functionality. I was asked to remove it, to align the behavior to iOS and JavaScript.
But, I have heard from many customers by now that this is an important piece of missing functionality. So, I've re-implemented a prototype of the functionality. With https://github.com/aws-amplify/amplify-android/pull/786, you would be able to add a "datastore"
block to your amplifyconfiguration.json
, as below. It would allow you to specify a particular API to use for DataStore sync:
{
...
"api": {
"plugins": {
"awsAPIPlugin": {
"[API NAME 1]": {
...
},
"[API NAME 2]": {
...
}
}
}
},
"datastore": {
"plugins": {
"awsDataStorePlugin": {
"apiName": "[API NAME 1]"
}
}
}
}
^^ Note: need to align this with my team & with the other platforms. The config structure is subject to change.
@jamesonwilliams really cant wait for that enhancement. It will improve app performance by 4x
Hey @Kayllory, could you elaborate a little more on your use case? How would it improve your app performance?
Amplify.DataStore
only works when conflict detection is enabled on your AppSync API. This is needed for DataStore to resolve conflicts when merging remote updates with the local store, so this probably won't be changing.
Amplify.API
currently only works when conflict detection is disabled. When enabled, queries return errors about conflict handling because mutations do not include the _version
of the model.
It may be possible to update Amplify.API
such that it can work with conflict detection enabled. But before we go down that route, could you describe what you want to use Amplify.API
for, that you can't do with Amplify.DataStore
?
@richardmcclellan - my understanding is that datastore store the data locally and sync with the backend dynamo while API is direct async call to the dynamo for CRUD operations. We see performance issues on the London and Frankfurt regions when do API Crud operations. With datastore we hoping user experience doesnt have to wait for that call, and simply persist locally and sync with the backend without user needed to constantly hit the backed. We found that if we can do a combination of datastore with sync for most of our calls and APi for the ones we need to always get latest from server, the application experience is much better. The time it takes to read 10rows about 4secs from backend with API, we tried with datastore and it was instant. Having API work with conflict detection enabled means we can use both datastore and api in the same app without issues is my understanding.
Happy to be corrected if my assumptions above are incorrect.
That's right, DataStore
persists data locally, so that when you do a DataStore.query
, you get an almost instant response, since it's reading from the SQLite table on disc, rather than making a network call. When DataStore
is initialized, it fetches all of your models from the AppSync API and saves them locally. This sync actually just uses Amplify.API
under the hood, so there's no different in "performance" between API and DataStore, except that DataStore is caching everything on disc when your app starts, so when you query for it, it's available right away.
We found that if we can do a combination of datastore with sync for most of our calls and API for the ones we need to always get latest from server, the application experience is much better.
DataStore
also subscribes to all changes on all models, so even after the sync queries are completed, it should always be up to date, so you shouldn't need to use Amplify.API
at all.
Hi @jamesonwilliams @richardmcclellan I have tried what you suggested to me, and I got this error
{message=Failure performing sync query to AppSync: [GraphQLResponse.Error{message='Cannot return null for non-nullable type: 'AWSTimestamp' within parent 'SelfEducation' (/syncSelfEducations/items[0]/_lastChangedAt)', locations='null', path='[GraphQLPathSegment{value='syncSelfEducations'}, GraphQLPathSegment{value='items'}, GraphQLPathSegment{value='0'}, GraphQLPathSegment{value='_lastChangedAt'}]', extensions='null'}, GraphQLResponse.Error{message='Cannot return null for non-nullable type: 'Int' within parent 'SelfEducation' (/syncSelfEducations/items[0]/_version)', locations='null', path='[GraphQLPathSegment{value='syncSelfEducations'}, GraphQLPathSegment{value='items'}, GraphQLPathSegment{value='0'}, GraphQLPathSegment{value='_version'}]', extensions='null'}, GraphQLResponse.Error{message='Cannot return null for non-nullable type: 'AWSTimestamp' within parent 'SelfEducation' (/syncSelfEducations/items[1]/_lastChangedAt)', locations='null', path='[GraphQLPathSegment{value='syncSelfEducations'}, GraphQLPathSegment{value='items'}, GraphQLPathSegment{value='1'}, GraphQLPathSegment{value='_lastChangedAt'}]', extensions='null'}, GraphQLResponse.Error{message='Cannot return null for non-nullable type: 'Int' within parent 'SelfEducation' (/syncSelfEducations/items[1]/_version)', locations='null', path='[GraphQLPathSegment{value='syncSelfEducations'}, GraphQLPathSegment{value='items'}, GraphQLPathSegment{value='1'}, GraphQLPathSegment{value='_version'}]', extensions='null'}, GraphQLResponse.Error{message='Cannot return null for non-nullable type: 'AWSTimestamp' within parent 'SelfEducation' (/syncSelfEducations/items[2]/_lastChangedAt)', locations='null', path='[GraphQLPathSegment{value='syncSelfEducations'}, GraphQLPathSegment{value='items'}, GraphQLPathSegment{value='2'}, GraphQLPathSegment{value='_lastChangedAt'}]', extensions='null'}, GraphQLResponse.Error{message='Cannot return null for non-nullable type: 'Int' within parent 'SelfEducation' (/syncSelfEducations/items[2]/_version)', locations='null', path='[GraphQLPathSegment{value='syncSelfEducations'}, GraphQLPathSegment{value='items'}, GraphQLPathSegment{value='2'}, GraphQLPathSegment{value='_version'}]', extensions='null'}], cause=null, recoverySuggestion=Sorry, we don't have a suggested fix for this error yet.}, recoverySuggestion=Check your internet connection.}
My schema look like:
type Self
@model(timestamps:{createdAt: "createdOn", updatedAt: "updatedOn"})
{
id:ID!
selfname: [SelfName] @connection(keyName: "bySelf", fields: ["id"])
selfeducationhistory: [SelfEducation] @connection(keyName: "bySelf", fields: ["id"])
...
updatedOn: AWSDateTime!
createdOn: AWSDateTime!
}
type SelfName
@model(timestamps:{createdAt: "createdOn", updatedAt: "updatedOn"})
@key(name: "bySelf", fields: ["selfid", "fullname"])
{
id:ID!
selfid:ID!
...
createdOn: AWSDateTime! #
updatedOn: AWSDateTime! #
}
type SelfEducation
@model(timestamps:{createdAt: "createdOn", updatedAt: "updatedOn"})
@key(name: "bySelf", fields: ["selfid", "institutionname"])
{
id:ID!
selfid:ID
...
createdOn: AWSDateTime! #
updatedOn: AWSDateTime! #
}
The error caused when I tried to add new SelfName to the existing Self type in dynamo db. Could you help me enlightened where did I do wrong? I didn't use Amplify.API in this case. And I am using 1.3.2 for every plugins. Thanks.
On 17th June, I was able to do update via Amplify with no issues. From Sunday, the 21st June 2020, I am no longer able to do this. The values do not get updated and I get errors.
Steps to reproduce.. Set api conflict resolution to auto merge
Android class
It doesn't update the sex from Male to Female.