RLMSyncPermissionResults.mm 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. ////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright 2017 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 "RLMSyncPermissionResults.h"
  19. #import "RLMCollection_Private.hpp"
  20. #import "RLMObjectSchema_Private.hpp"
  21. #import "RLMQueryUtil.hpp"
  22. #import "RLMResults_Private.hpp"
  23. #import "RLMSchema_Private.hpp"
  24. #import "RLMSyncPermission_Private.hpp"
  25. #import "RLMSyncUtil_Private.hpp"
  26. #import "RLMUtil.hpp"
  27. #import "object.hpp"
  28. using namespace realm;
  29. namespace {
  30. bool keypath_is_valid(NSString *keypath)
  31. {
  32. static auto valid = [NSSet setWithArray:@[RLMSyncPermissionSortPropertyPath,
  33. RLMSyncPermissionSortPropertyUserID,
  34. RLMSyncPermissionSortPropertyUpdated]];
  35. return [valid containsObject:keypath];
  36. }
  37. }
  38. /// Sort by the Realm Object Server path to the Realm to which the permission applies.
  39. RLMSyncPermissionSortProperty const RLMSyncPermissionSortPropertyPath = @"path";
  40. /// Sort by the identity of the user to whom the permission applies.
  41. RLMSyncPermissionSortProperty const RLMSyncPermissionSortPropertyUserID = @"userId";
  42. /// Sort by the date the permissions were last updated.
  43. RLMSyncPermissionSortProperty const RLMSyncPermissionSortPropertyUpdated = @"updatedAt";
  44. @interface RLMSyncPermissionResults ()
  45. @property (nonatomic, strong) RLMSchema *schema;
  46. @property (nonatomic, strong) RLMObjectSchema *objectSchema;
  47. @end
  48. @implementation RLMSyncPermissionResults
  49. #pragma mark - Public API
  50. - (RLMPropertyType)type {
  51. return RLMPropertyTypeObject;
  52. }
  53. - (NSString *)objectClassName {
  54. return NSStringFromClass([RLMSyncPermission class]);
  55. }
  56. - (RLMRealm *)realm {
  57. return nil;
  58. }
  59. - (RLMSyncPermission *)objectAtIndex:(NSUInteger)index {
  60. return translateRLMResultsErrors([&] {
  61. Object permission(_results.get_realm(), _results.get_object_schema(), _results.get(index));
  62. return [[RLMSyncPermission alloc] initWithPermission:Permission(permission)];
  63. });
  64. }
  65. - (RLMSyncPermission *)firstObject {
  66. return self.count == 0 ? nil : [self objectAtIndex:0];
  67. }
  68. - (RLMSyncPermission *)lastObject {
  69. return self.count == 0 ? nil : [self objectAtIndex:(self.count - 1)];
  70. }
  71. - (NSUInteger)indexOfObject:(RLMSyncPermission *)object {
  72. if (object.key) {
  73. // Key-value permissions are only used for setting; they are never returned.
  74. return NSNotFound;
  75. }
  76. // Canonicalize the path.
  77. NSString *path = object.path;
  78. if ([path rangeOfString:@"~"].location != NSNotFound) {
  79. path = [path stringByReplacingOccurrencesOfString:@"~" withString:object.identity];
  80. }
  81. NSString *topPrivilege;
  82. switch (object.accessLevel) {
  83. case RLMSyncAccessLevelNone:
  84. // Deleted permissions are removed from the permissions Realm by ROS.
  85. return NSNotFound;
  86. case RLMSyncAccessLevelRead:
  87. topPrivilege = @"mayRead";
  88. break;
  89. case RLMSyncAccessLevelWrite:
  90. topPrivilege = @"mayWrite";
  91. break;
  92. case RLMSyncAccessLevelAdmin:
  93. topPrivilege = @"mayManage";
  94. break;
  95. }
  96. // Build the predicate.
  97. NSPredicate *p = [NSPredicate predicateWithFormat:@"%K = %@ AND %K = %@ AND %K == YES",
  98. RLMSyncPermissionSortPropertyPath, path,
  99. RLMSyncPermissionSortPropertyUserID, object.identity,
  100. topPrivilege];
  101. return [self indexOfObjectWithPredicate:p];
  102. }
  103. - (NSUInteger)indexOfObjectWithPredicate:(NSPredicate *)predicate {
  104. return translateRLMResultsErrors([&] {
  105. auto& group = _results.get_realm()->read_group();
  106. auto query = RLMPredicateToQuery(predicate, self.objectSchema, self.schema, group);
  107. return RLMConvertNotFound(_results.index_of(std::move(query)));
  108. });
  109. }
  110. - (RLMResults<RLMSyncPermission *> *)objectsWithPredicate:(NSPredicate *)predicate {
  111. return translateRLMResultsErrors([&] {
  112. auto query = RLMPredicateToQuery(predicate, self.objectSchema, self.schema, _results.get_realm()->read_group());
  113. return [[RLMSyncPermissionResults alloc] initWithResults:_results.filter(std::move(query))];
  114. });
  115. }
  116. - (RLMResults<RLMSyncPermission *> *)sortedResultsUsingDescriptors:(NSArray<RLMSortDescriptor *> *)properties {
  117. if (properties.count == 0) {
  118. return self;
  119. }
  120. for (RLMSortDescriptor *descriptor in properties) {
  121. if (!keypath_is_valid(descriptor.keyPath)) {
  122. @throw RLMException(@"Invalid keypath specified. Use one of the constants defined in "
  123. @" `RLMSyncPermissionSortProperty`.");
  124. }
  125. }
  126. return translateRLMResultsErrors([&] {
  127. auto sorted = _results.sort(RLMSortDescriptorsToKeypathArray(properties));
  128. return [[RLMSyncPermissionResults alloc] initWithResults:std::move(sorted)];
  129. });
  130. }
  131. #pragma clang diagnostic push
  132. #pragma clang diagnostic ignored "-Wmismatched-parameter-types"
  133. - (RLMNotificationToken *)addNotificationBlock:(void(^)(RLMSyncPermissionResults *results,
  134. RLMCollectionChange *change,
  135. NSError *error))block {
  136. auto cb = [=](const realm::CollectionChangeSet& changes, std::exception_ptr ptr) {
  137. if (ptr) {
  138. NSError *error = translateSyncExceptionPtrToError(std::move(ptr), RLMPermissionActionTypeGet);
  139. REALM_ASSERT(error);
  140. block(nil, nil, error);
  141. } else {
  142. // Finished successfully
  143. block(self, [[RLMCollectionChange alloc] initWithChanges:changes], nil);
  144. }
  145. };
  146. return [[RLMCancellationToken alloc] initWithToken:_results.add_notification_callback(std::move(cb)) realm:nil];
  147. }
  148. #pragma clang diagnostic pop
  149. - (id)aggregate:(__unused NSString *)property
  150. method:(__unused util::Optional<Mixed> (Results::*)(size_t))method
  151. methodName:(__unused NSString *)methodName returnNilForEmpty:(__unused BOOL)returnNilForEmpty {
  152. // We don't support any of the min/max/average/sum APIs; they don't make sense for this collection type.
  153. return nil;
  154. }
  155. - (id)valueForKey:(NSString *)key {
  156. size_t count = self.count;
  157. if (count == 0) {
  158. return @[];
  159. }
  160. NSMutableArray *results = [NSMutableArray arrayWithCapacity:count];
  161. if ([key isEqualToString:@"self"]) {
  162. for (size_t i = 0; i < count; i++) {
  163. [results addObject:[self objectAtIndex:i]];
  164. }
  165. } else {
  166. for (size_t i = 0; i < count; i++) {
  167. [results addObject:[[self objectAtIndex:i] valueForKey:key] ?: NSNull.null];
  168. }
  169. }
  170. return results;
  171. }
  172. - (void)setValue:(__unused id)value forKey:(__unused NSString *)key {
  173. @throw RLMException(@"Cannot set values for the read-only type `RLMSyncPermission`.");
  174. }
  175. #pragma mark - System
  176. - (RLMSchema *)schema {
  177. if (!_schema) {
  178. _schema = [RLMSchema dynamicSchemaFromObjectStoreSchema:_results.get_realm()->schema()];
  179. }
  180. return _schema;
  181. }
  182. - (RLMObjectSchema *)objectSchema {
  183. if (!_objectSchema) {
  184. _objectSchema = [RLMObjectSchema objectSchemaForObjectStoreSchema:_results.get_object_schema()];
  185. }
  186. return _objectSchema;
  187. }
  188. - (NSString *)description {
  189. return RLMDescriptionWithMaxDepth(@"RLMSyncPermissionResults", self, 1);
  190. }
  191. - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state
  192. objects:(id __unsafe_unretained [])buffer
  193. count:(NSUInteger)len {
  194. // FIXME: It would be nice to have a shared fast enumeration implementation for `realm::Results`-only RLMResults.
  195. NSUInteger thisSize = self.count;
  196. if (state->state == 0) {
  197. state->extra[0] = 0;
  198. state->extra[1] = (long)thisSize;
  199. state->state = 1;
  200. }
  201. NSUInteger objectsInBuffer = 0;
  202. long idx = state->extra[0];
  203. if ((unsigned long)idx == thisSize) {
  204. // finished
  205. return 0;
  206. }
  207. state->itemsPtr = buffer;
  208. state->mutationsPtr = state->extra + 1;
  209. while (true) {
  210. if (objectsInBuffer == len) {
  211. // Buffer is full.
  212. state->extra[0] = idx;
  213. return objectsInBuffer;
  214. }
  215. if ((unsigned long)idx == thisSize) {
  216. // finished
  217. state->extra[0] = idx;
  218. return objectsInBuffer;
  219. }
  220. // Otherwise, add an object and advance the index pointer.
  221. RLMSyncPermission * __autoreleasing thisPermission = [self objectAtIndex:idx];
  222. buffer[objectsInBuffer] = thisPermission;
  223. idx++;
  224. objectsInBuffer++;
  225. }
  226. }
  227. @end