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

GraphQL helper doesn't support query and mutation on the many-to-many connection models #1814

Closed
3 of 9 tasks
MarlonJD opened this issue Jun 24, 2022 · 12 comments
Closed
3 of 9 tasks
Assignees
Labels
bug Something is not working; the issue has reproducible steps and has been reproduced GraphQL API Issues related to the API (GraphQL) Category

Comments

@MarlonJD
Copy link
Contributor

Description

Hello everyone. After encountering a lot of problems about DataStore, I removed all DataStore and check realtime datas on AppSync from Amplify on Flutter. Anyways here's is the issue.

TL; DR: ModelQueries.list creating missing document

related schema:

type Department @model @auth(rules: [{allow: public, operations: [read], provider: iam}, {allow: private}]) {
  id: ID!
  nameEn: String!
  nameTr: String!
  university: University @belongsTo
  mainStudents: [Student] @manyToMany(relationName: "MainDepartmentStudent")
  students: [Student] @manyToMany(relationName: "DepartmentStudents")
  mainTeachers: [Teacher] @manyToMany(relationName: "MainDepartmentTeachers")
  teachers: [Teacher] @manyToMany(relationName: "DepartmentTeachers")
}

type Student @model @auth(rules: [{allow: private, operations: [create, read, update]}, {allow: owner}]) {
  id: ID!
  photo: String
  phone: String
  universityNumber: String!
  email: String!
  birthday: AWSDate!
  gender: Gender!
  cognitoId: ID!
  internships: [Internship] @hasMany
  company: Company @belongsTo
  universityClass: UniversityClass
  universityLevel: UniversityLevel
  department: [Department] @manyToMany(relationName: "MainDepartmentStudent")
  departments: [Department] @manyToMany(relationName: "DepartmentStudents")
}

That's my query, it should work here's is request:

Future getStudentDepartment() async {
    try {
      final departmentRequest = ModelQueries.list(
          MainDepartmentStudent.classType,
          where: MainDepartmentStudent.STUDENT
              .eq(Get.find<AmplifyServices>().studentObj.value.id));

      // GraphQLRequest<PaginatedResult<MainDepartmentStudent>> request =
      //     GraphQLRequest<PaginatedResult<MainDepartmentStudent>>(
      //   document: getStudentDepartmentQuery,
      //   variables: {
      //     'student': Get.find<AmplifyServices>().studentObj.value.id,
      //   },
      //   decodePath: departmentRequest.decodePath,
      //   modelType: departmentRequest.modelType,
      // );

      print("TEEST: ${departmentRequest.variables}");
      print("TEEST: ${departmentRequest.document}");

      try {
        final departmentResponse =
            await Amplify.API.query(request: departmentRequest).response;

        // Get student department
        try {
          final departmentRequest = ModelQueries.get(Department.classType,
              departmentResponse.data!.items.first!.department.id);

          try {
            final departmentResponse =
                await Amplify.API.query(request: departmentRequest).response;

            studentDepartment = departmentResponse.data;
            update();
            debugPrint("ok.. found department");
          } catch (e) {
            print(e);
          }
        } catch (e) {
          debugPrint("cannot get department trying again... 0 $e");
          //await Future.delayed(const Duration(milliseconds: 100));
          //return getStudentDepartment();
        }
      } catch (e) {
        print(e);
      }
    } catch (e) {
      debugPrint("cannot get student trying again... $e");
      await Future.delayed(const Duration(milliseconds: 100));
      return getStudentDepartment();
    }
  }

here's the response, error related to department is null:

GraphQL query operation succeeded with response : ["data": "{\"listMainDepartmentStudents\":{\"nextToken\":null,\"items\":[{\"id\":\"b5b3aaf5-f23d-47fc-bc58-c643f1ede4ff\",\"student\":{\"universityClass\":\"THIRD\",\"id\":\"dd1c140f-4d0e-4332-a511-e4ce015d0f53\",\"updatedAt\":\"2022-06-21T15:18:46.925Z\",\"phone\":\"\",\"photo\":\"\",\"universityNumber\":\"4554545\",\"cognitoId\":\"1e2667c5-480f-44f5-b657-87c316c0bee7\",\"birthday\":\"2022-06-15\",\"universityLevel\":\"ASSOCIATE\",\"createdAt\":\"2022-06-21T15:18:46.925Z\",\"gender\":\"MALE\",\"email\":\"[email protected]\"},\"updatedAt\":\"2022-06-21T15:18:47.204Z\",\"createdAt\":\"2022-06-21T15:18:47.204Z\"}]}}", "errors": []]
flutter: cannot get department trying again... 0 AmplifyCodeGenModelException(message: The field you are accessing is not nullable but has a null value. It was marked as required (!) in your schema.graphql but the containing model class was initialized without setting its value., recoverySuggestion: Please validate that the containing model class was initialized properly with all requried fields being initialized. This can happen when a nested model is returned but only its id field has been set, underlyingException: Null check operator used on a null value)

Let's investigate graphql document and variables:
document:

variables: {filter: {studentID: {eq: dd1c140f-4d0e-4332-a511-e4ce015d0f53}}, limit: null, nextToken: null}
document: 
query listMainDepartmentStudents($filter: ModelMainDepartmentStudentFilterInput, $limit: Int, $nextToken: String) {
  listMainDepartmentStudents(filter: $filter, limit: $limit, nextToken: $nextToken) { 
      items { 
          id 
          createdAt
          updatedAt
          student {
            id
            photo
            phone 
            universityNumber
            email
            birthday
            gender
            cognitoId
            universityClass
            universityLevel
            createdAt
            updatedAt
          }
        }
      nextToken
    }
}

As we can we, there's no department in the graphql document, that's the issue. ModelQueries.list should create department as I need.

So I tried to modify variable and create custom request like this. I didn't use original document to modify because on filter there is filter object and I didn't want to parse these:

Future getStudentDepartment() async {
    try {
      final departmentRequest = ModelQueries.list(
          MainDepartmentStudent.classType,
          where: MainDepartmentStudent.STUDENT
              .eq(Get.find<AmplifyServices>().studentObj.value.id));

      GraphQLRequest<PaginatedResult<MainDepartmentStudent>> request =
          GraphQLRequest<PaginatedResult<MainDepartmentStudent>>(
        document: """
query getStudentDepartment(\$studentID: ID = "") {
  listMainDepartmentStudents(filter: {studentID: {eq: \$studentID}}) {
     items {
      id
      department {
        nameEn
        nameTr
        id
        createdAt
        universityDepartmentsId
        updatedAt
        university {
          id
          logo
          managerIds
          nameEn
          nameTr
          studentCount
          supportMail
          teacherCount
          updatedAt
          createdAt
        }
      }
      student {
        email
        gender
        birthday
        cognitoId
        companyStudentsId
        createdAt
        id
        owner
        phone
        photo
        universityClass
        universityLevel
        universityNumber
        updatedAt
      }
    }
    nextToken
  }
}""",
        variables: {
          'studentID': Get.find<AmplifyServices>().studentObj.value.id,
        },
        decodePath: departmentRequest.decodePath,
        modelType: departmentRequest.modelType,
      );

      print("TEEST: ${request.variables}");
      print("TEEST: ${request.document}");

      try {
        final departmentResponse =
            await Amplify.API.query(request: request).response;

        // Get student department
        try {
          final departmentRequest = ModelQueries.get(Department.classType,
              departmentResponse.data!.items.first!.department.id);

          try {
            final departmentResponse =
                await Amplify.API.query(request: departmentRequest).response;

            studentDepartment = departmentResponse.data;
            update();
            debugPrint("ok.. found department");
          } catch (e) {
            print(e);
          }
        } catch (e) {
          debugPrint("cannot get department trying again... 0 $e");
          //await Future.delayed(const Duration(milliseconds: 100));
          //return getStudentDepartment();
        }
      } catch (e) {
        print(e);
      }
    } catch (e) {
      debugPrint("cannot get student trying again... $e");
      await Future.delayed(const Duration(milliseconds: 100));
      return getStudentDepartment();
    }
  }

and here's the variable and document:

variables: {studentID: dd1c140f-4d0e-4332-a511-e4ce015d0f53}
document: 
  listMainDepartmentStudents(filter: {studentID: {eq: $studentID}}) {
     items {
      id
      department {
        nameEn
        nameTr
        id
        createdAt
        universityDepartmentsId
        updatedAt
        university {
          id
          logo
          managerIds
          nameEn
          nameTr
          studentCount
          supportMail
          teacherCount
          updatedAt
          createdAt
        }
      }
      student {
        email
        gender
        birthday
        cognitoId
        companyStudentsId
        createdAt
        id
        owner
        phone
        photo
        universityClass
        universityLevel
        universityNumber
        updatedAt
      }
    }
    nextToken
  }
}

and response:

GraphQL query operation succeeded with response : ["errors": [], "data": "{\"getDepartment\":{\"nameTr\":\"Any name\",\"id\":\"2a8b634e-43cf-4c13-ba74-a51e40355e3a\",\"nameEn\":\"Any name\",\"updatedAt\":\"2022-06-17T19:06:06.303Z\",\"university\":{\"studentCount\":1958,\"nameEn\":\"Any Name\",\"supportMail\":\"[email protected]\",\"id\":\"5166e729-abd8-4722-8a45-771c5b443744\",\"nameTr\":\"Any name\",\"updatedAt\":\"2022-06-13T18:13:45.221Z\",\"teacherCount\":243,\"managerIds\":null,\"createdAt\":\"2022-06-13T18:13:45.221Z\",\"logo\":\"\"},\"createdAt\":\"2022-06-17T19:06:06.303Z\"}}"]
flutter: ok.. found department

So it's succeed.

Categories

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

Steps to Reproduce

No response

Screenshots

No response

Platforms

  • iOS
  • Android

Android Device/Emulator API Level

API 21

Environment

[✓] Flutter (Channel stable, 3.0.2, on macOS 12.4 21F79 darwin-x64, locale tr)
    • Flutter version 3.0.2 at /Users/marlonjd/flutter/flutter2
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision cd41fdd495 (2 weeks ago), 2022-06-08 09:52:13 -0700
    • Engine revision f15f824b57
    • Dart version 2.17.3
    • DevTools version 2.12.2

[✓] Android toolchain - develop for Android devices (Android SDK version 32.0.0)
    • Android SDK at /Users/marlonjd/Library/Android/sdk
    • Platform android-32, build-tools 32.0.0
    • Java binary at: /Applications/Android Studio.app/Contents/jre/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.11+0-b60-7590822)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 13.4.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • CocoaPods version 1.11.3

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2021.1)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.11+0-b60-7590822)

[✓] VS Code (version 1.68.1)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.42.0

[✓] Connected device (3 available)
    • FF iPod touch (mobile) • be3091413ece7869d08367bf2985276a1e125390 • ios            • iOS 15.5 19F77
    • macOS (desktop)        • macos                                    • darwin-x64     • macOS 12.4 21F79 darwin-x64
    • Chrome (web)           • chrome                                   • web-javascript • Google Chrome 103.0.5060.53

[✓] HTTP Host Availability
    • All required HTTP hosts are available

• No issues found!

Dependencies

Dart SDK 2.17.3
Flutter SDK 3.0.2
monolibmobile 1.0.0+1

dependencies:
- amplify_analytics_pinpoint 0.6.0 [amplify_analytics_pinpoint_android amplify_analytics_pinpoint_ios amplify_core aws_common flutter meta]
- amplify_api 0.6.0 [amplify_api_android amplify_api_ios amplify_core amplify_flutter aws_common collection flutter meta plugin_platform_interface]
- amplify_auth_cognito 0.6.0 [amplify_auth_cognito_android amplify_auth_cognito_ios amplify_core aws_common collection flutter meta plugin_platform_interface]
- amplify_datastore 0.6.0 [flutter amplify_datastore_plugin_interface amplify_core plugin_platform_interface meta collection async]
- amplify_flutter 0.6.0 [amplify_core amplify_datastore_plugin_interface amplify_flutter_android amplify_flutter_ios aws_common collection flutter meta plugin_platform_interface]
- amplify_storage_s3 0.6.0 [amplify_storage_s3_android amplify_storage_s3_ios amplify_core aws_common meta flutter plugin_platform_interface]
- app_tutorial 0.3.2 [flutter_staggered_grid_view flutter]
- cached_network_image 3.2.1 [flutter flutter_cache_manager octo_image cached_network_image_platform_interface cached_network_image_web]
- card_swiper 2.0.4 [flutter]
- cloud_firestore 3.1.17 [cloud_firestore_platform_interface cloud_firestore_web collection firebase_core firebase_core_platform_interface flutter meta]
- cupertino_icons 1.0.4
- file_picker 3.0.4 [flutter flutter_web_plugins flutter_plugin_android_lifecycle plugin_platform_interface]
- firebase_analytics 9.1.9 [firebase_analytics_platform_interface firebase_analytics_web firebase_core firebase_core_platform_interface flutter]
- firebase_auth 3.3.19 [firebase_auth_platform_interface firebase_auth_web firebase_core firebase_core_platform_interface flutter meta]
- firebase_core 1.17.1 [firebase_core_platform_interface firebase_core_web flutter meta]
- firebase_messaging 11.4.1 [firebase_core firebase_core_platform_interface firebase_messaging_platform_interface firebase_messaging_web flutter meta]
- firebase_storage 10.2.17 [firebase_core firebase_core_platform_interface firebase_storage_platform_interface firebase_storage_web flutter]
- flutter 0.0.0 [characters collection material_color_utilities meta vector_math sky_engine]
- flutter_cache_manager 3.3.0 [clock collection file flutter http path path_provider pedantic rxdart sqflite uuid]
- flutter_chat_types 3.3.4 [equatable json_annotation meta]
- flutter_chat_ui 1.5.8 [flutter diffutil_dart equatable flutter_chat_types flutter_link_previewer flutter_parsed_text intl meta photo_view url_launcher visibility_detector]
- flutter_custom_carousel_slider 1.2.0 [flutter]
- flutter_firebase_chat_core 1.5.4 [flutter cloud_firestore firebase_auth firebase_core flutter_chat_types meta]
- flutter_local_notifications 9.5.3+1 [clock flutter flutter_local_notifications_linux flutter_local_notifications_platform_interface timezone]
- flutter_localizations 0.0.0 [flutter intl characters clock collection material_color_utilities meta path vector_math]
- flutter_mailer 2.0.1 [flutter]
- geo 0.3.0 [meta]
- get 4.6.5 [flutter]
- get_storage 2.0.3 [flutter get path_provider]
- getwidget 3.0.1 [flutter]
- http 0.13.4 [async http_parser meta path]
- image_picker 0.8.5+3 [flutter image_picker_android image_picker_for_web image_picker_ios image_picker_platform_interface]
- intl 0.17.0 [clock path]
- loader_overlay 2.0.7 [flutter back_button_interceptor]
- location 4.4.0 [flutter location_platform_interface location_web]
- material_design_icons_flutter 5.0.6595 [flutter]
- mime 1.0.2
- open_file 3.2.1 [flutter ffi]
- path_provider 2.0.10 [flutter path_provider_android path_provider_ios path_provider_linux path_provider_macos path_provider_platform_interface path_provider_windows]
- qr_flutter 4.0.0 [flutter qr]
- rive 0.9.0 [collection flutter graphs http meta]
- stories_for_flutter 1.2.0 [flutter flutter_web_plugins]

transitive dependencies:
- amplify_analytics_pinpoint_android 0.6.0 [flutter]
- amplify_analytics_pinpoint_ios 0.6.0 [flutter]
- amplify_api_android 0.6.0 [flutter]
- amplify_api_ios 0.6.0 [amplify_core flutter]
- amplify_auth_cognito_android 0.6.0 [flutter]
- amplify_auth_cognito_ios 0.6.0 [amplify_core flutter]
- amplify_core 0.6.0 [aws_common collection flutter intl json_annotation meta plugin_platform_interface uuid]
- amplify_datastore_plugin_interface 0.6.0 [amplify_core collection flutter meta]
- amplify_flutter_android 0.6.0 [flutter]
- amplify_flutter_ios 0.6.0 [amplify_core flutter]
- amplify_storage_s3_android 0.6.0 [flutter]
- amplify_storage_s3_ios 0.6.0 [flutter]
- args 2.3.1
- async 2.8.2 [collection meta]
- aws_common 0.1.1 [async collection http meta stream_transform uuid]
- back_button_interceptor 6.0.0 [collection flutter]
- cached_network_image_platform_interface 1.0.0 [flutter flutter_cache_manager]
- cached_network_image_web 1.0.1 [flutter flutter_cache_manager cached_network_image_platform_interface]
- characters 1.2.0
- charcode 1.3.1
- clock 1.1.0
- cloud_firestore_platform_interface 5.5.7 [collection firebase_core flutter meta plugin_platform_interface]
- cloud_firestore_web 2.6.16 [cloud_firestore_platform_interface collection firebase_core firebase_core_web flutter flutter_web_plugins js]
- collection 1.16.0
- cross_file 0.3.3+1 [js meta]
- crypto 3.0.2 [typed_data]
- csslib 0.17.2 [source_span]
- dbus 0.7.4 [args ffi meta xml]
- diffutil_dart 3.0.0
- equatable 2.0.3 [collection meta]
- ffi 1.2.1
- file 6.1.2 [meta path]
- firebase_analytics_platform_interface 3.1.7 [firebase_core flutter meta plugin_platform_interface]
- firebase_analytics_web 0.4.0+14 [firebase_analytics_platform_interface firebase_core firebase_core_web flutter flutter_web_plugins js]
- firebase_auth_platform_interface 6.2.7 [firebase_core flutter meta plugin_platform_interface]
- firebase_auth_web 3.3.16 [firebase_auth_platform_interface firebase_core firebase_core_web flutter flutter_web_plugins http_parser intl js meta]
- firebase_core_platform_interface 4.4.0 [collection flutter meta plugin_platform_interface]
- firebase_core_web 1.6.4 [firebase_core_platform_interface flutter flutter_web_plugins js meta]
- firebase_messaging_platform_interface 3.5.1 [firebase_core flutter meta plugin_platform_interface]
- firebase_messaging_web 2.4.1 [firebase_core firebase_core_web firebase_messaging_platform_interface flutter flutter_web_plugins js meta]
- firebase_storage_platform_interface 4.1.7 [collection firebase_core flutter meta plugin_platform_interface]
- firebase_storage_web 3.2.16 [async firebase_core firebase_core_web firebase_storage_platform_interface flutter flutter_web_plugins http js meta]
- flutter_blurhash 0.7.0 [flutter]
- flutter_link_previewer 2.6.6 [flutter flutter_chat_types flutter_linkify html http linkify meta url_launcher]
- flutter_linkify 5.0.2 [flutter linkify]
- flutter_local_notifications_linux 0.4.2 [flutter flutter_local_notifications_platform_interface dbus path xdg_directories]
- flutter_local_notifications_platform_interface 5.0.0 [flutter plugin_platform_interface]
- flutter_parsed_text 2.2.1 [flutter]
- flutter_plugin_android_lifecycle 2.0.6 [flutter]
- flutter_staggered_grid_view 0.4.1 [flutter]
- flutter_web_plugins 0.0.0 [flutter js characters collection material_color_utilities meta vector_math]
- graphs 2.1.0 [collection]
- html 0.15.0 [csslib source_span]
- http_parser 4.0.1 [collection source_span string_scanner typed_data]
- image_picker_android 0.8.5 [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.5+5 [flutter image_picker_platform_interface]
- image_picker_platform_interface 2.5.0 [cross_file flutter http plugin_platform_interface]
- js 0.6.4
- json_annotation 4.5.0 [meta]
- linkify 4.1.0
- location_platform_interface 2.3.0 [flutter meta plugin_platform_interface]
- location_web 3.1.1 [flutter flutter_web_plugins http_parser js location_platform_interface meta]
- material_color_utilities 0.1.4
- meta 1.7.0
- octo_image 1.0.2 [flutter flutter_blurhash]
- path 1.8.1
- path_provider_android 2.0.14 [flutter path_provider_platform_interface]
- path_provider_ios 2.0.9 [flutter path_provider_platform_interface]
- path_provider_linux 2.1.7 [ffi flutter path path_provider_platform_interface xdg_directories]
- path_provider_macos 2.0.6 [flutter path_provider_platform_interface]
- path_provider_platform_interface 2.0.4 [flutter platform plugin_platform_interface]
- path_provider_windows 2.0.7 [ffi flutter path path_provider_platform_interface win32]
- pedantic 1.11.1
- petitparser 5.0.0 [meta]
- photo_view 0.13.0 [flutter]
- platform 3.1.0
- plugin_platform_interface 2.1.2 [meta]
- process 4.2.4 [file path platform]
- qr 2.1.0 [meta]
- rxdart 0.27.4
- sky_engine 0.0.99
- source_span 1.8.2 [collection path term_glyph]
- sqflite 2.0.2+1 [flutter sqflite_common path]
- sqflite_common 2.2.1+1 [synchronized path meta]
- stream_transform 2.0.0
- string_scanner 1.1.0 [charcode source_span]
- synchronized 3.0.0+2
- term_glyph 1.2.0
- timezone 0.8.0 [path]
- typed_data 1.3.1 [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.17 [flutter url_launcher_platform_interface]
- url_launcher_ios 6.0.17 [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.11 [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.2
- visibility_detector 0.2.2 [flutter]
- win32 2.6.1 [ffi]
- xdg_directories 0.2.0+1 [meta path process]
- xml 6.1.0 [collection meta petitparser]

Device

iPod Touch 7

OS

iOS 15.5

CLI Version

9.0.0

Additional Context

No response

@fjnoyp
Copy link
Contributor

fjnoyp commented Jun 24, 2022

Hi @MarlonJD thank you for posting your issue and providing a detailed explanation of what you did.

It appears you are trying to access the Department field on your Student object.

We do not load the fields (except id) for nested models. The Student object has a Department field. The Department field is a nested model so we do not load all fields of that object. In the error message you received:

Please validate that the containing model class was initialized properly with all requried fields being initialized. **This can happen when a nested model is returned but only its id field has been set**

Instead, you can use the Department object's id field to make another query for the full Department object.

Apologies this wasn't clear in the beginning. We'll look internally into how we might improve documentation regarding this behavior.

@fjnoyp fjnoyp added the GraphQL API Issues related to the API (GraphQL) Category label Jun 24, 2022
@MarlonJD
Copy link
Contributor Author

Yes i understand what you mean but this isn't the solution because there is no department id in response. That's the issue. We can add access nested object if it's first level on Amplify.API, so there is no nested object issue in here. İssue is in the graphql document that using for the query. İf there was departmentID it could be. And student already becoming readable and also nested. So i don't think it is nested object issue.

@ragingsquirrel3 ragingsquirrel3 added the bug Something is not working; the issue has reproducible steps and has been reproduced label Jun 27, 2022
@fjnoyp
Copy link
Contributor

fjnoyp commented Jun 29, 2022

Thanks for the clarification @MarlonJD we'll take a further look. The issue appears to be with nested model behavior and how to query for relationships of manyToMany. Further note, the connected models have different access permissions.

@fjnoyp fjnoyp added the datastore Issues related to the DataStore Category label Jun 29, 2022
@HuiSF
Copy link
Member

HuiSF commented Jun 29, 2022

Hello @MarlonJD

Thanks for reporting this issue and providing the details.

As we can we, there's no department in the graphql document, that's the issue. ModelQueries.list should create department as I need.

I did some testing, I can see the API GraphQL helper currently supporting only generating GraphQL document with 1 belongsTo associated model. In your use case, the generated many-to-many connection model MainDepartmentStudent has two belongsTo associated models Department and Student. This cause two issues:

  1. Using API GraphQL to save record MainDepartmentStudent will fail, as it cannot provide either departmentId studentId
  2. Using API GraphQL to query record MainDepartmentStudent will missing selection set of one of the nested models

As GraphQL helper rolled out prior to Amplify GraphQL Transformer v2, it looks like we have a function disparity now. I will mark this issue as a feature request to follow up.

As a workaround, please continually create GraphQL document manually. Sorry for the inconvenience.

Also -

After encountering a lot of problems about DataStore, I removed all DataStore

Sorry that you encounter issues with DataStore, would you mind to share them with us, and to see how can we help? (I searched but seems that you haven't reported any issues around DataStore yet)

@HuiSF HuiSF added feature-request A request for a new feature or an enhancement to an existing API or category. and removed datastore Issues related to the DataStore Category labels Jun 29, 2022
@HuiSF HuiSF changed the title Amplify.API.query does not work properly GraphQL helper doesn't support query and mutation on the many-to-many connection models Jun 29, 2022
@MarlonJD
Copy link
Contributor Author

MarlonJD commented Jul 7, 2022

Hello @MarlonJD

Thanks for reporting this issue and providing the details.

As we can we, there's no department in the graphql document, that's the issue. ModelQueries.list should create department as I need.

I did some testing, I can see the API GraphQL helper currently supporting only generating GraphQL document with 1 belongsTo associated model. In your use case, the generated many-to-many connection model MainDepartmentStudent has two belongsTo associated models Department and Student. This cause two issues:

  1. Using API GraphQL to save record MainDepartmentStudent will fail, as it cannot provide either departmentId studentId
  2. Using API GraphQL to query record MainDepartmentStudent will missing selection set of one of the nested models

As GraphQL helper rolled out prior to Amplify GraphQL Transformer v2, it looks like we have a function disparity now. I will mark this issue as a feature request to follow up.

As a workaround, please continually create GraphQL document manually. Sorry for the inconvenience.

Also -

After encountering a lot of problems about DataStore, I removed all DataStore

Sorry that you encounter issues with DataStore, would you mind to share them with us, and to see how can we help? (I searched but seems that you haven't reported any issues around DataStore yet)

Hey thanks for you detailed answer. First of all, we need to fix graphql request creation or something like fullRequest: true parameter and make query with all fields included nested models.
On datastore side, i've been issued about public permissions and 2 belongsTo or ManyToMany fields cannot be get or saved. Now after i created ManyToMany fields i cannot even datastore sync anymore, so i needed to remove all datastore from my code, #1736 here is my datastore issue about permission issue. There is so much problem which we cannot modify query on datastore.

@HuiSF
Copy link
Member

HuiSF commented Jul 7, 2022

Thanks for the follow up @MarlonJD I'll find some time to test the datastore issue you described.

@Jordan-Nelson Jordan-Nelson removed the feature-request A request for a new feature or an enhancement to an existing API or category. label Aug 24, 2022
@RikiZimbakov
Copy link

Hello @MarlonJD

Thanks for reporting this issue and providing the details.

As we can we, there's no department in the graphql document, that's the issue. ModelQueries.list should create department as I need.

I did some testing, I can see the API GraphQL helper currently supporting only generating GraphQL document with 1 belongsTo associated model. In your use case, the generated many-to-many connection model MainDepartmentStudent has two belongsTo associated models Department and Student. This cause two issues:

  1. Using API GraphQL to save record MainDepartmentStudent will fail, as it cannot provide either departmentId studentId
  2. Using API GraphQL to query record MainDepartmentStudent will missing selection set of one of the nested models

As GraphQL helper rolled out prior to Amplify GraphQL Transformer v2, it looks like we have a function disparity now. I will mark this issue as a feature request to follow up.

As a workaround, please continually create GraphQL document manually. Sorry for the inconvenience.

Also -

After encountering a lot of problems about DataStore, I removed all DataStore

Sorry that you encounter issues with DataStore, would you mind to share them with us, and to see how can we help? (I searched but seems that you haven't reported any issues around DataStore yet)

hey @HuiSF is that really true? I have a relationship that I believe has two @belongsto relationships yet I am able to save both succesfully:
type Session @model @auth( rules: [ { allow: public } { allow: owner } { allow: groups, groups: ["Admin"] } ] ) { id: ID! name: String numPeoplePresent: Int notes: String eIdReader: String weighTiming: String cows: [Cow] @manyToMany(relationName: "CowSession") proceduresID: ID procedures: Procedures @hasOne(fields: ["proceduresID"]) }
yet the only time I struggle is when I try to query the nested relationship. I know it works because I tested it on the graphQL console provided by amplify:
This works locally:
String graphQLDocument = '''query getSession(\$id: ID!) { $getSession(id: \$id) { numPeoplePresent notes name eIdReader id owner proceduresID updatedAt weighTiming } }''';
but this breaks:
String graphQLDocument = '''query getSession(\$id: ID!) { $getSession(id: \$id) { numPeoplePresent notes. name. eIdReader id owner proceduresID updatedAt weighTiming cows { items { cow { RfId } } } } }''';
any idea why?

@fjnoyp
Copy link
Contributor

fjnoyp commented Aug 27, 2022

Hi @RikiZimbakov can you please share the graphql schema you're using?

@MarlonJD
Copy link
Contributor Author

Hello @MarlonJD

Thanks for reporting this issue and providing the details.

As we can we, there's no department in the graphql document, that's the issue. ModelQueries.list should create department as I need.

I did some testing, I can see the API GraphQL helper currently supporting only generating GraphQL document with 1 belongsTo associated model. In your use case, the generated many-to-many connection model MainDepartmentStudent has two belongsTo associated models Department and Student. This cause two issues:

  1. Using API GraphQL to save record MainDepartmentStudent will fail, as it cannot provide either departmentId studentId
  2. Using API GraphQL to query record MainDepartmentStudent will missing selection set of one of the nested models

As GraphQL helper rolled out prior to Amplify GraphQL Transformer v2, it looks like we have a function disparity now. I will mark this issue as a feature request to follow up.

As a workaround, please continually create GraphQL document manually. Sorry for the inconvenience.

Also -

After encountering a lot of problems about DataStore, I removed all DataStore

Sorry that you encounter issues with DataStore, would you mind to share them with us, and to see how can we help? (I searched but seems that you haven't reported any issues around DataStore yet)

hey @HuiSF is that really true? I have a relationship that I believe has two @belongsto relationships yet I am able to save both succesfully:
type Session @model @auth( rules: [ { allow: public } { allow: owner } { allow: groups, groups: ["Admin"] } ] ) { id: ID! name: String numPeoplePresent: Int notes: String eIdReader: String weighTiming: String cows: [Cow] @manyToMany(relationName: "CowSession") proceduresID: ID procedures: Procedures @hasOne(fields: ["proceduresID"]) }
yet the only time I struggle is when I try to query the nested relationship. I know it works because I tested it on the graphQL console provided by amplify:
This works locally:
String graphQLDocument = '''query getSession(\$id: ID!) { $getSession(id: \$id) { numPeoplePresent notes name eIdReader id owner proceduresID updatedAt weighTiming } }''';
but this breaks:
String graphQLDocument = '''query getSession(\$id: ID!) { $getSession(id: \$id) { numPeoplePresent notes. name. eIdReader id owner proceduresID updatedAt weighTiming cows { items { cow { RfId } } } } }''';
any idea why?

Thank you for all detailed answer. Same scheme and i just cannot sync datastore. İt's giving me error, when anything has 2 belongsTo even it's manyToMany. I tried to modify add all belongsTo but Json is malformed before there. Maybe i have to modify android/iOS library instead of flutter. I'll try to dig in again

@ignitum-ryan
Copy link

ignitum-ryan commented Aug 31, 2022

@fjnoyp - Feel free to check out issue #2073 for a simple schema to replicate the issue. @haverchuck was kind enough to link my ticket to this issue.

As this has been a showstopper for my team and client, we dug further into the issue. I've found that inside of the graphql_request_factory.dart, when the request gets inside of buildInputVariableForMutations function, it attempts to gather the belongsTo fields by calling the getBelongsToFieldFromModelSchema function to get details around the field marked as belongsTo. The getBelongsToFieldFromModelSchema function:

ModelField? getBelongsToFieldFromModelSchema(ModelSchema modelSchema) {
  return _getRelatedFields(modelSchema).singleFields.firstWhereOrNull((entry) =>
      entry.association?.associationType == ModelAssociationEnum.BelongsTo);
}

As you can see, it calls firstWhereOrNull on the fields which will only select the FIRST field that has a belongsTo annotation. After the getBelongsToFieldFromModelSchema is called from the buildInputVariableForMutations function, the next step that is performed is the REMOVAL of any fields that is deemed to be readonly or purely relational fields:

// Remove any relational fields or readonly.
    Set<String> fieldsToRemove = schema.fields!.entries
        .where((entry) =>
            entry.value.association != null || entry.value.isReadOnly)
        .map((entry) => entry.key)
        .toSet();

What I'm not sure of, is how the fields are being selected for removal, since the entry.value.association SHOULD be ModelAssociationEnum.BelongsTo, instead of null causing the field to be skipped (or at least I would think).

This is where I believe the fields are being removed causing the issue related to this ticket. From what I can see, it doesn't appear multiple belongsTo on a single model was ever implemented.

Hopefully this information helps the team drive towards a hastened delivery of the solution. If this is duplicative information that the team was already aware of...don't mind me and Carry On! :)

@fjnoyp
Copy link
Contributor

fjnoyp commented Sep 1, 2022

Hi @ignitum-ryan thanks for your great insights here! Yes the firstWhereOrNull call is the root cause of this error. And yes you're right this was an oversight and not implemented. We are working on this now.

@MarlonJD
Copy link
Contributor Author

thanks to @fjnoyp. He fixed this issue. with #2087 and it's released on 0.6.9

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something is not working; the issue has reproducible steps and has been reproduced GraphQL API Issues related to the API (GraphQL) Category
Projects
None yet
Development

No branches or pull requests

7 participants