Skip to content

Commit f0acf51

Browse files
ruiguoamzGuo
andauthored
Datastore/sort by (#580)
* initial orderBy * rename order * in case of sudden shut down, urgent push * update codes according to updated proposal * refactor sort code * finished up integration tests * renamed some stuff * 1st: fixed PR comments * remove a Todo comment, update AssertTrue to AssertEqual, remove AWSMobileClient * removing Pods folder * fixed namespace issue * remove additionalStatements * removing additional statements in mock* Co-authored-by: Guo <[email protected]>
1 parent 11ed503 commit f0acf51

25 files changed

+556
-77
lines changed

Amplify.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,7 @@
353353
B9FAA180238FBB5D009414B4 /* Model+Array.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9FAA17F238FBB5D009414B4 /* Model+Array.swift */; };
354354
B9FB05F82383740D00DE1FD4 /* DataStoreStatement.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9FB05F72383740D00DE1FD4 /* DataStoreStatement.swift */; };
355355
D83C5160248964780091548E /* ModelGraphQLTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D83C515F248964780091548E /* ModelGraphQLTests.swift */; };
356+
D8DD7A1D24A1CCCD001C49FD /* QuerySortInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8DD7A1C24A1CCCD001C49FD /* QuerySortInput.swift */; };
356357
FA0173352375F8A5005DDDFC /* LoggingError.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA0173342375F8A5005DDDFC /* LoggingError.swift */; };
357358
FA0173372375FAA5005DDDFC /* HubError.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA0173362375FAA5005DDDFC /* HubError.swift */; };
358359
FA09337C23844E9F00C2FD5F /* GraphQLOperationRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA09337B23844E9F00C2FD5F /* GraphQLOperationRequest.swift */; };
@@ -1120,6 +1121,7 @@
11201121
D5363CAF9EFAA822FED56808 /* Pods_Amplify_AWSPluginsCore_AWSPluginsTestConfigs_AWSPluginsTestCommon.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Amplify_AWSPluginsCore_AWSPluginsTestConfigs_AWSPluginsTestCommon.framework; sourceTree = BUILT_PRODUCTS_DIR; };
11211122
D5521D5FA66340943C39C451 /* Pods-Amplify-AmplifyAWSPlugins-AWSPluginsCore-AWSAPICategoryPlugin.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Amplify-AmplifyAWSPlugins-AWSPluginsCore-AWSAPICategoryPlugin.debug.xcconfig"; path = "Target Support Files/Pods-Amplify-AmplifyAWSPlugins-AWSPluginsCore-AWSAPICategoryPlugin/Pods-Amplify-AmplifyAWSPlugins-AWSPluginsCore-AWSAPICategoryPlugin.debug.xcconfig"; sourceTree = "<group>"; };
11221123
D83C515F248964780091548E /* ModelGraphQLTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModelGraphQLTests.swift; sourceTree = "<group>"; };
1124+
D8DD7A1C24A1CCCD001C49FD /* QuerySortInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuerySortInput.swift; sourceTree = "<group>"; };
11231125
DD2486414D63230FF39130C7 /* Pods-Amplify-AWSPluginsCore.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Amplify-AWSPluginsCore.debug.xcconfig"; path = "Target Support Files/Pods-Amplify-AWSPluginsCore/Pods-Amplify-AWSPluginsCore.debug.xcconfig"; sourceTree = "<group>"; };
11241126
DEEB82A328223C60557B75C1 /* Pods-Amplify-AmplifyAWSPlugins-AWSPluginsCore-AWSPinpointAnalyticsPlugin.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Amplify-AmplifyAWSPlugins-AWSPluginsCore-AWSPinpointAnalyticsPlugin.release.xcconfig"; path = "Target Support Files/Pods-Amplify-AmplifyAWSPlugins-AWSPluginsCore-AWSPinpointAnalyticsPlugin/Pods-Amplify-AmplifyAWSPlugins-AWSPluginsCore-AWSPinpointAnalyticsPlugin.release.xcconfig"; sourceTree = "<group>"; };
11251127
E1306F31E45EE7C6B6048F89 /* Pods-AmplifyAWSPlugins-AWSPluginsCore-AWSS3StoragePlugin-AWSS3StoragePluginTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AmplifyAWSPlugins-AWSPluginsCore-AWSS3StoragePlugin-AWSS3StoragePluginTests.release.xcconfig"; path = "Target Support Files/Pods-AmplifyAWSPlugins-AWSPluginsCore-AWSS3StoragePlugin-AWSS3StoragePluginTests/Pods-AmplifyAWSPlugins-AWSPluginsCore-AWSS3StoragePlugin-AWSS3StoragePluginTests.release.xcconfig"; sourceTree = "<group>"; };
@@ -2295,6 +2297,7 @@
22952297
B98E9D072372236200934B51 /* QueryOperator.swift */,
22962298
B98E9D0B2372236200934B51 /* QueryOperator+Equatable.swift */,
22972299
B912D1B5242960D40028F05C /* QueryPaginationInput.swift */,
2300+
D8DD7A1C24A1CCCD001C49FD /* QuerySortInput.swift */,
22982301
B98E9D082372236200934B51 /* QueryPredicate.swift */,
22992302
B98E9D0C2372236200934B51 /* QueryPredicate+Equatable.swift */,
23002303
);
@@ -4375,6 +4378,7 @@
43754378
B450741324115C260098F02D /* AuthSignInRequest.swift in Sources */,
43764379
B4FA336A24105EB700E1C659 /* AuthCategoryConfiguration.swift in Sources */,
43774380
FAC23523227A053D00424678 /* LoggingCategoryPlugin.swift in Sources */,
4381+
D8DD7A1D24A1CCCD001C49FD /* QuerySortInput.swift in Sources */,
43784382
B9FB05F82383740D00DE1FD4 /* DataStoreStatement.swift in Sources */,
43794383
FAC23527227A053D00424678 /* LoggingCategoryClientBehavior.swift in Sources */,
43804384
FA09B92B2321A10E000E064D /* AnalyticsCategory+CategoryConfigurable.swift in Sources */,

Amplify/Categories/DataStore/DataStoreCategory+Behavior.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,10 @@ extension DataStoreCategory: DataStoreBaseBehavior {
2020

2121
public func query<M: Model>(_ modelType: M.Type,
2222
where predicate: QueryPredicate? = nil,
23+
sort sortInput: QuerySortInput? = nil,
2324
paginate paginationInput: QueryPaginationInput? = nil,
2425
completion: DataStoreCallback<[M]>) {
25-
plugin.query(modelType, where: predicate, paginate: paginationInput, completion: completion)
26+
plugin.query(modelType, where: predicate, sort: sortInput, paginate: paginationInput, completion: completion)
2627
}
2728

2829
public func delete<M: Model>(_ model: M,

Amplify/Categories/DataStore/DataStoreCategoryBehavior.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ public protocol DataStoreBaseBehavior {
2222

2323
func query<M: Model>(_ modelType: M.Type,
2424
where predicate: QueryPredicate?,
25+
sort sortInput: QuerySortInput?,
2526
paginate paginationInput: QueryPaginationInput?,
2627
completion: DataStoreCallback<[M]>)
2728

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
//
2+
// Copyright 2018-2020 Amazon.com,
3+
// Inc. or its affiliates. All Rights Reserved.
4+
//
5+
// SPDX-License-Identifier: Apache-2.0
6+
//
7+
8+
import Foundation
9+
10+
/// A simple enum that holding a sorting direction for a field that can be applied to queries.
11+
public enum QuerySortBy {
12+
case ascending(CodingKey)
13+
case descending(CodingKey)
14+
}
15+
16+
public struct QuerySortInput {
17+
public let inputs: [QuerySortBy]
18+
19+
public init(_ inputs: [QuerySortBy]) {
20+
self.inputs = inputs
21+
}
22+
23+
/// Creates a `QuerySortInput` in an expressive way, enabling a short
24+
/// and developer friendly access to an instance of `QuerySortInput`.
25+
/// Simply by calling:
26+
/// - Amplify.Datastore.query(model.self, sort: .ascending(model.keys.id))
27+
/// or
28+
/// - Amplify.Datastore.query(model.self, sort: .descending(model.keys.id))
29+
/// or
30+
/// - Amplify.Datastore.query(model.self, sort: .by(.ascending(model.keys.id), .descending(model.keys.createdAt))
31+
///
32+
/// - Parameters:
33+
/// - inputs: a variadic parameters that take uncertain number of `QuerySortBy`
34+
/// - Returns: a new instance of `QuerySortInput`
35+
public static func by(_ inputs: QuerySortBy...) -> QuerySortInput {
36+
return self.init(inputs)
37+
}
38+
39+
/// Returns an ascending sort specifier for `field`
40+
public static func ascending(_ field: CodingKey) -> QuerySortInput {
41+
return QuerySortInput([.ascending(field)])
42+
}
43+
44+
/// Returns an descending sort specifier for `field`
45+
public static func descending(_ field: CodingKey) -> QuerySortInput {
46+
return QuerySortInput([.descending(field)])
47+
}
48+
}

AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/AWSDataStorePlugin+DataStoreBaseBehavior.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,13 @@ extension AWSDataStorePlugin: DataStoreBaseBehavior {
7979

8080
public func query<M: Model>(_ modelType: M.Type,
8181
where predicate: QueryPredicate? = nil,
82+
sort sortInput: QuerySortInput? = nil,
8283
paginate paginationInput: QueryPaginationInput? = nil,
8384
completion: DataStoreCallback<[M]>) {
8485
reinitStorageEngineIfNeeded()
8586
storageEngine.query(modelType,
8687
predicate: predicate,
88+
sort: sortInput,
8789
paginationInput: paginationInput,
8890
completion: completion)
8991
}
@@ -165,6 +167,7 @@ extension AWSDataStorePlugin: DataStoreBaseBehavior {
165167
let metadata = MutationSyncMetadata.keys
166168
storageEngine.query(MutationSyncMetadata.self,
167169
predicate: metadata.id == model.id,
170+
sort: nil,
168171
paginationInput: .firstResult) {
169172
switch $0 {
170173
case .success(let result):

AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Storage/ModelStorageBehavior.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ protocol ModelStorageBehavior {
2424

2525
func query<M: Model>(_ modelType: M.Type,
2626
predicate: QueryPredicate?,
27+
sort: QuerySortInput?,
2728
paginationInput: QueryPaginationInput?,
2829
completion: DataStoreCallback<[M]>)
2930

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//
2+
// Copyright 2018-2020 Amazon.com,
3+
// Inc. or its affiliates. All Rights Reserved.
4+
//
5+
// SPDX-License-Identifier: Apache-2.0
6+
//
7+
8+
import Amplify
9+
import Foundation
10+
import SQLite
11+
12+
extension QuerySortBy {
13+
var fieldName: String {
14+
switch self {
15+
case .ascending(let key), .descending(let key):
16+
return key.stringValue
17+
}
18+
}
19+
20+
var fieldOrder: String {
21+
switch self {
22+
case .ascending:
23+
return "asc"
24+
case .descending:
25+
return "desc"
26+
}
27+
}
28+
}
29+
30+
extension QuerySortInput {
31+
func sortStatement(namespace: String) -> String {
32+
let sqlResult = inputs
33+
.map { QuerySortInput.columnFor(field: $0.fieldName,
34+
order: $0.fieldOrder,
35+
namespace: namespace) }
36+
37+
return sqlResult.joined(separator: ", ")
38+
}
39+
40+
static func columnFor(field: String,
41+
order: String,
42+
namespace: String) -> String {
43+
return namespace.quoted() + "." + field.quoted() + " " + order
44+
45+
}
46+
}

AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Storage/SQLite/SQLStatement+Select.swift

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,10 @@ struct SelectStatementMetadata {
1919
let columnMapping: ColumnMapping
2020
let bindings: [Binding?]
2121

22-
// TODO remove additionalStatements once sorting support is added to DataStore
2322
static func metadata(from modelType: Model.Type,
2423
predicate: QueryPredicate? = nil,
25-
paginationInput: QueryPaginationInput? = nil,
26-
additionalStatements: String? = nil) -> SelectStatementMetadata {
24+
sort: QuerySortInput? = nil,
25+
paginationInput: QueryPaginationInput? = nil) -> SelectStatementMetadata {
2726
let rootNamespace = "root"
2827
let schema = modelType.schema
2928
let fields = schema.columns
@@ -59,10 +58,10 @@ struct SelectStatementMetadata {
5958
"""
6059
}
6160

62-
if let additionalStatements = additionalStatements {
61+
if let sort = sort, !sort.inputs.isEmpty {
6362
sql = """
6463
\(sql)
65-
\(additionalStatements)
64+
order by \(sort.sortStatement(namespace: rootNamespace))
6665
"""
6766
}
6867

@@ -72,6 +71,7 @@ struct SelectStatementMetadata {
7271
\(paginationInput.sqlStatement)
7372
"""
7473
}
74+
7575
return SelectStatementMetadata(statement: sql,
7676
columnMapping: columnMapping,
7777
bindings: bindings)
@@ -137,13 +137,13 @@ struct SelectStatement: SQLStatement {
137137

138138
init(from modelType: Model.Type,
139139
predicate: QueryPredicate? = nil,
140-
paginationInput: QueryPaginationInput? = nil,
141-
additionalStatements: String? = nil) {
140+
sort: QuerySortInput? = nil,
141+
paginationInput: QueryPaginationInput? = nil) {
142142
self.modelType = modelType
143143
self.metadata = .metadata(from: modelType,
144144
predicate: predicate,
145-
paginationInput: paginationInput,
146-
additionalStatements: additionalStatements)
145+
sort: sort,
146+
paginationInput: paginationInput)
147147
}
148148

149149
var stringValue: String {

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

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -188,25 +188,14 @@ final class SQLiteStorageEngineAdapter: StorageEngineAdapter {
188188

189189
func query<M: Model>(_ modelType: M.Type,
190190
predicate: QueryPredicate? = nil,
191+
sort: QuerySortInput? = nil,
191192
paginationInput: QueryPaginationInput? = nil,
192193
completion: DataStoreCallback<[M]>) {
193-
query(modelType,
194-
predicate: predicate,
195-
paginationInput: paginationInput,
196-
additionalStatements: nil,
197-
completion: completion)
198-
}
199-
200-
func query<M: Model>(_ modelType: M.Type,
201-
predicate: QueryPredicate? = nil,
202-
paginationInput: QueryPaginationInput? = nil,
203-
additionalStatements: String? = nil,
204-
completion: DataStoreCallback<[M]>) {
205194
do {
206195
let statement = SelectStatement(from: modelType,
207196
predicate: predicate,
208-
paginationInput: paginationInput,
209-
additionalStatements: additionalStatements)
197+
sort: sort,
198+
paginationInput: paginationInput)
210199
let rows = try connection.prepare(statement.stringValue).run(statement.variables)
211200
let result: [M] = try rows.convert(to: modelType, using: statement)
212201
completion(.success(result))

AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Storage/StorageEngine.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,8 +293,8 @@ final class StorageEngine: StorageEngineBehavior {
293293
try storageAdapter.transaction {
294294
storageAdapter.query(modelType,
295295
predicate: predicate,
296+
sort: nil,
296297
paginationInput: nil,
297-
additionalStatements: nil,
298298
completion: queryCompletionBlock)
299299
}
300300
} catch {
@@ -329,10 +329,12 @@ final class StorageEngine: StorageEngineBehavior {
329329

330330
func query<M: Model>(_ modelType: M.Type,
331331
predicate: QueryPredicate? = nil,
332+
sort: QuerySortInput? = nil,
332333
paginationInput: QueryPaginationInput? = nil,
333334
completion: DataStoreCallback<[M]>) {
334335
return storageAdapter.query(modelType,
335336
predicate: predicate,
337+
sort: sort,
336338
paginationInput: paginationInput,
337339
completion: completion)
338340
}

0 commit comments

Comments
 (0)