RLMSyncSubscription.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. ////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright 2018 Realm Inc.
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the "License");
  6. // you may not use this file except in compliance with the License.
  7. // You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS,
  13. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. //
  17. ////////////////////////////////////////////////////////////////////////////
  18. #import <Realm/RLMRealm.h>
  19. #import <Realm/RLMResults.h>
  20. NS_ASSUME_NONNULL_BEGIN
  21. /**
  22. `RLMSyncSubscriptionState` is an enumeration representing the possible state of a sync subscription.
  23. */
  24. typedef RLM_CLOSED_ENUM(NSInteger, RLMSyncSubscriptionState) {
  25. /**
  26. An error occurred while creating the subscription or while the server was processing it.
  27. */
  28. RLMSyncSubscriptionStateError = -1,
  29. /**
  30. The subscription is being created, but has not yet been written to the synced Realm.
  31. */
  32. RLMSyncSubscriptionStateCreating = 2,
  33. /**
  34. The subscription has been created, and is waiting to be processed by the server.
  35. */
  36. RLMSyncSubscriptionStatePending = 0,
  37. /**
  38. The subscription has been processed by the server, and objects matching the subscription
  39. are now being synchronized to this client.
  40. */
  41. RLMSyncSubscriptionStateComplete = 1,
  42. /**
  43. This subscription has been removed.
  44. */
  45. RLMSyncSubscriptionStateInvalidated = 3,
  46. };
  47. /**
  48. `RLMSyncSubscription` represents a subscription to a set of objects in a synced Realm.
  49. When query-based sync is enabled for a synchronized Realm, the server only
  50. synchronizes objects to the client when they match a sync subscription
  51. registered by that client. A subscription consists of of a query (represented
  52. by an `RLMResults`) and an optional name.
  53. The state of the subscription can be observed using
  54. [Key-Value Observing](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html)
  55. on the `state` property.
  56. Subscriptions are created using `-[RLMResults subscribe]` or
  57. `-[RLMResults subscribeWithName:]`. Existing subscriptions for a Realm can be
  58. looked up with `-[RLMRealm subscriptions]` or `-[RLMRealm subscriptionWithName:]`.
  59. */
  60. @interface RLMSyncSubscription : NSObject
  61. /**
  62. The unique name for this subscription.
  63. This will be `nil` if this object was created with `-[RLMResults subscribe]`.
  64. Subscription objects read from a Realm with `-[RLMRealm subscriptions]` will
  65. always have a non-`nil` name and subscriptions which were not explicitly named
  66. will have an automatically generated one.
  67. */
  68. @property (nonatomic, readonly, nullable) NSString *name;
  69. /**
  70. The current state of the subscription. See `RLMSyncSubscriptionState`.
  71. */
  72. @property (nonatomic, readonly) RLMSyncSubscriptionState state;
  73. /**
  74. The error which occurred when registering this subscription, if any.
  75. Will be non-nil only when `state` is `RLMSyncSubscriptionStateError`.
  76. */
  77. @property (nonatomic, readonly, nullable) NSError *error;
  78. /**
  79. The raw query which this subscription is running on the server.
  80. This string is a serialized representation of the RLMResults which the
  81. subscription was created from. This representation does *not* use NSPredicate
  82. syntax, and is not guaranteed to remain consistent between versions of Realm.
  83. Any use of this other than manual inspection when debugging is likely to be
  84. incorrect.
  85. This is `nil` while the subscription is in the Creating state.
  86. */
  87. @property (nonatomic, readonly, nullable) NSString *query;
  88. /**
  89. When this subscription was first created.
  90. This value will be `nil` for subscriptions created with older versions of Realm
  91. which did not store the creation date. Newly created subscriptions should
  92. always have a non-nil creation date.
  93. */
  94. @property (nonatomic, readonly, nullable) NSDate *createdAt;
  95. /**
  96. When this subscription was last updated.
  97. This value will be `nil` for subscriptions created with older versions of Realm
  98. which did not store the update date. Newly created subscriptions should
  99. always have a non-nil update date.
  100. The update date is the time when the subscription was last updated by a call
  101. to `-[RLMResults subscribeWithOptions:]`, and not when the set of objects which
  102. match the subscription last changed.
  103. */
  104. @property (nonatomic, readonly, nullable) NSDate *updatedAt;
  105. /**
  106. When this subscription will be automatically removed.
  107. If the `timeToLive` parameter is set when creating a sync subscription, the
  108. subscription will be automatically removed the first time that any subscription
  109. is created, modified, or deleted after that time has elapsed.
  110. This property will be `nil` if the `timeToLive` option was not enabled.
  111. */
  112. @property (nonatomic, readonly, nullable) NSDate *expiresAt;
  113. /**
  114. How long this subscription will persist after last being updated.
  115. If the `timeToLive` parameter is set when creating a sync subscription, the
  116. subscription will be automatically removed the first time that any subscription
  117. is created, modified, or deleted after that time has elapsed.
  118. This property will be NaN if the `timeToLive` option was not enabled.
  119. */
  120. @property (nonatomic, readonly) NSTimeInterval timeToLive;
  121. /**
  122. Remove this subscription.
  123. Removing a subscription will delete all objects from the local Realm that were
  124. matched only by that subscription and not any remaining subscriptions. The
  125. deletion is performed by the server, and so has no immediate impact on the
  126. contents of the local Realm. If the device is currently offline, the removal
  127. will not be processed until the device returns online.
  128. Unsubscribing is an asynchronous operation and will not immediately remove the
  129. subscription from the Realm's list of subscriptions. Observe the state property
  130. to be notified of when the subscription has actually been removed.
  131. */
  132. - (void)unsubscribe;
  133. #pragma mark - Unavailable Methods
  134. /**
  135. `-[RLMSyncSubscription init]` is not available because `RLMSyncSubscription` cannot be created directly.
  136. */
  137. - (instancetype)init __attribute__((unavailable("RLMSyncSubscription cannot be created directly")));
  138. /**
  139. `+[RLMSyncSubscription new]` is not available because `RLMSyncSubscription` cannot be created directly.
  140. */
  141. + (instancetype)new __attribute__((unavailable("RLMSyncSubscription cannot be created directly")));
  142. @end
  143. /**
  144. Configuration options for query-based sync subscriptions.
  145. */
  146. @interface RLMSyncSubscriptionOptions : NSObject
  147. /**
  148. The name of the subscription.
  149. Naming a subscription makes it possible to look up a subscription by name
  150. (using `-[RLMRealm subscriptionWithName:]`) or update an existing
  151. subscription rather than creating a new one.
  152. */
  153. @property (nonatomic, copy, nullable) NSString *name;
  154. /**
  155. Whether this should update an existing subscription with the same name.
  156. By default trying to create a subscription with a name that's already in use
  157. will fail unless the new subscription is an exact match for the existing one.
  158. If this is set to YES, instead the existing subscription will be updated using
  159. the query and options from the new subscription. This only works if the new
  160. subscription is for the same type of objects as the existing subscription.
  161. Trying to overwrite a subscription with a subscription of a different type of
  162. objects will fail.
  163. The `updatedAt` and (if `timeToLive` is used) `expiresAt` properties are
  164. updated whenever a subscription is overwritten even if nothing else has changed.
  165. */
  166. @property (nonatomic) BOOL overwriteExisting;
  167. /**
  168. How long (in seconds) a subscription should persist after being created.
  169. By default subscriptions are persistent, and last until they are explicitly
  170. removed by calling `unsubscribe()`. Subscriptions can instead be made temporary
  171. by setting the time to live to how long the subscription should remain. After
  172. that time has elapsed the subscription will be automatically removed.
  173. A time to live of 0 or less disables subscription expiration.
  174. */
  175. @property (nonatomic) NSTimeInterval timeToLive;
  176. /**
  177. The maximum number of top-level matches to include in this subscription.
  178. If more top-level objects than the limit match the query, only the first
  179. `limit` objects will be included. This respects the sort and distinct order of
  180. the query being subscribed to for the determination of what the "first" objects
  181. are.
  182. The limit does not count or apply to objects which are added indirectly due to
  183. being linked to by the objects in the subscription or due to being listed in
  184. `includeLinkingObjectProperties`. If the limit is larger than the number of
  185. objects which match the query, all objects will be included. A limit of zero is
  186. treated as unlimited.
  187. */
  188. @property (nonatomic) NSUInteger limit;
  189. /**
  190. Which RLMLinkingObjects properties should be included in the subscription.
  191. Outgoing links (i.e. `RLMArray` and `RLMObject` properties) are automatically
  192. included in sync subscriptions. That is, if you subscribe to a query which
  193. matches one object, every object which is reachable via links from that object
  194. are also included in the subscription.
  195. By default, RLMLinkingObjects properties do not work this way. Instead, they
  196. only report objects which happen to be included in a subscription. By naming
  197. a RLMLinkingObjects property in this array, it can instead be treated as if
  198. it was a RLMArray and include all objects which link to this object.
  199. Any keypath which ends in a RLMLinkingObject property can be included in this
  200. array, including ones involving intermediate links.
  201. */
  202. @property (nonatomic, copy, nullable) NSArray<NSString *> *includeLinkingObjectProperties;
  203. @end
  204. /**
  205. Support for subscribing to the results of object queries in a synced Realm.
  206. */
  207. @interface RLMResults (SyncSubscription)
  208. /**
  209. Subscribe to the query represented by this `RLMResults`.
  210. Subscribing to a query asks the server to synchronize all objects to the
  211. client which match the query, along with all objects which are reachable
  212. from those objects via links. This happens asynchronously, and the local
  213. client Realm may not immediately have all objects which match the query.
  214. Observe the `state` property of the returned subscription object to be
  215. notified of when the subscription has been processed by the server and
  216. all objects matching the query are available.
  217. The subscription will not be explicitly named. A name will be automatically
  218. generated for internal use. The exact format of this name may change without
  219. warning and should not be depended on.
  220. @return An object representing the newly-created subscription.
  221. @see RLMSyncSubscription
  222. */
  223. - (RLMSyncSubscription *)subscribe;
  224. /**
  225. Subscribe to the query represented by this `RLMResults`.
  226. Subscribing to a query asks the server to synchronize all objects to the
  227. client which match the query, along with all objects which are reachable
  228. from those objects via links. This happens asynchronously, and the local
  229. client Realm may not immediately have all objects which match the query.
  230. Observe the `state` property of the returned subscription object to be
  231. notified of when the subscription has been processed by the server and
  232. all objects matching the query are available.
  233. Creating a new subscription with the same name and query as an existing
  234. subscription will not create a new subscription, but instead will return
  235. an object referring to the existing sync subscription. This means that
  236. performing the same subscription twice followed by removing it once will
  237. result in no subscription existing.
  238. The newly created subscription will not be reported by
  239. `-[RLMRealm subscriptions]` or `-[RLMRealm subscriptionWithName:]` until
  240. `state` has transitioned from `RLMSyncSubscriptionStateCreating` to any of the
  241. other states.
  242. @param subscriptionName The name of the subscription.
  243. @return An object representing the newly-created subscription.
  244. @see RLMSyncSubscription
  245. */
  246. - (RLMSyncSubscription *)subscribeWithName:(nullable NSString *)subscriptionName;
  247. /**
  248. Subscribe to a subset of the query represented by this `RLMResults`.
  249. Subscribing to a query asks the server to synchronize all objects to the
  250. client which match the query, along with all objects which are reachable
  251. from those objects via links. This happens asynchronously, and the local
  252. client Realm may not immediately have all objects which match the query.
  253. Observe the `state` property of the returned subscription object to be
  254. notified of when the subscription has been processed by the server and
  255. all objects matching the query are available.
  256. Creating a new subscription with the same name and query as an existing
  257. subscription will not create a new subscription, but instead will return
  258. an object referring to the existing sync subscription. This means that
  259. performing the same subscription twice followed by removing it once will
  260. result in no subscription existing.
  261. The newly created subscription will not be reported by
  262. `-[RLMRealm subscriptions]` or `-[RLMRealm subscriptionWithName:]` until
  263. `state` has transitioned from `RLMSyncSubscriptionStateCreating` to any of the
  264. other states.
  265. The number of top-level matches may optionally be limited. This limit
  266. respects the sort and distinct order of the query being subscribed to,
  267. if any. Please note that the limit does not count or apply to objects
  268. which are added indirectly due to being linked to by the objects in the
  269. subscription. If the limit is larger than the number of objects which
  270. match the query, all objects will be included.
  271. @param subscriptionName The name of the subscription
  272. @param limit The maximum number of objects to include in the subscription.
  273. @return The subscription
  274. @see RLMSyncSubscription
  275. */
  276. - (RLMSyncSubscription *)subscribeWithName:(nullable NSString *)subscriptionName limit:(NSUInteger)limit;
  277. /**
  278. Subscribe to a subset of the query represented by this `RLMResults`.
  279. Subscribing to a query asks the server to synchronize all objects to the
  280. client which match the query, along with all objects which are reachable
  281. from those objects via links. This happens asynchronously, and the local
  282. client Realm may not immediately have all objects which match the query.
  283. Observe the `state` property of the returned subscription object to be
  284. notified of when the subscription has been processed by the server and
  285. all objects matching the query are available.
  286. Creating a new subscription with the same name and query as an existing
  287. subscription will not create a new subscription, but instead will return
  288. an object referring to the existing sync subscription. This means that
  289. performing the same subscription twice followed by removing it once will
  290. result in no subscription existing.
  291. The newly created subscription will not be reported by
  292. `-[RLMRealm subscriptions]` or `-[RLMRealm subscriptionWithName:]` until
  293. `state` has transitioned from `RLMSyncSubscriptionStateCreating` to any of the
  294. other states.
  295. @param options The additional configuration options for the subscription.
  296. @return The subscription.
  297. @see RLMSyncSubscription
  298. */
  299. - (RLMSyncSubscription *)subscribeWithOptions:(RLMSyncSubscriptionOptions *)options;
  300. @end
  301. /**
  302. Support for managing existing subscriptions to object queries in a Realm.
  303. */
  304. @interface RLMRealm (SyncSubscription)
  305. /**
  306. Get a list of the query-based sync subscriptions made for this Realm.
  307. This list includes all subscriptions which are currently in the states `Pending`,
  308. `Created`, and `Error`. Newly created subscriptions which are still in the
  309. `Creating` state are not included, and calling this immediately after calling
  310. `-[RLMResults subscribe]` will typically not include that subscription. Similarly,
  311. because unsubscription happens asynchronously, this may continue to include
  312. subscriptions after `-[RLMSyncSubscription unsubscribe]` is called on them.
  313. This method can only be called on a Realm which is using query-based sync and
  314. will throw an exception if called on a non-synchronized or full-sync Realm.
  315. */
  316. - (RLMResults<RLMSyncSubscription *> *)subscriptions;
  317. /**
  318. Look up a specific query-based sync subscription by name.
  319. Subscriptions are created asynchronously, so calling this immediately after
  320. calling `subscribeWithName:` on a `RLMResults` will typically return `nil`.
  321. Only subscriptions which are currently in the states `Pending`, `Created`,
  322. and `Error` can be retrieved with this method.
  323. This method can only be called on a Realm which is using query-based sync and
  324. will throw an exception if called on a non-synchronized or full-sync Realm.
  325. @return The named subscription, or `nil` if no subscription exists with that name.
  326. */
  327. - (nullable RLMSyncSubscription *)subscriptionWithName:(NSString *)name;
  328. @end
  329. NS_ASSUME_NONNULL_END