Skip to content
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

DataStore.save() fails when a field used as a partition key is left empty #1360

Closed
2 of 9 tasks
justkj7 opened this issue Jun 10, 2022 · 9 comments
Closed
2 of 9 tasks
Assignees
Labels
bug Something isn't working DataStore p3

Comments

@justkj7
Copy link

justkj7 commented Jun 10, 2022

Description

I deployed my stack in remote server already using amplify init && amplify push
However, when DataStore.save() is invoked, it seems local db is updated but db in remote server is not updated correspondingly.

Here is amplify status using the command.

$ amplify status

    Current Environment: dev
    
┌──────────┬───────────────┬───────────┬───────────────────┐
│ Category │ Resource name │ Operation │ Provider plugin   │
├──────────┼───────────────┼───────────┼───────────────────┤
│ Api      │ chatservice   │ Update    │ awscloudformation │
└──────────┴───────────────┴───────────┴───────────────────┘

GraphQL endpoint: xxxx
GraphQL API KEY: xxxx

GraphQL transformer version: 2

Categories

  • Analytics
  • API (REST)
  • API (GraphQL)
  • Auth
  • Authenticator
  • DataStore
  • Storage

Steps to Reproduce

  1. configure schema.graphql as following
type Room @model @auth(rules: [{allow: public}]) {
  id: ID! @index(name: "roomIdOnCreatedAt", sortKeyFields: ["createdAt"], queryField: "roomIdOnCreatedAt")
  name: String!
  Messages: [Message] @hasMany(indexName: "byRoom", fields: ["id"])
  createdAt: AWSDateTime
}

type Message @model @auth(rules: [{allow: public}]) {
  id: ID!
  content: String!
  username: String
  roomID: ID! @index(name: "byRoom", sortKeyFields: ["createdAt"], queryField: "byRoomCreatedAt")
  createdAt: AWSDateTime
}
  1. Setup amplify client as following
class _MyAppState extends State<MyApp> {
  final AmplifyDataStore _dataStorePlugin = AmplifyDataStore(
    modelProvider: ModelProvider.instance,
  );
  final AmplifyAPI _apiPlugin =
      AmplifyAPI(modelProvider: ModelProvider.instance);

  bool _isLoading = true;

  @override
  initState() {
    super.initState();
    _configureAmplify();
  }

  Future<void> _configureAmplify() async {
    // await Amplify.addPlugin(AmplifyAPI()); // UNCOMMENT this line after backend is deployed
    try {
      await Amplify.addPlugins([_dataStorePlugin, _apiPlugin]);

      // Once Plugins are added, configure Amplify
      await Amplify.configure(amplifyconfig);
    } catch (e) {
      print(e);
    }

    setState(() {
      _isLoading = false;
    });
  }
...
  1. Invoke save()
      Room newRoom = Room(
        name: _tfNameController.text,
      );
      await Amplify.DataStore.save(newRoom);
  1. Check new record saved in remote server

Screenshots

No response

Platforms

  • iOS
  • Android

Android Device/Emulator API Level

No response

Environment

Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 2.5.3, on macOS 12.4 21F79 darwin-x64, locale en-US)
[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.2)
[✓] Xcode - develop for iOS and macOS
[✓] Chrome - develop for the web
[✓] Android Studio (version 3.5)
[✓] VS Code (version 1.67.2)
[✓] Connected device (2 available)

• No issues found!

Dependencies

- cross_file 0.3.3+1 [js meta]
- crypto 3.0.2 [typed_data]
- csslib 0.17.2 [source_span]
- date_time_format 2.0.1
- diffutil_dart 3.0.0
- equatable 2.0.3 [collection meta]
- ffi 1.2.1
- flutter_chat_types 3.2.1 [equatable json_annotation meta]
- flutter_link_previewer 2.6.1 [flutter flutter_chat_types flutter_linkify html http linkify meta url_launcher]
- flutter_linkify 5.0.2 [flutter linkify]
- flutter_plugin_android_lifecycle 2.0.6 [flutter]
- flutter_web_plugins 0.0.0 [flutter js characters collection meta typed_data vector_math]
- html 0.15.0 [csslib source_span]
- http 0.13.4 [async http_parser meta path]
- http_parser 4.0.1 [collection source_span string_scanner typed_data]
- image_picker_android 0.8.4+13 [flutter flutter_plugin_android_lifecycle image_picker_platform_interface]
- image_picker_for_web 2.1.8 [flutter flutter_web_plugins image_picker_platform_interface]
- image_picker_ios 0.8.4+11 [flutter image_picker_platform_interface]
- image_picker_platform_interface 2.5.0 [cross_file flutter http plugin_platform_interface]
- js 0.6.3
- json_annotation 4.5.0 [meta]
- linkify 4.1.0
- meta 1.7.0
- path 1.8.0
- photo_view 0.13.0 [flutter]
- plugin_platform_interface 2.1.2 [meta]
- sky_engine 0.0.99
- source_span 1.8.1 [collection path term_glyph]
- string_scanner 1.1.0 [charcode source_span]
- term_glyph 1.2.0
- typed_data 1.3.0 [collection]
- url_launcher 6.1.2 [flutter url_launcher_android url_launcher_ios url_launcher_linux url_launcher_macos url_launcher_platform_interface url_launcher_web url_launcher_windows]
- url_launcher_android 6.0.14 [flutter url_launcher_platform_interface]
- url_launcher_ios 6.0.14 [flutter url_launcher_platform_interface]
- url_launcher_linux 3.0.1 [flutter url_launcher_platform_interface]
- url_launcher_macos 3.0.1 [flutter url_launcher_platform_interface]
- url_launcher_platform_interface 2.0.5 [flutter plugin_platform_interface]
- url_launcher_web 2.0.7 [flutter flutter_web_plugins url_launcher_platform_interface]
- url_launcher_windows 3.0.1 [flutter url_launcher_platform_interface]
- uuid 3.0.6 [crypto]
- vector_math 2.1.0

Device

iPhone SE - 3rd generation

OS

iOS 15.5

CLI Version

8.3.1

Additional Context

No response

@Jordan-Nelson
Copy link
Member

Hello @justkj7 - can you confirm you have conflict resolution enabled? You can view the conflict resolution strategy in amplify/backend/api/{project}/cli-inputs.json.

@justkj7
Copy link
Author

justkj7 commented Jun 11, 2022

Hi @Jordan-Nelson Yes. Here is snippet for conflict resolution in cli-inputs.json.

    "conflictResolution": {
      "defaultResolutionStrategy": {
        "type": "AUTOMERGE"
      },
      "perModelResolutionStrategy": [
        {
          "resolutionStrategy": {
            "type": "AUTOMERGE"
          },
          "entityName": "Room"
        },
        {
          "resolutionStrategy": {
            "type": "AUTOMERGE"
          },
          "entityName": "Message"
        },
        {
          "resolutionStrategy": {
            "type": "AUTOMERGE"
          },
          "entityName": "Dummy"
        }
      ]
    }

@HuiSF
Copy link
Member

HuiSF commented Jul 1, 2022

Hello @justkj7 sorry for the delayed response. I was trying to repro this issue you were experience.

Could you let me know:

  • Is this still happening for you?
  • when you say "when DataStore.save() is invoked, it seems local db is updated but db in remote server is not updated correspondingly", was that happening for all models listed in your schema? Or any particular one?
  • In your output of amplify status, I noticed that you had local changes on the schema, did you try to amplify push to deploy the changes into cloud and to save again?

@HuiSF
Copy link
Member

HuiSF commented Jul 1, 2022

Hi @justkj7 I see the issue now.

Looking at your schema for Room model

type Room @model @auth(rules: [{allow: public}]) {
  id: ID! @index(name: "roomIdOnCreatedAt", sortKeyFields: ["createdAt"], queryField: "roomIdOnCreatedAt")
  name: String!
  Messages: [Message] @hasMany(indexName: "byRoom", fields: ["id"])
  createdAt: AWSDateTime
}

You are creating a Secondary Index on the model id field (this field is the partition key in DynamoDB), where you also specified createdAt as the sort key of this index.

When you invoke the save API:

Room newRoom = Room(
  name: _tfNameController.text,
);
await Amplify.DataStore.save(newRoom);

You haven't provided a value for createdAt field. In this case, when DataStore tries to sync this newly saved data to cloud it uses the following mutation, within which createdAt is assigned null.

{
	"variables": {
		"input": {
			"name": "a room",
			"id": "0417e26f-c95c-4f38-8c4d-9e9b00e0ae5b",
			"createdAt": null
		}
	},
	"query": "mutation CreateRoom($input: CreateRoomInput!) {\n  createRoom(input: $input) {\n    id\n    createdAt\n    name\n    updatedAt\n    __typename\n    _version\n    _deleted\n    _lastChangedAt\n  }\n}"
}

As createdAt is used as the sort key in the secondary index, it's required to be empty, or to have a valid value. But this mutation explicitly lists createdAt as null, which trigger validation error:

{
	"data": {
		"createRoom": null
	},
	"errors": [{
		"path": ["createRoom"],
		"data": null,
		"errorType": "DynamoDB:DynamoDbException",
		"errorInfo": null,
		"locations": [{
			"line": 2,
			"column": 3,
			"sourceName": null
		}],
		"message": "One or more parameter values were invalid: Type mismatch for Index Key createdAt Expected: S Actual: NULL IndexName: roomIdOnCreatedAt (Service: DynamoDb, Status Code: 400, Request ID: 1FPMGDEJ1D64H5VD267OABTU6RVV4KQNSO5AEMVJF66Q9ASUAAJG)"
	}]
}

So the data failed to sync to cloud. As your createdAt field is optional, I think this validation should not complain errors. I will confirm this with Amplify Data team.

In the meantime, please try to provide a valid value for createdAt, which ensures your records can be synced to cloud.

@justkj7
Copy link
Author

justkj7 commented Jul 2, 2022

Hi @HuiSF

Thanks a lot for answering my queries. The reason not to specify createAt when saving is to make it assigned value by server.
Is there any way to use createdAt which value is assigned by server as sorted key?

@HuiSF
Copy link
Member

HuiSF commented Jul 8, 2022

Hi @justkj7 sorry for the delayed response. This issue is very similar to aws-amplify/amplify-flutter#306 which probably requires a fix in the transformer. I've reached out to amplify-category-api maintainers for taking a look.

@HuiSF HuiSF added bug Something isn't working and removed pending-triage labels Jul 8, 2022
@Abdelazeem777
Copy link

I am facing the same issue here!

@Jordan-Nelson Jordan-Nelson changed the title DataStore.save() doesn't get the record saved in remote server DataStore.save() fails when a field used as a partition key is left empty Jan 24, 2023
@HuiSF HuiSF transferred this issue from aws-amplify/amplify-flutter Mar 22, 2023
@alharris-at alharris-at added the p3 label May 25, 2023
@dpilch
Copy link
Member

dpilch commented Jul 2, 2024

Duplicate of aws-amplify/amplify-flutter#5050

@dpilch dpilch marked this as a duplicate of aws-amplify/amplify-flutter#5050 Jul 2, 2024
@dpilch dpilch closed this as completed Jul 2, 2024
Copy link

github-actions bot commented Jul 2, 2024

This issue is now closed. Comments on closed issues are hard for our team to see.
If you need more assistance, please open a new issue that references this one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working DataStore p3
Projects
None yet
Development

No branches or pull requests

6 participants