Skip to content

Commit

Permalink
Move initial subscription logic into Core
Browse files Browse the repository at this point in the history
  • Loading branch information
nirinchev committed Apr 15, 2024
1 parent 2f0274f commit 04969a5
Show file tree
Hide file tree
Showing 19 changed files with 247 additions and 53 deletions.
1 change: 1 addition & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ let package = Package(
"Realm/RLMEmailPasswordAuth.mm",
"Realm/RLMFindOneAndModifyOptions.mm",
"Realm/RLMFindOptions.mm",
"Realm/RLMInitialSubscriptionsConfiguration.m",
"Realm/RLMMongoClient.mm",
"Realm/RLMMongoCollection.mm",
"Realm/RLMNetworkTransport.mm",
Expand Down
1 change: 1 addition & 0 deletions Realm.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ Pod::Spec.new do |s|
'include/RLMApp.h',
'include/RLMAppCredentials.h',
'include/RLMBSON.h',
'include/RLMInitialSubscriptionsConfiguration.h',
'include/RLMNetworkTransport.h',
'include/RLMPushClient.h',
'include/RLMProviderClient.h',
Expand Down
10 changes: 10 additions & 0 deletions Realm.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,12 @@
0C3BD4B325C1BDF1007CFDD3 /* RLMDictionary.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0C3BD4B125C1BDF1007CFDD3 /* RLMDictionary.mm */; };
0C3BD4D325C1C5AB007CFDD3 /* Map.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C3BD4D225C1C5AB007CFDD3 /* Map.swift */; };
0C5796A225643D7500744CAE /* RLMUUID.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0C57969F25643D7500744CAE /* RLMUUID.mm */; };
0C63BB902BCD787300E25C3A /* RLMInitialSubscriptionsConfiguration.h in Sources */ = {isa = PBXBuildFile; fileRef = 0CC270AB2BCD665800788EE1 /* RLMInitialSubscriptionsConfiguration.h */; };
0C86B33925E15B6000775FED /* PrimitiveDictionaryPropertyTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C86B33825E15B6000775FED /* PrimitiveDictionaryPropertyTests.m */; };
0C9758BF264974660097B48D /* SwiftRLMDictionaryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C9758BE264974660097B48D /* SwiftRLMDictionaryTests.swift */; };
0CBF2DB927286FFD00635902 /* ProjectedCollectTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CBF2DB827286FFD00635902 /* ProjectedCollectTests.swift */; };
0CC270AA2BCD664200788EE1 /* RLMInitialSubscriptionsConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CC270A92BCD664200788EE1 /* RLMInitialSubscriptionsConfiguration.m */; };
0CC270AC2BCD665800788EE1 /* RLMInitialSubscriptionsConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 0CC270AB2BCD665800788EE1 /* RLMInitialSubscriptionsConfiguration.h */; settings = {ATTRIBUTES = (Public, ); }; };
0CD1632826D3DF1D0027C49B /* ProjectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CD1632726D3DF1C0027C49B /* ProjectionTests.swift */; };
0CED6DB82655087200B80277 /* RLMDictionary_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C3BD50125C1DE6F007CFDD3 /* RLMDictionary_Private.h */; settings = {ATTRIBUTES = (Private, ); }; };
1A0512771D8746CD00806AEC /* RLMSyncConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A3623651D8384BA00945A54 /* RLMSyncConfiguration.h */; settings = {ATTRIBUTES = (Public, ); }; };
Expand Down Expand Up @@ -628,6 +631,8 @@
0C86B33825E15B6000775FED /* PrimitiveDictionaryPropertyTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PrimitiveDictionaryPropertyTests.m; sourceTree = "<group>"; };
0C9758BE264974660097B48D /* SwiftRLMDictionaryTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftRLMDictionaryTests.swift; sourceTree = "<group>"; };
0CBF2DB827286FFD00635902 /* ProjectedCollectTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProjectedCollectTests.swift; sourceTree = "<group>"; };
0CC270A92BCD664200788EE1 /* RLMInitialSubscriptionsConfiguration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RLMInitialSubscriptionsConfiguration.m; sourceTree = "<group>"; };
0CC270AB2BCD665800788EE1 /* RLMInitialSubscriptionsConfiguration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RLMInitialSubscriptionsConfiguration.h; sourceTree = "<group>"; };
0CD1632526D3DD7B0027C49B /* Projection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Projection.swift; sourceTree = "<group>"; };
0CD1632726D3DF1C0027C49B /* ProjectionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProjectionTests.swift; sourceTree = "<group>"; };
1A0512731D87413000806AEC /* RLMSyncUtil_Private.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = RLMSyncUtil_Private.hpp; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1200,6 +1205,8 @@
4993220324129DCD00A0EC8E /* RLMCredentials.h */,
4993220424129DCD00A0EC8E /* RLMCredentials.mm */,
4993220224129DCD00A0EC8E /* RLMCredentials_Private.hpp */,
0CC270AB2BCD665800788EE1 /* RLMInitialSubscriptionsConfiguration.h */,
0CC270A92BCD664200788EE1 /* RLMInitialSubscriptionsConfiguration.m */,
4993221524129E6600A0EC8E /* RLMNetworkTransport.h */,
4993221424129E6500A0EC8E /* RLMNetworkTransport.mm */,
CF330BBB24E56E3A00F07EE2 /* RLMNetworkTransport_Private.hpp */,
Expand Down Expand Up @@ -1906,6 +1913,7 @@
6807E64F2487F9210096066F /* RLMPushClient_Private.hpp in Headers */,
1AD397CF1F72FFC7002AA897 /* RLMRealm+Sync.h in Headers */,
5D659EBF1BE04556006515A0 /* RLMRealm.h in Headers */,
0CC270AC2BCD665800788EE1 /* RLMInitialSubscriptionsConfiguration.h in Headers */,
5D659EC01BE04556006515A0 /* RLMRealm_Dynamic.h in Headers */,
5D659EC11BE04556006515A0 /* RLMRealm_Private.h in Headers */,
5D659EC21BE04556006515A0 /* RLMRealmConfiguration.h in Headers */,
Expand Down Expand Up @@ -2454,6 +2462,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0C63BB902BCD787300E25C3A /* RLMInitialSubscriptionsConfiguration.h in Sources */,
3F73BC961E3A878500FE80B6 /* NSError+RLMSync.m in Sources */,
5D659E851BE04556006515A0 /* RLMAccessor.mm in Sources */,
5D659E861BE04556006515A0 /* RLMAnalytics.mm in Sources */,
Expand Down Expand Up @@ -2513,6 +2522,7 @@
531F956C27906F7600E497F1 /* RLMSyncSubscription.mm in Sources */,
1A84132F1D4BCCE600C5326F /* RLMSyncUtil.mm in Sources */,
3F67DB3E1E26D69C0024533D /* RLMThreadSafeReference.mm in Sources */,
0CC270AA2BCD664200788EE1 /* RLMInitialSubscriptionsConfiguration.m in Sources */,
5D659E9A1BE04556006515A0 /* RLMUpdateChecker.mm in Sources */,
CF76F7DD24816AAB00890DD2 /* RLMUpdateResult.mm in Sources */,
1ABDCDB01D793008003489E3 /* RLMUser.mm in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,16 @@
value = "1"
isEnabled = "YES">
</EnvironmentVariable>
<EnvironmentVariable
key = "AWS_ACCESS_KEY_ID"
value = "ASIA6DOYLZRMQXGYNKWS"
isEnabled = "YES">
</EnvironmentVariable>
<EnvironmentVariable
key = "AWS_SECRET_ACCESS_KEY"
value = "d5G0xWLqfJNpZBNLmj7Wov+2Yd9LdSX6SAKBEtVc"
isEnabled = "YES">
</EnvironmentVariable>
</EnvironmentVariables>
<EnvironmentVariable
key = "key"
Expand Down
58 changes: 58 additions & 0 deletions Realm/ObjectServerTests/AsyncSyncTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,11 @@ class AsyncFlexibleSyncTests: SwiftSyncTestCase {
})
})
config.objectTypes = [SwiftPerson.self]

XCTAssertNotNil(config.syncConfiguration?.initialSubscriptions)
XCTAssertNotNil(config.syncConfiguration?.initialSubscriptions?.callback)
XCTAssertEqual(config.syncConfiguration?.initialSubscriptions?.rerunOnOpen, false)

let realm = try await Realm(configuration: config, downloadBeforeOpen: .once)
XCTAssertEqual(realm.subscriptions.count, 1)
checkCount(expected: 10, realm, SwiftPerson.self)
Expand Down Expand Up @@ -644,6 +649,11 @@ class AsyncFlexibleSyncTests: SwiftSyncTestCase {
}
}, rerunOnOpen: true)
config.objectTypes = [SwiftPerson.self]

XCTAssertNotNil(config.syncConfiguration?.initialSubscriptions)
XCTAssertNotNil(config.syncConfiguration?.initialSubscriptions?.callback)
XCTAssertEqual(config.syncConfiguration?.initialSubscriptions?.rerunOnOpen, false)

try await Task {
let realm = try await Realm(configuration: config, downloadBeforeOpen: .once)
XCTAssertEqual(realm.subscriptions.count, 1)
Expand Down Expand Up @@ -729,6 +739,54 @@ class AsyncFlexibleSyncTests: SwiftSyncTestCase {
XCTAssertEqual(realm.subscriptions.count, 1)
}

@MainActor
func testFlexibleSyncInitialSubscriptionsConfiguredViaProperty() async throws {
let user = try await createUser()
var config = user.flexibleSyncConfiguration()
config.syncConfiguration!.initialSubscriptions = InitialSubscriptionsConfiguration(callback: { subscriptions in
subscriptions.append(QuerySubscription<SwiftPerson>() {
$0.age > 10 && $0.firstName == "\(self.name)"
})
})
config.objectTypes = [SwiftPerson.self]
let realm = try await Realm(configuration: config, downloadBeforeOpen: .once)
XCTAssertEqual(realm.subscriptions.count, 1)

let realm2 = try await Realm(configuration: config, downloadBeforeOpen: .once)
XCTAssertNotNil(realm2)
XCTAssertEqual(realm.subscriptions.count, 1)
}

@MainActor
func testFlexibleSyncInitialSubscriptionsConfiguredViaPropertyRerunOnOpen() async throws {
let user = try await createUser()
var config = user.flexibleSyncConfiguration()
let invocations = Locked(0)
config.syncConfiguration!.initialSubscriptions = InitialSubscriptionsConfiguration(callback: { subscriptions in
invocations.withLock { invocations in
invocations += 1
}
subscriptions.append(QuerySubscription<SwiftPerson>() {
$0.age > invocations.wrappedValue
})
}, rerunOnOpen: true)
config.objectTypes = [SwiftPerson.self]

let c = config
try await Task {
let realm = try await Realm(configuration: c, downloadBeforeOpen: .once)
XCTAssertEqual(realm.subscriptions.count, 1)
}.value

try await Task {
let realm = try await Realm(configuration: c, downloadBeforeOpen: .once)
XCTAssertEqual(realm.subscriptions.count, 2)
}.value

XCTAssertEqual(invocations.wrappedValue, 2)
}


// MARK: Subscribe

@MainActor
Expand Down
45 changes: 45 additions & 0 deletions Realm/RLMInitialSubscriptionsConfiguration.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
////////////////////////////////////////////////////////////////////////////
//
// Copyright 2024 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////


#import <Foundation/Foundation.h>
#import <Realm/RLMRealm.h>

RLM_HEADER_AUDIT_BEGIN(nullability, sendability)

/**
A block which receives a subscription set instance, that can be used to add an initial set of subscriptions which will be executed
when the Realm is first opened.
*/
RLM_SWIFT_SENDABLE
typedef void(^RLMFlexibleSyncInitialSubscriptionsBlock)(RLMSyncSubscriptionSet * _Nonnull subscriptions);

@interface RLMInitialSubscriptionsConfiguration : NSObject

/**
A callback that's executed when a Realm is first created or every time it's opened if `rerunOnOpen` is true.
*/
@property (nonatomic, readonly) RLMFlexibleSyncInitialSubscriptionsBlock callback;
@property (nonatomic, readonly) BOOL rerunOnOpen;

-(id)initWithCallback:(RLMFlexibleSyncInitialSubscriptionsBlock)callback rerunOnOpen: (BOOL)rerunOnOpen;
-(id)initWithCallback:(RLMFlexibleSyncInitialSubscriptionsBlock)callback;

@end

RLM_HEADER_AUDIT_END(nullability, sendability)
36 changes: 36 additions & 0 deletions Realm/RLMInitialSubscriptionsConfiguration.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
////////////////////////////////////////////////////////////////////////////
//
// Copyright 2024 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////


#import "RLMInitialSubscriptionsConfiguration.h"

@implementation RLMInitialSubscriptionsConfiguration

-(id)initWithCallback:(RLMFlexibleSyncInitialSubscriptionsBlock)callback
{
return [self initWithCallback: callback rerunOnOpen: false];
}

-(id)initWithCallback:(RLMFlexibleSyncInitialSubscriptionsBlock)callback rerunOnOpen: (BOOL)rerunOnOpen
{
_callback = callback;
_rerunOnOpen = rerunOnOpen;
return self;
}

@end
19 changes: 1 addition & 18 deletions Realm/RLMRealm.mm
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,6 @@ + (instancetype)realmWithConfiguration:(RLMRealmConfiguration *)configuration
}
}

bool isFirstOpen = false;
if (realm->_schema) { }
else if (dynamic) {
realm->_schema = [RLMSchema dynamicSchemaFromObjectStoreSchema:realm->_realm->schema()];
Expand Down Expand Up @@ -482,16 +481,9 @@ + (instancetype)realmWithConfiguration:(RLMRealmConfiguration *)configuration
};
}

DataInitializationFunction initializationFunction;
if (!configuration.rerunOnOpen && configuration.initialSubscriptions) {
initializationFunction = [&isFirstOpen](SharedRealm) {
isFirstOpen = true;
};
}

try {
realm->_realm->update_schema(schema.objectStoreCopy, config.schema_version,
std::move(migrationFunction), std::move(initializationFunction));
std::move(migrationFunction));
}
catch (...) {
RLMRealmTranslateException(error);
Expand Down Expand Up @@ -522,15 +514,6 @@ + (instancetype)realmWithConfiguration:(RLMRealmConfiguration *)configuration
realm->_realm->m_binding_context->realm = realm->_realm;
}

#if REALM_ENABLE_SYNC
if (isFirstOpen || (configuration.rerunOnOpen && !realmIsCached)) {
RLMSyncSubscriptionSet *subscriptions = realm.subscriptions;
[subscriptions update:^{
configuration.initialSubscriptions(subscriptions);
}];
}
#endif

// Run Analytics and Update checker, this will be run only the first any realm open
[self runFirstCheckForConfiguration:configuration schema:realm.schema];

Expand Down
7 changes: 0 additions & 7 deletions Realm/RLMRealmConfiguration.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,6 @@ RLM_HEADER_AUDIT_BEGIN(nullability, sendability)
RLM_SWIFT_SENDABLE
typedef BOOL (^RLMShouldCompactOnLaunchBlock)(NSUInteger totalBytes, NSUInteger bytesUsed);

/**
A block which receives a subscription set instance, that can be used to add an initial set of subscriptions which will be executed
when the Realm is first opened.
*/
RLM_SWIFT_SENDABLE
typedef void(^RLMFlexibleSyncInitialSubscriptionsBlock)(RLMSyncSubscriptionSet * _Nonnull subscriptions);

/**
An `RLMRealmConfiguration` instance describes the different options used to
create an instance of a Realm.
Expand Down
2 changes: 0 additions & 2 deletions Realm/RLMRealmConfiguration.mm
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,6 @@ - (instancetype)copyWithZone:(NSZone *)zone {
configuration->_customSchema = _customSchema;
configuration->_eventConfiguration = _eventConfiguration;
configuration->_migrationObjectClass = _migrationObjectClass;
configuration->_initialSubscriptions = _initialSubscriptions;
configuration->_rerunOnOpen = _rerunOnOpen;
return configuration;
}

Expand Down
4 changes: 0 additions & 4 deletions Realm/RLMRealmConfiguration_Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,6 @@ RLM_HEADER_AUDIT_BEGIN(nullability)
@property (nonatomic, nullable) Class migrationObjectClass;
@property (nonatomic) bool disableAutomaticChangeNotifications;

// Flexible Sync
@property (nonatomic, readwrite, nullable) RLMFlexibleSyncInitialSubscriptionsBlock initialSubscriptions;
@property (nonatomic, readwrite) BOOL rerunOnOpen;

// Get the default configuration without copying it
+ (RLMRealmConfiguration *)rawDefaultConfiguration;

Expand Down
7 changes: 7 additions & 0 deletions Realm/RLMSyncConfiguration.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@
#import <Foundation/Foundation.h>

#import <Realm/RLMSyncManager.h>
#import <Realm/RLMInitialSubscriptionsConfiguration.h>

@class RLMApp;
@class RLMRealm;
@class RLMRealmConfiguration;
@class RLMUser;
@class RLMInitialSubscriptionsConfiguration;
@protocol RLMBSON;

RLM_HEADER_AUDIT_BEGIN(nullability, sendability)
Expand Down Expand Up @@ -175,6 +177,11 @@ typedef void(^RLMClientResetAfterBlock)(RLMRealm * _Nonnull beforeFrozen, RLMRea
*/
@property (nonatomic, nullable) RLMSyncErrorReportingBlock manualClientResetHandler;

/**
A configuration that controls how initial subscriptions are populated when the Realm is opened.
@see `RLMInitialSubscriptionsConfiguration`
*/
@property (nonatomic, readwrite, nullable) RLMInitialSubscriptionsConfiguration *initialSubscriptions;

/**
Whether nonfatal connection errors should cancel async opens.
Expand Down
Loading

0 comments on commit 04969a5

Please sign in to comment.