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