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

RCOCOA-2423 Fix the type signature of async User.functions #8670

Merged
merged 1 commit into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ x.y.z Release notes (yyyy-MM-dd)
non-null return value despite always returning `nil` (since v10.29.0).
* Eliminate several clang static analyzer warnings which did not report actual
bugs.
* The async and Future versions of `User.functions` only worked for functions
which took exactly one argument, which had to be an array ([#8669](https://github.com/realm/realm-swift/issues/8669), since 10.16.0).

### Compatibility
* Realm Studio: 15.0.0 or later.
Expand Down
2 changes: 1 addition & 1 deletion Realm/ObjectServerTests/AsyncSyncTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

import Realm
import Realm.Private
@_spi(RealmSwiftExperimental) import RealmSwift

Check notice on line 23 in Realm/ObjectServerTests/AsyncSyncTests.swift

View check run for this annotation

Xcode Cloud / RealmSwift | sync_15.1 | Test - macOS

Realm/ObjectServerTests/AsyncSyncTests.swift#L23

Add '@preconcurrency' to suppress 'Sendable'-related warnings from module 'RealmSwift'

Check notice on line 23 in Realm/ObjectServerTests/AsyncSyncTests.swift

View check run for this annotation

Xcode Cloud / RealmSwift | sync_16 beta 4 | Test - macOS

Realm/ObjectServerTests/AsyncSyncTests.swift#L23

Add '@preconcurrency' to suppress 'Sendable'-related warnings from module 'RealmSwift'
import XCTest

#if canImport(RealmTestSupport)
Expand Down Expand Up @@ -279,7 +279,7 @@

let configuration = try configuration()
func isolatedOpen(_ actor: isolated CustomExecutorActor) async throws {
_ = try await Realm(configuration: configuration, actor: actor, downloadBeforeOpen: .always)

Check notice on line 282 in Realm/ObjectServerTests/AsyncSyncTests.swift

View check run for this annotation

Xcode Cloud / RealmSwift | sync_15.1 | Test - macOS

Realm/ObjectServerTests/AsyncSyncTests.swift#L282

Non-sendable type 'Realm' returned by implicitly asynchronous call to nonisolated function cannot cross actor boundary

Check notice on line 282 in Realm/ObjectServerTests/AsyncSyncTests.swift

View check run for this annotation

Xcode Cloud / RealmSwift | sync_16 beta 4 | Test - macOS

Realm/ObjectServerTests/AsyncSyncTests.swift#L282

Non-sendable type 'Realm' returned by implicitly asynchronous call to nonisolated function cannot cross actor boundary; this is an error in the Swift 6 language mode
}

// Try opening the Realm with the Task being cancelled at every possible
Expand Down Expand Up @@ -349,8 +349,8 @@
}

func testUserCallFunctionAsyncAwait() async throws {
let user = try await self.app.login(credentials: basicCredentials())

Check notice on line 352 in Realm/ObjectServerTests/AsyncSyncTests.swift

View check run for this annotation

Xcode Cloud / RealmSwift | sync_16 beta 4 | Test - macOS

Realm/ObjectServerTests/AsyncSyncTests.swift#L352

Sending main actor-isolated value of type 'Credentials' with later accesses to nonisolated context risks causing data races; this is an error in the Swift 6 language mode
guard case let .int32(sum) = try await user.functions.sum([1, 2, 3, 4, 5]) else {
guard case let .int32(sum) = try await user.functions.sum(.array([1, 2, 3, 4, 5])) else {
return XCTFail("Should be int32")
}
XCTAssertEqual(sum, 15)
Expand Down Expand Up @@ -422,7 +422,7 @@
["favourite_colour": "green", "apples": 10]
])

try await user.refreshCustomData()

Check notice on line 425 in Realm/ObjectServerTests/AsyncSyncTests.swift

View check run for this annotation

Xcode Cloud / RealmSwift | sync_15.1 | Test - macOS

Realm/ObjectServerTests/AsyncSyncTests.swift#L425

Non-sendable type '[AnyHashable : Any]' returned by implicitly asynchronous call to nonisolated function cannot cross actor boundary

Check notice on line 425 in Realm/ObjectServerTests/AsyncSyncTests.swift

View check run for this annotation

Xcode Cloud / RealmSwift | sync_16 beta 4 | Test - macOS

Realm/ObjectServerTests/AsyncSyncTests.swift#L425

Non-sendable type '[AnyHashable : Any]' returned by implicitly asynchronous call to nonisolated function cannot cross actor boundary; this is an error in the Swift 6 language mode
XCTAssertEqual(user.customData["favourite_colour"], .string("green"))
XCTAssertEqual(user.customData["apples"], .int64(10))
}
Expand Down Expand Up @@ -875,7 +875,7 @@
let user = try await createUser()
var config = user.flexibleSyncConfiguration()
config.objectTypes = [SwiftPerson.self]
let realm = try await Realm(configuration: config, actor: MainActor.shared)

Check notice on line 878 in Realm/ObjectServerTests/AsyncSyncTests.swift

View check run for this annotation

Xcode Cloud / RealmSwift | sync_15.1 | Test - macOS

Realm/ObjectServerTests/AsyncSyncTests.swift#L878

Non-sendable type 'Realm' returned by implicitly asynchronous call to nonisolated function cannot cross actor boundary

Check notice on line 878 in Realm/ObjectServerTests/AsyncSyncTests.swift

View check run for this annotation

Xcode Cloud / RealmSwift | sync_16 beta 4 | Test - macOS

Realm/ObjectServerTests/AsyncSyncTests.swift#L878

Non-sendable type 'Realm' returned by implicitly asynchronous call to nonisolated function cannot cross actor boundary; this is an error in the Swift 6 language mode
let results1 = try await realm.objects(SwiftPerson.self)
.where { $0.firstName == name && $0.age > 8 }.subscribe(waitForSync: .onCreation)
XCTAssertEqual(results1.count, 2)
Expand All @@ -895,7 +895,7 @@
let user = try await createUser()
var config = user.flexibleSyncConfiguration()
config.objectTypes = [SwiftPerson.self]
let realm = try await Realm(configuration: config, actor: CustomGlobalActor.shared)

Check notice on line 898 in Realm/ObjectServerTests/AsyncSyncTests.swift

View check run for this annotation

Xcode Cloud / RealmSwift | sync_15.1 | Test - macOS

Realm/ObjectServerTests/AsyncSyncTests.swift#L898

Non-sendable type 'Realm' returned by implicitly asynchronous call to nonisolated function cannot cross actor boundary

Check notice on line 898 in Realm/ObjectServerTests/AsyncSyncTests.swift

View check run for this annotation

Xcode Cloud / RealmSwift | sync_16 beta 4 | Test - macOS

Realm/ObjectServerTests/AsyncSyncTests.swift#L898

Non-sendable type 'Realm' returned by implicitly asynchronous call to nonisolated function cannot cross actor boundary; this is an error in the Swift 6 language mode
let results1 = try await realm.objects(SwiftPerson.self)
.where { $0.firstName == name && $0.age > 8 }.subscribe(waitForSync: .onCreation)
XCTAssertEqual(results1.count, 2)
Expand Down
2 changes: 1 addition & 1 deletion Realm/ObjectServerTests/SwiftObjectServerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -571,7 +571,7 @@
proxy.stop()
}

class LocationOverrideTransport: RLMNetworkTransport, Sendable {

Check notice on line 574 in Realm/ObjectServerTests/SwiftObjectServerTests.swift

View check run for this annotation

Xcode Cloud / RealmSwift | sync_16 beta 4 | Test - macOS

Realm/ObjectServerTests/SwiftObjectServerTests.swift#L574

Class 'LocationOverrideTransport' must restate inherited '@unchecked Sendable' conformance
let hostname: String
let wsHostname: String
init(hostname: String = "http://localhost:9090", wsHostname: String = "ws://invalid.com:9090") {
Expand Down Expand Up @@ -893,7 +893,7 @@
let credentials = Credentials.emailPassword(email: email, password: password)
let syncUser = app.login(credentials: credentials).await(self)

let bson = syncUser.functions.sum([1, 2, 3, 4, 5]).await(self)
let bson = syncUser.functions.sum(.array([1, 2, 3, 4, 5])).await(self)
guard case let .int32(sum) = bson else {
XCTFail("unexpected bson type in sum: \(bson)")
return
Expand Down
40 changes: 33 additions & 7 deletions RealmSwift/Sync.swift
Original file line number Diff line number Diff line change
Expand Up @@ -667,19 +667,34 @@ public struct FunctionCallable: Sendable {
fileprivate let name: String
fileprivate let user: User

/// :nodoc:
@available(*, deprecated, message: "Explicitly specify .array(arg)")
@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
public func dynamicallyCall(withArguments args: [[AnyBSON]]) -> Future<AnyBSON, Error> {
return future { promise in
let objcArgs = args.first!.map(ObjectiveCSupport.convertBson)
self.user.__callFunctionNamed(name, arguments: objcArgs) { (bson: RLMBSON?, error: Error?) in
if let b = bson.map(ObjectiveCSupport.convertBson), let bson = b {
promise(.success(bson))
} else {
promise(.failure(error ?? Realm.Error.callFailed))
}
}
}
}

/// The implementation of @dynamicCallable that allows for `Future<AnyBSON, Error>` callable return.
///
/// let cancellable = user.functions.sum([1, 2, 3, 4, 5])
/// let cancellable = user.functions.sum(.array([1, 2, 3, 4, 5]))
/// .sink(receiveCompletion: { result in
/// }, receiveValue: { value in
/// // Returned value from function
/// })
///
@preconcurrency
@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
public func dynamicallyCall(withArguments args: [[AnyBSON]]) -> Future<AnyBSON, Error> {
public func dynamicallyCall(withArguments args: [AnyBSON]) -> Future<AnyBSON, Error> {
return future { promise in
let objcArgs = args.first!.map(ObjectiveCSupport.convertBson)
let objcArgs = args.map(ObjectiveCSupport.convertBson)
self.user.__callFunctionNamed(name, arguments: objcArgs) { (bson: RLMBSON?, error: Error?) in
if let b = bson.map(ObjectiveCSupport.convertBson), let bson = b {
promise(.success(bson))
Expand Down Expand Up @@ -1134,14 +1149,25 @@ public extension User {

@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
extension FunctionCallable {
/// :nodoc:
@available(*, deprecated, message: "Explicitly specify .array(arg)")
public func dynamicallyCall(withArguments args: [[AnyBSON]]) async throws -> AnyBSON {
let objcArgs = args.first!.map(ObjectiveCSupport.convertBson)
let ret = try await user.__callFunctionNamed(name, arguments: objcArgs)
if let bson = ObjectiveCSupport.convertBson(object: ret) {
return bson
}
throw Realm.Error.callFailed
}

/// The implementation of @dynamicMemberLookup that allows for `async await` callable return.
///
/// guard case let .int32(sum) = try await user.functions.sum([1, 2, 3, 4, 5]) else {
/// guard case let .int32(sum) = try await user.functions.sum(.array([1, 2, 3, 4, 5])) else {
/// return
/// }
///
public func dynamicallyCall(withArguments args: [[AnyBSON]]) async throws -> AnyBSON {
let objcArgs = args.first!.map(ObjectiveCSupport.convertBson)
public func dynamicallyCall(withArguments args: [AnyBSON]) async throws -> AnyBSON {
let objcArgs = args.map(ObjectiveCSupport.convertBson)
let ret = try await user.__callFunctionNamed(name, arguments: objcArgs)
if let bson = ObjectiveCSupport.convertBson(object: ret) {
return bson
Expand Down
Loading