Skip to content

Commit c393d78

Browse files
authored
fix(v1): CPK has-many has-one associatedFields (#2734)
1 parent fcc10ed commit c393d78

File tree

7 files changed

+53
-22
lines changed

7 files changed

+53
-22
lines changed

Amplify/Categories/DataStore/Model/Internal/Schema/ModelField+Association.swift

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ import Foundation
8787
/// - Warning: Although this has `public` access, it is intended for internal & codegen use and should not be used
8888
/// directly by host applications. The behavior of this may change without warning.
8989
public enum ModelAssociation {
90-
case hasMany(associatedFieldName: String?)
91-
case hasOne(associatedFieldName: String?, targetNames: [String])
90+
case hasMany(associatedFieldName: String?, associatedFieldNames: [String] = [])
91+
case hasOne(associatedFieldName: String?, associatedFieldNames: [String] = [], targetNames: [String])
9292
case belongsTo(associatedFieldName: String?, targetNames: [String])
9393

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

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

105-
@available(*, deprecated, message: "Use hasOne(associatedWith:targetNames:)")
106-
public static func hasOne(associatedWith: CodingKey?, targetName: String? = nil) -> ModelAssociation {
107+
@available(*, deprecated, message: "Use hasOne(associatedWith:associatedFields:targetNames:)")
108+
public static func hasOne(associatedWith: CodingKey?,
109+
targetName: String? = nil) -> ModelAssociation {
107110
let targetNames = targetName.map { [$0] } ?? []
108111
return .hasOne(associatedWith: associatedWith, targetNames: targetNames)
109112
}
110113

111-
public static func hasOne(associatedWith: CodingKey?, targetNames: [String] = []) -> ModelAssociation {
112-
return .hasOne(associatedFieldName: associatedWith?.stringValue, targetNames: targetNames)
114+
public static func hasOne(associatedWith: CodingKey? = nil,
115+
associatedFields: [CodingKey] = [],
116+
targetNames: [String] = []) -> ModelAssociation {
117+
return .hasOne(associatedFieldName: associatedWith?.stringValue,
118+
associatedFieldNames: associatedFields.map { $0.stringValue },
119+
targetNames: targetNames)
113120
}
114121

115122
@available(*, deprecated, message: "Use belongsTo(associatedWith:targetNames:)")
@@ -234,13 +241,9 @@ extension ModelField {
234241
if hasAssociation {
235242
let associatedModel = requiredAssociatedModelName
236243
switch association {
237-
case .belongsTo(let associatedKey, _):
238-
// TODO handle modelName casing (convert to camelCase)
239-
let key = associatedKey ?? associatedModel
240-
let schema = ModelRegistry.modelSchema(from: associatedModel)
241-
return schema?.field(withName: key)
242-
case .hasOne(let associatedKey, _),
243-
.hasMany(let associatedKey):
244+
case .belongsTo(let associatedKey, _),
245+
.hasOne(let associatedKey, _, _),
246+
.hasMany(let associatedKey, _):
244247
// TODO handle modelName casing (convert to camelCase)
245248
let key = associatedKey ?? associatedModel
246249
let schema = ModelRegistry.modelSchema(from: associatedModel)

Amplify/Categories/DataStore/Model/Internal/Schema/ModelSchema+Definition.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,19 @@ public enum ModelFieldDefinition {
241241
association: .hasMany(associatedWith: associatedKey))
242242
}
243243

244+
public static func hasMany(_ key: CodingKey,
245+
is nullability: ModelFieldNullability = .required,
246+
isReadOnly: Bool = false,
247+
ofType type: Model.Type,
248+
associatedFields associatedKeys: [CodingKey]) -> ModelFieldDefinition {
249+
return .field(key,
250+
is: nullability,
251+
isReadOnly: isReadOnly,
252+
ofType: .collection(of: type),
253+
association: .hasMany(associatedWith: associatedKeys.first,
254+
associatedFields: associatedKeys))
255+
}
256+
244257
public static func hasOne(_ key: CodingKey,
245258
is nullability: ModelFieldNullability = .required,
246259
isReadOnly: Bool = false,
@@ -267,6 +280,21 @@ public enum ModelFieldDefinition {
267280
association: .hasOne(associatedWith: associatedKey, targetNames: targetNames))
268281
}
269282

283+
public static func hasOne(_ key: CodingKey,
284+
is nullability: ModelFieldNullability = .required,
285+
isReadOnly: Bool = false,
286+
ofType type: Model.Type,
287+
associatedFields associatedKeys: [CodingKey],
288+
targetNames: [String]) -> ModelFieldDefinition {
289+
return .field(key,
290+
is: nullability,
291+
isReadOnly: isReadOnly,
292+
ofType: .model(type: type),
293+
association: .hasOne(associatedWith: associatedKeys.first,
294+
associatedFields: associatedKeys,
295+
targetNames: targetNames))
296+
}
297+
270298
public static func belongsTo(_ key: CodingKey,
271299
is nullability: ModelFieldNullability = .required,
272300
isReadOnly: Bool = false,

AmplifyPlugins/Core/AWSPluginsCore/Model/Support/Model+GraphQL.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ extension Model {
207207
let defaultFieldName = modelName.camelCased() + modelField.name.pascalCased() + "Id"
208208
if case let .belongsTo(_, targetNames) = modelField.association, !targetNames.isEmpty {
209209
return targetNames
210-
} else if case let .hasOne(_, targetNames) = modelField.association,
210+
} else if case let .hasOne(_, _, targetNames) = modelField.association,
211211
!targetNames.isEmpty {
212212
return targetNames
213213
}

AmplifyPlugins/Core/AWSPluginsCore/Model/Support/QueryPredicate+GraphQL.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ extension QueryPredicateOperation: GraphQLFilterConvertible {
131131
}
132132
let targetName = targetNames.first ?? defaultFieldName
133133
return targetName
134-
case .hasOne(_, let targetNames):
134+
case .hasOne(_, _, let targetNames):
135135
guard targetNames.count == 1 else {
136136
preconditionFailure("QueryPredicate not supported on associated field with composite key: \(field)")
137137
}

AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Storage/SQLite/ModelSchema+SQLite.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ extension ModelField: SQLColumn {
8282
var sqlName: String {
8383
if case let .belongsTo(_, targetNames) = association {
8484
return foreignKeySqlName(withAssociationTargets: targetNames)
85-
} else if case let .hasOne(_, targetNames) = association {
85+
} else if case let .hasOne(_, _, targetNames) = association {
8686
return foreignKeySqlName(withAssociationTargets: targetNames)
8787
}
8888
return name

AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginTests/Subscribe/DataStoreObserveQueryOperationTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ class DataStoreObserveQueryOperationTests: XCTestCase {
9292
let secondSnapshot = expectation(description: "second query snapshots")
9393
let thirdSnapshot = expectation(description: "third query snapshot")
9494
thirdSnapshot.isInverted = true
95-
95+
9696
var querySnapshots = [DataStoreQuerySnapshot<Post>]()
9797
let dispatchedModelSyncedEvent = AtomicValue(initialValue: false)
9898
let operation = AWSDataStoreObserveQueryOperation(

AmplifyTests/CategoryTests/DataStore/ModelFieldAssociationTests.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class ModelFieldAssociationTests: XCTestCase {
2828

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

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

4848
func testHasOneWithCodingKeysWithTargetName() {
4949
let hasOne = ModelAssociation.hasOne(associatedWith: Comment.keys.post, targetName: "postID")
50-
guard case .hasOne(let fieldName, let target) = hasOne else {
50+
guard case .hasOne(let fieldName, _, let target) = hasOne else {
5151
XCTFail("Should create hasOne association")
5252
return
5353
}

0 commit comments

Comments
 (0)