Skip to content

Commit

Permalink
fix(v1): CPK has-many has-one associatedFields
Browse files Browse the repository at this point in the history
  • Loading branch information
lawmicha committed Feb 3, 2023
1 parent 9bf836c commit 1f3cc79
Show file tree
Hide file tree
Showing 7 changed files with 53 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ import Foundation
/// - Warning: Although this has `public` access, it is intended for internal & codegen use and should not be used
/// directly by host applications. The behavior of this may change without warning.
public enum ModelAssociation {
case hasMany(associatedFieldName: String?)
case hasOne(associatedFieldName: String?, targetNames: [String])
case hasMany(associatedFieldName: String?, associatedFieldNames: [String] = [])
case hasOne(associatedFieldName: String?, associatedFieldNames: [String] = [], targetNames: [String])
case belongsTo(associatedFieldName: String?, targetNames: [String])

public static let belongsTo: ModelAssociation = .belongsTo(associatedFieldName: nil, targetNames: [])
Expand All @@ -98,18 +98,25 @@ public enum ModelAssociation {
return .belongsTo(associatedFieldName: nil, targetNames: targetNames)
}

public static func hasMany(associatedWith: CodingKey?) -> ModelAssociation {
return .hasMany(associatedFieldName: associatedWith?.stringValue)
public static func hasMany(associatedWith: CodingKey? = nil,
associatedFields: [CodingKey] = []) -> ModelAssociation {
return .hasMany(associatedFieldName: associatedWith?.stringValue,
associatedFieldNames: associatedFields.map { $0.stringValue })
}

@available(*, deprecated, message: "Use hasOne(associatedWith:targetNames:)")
public static func hasOne(associatedWith: CodingKey?, targetName: String? = nil) -> ModelAssociation {
@available(*, deprecated, message: "Use hasOne(associatedWith:associatedFields:targetNames:)")
public static func hasOne(associatedWith: CodingKey?,
targetName: String? = nil) -> ModelAssociation {
let targetNames = targetName.map { [$0] } ?? []
return .hasOne(associatedWith: associatedWith, targetNames: targetNames)
}

public static func hasOne(associatedWith: CodingKey?, targetNames: [String] = []) -> ModelAssociation {
return .hasOne(associatedFieldName: associatedWith?.stringValue, targetNames: targetNames)
public static func hasOne(associatedWith: CodingKey? = nil,
associatedFields: [CodingKey] = [],
targetNames: [String] = []) -> ModelAssociation {
return .hasOne(associatedFieldName: associatedWith?.stringValue,
associatedFieldNames: associatedFields.map { $0.stringValue },
targetNames: targetNames)
}

@available(*, deprecated, message: "Use belongsTo(associatedWith:targetNames:)")
Expand Down Expand Up @@ -234,13 +241,9 @@ extension ModelField {
if hasAssociation {
let associatedModel = requiredAssociatedModelName
switch association {
case .belongsTo(let associatedKey, _):
// TODO handle modelName casing (convert to camelCase)
let key = associatedKey ?? associatedModel
let schema = ModelRegistry.modelSchema(from: associatedModel)
return schema?.field(withName: key)
case .hasOne(let associatedKey, _),
.hasMany(let associatedKey):
case .belongsTo(let associatedKey, _),
.hasOne(let associatedKey, _, _),
.hasMany(let associatedKey, _):
// TODO handle modelName casing (convert to camelCase)
let key = associatedKey ?? associatedModel
let schema = ModelRegistry.modelSchema(from: associatedModel)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,19 @@ public enum ModelFieldDefinition {
association: .hasMany(associatedWith: associatedKey))
}

public static func hasMany(_ key: CodingKey,
is nullability: ModelFieldNullability = .required,
isReadOnly: Bool = false,
ofType type: Model.Type,
associatedFields associatedKeys: [CodingKey]) -> ModelFieldDefinition {
return .field(key,
is: nullability,
isReadOnly: isReadOnly,
ofType: .collection(of: type),
association: .hasMany(associatedWith: associatedKeys.first ?? nil,
associatedFields: associatedKeys))
}

public static func hasOne(_ key: CodingKey,
is nullability: ModelFieldNullability = .required,
isReadOnly: Bool = false,
Expand All @@ -267,6 +280,21 @@ public enum ModelFieldDefinition {
association: .hasOne(associatedWith: associatedKey, targetNames: targetNames))
}

public static func hasOne(_ key: CodingKey,
is nullability: ModelFieldNullability = .required,
isReadOnly: Bool = false,
ofType type: Model.Type,
associatedFields associatedKeys: [CodingKey],
targetNames: [String]) -> ModelFieldDefinition {
return .field(key,
is: nullability,
isReadOnly: isReadOnly,
ofType: .model(type: type),
association: .hasOne(associatedWith: associatedKeys.first ?? nil,
associatedFields: associatedKeys,
targetNames: targetNames))
}

public static func belongsTo(_ key: CodingKey,
is nullability: ModelFieldNullability = .required,
isReadOnly: Bool = false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ extension Model {
let defaultFieldName = modelName.camelCased() + modelField.name.pascalCased() + "Id"
if case let .belongsTo(_, targetNames) = modelField.association, !targetNames.isEmpty {
return targetNames
} else if case let .hasOne(_, targetNames) = modelField.association,
} else if case let .hasOne(_, _, targetNames) = modelField.association,
!targetNames.isEmpty {
return targetNames
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ extension QueryPredicateOperation: GraphQLFilterConvertible {
}
let targetName = targetNames.first ?? defaultFieldName
return targetName
case .hasOne(_, let targetNames):
case .hasOne(_, _, let targetNames):
guard targetNames.count == 1 else {
preconditionFailure("QueryPredicate not supported on associated field with composite key: \(field)")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ extension ModelField: SQLColumn {
var sqlName: String {
if case let .belongsTo(_, targetNames) = association {
return foreignKeySqlName(withAssociationTargets: targetNames)
} else if case let .hasOne(_, targetNames) = association {
} else if case let .hasOne(_, _, targetNames) = association {
return foreignKeySqlName(withAssociationTargets: targetNames)
}
return name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ class DataStoreObserveQueryOperationTests: XCTestCase {
let secondSnapshot = expectation(description: "second query snapshots")
let thirdSnapshot = expectation(description: "third query snapshot")
thirdSnapshot.isInverted = true

var querySnapshots = [DataStoreQuerySnapshot<Post>]()
let dispatchedModelSyncedEvent = AtomicValue(initialValue: false)
let operation = AWSDataStoreObserveQueryOperation(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class ModelFieldAssociationTests: XCTestCase {

func testHasManyWithCodingKeys() {
let hasMany = ModelAssociation.hasMany(associatedWith: Comment.keys.post)
guard case .hasMany(let fieldName) = hasMany else {
guard case .hasMany(let fieldName, _) = hasMany else {
XCTFail("Should create hasMany association")
return
}
Expand All @@ -37,7 +37,7 @@ class ModelFieldAssociationTests: XCTestCase {

func testHasOneWithCodingKeys() {
let hasOne = ModelAssociation.hasOne(associatedWith: Comment.keys.post, targetName: nil)
guard case .hasOne(let fieldName, let target) = hasOne else {
guard case .hasOne(let fieldName, _, let target) = hasOne else {
XCTFail("Should create hasOne association")
return
}
Expand All @@ -47,7 +47,7 @@ class ModelFieldAssociationTests: XCTestCase {

func testHasOneWithCodingKeysWithTargetName() {
let hasOne = ModelAssociation.hasOne(associatedWith: Comment.keys.post, targetName: "postID")
guard case .hasOne(let fieldName, let target) = hasOne else {
guard case .hasOne(let fieldName, _, let target) = hasOne else {
XCTFail("Should create hasOne association")
return
}
Expand Down

0 comments on commit 1f3cc79

Please sign in to comment.