aws-amplify / aws-amplify/amplify-codegen

[iOS & Swift] UUID strings are in All caps/uppercase, causing issues on DynamoDB

Open
#470 0 comments 0 reactions 0 assignees View on GitHub
bug p2 transferred
Dominant language
TypeScript
Stars
59
Forks
64
PR merge metrics
No merged PRs in 30d

Description

### Before opening, please confirm:

- [X] I have installed the latest version of the Amplify CLI (see above), and confirmed that the issue still persists.
- [X] I have [searched for duplicate or closed issues](https://github.com/aws-amplify/amplify-cli/issues?q=is%3Aissue+).
- [X] I have read the guide for [submitting bug reports](https://github.com/aws-amplify/amplify-cli/blob/dev/CONTRIBUTING.md#bug-reports).
- [X] I have done my best to include a minimal, self-contained set of instructions for consistently reproducing the issue.
- [X] I have removed any sensitive information from my code snippets and submission.

### How did you install the Amplify CLI?

npm

### If applicable, what version of Node.js are you using?

17.4.0

### Amplify CLI Version

9.1.0

### What operating system are you using?

Mac

### Did you make any manual changes to the cloud resources managed by Amplify? Please describe the changes made.

No manual changes made

### Amplify Categories

auth, storage, api

### Amplify Commands

codegen, pull

### Describe the bug

On iOS (Swift), `amplify codegen models` generates models in swift. The issue (only on iOS, Swift) is as follows:

1. The generated models use `UUID().uuidString` for fields defined as `ID` in the schema, and stores them as `String` type because DynamoDB expects a `String` type as key. In Swift, `UUID().uuidString` results in an **all caps/uppercase** string to be generated, which is an Apple standard.
2. The issue is that having the same UUID in uppercase vs lowercase causes two different keys to be identified by **DynamoDB**. This is especially a problem for us because we have multiple scripts (for media processing and storage) running in background that expect all lowercase strings. Since DynamoDB stores UUID strings instead of actual UUIDs for keys, we cannot rely on the case-insensitivity of UUIDs.
3. What we want is to have the IDs of every record generated on Swift (iOS) to be strictly in lowercase. Maybe using `UUID().uuidString.lowercased()` to generate `String` for the `ID` field of each model.

### The Swift struct for Post model

```Swift
public struct Post: Model {
public let id: String
public var name: String
public var random_id: String?
public var blog: Blog?
public var createdAt: Temporal.DateTime?
public var updatedAt: Temporal.DateTime?

public init(id: String = UUID().uuidString,
name: String,
random_id: String? = nil,
blog: Blog? = nil) {
self.init(id: id,
name: name,
random_id: random_id,
blog: blog,
createdAt: nil,
updatedAt: nil)
}
internal init(id: String = UUID().uuidString,
name: String,
random_id: String? = nil,
blog: Blog? = nil,
createdAt: Temporal.DateTime? = nil,
updatedAt: Temporal.DateTime? = nil) {
self.id = id
self.name = name
self.random_id = random_id
self.blog = blog
self.createdAt = createdAt
self.updatedAt = updatedAt
}
}
```

I also tried using an extension to address this, but as you probably know, I have to create a new stored property to store the lowercase version of the uuidString and then use the newly defined variable. My implementation is as follows:

```Swift
extension UUID {
var uuidStringLowercased: String {
get {
return self.uuidString.lowercased()
}
}
}
```

### Expected behavior

The ID should be a lowercased String in the UUID format. Since Apple gives an ALL CAPS string, I want a way to have it converted to lowercased string to create objects from the codegenerated models.

Something as simple as having `id: String = UUID().uuidString.lowercased()` in the constructors would do the trick while also respecting the best practices of using UUIDs, i.e., to use them in a lowercased form.

If the above mentioned method is troubling to implement, please explain to me why that's the case and how I can get around the issue.

I am open to using other ways to have either UUID().uuidString inherently give a lowercased string, if possible, OR have a script run to convert the line `UUID().uuidString` to `UUID().uuidString.lowercased()` in every single model. Currently, I have 18 files that each contain this line in 2 places, which makes it stupid to change every single file every time I do an `amplify pull`.

I want to avoid using uppercase strings at all if possible because it is prone to causing a system breakdown in case the same string exists as 2 different ids because if it being in different alphabetical cases.

### Reproduction steps

1. Set up using any generic graphQL schema which has **ID!** field.
2. Do an `amplify codegen models`
3. Go to the model and see the constructor first line to see what part of code I am talking about
4. Create a new object and push it to DynamoDB via AppSync.
5. Now use the newly created object's string -> convert it to lowercase -> use the lowercase string to create another object -> push it to dynamoDB via AppSync
6. Notice how the same uuidString causes 2 different entries to be created on DynamoDB.

### GraphQL schema(s)

```graphql
# Put schemas below this line
type Blog @model @auth(rules: [{allow: public}]) {
id: ID!
name: String!
customs: [MyCustomModel]
notes: [String]
post: [Post] @hasMany(indexName: "postByBlog", fields: ["id"])
}

type Post @model @auth(rules: [{allow: public}]) {
id: ID!
name: String!
blog_id: ID @index(name: "postByBlog")
random_id: String @index(name: "byRandom")
blog: Blog @belongsTo(fields: ["blog_id"])
}

type MyCustomModel {
id: ID!
name: String!
desc: String
children: [MyNestedModel]
}

type MyNestedModel {
id: ID!
nestedName: String!
notes: [String]
}

```

### Project Identifier

_No response_

### Log output

```
# Put your logs below this line

```

### Additional information

1. Workaround: Add `.lowercased()` statement after the `UUID().uuidString` declaration to convert to lowercase.
2. Run a script to change all models to modify that particular line
3. Create an extension of UUID and define a new stored property to store lowercase version of uuidString and use that in models, which would again require changing every single model.swift file.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.