awslabs / aws-mobile-appsync-sdk-android

Android SDK for AWS AppSync.
https://docs.amplify.aws/sdk/api/graphql/q/platform/android/
Apache License 2.0
105 stars 58 forks source link

Does AWS AppSync SDK for Java/Android supports querying one to many GraphQL fields? #247

Closed Crisp3333 closed 2 years ago

Crisp3333 commented 4 years ago

State your question Does AWS AppSync SDK for Java/Android supports querying by connections support one to many? I notice that after adding one to many field to my schema shares, the generated Java files for the connection field only has a __typename and nextToken attributes/fields. Because of this I am wondering if AppSync Supports one to many connections for Java. I have tested the query in the AWS AppSync console and query on the Media table works fine for shares one to many connections, giving back the associated Share response. One to one connections works fine in my Android application as it is straight forward, however, figuring out how to get the results from shares is a puzzle.

Provide code snippets (if applicable) Below is the schema and the static class Shares that is within the AllMediaByAuthor class. As you can see, there is not much to go by with the one to many connection that is suppose to be controlled by Shares.

Schema

type Media @model
  @key(name: "getMedia", fields: ["media_name"], queryField: "getMediaByName")
  @key(name: "byAuthor", fields: ["author", "createdAt"], queryField: "allMediaByAuthor"){
    id: ID! 
    media_name: ID!
    author: ID!
    createdAt: AWSDateTime!
    shares: [Share] @connection(keyName: "byMedia", fields: ["media_name"])
}
type Share @model 
  @key(name: "byShared", fields: ["shared_to", "createdAt"])
  @key(name: "byMedia", fields: ["media_nameID"],  queryField: "allByMedia"){
    id: ID!
    shared_to: ID!
    createdAt: AWSDateTime!
    media_nameID: ID!
    smedia: SecretMedia @connection(name: "getMedia", fields: ["media_nameID"])
}

Generated GraphQL Java file for AllByMediaQuries -> Shares

public static class Shares {
    static final ResponseField[] $responseFields = {
      ResponseField.forString("__typename", "__typename", null, false, Collections.<ResponseField.Condition>emptyList()),
      ResponseField.forString("nextToken", "nextToken", null, true, Collections.<ResponseField.Condition>emptyList())
    };

    final @Nonnull String __typename;

    final @Nullable String nextToken;

    private volatile String $toString;

    private volatile int $hashCode;

    private volatile boolean $hashCodeMemoized;

    public Shares(@Nonnull String __typename, @Nullable String nextToken) {
      this.__typename = Utils.checkNotNull(__typename, "__typename == null");
      this.nextToken = nextToken;
    }

    public @Nonnull String __typename() {
      return this.__typename;
    }

    public @Nullable String nextToken() {
      return this.nextToken;
    }

    public ResponseFieldMarshaller marshaller() {
      return new ResponseFieldMarshaller() {
        @Override
        public void marshal(ResponseWriter writer) {
          writer.writeString($responseFields[0], __typename);
          writer.writeString($responseFields[1], nextToken);
        }
      };
    }

    @Override
    public String toString() {
      if ($toString == null) {
        $toString = "Shares{"
          + "__typename=" + __typename + ", "
          + "nextToken=" + nextToken
          + "}";
      }
      return $toString;
    }

    @Override
    public boolean equals(Object o) {
      if (o == this) {
        return true;
      }
      if (o instanceof Shares) {
        Shares that = (Shares) o;
        return this.__typename.equals(that.__typename)
         && ((this.nextToken == null) ? (that.nextToken == null) : this.nextToken.equals(that.nextToken));
      }
      return false;
    }

    @Override
    public int hashCode() {
      if (!$hashCodeMemoized) {
        int h = 1;
        h *= 1000003;
        h ^= __typename.hashCode();
        h *= 1000003;
        h ^= (nextToken == null) ? 0 : nextToken.hashCode();
        $hashCode = h;
        $hashCodeMemoized = true;
      }
      return $hashCode;
    }

    public static final class Mapper implements ResponseFieldMapper<Shares> {
      @Override
      public Shares map(ResponseReader reader) {
        final String __typename = reader.readString($responseFields[0]);
        final String nextToken = reader.readString($responseFields[1]);
        return new Shares(__typename, nextToken);
      }
    }
}

In other words, with the generated java classes I cannot achieve the following shares response which I can easily achieve in the AppSync console with the following query.

query mediaByAuthor {
    allMediaByAuthor(author: "9035e1c2-23e4-8589-0977-2055gc89fbfd") {
        items {
            id
            author
            media_name
            shares {
                items {
                    shared_to
                }
            }
        }
    }
}

Environment(please complete the following information): AppSync SDK Version: [2.8.3] Environment: Windows 10 IDE: Android Studio: 3.5.3 AWS: aws-cli: 1.16.43

Device Information (please complete the following information):

micstepper commented 4 years ago

Any progress on that? Dealing with the same question right now...

micstepper commented 4 years ago

I figured it out. The trick is to the set the right depth in the .graphqlconfig which is placed in the project root. I changed it from 2 to 3 which is likely the depth simple nested queries have.

maxDepth: 3

After that run "amplify codegen" and then build the project.

eeatonaws commented 2 years ago

Closing this issue since the original question was answered and this issue has been inactive for some time. Please create a new issue if you have additional questions.