aws-amplify / amplify-js

A declarative JavaScript library for application development using cloud services.
https://docs.amplify.aws/lib/q/platform/js
Apache License 2.0
9.43k stars 2.13k forks source link

DataStore: Cannot create record with no value for optional @connection field #8398

Closed james-braund closed 3 years ago

james-braund commented 3 years ago

Before opening, please confirm:

JavaScript Framework

React

Amplify APIs

Authentication, DataStore

Amplify Categories

auth, function, api

Environment information

``` # Put output below this line System: OS: Linux 4.19 Ubuntu 20.04.2 LTS (Focal Fossa) CPU: (4) x64 Intel(R) Core(TM) i5-4670K CPU @ 3.40GHz Memory: 21.51 GB / 25.02 GB Container: Yes Shell: 5.8 - /bin/zsh Binaries: Node: 14.15.0 - ~/.nvm/versions/node/v14.15.0/bin/node Yarn: 1.22.10 - ~/.nvm/versions/node/v14.15.0/bin/yarn npm: 6.14.8 - ~/.nvm/versions/node/v14.15.0/bin/npm Browsers: Chrome: 88.0.4324.96 npmPackages: @aws-amplify/ui-react: ^1.1.0 => 1.1.0 @aws-sdk/client-s3: ^3.15.0 => 3.15.0 (3.6.1) @aws-sdk/lib-storage: ^3.15.0 => 3.15.0 @electron-forge/cli: ^6.0.0-beta.54 => 6.0.0-beta.54 @electron-forge/maker-deb: ^6.0.0-beta.54 => 6.0.0-beta.54 @electron-forge/maker-rpm: ^6.0.0-beta.54 => 6.0.0-beta.54 @electron-forge/maker-squirrel: ^6.0.0-beta.54 => 6.0.0-beta.54 @electron-forge/maker-zip: ^6.0.0-beta.54 => 6.0.0-beta.54 @electron-forge/plugin-webpack: 6.0.0-beta.54 => 6.0.0-beta.54 @electron-forge/publisher-github: ^6.0.0-beta.54 => 6.0.0-beta.54 @marshallofsound/webpack-asset-relocator-loader: ^0.5.0 => 0.5.0 @material-ui/core: ^4.11.4 => 4.11.4 @material-ui/icons: ^4.11.2 => 4.11.2 @material-ui/lab: ^4.0.0-alpha.58 => 4.0.0-alpha.58 @types/dateformat: ^3.0.1 => 3.0.1 @types/mime-types: ^2.1.0 => 2.1.0 @types/mv: ^2.1.1 => 2.1.1 @types/nanoid-dictionary: ^4.2.0 => 4.2.0 @types/react: ^17.0.5 => 17.0.5 @types/react-dom: ^17.0.4 => 17.0.4 @types/sharp: ^0.28.1 => 0.28.1 @typescript-eslint/eslint-plugin: ^4.23.0 => 4.23.0 @typescript-eslint/parser: ^4.23.0 => 4.23.0 aws-amplify: ^3.4.0 => 3.4.2 chokidar: ^3.5.1 => 3.5.1 (2.1.8) css-loader: ^4.2.1 => 4.3.0 dateformat: ^4.5.1 => 4.5.1 electron: 11.2.1 => 11.2.1 electron-squirrel-startup: ^1.0.0 => 1.0.0 eslint: ^7.26.0 => 7.26.0 eslint-config-airbnb-typescript: ^12.3.1 => 12.3.1 eslint-config-prettier: ^7.2.0 => 7.2.0 eslint-plugin-import: ^2.22.1 => 2.22.1 eslint-plugin-jsx-a11y: ^6.4.1 => 6.4.1 eslint-plugin-prettier: ^3.4.0 => 3.4.0 eslint-plugin-react: ^7.23.2 => 7.23.2 eslint-plugin-react-hooks: ^4.2.0 => 4.2.0 file-loader: ^6.2.0 => 6.2.0 fork-ts-checker-webpack-plugin: ^5.0.14 => 5.2.1 history: ^5.0.0 => 5.0.0 memo-parser: 0.2.1 mime-types: ^2.1.30 => 2.1.30 mv: ^2.1.1 => 2.1.1 nanoid: ^3.1.23 => 3.1.23 nanoid-dictionary: ^4.3.0 => 4.3.0 node-loader: ^1.0.3 => 1.0.3 prettier: ^2.3.0 => 2.3.0 react: ^17.0.2 => 17.0.2 react-dom: ^17.0.2 => 17.0.2 react-hook-form: ^7.6.10 => 7.6.10 react-router-dom: ^6.0.0-beta.0 => 6.0.0-beta.0 sharp: ^0.28.2 => 0.28.2 style-loader: ^1.2.1 => 1.3.0 ts-loader: ^8.2.0 => 8.2.0 typeface-roboto: ^1.1.13 => 1.1.13 typescript: ^4.2.4 => 4.2.4 npmGlobalPackages: @aws-amplify/cli: 4.51.2 ngrok: 3.3.0 npm: 6.14.8 yarn: 1.22.10 ```

Describe the bug

Using DataStore, when I am try to create an entity which has an optional relationship with another entity, and I do not provide a value for the optional entity, the new entity fails to save with the error:

One or more parameter values were invalid: Type mismatch for Index Key subjectID Expected: S Actual: NULL IndexName: bySubject (Service: DynamoDb, Status Code: 400, Request ID: XXXXX, Extended Request ID: null)

Expected behavior

Entities for models with optional fields which use the @connection directive to reference other models, should be creatable without specifying a value for the given optional field.

Reproduction steps

  1. I modelled my entities for DataStore in GraphQL, using the Amplify transformers. Rough definition below (e.g. Event model excluded):
type Session @model
  @key(name: "byEvent", fields: ["eventID"])
  @key(name: "bySubject", fields: ["subjectID"])
  @auth(rules: [
    { allow: private, provider: iam }
  ])
  {
  id: ID!
  eventID: ID!
  event: Event @connection(fields: ["eventID"])
  subjectID: ID
  subject: Subject @connection(fields: ["subjectID"])
  status: SessionStatus!
}

enum SessionStatus {
  in_progress
  done
}

type Subject @model
  @key(name: "byEvent", fields: ["eventID"])
  @auth(rules: [
    { allow: private, provider: iam }
  ])
  {
  id: ID!
  firstName: String!
  lastName: String!
  eventID: ID!
  event: Event @connection(fields: ["eventID"])
  sessions: [Session] @connection(keyName: "bySubject", fields: ["id"])
}
  1. I then pushed my schema to my back-end using:

    amplify push
  2. I generated the models and copied them into my TS project using:

amplify codegen --max-depth 4
amplify codegen models --max-depth 4
amplify codegen types --max-depth 4
# then copied to correct place in project
  1. Updated code with the following call to DataStore when a user reaches my "Session" view (if one is not in progress):

    const newSessionForCreation = new Session({
    status: SessionStatus.IN_PROGRESS,
    event,
    });
    const newSession = await DataStore.save(newSessionForCreation);
    # then do stuff with newSession
  2. Started application, navigated to "Session" view, observed described error in logs.

Code Snippet

// Put your code below this line.
See reproduction steps.

Log output

``` // Put your logs below this line One or more parameter values were invalid: Type mismatch for Index Key subjectID Expected: S Actual: NULL IndexName: bySubject (Service: DynamoDb, Status Code: 400, Request ID: XXXXX, Extended Request ID: null) ```

aws-exports.js

No response

Manual configuration

No response

Additional configuration

No response

Mobile Device

No response

Mobile Operating System

No response

Mobile Browser

No response

Mobile Browser Version

No response

Additional information and screenshots

I originally raised this against https://github.com/aws-amplify/amplify-js/issues/5800#issuecomment-848212339 which showed someone having this issue several years ago. @sacrampton then reported the same issue (https://github.com/aws-amplify/amplify-js/issues/8361), but subsequently reported that they worked around it by passing an empty object as the connection field value. I tried this:

const newSessionForCreation = new Session({
  status: SessionStatus.IN_PROGRESS,
  event,
  subject: {} as Subject, # type coercion required as I am using TS
});
const newSession = await DataStore.save(newSessionForCreation);

But this produced the following error instead:

Uncaught (in promise) DOMException: Failed to execute 'get' on 'IDBIndex': No key or key range specified.
    at Proxy.<anonymous> (http://localhost:3000/main_window/index.js:461532:26)
    at IndexedDBAdapter.<anonymous> (http://localhost:3000/main_window/index.js:24239:52)
    at step (http://localhost:3000/main_window/index.js:24001:23)
    at Object.next (http://localhost:3000/main_window/index.js:23982:53)
    at http://localhost:3000/main_window/index.js:23976:71
    at new Promise (<anonymous>)
    at ./node_modules/@aws-amplify/datastore/lib-esm/storage/adapter/IndexedDBAdapter.js.__awaiter (http://localhost:3000/main_window/index.js:23972:12)
    at IndexedDBAdapter../node_modules/@aws-amplify/datastore/lib-esm/storage/adapter/IndexedDBAdapter.js.IndexedDBAdapter._get (http://localhost:3000/main_window/index.js:24226:16)
    at IndexedDBAdapter.<anonymous> (http://localhost:3000/main_window/index.js:24297:51)
    at step (http://localhost:3000/main_window/index.js:24001:23)

I've also reviewed the documentation for relational modelling, and also tried passing in the field as explicitly null or undefined. No joy.

I'm not sure if this is a bug, or if I'm simply doing something wrong here. Could I get some help please?

james-braund commented 3 years ago

Hi @iartemiev - any news on this please? Is there any other information I can provide to be of assistance?

I'm currently working around this issue by arbitrarily assigning a Subject to the Session when it begins, and then the user can choose a different one when they want, but that isn't a viable solution for Production.

james-braund commented 3 years ago

Hi @iartemiev - any news on this please?

james-braund commented 3 years ago

Good evening @iartemiev , @chrisbonifacio - do you have any news on this issue?

To help clarify things, I've produced a standalone repository to demonstrate the problem, which you can find here:

https://github.com/james-braund/amplify-demo

In order to see the problem:

  1. Clone down the repo
  2. Setup your team-provider-info.json
  3. Push the Amplify back-end with amplify push
  4. Ensure aws-exports.js has been generated under src/
  5. Start the React app with npm start
  6. Navigate to the app and click the "Add a post (with author)" button to see a successful blog post creation (review console logs to confirm)
  7. Click the "Add a post (no author)" button, and view the console logs. You will see the error:
    "One or more parameter values were invalid: Type mismatch for Index Key authorID Expected: S Actual: NULL IndexName: byAuthor (Service: DynamoDb, Status Code: 400, Request ID: XXXXX, Extended Request ID: null)"

Please let me know if there is any other information I can provide. We're looking to ship our app to Production for a client in the next few weeks, and would really like to get this sorted by then. I'll continue to investigate it in my own time when I can. I'd really appreciate any help you can offer.

nickarocho commented 3 years ago

Hi @james-braund thank you for your patience while we look into this issue. Also, thank you for creating a sample app to reproduce the problem you are seeing.

I was able to set up the app and reproduce the same issue. I'm going to look deeper into the root cause of the problem and will keep you posted on what I discover.

Thanks!

nickarocho commented 3 years ago

@james-braund we have identified the issue and I just created a PR to fix the issue!

I wanted to thank you again on behalf the Amplify JS team for discovering this problem, your patience as we identified the root cause, and for your thorough explanation/demonstration through creating a sample repo to reproduce and ultimately solve the problem.

The fix should be merged soon and available in our upcoming release. I'll send a reminder when it is available for you to test out on your end.

Thanks!

james-braund commented 3 years ago

Hi @nickarocho - that's great news, thank you! Glad I was able to be of some assistance. I'll keep an eye out for the notification about the new release, and then I'll give it a whirl and feed back to you.

iartemiev commented 3 years ago

@james-braund the fix has been released as part of aws-amplify@4.2.1

buildhitesh commented 3 years ago

Getting the same error with the aws-amplify@4.2.1 version also.

nickarocho commented 3 years ago

Hi @buildhitesh, could you provide us with your environment information?

Please paste the output from this command: npx envinfo --system --binaries --browsers --npmPackages --duplicates --npmGlobalPackages

Also, it would be helpful to know the specific steps you've taken so far to remediate the problem (i.e. deleted/reinstalled node_modules, checked different environments, etc.). Any code snippets of your models and app code would be helpful as well (i.e. your schema.graqhql file and maybe some of the frontend application code you call when the issue happens).

Thanks!

buildhitesh commented 3 years ago

Here are the environment info:

System:
    OS: macOS 11.5
    CPU: (8) x64 Intel(R) Core(TM) i5-8259U CPU @ 2.30GHz
    Memory: 801.35 MB / 8.00 GB
    Shell: 5.8 - /bin/zsh
  Binaries:
    Node: 14.17.3 - /usr/local/bin/node
    npm: 6.14.13 - /usr/local/bin/npm
  Browsers:
    Chrome: 92.0.4515.107
    Safari: 14.1.2
  npmPackages:
    @babel/core: ^7.8.6 => 7.14.8 (7.9.0)
    @dudigital/react-native-zoomable-view: ^1.0.15 => 1.1.3 
    @expo/vector-icons: ^12.0.5 => 12.0.5 (10.2.1)
    @react-native-community/datetimepicker: 3.0.0 => 3.0.0 
    @react-native-community/eslint-config:  1.1.0 
    @react-native-community/eslint-plugin:  1.0.0 
    @react-native-community/masked-view: 0.1.10 => 0.1.10 
    @react-native-community/netinfo: 5.9.6 => 5.9.6 
    @react-navigation/native: ^5.7.3 => 5.9.4 
    @react-navigation/stack: ^5.9.0 => 5.14.5 
    @types/react: ~16.9.35 => 16.9.56 
    @types/react-native: ~0.63.2 => 0.63.52 
    HelloWorld:  0.0.1 
    aws-amplify: ^3.0.21 => 3.4.3 
    aws-amplify-react-native: ^4.2.2 => 4.3.3 
    aws-sdk: ^2.728.0 => 2.954.0 
    babel-eslint: ^10.1.0 => 10.1.0 
    babel-plugin-inline-view-configs:  0.0.5 
    babel-preset-expo: ^8.3.0 => 8.3.0 
    eslint: ^7.10.0 => 7.31.0 
    eslint-config-airbnb: ^18.2.0 => 18.2.1 
    eslint-plugin-import: ^2.22.1 => 2.23.4 
    eslint-plugin-jsx-a11y: ^6.3.1 => 6.4.1 
    eslint-plugin-react: ^7.21.3 => 7.24.0 
    eslint-plugin-react-hooks: ^4.1.2 => 4.2.0 
    eslint-plugin-react-native: ^3.10.0 => 3.11.0 
    expo: ^39.0.0 => 39.0.5 
    expo-cli: ^4.7.2 => 4.8.1 
    expo-file-system: ~9.2.0 => 9.2.0 
    expo-font: ~8.3.0 => 8.3.0 
    expo-image-picker: ~9.1.0 => 9.1.1 
    expo-intent-launcher: ~8.3.0 => 8.3.0 
    expo-linear-gradient: ~8.3.0 => 8.3.1 
    expo-sharing: ~8.4.1 => 8.4.1 
    expo-status-bar: ~1.0.2 => 1.0.4 
    hermes-inspector-msggen:  1.0.0 
    husky: ^4.3.0 => 4.3.8 
    ini: ^1.3.5 => 1.3.8 
    inquirer: ^6.5.1 => 6.5.2 (3.3.0)
    metro-config: ^0.66.0 => 0.66.2 (0.59.0)
    react: 16.13.1 => 16.13.1 
    react-animated:  0.1.0 
    react-dom: 16.13.1 => 16.13.1 
    react-hook-form: ^6.4.1 => 6.15.8 
    react-native: https://github.com/expo/react-native/archive/sdk-39.0.0.tar.gz => 0.63.2 
    react-native-codegen:  0.0.2 
    react-native-dropdown-picker: ^3.6.8 => 3.8.3 
    react-native-extended-stylesheet: ^0.12.0 => 0.12.0 
    react-native-gesture-handler: ~1.7.0 => 1.7.0 
    react-native-reanimated: ~1.13.0 => 1.13.3 
    react-native-safe-area-context: 3.1.4 => 3.1.4 
    react-native-safe-area-view: ^1.1.1 => 1.1.1 
    react-native-screens: ~2.10.1 => 2.10.1 
    react-native-svg: 12.1.0 => 12.1.0 
    react-native-svg-transformer: ^0.14.3 => 0.14.3 
    react-native-web: ~0.13.7 => 0.13.18 
    sentry-expo: ^3.1.4 => 3.1.4 
    typescript: ~3.9.2 => 3.9.10 
  npmGlobalPackages:
    @aws-amplify/cli: 5.1.2
    expo-cli: 4.7.2
    npm: 6.14.13

The error I'm getting on Datastore Create:

[WARN] 17:54.300 DataStore, Object {
  "errorInfo": null,
  "errorType": "DynamoDB:DynamoDbException",
  "localModel": Switchgear {
    "_deleted": undefined,
    "_lastChangedAt": undefined,
    "_version": undefined,
    "breakerSlotCount": 2,
    "catalogNumber": "",
    "depth": null,
    "groundBusPresent": false,
    "height": null,
    "id": "b6c087e7-4c58-4599-b0dc-769ca2b58013",
    "installDate": 0,
    "location": "Test location",
    "mainDisconnect": "breaker",
    "manufacturer": "",
    "model": undefined,
    "mountType": "surface",
    "name": "Test Switchgear",
    "neutralBonded": undefined,
    "neutralBusPresent": false,
    "parent": null,
    "powerPhases": 3,
    "racewayCountBack": 0,
    "racewayCountBottom": 0,
    "racewayCountLeft": 0,
    "racewayCountRight": 0,
    "racewayCountTop": 0,
    "system": "e65ac242-b139-4a78-bcde-a7e40f0d9e24",
    "width": null,
  },
  "message": "One or more parameter values were invalid: Type mismatch for Index Key parent Expected: S Actual: NULL IndexName: BySystem (Service: DynamoDb, Status Code: 400, Request ID: 139FVATN6CH525HIQT4JRFB5S7VV4KQNSO5AEMVJF66Q9ASUAAJG, Extended Request ID: null)",
  "operation": "Create",
  "remoteModel": null,
}
at [native code]:null in warn
at node_modules/@aws-amplify/core/lib-esm/Logger/ConsoleLogger.js:99:13 in prototype._log
at node_modules/@aws-amplify/core/lib-esm/Logger/ConsoleLogger.js:145:4 in <anonymous>
at node_modules/@aws-amplify/datastore/lib-esm/datastore/datastore.js:377:1 in <global>
at node_modules/@aws-amplify/datastore/lib-esm/sync/processors/mutation.js:361:60 in __generator$argument_1
at node_modules/@aws-sdk/client-s3/node_modules/@aws-crypto/sha256-js/node_modules/tslib/tslib.js:142:24 in step
at node_modules/@aws-sdk/client-s3/node_modules/@aws-crypto/sha256-js/node_modules/tslib/tslib.js:122:27 in verb
at node_modules/@aws-sdk/client-s3/node_modules/@aws-crypto/sha256-js/node_modules/tslib/tslib.js:113:90 in rejected
at [native code]:null in flushedQueue
at [native code]:null in callFunctionReturnFlushedQueue

default values are coming as undefined instead of null or blank.

GraphQL schema is:

type Switchgear implements Equipment
  @model
  @auth(rules: [{ allow: private }])
  @key(
    name: "BySystem"
    fields: ["system", "parent"]
    queryField: "switchgearBySystem"
  ) {
  id: ID!
  system: ID!
  parent: ID
  breakerSlotCount: Int
  breakers: [Breaker] @connection
  catalogNumber: String
  depth: Float
  groundBusPresent: Boolean
  height: Float
  installDate: Int
  mainDisconnect: String
  model: String
  manufacturer: String
  mountType: String
  name: String
  location: String
  neutralBonded: Boolean
  neutralBusPresent: Boolean
  powerPhases: Int
  racewayCountBack: Int
  racewayCountBottom: Int
  racewayCountLeft: Int
  racewayCountRight: Int
  racewayCountTop: Int
  width: Float
}

as you can see neutralBonded column value is optional, but still Datastore taking it as undefined, then dynamodb throwing the error.

nickarocho commented 3 years ago

Hi @buildhitesh thanks for the system info and code snippets.

The output of your npmPackages shows aws-amplify: ^3.0.21 => 3.4.3, which will not contain the fix we made last week. Can you try bumping up to aws-amplify@4.2.1 and let us know if you are still experiencing this problem?

github-actions[bot] commented 2 years ago

This issue has been automatically locked since there hasn't been any recent activity after it was closed. Please open a new issue for related bugs.

Looking for a help forum? We recommend joining the Amplify Community Discord server *-help channels or Discussions for those types of questions.