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

chore: kickoff release #3808

Merged
merged 7 commits into from
Aug 12, 2024
36 changes: 0 additions & 36 deletions Amplify/Categories/DataStore/Model/Internal/Persistable.swift
Original file line number Diff line number Diff line change
@@ -65,12 +65,6 @@ struct PersistableHelper {
return lhs == rhs
case let (lhs, rhs) as (String, String):
return lhs == rhs
case let (lhs, rhs) as (any EnumPersistable, String):
return lhs.rawValue == rhs
case let (lhs, rhs) as (String, any EnumPersistable):
return lhs == rhs.rawValue
case let (lhs, rhs) as (any EnumPersistable, any EnumPersistable):
return lhs.rawValue == rhs.rawValue
default:
return false
}
@@ -100,12 +94,6 @@ struct PersistableHelper {
return lhs == Double(rhs)
case let (lhs, rhs) as (String, String):
return lhs == rhs
case let (lhs, rhs) as (any EnumPersistable, String):
return lhs.rawValue == rhs
case let (lhs, rhs) as (String, any EnumPersistable):
return lhs == rhs.rawValue
case let (lhs, rhs) as (any EnumPersistable, any EnumPersistable):
return lhs.rawValue == rhs.rawValue
default:
return false
}
@@ -134,12 +122,6 @@ struct PersistableHelper {
return lhs <= Double(rhs)
case let (lhs, rhs) as (String, String):
return lhs <= rhs
case let (lhs, rhs) as (any EnumPersistable, String):
return lhs.rawValue <= rhs
case let (lhs, rhs) as (String, any EnumPersistable):
return lhs <= rhs.rawValue
case let (lhs, rhs) as (any EnumPersistable, any EnumPersistable):
return lhs.rawValue <= rhs.rawValue
default:
return false
}
@@ -168,12 +150,6 @@ struct PersistableHelper {
return lhs < Double(rhs)
case let (lhs, rhs) as (String, String):
return lhs < rhs
case let (lhs, rhs) as (any EnumPersistable, String):
return lhs.rawValue < rhs
case let (lhs, rhs) as (String, any EnumPersistable):
return lhs < rhs.rawValue
case let (lhs, rhs) as (any EnumPersistable, any EnumPersistable):
return lhs.rawValue < rhs.rawValue
default:
return false
}
@@ -202,12 +178,6 @@ struct PersistableHelper {
return lhs >= Double(rhs)
case let (lhs, rhs) as (String, String):
return lhs >= rhs
case let (lhs, rhs) as (any EnumPersistable, String):
return lhs.rawValue >= rhs
case let (lhs, rhs) as (String, any EnumPersistable):
return lhs >= rhs.rawValue
case let (lhs, rhs) as (any EnumPersistable, any EnumPersistable):
return lhs.rawValue >= rhs.rawValue
default:
return false
}
@@ -236,12 +206,6 @@ struct PersistableHelper {
return Double(lhs) > rhs
case let (lhs, rhs) as (String, String):
return lhs > rhs
case let (lhs, rhs) as (any EnumPersistable, String):
return lhs.rawValue > rhs
case let (lhs, rhs) as (String, any EnumPersistable):
return lhs > rhs.rawValue
case let (lhs, rhs) as (any EnumPersistable, any EnumPersistable):
return lhs.rawValue > rhs.rawValue
default:
return false
}
5 changes: 0 additions & 5 deletions Amplify/Categories/DataStore/Query/ModelKey.swift
Original file line number Diff line number Diff line change
@@ -36,11 +36,6 @@ public protocol ModelKey: CodingKey, CaseIterable, QueryFieldOperation {}

extension CodingKey where Self: ModelKey {

// MARK: - attributeExists
public func attributeExists(_ value: Bool) -> QueryPredicateOperation {
return field(stringValue).attributeExists(value)
}

// MARK: - beginsWith
public func beginsWith(_ value: String) -> QueryPredicateOperation {
return field(stringValue).beginsWith(value)
7 changes: 1 addition & 6 deletions Amplify/Categories/DataStore/Query/QueryField.swift
Original file line number Diff line number Diff line change
@@ -30,7 +30,7 @@ public func field(_ name: String) -> QueryField {
/// - seealso: `ModelKey`
public protocol QueryFieldOperation {
// MARK: - Functions
func attributeExists(_ value: Bool) -> QueryPredicateOperation

func beginsWith(_ value: String) -> QueryPredicateOperation
func between(start: Persistable, end: Persistable) -> QueryPredicateOperation
func contains(_ value: String) -> QueryPredicateOperation
@@ -61,11 +61,6 @@ public struct QueryField: QueryFieldOperation {

public let name: String

// MARK: - attributeExists
public func attributeExists(_ value: Bool) -> QueryPredicateOperation {
return QueryPredicateOperation(field: name, operator: .attributeExists(value))
}

// MARK: - beginsWith
public func beginsWith(_ value: String) -> QueryPredicateOperation {
return QueryPredicateOperation(field: name, operator: .beginsWith(value))
Original file line number Diff line number Diff line change
@@ -24,8 +24,6 @@ extension QueryOperator: Equatable {
case let (.between(oneStart, oneEnd), .between(otherStart, otherEnd)):
return PersistableHelper.isEqual(oneStart, otherStart)
&& PersistableHelper.isEqual(oneEnd, otherEnd)
case let (.attributeExists(one), .attributeExists(other)):
return one == other
default:
return false
}
19 changes: 4 additions & 15 deletions Amplify/Categories/DataStore/Query/QueryOperator.swift
Original file line number Diff line number Diff line change
@@ -18,9 +18,8 @@ public enum QueryOperator: Encodable {
case notContains(_ value: String)
case between(start: Persistable, end: Persistable)
case beginsWith(_ value: String)
case attributeExists(_ value: Bool)

public func evaluate(target: Any?) -> Bool {
public func evaluate(target: Any) -> Bool {
switch self {
case .notEqual(let predicateValue):
return !PersistableHelper.isEqual(target, predicateValue)
@@ -35,26 +34,20 @@ public enum QueryOperator: Encodable {
case .greaterThan(let predicateValue):
return PersistableHelper.isGreaterThan(target, predicateValue)
case .contains(let predicateString):
if let targetString = target.flatMap({ $0 as? String }) {
if let targetString = target as? String {
return targetString.contains(predicateString)
}
return false
case .notContains(let predicateString):
if let targetString = target.flatMap({ $0 as? String }) {
if let targetString = target as? String {
return !targetString.contains(predicateString)
}
case .between(let start, let end):
return PersistableHelper.isBetween(start, end, target)
case .beginsWith(let predicateValue):
if let targetString = target.flatMap({ $0 as? String }) {
if let targetString = target as? String {
return targetString.starts(with: predicateValue)
}
case .attributeExists(let predicateValue):
if case .some = target {
return predicateValue == true
} else {
return predicateValue == false
}
}
return false
}
@@ -112,10 +105,6 @@ public enum QueryOperator: Encodable {
case .beginsWith(let value):
try container.encode("beginsWith", forKey: .type)
try container.encode(value, forKey: .value)

case .attributeExists(let value):
try container.encode("attributeExists", forKey: .type)
try container.encode(value, forKey: .value)
}
}
}
30 changes: 29 additions & 1 deletion Amplify/Categories/DataStore/Query/QueryPredicate.swift
Original file line number Diff line number Diff line change
@@ -155,6 +155,34 @@ public class QueryPredicateOperation: QueryPredicate, Encodable {
}

public func evaluate(target: Model) -> Bool {
return self.operator.evaluate(target: target[field]?.flatMap { $0 })
guard let fieldValue = target[field] else {
return false
}

guard let value = fieldValue else {
return false
}

if let booleanValue = value as? Bool {
return self.operator.evaluate(target: booleanValue)
}

if let doubleValue = value as? Double {
return self.operator.evaluate(target: doubleValue)
}

if let intValue = value as? Int {
return self.operator.evaluate(target: intValue)
}

if let timeValue = value as? Temporal.Time {
return self.operator.evaluate(target: timeValue)
}

if let enumValue = value as? EnumPersistable {
return self.operator.evaluate(target: enumValue.rawValue)
}

return self.operator.evaluate(target: value)
}
}
Original file line number Diff line number Diff line change
@@ -145,56 +145,4 @@ extension GraphQLModelBasedTests {
XCTAssertNotNil(error)
}
}

/**
- Given: API with Post schema and optional field 'draft'
- When:
- create a new post with optional field 'draft' value .none
- Then:
- query Posts with filter {eq : null} shouldn't include the post
*/
func test_listModelsWithNilOptionalField_failedWithEqFilter() async throws {
let post = Post(title: UUID().uuidString, content: UUID().uuidString, createdAt: .now())
_ = try await Amplify.API.mutate(request: .create(post))
let posts = try await list(.list(
Post.self,
where: Post.keys.draft == nil && Post.keys.createdAt >= post.createdAt
))

XCTAssertFalse(posts.map(\.id).contains(post.id))
}

/**
- Given: DataStore with Post schema and optional field 'draft'
- When:
- create a new post with optional field 'draft' value .none
- Then:
- query Posts with filter {attributeExists : false} should include the post
*/
func test_listModelsWithNilOptionalField_successWithAttributeExistsFilter() async throws {
let post = Post(title: UUID().uuidString, content: UUID().uuidString, createdAt: .now())
_ = try await Amplify.API.mutate(request: .create(post))
let listPosts = try await list(
.list(
Post.self,
where: Post.keys.draft.attributeExists(false)
&& Post.keys.createdAt >= post.createdAt
)
)

XCTAssertTrue(listPosts.map(\.id).contains(post.id))
}

func list<M: Model>(_ request: GraphQLRequest<List<M>>) async throws -> [M] {
func getAllPages(_ list: List<M>) async throws -> [M] {
if list.hasNextPage() {
return list.elements + (try await getAllPages(list.getNextPage()))
} else {
return list.elements
}
}

return try await getAllPages(try await Amplify.API.query(request: request).get())
}

}
Original file line number Diff line number Diff line change
@@ -187,8 +187,6 @@ extension QueryOperator {
return "beginsWith"
case .notContains:
return "notContains"
case .attributeExists:
return "attributeExists"
}
}

@@ -214,8 +212,6 @@ extension QueryOperator {
return value
case .notContains(let value):
return value
case .attributeExists(let value):
return value
}
}
}
Original file line number Diff line number Diff line change
@@ -218,88 +218,4 @@ class GraphQLListQueryTests: XCTestCase {
XCTAssertEqual(variables["limit"] as? Int, 1_000)
XCTAssertNotNil(variables["filter"])
}

/**
- Given:
- A Post schema with optional field 'draft'
- When:
- Using list query to filter records that either don't have 'draft' field or have 'null' value
- Then:
- the query document as expected
- the filter is encoded correctly
*/
func test_listQuery_withAttributeExistsFilter_correctlyBuildGraphQLQueryStatement() {
let post = Post.keys
let predicate = post.id.eq("id")
&& (post.draft.attributeExists(false) || post.draft.eq(nil))

var documentBuilder = ModelBasedGraphQLDocumentBuilder(modelSchema: Post.schema, operationType: .query)
documentBuilder.add(decorator: DirectiveNameDecorator(type: .list))
documentBuilder.add(decorator: PaginationDecorator())
documentBuilder.add(decorator: FilterDecorator(filter: predicate.graphQLFilter(for: Post.schema)))
let document = documentBuilder.build()
let expectedQueryDocument = """
query ListPosts($filter: ModelPostFilterInput, $limit: Int) {
listPosts(filter: $filter, limit: $limit) {
items {
id
content
createdAt
draft
rating
status
title
updatedAt
__typename
}
nextToken
}
}
"""
XCTAssertEqual(document.name, "listPosts")
XCTAssertEqual(document.stringValue, expectedQueryDocument)
guard let variables = document.variables else {
XCTFail("The document doesn't contain variables")
return
}
XCTAssertNotNil(variables["limit"])
XCTAssertEqual(variables["limit"] as? Int, 1_000)

guard let filter = variables["filter"] as? GraphQLFilter else {
XCTFail("variables should contain a valid filter")
return
}

// Test filter for a valid JSON format
let filterJSON = try? JSONSerialization.data(withJSONObject: filter,
options: .prettyPrinted)
XCTAssertNotNil(filterJSON)

let expectedFilterJSON = """
{
"and" : [
{
"id" : {
"eq" : "id"
}
},
{
"or" : [
{
"draft" : {
"attributeExists" : false
}
},
{
"draft" : {
"eq" : null
}
}
]
}
]
}
"""
XCTAssertEqual(String(data: filterJSON!, encoding: .utf8), expectedFilterJSON)
}
}
Original file line number Diff line number Diff line change
@@ -41,7 +41,7 @@ class QueryPredicateEvaluateGeneratedBoolTests: XCTestCase {

let evaluation = try predicate.evaluate(target: instance.eraseToAnyModel().instance)

XCTAssertTrue(evaluation)
XCTAssertFalse(evaluation)
}

func testBoolfalsenotEqualBooltrue() throws {
@@ -70,7 +70,7 @@ class QueryPredicateEvaluateGeneratedBoolTests: XCTestCase {

let evaluation = try predicate.evaluate(target: instance.eraseToAnyModel().instance)

XCTAssertTrue(evaluation)
XCTAssertFalse(evaluation)
}

func testBooltrueequalsBooltrue() throws {
Loading

Unchanged files with check annotations Beta

func testExample() throws {
// UI tests must launch the application that they test.
let app = XCUIApplication()
app.launch()

Check failure on line 28 in canaries/example/MyAmplifyAppUITests/MyAmplifyAppUITests.swift

GitHub Actions / Canary Test - Xcode 15.0.1

testExample, Application 'my.org.MyAmplifyApp' does not have a process ID
// Use recording to get started writing UI tests.
// Use XCTAssert and related functions to verify your tests produce the correct results.