amplify-codegen icon indicating copy to clipboard operation
amplify-codegen copied to clipboard

codegen models doesn't generate id for belongs-to connection

Open marlonmarcello opened this issue 3 years ago • 6 comments

Before opening, please confirm:

I have searched for duplicate or closed issues. I have read the guide for submitting bug reports. I have done my best to include a minimal, self-contained set of instructions for consistently reproducing the issue.

JavaScript Framework

React

Amplify APIs

GraphQL API, DataStore

Amplify Categories

api

Environment information

# Put output below this line

  System:
    OS: macOS 11.2.3
    CPU: (12) x64 Intel(R) Core(TM) i9-8950HK CPU @ 2.90GHz
    Memory: 452.77 MB / 32.00 GB
    Shell: 3.2.1 - /usr/local/bin/fish
  Binaries:
    Node: 12.18.3 - ~/n/bin/node
    Yarn: 1.22.10 - ~/npm/bin/yarn
    npm: 7.5.2 - ~/npm/bin/npm
  Browsers:
    Chrome: 89.0.4389.114
    Firefox: 87.0
    Safari: 14.0.3
  npmGlobalPackages:
    @aws-amplify/cli: 4.46.1
    @marlonmarcello/vite-plugin-pug: 1.0.3
    @wethegit/preact-stickerbook: 1.0.2
    @wethegit/sweet-potato-components: 0.0.3
    @wethegit/sweet-potato-cooker: 0.9.0
    @wethegit/sweet-potato-peeler: 0.3.8
    node-gyp: 7.1.2
    npm: 7.5.2
    twosg: 0.1.0
    tpci-tcgportal: 1.0.0
    yarn: 1.22.10

Describe the bug

By following the tutorial on the docs on how to create a belongs-to connection I came up with the following graphql.schema:

type Project @model {
  id: ID!
  name: String!
  emails: [Email] @connection(keyName: "byProject", fields: ["id"])
}

type Email @model @key(name: "byProject", fields: ["projectID"]) {
  id: ID!
  title: String!
  language: String!
  body: String!
  projectID: ID!
  project: Project @connection(fields: ["projectID"])
}

After that, I ran amplify codegen and amplify codegen models. The generated model was the following:

import { ModelInit, MutableModel, PersistentModelConstructor } from "@aws-amplify/datastore";

export declare class Project {
  readonly id: string;
  readonly name: string;
  readonly emails?: (Email | null)[];
  constructor(init: ModelInit<Project>);
  static copyOf(source: Project, mutator: (draft: MutableModel<Project>) => MutableModel<Project> | void): Project;
}

export declare class Email {
  readonly id: string;
  readonly title: string;
  readonly language: string;
  readonly body: string;
  readonly project?: Project;
  constructor(init: ModelInit<Email>);
  static copyOf(source: Email, mutator: (draft: MutableModel<Email>) => MutableModel<Email> | void): Email;
}

Issue 1:

Notice that the Email class is missing projectID.

Issue 2:

Because of Issue 1, when using typescript the following error is given:

const email = await DataStore.save(
      new Email({
        title: "Email title",
        language: "en",
        body: JSON.stringify(rows),
        projectID: id,
      })
    );

//   Argument of type '{ title: string; language: string; body: string; projectID: string; }' is not assignable to parameter of type 'ModelInit<Email>'.
// Object literal may only specify known properties, but 'projectID' does not exist in type 'ModelInit<Email>'. Did you mean to write 'project'?ts(2345)

Expected behavior

amplify codegen models should include the projectID field on the generated class.

Reproduction steps

  1. amplify init
  2. amplify add api
  3. Select GraphQL and go through base steps
  4. Use the schema provided above
  5. amplify codegen models

Notice the missing connection ID.

Code Snippet

// Put your code below this line.

Log output

// Put your logs below this line


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

marlonmarcello avatar Apr 08 '21 22:04 marlonmarcello

Hi @marlonmarcello. Thanks for reporting this. We will look into this soon and let you know.

phani-srikar avatar Apr 09 '21 17:04 phani-srikar

Hi @marlonmarcello, can you try to pass in the Project object to associate with the Email like,

const email = await DataStore.save(
      new Email({
        title: "Email title",
        language: "en",
        body: JSON.stringify(rows),
        project: project,
      })
    );

phani-srikar avatar Apr 23 '21 21:04 phani-srikar

Hi @marlonmarcello, can you try to pass in the Project object to associate with the Email like,

const email = await DataStore.save(
      new Email({
        title: "Email title",
        language: "en",
        body: JSON.stringify(rows),
        project: project,
      })
    );

This is not an issue with passing in data, it's an issue with generating the correct types.

We have the same exact issue, where not only certain properties are removed in the TS definitions, but also id is added when it doesn't exist.

Example:

type OrderAssignment
@model
@key(fields: [ "orderId", "designWorkflowStageId" ])
{
  businessId: ID!
  orderId: ID!
  order: Order @connection(fields: [ "orderId" ])
  designWorkflowStageId: ID!
  status: OrderAssignmentStatusType!
}

results in:

export declare class OrderAssignment {
  readonly id: string;
  readonly businessId: string;
  readonly order?: Order;
  readonly designWorkflowStageId: string;
  readonly status: OrderAssignmentStatusType | keyof typeof OrderAssignmentStatusType;
  constructor(init: ModelInit<OrderAssignment>);
  static copyOf(source: OrderAssignment, mutator: (draft: MutableModel<OrderAssignment>) => MutableModel<OrderAssignment> | void): OrderAssignment;
}

Two things to note:

  1. id shouldn't be there, it doesn't exist
  2. orderId is omitted, but should be there

TheDutchCoder avatar Jun 10 '21 21:06 TheDutchCoder

Experience the same problem. In my use case I'm trying to selectively sync DataStore against the "disappeared" id field which clearly won't work unless the field exists locally. Trying to find a work around but this seems like a bug. Did you find any solutions?

harrisontaee avatar Feb 21 '22 13:02 harrisontaee

Hi, I think this is worth to mention there is a workaround. Do not use amplify codegen - use Amplify Studio instead. Remove your relations from your datamodel and amplify push, next configure your datamodel relations using the Amplify Studio web console and then update the datamodel from within the Amplify Studio. After the update completes execute amplify pull locally. Updated schema will be downloaded along with proper typescript model (having the missing ID's) - allowing you to reference and query your data 😃

szymon-lab avatar Jun 08 '22 10:06 szymon-lab

I'm experiencing the same issue with Swift models. Here the point in which those fields are removed https://github.com/aws-amplify/amplify-codegen/blob/main/packages/appsync-modelgen-plugin/src/visitors/appsync-visitor.ts#L532 but sadly I don't understand the reason behind this choice.

dral3x avatar Jul 15 '22 10:07 dral3x