nano-store 0.3.8 → 0.3.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/Gemfile.lock +3 -3
  2. data/Rakefile +1 -1
  3. data/lib/nano_store/finder.rb +12 -6
  4. data/lib/nano_store/version.rb +1 -1
  5. data/vendor/Podfile.lock +2 -2
  6. data/vendor/Pods/Headers/NanoStore/NSFNanoBag.h +8 -2
  7. data/vendor/Pods/Headers/NanoStore/NSFNanoSearch.h +2 -0
  8. data/vendor/Pods/Headers/NanoStore/NSFNanoStore_Private.h +1 -1
  9. data/vendor/Pods/NanoStore/Classes/Private/NSFNanoStore_Private.h +1 -1
  10. data/vendor/Pods/NanoStore/Classes/Public/NSFNanoBag.h +8 -2
  11. data/vendor/Pods/NanoStore/Classes/Public/NSFNanoBag.m +7 -4
  12. data/vendor/Pods/NanoStore/Classes/Public/NSFNanoExpression.m +2 -6
  13. data/vendor/Pods/NanoStore/Classes/Public/NSFNanoSearch.h +2 -0
  14. data/vendor/Pods/NanoStore/Classes/Public/NSFNanoSearch.m +9 -7
  15. data/vendor/Pods/NanoStore/Classes/Public/NSFNanoStore.m +14 -4
  16. data/vendor/Pods/Pods.bridgesupport +8 -1
  17. metadata +8 -43
  18. data/vendor/NanoStore/Classes/Advanced/NSFNanoEngine.h +0 -542
  19. data/vendor/NanoStore/Classes/Advanced/NSFNanoEngine.m +0 -1781
  20. data/vendor/NanoStore/Classes/Advanced/NSFNanoResult.h +0 -137
  21. data/vendor/NanoStore/Classes/Advanced/NSFNanoResult.m +0 -265
  22. data/vendor/NanoStore/Classes/Private/NSFNanoBag_Private.h +0 -37
  23. data/vendor/NanoStore/Classes/Private/NSFNanoEngine_Private.h +0 -69
  24. data/vendor/NanoStore/Classes/Private/NSFNanoExpression_Private.h +0 -35
  25. data/vendor/NanoStore/Classes/Private/NSFNanoGlobals_Private.h +0 -99
  26. data/vendor/NanoStore/Classes/Private/NSFNanoObject_Private.h +0 -35
  27. data/vendor/NanoStore/Classes/Private/NSFNanoPredicate_Private.h +0 -35
  28. data/vendor/NanoStore/Classes/Private/NSFNanoResult_Private.h +0 -43
  29. data/vendor/NanoStore/Classes/Private/NSFNanoSearch_Private.h +0 -48
  30. data/vendor/NanoStore/Classes/Private/NSFNanoStore_Private.h +0 -57
  31. data/vendor/NanoStore/Classes/Private/NanoStore_Private.h +0 -37
  32. data/vendor/NanoStore/Classes/Public/NSFNanoBag.h +0 -306
  33. data/vendor/NanoStore/Classes/Public/NSFNanoBag.m +0 -485
  34. data/vendor/NanoStore/Classes/Public/NSFNanoExpression.h +0 -125
  35. data/vendor/NanoStore/Classes/Public/NSFNanoExpression.m +0 -103
  36. data/vendor/NanoStore/Classes/Public/NSFNanoGlobals.h +0 -323
  37. data/vendor/NanoStore/Classes/Public/NSFNanoGlobals.m +0 -145
  38. data/vendor/NanoStore/Classes/Public/NSFNanoObject.h +0 -298
  39. data/vendor/NanoStore/Classes/Public/NSFNanoObject.m +0 -187
  40. data/vendor/NanoStore/Classes/Public/NSFNanoObjectProtocol.h +0 -119
  41. data/vendor/NanoStore/Classes/Public/NSFNanoPredicate.h +0 -123
  42. data/vendor/NanoStore/Classes/Public/NSFNanoPredicate.m +0 -130
  43. data/vendor/NanoStore/Classes/Public/NSFNanoSearch.h +0 -381
  44. data/vendor/NanoStore/Classes/Public/NSFNanoSearch.m +0 -835
  45. data/vendor/NanoStore/Classes/Public/NSFNanoSortDescriptor.h +0 -124
  46. data/vendor/NanoStore/Classes/Public/NSFNanoSortDescriptor.m +0 -79
  47. data/vendor/NanoStore/Classes/Public/NSFNanoStore.h +0 -475
  48. data/vendor/NanoStore/Classes/Public/NSFNanoStore.m +0 -1375
  49. data/vendor/NanoStore/Classes/Public/NanoStore.h +0 -463
  50. data/vendor/NanoStore/LICENSE +0 -25
  51. data/vendor/NanoStore/NanoStore.bridgesupport +0 -1215
  52. data/vendor/NanoStore/README.md +0 -411
@@ -1,1375 +0,0 @@
1
- /*
2
- NSFNanoStore.m
3
- NanoStore
4
-
5
- Copyright (c) 2010 Webbo, L.L.C. All rights reserved.
6
-
7
- Redistribution and use in source and binary forms, with or without modification, are permitted
8
- provided that the following conditions are met:
9
-
10
- * Redistributions of source code must retain the above copyright notice, this list of conditions
11
- and the following disclaimer.
12
- * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
13
- and the following disclaimer in the documentation and/or other materials provided with the distribution.
14
- * Neither the name of Webbo nor the names of its contributors may be used to endorse or promote
15
- products derived from this software without specific prior written permission.
16
-
17
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
18
- WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
19
- PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY
20
- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21
- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22
- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
23
- OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
- SUCH DAMAGE.
25
- */
26
-
27
- #import "NanoStore.h"
28
- #import "NSFNanoObjectProtocol.h"
29
- #import "NanoStore_Private.h"
30
- #import "NSFNanoStore_Private.h"
31
-
32
- #include <stdlib.h>
33
-
34
- @implementation NSFNanoStore
35
- {
36
- @protected
37
- NSFNanoEngine *nanoStoreEngine;
38
- NSFEngineProcessingMode nanoEngineProcessingMode;
39
- NSUInteger saveInterval;
40
-
41
- /** \cond */
42
- NSMutableArray *addedObjects;
43
- BOOL _isOurTransaction;
44
- sqlite3_stmt *_storeValuesStatement;
45
- sqlite3_stmt *_storeKeysStatement;
46
- /** \endcond */
47
- }
48
-
49
- @synthesize nanoStoreEngine;
50
- @synthesize nanoEngineProcessingMode;
51
- @synthesize saveInterval;
52
-
53
- // ----------------------------------------------
54
- // Initialization / Cleanup
55
- // ----------------------------------------------
56
-
57
- + (NSFNanoStore *)createStoreWithType:(NSFNanoStoreType)theType path:(NSString *)thePath
58
- {
59
- return [[self alloc]initStoreWithType:theType path:thePath];
60
- }
61
-
62
- + (NSFNanoStore *)createAndOpenStoreWithType:(NSFNanoStoreType)theType path:(NSString *)thePath error:(out NSError **)outError
63
- {
64
- NSFNanoStore *nanoStore = [[self alloc]initStoreWithType:theType path:thePath];
65
- [nanoStore openWithError:outError];
66
- return nanoStore;
67
- }
68
-
69
- - (id)initStoreWithType:(NSFNanoStoreType)theType path:(NSString *)thePath
70
- {
71
- switch (theType) {
72
- case NSFMemoryStoreType:
73
- thePath = NSFMemoryDatabase;
74
- break;
75
- case NSFTemporaryStoreType:
76
- thePath = NSFTemporaryDatabase;
77
- break;
78
- default:
79
- // Do nothing
80
- break;
81
- }
82
-
83
- if (nil == thePath) {
84
- [[NSException exceptionWithName:NSFUnexpectedParameterException
85
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: the path cannot be nil.", [self class], _cmd]
86
- userInfo:nil]raise];
87
- }
88
-
89
- if ((self = [super init])) {
90
- nanoStoreEngine = [[NSFNanoEngine alloc]initWithPath:[thePath stringByExpandingTildeInPath]];
91
- if (nil == nanoStoreEngine) {
92
- _NSFLog([NSString stringWithFormat:@"*** -[%@ %s]: [NSFNanoEngine initWithPath:] failed: %@", [self class], _cmd, thePath]);
93
- [self closeWithError:nil];
94
- return nil;
95
- }
96
-
97
- nanoEngineProcessingMode = NSFEngineProcessingDefaultMode;
98
-
99
- _isOurTransaction = NO;
100
- saveInterval = 1;
101
-
102
- _storeValuesStatement = NULL;
103
- _storeKeysStatement = NULL;
104
-
105
- addedObjects = [[NSMutableArray alloc]initWithCapacity:saveInterval];
106
- }
107
-
108
- return self;
109
- }
110
-
111
- - (void)dealloc
112
- {
113
- [self closeWithError:nil];
114
-
115
-
116
- }
117
-
118
- - (NSString *)filePath
119
- {
120
- return [nanoStoreEngine path];
121
- }
122
-
123
- - (BOOL)openWithError:(out NSError **)outError
124
- {
125
- if ([nanoStoreEngine isDatabaseOpen] == YES)
126
- return YES;
127
-
128
- if ([nanoStoreEngine openWithCacheMethod:CacheAllData useFastMode:(NSFEngineProcessingFastMode == nanoEngineProcessingMode)] == NO) {
129
- NSString *message = [NSString stringWithFormat:@"*** -[%@ %s]: open database failed: %@", [self class], _cmd, [self filePath]];
130
- _NSFLog(message);
131
- if (nil != outError)
132
- *outError = [NSError errorWithDomain:NSFDomainKey
133
- code:NSFNanoStoreErrorKey
134
- userInfo:[NSDictionary dictionaryWithObject:message
135
- forKey:NSLocalizedFailureReasonErrorKey]];
136
- [self closeWithError:nil];
137
- return NO;
138
- }
139
-
140
- if ([self _setupCachingSchema] == NO) {
141
- NSString *message = [NSString stringWithFormat:@"*** -[%@ %s]: the schema could not be created when opening database: %@", [self class], _cmd, [self filePath]];
142
- _NSFLog(message);
143
- if (nil != outError)
144
- *outError = [NSError errorWithDomain:NSFDomainKey
145
- code:NSFNanoStoreErrorKey
146
- userInfo:[NSDictionary dictionaryWithObject:message
147
- forKey:NSLocalizedFailureReasonErrorKey]];
148
- [self closeWithError:nil];
149
- return NO;
150
- }
151
-
152
- if ([self _initializePreparedStatementsWithError:outError] == NO) {
153
- NSString *message = [NSString stringWithFormat:@"*** -[%@ %s]: the SQL statements could not be prepared when opening database: %@", [self class], _cmd, [self filePath]];
154
- _NSFLog(message);
155
- [self closeWithError:nil];
156
- return NO;
157
- }
158
-
159
- return YES;
160
- }
161
-
162
- - (BOOL)closeWithError:(out NSError **)outError
163
- {
164
- BOOL success = [self saveStoreAndReturnError:outError];
165
- [self _releasePreparedStatements];
166
- [nanoStoreEngine close];
167
-
168
- return success;
169
- }
170
-
171
- - (BOOL)isClosed
172
- {
173
- return ([nanoStoreEngine isDatabaseOpen] == NO);
174
- }
175
-
176
- - (NSString*)description
177
- {
178
- return [self _nestedDescriptionWithPrefixedSpace:@""];
179
- }
180
-
181
- - (BOOL)hasUnsavedChanges
182
- {
183
- return ([addedObjects count] > 0);
184
- }
185
-
186
- #pragma mark -
187
-
188
- - (BOOL)addObject:(id <NSFNanoObjectProtocol>)object error:(out NSError **)outError
189
- {
190
- NSArray *wrapper = [[NSArray alloc]initWithObjects:object, nil];
191
- BOOL success = [self addObjectsFromArray:wrapper error:outError];
192
- return success;
193
- }
194
-
195
- - (BOOL)addObjectsFromArray:(NSArray *)someObjects error:(out NSError **)outError
196
- {
197
- if (nil == someObjects) {
198
- [[NSException exceptionWithName:NSFUnexpectedParameterException
199
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: someObjects is nil.", [self class], _cmd]
200
- userInfo:nil]raise];
201
- }
202
-
203
- if ([someObjects count] == 0) {
204
- if (nil != outError)
205
- *outError = [NSError errorWithDomain:NSFDomainKey
206
- code:NSFNanoStoreErrorKey
207
- userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"*** -[%@ %s]: ([someObjects count] == 0)", [self class], _cmd]
208
- forKey:NSLocalizedFailureReasonErrorKey]];
209
- return NO;
210
- }
211
-
212
- // Add the regular objects. For bags, redirect it the saving method.
213
- NSMutableArray *nonBagObjects = [[NSMutableArray alloc]initWithCapacity:[someObjects count]];
214
-
215
- for (id object in someObjects) {
216
- // If it's a bag, make sure the name is unique
217
- if (YES == [object isKindOfClass:[NSFNanoBag class]]) {
218
- NSFNanoBag *bag = (NSFNanoBag *)object;
219
- NSString *bagName = bag.name;
220
- if (bagName.length > 0) {
221
- NSFNanoBag *bagWithSameName = [self bagWithName:bagName];
222
- if (nil != bagWithSameName) {
223
- if (nil != outError) {
224
- *outError = [NSError errorWithDomain:NSFDomainKey
225
- code:NSFNanoStoreErrorKey
226
- userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"*** -[%@ %s]: a bag named '%@' already exists.", [self class], _cmd, bagName]
227
- forKey:NSLocalizedFailureReasonErrorKey]];
228
-
229
- return NO;
230
- }
231
- }
232
- }
233
-
234
-
235
- // If it's a bag, process it first by gathering. If it's not dirty, there's no need to save...
236
- if (YES == [object hasUnsavedChanges]) {
237
- NSError *error = nil;
238
-
239
- // Associate the bag to this store
240
- if (nil == [object store]) {
241
- [object _setStore:self];
242
- }
243
-
244
- if (NO == [object _saveInStore:self error:&error]) {
245
- [[NSException exceptionWithName:NSFNanoStoreUnableToManipulateStoreException
246
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: %@", [self class], _cmd, [error localizedDescription]]
247
- userInfo:nil]raise];
248
- }
249
- }
250
- } else {
251
- if (NO == [(id)object conformsToProtocol:@protocol(NSFNanoObjectProtocol)]) {
252
- [[NSException exceptionWithName:NSFNonConformingNanoObjectProtocolException
253
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: the object does not conform to NSFNanoObjectProtocol.", [self class], _cmd]
254
- userInfo:nil]raise];
255
- }
256
-
257
- if (nil == [object nanoObjectKey]) {
258
- [[NSException exceptionWithName:NSFNanoObjectBehaviorException
259
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: unexpected NSFNanoObject behavior. Reason: the object's key is nil.", [self class], _cmd]
260
- userInfo:nil]raise];
261
- }
262
-
263
- [nonBagObjects addObject:object];
264
- }
265
- }
266
-
267
- BOOL success = [self _addObjectsFromArray:nonBagObjects forceSave:NO error:outError];
268
-
269
-
270
- return success;
271
- }
272
-
273
- - (BOOL)removeObject:(id <NSFNanoObjectProtocol>)theObject error:(out NSError **)outError
274
- {
275
- NSArray *wrapper = [[NSArray alloc]initWithObjects:theObject, nil];
276
- BOOL success = [self removeObjectsInArray:wrapper error:outError];
277
- return success;
278
- }
279
-
280
- - (BOOL)removeObjectsWithKeysInArray:(NSArray *)someKeys error:(out NSError **)outError
281
- {
282
- if ([self _checkNanoStoreIsReadyAndReturnError:outError] == NO)
283
- return NO;
284
-
285
- if (nil == someKeys)
286
- [[NSException exceptionWithName:NSFUnexpectedParameterException
287
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: someKeys is nil.", [self class], _cmd]
288
- userInfo:nil]raise];
289
-
290
- NSUInteger count = [someKeys count];
291
-
292
- if (0 == count)
293
- return NO;
294
-
295
- BOOL transactionStartedHere = [self beginTransactionAndReturnError:nil];
296
-
297
- NSString *theSQLStatement = [[NSString alloc]initWithFormat:@"CREATE TEMP TABLE %@(x);", NSF_Private_ToDeleteTableKey];
298
- [nanoStoreEngine executeSQL:theSQLStatement];
299
-
300
- sqlite3_stmt *statement;
301
- theSQLStatement = [[NSString alloc]initWithFormat:@"INSERT INTO %@ VALUES (?);", NSF_Private_ToDeleteTableKey];
302
- BOOL success = [self _prepareSQLite3Statement:&statement theSQLStatement:theSQLStatement];
303
-
304
- if (success) {
305
- for (NSString *key in someKeys) {
306
- int status = sqlite3_reset (statement);
307
- if (SQLITE_OK != status) {
308
- break;
309
- }
310
-
311
- // Bind and execute the statement...
312
- status = sqlite3_bind_text ( statement, 1, [key UTF8String], -1, SQLITE_STATIC);
313
-
314
- // Since we're operating with extended result code support, extract the bits
315
- // and obtain the regular result code
316
- // For more info check: http://www.sqlite.org/c3ref/c_ioerr_access.html
317
-
318
- status = [NSFNanoEngine NSFP_stripBitsFromExtendedResultCode:status];
319
-
320
- if (SQLITE_OK == status) {
321
- [self _executeSQLite3StepUsingSQLite3Statement:statement];
322
- }
323
- }
324
- sqlite3_finalize(statement);
325
- }
326
-
327
- _NSFLog(@" Before removing the keys to be stored from NSFKeys...");
328
- theSQLStatement = [[NSString alloc]initWithFormat:@"DELETE FROM %@ WHERE %@ IN (SELECT * FROM %@);", NSFKeys, NSFKey, NSF_Private_ToDeleteTableKey];
329
- [nanoStoreEngine executeSQL:theSQLStatement];
330
-
331
- _NSFLog(@" Before removing the keys to be stored from NSFValues...");
332
- theSQLStatement = [[NSString alloc]initWithFormat:@"DELETE FROM %@ WHERE %@ IN (SELECT * FROM %@);", NSFValues, NSFKey, NSF_Private_ToDeleteTableKey];
333
- [nanoStoreEngine executeSQL:theSQLStatement];
334
-
335
- _NSFLog(@" Before DROP TABLE NSF_Private_ToDeleteTableKey...");
336
- theSQLStatement = [[NSString alloc]initWithFormat:@"DROP TABLE %@;", NSF_Private_ToDeleteTableKey];
337
- [nanoStoreEngine executeSQL:theSQLStatement];
338
-
339
- if (transactionStartedHere)
340
- if ([self commitTransactionAndReturnError:nil] == NO)
341
- _NSFLog(@" Could not commit the transaction.");
342
-
343
- return YES;
344
- }
345
-
346
- - (BOOL)removeObjectsInArray:(NSArray *)someObjects error:(out NSError **)outError
347
- {
348
- NSMutableArray *someKeys = [NSMutableArray array];
349
-
350
- // Extract the keys from the objects
351
- for (id object in someObjects) {
352
- if (NO == [(id)object conformsToProtocol:@protocol(NSFNanoObjectProtocol)]) {
353
- [[NSException exceptionWithName:NSFNonConformingNanoObjectProtocolException
354
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: the object does not conform to NSFNanoObjectProtocol.", [self class], _cmd]
355
- userInfo:nil]raise];
356
- } else {
357
- NSString *objectKey = [(id)object nanoObjectKey];
358
- if (nil == objectKey) {
359
- [[NSException exceptionWithName:NSFNanoObjectBehaviorException
360
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: unexpected NSFNanoObject behavior. Reason: the object's key is nil.", [self class], _cmd]
361
- userInfo:nil]raise];
362
- }
363
- [someKeys addObject:objectKey];
364
- }
365
- }
366
-
367
- return [self removeObjectsWithKeysInArray:someKeys error:outError];
368
- }
369
-
370
- #pragma mark -
371
- #pragma mark Searching
372
- #pragma mark -
373
-
374
- - (NSArray *)bags
375
- {
376
- NSFNanoSearch *search = [NSFNanoSearch searchWithStore:self];
377
- NSString *theSQLStatement = [NSString stringWithFormat:@"SELECT NSFKey, NSFPlist, NSFObjectClass FROM NSFKeys WHERE NSFObjectClass = \"%@\"", NSStringFromClass([NSFNanoBag class])];
378
-
379
- return [[search executeSQL:theSQLStatement returnType:NSFReturnObjects error:nil]allValues];
380
-
381
- }
382
-
383
- - (NSFNanoBag *)bagWithName:(NSString *)theName
384
- {
385
- NSFNanoSearch *search = [NSFNanoSearch searchWithStore:self];
386
-
387
- search.attribute = NSF_Private_NSFNanoBag_Name;
388
- search.match = NSFEqualTo;
389
- search.value = theName;
390
-
391
- // Returns a dictionary with the UUID of the object (key) and the NanoObject (value).
392
- return [[[search searchObjectsWithReturnType:NSFReturnObjects error:nil]allObjects]lastObject];
393
- }
394
-
395
- - (NSArray *)bagsWithKeysInArray:(NSArray *)someKeys
396
- {
397
- if ([someKeys count] == 0) {
398
- return [NSArray array];
399
- }
400
-
401
- NSFNanoSearch *search = [NSFNanoSearch searchWithStore:self];
402
- NSString *quotedString = [NSFNanoSearch _quoteStrings:someKeys joiningWithDelimiter:@","];
403
- NSString *theSQLStatement = [NSString stringWithFormat:@"SELECT NSFKey, NSFPlist, NSFObjectClass FROM NSFKeys WHERE NSFKey IN (%@) AND NSFObjectClass = \"%@\"", quotedString, NSStringFromClass([NSFNanoBag class])];
404
-
405
- return [[search executeSQL:theSQLStatement returnType:NSFReturnObjects error:nil]allValues];
406
- }
407
-
408
- - (NSArray *)bagsContainingObjectWithKey:(NSString *)aKey
409
- {
410
- if (nil == aKey) {
411
- return [NSArray array];
412
- }
413
-
414
- NSFNanoSearch *search = [NSFNanoSearch searchWithStore:self];
415
- NSString *theSQLStatement = [NSString stringWithFormat:@"SELECT NSFKey, NSFPlist, NSFObjectClass FROM NSFKeys WHERE NSFKey IN (SELECT DISTINCT (NSFKEY) FROM NSFValues WHERE NSFValue = \"%@\") AND NSFObjectClass = \"%@\"", aKey, NSStringFromClass([NSFNanoBag class])];
416
-
417
- return [[search executeSQL:theSQLStatement returnType:NSFReturnObjects error:nil]allValues];
418
- }
419
-
420
- - (NSArray *)objectsWithKeysInArray:(NSArray *)someKeys
421
- {
422
- if ([someKeys count] == 0) {
423
- return [NSArray array];
424
- }
425
-
426
- NSFNanoSearch *search = [NSFNanoSearch searchWithStore:self];
427
- NSString *quotedString = [NSFNanoSearch _quoteStrings:someKeys joiningWithDelimiter:@","];
428
- NSString *theSQLStatement = [NSString stringWithFormat:@"SELECT NSFKey, NSFPlist, NSFObjectClass FROM NSFKeys WHERE NSFKey IN (%@)", quotedString];
429
-
430
- return [[search executeSQL:theSQLStatement returnType:NSFReturnObjects error:nil]allValues];
431
- }
432
-
433
- - (NSArray *)allObjectClasses
434
- {
435
- NSFNanoResult *results = [self _executeSQL:@"SELECT DISTINCT(NSFObjectClass) FROM NSFKeys"];
436
-
437
- return [results valuesForColumn:@"NSFKeys.NSFObjectClass"];
438
- }
439
-
440
- - (NSArray *)objectsOfClassNamed:(NSString *)theClassName
441
- {
442
- return [self objectsOfClassNamed:theClassName usingSortDescriptors:nil];
443
- }
444
-
445
- - (NSArray *)objectsOfClassNamed:(NSString *)theClassName usingSortDescriptors:(NSArray *)theSortDescriptors
446
- {
447
- if (nil == theClassName) {
448
- [[NSException exceptionWithName:NSFUnexpectedParameterException
449
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: the class name cannot be nil.", [self class], _cmd]
450
- userInfo:nil]raise];
451
- }
452
-
453
- NSFNanoSearch *search = [NSFNanoSearch searchWithStore:self];
454
- search.sort = theSortDescriptors;
455
-
456
- NSString *theSQLStatement = [NSString stringWithFormat:@"SELECT NSFKey, NSFPlist, NSFObjectClass FROM NSFKeys WHERE NSFObjectClass = \"%@\"", theClassName];
457
-
458
- if (nil == theSortDescriptors)
459
- return [[search executeSQL:theSQLStatement returnType:NSFReturnObjects error:nil] allValues];
460
- else
461
- return [search executeSQL:theSQLStatement returnType:NSFReturnObjects error:nil];
462
- }
463
-
464
- - (long long)countOfObjectsOfClassNamed:(NSString *)theClassName
465
- {
466
- if (nil == theClassName) {
467
- [[NSException exceptionWithName:NSFUnexpectedParameterException
468
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: the class name cannot be nil.", [self class], _cmd]
469
- userInfo:nil]raise];
470
- }
471
-
472
- NSFNanoSearch *search = [NSFNanoSearch searchWithStore:self];
473
-
474
- NSString *theSQLStatement = [NSString stringWithFormat:@"SELECT count(*) FROM NSFKeys WHERE NSFObjectClass = \"%@\"", theClassName];
475
- NSFNanoResult *results = [search executeSQL:theSQLStatement];
476
-
477
- return [[results firstValue]longLongValue];
478
- }
479
-
480
- #pragma mark -
481
- #pragma mark Database Optimizations and Maintenance
482
- #pragma mark -
483
-
484
- - (BOOL)beginTransactionAndReturnError:(out NSError **)outError
485
- {
486
- if ([self _checkNanoStoreIsReadyAndReturnError:outError] == NO)
487
- return NO;
488
-
489
- if ([self _isOurTransaction] == YES)
490
- return NO;
491
-
492
- [self _setIsOurTransaction:[[self nanoStoreEngine]beginTransaction]];
493
-
494
- return [self _isOurTransaction];
495
- }
496
-
497
- - (BOOL)commitTransactionAndReturnError:(out NSError **)outError
498
- {
499
- if ([self _checkNanoStoreIsReadyAndReturnError:outError] == NO)
500
- return NO;
501
-
502
- if ([self _isOurTransaction] == YES) {
503
- if ([[self nanoStoreEngine]commitTransaction] == YES) {
504
- [self _setIsOurTransaction:NO];
505
- return YES;
506
- }
507
- }
508
-
509
- return NO;
510
- }
511
-
512
- - (BOOL)rollbackTransactionAndReturnError:(out NSError **)outError
513
- {
514
- if ([self _checkNanoStoreIsReadyAndReturnError:outError] == NO)
515
- return NO;
516
-
517
- if ([self _isOurTransaction] == YES) {
518
- [[self nanoStoreEngine]rollbackTransaction];
519
- [self _setIsOurTransaction:NO];
520
- return YES;
521
- }
522
-
523
- return NO;
524
- }
525
-
526
- #pragma mark -
527
-
528
- // ----------------------------------------------
529
- // Store/save unsaved objects
530
- // ----------------------------------------------
531
-
532
- - (BOOL)saveStoreAndReturnError:(out NSError **)outError
533
- {
534
- // We are really not saving anything new, just indicating that we should commit the unsaved changes.
535
- if (NO == self.hasUnsavedChanges) {
536
- return YES;
537
- }
538
-
539
- return [self _addObjectsFromArray:[NSArray array] forceSave:YES error:outError];
540
- }
541
-
542
- - (void)discardUnsavedChanges
543
- {
544
- [addedObjects removeAllObjects];
545
- }
546
-
547
- // ----------------------------------------------
548
- // Clearing the store
549
- // ----------------------------------------------
550
-
551
- - (BOOL)removeAllObjectsFromStoreAndReturnError:(out NSError **)outError
552
- {
553
- if ([self _checkNanoStoreIsReadyAndReturnError:outError] == NO)
554
- return NO;
555
-
556
- NSError *resultKeys = [[self _executeSQL:[NSString stringWithFormat:@"DROP TABLE %@", NSFKeys]]error];
557
- NSError *resultValues = [[self _executeSQL:[NSString stringWithFormat:@"DROP TABLE %@", NSFValues]]error];
558
-
559
- [self _setupCachingSchema];
560
-
561
- [self rebuildIndexesAndReturnError:nil];
562
-
563
- if ((nil != resultKeys) || (nil != resultValues)) {
564
- if (nil != outError) {
565
- *outError = [NSError errorWithDomain:NSFDomainKey
566
- code:NSFNanoStoreErrorKey
567
- userInfo:[NSDictionary dictionaryWithObject:@"Could not remove all objects from the database."
568
- forKey:NSLocalizedDescriptionKey]];
569
- }
570
- return NO;
571
- }
572
-
573
- return YES;
574
- }
575
-
576
- // ----------------------------------------------
577
- // Compacting the database
578
- // ----------------------------------------------
579
-
580
- - (BOOL)compactStoreAndReturnError:(out NSError **)outError
581
- {
582
- if ([self _checkNanoStoreIsReadyAndReturnError:outError] == NO)
583
- return NO;
584
-
585
- return [[self nanoStoreEngine]compact];
586
- }
587
-
588
- - (BOOL)clearIndexesAndReturnError:(out NSError **)outError
589
- {
590
- if ([self _checkNanoStoreIsReadyAndReturnError:outError] == NO)
591
- return NO;
592
-
593
- NSArray *indexes = [[self nanoStoreEngine]indexes];
594
-
595
- _NSFLog(@"Before clearIndexes...");
596
- NSDate *startDate = [NSDate date];
597
-
598
- for (NSString *index in indexes)
599
- [[self nanoStoreEngine]dropIndex:index];
600
-
601
- NSTimeInterval seconds = [[NSDate date]timeIntervalSinceDate:startDate];
602
- _NSFLog(@"Done. Clearing the indexes took %.3f seconds", seconds);
603
-
604
- return YES;
605
- }
606
-
607
- - (BOOL)rebuildIndexesAndReturnError:(out NSError **)outError
608
- {
609
- if ([self _checkNanoStoreIsReadyAndReturnError:outError] == NO)
610
- return NO;
611
-
612
- // Force the indexes to be dropped
613
- [self clearIndexesAndReturnError:nil];
614
-
615
- _NSFLog(@"Before rebuildIndexes...");
616
- NSDate *startDate = [NSDate date];
617
-
618
- _NSFLog(@" [[self nanoStoreEngine]createIndexForColumn: NSFKey table: NSFValues isUnique:NO]: %@", [[self nanoStoreEngine]createIndexForColumn:NSFKey table:NSFValues isUnique:NO] ? @"YES" : @"NO");
619
- _NSFLog(@" [[self nanoStoreEngine]createIndexForColumn: NSFAttribute table: NSFValues isUnique:NO]: %@", [[self nanoStoreEngine]createIndexForColumn:NSFAttribute table:NSFValues isUnique:NO] ? @"YES" : @"NO");
620
- _NSFLog(@" [[self nanoStoreEngine]createIndexForColumn: NSFValue table: NSFValues isUnique:NO]: %@", [[self nanoStoreEngine]createIndexForColumn:NSFValue table:NSFValues isUnique:NO] ? @"YES" : @"NO");
621
-
622
- _NSFLog(@" [[self nanoStoreEngine]createIndexForColumn: NSFKey table: NSFKeys isUnique:YES]: %@", [[self nanoStoreEngine]createIndexForColumn:NSFKey table:NSFKeys isUnique:YES] ? @"YES" : @"NO");
623
- _NSFLog(@" [[self nanoStoreEngine]createIndexForColumn: NSFCalendarDate table: NSFKeys isUnique:NO]: %@", [[self nanoStoreEngine]createIndexForColumn:NSFCalendarDate table:NSFKeys isUnique:NO] ? @"YES" : @"NO");
624
- _NSFLog(@" [[self nanoStoreEngine]createIndexForColumn: NSFObjectClass table: NSFKeys isUnique:NO]: %@", [[self nanoStoreEngine]createIndexForColumn:NSFObjectClass table:NSFKeys isUnique:NO] ? @"YES" : @"NO");
625
-
626
- NSTimeInterval seconds = [[NSDate date]timeIntervalSinceDate:startDate];
627
- _NSFLog(@"Done. Rebuilding the indexes took %.3f seconds", seconds);
628
-
629
- return YES;
630
- }
631
-
632
- - (BOOL)saveStoreToDirectoryAtPath:(NSString *)path compactDatabase:(BOOL)compact error:(out NSError **)outError
633
- {
634
- if (nil == path)
635
- [[NSException exceptionWithName:NSFUnexpectedParameterException
636
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: path is nil.", [self class], _cmd]
637
- userInfo:nil]raise];
638
-
639
- // Make sure we've expanded the tilde
640
- path = [path stringByExpandingTildeInPath];
641
-
642
- if ([self _checkNanoStoreIsReadyAndReturnError:outError] == NO)
643
- return NO;
644
-
645
- if ([[self nanoStoreEngine]isTransactionActive]) {
646
- if (nil != outError)
647
- *outError = [NSError errorWithDomain:NSFDomainKey
648
- code:NSFNanoStoreErrorKey
649
- userInfo:[NSDictionary dictionaryWithObject:@"Cannot backup store. A transaction is still open."
650
- forKey:NSLocalizedDescriptionKey]];
651
- return NO;
652
- }
653
-
654
- if ([[self filePath]isEqualToString:NSFMemoryDatabase] == YES) {
655
- return [self _backupMemoryStoreToDirectoryAtPath:path extension:nil compact:compact error:outError];
656
- } else {
657
- return [self _backupFileStoreToDirectoryAtPath:path extension:nil compact:compact error:outError];
658
- }
659
-
660
- return NO;
661
- }
662
-
663
- #pragma mark - Private Methods
664
- #pragma mark -
665
-
666
- /** \cond */
667
-
668
- + (NSFNanoStore *)_debug
669
- {
670
- return [NSFNanoStore createStoreWithType:NSFPersistentStoreType path:[@"~/Desktop/NanoStoreDebug.db" stringByExpandingTildeInPath]];
671
- }
672
-
673
- - (NSFNanoResult *)_executeSQL:(NSString *)theSQLStatement
674
- {
675
- if (nil == theSQLStatement)
676
- return nil;
677
-
678
- return [[self nanoStoreEngine]executeSQL:theSQLStatement];
679
- }
680
-
681
- - (BOOL)_initializePreparedStatementsWithError:(out NSError **)outError
682
- {
683
- BOOL hasInitializationSucceeded = YES;
684
-
685
- if (NULL == _storeValuesStatement) {
686
- NSString *theSQLStatement = [[NSString alloc]initWithFormat:@"INSERT INTO %@(%@, %@, %@, %@) VALUES (?,?,?,?);", NSFValues, NSFKey, NSFAttribute, NSFValue, NSFDatatype];
687
- hasInitializationSucceeded = [self _prepareSQLite3Statement:&_storeValuesStatement theSQLStatement:theSQLStatement];
688
-
689
- if ((nil != outError) && (NO == hasInitializationSucceeded)) {
690
- *outError = [NSError errorWithDomain:NSFDomainKey
691
- code:NSFNanoStoreErrorKey
692
- userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"*** -[%@ %s]: failed to prepare _storeValuesStatement.", [self class], _cmd]
693
- forKey:NSLocalizedFailureReasonErrorKey]];
694
- }
695
- }
696
-
697
- if ((NULL == _storeKeysStatement) && (YES == hasInitializationSucceeded)) {
698
- NSString *theSQLStatement = [[NSString alloc]initWithFormat:@"INSERT INTO %@(%@, %@, %@, %@) VALUES (?,?,?,?);", NSFKeys, NSFKey, NSFPlist, NSFCalendarDate, NSFObjectClass];
699
- hasInitializationSucceeded = [self _prepareSQLite3Statement:&_storeKeysStatement theSQLStatement:theSQLStatement];
700
-
701
- if ((nil != outError) && (NO == hasInitializationSucceeded)) {
702
- *outError = [NSError errorWithDomain:NSFDomainKey
703
- code:NSFNanoStoreErrorKey
704
- userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"*** -[%@ %s]: failed to prepare _storeKeysStatement.", [self class], _cmd]
705
- forKey:NSLocalizedFailureReasonErrorKey]];
706
- }
707
- }
708
-
709
- return hasInitializationSucceeded;
710
- }
711
-
712
- - (void)_releasePreparedStatements
713
- {
714
- if (_storeValuesStatement != NULL) { sqlite3_finalize(_storeValuesStatement);_storeValuesStatement = NULL; }
715
- if (_storeKeysStatement != NULL) { sqlite3_finalize(_storeKeysStatement);_storeKeysStatement = NULL; }
716
- }
717
-
718
- - (void)_setIsOurTransaction:(BOOL)value
719
- {
720
- if (_isOurTransaction != value) {
721
- _isOurTransaction = value;
722
- }
723
- }
724
-
725
- - (BOOL)_isOurTransaction
726
- {
727
- return _isOurTransaction;
728
- }
729
-
730
- - (NSString*)_nestedDescriptionWithPrefixedSpace:(NSString *)prefixedSpace
731
- {
732
- if (nil == prefixedSpace) {
733
- prefixedSpace = @"";
734
- }
735
-
736
- NSMutableString *description = [NSMutableString string];
737
- [description appendString:@"\n"];
738
- [description appendString:[NSString stringWithFormat:@"%@NanoStore address : 0x%x\n", prefixedSpace, self]];
739
- [description appendString:[NSString stringWithFormat:@"%@Is our transaction? : %@\n", prefixedSpace, (_isOurTransaction ? @"Yes" : @"No")]];
740
- [description appendString:[NSString stringWithFormat:@"%@Save interval : %ld\n", prefixedSpace, (saveInterval == 0 ? 1 : saveInterval)]];
741
- [description appendString:[NSString stringWithFormat:@"%@Engine : %@\n", prefixedSpace, [nanoStoreEngine NSFP_nestedDescriptionWithPrefixedSpace:@" "]]];
742
-
743
- return description;
744
- }
745
-
746
- - (BOOL)_checkNanoStoreIsReadyAndReturnError:(out NSError **)outError
747
- {
748
- if (nil == [self nanoStoreEngine]) {
749
- if (nil != outError)
750
- *outError = [NSError errorWithDomain:NSFDomainKey
751
- code:NSFNanoStoreErrorKey
752
- userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"*** -[%@ %s]: the NSF store has not been set.", [self class], _cmd]
753
- forKey:NSLocalizedFailureReasonErrorKey]];
754
- return NO;
755
- }
756
-
757
- if ([[self nanoStoreEngine]isDatabaseOpen] == NO) {
758
- if (nil != outError)
759
- *outError = [NSError errorWithDomain:NSFDomainKey
760
- code:NSFNanoStoreErrorKey
761
- userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"*** -[%@ %s]: the store is not open.", [self class], _cmd]
762
- forKey:NSLocalizedFailureReasonErrorKey]];
763
- return NO;
764
- }
765
-
766
- return YES;
767
- }
768
-
769
- - (BOOL)_setupCachingSchema
770
- {
771
- NSString *theSQLStatement;
772
- BOOL success;
773
- NSArray *tables = [[self nanoStoreEngine]tables];
774
- NSString *rowUIDDatatype = NSFStringFromNanoDataType(NSFNanoTypeRowUID);
775
- NSString *stringDatatype = NSFStringFromNanoDataType(NSFNanoTypeString);
776
- NSString *dateDatatype = NSFStringFromNanoDataType(NSFNanoTypeDate);
777
-
778
- // Setup the Values table
779
- if ([tables containsObject:NSFValues] == NO) {
780
- theSQLStatement = [NSString stringWithFormat:@"CREATE TABLE %@(ROWID INTEGER PRIMARY KEY, %@ TEXT, %@ TEXT, %@ NONE, %@ TEXT);", NSFValues, NSFKey, NSFAttribute, NSFValue, NSFDatatype];
781
- success = (nil == [[[self nanoStoreEngine]executeSQL:theSQLStatement]error]);
782
- if (NO == success)
783
- return NO;
784
-
785
- [[self nanoStoreEngine]NSFP_insertStringValues:[NSArray arrayWithObjects:NSFValues, NSFRowIDColumnName, rowUIDDatatype, nil] forColumns:[NSArray arrayWithObjects:NSFP_TableIdentifier, NSFP_ColumnIdentifier, NSFP_DatatypeIdentifier, nil]table:NSFP_SchemaTable];
786
- [[self nanoStoreEngine]NSFP_insertStringValues:[NSArray arrayWithObjects:NSFValues, NSFKey, stringDatatype, nil] forColumns:[NSArray arrayWithObjects:NSFP_TableIdentifier, NSFP_ColumnIdentifier, NSFP_DatatypeIdentifier, nil]table:NSFP_SchemaTable];
787
- [[self nanoStoreEngine]NSFP_insertStringValues:[NSArray arrayWithObjects:NSFValues, NSFAttribute, stringDatatype, nil] forColumns:[NSArray arrayWithObjects:NSFP_TableIdentifier, NSFP_ColumnIdentifier, NSFP_DatatypeIdentifier, nil]table:NSFP_SchemaTable];
788
- [[self nanoStoreEngine]NSFP_insertStringValues:[NSArray arrayWithObjects:NSFValues, NSFValue, stringDatatype, nil] forColumns:[NSArray arrayWithObjects:NSFP_TableIdentifier, NSFP_ColumnIdentifier, NSFP_DatatypeIdentifier, nil]table:NSFP_SchemaTable];
789
- [[self nanoStoreEngine]NSFP_insertStringValues:[NSArray arrayWithObjects:NSFValues, NSFDatatype, stringDatatype, nil] forColumns:[NSArray arrayWithObjects:NSFP_TableIdentifier, NSFP_ColumnIdentifier, NSFP_DatatypeIdentifier, nil]table:NSFP_SchemaTable];
790
- }
791
-
792
- // Setup the Plist table
793
- if ([tables containsObject:NSFKeys] == NO) {
794
- theSQLStatement = [NSString stringWithFormat:@"CREATE TABLE %@(ROWID INTEGER PRIMARY KEY, %@ TEXT, %@ TEXT, %@ TEXT, %@ TEXT);", NSFKeys, NSFKey, NSFPlist, NSFCalendarDate, NSFObjectClass];
795
- success = (nil == [[[self nanoStoreEngine]executeSQL:theSQLStatement]error]);
796
- if (NO == success)
797
- return NO;
798
-
799
- [[self nanoStoreEngine]NSFP_insertStringValues:[NSArray arrayWithObjects:NSFKeys, NSFRowIDColumnName, rowUIDDatatype, nil] forColumns:[NSArray arrayWithObjects:NSFP_TableIdentifier, NSFP_ColumnIdentifier, NSFP_DatatypeIdentifier, nil]table:NSFP_SchemaTable];
800
- [[self nanoStoreEngine]NSFP_insertStringValues:[NSArray arrayWithObjects:NSFKeys, NSFKey, stringDatatype, nil] forColumns:[NSArray arrayWithObjects:NSFP_TableIdentifier, NSFP_ColumnIdentifier, NSFP_DatatypeIdentifier, nil]table:NSFP_SchemaTable];
801
- [[self nanoStoreEngine]NSFP_insertStringValues:[NSArray arrayWithObjects:NSFKeys, NSFPlist, stringDatatype, nil] forColumns:[NSArray arrayWithObjects:NSFP_TableIdentifier, NSFP_ColumnIdentifier, NSFP_DatatypeIdentifier, nil]table:NSFP_SchemaTable];
802
- [[self nanoStoreEngine]NSFP_insertStringValues:[NSArray arrayWithObjects:NSFKeys, dateDatatype, dateDatatype, nil] forColumns:[NSArray arrayWithObjects:NSFP_TableIdentifier, NSFP_ColumnIdentifier, NSFP_DatatypeIdentifier, nil]table:NSFP_SchemaTable];
803
- [[self nanoStoreEngine]NSFP_insertStringValues:[NSArray arrayWithObjects:NSFKeys, NSFObjectClass, stringDatatype, nil] forColumns:[NSArray arrayWithObjects:NSFP_TableIdentifier, NSFP_ColumnIdentifier, NSFP_DatatypeIdentifier, nil]table:NSFP_SchemaTable];
804
- }
805
-
806
- return YES;
807
- }
808
-
809
- - (BOOL)_storeDictionary:(NSDictionary *)someInfo forKey:(NSString *)aKey forClassNamed:(NSString *)className usingSQLite3Statement:(sqlite3_stmt *)storeValuesStatement error:(out NSError **)outError
810
- {
811
- if (nil == someInfo)
812
- [[NSException exceptionWithName:NSFUnexpectedParameterException
813
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: someInfo is nil.", [self class], _cmd]
814
- userInfo:nil]raise];
815
-
816
- if (nil == aKey)
817
- [[NSException exceptionWithName:NSFUnexpectedParameterException
818
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: aKey is nil.", [self class], _cmd]
819
- userInfo:nil]raise];
820
-
821
- if (nil == storeValuesStatement)
822
- [[NSException exceptionWithName:NSFUnexpectedParameterException
823
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: aStatement is NULL.", [self class], _cmd]
824
- userInfo:nil]raise];
825
-
826
- NSRange range = [aKey rangeOfString:@"."];
827
- if (NSNotFound != range.location)
828
- [[NSException exceptionWithName:NSFUnexpectedParameterException
829
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: aKey cannot contain a period ('.')", [self class], _cmd]
830
- userInfo:nil]raise];
831
-
832
- NSArray *keys = [someInfo allKeys];
833
- for (NSString *key in keys) {
834
- range = [key rangeOfString:@"."];
835
- if (NSNotFound != range.location)
836
- [[NSException exceptionWithName:NSFUnexpectedParameterException
837
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: the keys of the dictionary cannot contain a period ('.')", [self class], _cmd]
838
- userInfo:nil]raise];
839
- }
840
-
841
- const char *aKeyUTF8 = [aKey UTF8String];
842
- BOOL success = YES;
843
-
844
- // Flatten the dictionary
845
- {
846
- NSMutableArray *flattenedKeys = [NSMutableArray new];
847
- NSMutableArray *flattenedValues = [NSMutableArray new];
848
-
849
- @autoreleasepool {
850
- [self _flattenCollection:someInfo keys:&flattenedKeys values:&flattenedValues];
851
-
852
- NSUInteger i, count = [flattenedKeys count];
853
-
854
- success = NO;
855
-
856
- for (i = 0; i < count; i++) {
857
- NSString *attribute = [flattenedKeys objectAtIndex:i];
858
- id value = [flattenedValues objectAtIndex:i];
859
-
860
- // Reset, as required by SQLite...
861
- int status = sqlite3_reset (storeValuesStatement);
862
-
863
- // Since we're operating with extended result code support, extract the bits
864
- // and obtain the regular result code
865
- // For more info check: http://www.sqlite.org/c3ref/c_ioerr_access.html
866
-
867
- status = [NSFNanoEngine NSFP_stripBitsFromExtendedResultCode:status];
868
-
869
- if (SQLITE_OK == status) {
870
-
871
- // Bind and execute the statement...
872
- BOOL resultBindKey = (sqlite3_bind_text (storeValuesStatement, 1, aKeyUTF8, -1, SQLITE_STATIC) == SQLITE_OK);
873
- BOOL resultBindAttribute = (sqlite3_bind_text (storeValuesStatement, 2, [attribute UTF8String], -1, SQLITE_STATIC) == SQLITE_OK);
874
-
875
- // Take advantage of manifest typing
876
- // Branch the type of bind based on the type to be stored: NSString, NSData, NSDate or NSNumber
877
- NSFNanoDatatype valueDataType = [self _NSFDatatypeOfObject:value];
878
- BOOL resultBindValue = NO;
879
-
880
- switch (valueDataType) {
881
- case NSFNanoTypeData:
882
- resultBindValue = (sqlite3_bind_blob(storeValuesStatement, 3, [value bytes], [value length], NULL) == SQLITE_OK);
883
- break;
884
- case NSFNanoTypeString:
885
- case NSFNanoTypeDate:
886
- resultBindValue = (sqlite3_bind_text (storeValuesStatement, 3, [[self _stringFromValue:value]UTF8String], -1, SQLITE_STATIC) == SQLITE_OK);
887
- break;
888
- break;
889
- case NSFNanoTypeNumber:
890
- resultBindValue = (sqlite3_bind_double (storeValuesStatement, 3, [value doubleValue]) == SQLITE_OK);
891
- break;
892
- default:
893
- [[NSException exceptionWithName:NSFUnexpectedParameterException
894
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: datatype %@ cannot be stored because its class type is unknown.", [self class], _cmd, [value class]]
895
- userInfo:nil]raise];
896
- break;
897
- }
898
-
899
- // Store the element's datatype so we can recreate it later on when we read it back from the store...
900
- NSString *valueDatatypeString = NSFStringFromNanoDataType(valueDataType);
901
- BOOL resultBindDatatype = (sqlite3_bind_text (storeValuesStatement, 4, [valueDatatypeString UTF8String], -1, SQLITE_STATIC) == SQLITE_OK);
902
-
903
- success = (resultBindKey && resultBindAttribute && resultBindValue && resultBindDatatype);
904
- if (success) {
905
- [self _executeSQLite3StepUsingSQLite3Statement:storeValuesStatement];
906
- }
907
- }
908
- }
909
-
910
- }
911
- }
912
-
913
- if (YES == success) {
914
- // Save the Key and its Plist (if it applies)
915
- NSString *dictXML = nil;
916
- NSString *errorString = nil;
917
-
918
- NSData *dictData = [NSPropertyListSerialization dataFromPropertyList:someInfo format:NSPropertyListXMLFormat_v1_0 errorDescription:&errorString];
919
- if (nil != errorString) {
920
- NSLog(@" Dictionary: %@", someInfo);
921
- NSLog(@"*** -[%@ %@]: [NSPropertyListSerialization dataFromPropertyList] failure. %@", [self class], NSStringFromSelector(_cmd), errorString);
922
- NSLog(@" Dictionary info: %@", someInfo);
923
- success = NO;
924
- } else {
925
- if ([dictData length] > 0)
926
- dictXML = [[NSString alloc]initWithBytes:[dictData bytes]length:[dictData length]encoding:NSUTF8StringEncoding];
927
- else
928
- dictXML = @"";
929
-
930
- if (nil == dictXML) {
931
- if (nil != outError)
932
- *outError = [NSError errorWithDomain:NSFDomainKey
933
- code:NSF_Private_InvalidParameterDataCodeKey
934
- userInfo:[NSDictionary dictionaryWithObject:@"Couldn't serialize the object: %@"
935
- forKey:NSLocalizedDescriptionKey]];
936
- success = NO;
937
- } else {
938
- // Reset, as required by SQLite...
939
- int status = sqlite3_reset (_storeKeysStatement);
940
-
941
- // Since we're operating with extended result code support, extract the bits
942
- // and obtain the regular result code
943
- // For more info check: http://www.sqlite.org/c3ref/c_ioerr_access.html
944
-
945
- status = [NSFNanoEngine NSFP_stripBitsFromExtendedResultCode:status];
946
-
947
- // Bind and execute the statement...
948
- if (SQLITE_OK == status) {
949
-
950
- BOOL resultBindKey = (sqlite3_bind_text (_storeKeysStatement, 1, aKeyUTF8, -1, SQLITE_STATIC) == SQLITE_OK);
951
- BOOL resultBindPlist = (sqlite3_bind_text (_storeKeysStatement, 2, [dictXML UTF8String], -1, SQLITE_STATIC) == SQLITE_OK);
952
- BOOL resultBindCalendarDate = (sqlite3_bind_text (_storeKeysStatement, 3, [[NSFNanoStore _calendarDateToString:[NSDate date]]UTF8String], -1, SQLITE_STATIC) == SQLITE_OK);
953
- BOOL resultBindClass = (sqlite3_bind_text (_storeKeysStatement, 4, [className UTF8String], -1, SQLITE_STATIC) == SQLITE_OK);
954
-
955
- success = (resultBindKey && resultBindPlist && resultBindCalendarDate && resultBindClass);
956
- if (success) {
957
- [self _executeSQLite3StepUsingSQLite3Statement:_storeKeysStatement];
958
- }
959
- }
960
- }
961
- }
962
- }
963
-
964
- return success;
965
- }
966
-
967
- - (NSFNanoDatatype)_NSFDatatypeOfObject:(id)value
968
- {
969
- NSFNanoDatatype type = NSFNanoTypeUnknown;
970
-
971
- if ([value isKindOfClass:[NSString class]])
972
- return NSFNanoTypeString;
973
- else if ([value isKindOfClass:[NSNumber class]])
974
- return NSFNanoTypeNumber;
975
- else if ([value isKindOfClass:[NSDate class]])
976
- return NSFNanoTypeDate;
977
- else if ([value isKindOfClass:[NSData class]])
978
- return NSFNanoTypeData;
979
-
980
- return type;
981
- }
982
-
983
- - (NSString *)_stringFromValue:(id)aValue
984
- {
985
- if (nil != aValue) {
986
- if ([aValue isKindOfClass:[NSString class]]) {
987
- return aValue;
988
- } else if ([aValue isKindOfClass:[NSDate class]]) {
989
- return [NSFNanoStore _calendarDateToString:aValue];
990
- } else if ([aValue respondsToSelector:@selector(stringValue)]) {
991
- return [aValue stringValue];
992
- } else if ([aValue respondsToSelector:@selector(description)]) {
993
- return [aValue description];
994
- } else {
995
- [[NSException exceptionWithName:NSFUnexpectedParameterException
996
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: datatype %@ doesn't respond to selector 'stringValue' or 'description'.", [self class], _cmd, [aValue class]]
997
- userInfo:nil]raise];
998
- }
999
- }
1000
-
1001
- return [[NSNull null]description];
1002
- }
1003
-
1004
- + (NSString *)_calendarDateToString:(NSDate *)aDate
1005
- {
1006
- static NSDateFormatter *__sNSFNanoStoreDateFormatter = nil;
1007
- if (nil == __sNSFNanoStoreDateFormatter) {
1008
- __sNSFNanoStoreDateFormatter = [NSDateFormatter new];
1009
- [__sNSFNanoStoreDateFormatter setDateStyle:NSDateFormatterShortStyle];
1010
- [__sNSFNanoStoreDateFormatter setTimeStyle:NSDateFormatterFullStyle];
1011
- [__sNSFNanoStoreDateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss:SSS"];
1012
- }
1013
-
1014
- if (nil == aDate)
1015
- [[NSException exceptionWithName:NSFUnexpectedParameterException
1016
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: aDate is nil.", [self class], _cmd]
1017
- userInfo:nil]raise];
1018
-
1019
- return [__sNSFNanoStoreDateFormatter stringFromDate:aDate];
1020
- }
1021
-
1022
- - (void)_flattenCollection:(NSDictionary *)info keys:(NSMutableArray **)flattenedKeys values:(NSMutableArray **)flattenedValues
1023
- {
1024
- NSMutableArray *keyPath = [NSMutableArray new];
1025
- [self _flattenCollection:info keyPath:&keyPath keys:flattenedKeys values:flattenedValues];
1026
- }
1027
-
1028
- - (void)_flattenCollection:(id)someObject keyPath:(NSMutableArray **)aKeyPath keys:(NSMutableArray **)flattenedKeys values:(NSMutableArray **)flattenedValues
1029
- {
1030
- BOOL isOfTypeCollection = ([someObject isKindOfClass:[NSDictionary class]] || [someObject isKindOfClass:[NSArray class]]);
1031
-
1032
- if (NO == isOfTypeCollection) {
1033
- if (nil != flattenedKeys) {
1034
- NSString *keyPath = [*aKeyPath componentsJoinedByString:@"."];
1035
- [*flattenedKeys addObject:keyPath];
1036
- [*flattenedValues addObject:someObject];
1037
- }
1038
- } else {
1039
- if ([someObject isKindOfClass:[NSDictionary class]]) {
1040
- for (NSString *key in someObject) {
1041
- [*aKeyPath addObject:key];
1042
- [self _flattenCollection:[someObject objectForKey:key] keyPath:aKeyPath keys:flattenedKeys values:flattenedValues];
1043
- [*aKeyPath removeLastObject];
1044
- }
1045
- } else if ([someObject isKindOfClass:[NSArray class]]) {
1046
- for (id anObject in someObject) {
1047
- [self _flattenCollection:anObject keyPath:aKeyPath keys:flattenedKeys values:flattenedValues];
1048
- }
1049
- }
1050
- }
1051
- }
1052
-
1053
- - (BOOL)_prepareSQLite3Statement:(sqlite3_stmt **)aStatement theSQLStatement:(NSString *)aSQLQuery
1054
- {
1055
- // Prepare SQLite's VM. It's placed here so we can speed up stores...
1056
- sqlite3* sqliteDatabase = [[self nanoStoreEngine]sqlite];
1057
- int status = SQLITE_OK;
1058
- BOOL continueLooping = YES;
1059
- const char *query = [aSQLQuery UTF8String];
1060
-
1061
- do {
1062
- status = sqlite3_prepare_v2(sqliteDatabase, query, (int)strlen(query), aStatement, &query);
1063
-
1064
- // Since we're operating with extended result code support, extract the bits
1065
- // and obtain the regular result code
1066
- // For more info check: http://www.sqlite.org/c3ref/c_ioerr_access.html
1067
-
1068
- status = [NSFNanoEngine NSFP_stripBitsFromExtendedResultCode:status];
1069
-
1070
- continueLooping = ((SQLITE_LOCKED == status) || (SQLITE_BUSY == status));
1071
- } while (continueLooping);
1072
-
1073
- return (SQLITE_OK == status);
1074
- }
1075
-
1076
- - (void)_executeSQLite3StepUsingSQLite3Statement:(sqlite3_stmt *)aStatement
1077
- {
1078
- BOOL waitingForRow = YES;
1079
-
1080
- do {
1081
- int status = sqlite3_step(aStatement);
1082
-
1083
- // Since we're operating with extended result code support, extract the bits
1084
- // and obtain the regular result code
1085
- // For more info check: http://www.sqlite.org/c3ref/c_ioerr_access.html
1086
-
1087
- status = [NSFNanoEngine NSFP_stripBitsFromExtendedResultCode:status];
1088
-
1089
- switch (status) {
1090
- case SQLITE_BUSY:
1091
- break;
1092
- case SQLITE_OK:
1093
- case SQLITE_DONE:
1094
- waitingForRow = NO;
1095
- break;
1096
- case SQLITE_ROW:
1097
- waitingForRow = NO;
1098
- break;
1099
- default:
1100
- waitingForRow = NO;
1101
- break;
1102
- }
1103
- } while (waitingForRow);
1104
- }
1105
-
1106
- - (BOOL)_addObjectsFromArray:(NSArray *)someObjects forceSave:(BOOL)forceSave error:(out NSError **)outError
1107
- {
1108
- // Collect the objects
1109
- [addedObjects addObjectsFromArray:someObjects];
1110
-
1111
- // No need to continue if there's nothing to be saved
1112
- NSUInteger unsavedObjectsCount = [addedObjects count];
1113
- if (0 == unsavedObjectsCount) {
1114
- return YES;
1115
- }
1116
-
1117
- if ((YES == forceSave) || (0 == unsavedObjectsCount % saveInterval)) {
1118
- NSDate *startStoringDate = [NSDate date];
1119
-
1120
- NSDate *startRemovingDate = [NSDate date];
1121
- _NSFLog(@" Removing the objects to be stored...");
1122
- NSMutableSet *keys = [NSMutableSet new];
1123
- NSInteger i = unsavedObjectsCount;
1124
-
1125
- // Remove all objects non conforming with the NSFNanoObjectProtocol
1126
- while ( i-- ) {
1127
- id object = [addedObjects objectAtIndex:i];
1128
- if (NO == [object conformsToProtocol:@protocol(NSFNanoObjectProtocol)]) {
1129
- [addedObjects removeObjectAtIndex:i];
1130
- i--;
1131
- continue;
1132
- }
1133
-
1134
- NSString *objectKey = [(id)object nanoObjectKey];
1135
- if (nil == objectKey) {
1136
- [[NSException exceptionWithName:NSFNanoObjectBehaviorException
1137
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: unexpected NSFNanoObject behavior. Reason: the object's key is nil.", [self class], _cmd]
1138
- userInfo:nil]raise];
1139
- }
1140
- [keys addObject:objectKey];
1141
- }
1142
-
1143
- // Recalculate how many elements we have left
1144
- unsavedObjectsCount = [addedObjects count];
1145
-
1146
- if (unsavedObjectsCount > 0) {
1147
- if (NO == [self removeObjectsWithKeysInArray:[keys allObjects] error:outError]) {
1148
- [[NSException exceptionWithName:NSFNanoStoreUnableToManipulateStoreException
1149
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: %@", [self class], _cmd, [*outError localizedDescription]]
1150
- userInfo:nil]raise];
1151
- }
1152
- }
1153
-
1154
- NSTimeInterval secondsRemoving = [[NSDate date]timeIntervalSinceDate:startRemovingDate];
1155
- _NSFLog(@" Done. Removing the objects took %.3f seconds", secondsRemoving);
1156
-
1157
- // Store the objects...
1158
- BOOL transactionStartedHere = [self beginTransactionAndReturnError:nil];
1159
-
1160
- _NSFLog(@" Storing %ld objects...", unsavedObjectsCount);
1161
-
1162
- // Reset the default save interval if needed...
1163
- if (0 == saveInterval) {
1164
- self.saveInterval = 1;
1165
- }
1166
-
1167
- for (id object in addedObjects) {
1168
- @autoreleasepool {
1169
- // If the object was originally created by storing a class not recognized by this process, honor it and store it with the right class string.
1170
- NSString *className = nil;
1171
- if (YES == [object respondsToSelector:@selector(originalClassString)]) {
1172
- className = [object originalClassString];
1173
- }
1174
-
1175
- // Otherwise, just save the class name of the object being stored
1176
- if (nil == className) {
1177
- className = NSStringFromClass([object class]);
1178
- }
1179
-
1180
- if (NO == [self _storeDictionary:[object nanoObjectDictionaryRepresentation] forKey:[(id)object nanoObjectKey] forClassNamed:className usingSQLite3Statement:_storeValuesStatement error:outError]) {
1181
- [[NSException exceptionWithName:NSFNanoStoreUnableToManipulateStoreException
1182
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: %@", [self class], _cmd, [*outError localizedDescription]]
1183
- userInfo:nil]raise];
1184
- }
1185
-
1186
- i++;
1187
-
1188
- // Commit every 'saveInterval' interations...
1189
- if ((0 == i % self.saveInterval) && transactionStartedHere) {
1190
- if (NO == [self commitTransactionAndReturnError:outError]) {
1191
- [[NSException exceptionWithName:NSFNanoStoreUnableToManipulateStoreException
1192
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: %@", [self class], _cmd, [*outError localizedDescription]]
1193
- userInfo:nil]raise];
1194
- }
1195
-
1196
- if (YES == transactionStartedHere) {
1197
- transactionStartedHere = [self beginTransactionAndReturnError:outError];
1198
- if (NO == transactionStartedHere) {
1199
- [[NSException exceptionWithName:NSFNanoStoreUnableToManipulateStoreException
1200
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: %@", [self class], _cmd, [*outError localizedDescription]]
1201
- userInfo:nil]raise];
1202
- }
1203
- }
1204
- }
1205
- }
1206
- }
1207
-
1208
- // Commit the changes
1209
- if (transactionStartedHere) {
1210
- if (NO == [self commitTransactionAndReturnError:outError]) {
1211
- [[NSException exceptionWithName:NSFNanoStoreUnableToManipulateStoreException
1212
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: %@", [self class], _cmd, [*outError localizedDescription]]
1213
- userInfo:nil]raise];
1214
- }
1215
- }
1216
-
1217
- NSTimeInterval secondsStoring = [[NSDate date]timeIntervalSinceDate:startStoringDate];
1218
- double ratio = unsavedObjectsCount/secondsStoring;
1219
- _NSFLog(@" Done. Storing the objects took %.3f seconds (%.0f keys/sec.)", secondsStoring, ratio);
1220
-
1221
- [addedObjects removeAllObjects];
1222
- }
1223
-
1224
- return YES;
1225
- }
1226
-
1227
- + (NSDictionary *)_defaultTestData
1228
- {
1229
- NSArray *dishesInfo = [NSArray arrayWithObject:@"Cassoulet"];
1230
- NSDictionary *citiesInfo = [NSDictionary dictionaryWithObjectsAndKeys:
1231
- @"Bouillabaisse", @"Marseille",
1232
- dishesInfo, @"Nice",
1233
- @"Good", @"Rating",
1234
- nil, nil];
1235
- NSDictionary *countriesInfo = [NSDictionary dictionaryWithObjectsAndKeys:
1236
- @"Barcelona", @"Spain",
1237
- @"San Francisco", @"USA",
1238
- citiesInfo, @"France",
1239
- @"Very Good", @"Rating",
1240
- nil, nil];
1241
- NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:
1242
- @"Tito", @"FirstName",
1243
- @"Ciuro", @"LastName",
1244
- countriesInfo, @"Countries",
1245
- [NSNumber numberWithUnsignedInt:(arc4random() % 32767) + 1], @"SomeNumber",
1246
- @"To be decided", @"Rating",
1247
- nil, nil];
1248
-
1249
- return info;
1250
- }
1251
-
1252
- // ----------------------------------------------
1253
- // Backup the store to a specific location
1254
- // ----------------------------------------------
1255
-
1256
- - (BOOL)_backupFileStoreToDirectoryAtPath:(NSString *)backupPath extension:(NSString *)anExtension compact:(BOOL)flag error:(out NSError **)outError
1257
- {
1258
- NSString *filePath = [self filePath];
1259
- if ((anExtension != nil) && (NO == [backupPath hasSuffix:anExtension]))
1260
- backupPath = [NSString stringWithFormat:@"%@.%@", backupPath, anExtension];
1261
-
1262
- // Make sure we the destination path is not the same as the source!
1263
- if (YES == [filePath isEqualToString:backupPath]) {
1264
- if (nil != outError)
1265
- *outError = [NSError errorWithDomain:NSFDomainKey
1266
- code:NSFNanoStoreErrorKey
1267
- userInfo:[NSDictionary dictionaryWithObject:@"Cannot backup store. The source and destination directories are the same."
1268
- forKey:NSLocalizedDescriptionKey]];
1269
- return NO;
1270
- }
1271
-
1272
- NSFileManager *fm = [NSFileManager defaultManager];
1273
- BOOL destinationLocationIsClear = YES;
1274
-
1275
- if (YES == [fm fileExistsAtPath:backupPath]) {
1276
- destinationLocationIsClear = [fm removeItemAtPath:backupPath error:nil];
1277
- if (NO == destinationLocationIsClear) {
1278
- if (nil != outError)
1279
- *outError = [NSError errorWithDomain:NSFDomainKey
1280
- code:NSF_Private_MacOSXErrorCodeKey
1281
- userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"Existing file couldn't be removed in path: %@. Backup cannot proceed.", backupPath]
1282
- forKey:NSLocalizedDescriptionKey]];
1283
- return NO;
1284
- }
1285
- }
1286
-
1287
- if (flag)
1288
- // First compact the store
1289
- [self compactStoreAndReturnError:outError];
1290
-
1291
- // Try to copy the file to the destination
1292
- if ([fm fileExistsAtPath:filePath]) {
1293
- [fm copyItemAtPath:filePath toPath:backupPath error:outError];
1294
- } else {
1295
- if (nil != outError)
1296
- *outError = [NSError errorWithDomain:NSFDomainKey
1297
- code:NSF_Private_MacOSXErrorCodeKey
1298
- userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"File doesn't exist at path: %@", filePath]
1299
- forKey:NSLocalizedDescriptionKey]];
1300
- return NO;
1301
- }
1302
-
1303
- return YES;
1304
- }
1305
-
1306
- - (BOOL)_backupMemoryStoreToDirectoryAtPath:(NSString *)backupPath extension:(NSString *)anExtension compact:(BOOL)flag error:(out NSError **)outError
1307
- {
1308
- NSString *filePath = [self filePath];
1309
- if ((anExtension != nil) && (NO == [backupPath hasSuffix:anExtension])) {
1310
- backupPath = [NSString stringWithFormat:@"%@.%@", backupPath, anExtension];
1311
- }
1312
-
1313
- // Make sure we the destination path is not the same as the source!
1314
- if (YES == [filePath isEqualToString:backupPath]) {
1315
- if (nil != outError)
1316
- *outError = [NSError errorWithDomain:NSFDomainKey
1317
- code:NSFNanoStoreErrorKey
1318
- userInfo:[NSDictionary dictionaryWithObject:@"Cannot backup store. The source and destination directories are the same."
1319
- forKey:NSLocalizedDescriptionKey]];
1320
- return NO;
1321
- }
1322
-
1323
- if (flag) {
1324
- // First compact the store
1325
- [self compactStoreAndReturnError:outError];
1326
- }
1327
-
1328
- NSFileManager *fm = [NSFileManager defaultManager];
1329
- BOOL destinationLocationIsClear = YES;
1330
-
1331
- if (YES == [fm fileExistsAtPath:backupPath]) {
1332
- destinationLocationIsClear = [fm removeItemAtPath:backupPath error:nil];
1333
- if (NO == destinationLocationIsClear) {
1334
- if (nil != outError)
1335
- *outError = [NSError errorWithDomain:NSFDomainKey
1336
- code:NSF_Private_MacOSXErrorCodeKey
1337
- userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"Existing file couldn't be removed in path: %@. Backup cannot proceed.", backupPath]
1338
- forKey:NSLocalizedDescriptionKey]];
1339
- return NO;
1340
- }
1341
- }
1342
-
1343
- NSString *tempPath = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSFNanoEngine stringWithUUID]];
1344
-
1345
- NSFNanoStore *fileDB = [NSFNanoStore createStoreWithType:NSFPersistentStoreType path:tempPath];
1346
- if (NO == [fileDB openWithError:outError])
1347
- return NO;
1348
-
1349
- // Attach the file-based database to the memory-based one
1350
- NSString *theSQLStatement = [NSString stringWithFormat:@"ATTACH DATABASE '%@' AS fileDB", [fileDB filePath]];
1351
- [self _executeSQL:theSQLStatement];
1352
-
1353
- // Transfer the NSFKeys table
1354
- NSString *columns = [[[self nanoStoreEngine]columnsForTable:NSFKeys]componentsJoinedByString:@", "];
1355
- theSQLStatement = [NSString stringWithFormat:@"INSERT INTO fileDB.%@ (%@) SELECT * FROM main.%@", NSFKeys, columns, NSFKeys];
1356
- [self _executeSQL:theSQLStatement];
1357
-
1358
- // Transfer the NSFValues table
1359
- columns = [[[self nanoStoreEngine]columnsForTable:NSFValues]componentsJoinedByString:@", "];
1360
- theSQLStatement = [NSString stringWithFormat:@"INSERT INTO fileDB.%@ (%@) SELECT * FROM main.%@", NSFValues, columns, NSFValues];
1361
- [self _executeSQL:theSQLStatement];
1362
-
1363
- // Safely detach the file-based database
1364
- [self _executeSQL:@"DETACH DATABASE fileDB"];
1365
-
1366
- // We can now close the database
1367
- [fileDB closeWithError:outError];
1368
-
1369
- // Move the file to the specified destination
1370
- return [fm moveItemAtPath:tempPath toPath:backupPath error:outError];
1371
- }
1372
-
1373
- /** \endcond */
1374
-
1375
- @end