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

_version field not getting added when using amplify pull #3770

Open
amruth-movano opened this issue Jul 3, 2024 · 18 comments
Open

_version field not getting added when using amplify pull #3770

amruth-movano opened this issue Jul 3, 2024 · 18 comments
Labels
api Issues related to the API category question General question

Comments

@amruth-movano
Copy link

amruth-movano commented Jul 3, 2024

Describe the bug

I want to update the model using Amplify.API.Query(request.update),
But when i update a model I am getting error -

GraphQLResponseError: GraphQL service returned a successful response containing errors: [Amplify.GraphQLError(message: "Conflict resolver rejects mutation.", locations: Optional([Amplify.GraphQLError.Location(line: 2, column: 3)]), path: Optional([Amplify.JSONValue.string("updateExerciseSession2")]), extensions: Optional(["errorType": Amplify.JSONValue.string("ConflictUnhandled"), "errorInfo": Amplify.JSONValue.null, "data": Amplify.JSONValue.object(["createdAt": Amplify.JSONValue.string("2024-07-03T15:24:01.148Z"),"owner": Amplify.JSONValue.null, "__typename": Amplify.JSONValue.string("ExerciseSession2"), "updatedAt": Amplify.JSONValue.string("2024-07-03T15:24:01.148Z"), "user_id": Amplify.JSONValue.string("*******"), "start_time": Amplify.JSONValue.string("2024-07-03T15:23:59.055Z")])]))]

I think it is because we are not sending version but we don't have _version field in generated models.

Our model is like below -

extension ExerciseSession2 {
// MARK: - CodingKeys
enum CodingKeys: String, ModelKey {
case user_id
case start_time
case owner
case createdAt
case updatedAt
}

static let keys = CodingKeys.self
// MARK: - ModelSchema

static let schema = defineSchema { model in
let exerciseSession2 = ExerciseSession2.keys

model.authRules = [
  rule(allow: .owner, ownerField: "owner", identityClaim: "cognito:username", provider: .userPools, operations: [.create, .update, .delete, .read])
]

model.listPluralName = "ExerciseSession2s"
model.syncPluralName = "ExerciseSession2s"

model.attributes(
  .index(fields: ["user_id", "start_time"], name: nil),
  .primaryKey(fields: [exerciseSession2.user_id, exerciseSession2.start_time])
)

model.fields(
  .field(exerciseSession2.user_id, is: .required, ofType: .string),
  .field(exerciseSession2.start_time, is: .required, ofType: .dateTime),
  .field(exerciseSession2.owner, is: .optional, ofType: .string),
  .field(exerciseSession2.createdAt, is: .optional, isReadOnly: true, ofType: .dateTime),
  .field(exerciseSession2.updatedAt, is: .optional, isReadOnly: true, ofType: .dateTime)
)
}

}

Steps To Reproduce

Create a model using create query
Try to update model using query

Expected behavior

We should get version in generated schema

Amplify Framework Version

2.33.3

Amplify Categories

API, DataStore

Dependency manager

Swift PM

Swift version

5.9.2

CLI version

12.1.1

Xcode version

15.0

Relevant log output

No response

Is this a regression?

Yes

Regression additional context

No response

Platforms

iOS

OS Version

iOS 17.0

Device

iPhone 15 Plus

Specific to simulators

No response

Additional context

No response

@5d 5d added api Issues related to the API category question General question labels Jul 3, 2024
@5d
Copy link
Member

5d commented Jul 3, 2024

Hi @amruth-movano ,

The _version model field is a reserved field for the AWS AppSync service. Any attempt to modify the _version field will result in a Bad Request response.

To update a model using the Amplify API plugin, you should use the .mutate API rather than the .query API.

@amruth-movano
Copy link
Author

Yes @5d
But I am facing issue to get the current version on server.
As In my schema version field is not generated, can you guide me how can I access to version field from fetch fro the particular data from db

@5d
Copy link
Member

5d commented Jul 4, 2024

Hi @amruth-movano ,

The _version field is part of the metadata managed by the Amplify library, and there is no public API available to access it. I am interested in understanding the requirements for accessing the _version field.

@amruth-movano
Copy link
Author

Actually we want using Amplify API query to create & update the rows. So one row for exercise table, the data can be updated multiple times. So to update the particular row for n number of times we need the version to pass to updatemutation query.

So do we have any idea how can we get the version for a row in dynamodb to update it @5d ?

@5d
Copy link
Member

5d commented Jul 4, 2024

Hi @amruth-movano ,

Thank you for the information.

In the Amplify library, the _version field is managed by the Datastore plugin through real-time updates from AppSync.

However, if you use the API plugin, you will need to handle this metadata manually. Rather than utilizing the convenient APIs we designed for quickly creating a GraphQLRequest, you should use the standard GraphQLRequest APIs.

For example, in your case of updating a model instance, you should:

  1. Query the latest version first.
  2. Use that information to make an update mutation request.
  3. Maintain the version information afterwards.
var version: Int?
let blogOnServer = try await Amplify.API.query(
    request: .query(modelName: Blog.modelName, byId: blogId)
)
version = try? blogOnServer.map(\.?.syncMetadata.version).get()
print("version on server: ", version ?? "N/A")
let newBlog = Blog(id: blogId, name: UUID().uuidString)
let updateResult = try await Amplify.API.mutate(
    request: .updateMutation(of: newBlog, version: version)
)
version = try? updateResult.map(\.syncMetadata.version).get()
print("new version: ", version ?? "N/A")

@amruth-movano
Copy link
Author

Hi @5d
I am trying the query in below format -

let dataQ = try await Amplify.API.query(request: .query(modelName: ActivityIntensity.modelName, byId: "7BBD68F6-64E2-4507-A792-9E6BCC64FFDE"))
let version2 = try? dataQ.map(.?.syncMetadata.version).get()
print("version on server :(dataQ): ", version2 ?? "N/A")

Received output =>
version on server :failure(GraphQLResponseError<Optional<MutationSync>>: GraphQL service returned a successful response containing errors: [Amplify.GraphQLError(message: "Validation error of type MissingFieldArgument: Missing field argument user_id @ 'getActivityIntensity'", locations: Optional([Amplify.GraphQLError.Location(line: 2, column: 3)]), path: nil, extensions: nil), Amplify.GraphQLError(message: "Validation error of type MissingFieldArgument: Missing field argument data_timestamp @ 'getActivityIntensity'", locations: Optional([Amplify.GraphQLError.Location(line: 2, column: 3)]), path: nil, extensions: nil), Amplify.GraphQLError(message: "Validation error of type UnknownArgument: Unknown field argument id @ 'getActivityIntensity'", locations: Optional([Amplify.GraphQLError.Location(line: 2, column: 24)]), path: nil, extensions: nil)] 






So now main thing is for some tables we don’t have ID primary field in table instead of that we have start_time/data_timestamp field which is primary key. 
So how should we use start_time/data_timestamp to fetch that element with version. Also our backend needs to pass the userId as well with the query.

And one more question, can we fetch version in list query? Ex; Amplify.API.query(request: .list)

@amruth-movano
Copy link
Author

@5d Can you please guide us in this scenario?

@harsh62
Copy link
Member

harsh62 commented Jul 11, 2024

@amruth-movano I will take a look at your query and try to get an answer for your question. Appreciate your patience on this.

@amruth-movano
Copy link
Author

@harsh62 Yes please take a look and let us know the solution, as it's a blocker for us.

@harsh62
Copy link
Member

harsh62 commented Jul 11, 2024

Starting off with the last question first:

can we fetch version in list query? Ex; Amplify.API.query(request: .list)

Yes, you should be able to do it.

So how should we use start_time/data_timestamp to fetch that element with version

Your start_time becomes the id

let version2 = try? dataQ.map(.?.syncMetadata.version).get()

You are missing a backslash \ when accessing version in the map.

Also our backend needs to pass the userId as well with the query.


You should be able to use predicates to query data. https://docs.amplify.aws/gen1/swift/build-a-backend/graphqlapi/query-data/

Hope these answers your question.

@amruth-movano
Copy link
Author

Hi @harsh62
I am not able to use start_time as Id, if I use that I am getting error for missing userID field

let dataQuery = try await Amplify.API.query(request: .get(ExerciseSession2.self, byId: startTime.temporalDateTime.iso8601String))

Error -
GraphQLResponseError<Optional>: GraphQL service returned a successful response containing errors: [Amplify.GraphQLError(message: "Validation error of type MissingFieldArgument: Missing field argument user_id @ 'getExerciseSession2'", locations: Optional([Amplify.GraphQLError.Location(line: 2, column: 3)]), path: nil, extensions: nil), Amplify.GraphQLError(message: "Validation error of type MissingFieldArgument: Missing field argument start_time @ 'getExerciseSession2'", locations: Optional([Amplify.GraphQLError.Location(line: 2, column: 3)]), path: nil, extensions: nil), Amplify.GraphQLError(message: "Validation error of type UnknownArgument: Unknown field argument id @ 'getExerciseSession2'", locations: Optional([Amplify.GraphQLError.Location(line: 2, column: 23)]), path: nil, extensions: nil)]

And for list query getting error there is no field called syncMetadata

@harsh62
Copy link
Member

harsh62 commented Jul 12, 2024

Are you able to use a predicate to pass both the fields?

You should be able to use predicates to query data. https://docs.amplify.aws/gen1/swift/build-a-backend/graphqlapi/query-data/

@amruth-movano
Copy link
Author

@harsh62 if we pass through predicate also, it is giving same error as our backend needs userID directly & not from the predicate, so we are ovverriding it directly

@amruth-movano
Copy link
Author

@harsh62 Can you give me a example to fetch version from list query? This will be easy for me if you can guide me in list query

@harsh62
Copy link
Member

harsh62 commented Jul 16, 2024

@amruth-movano I will work on drafting a query and provide an update soon.

@amruth-movano
Copy link
Author

@harsh62 Yes, please. We will be waiting for your response

@amruth-movano
Copy link
Author

@harsh62 Is there any update?

@5d
Copy link
Member

5d commented Jul 29, 2024

Hi @amruth-movano ,

When working with a model schema with composite key, you have two options to access the composite identifier.

Firstly, you could utilize the computed property .identifier on the model instance. For example, exerciseSession.identifier.

Alternatively, you can build a composite key by specifying the values of the individual properties that make up the composite key, which might look something like this [ref]:

try await Amplify.API.query(
    request: .get(
        ActivityIntensity.modelName,
        byIdentifier: .identifier(<partitionKeyName>: <partitionKeyValue>, <sortKeyName>: <SortKeyValue>)
    )
)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api Issues related to the API category question General question
Projects
None yet
Development

No branches or pull requests

3 participants