Skip to content

Commit 634b25e

Browse files
authored
chore: kickoff release
2 parents f85c85c + b46559f commit 634b25e

File tree

430 files changed

+34010
-972
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

430 files changed

+34010
-972
lines changed

.github/workflows/integ_test_api.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,6 @@ jobs:
163163
scheme: AWSAPIPluginGraphQLLambdaAuthTests
164164

165165
api-lazy-load-test:
166-
if: ${{ false }}
167166
needs: prepare-for-test
168167
runs-on: macos-12
169168
environment: IntegrationTest

.github/workflows/integ_test_datastore_lazy_load.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
name: DataStore Lazy Load Tests
22
on:
33
workflow_dispatch:
4+
push:
5+
branches: [main]
46

57
permissions:
68
id-token: write
@@ -27,7 +29,7 @@ jobs:
2729
aws_region: ${{ secrets.AWS_REGION }}
2830
aws_s3_bucket: ${{ secrets.AWS_S3_BUCKET_INTEG }}
2931

30-
datastore-integration-v2-test:
32+
datastore-integration-lazy-load-test:
3133
timeout-minutes: 30
3234
needs: prepare-for-test
3335
runs-on: macos-12
@@ -53,5 +55,3 @@ jobs:
5355
with:
5456
project_path: ./AmplifyPlugins/DataStore/Tests/DataStoreHostApp
5557
scheme: AWSDataStorePluginLazyLoadTests
56-
57-

.swiftpm/xcode/xcshareddata/xcschemes/AWSLocationGeoPlugin.xcscheme

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<Scheme
3-
LastUpgradeVersion = "1400"
3+
LastUpgradeVersion = "1410"
44
version = "1.3">
55
<BuildAction
66
parallelizeBuildables = "YES"
@@ -20,6 +20,20 @@
2020
ReferencedContainer = "container:">
2121
</BuildableReference>
2222
</BuildActionEntry>
23+
<BuildActionEntry
24+
buildForTesting = "YES"
25+
buildForRunning = "NO"
26+
buildForProfiling = "NO"
27+
buildForArchiving = "NO"
28+
buildForAnalyzing = "NO">
29+
<BuildableReference
30+
BuildableIdentifier = "primary"
31+
BlueprintIdentifier = "AWSLocationGeoPluginTests"
32+
BuildableName = "AWSLocationGeoPluginTests"
33+
BlueprintName = "AWSLocationGeoPluginTests"
34+
ReferencedContainer = "container:">
35+
</BuildableReference>
36+
</BuildActionEntry>
2337
</BuildActionEntries>
2438
</BuildAction>
2539
<TestAction

Amplify/Categories/API/Internal/APICategory+Resettable.swift

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,6 @@ extension APICategory: Resettable {
2020
}
2121
await taskGroup.waitForAll()
2222
}
23-
log.verbose("Resetting ModelRegistry and ModelListDecoderRegistry")
24-
ModelRegistry.reset()
25-
ModelListDecoderRegistry.reset()
26-
log.verbose("Resetting ModelRegistry and ModelListDecoderRegistry: finished")
2723

2824
isConfigured = false
2925
}

Amplify/Categories/DataStore/Internal/DataStoreCategory+Resettable.swift

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,6 @@ extension DataStoreCategory: Resettable {
2020
}
2121
await taskGroup.waitForAll()
2222
}
23-
log.verbose("Resetting ModelRegistry and ModelListDecoderRegistry")
24-
ModelRegistry.reset()
25-
ModelListDecoderRegistry.reset()
26-
log.verbose("Resetting ModelRegistry and ModelListDecoderRegistry: finished")
2723

2824
isConfigured = false
2925
}

Amplify/Categories/DataStore/Model/Internal/ModelListDecoder.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,5 @@ extension ModelListDecoderRegistry {
3636
/// application making any change to these `public` types should be backward compatible, otherwise it will be a breaking
3737
/// change.
3838
public protocol ModelListDecoder {
39-
static func shouldDecode<ModelType: Model>(modelType: ModelType.Type, decoder: Decoder) -> Bool
40-
static func makeListProvider<ModelType: Model>(
41-
modelType: ModelType.Type, decoder: Decoder) throws -> AnyModelListProvider<ModelType>
39+
static func decode<ModelType: Model>(modelType: ModelType.Type, decoder: Decoder) -> AnyModelListProvider<ModelType>?
4240
}

Amplify/Categories/DataStore/Model/Internal/ModelListProvider.swift

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
//
77

88
import Foundation
9-
import Combine
109

1110
/// Empty protocol used as a marker to detect when the type is a `List`
1211
///
@@ -23,7 +22,13 @@ public protocol ModelListMarker { }
2322
/// application making any change to these `public` types should be backward compatible, otherwise it will be a breaking
2423
/// change.
2524
public enum ModelListProviderState<Element: Model> {
26-
case notLoaded
25+
/// If the list represents an association between two models, the `associatedIdentifiers` will
26+
/// hold the information necessary to query the associated elements (e.g. comments of a post)
27+
///
28+
/// The associatedFields represents the field to which the owner of the `List` is linked to.
29+
/// For example, if `Post.comments` is associated with `Comment.post` the `List<Comment>`
30+
/// of `Post` will have a reference to the `post` field in `Comment`.
31+
case notLoaded(associatedIdentifiers: [String], associatedFields: [String])
2732
case loaded([Element])
2833
}
2934

@@ -47,6 +52,9 @@ public protocol ModelListProvider {
4752
/// Asynchronously retrieve the next page as a new in-memory List object. Returns a failure if there
4853
/// is no next page of results. You can validate whether the list has another page with `hasNextPage()`.
4954
func getNextPage() async throws -> List<Element>
55+
56+
/// Custom encoder
57+
func encode(to encoder: Encoder) throws
5058
}
5159

5260
/// - Warning: Although this has `public` access, it is intended for internal & codegen use and should not be used
@@ -58,14 +66,16 @@ public struct AnyModelListProvider<Element: Model>: ModelListProvider {
5866
private let loadAsync: () async throws -> [Element]
5967
private let hasNextPageClosure: () -> Bool
6068
private let getNextPageAsync: () async throws -> List<Element>
61-
69+
private let encodeClosure: (Encoder) throws -> Void
70+
6271
public init<Provider: ModelListProvider>(
6372
provider: Provider
6473
) where Provider.Element == Self.Element {
6574
self.getStateClosure = provider.getState
6675
self.loadAsync = provider.load
6776
self.hasNextPageClosure = provider.hasNextPage
6877
self.getNextPageAsync = provider.getNextPage
78+
self.encodeClosure = provider.encode
6979
}
7080

7181
public func getState() -> ModelListProviderState<Element> {
@@ -83,6 +93,10 @@ public struct AnyModelListProvider<Element: Model>: ModelListProvider {
8393
public func getNextPage() async throws -> List<Element> {
8494
try await getNextPageAsync()
8595
}
96+
97+
public func encode(to encoder: Encoder) throws {
98+
try encodeClosure(encoder)
99+
}
86100
}
87101

88102
/// - Warning: Although this has `public` access, it is intended for internal & codegen use and should not be used
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
//
2+
// Copyright Amazon.com Inc. or its affiliates.
3+
// All Rights Reserved.
4+
//
5+
// SPDX-License-Identifier: Apache-2.0
6+
//
7+
8+
import Foundation
9+
10+
/// Protocol used as a marker to detect when the type is a `LazyReference`.
11+
/// Used to retrieve either the `reference` or the `identifiers` of the Model directly, without having load a not
12+
/// loaded LazyReference. This is useful when translating the model object over to the payload required for the
13+
/// underlying storage, such as storing the values in DataStore's local database or AppSync GraphQL request payload.
14+
///
15+
///
16+
/// - Warning: Although this has `public` access, it is intended for internal & codegen use and should not be used
17+
/// directly by host applications. The behavior of this may change without warning. Though it is not used by host
18+
/// application making any change to these `public` types should be backward compatible, otherwise it will be a breaking
19+
/// change.
20+
public protocol _LazyReferenceValue {
21+
var _state: _LazyReferenceValueState { get }
22+
}
23+
24+
public enum _LazyReferenceValueState {
25+
case notLoaded(identifiers: [LazyReferenceIdentifier]?)
26+
case loaded(model: Model?)
27+
}
28+
29+
/// State of the ModelProvider
30+
///
31+
/// - Warning: Although this has `public` access, it is intended for internal & codegen use and should not be used
32+
/// directly by host applications. The behavior of this may change without warning. Though it is not used by host
33+
/// application making any change to these `public` types should be backward compatible, otherwise it will be a breaking
34+
/// change.
35+
public enum ModelProviderState<Element: Model> {
36+
case notLoaded(identifiers: [LazyReferenceIdentifier]?)
37+
case loaded(model: Element?)
38+
}
39+
40+
/// - Warning: Although this has `public` access, it is intended for internal & codegen use and should not be used
41+
/// directly by host applications. The behavior of this may change without warning. Though it is not used by host
42+
/// application making any change to these `public` types should be backward compatible, otherwise it will be a breaking
43+
/// change.
44+
public protocol ModelProvider {
45+
associatedtype Element: Model
46+
47+
func load() async throws -> Element?
48+
49+
func getState() -> ModelProviderState<Element>
50+
51+
func encode(to encoder: Encoder) throws
52+
}
53+
54+
/// - Warning: Although this has `public` access, it is intended for internal & codegen use and should not be used
55+
/// directly by host applications. The behavior of this may change without warning. Though it is not used by host
56+
/// application making any change to these `public` types should be backward compatible, otherwise it will be a breaking
57+
/// change.
58+
public struct AnyModelProvider<Element: Model>: ModelProvider {
59+
60+
private let loadAsync: () async throws -> Element?
61+
private let getStateClosure: () -> ModelProviderState<Element>
62+
private let encodeClosure: (Encoder) throws -> Void
63+
64+
public init<Provider: ModelProvider>(provider: Provider) where Provider.Element == Self.Element {
65+
self.loadAsync = provider.load
66+
self.getStateClosure = provider.getState
67+
self.encodeClosure = provider.encode
68+
}
69+
70+
public func load() async throws -> Element? {
71+
try await loadAsync()
72+
}
73+
74+
public func getState() -> ModelProviderState<Element> {
75+
getStateClosure()
76+
}
77+
78+
public func encode(to encoder: Encoder) throws {
79+
try encodeClosure(encoder)
80+
}
81+
}
82+
83+
/// - Warning: Although this has `public` access, it is intended for internal & codegen use and should not be used
84+
/// directly by host applications. The behavior of this may change without warning. Though it is not used by host
85+
/// application making any change to these `public` types should be backward compatible, otherwise it will be a breaking
86+
/// change.
87+
public extension ModelProvider {
88+
func eraseToAnyModelProvider() -> AnyModelProvider<Element> {
89+
AnyModelProvider(provider: self)
90+
}
91+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//
2+
// Copyright Amazon.com Inc. or its affiliates.
3+
// All Rights Reserved.
4+
//
5+
// SPDX-License-Identifier: Apache-2.0
6+
//
7+
8+
import Foundation
9+
10+
/// Registry of `ModelProviderDecoder`'s used to retrieve decoders that can create `ModelProvider`s to perform
11+
/// LazyReference functionality.
12+
///
13+
/// - Warning: Although this has `public` access, it is intended for internal & codegen use and should not be used
14+
/// directly by host applications. The behavior of this may change without warning. Though it is not used by host
15+
/// application making any change to these `public` types should be backward compatible, otherwise it will be a breaking
16+
/// change.
17+
public struct ModelProviderRegistry {
18+
static var decoders = AtomicValue(initialValue: [ModelProviderDecoder.Type]())
19+
20+
/// Register a decoder during plugin configuration time, to allow runtime retrievals of model providers.
21+
public static func registerDecoder(_ decoder: ModelProviderDecoder.Type) {
22+
decoders.append(decoder)
23+
}
24+
}
25+
26+
extension ModelProviderRegistry {
27+
static func reset() {
28+
decoders.set([ModelProviderDecoder.Type]())
29+
}
30+
}
31+
32+
/// `ModelProviderDecoder` provides decoding and lazy reference functionality.
33+
///
34+
/// - Warning: Although this has `public` access, it is intended for internal & codegen use and should not be used
35+
/// directly by host applications. The behavior of this may change without warning. Though it is not used by host
36+
/// application making any change to these `public` types should be backward compatible, otherwise it will be a breaking
37+
/// change.
38+
public protocol ModelProviderDecoder {
39+
static func decode<ModelType: Model>(modelType: ModelType.Type, decoder: Decoder) -> AnyModelProvider<ModelType>?
40+
}

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

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ 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?)
90+
case hasMany(associatedFieldName: String?, associatedFieldNames: [String] = [])
9191
case hasOne(associatedFieldName: String?, targetNames: [String])
9292
case belongsTo(associatedFieldName: String?, targetNames: [String])
9393

@@ -98,8 +98,8 @@ 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, associatedFields: [CodingKey] = []) -> ModelAssociation {
102+
return .hasMany(associatedFieldName: associatedWith?.stringValue, associatedFieldNames: associatedFields.map { $0.stringValue })
103103
}
104104

105105
@available(*, deprecated, message: "Use hasOne(associatedWith:targetNames:)")
@@ -226,6 +226,19 @@ extension ModelField {
226226
return true
227227
}
228228

229+
/// - Warning: Although this has `public` access, it is intended for internal & codegen use and should not be used
230+
/// directly by host applications. The behavior of this may change without warning. Though it is not used by host
231+
/// application making any change to these `public` types should be backward compatible, otherwise it will be a
232+
/// breaking change.
233+
public var _isBelongsToOrHasOne: Bool {
234+
switch association {
235+
case .belongsTo, .hasOne:
236+
return true
237+
case .hasMany, .none:
238+
return false
239+
}
240+
}
241+
229242
/// - Warning: Although this has `public` access, it is intended for internal & codegen use and should not be used
230243
/// directly by host applications. The behavior of this may change without warning. Though it is not used by host
231244
/// application making any change to these `public` types should be backward compatible, otherwise it will be a
@@ -234,13 +247,9 @@ extension ModelField {
234247
if hasAssociation {
235248
let associatedModel = requiredAssociatedModelName
236249
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):
250+
case .belongsTo(let associatedKey, _),
251+
.hasOne(let associatedKey, _),
252+
.hasMany(let associatedKey, _):
244253
// TODO handle modelName casing (convert to camelCase)
245254
let key = associatedKey ?? associatedModel
246255
let schema = ModelRegistry.modelSchema(from: associatedModel)
@@ -252,6 +261,29 @@ extension ModelField {
252261
return nil
253262
}
254263

264+
/// - Warning: Although this has `public` access, it is intended for internal & codegen use and should not be used
265+
/// directly by host applications. The behavior of this may change without warning. Though it is not used by host
266+
/// application making any change to these `public` types should be backward compatible, otherwise it will be a
267+
/// breaking change.
268+
public var associatedFieldNames: [String] {
269+
switch association {
270+
case .hasMany(let associatedKey, let associatedKeys):
271+
if associatedKeys.isEmpty, let associatedKey = associatedKey {
272+
return [associatedKey]
273+
}
274+
return associatedKeys
275+
276+
case .hasOne, .belongsTo:
277+
return ModelRegistry.modelSchema(from: requiredAssociatedModelName)?
278+
.primaryKey
279+
.fields
280+
.map(\.name) ?? []
281+
282+
case .none:
283+
return []
284+
}
285+
}
286+
255287
/// - Warning: Although this has `public` access, it is intended for internal & codegen use and should not be used
256288
/// directly by host applications. The behavior of this may change without warning. Though it is not used by host
257289
/// application making any change to these `public` types should be backward compatible, otherwise it will be a

0 commit comments

Comments
 (0)