added iOS source code
[wl-app.git] / iOS / Pods / Realm / Realm / RLMRealmConfiguration.mm
1 ////////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright 2015 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 "RLMRealmConfiguration_Private.h"
20
21 #import "RLMObjectSchema_Private.hpp"
22 #import "RLMRealm_Private.h"
23 #import "RLMSchema_Private.hpp"
24 #import "RLMUtil.hpp"
25
26 #import "schema.hpp"
27 #import "shared_realm.hpp"
28 #import "sync/sync_config.hpp"
29
30 static NSString *const c_RLMRealmConfigurationProperties[] = {
31     @"fileURL",
32     @"inMemoryIdentifier",
33     @"encryptionKey",
34     @"readOnly",
35     @"schemaVersion",
36     @"migrationBlock",
37     @"deleteRealmIfMigrationNeeded",
38     @"shouldCompactOnLaunch",
39     @"dynamic",
40     @"customSchema",
41 };
42
43 static NSString *const c_defaultRealmFileName = @"default.realm";
44 RLMRealmConfiguration *s_defaultConfiguration;
45
46 NSString *RLMRealmPathForFileAndBundleIdentifier(NSString *fileName, NSString *bundleIdentifier) {
47     return [RLMDefaultDirectoryForBundleIdentifier(bundleIdentifier)
48             stringByAppendingPathComponent:fileName];
49 }
50
51 NSString *RLMRealmPathForFile(NSString *fileName) {
52     static NSString *directory = RLMDefaultDirectoryForBundleIdentifier(nil);
53     return [directory stringByAppendingPathComponent:fileName];
54 }
55
56 @implementation RLMRealmConfiguration {
57     realm::Realm::Config _config;
58 }
59
60 - (realm::Realm::Config&)config {
61     return _config;
62 }
63
64 + (instancetype)defaultConfiguration {
65     return [[self rawDefaultConfiguration] copy];
66 }
67
68 + (void)setDefaultConfiguration:(RLMRealmConfiguration *)configuration {
69     if (!configuration) {
70         @throw RLMException(@"Cannot set the default configuration to nil.");
71     }
72     @synchronized(c_defaultRealmFileName) {
73         s_defaultConfiguration = [configuration copy];
74     }
75 }
76
77 + (RLMRealmConfiguration *)rawDefaultConfiguration {
78     RLMRealmConfiguration *configuration;
79     @synchronized(c_defaultRealmFileName) {
80         if (!s_defaultConfiguration) {
81             s_defaultConfiguration = [[RLMRealmConfiguration alloc] init];
82         }
83         configuration = s_defaultConfiguration;
84     }
85     return configuration;
86 }
87
88 + (void)resetRealmConfigurationState {
89     @synchronized(c_defaultRealmFileName) {
90         s_defaultConfiguration = nil;
91     }
92 }
93
94 - (instancetype)init {
95     self = [super init];
96     if (self) {
97         static NSURL *defaultRealmURL = [NSURL fileURLWithPath:RLMRealmPathForFile(c_defaultRealmFileName)];
98         self.fileURL = defaultRealmURL;
99         self.schemaVersion = 0;
100         self.cache = YES;
101
102         // We have our own caching of RLMRealm instances, so the ObjectStore
103         // cache is at best pointless, and may result in broken behavior when
104         // a realm::Realm instance outlives the RLMRealm (due to collection
105         // notifiers being in the middle of running when the RLMRealm is
106         // dealloced) and then reused for a new RLMRealm
107         _config.cache = false;
108     }
109
110     return self;
111 }
112
113 - (instancetype)copyWithZone:(NSZone *)zone {
114     RLMRealmConfiguration *configuration = [[[self class] allocWithZone:zone] init];
115     configuration->_config = _config;
116     configuration->_cache = _cache;
117     configuration->_dynamic = _dynamic;
118     configuration->_migrationBlock = _migrationBlock;
119     configuration->_shouldCompactOnLaunch = _shouldCompactOnLaunch;
120     configuration->_customSchema = _customSchema;
121     return configuration;
122 }
123
124 - (NSString *)description {
125     NSMutableString *string = [NSMutableString stringWithFormat:@"%@ {\n", self.class];
126     for (NSString *key : c_RLMRealmConfigurationProperties) {
127         NSString *description = [[self valueForKey:key] description];
128         description = [description stringByReplacingOccurrencesOfString:@"\n" withString:@"\n\t"];
129
130         [string appendFormat:@"\t%@ = %@;\n", key, description];
131     }
132     return [string stringByAppendingString:@"}"];
133 }
134
135 static void RLMNSStringToStdString(std::string &out, NSString *in) {
136     out.resize([in maximumLengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
137     if (out.empty()) {
138         return;
139     }
140
141     NSUInteger size = out.size();
142     [in getBytes:&out[0]
143        maxLength:size
144       usedLength:&size
145         encoding:NSUTF8StringEncoding
146          options:0 range:{0, in.length} remainingRange:nullptr];
147     out.resize(size);
148 }
149
150 - (NSURL *)fileURL {
151     if (_config.in_memory || _config.sync_config) {
152         return nil;
153     }
154     return [NSURL fileURLWithPath:@(_config.path.c_str())];
155 }
156
157 - (void)setFileURL:(NSURL *)fileURL {
158     NSString *path = fileURL.path;
159     if (path.length == 0) {
160         @throw RLMException(@"Realm path must not be empty");
161     }
162     _config.sync_config = nullptr;
163
164     RLMNSStringToStdString(_config.path, path);
165     _config.in_memory = false;
166 }
167
168 - (NSString *)inMemoryIdentifier {
169     if (!_config.in_memory) {
170         return nil;
171     }
172     return [@(_config.path.c_str()) lastPathComponent];
173 }
174
175 - (void)setInMemoryIdentifier:(NSString *)inMemoryIdentifier {
176     if (inMemoryIdentifier.length == 0) {
177         @throw RLMException(@"In-memory identifier must not be empty");
178     }
179     _config.sync_config = nullptr;
180
181     RLMNSStringToStdString(_config.path, [NSTemporaryDirectory() stringByAppendingPathComponent:inMemoryIdentifier]);
182     _config.in_memory = true;
183 }
184
185 - (NSData *)encryptionKey {
186     return _config.encryption_key.empty() ? nil : [NSData dataWithBytes:_config.encryption_key.data() length:_config.encryption_key.size()];
187 }
188
189 - (void)setEncryptionKey:(NSData * __nullable)encryptionKey {
190     if (NSData *key = RLMRealmValidatedEncryptionKey(encryptionKey)) {
191         auto bytes = static_cast<const char *>(key.bytes);
192         _config.encryption_key.assign(bytes, bytes + key.length);
193         if (_config.sync_config) {
194             auto& sync_encryption_key = self.config.sync_config->realm_encryption_key;
195             sync_encryption_key = std::array<char, 64>();
196             std::copy_n(_config.encryption_key.begin(), 64, sync_encryption_key->begin());
197         }
198     }
199     else {
200         _config.encryption_key.clear();
201         if (_config.sync_config)
202             _config.sync_config->realm_encryption_key = realm::util::none;
203     }
204 }
205
206 - (BOOL)readOnly {
207     return _config.immutable();
208 }
209
210 - (void)setReadOnly:(BOOL)readOnly {
211     if (readOnly) {
212         if (self.deleteRealmIfMigrationNeeded) {
213             @throw RLMException(@"Cannot set `readOnly` when `deleteRealmIfMigrationNeeded` is set.");
214         } else if (self.shouldCompactOnLaunch) {
215             @throw RLMException(@"Cannot set `readOnly` when `shouldCompactOnLaunch` is set.");
216         }
217         _config.schema_mode = realm::SchemaMode::Immutable;
218     }
219     else if (self.readOnly) {
220         _config.schema_mode = realm::SchemaMode::Automatic;
221     }
222 }
223
224 - (uint64_t)schemaVersion {
225     return _config.schema_version;
226 }
227
228 - (void)setSchemaVersion:(uint64_t)schemaVersion {
229     if (schemaVersion == RLMNotVersioned) {
230         @throw RLMException(@"Cannot set schema version to %llu (RLMNotVersioned)", RLMNotVersioned);
231     }
232     _config.schema_version = schemaVersion;
233 }
234
235 - (BOOL)deleteRealmIfMigrationNeeded {
236     return _config.schema_mode == realm::SchemaMode::ResetFile;
237 }
238
239 - (void)setDeleteRealmIfMigrationNeeded:(BOOL)deleteRealmIfMigrationNeeded {
240     if (deleteRealmIfMigrationNeeded) {
241         if (self.readOnly) {
242             @throw RLMException(@"Cannot set `deleteRealmIfMigrationNeeded` when `readOnly` is set.");
243         }
244         _config.schema_mode = realm::SchemaMode::ResetFile;
245     }
246     else if (self.deleteRealmIfMigrationNeeded) {
247         _config.schema_mode = realm::SchemaMode::Automatic;
248     }
249 }
250
251 - (NSArray *)objectClasses {
252     return [_customSchema.objectSchema valueForKeyPath:@"objectClass"];
253 }
254
255 - (void)setObjectClasses:(NSArray *)objectClasses {
256     self.customSchema = [RLMSchema schemaWithObjectClasses:objectClasses];
257 }
258
259 - (void)setDynamic:(bool)dynamic {
260     _dynamic = dynamic;
261     self.cache = !dynamic;
262 }
263
264 - (bool)disableFormatUpgrade {
265     return _config.disable_format_upgrade;
266 }
267
268 - (void)setDisableFormatUpgrade:(bool)disableFormatUpgrade {
269     _config.disable_format_upgrade = disableFormatUpgrade;
270 }
271
272 - (realm::SchemaMode)schemaMode {
273     return _config.schema_mode;
274 }
275
276 - (void)setSchemaMode:(realm::SchemaMode)mode {
277     _config.schema_mode = mode;
278 }
279
280 - (NSString *)pathOnDisk {
281     return @(_config.path.c_str());
282 }
283
284 - (void)setShouldCompactOnLaunch:(RLMShouldCompactOnLaunchBlock)shouldCompactOnLaunch {
285     if (shouldCompactOnLaunch) {
286         if (self.readOnly) {
287             @throw RLMException(@"Cannot set `shouldCompactOnLaunch` when `readOnly` is set.");
288         } else if (_config.sync_config) {
289             @throw RLMException(@"Cannot set `shouldCompactOnLaunch` when `syncConfiguration` is set.");
290         }
291         _config.should_compact_on_launch_function = [=](size_t totalBytes, size_t usedBytes) {
292             return shouldCompactOnLaunch(totalBytes, usedBytes);
293         };
294     }
295     else {
296         _config.should_compact_on_launch_function = nullptr;
297     }
298     _shouldCompactOnLaunch = shouldCompactOnLaunch;
299 }
300
301 - (void)setCustomSchemaWithoutCopying:(RLMSchema *)schema {
302     _customSchema = schema;
303 }
304
305 @end