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

fix(amplify-codegen-appsync-model-plugin): Support Embeddable Types for iOS #4545

Merged
merged 11 commits into from
Jun 16, 2020
Original file line number Diff line number Diff line change
Expand Up @@ -696,19 +696,19 @@ describe('AppSyncSwiftVisitor', () => {

model.fields(
.id(),
.field(objectWithNativeTypes.intArr, is: .optional, ofType: .customType([Int].self)),
.field(objectWithNativeTypes.strArr, is: .optional, ofType: .customType([String].self)),
.field(objectWithNativeTypes.floatArr, is: .optional, ofType: .customType([Double].self)),
.field(objectWithNativeTypes.boolArr, is: .optional, ofType: .customType([Bool].self)),
.field(objectWithNativeTypes.dateArr, is: .optional, ofType: .customType([Temporal.Date].self)),
.field(objectWithNativeTypes.enumArr, is: .optional, ofType: .customType([EnumType].self))
.field(objectWithNativeTypes.intArr, is: .optional, ofType: .embeddedCollection(of: Int.self)),
.field(objectWithNativeTypes.strArr, is: .optional, ofType: .embeddedCollection(of: String.self)),
.field(objectWithNativeTypes.floatArr, is: .optional, ofType: .embeddedCollection(of: Double.self)),
.field(objectWithNativeTypes.boolArr, is: .optional, ofType: .embeddedCollection(of: Bool.self)),
.field(objectWithNativeTypes.dateArr, is: .optional, ofType: .embeddedCollection(of: Temporal.Date.self)),
.field(objectWithNativeTypes.enumArr, is: .optional, ofType: .embeddedCollection(of: EnumType.self))
)
}
}"
`);
});

it('should support using non model types in models', () => {
it('should support using embedded types in models', () => {
const schema = /* GraphQL */ `
type Attraction @model {
id: ID!
Expand Down Expand Up @@ -792,11 +792,11 @@ describe('AppSyncSwiftVisitor', () => {
model.fields(
.id(),
.field(attraction.name, is: .required, ofType: .string),
.field(attraction.location, is: .required, ofType: .customType(Location.self)),
.field(attraction.nearByLocations, is: .optional, ofType: .customType([Location].self)),
.field(attraction.location, is: .required, ofType: .embedded(type: Location.self)),
.field(attraction.nearByLocations, is: .optional, ofType: .embeddedCollection(of: Location.self)),
.field(attraction.status, is: .required, ofType: .enum(type: Status.self)),
.field(attraction.statusHistory, is: .optional, ofType: .customType([Status].self)),
.field(attraction.tags, is: .optional, ofType: .customType([String].self))
.field(attraction.statusHistory, is: .optional, ofType: .embeddedCollection(of: Status.self)),
.field(attraction.tags, is: .optional, ofType: .embeddedCollection(of: String.self))
)
}
}"
Expand All @@ -820,13 +820,46 @@ describe('AppSyncSwiftVisitor', () => {
import Amplify
import Foundation

public struct Location: Codable {
public struct Location: Embedded {
var lat: String
var lang: String
var tags: [String]?
}"
`);

const visitorLocationSchema = getVisitor(schema, 'Location', CodeGenGenerateEnum.metadata);
const generatedCode = visitorLocationSchema.generate()
console.log(generatedCode)
lawmicha marked this conversation as resolved.
Show resolved Hide resolved
expect(generatedCode).toMatchInlineSnapshot(`
"// swiftlint:disable all
import Amplify
import Foundation

extension Location {
// MARK: - CodingKeys
public enum CodingKeys: String, ModelKey {
case lat
case lang
case tags
}

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

public static let schema = defineSchema { model in
let location = Location.keys

model.pluralName = "Locations"

model.fields(
.field(location.lat, is: .required, ofType: .string),
.field(location.lang, is: .required, ofType: .string),
.field(location.tags, is: .optional, ofType: .embeddedCollection(of: String.self))
)
}
}"
`);

const visitorClassLoader = getVisitor(schema, undefined, CodeGenGenerateEnum.loader);
expect(visitorClassLoader.generate()).toMatchInlineSnapshot(`
"// swiftlint:disable all
Expand Down Expand Up @@ -1213,7 +1246,7 @@ describe('AppSyncSwiftVisitor', () => {
model.fields(
.id(),
.field(post.title, is: .required, ofType: .string),
.field(post.groups, is: .required, ofType: .customType([String].self))
.field(post.groups, is: .required, ofType: .embeddedCollection(of: String.self))
)
}
}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export class AppSyncSwiftVisitor extends AppSyncModelVisitor {
const structBlock: SwiftDeclarationBlock = new SwiftDeclarationBlock()
.withName(this.getModelName(obj))
.access('public')
.withProtocols(['Codable']);
.withProtocols(['Embedded']);
Object.values(obj.fields).forEach(field => {
const fieldType = this.getNativeType(field);
structBlock.addProperty(this.getFieldName(field), fieldType, undefined, 'DEFAULT', {
Expand Down Expand Up @@ -124,6 +124,16 @@ export class AppSyncSwiftVisitor extends AppSyncModelVisitor {

result.push(schemaDeclarations.string);
});

Object.values(this.getSelectedNonModels())
.forEach(model => {
const schemaDeclarations = new SwiftDeclarationBlock().asKind('extension').withName(this.getModelName(model));
yuth marked this conversation as resolved.
Show resolved Hide resolved

this.generateCodingKeys(this.getModelName(model), model, schemaDeclarations),
lawmicha marked this conversation as resolved.
Show resolved Hide resolved
this.generateModelSchema(this.getModelName(model), model, schemaDeclarations);
lawmicha marked this conversation as resolved.
Show resolved Hide resolved

result.push(schemaDeclarations.string);
});
return result.join('\n');
}

Expand Down Expand Up @@ -249,15 +259,15 @@ export class AppSyncSwiftVisitor extends AppSyncModelVisitor {
if (isModelType) {
ofType = `.collection(of: ${this.getSwiftModelTypeName(field)})`;
} else {
ofType = `.customType(${this.getSwiftModelTypeName(field)})`;
ofType = `.embeddedCollection(of: ${this.getSwiftModelTypeName(field)})`;
}
} else {
if (isEnumType) {
ofType = `.enum(type: ${typeName})`;
} else if (isModelType) {
ofType = `.model(${typeName})`;
} else if (isNonModelType) {
ofType = `.customType(${typeName})`;
ofType = `.embedded(type: ${typeName})`;
} else {
ofType = typeName;
}
Expand All @@ -269,19 +279,17 @@ export class AppSyncSwiftVisitor extends AppSyncModelVisitor {

private getSwiftModelTypeName(field: CodeGenField) {
if (this.isEnumType(field)) {
const name = this.getEnumName(field.type);
return field.isList ? `[${name}].self` : `${name}.self`;
return `${this.getEnumName(field.type)}.self`;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

confirm enum collections

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you

Copy link
Contributor Author

@lawmicha lawmicha Jun 16, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ran codegen + provisioned API with schema using array of an enum. API calls look good, as long as it is an enum, it will be embedded inside .embedded(type) or .embeddedCollection(of:) when it is an array, without needing square brackets (as removed here)

}
if (this.isModelType(field)) {
return `${this.getModelName(this.modelMap[field.type])}.self`;
}
if (this.isNonModelType(field)) {
const name = this.getNonModelName(this.nonModelMap[field.type]);
return field.isList ? `[${name}].self` : `${name}.self`;
return `${this.getNonModelName(this.nonModelMap[field.type])}.self`;
}
if (field.type in schemaTypeMap) {
if (field.isList) {
return `[${this.getNativeType(field)}].self`;
return `${this.getNativeType(field)}.self`;
}
return schemaTypeMap[field.type];
}
Expand Down