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

Incorrect codegen error - DataStore does not support 1 to 1 connection with both sides of connection as optional field

Open anthonymoretti opened this issue 5 years ago • 20 comments

Describe the bug Codegen produces the following error even though both sides of the connection are actually non-optional: "DataStore does not support 1 to 1 connection with both sides of connection as optional field"

To Reproduce

  1. Create the schema below
  2. Add api, push, then run amplify codegen models
  3. See error

Expected behavior Generates the code

Environment:

  • Amplify Framework Version: 4.21.0
  • Dependency Manager: Cocoapods
  • Swift Version : 5.0

Device Information:

  • Device: Simulator
  • iOS Version: iOS 13.5

Additional context Schema:

type PhoneCall @model {
  id: ID!
  caller: Person! @connection(name: "PhoneCallCaller")
  callee: Person! @connection(name: "PhoneCallCallee")
  transcript: Transcript! @connection(name: "PhoneCallTranscript")
}

type Person @model {
  id: ID!
  name: String!
  callerOf: [PhoneCall!] @connection(name: "PhoneCallCaller")
  calleeOf: [PhoneCall!] @connection(name: "PhoneCallCallee")
}

type Transcript @model {
  id: ID!
  text: String!
  language: String
  phoneCall: PhoneCall! @connection(name: "PhoneCallTranscript")
}

anthonymoretti avatar Jun 01 '20 16:06 anthonymoretti

I'm having the same issue on amplify-android library. Maybe this is related to amplify-cli...

watanabethais avatar Jun 04 '20 19:06 watanabethais

+1

wooklym avatar Jun 05 '20 12:06 wooklym

type TestModel @model {
  id: ID!
  name: String
}

type TestModel2 @model {
  id: ID!
  test1: TestModel! @connection
}

this works well, but

type TestModel @model {
  id: ID!
  name: String
}

type TestModel2 @model {
  id: ID!
  test1Id: ID!
  test1: TestModel! @connection(fields: ["test1Id"])
}

this causes error: DataStore does not support 1 to 1 connection with both sides of connection as optional field

But,

type TestModel @model {
  id: ID!
  name: String
}

type TestModel2 @model {
  id: ID!
  test1Id: ID!
  test1: TestModel @connection(fields: ["test1Id"]) # `!` removed
}

This works!!! 🙃 @anthonymoretti @watanabethais

wooklym avatar Jun 05 '20 12:06 wooklym

Thanks guys. I've been told it's being looked into, has to do with which side of the relationship should be the "owner". I've made a feature request that possibly addresses this and other issues RFC - Simplified @connection directive

anthonymoretti avatar Jun 05 '20 20:06 anthonymoretti

I just ran into this, and can confirm paradoxically removing the ! from the connected model (TestModel in the example above) avoids the error as well for me.

The downside is now the generated TypeScript binding has the field as a nullable field when I want it non-nullable, especially as the key (test1Id in the example above) is defined as non-nullable, so it doesn't make sense that the connected field is nullable.

I wonder if there's any update to this bug?

danrivett avatar Sep 17 '20 02:09 danrivett

Isn't the bug here?: https://github.com/aws-amplify/amplify-cli/blob/master/packages/amplify-codegen-appsync-model-plugin/src/utils/process-connections.ts#L201

There are only 3 branches in the if statement checking if both sides of the connection are null or not:

  • if (!field.isNullable && otherSideField.isNullable)
  • else if (field.isNullable && !otherSideField.isNullable)
  • else

But there are 4 separate possibilities, and 2 of them are being swallowed up by the last else clause. It looks like there should be a separate clause checking that both are not null and not throwing an error in that case.

I confirmed by monkey patch that if there was this 4th branch added (!field.isNullable && !otherSideField.isNullable), then it would fall into it and not error out for the schema @wooklym provided above.

@drochetti is the above known, and any idea if this will be fixed any time soon if so?

danrivett avatar Sep 17 '20 02:09 danrivett

This issue is stale because it has been open 14 days with no activity. Please, provide an update or this will be automatically closed in 7 days.

github-actions[bot] avatar Oct 13 '20 00:10 github-actions[bot]

This is still a relevant issue and needs to be triaged and prioritized.

drochetti avatar Oct 13 '20 17:10 drochetti

I'm using a translation tool, so it may be confusing I added a child element connection to the parent element and verified that it works In @wooklym, amplify codegen models does not output an error, but DataStore.query cannot get it as Connection.

type TestModel @model {
  id: ID!
  name: String
  children: [TestModel2] @connection(fields: ["id"])
}

type TestModel2 @model {
  id: ID!
  test1Id: ID!
  test1: TestModel! @connection(fields: ["test1Id"])
}

yu-chan-901 avatar Oct 21 '20 19:10 yu-chan-901

@danrivett did any downstream issues come up from your monkey patch?

kldeb avatar Dec 01 '20 16:12 kldeb

@kldeb we removed the connection for now instead of money-patching; we monkey-patched just to prove out the theory that the if-block is missing a clause and it would fall into that missing clause if added instead of erroring.

@drochetti I guess everyone is busy, but been 6 months since this ticket was opened and the issue looks relatively simple to triage if someone is available to.

danrivett avatar Dec 01 '20 19:12 danrivett

If this is an easy fix maybe i'll try my luck with a PR

kldeb avatar Dec 02 '20 19:12 kldeb

@danrivett how did you apply the monkey patch?

micstepper avatar Dec 02 '20 22:12 micstepper

For the record this isn't just a iOS issue. Hit it today trying to get the new Admin UI working on an existing schema, this requires DataStore to be configurated which throws this error when I push :(

PeteDuncanson avatar Dec 07 '20 12:12 PeteDuncanson

@kldeb we removed the connection for now instead of money-patching; we monkey-patched just to prove out the theory that the if-block is missing a clause and it would fall into that missing clause if added instead of erroring.

@drochetti I guess everyone is busy, but been 6 months since this ticket was opened and the issue looks relatively simple to triage if someone is available to.

I mentioned it earlier in https://github.com/aws-amplify/amplify-ios/issues/505#issuecomment-639804984 - I was told it's being looked into and has to do with determining which side of the relationship should be the "owner". If the missing else clause is added I think you still have the problem of determining the "owner" and thus have a problem setting deletion rules. I've made a feature request that might solve this and other problems: RFC - Simplified @connection directive

anthonymoretti avatar Dec 07 '20 20:12 anthonymoretti

Any updates?

micstepper avatar Apr 08 '21 23:04 micstepper

Thanks for taking the time to comment. We’re working on ways to make DataStore relationships simpler. We’ll update this issue as soon as we have more information.

diegocstn avatar Jun 18 '21 16:06 diegocstn

What's the rationale for not generating models when both sides of a connection are optional?

htc007 avatar Sep 09 '21 16:09 htc007

Any update on this yet?

harishanth avatar Nov 23 '21 05:11 harishanth

Any update on this?

julien-tamade avatar May 04 '22 15:05 julien-tamade

With the launch of TransformerV2 directives (hasOne/belongsTo/hasMany/etc), I started off by translating the schema over to

type PhoneCall @model {
  id: ID!
  callerId: ID! @index(name: "byCaller")
  calleeId: ID! @index(name: "byCallee")
  caller: Person! @belongsTo(fields: ["callerId"])
  callee: Person! @belongsTo(fields: ["calleeId"])
  transcript: Transcript @hasOne
}

type Person @model {
  id: ID!
  name: String!
  callerOf: [PhoneCall!] @hasMany(indexName: "byCaller")
  calleeOf: [PhoneCall!] @hasMany(indexName: "byCallee")
}

type Transcript @model {
  id: ID!
  text: String!
  language: String
  phoneCall: PhoneCall @belongsTo
}

I kept both 1:1 Transcript to PhoneCall as optional, but now that I reviewed the conversation here, I believe one side can made required. Let's take, for example, the calling code when using DataStore (Swift). We have to create individual instances of PhoneCall and Transcript, so at least one of the sides have to be optional to allow the FK to be set later:

// Create both instances
var phoneCall = PhoneCall(caller: savedCaller, callee: savedCallee)
let transcript = Transcript(text: "text", phoneCall: phoneCall)

// Set the PhoneCall's FK to the Transcript, ie.
phoneCall.setTranscript(transcript)
phoneCall.phoneCallTranscriptId = transcript.id

// Save both models
try await DataStore.save(phoneCall)
try await DataStore.save(transcript)

In this calling pattern, I think the Transcript's connected model to PhoneCall can be made required. This use case is enabled by the latest codegen and library changes we are currently working on in https://github.com/aws-amplify/amplify-swift/pull/2583

lawmicha avatar Dec 30 '22 23:12 lawmicha

The Lazy Loading feature was released in version 2.4.0. This should address this issue.

This support requires the lazy loading feature flag. Please use the latest version of the amplify CLI and review or make updates to cli.json (in the amplify folder) to ensure you have the following settings:

"transformerversion":2 "respectprimarykeyattributesonconnectionfield": true "generatemodelsforlazyloadandcustomselectionset": true

Please open a new issue if this release does not resolve the problem.

ameter avatar Feb 17 '23 17:02 ameter

This is yet another bug that makes me regret every relying on Amplify.

I can't go to V2 because of https://github.com/aws-amplify/amplify-category-api/issues/110

My schema worked perfectly, but not I am getting this error and it is stopping releases.

spc16670 avatar Nov 17 '23 19:11 spc16670

Hey @spc16670, this issue was closed since we released the changes in 2.4.0 of the library. It was related to representing 1:1 relationships in the swift codegenerated model types. At a glance, I don't see the correlation between the two issues, the linked issue sounds like it's about auth rules with groupsField and groupClaim not working. If i'm wrong here, please open a new issue in the library repo with more details, and reference the related issue you're referring to https://github.com/aws-amplify/amplify-swift/issues/new?assignees=&labels=&projects=&template=bug_report.yaml

lawmicha avatar Nov 17 '23 20:11 lawmicha