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

API QueryPredicate `Foo.keys.bar == nil` unexpected behavior

Open atierian opened this issue 2 years ago • 6 comments

Describe the bug

Given a schema:

type Post @model { 
  id: ID!
  title: String!
  status: PostStatus!
  rating: Int
  content: String
}

enum PostStatus {
  DRAFT
  PUBLISHED
}
let predicate = Post.keys.content == nil 
Amplify.DataStore.query(Post.self, where: predicate) { _ in ... }

will return Posts where content is nil.

let predicate = Post.keys.content == nil 
Amplify.API.query(request: .list(Post.self, where: predicate)) { _ in ... }

returns no results, despite Posts existing where content is nil.

This inconsistent behavior is confusing.

Steps To Reproduce

Steps to reproduce the behavior:
1. Setup project with API (and DataStore for comparison in behavior)
2. Use schema defined above or any schema with optional properties.
3. Create and save models with `nil` for that optional property.
4. Query with a `QueryPredicate` looking for models where that property is `nil`

Expected behavior

Querying with the predicatePost.keys.rating == nil with API should return Posts where the rating is nil / doesn't exist.

Amplify Framework Version

1.24.0

Amplify Categories

API

Dependency manager

Swift PM

Swift version

5.6

CLI version

8.1.0

Xcode version

13.3.1

Relevant log output

No response

Is this a regression?

No

Regression additional context

No response

Device

n/a

iOS Version

n/a

Specific to simulators

No response

Additional context

No response

atierian avatar May 11 '22 12:05 atierian

DataStore APIs interact with SQLite database directly so the predicate is translated to the SQL expression, while the predicate for APIPlugin APIs interact with the Transformer provisioned AppSync service. We can do two things next in the investigation on AppSync use cases:

  • Construct a request that adds a filter on null using AppSync console's Queries tab, is it possible? does it work as expected?
  • Write a unit test that generates the GraphQL documennt and variables based on the predicate let predicate = Post.keys.content == nil and see if that matches a valid request

lawmicha avatar May 16 '22 17:05 lawmicha

It appears as though AppSync supports this through attributeExists.

query MyQuery {
  listPosts(filter: {content: {attributeExists: false}}) {
    items {
      content
      createdAt
      id
      rating
      status
      title
      updatedAt
    }
  }
}

atierian avatar May 17 '22 16:05 atierian

Looks related: https://github.com/aws-amplify/amplify-js/issues/5179

svidgen avatar Jun 06 '22 18:06 svidgen

I believe the implementation lives in the translation from the prediate to GraphQL input, we need to map the equal operation to attributeExists : false when the value is null

lawmicha avatar Jun 08 '22 15:06 lawmicha

I'm not certain we should add a mapping. In JS a predicate builder is not used and the filter is written out manually. Since the filter on JS is the exact same that is sent over the GraphQL query I don't think it makes sense to add the mapping for JS. So it may be confusing when seemingly the same filter will have different functionality across different platforms.

let predicate = Post.keys.content == nil
Amplify.API.query(request: .list(Post.self, where: predicate))

// maps to =>
{ content: { attributeExists: false } } 
const filter = { content: { eq: null } };
await API.graphql({ query: listPosts, variables: { filter }});

// isn't modified
{ content: { eq: null } }

dpilch avatar Jul 07 '22 15:07 dpilch

We have discussed this issue some and the solution will likely be to update the VTL in AppSync. AppSync API VTL will modify { eq: null } filters to use { attributeExists: false }. This will provide identical functionality across platforms.

dpilch avatar Jul 13 '22 17:07 dpilch

Thanks @dpilch, where can this change be requested and tracked?

lawmicha avatar Oct 31 '22 19:10 lawmicha

I haven't created a ticket. I'll create one soon in amplify-category-api and link back here.

dpilch avatar Oct 31 '22 19:10 dpilch

Closing this issue, the fix will be in the api category and can be tracked here - https://github.com/aws-amplify/amplify-category-api/issues/943

royjit avatar Feb 24 '23 20:02 royjit