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

Support enums in code generated models #111

Closed
palpatim opened this issue Nov 19, 2019 · 5 comments
Closed

Support enums in code generated models #111

palpatim opened this issue Nov 19, 2019 · 5 comments
Assignees
Labels
datastore Issues related to the DataStore category

Comments

@palpatim
Copy link
Member

Given the following type:

public struct MutationEvent: Model {
    public enum MutationType: String, Codable {
        case create
        case update
        case delete
    }

    public let id: Identifier
    public let modelName: String
    public let json: String
    public let mutationType: MutationType
    public let createdAt: Date

    public init(id: Identifier = UUID().uuidString,
                modelName: String,
                data: String,
                mutationType: MutationType,
                createdAt: Date = Date()) {
        self.id = id
        self.modelName = modelName
        self.json = data
        self.mutationType = mutationType
        self.createdAt = createdAt
    }
}

extension MutationEvent {
    // MARK: - CodingKeys

    public enum CodingKeys: String, ModelKey {
        case id
        case modelName
        case json
        case mutationType
        case createdAt
    }

    public static let keys = CodingKeys.self

    // MARK: - ModelSchema

    public static let schema = defineSchema { definition in
        let mutation = MutationEvent.keys

        definition.attributes(.isSyncable, .isSystem)

        definition.fields(
            .id(),
            .field(mutation.modelName, is: .required, ofType: .string),
            .field(mutation.json, is: .required, ofType: .string),
            .field(mutation.mutationType,
                   is: .required,
                   ofType: .enum(type: MutationType.self)),
            .field(mutation.createdAt, is: .required, ofType: .dateTime)
        )
    }
}

Registering the type as a model fails:

2019-11-18 16:19:40.219199-0800 AmplifyTestApp[21061:3952734] Fatal error: Model with name MutationType could not be found.: file /Users/schmelte/src/github-repos/amplify-ios/Amplify/Categories/DataStore/Model/ModelSchema+Definition.swift, line 70

It looks like it's not going to be as simple as just detecting the type in ModelField.typeDefinition, since the incoming type on the field is MutationType, and I don't see any path to find that it's actually an enum.

@palpatim palpatim added the datastore Issues related to the DataStore category label Nov 19, 2019
palpatim added a commit that referenced this issue Nov 19, 2019
- Fix bug where MutationEvent is marked syncable
- Setting MutationEvent.mutationType to be a String pending resolution of #111
- Make StorageEngine rely on a SyncEngineFactory in the injection constructor,
  and make syncEngine a lazily initialized property since there's a circular
  reference there.
- Weakened circular references to avoid retain cycles
@drochetti
Copy link
Contributor

drochetti commented Nov 19, 2019

Quick update on this:

So far the best I could come up with was to introduce a new contract to enums, something like PersistableEnum:

enum PostStatus: String, PersistableEnum {
  case draft
  case published
}

protocol PersistableEnum {
    var enumValue: String { get }
}

extension PersistableEnum 
where Self: RawRepresentable, Self.RawValue == String {
    var enumValue: String { return rawValue }
}

if let value = PostStatus.draft as? PersistableEnum {
  print(value.enumValue)
}

that way we can always check Any for PersistableEnum conformance and call enumValue. Not 100% clear yet how I'm going to de-serialize a String back to PersistableEnum.

I tried using Swift built-in types only, like RawRepresentable<String>, StringRepresentable and CustomStringConvertible with no luck

@rodrigoelp
Copy link

Hello, trying to understand this issue (as I think I have just hit it and I created a ticket that might be duplicate of this one with a different symptom)

Assuming my schema is:

enum Gender {
  male,
  female,
}

type Person @model 
  (mutations: { create: "newPerson", update: "updPerson", delete: "delPerson"  } ) {
  id: ID!
  name: String!
  gender: Gender!
}

The generated enum is not supported at the time of applying a mutation, right?

I created a ticket indicating the enum doesn't conform with the Codable protocol but reading this ticket (and based on my current code that is crashing Fatal error: Model with name Gender could not be found.: file) I assume it is the same root cause.

If that is the case, I can close the #246 ticket as duplicate.

@palpatim
Copy link
Member Author

palpatim commented Dec 11, 2019

There are actually 2 separate issues that you've correctly identified:

  1. Codegen isn't conforming enums to Codable
  2. DataStore expects the associated type to be a @model, which doesn't really make sense for enum values. We may in the end elect to treat them as models, but it doesn't seem right for a customer to have to tag an enum value with @model. We're working on this and will update when we have more info.

These two may end up devolving into a single root cause (again as you've correctly identified), but for now it makes sense to consider them separately.

@rodrigoelp
Copy link

Fair enough.

Looking forward to the decision.

drochetti added a commit that referenced this issue Feb 13, 2020
**Notes:**

- introduced a `PersistentModel` protocol to indicate enums that can be
persisted
- changed `ModelRegistry` to accept enum registration
- updated the DataStore plugin to handle `PersistentEnum`
drochetti added a commit that referenced this issue Mar 5, 2020
This fixes problems reported in several issues:  #111 #240 #246 #318 #314

**Notes:**

- added support for SQLite to handle Enums
- added support for SQLite to handle non-model types:
  - custom Codable structs
  - codable arrays
- added tests to make sure the right values are represented as SQLite
bindings
- remove field type string representation
- re-organized schema related files
- add support for Enum and non-model types
- remove commented code
- fix SQLite Int64 precision
- improve documentation and test cases
- better error handling and parameter naming
- addressed PR feedback
- add tests for `AnyEncodable`
- renamed variables for improved readability
- improved error message
- minor naming changes to address PR feedback
- update cocoapods version to be in sync with master

**Tests:**

- added a model that has all types of fields to make it easier to
visualize how data is represented on SQLite

**Pending:**

- More documentation
- GraphQL clenup on API category
@drochetti
Copy link
Contributor

This was resolved by PR #334

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

No branches or pull requests

4 participants