nano-store 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +3 -0
- data/.gitmodules +3 -0
- data/.rvmrc +1 -0
- data/Gemfile +4 -0
- data/LICENSE +25 -0
- data/README.md +193 -0
- data/Rakefile +1 -0
- data/app/app_delegate.rb +5 -0
- data/lib/nano-store.rb +1 -0
- data/lib/nano_store/bag.rb +98 -0
- data/lib/nano_store/model.rb +142 -0
- data/lib/nano_store/nano_store.rb +36 -0
- data/lib/nano_store/store_extension.rb +150 -0
- data/lib/nano_store/version.rb +3 -0
- data/lib/nano_store.rb +14 -0
- data/nano-store.gemspec +17 -0
- data/resources/.gitignore +0 -0
- data/spec/bag_spec.rb +66 -0
- data/spec/model_spec.rb +130 -0
- data/spec/nano_store_spec.rb +48 -0
- data/spec/store_extension_spec.rb +110 -0
- data/vendor/NanoStore/Classes/Advanced/NSFNanoEngine.h +542 -0
- data/vendor/NanoStore/Classes/Advanced/NSFNanoEngine.m +1781 -0
- data/vendor/NanoStore/Classes/Advanced/NSFNanoResult.h +137 -0
- data/vendor/NanoStore/Classes/Advanced/NSFNanoResult.m +265 -0
- data/vendor/NanoStore/Classes/Private/NSFNanoBag_Private.h +37 -0
- data/vendor/NanoStore/Classes/Private/NSFNanoEngine_Private.h +69 -0
- data/vendor/NanoStore/Classes/Private/NSFNanoExpression_Private.h +35 -0
- data/vendor/NanoStore/Classes/Private/NSFNanoGlobals_Private.h +99 -0
- data/vendor/NanoStore/Classes/Private/NSFNanoObject_Private.h +35 -0
- data/vendor/NanoStore/Classes/Private/NSFNanoPredicate_Private.h +35 -0
- data/vendor/NanoStore/Classes/Private/NSFNanoResult_Private.h +43 -0
- data/vendor/NanoStore/Classes/Private/NSFNanoSearch_Private.h +48 -0
- data/vendor/NanoStore/Classes/Private/NSFNanoStore_Private.h +57 -0
- data/vendor/NanoStore/Classes/Private/NanoStore_Private.h +37 -0
- data/vendor/NanoStore/Classes/Public/NSFNanoBag.h +306 -0
- data/vendor/NanoStore/Classes/Public/NSFNanoBag.m +485 -0
- data/vendor/NanoStore/Classes/Public/NSFNanoExpression.h +125 -0
- data/vendor/NanoStore/Classes/Public/NSFNanoExpression.m +103 -0
- data/vendor/NanoStore/Classes/Public/NSFNanoGlobals.h +323 -0
- data/vendor/NanoStore/Classes/Public/NSFNanoGlobals.m +145 -0
- data/vendor/NanoStore/Classes/Public/NSFNanoObject.h +298 -0
- data/vendor/NanoStore/Classes/Public/NSFNanoObject.m +187 -0
- data/vendor/NanoStore/Classes/Public/NSFNanoObjectProtocol.h +119 -0
- data/vendor/NanoStore/Classes/Public/NSFNanoPredicate.h +123 -0
- data/vendor/NanoStore/Classes/Public/NSFNanoPredicate.m +130 -0
- data/vendor/NanoStore/Classes/Public/NSFNanoSearch.h +381 -0
- data/vendor/NanoStore/Classes/Public/NSFNanoSearch.m +835 -0
- data/vendor/NanoStore/Classes/Public/NSFNanoSortDescriptor.h +124 -0
- data/vendor/NanoStore/Classes/Public/NSFNanoSortDescriptor.m +79 -0
- data/vendor/NanoStore/Classes/Public/NSFNanoStore.h +475 -0
- data/vendor/NanoStore/Classes/Public/NSFNanoStore.m +1375 -0
- data/vendor/NanoStore/Classes/Public/NanoStore.h +463 -0
- data/vendor/NanoStore/LICENSE +25 -0
- data/vendor/NanoStore/NanoStore.bridgesupport +1215 -0
- data/vendor/NanoStore/README.md +411 -0
- metadata +118 -0
@@ -0,0 +1,485 @@
|
|
1
|
+
/*
|
2
|
+
NSFNanoBag.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 "NSFNanoBag.h"
|
28
|
+
#import "NSFNanoBag_Private.h"
|
29
|
+
#import "NSFNanoGlobals.h"
|
30
|
+
#import "NSFNanoGlobals_Private.h"
|
31
|
+
#import "NSFNanoStore_Private.h"
|
32
|
+
#import "NSFNanoSearch_Private.h"
|
33
|
+
|
34
|
+
@implementation NSFNanoBag
|
35
|
+
{
|
36
|
+
@protected
|
37
|
+
/** \cond */
|
38
|
+
NSMutableDictionary *savedObjects;
|
39
|
+
NSMutableDictionary *unsavedObjects;
|
40
|
+
NSMutableDictionary *removedObjects;
|
41
|
+
/** \endcond */
|
42
|
+
}
|
43
|
+
|
44
|
+
@synthesize store, name, key, savedObjects, unsavedObjects, removedObjects, hasUnsavedChanges;
|
45
|
+
|
46
|
+
+ (NSFNanoBag*)bag
|
47
|
+
{
|
48
|
+
return [[self alloc]initBagWithName:nil andObjects:[NSArray array]];
|
49
|
+
}
|
50
|
+
|
51
|
+
+ (NSFNanoBag*)bagWithObjects:(NSArray *)someObjects
|
52
|
+
{
|
53
|
+
return [[self alloc]initBagWithName:nil andObjects:someObjects];
|
54
|
+
}
|
55
|
+
|
56
|
+
+ bagWithName:(NSString *)theName
|
57
|
+
{
|
58
|
+
return [[self alloc]initBagWithName:theName andObjects:[NSArray array]];
|
59
|
+
}
|
60
|
+
|
61
|
+
+ bagWithName:(NSString *)theName andObjects:(NSArray *)someObjects
|
62
|
+
{
|
63
|
+
return [[self alloc]initBagWithName:theName andObjects:someObjects];
|
64
|
+
}
|
65
|
+
|
66
|
+
- (id)initBagWithName:(NSString *)theName andObjects:(NSArray *)someObjects
|
67
|
+
{
|
68
|
+
if ((self = [self init])) {
|
69
|
+
NSError *outError = nil;
|
70
|
+
if (NO == [self addObjectsFromArray:someObjects error:&outError]) {
|
71
|
+
NSLog(@"%@", [NSString stringWithFormat:@"*** -[%@ %s]: a problem occurred while initializing the NanoBag, leaving it in an inconsistent state. Reason: %@.", [self class], _cmd, [outError localizedDescription]]);
|
72
|
+
}
|
73
|
+
|
74
|
+
name = [theName copy];
|
75
|
+
hasUnsavedChanges = YES;
|
76
|
+
}
|
77
|
+
|
78
|
+
return self;
|
79
|
+
}
|
80
|
+
|
81
|
+
/** \cond */
|
82
|
+
|
83
|
+
- (id)init
|
84
|
+
{
|
85
|
+
if ((self = [super init])) {
|
86
|
+
key = [NSFNanoEngine stringWithUUID];
|
87
|
+
savedObjects = [NSMutableDictionary new];
|
88
|
+
unsavedObjects = [NSMutableDictionary new];
|
89
|
+
removedObjects = [NSMutableDictionary new];
|
90
|
+
|
91
|
+
hasUnsavedChanges = NO;
|
92
|
+
}
|
93
|
+
|
94
|
+
return self;
|
95
|
+
}
|
96
|
+
|
97
|
+
- (id)copyWithZone:(NSZone *)zone
|
98
|
+
{
|
99
|
+
NSFNanoBag *copy = [[[self class]allocWithZone:zone]initNanoObjectFromDictionaryRepresentation:[self dictionaryRepresentation] forKey:[NSFNanoEngine stringWithUUID] store:store];
|
100
|
+
return copy;
|
101
|
+
}
|
102
|
+
|
103
|
+
|
104
|
+
- (id)rootObject
|
105
|
+
{
|
106
|
+
return self;
|
107
|
+
}
|
108
|
+
|
109
|
+
#pragma mark -
|
110
|
+
|
111
|
+
- (void)setName:(NSString *)aName
|
112
|
+
{
|
113
|
+
name = [aName copy];
|
114
|
+
hasUnsavedChanges = YES;
|
115
|
+
}
|
116
|
+
|
117
|
+
/** \endcond */
|
118
|
+
|
119
|
+
- (NSString *)name
|
120
|
+
{
|
121
|
+
return name;
|
122
|
+
}
|
123
|
+
|
124
|
+
- (NSUInteger)count
|
125
|
+
{
|
126
|
+
return savedObjects.count + unsavedObjects.count;
|
127
|
+
}
|
128
|
+
|
129
|
+
- (NSString*)description
|
130
|
+
{
|
131
|
+
NSMutableString *description = [NSMutableString string];
|
132
|
+
|
133
|
+
[description appendString:@"\n"];
|
134
|
+
[description appendString:[NSString stringWithFormat:@"NanoBag address : 0x%x\n", self]];
|
135
|
+
[description appendString:[NSString stringWithFormat:@"Name : %@\n", (nil != name) ? name : @"<untitled>"]];
|
136
|
+
[description appendString:[NSString stringWithFormat:@"Document store : 0x%x\n", store]];
|
137
|
+
[description appendString:[NSString stringWithFormat:@"Has unsaved changes? : %@\n", (hasUnsavedChanges ? @"YES" : @"NO")]];
|
138
|
+
[description appendString:[NSString stringWithFormat:@"Saved objects : %ld key/value pairs\n", [savedObjects count]]];
|
139
|
+
[description appendString:[NSString stringWithFormat:@"Unsaved objects : %ld key/value pairs\n", [unsavedObjects count]]];
|
140
|
+
[description appendString:[NSString stringWithFormat:@"Removed objects : %ld key/value pairs\n", [removedObjects count]]];
|
141
|
+
|
142
|
+
return description;
|
143
|
+
}
|
144
|
+
|
145
|
+
- (BOOL)isEqualToNanoBag:(NSFNanoBag *)otherNanoBag
|
146
|
+
{
|
147
|
+
if (self == otherNanoBag) {
|
148
|
+
return YES;
|
149
|
+
}
|
150
|
+
|
151
|
+
BOOL success = YES;
|
152
|
+
|
153
|
+
NSArray *sortedArraySelf = [[[self savedObjects]allKeys]sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
|
154
|
+
NSArray *sortedArrayOther = [[[otherNanoBag savedObjects]allKeys]sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
|
155
|
+
if (NO == [sortedArraySelf isEqualToArray:sortedArrayOther]) {
|
156
|
+
success = NO;
|
157
|
+
} else {
|
158
|
+
sortedArraySelf = [[[self unsavedObjects]allKeys]sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
|
159
|
+
sortedArrayOther = [[[otherNanoBag unsavedObjects]allKeys]sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
|
160
|
+
if (NO == [sortedArraySelf isEqualToArray:sortedArrayOther]) {
|
161
|
+
success = NO;
|
162
|
+
} else {
|
163
|
+
sortedArraySelf = [[[self removedObjects]allKeys]sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
|
164
|
+
sortedArrayOther = [[[otherNanoBag removedObjects]allKeys]sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
|
165
|
+
if (NO == [sortedArraySelf isEqualToArray:sortedArrayOther]) {
|
166
|
+
success = NO;
|
167
|
+
}
|
168
|
+
}
|
169
|
+
}
|
170
|
+
|
171
|
+
return success;
|
172
|
+
}
|
173
|
+
|
174
|
+
- (NSDictionary *)dictionaryRepresentation
|
175
|
+
{
|
176
|
+
// Iterate the objects collecting the object keys
|
177
|
+
NSMutableArray *objectKeys = [NSMutableArray new];
|
178
|
+
for (NSString *objectKey in self.savedObjects) {
|
179
|
+
[objectKeys addObject:objectKey];
|
180
|
+
}
|
181
|
+
for (NSString *objectKey in self.unsavedObjects) {
|
182
|
+
[objectKeys addObject:objectKey];
|
183
|
+
}
|
184
|
+
|
185
|
+
NSMutableDictionary *info = [NSMutableDictionary dictionary];
|
186
|
+
|
187
|
+
if (nil != name) {
|
188
|
+
[info setObject:name forKey:NSF_Private_NSFNanoBag_Name];
|
189
|
+
}
|
190
|
+
[info setObject:self.key forKey:NSF_Private_NSFNanoBag_NSFKey];
|
191
|
+
[info setObject:objectKeys forKey:NSF_Private_NSFNanoBag_NSFObjectKeys];
|
192
|
+
|
193
|
+
return info;
|
194
|
+
}
|
195
|
+
|
196
|
+
#pragma mark -
|
197
|
+
|
198
|
+
- (BOOL)addObject:(id <NSFNanoObjectProtocol>)object error:(out NSError **)outError
|
199
|
+
{
|
200
|
+
if (NO == [(id)object conformsToProtocol:@protocol(NSFNanoObjectProtocol)]) {
|
201
|
+
[[NSException exceptionWithName:NSFNonConformingNanoObjectProtocolException
|
202
|
+
reason:[NSString stringWithFormat:@"*** -[%@ %s]: the object does not conform to NSFNanoObjectProtocol.", [self class], _cmd]
|
203
|
+
userInfo:nil]raise];
|
204
|
+
}
|
205
|
+
|
206
|
+
NSString *objectKey = [(id)object nanoObjectKey];
|
207
|
+
NSDictionary *info = [(id)object dictionaryRepresentation];
|
208
|
+
|
209
|
+
if (objectKey && info) {
|
210
|
+
[savedObjects removeObjectForKey:objectKey];
|
211
|
+
[unsavedObjects setObject:object forKey:objectKey];
|
212
|
+
[removedObjects removeObjectForKey:objectKey];
|
213
|
+
hasUnsavedChanges = YES;
|
214
|
+
} else {
|
215
|
+
NSString *message = nil;
|
216
|
+
if (nil == objectKey)
|
217
|
+
message = [NSString stringWithFormat:@"*** -[%@ %s]: unexpected NSFNanoObject behavior. Reason: the object's key is nil.", [self class], _cmd];
|
218
|
+
else
|
219
|
+
message = [NSString stringWithFormat:@"*** -[%@ %s]: unexpected NSFNanoObject behavior. Reason: the object's dictionary is nil.", [self class], _cmd];
|
220
|
+
|
221
|
+
[[NSException exceptionWithName:NSFNanoObjectBehaviorException reason:message userInfo:nil]raise];
|
222
|
+
}
|
223
|
+
|
224
|
+
return YES;
|
225
|
+
}
|
226
|
+
|
227
|
+
- (BOOL)addObjectsFromArray:(NSArray *)someObjects error:(out NSError **)outError
|
228
|
+
{
|
229
|
+
if (nil == someObjects) {
|
230
|
+
if (nil != outError) {
|
231
|
+
*outError = [NSError errorWithDomain:NSFDomainKey
|
232
|
+
code:NSFNanoStoreErrorKey
|
233
|
+
userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"*** -[%@ %s]: the object cannot be added because the list provided is nil.", [self class], _cmd]
|
234
|
+
forKey:NSLocalizedFailureReasonErrorKey]];
|
235
|
+
}
|
236
|
+
return NO;
|
237
|
+
}
|
238
|
+
|
239
|
+
BOOL success = YES;
|
240
|
+
|
241
|
+
for (id object in someObjects) {
|
242
|
+
if (NO == [self addObject:object error:outError]) {
|
243
|
+
success = NO;
|
244
|
+
}
|
245
|
+
}
|
246
|
+
|
247
|
+
return success;
|
248
|
+
}
|
249
|
+
|
250
|
+
- (void)removeObject:(id <NSFNanoObjectProtocol>)object
|
251
|
+
{
|
252
|
+
if (NO == [(id)object conformsToProtocol:@protocol(NSFNanoObjectProtocol)]) {
|
253
|
+
[[NSException exceptionWithName:NSFNonConformingNanoObjectProtocolException
|
254
|
+
reason:[NSString stringWithFormat:@"*** -[%@ %s]: the object does not conform to NSFNanoObjectProtocol.", [self class], _cmd]
|
255
|
+
userInfo:nil]raise];
|
256
|
+
}
|
257
|
+
|
258
|
+
[self removeObjectWithKey:[(id)object nanoObjectKey]];
|
259
|
+
}
|
260
|
+
|
261
|
+
- (void)removeAllObjects
|
262
|
+
{
|
263
|
+
NSMutableDictionary *objects = [[NSMutableDictionary alloc]initWithCapacity:(savedObjects.count + removedObjects.count)];
|
264
|
+
|
265
|
+
// Save the object and its key
|
266
|
+
for (id object in savedObjects) {
|
267
|
+
[objects setObject:object forKey:[object performSelector:@selector(key)]];
|
268
|
+
}
|
269
|
+
|
270
|
+
// Save the previously removed objects (if any)
|
271
|
+
[objects addEntriesFromDictionary:removedObjects];
|
272
|
+
|
273
|
+
[savedObjects removeAllObjects];
|
274
|
+
[unsavedObjects removeAllObjects];
|
275
|
+
[removedObjects setDictionary:objects];
|
276
|
+
hasUnsavedChanges = YES;
|
277
|
+
|
278
|
+
}
|
279
|
+
|
280
|
+
- (void)removeObjectsInArray:(NSArray *)someObjects
|
281
|
+
{
|
282
|
+
for (id object in someObjects) {
|
283
|
+
[self removeObject:object];
|
284
|
+
}
|
285
|
+
}
|
286
|
+
|
287
|
+
- (void)removeObjectWithKey:(NSString *)objectKey
|
288
|
+
{
|
289
|
+
if (nil == objectKey) {
|
290
|
+
[[NSException exceptionWithName:NSFNanoObjectBehaviorException
|
291
|
+
reason:[NSString stringWithFormat:@"*** -[%@ %s]: unexpected NSFNanoObject behavior. Reason: the object's key is nil.", [self class], _cmd]
|
292
|
+
userInfo:nil]raise];
|
293
|
+
}
|
294
|
+
|
295
|
+
// Is the object an existing one?
|
296
|
+
id object = [savedObjects objectForKey:objectKey];
|
297
|
+
if (nil != object) {
|
298
|
+
[savedObjects removeObjectForKey:objectKey];
|
299
|
+
} else {
|
300
|
+
// Is the object still unsaved?
|
301
|
+
object = [unsavedObjects objectForKey:objectKey];
|
302
|
+
if (nil != object) {
|
303
|
+
[unsavedObjects removeObjectForKey:objectKey];
|
304
|
+
}
|
305
|
+
}
|
306
|
+
|
307
|
+
if (nil == object) {
|
308
|
+
// The object doesn't exist, so there is no need to mark the bag as dirty
|
309
|
+
} else {
|
310
|
+
[removedObjects setObject:object forKey:objectKey];
|
311
|
+
hasUnsavedChanges = YES;
|
312
|
+
}
|
313
|
+
}
|
314
|
+
|
315
|
+
- (void)removeObjectsWithKeysInArray:(NSArray *)someKeys
|
316
|
+
{
|
317
|
+
for (NSString *objectKey in someKeys) {
|
318
|
+
[self removeObjectWithKey:objectKey];
|
319
|
+
}
|
320
|
+
}
|
321
|
+
|
322
|
+
- (BOOL)saveAndReturnError:(out NSError **)outError
|
323
|
+
{
|
324
|
+
if (NO == self.hasUnsavedChanges) {
|
325
|
+
return YES;
|
326
|
+
}
|
327
|
+
|
328
|
+
if (nil == store) {
|
329
|
+
if (nil != outError) {
|
330
|
+
*outError = [NSError errorWithDomain:NSFDomainKey
|
331
|
+
code:NSFNanoStoreErrorKey
|
332
|
+
userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"*** -[%@ %s]: unable to save the bag. Reason: the store has not been set.", [self class], _cmd]
|
333
|
+
forKey:NSLocalizedFailureReasonErrorKey]];
|
334
|
+
}
|
335
|
+
return NO;
|
336
|
+
}
|
337
|
+
|
338
|
+
return [self _saveInStore:store error:outError];
|
339
|
+
}
|
340
|
+
|
341
|
+
#pragma mark -
|
342
|
+
|
343
|
+
- (void)deflateBag
|
344
|
+
{
|
345
|
+
NSArray *savedObjectsCopy = [[NSArray alloc]initWithArray:[savedObjects allKeys]];
|
346
|
+
|
347
|
+
for (id saveObjectKey in savedObjectsCopy) {
|
348
|
+
[savedObjects setObject:[NSNull null] forKey:saveObjectKey];
|
349
|
+
}
|
350
|
+
|
351
|
+
}
|
352
|
+
|
353
|
+
- (void)inflateBag
|
354
|
+
{
|
355
|
+
NSArray *objectKeys = [savedObjects allKeys];
|
356
|
+
[self _inflateObjectsWithKeys:objectKeys];
|
357
|
+
}
|
358
|
+
|
359
|
+
- (BOOL)reloadBagWithError:(out NSError **)outError
|
360
|
+
{
|
361
|
+
// If the bag is not associated to a document store, there is no need to continue
|
362
|
+
if (nil == store) {
|
363
|
+
return YES;
|
364
|
+
}
|
365
|
+
|
366
|
+
// Refresh the bag to match the contents stored on the database
|
367
|
+
[self _inflateObjectsWithKeys:[NSArray arrayWithObject:key]];
|
368
|
+
NSFNanoBag *savedBag = [savedObjects objectForKey:key];
|
369
|
+
if (nil != savedBag) {
|
370
|
+
[savedObjects removeAllObjects];
|
371
|
+
[savedObjects addEntriesFromDictionary:savedBag.savedObjects];
|
372
|
+
for (NSString *objectKey in unsavedObjects) {
|
373
|
+
[savedObjects removeObjectForKey:objectKey];
|
374
|
+
}
|
375
|
+
} else {
|
376
|
+
if (nil != outError) {
|
377
|
+
*outError = [NSError errorWithDomain:NSFDomainKey
|
378
|
+
code:NSFNanoStoreErrorKey
|
379
|
+
userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"*** -[%@ %s]: the bag could not be refreshed.", [self class], _cmd]
|
380
|
+
forKey:NSLocalizedFailureReasonErrorKey]];
|
381
|
+
}
|
382
|
+
return NO;
|
383
|
+
}
|
384
|
+
|
385
|
+
return YES;
|
386
|
+
}
|
387
|
+
|
388
|
+
- (BOOL)undoChangesWithError:(out NSError **)outError
|
389
|
+
{
|
390
|
+
[savedObjects removeAllObjects];
|
391
|
+
[unsavedObjects removeAllObjects];
|
392
|
+
[removedObjects removeAllObjects];
|
393
|
+
|
394
|
+
hasUnsavedChanges = NO;
|
395
|
+
|
396
|
+
return [self reloadBagWithError:outError];
|
397
|
+
}
|
398
|
+
|
399
|
+
#pragma mark -
|
400
|
+
#pragma mark Private Methods
|
401
|
+
#pragma mark -
|
402
|
+
|
403
|
+
/** \cond */
|
404
|
+
|
405
|
+
- (id)initNanoObjectFromDictionaryRepresentation:(NSDictionary *)dictionary forKey:(NSString *)aKey store:(NSFNanoStore *)aStore
|
406
|
+
{
|
407
|
+
if ((self = [self init])) {
|
408
|
+
name = [[dictionary objectForKey:NSF_Private_NSFNanoBag_Name]copy];
|
409
|
+
store = aStore;
|
410
|
+
key = aKey;
|
411
|
+
savedObjects = [NSMutableDictionary new];
|
412
|
+
unsavedObjects = [NSMutableDictionary new];
|
413
|
+
removedObjects = [NSMutableDictionary new];
|
414
|
+
|
415
|
+
NSArray *objectKeys = [dictionary objectForKey:NSF_Private_NSFNanoBag_NSFObjectKeys];
|
416
|
+
|
417
|
+
[self _inflateObjectsWithKeys:objectKeys];
|
418
|
+
|
419
|
+
hasUnsavedChanges = NO;
|
420
|
+
}
|
421
|
+
|
422
|
+
return self;
|
423
|
+
}
|
424
|
+
|
425
|
+
- (NSDictionary *)nanoObjectDictionaryRepresentation
|
426
|
+
{
|
427
|
+
return [self dictionaryRepresentation];
|
428
|
+
}
|
429
|
+
|
430
|
+
- (NSString *)nanoObjectKey
|
431
|
+
{
|
432
|
+
return key;
|
433
|
+
}
|
434
|
+
|
435
|
+
- (void)_setStore:(NSFNanoStore *)aStore
|
436
|
+
{
|
437
|
+
store = aStore;
|
438
|
+
}
|
439
|
+
|
440
|
+
- (BOOL)_saveInStore:(NSFNanoStore *)someStore error:(out NSError **)outError
|
441
|
+
{
|
442
|
+
// Save the unsaved objects first...
|
443
|
+
NSArray *contentsToBeSaved = [unsavedObjects allValues];
|
444
|
+
if ([contentsToBeSaved count] > 0) {
|
445
|
+
[someStore _addObjectsFromArray:contentsToBeSaved forceSave:YES error:outError];
|
446
|
+
}
|
447
|
+
|
448
|
+
// Move the existing objects to the unsaved list, in order to save the bag
|
449
|
+
[unsavedObjects addEntriesFromDictionary:savedObjects];
|
450
|
+
[savedObjects removeAllObjects];
|
451
|
+
[removedObjects removeAllObjects];
|
452
|
+
|
453
|
+
// Save the unsaved bag...
|
454
|
+
BOOL success = [someStore _addObjectsFromArray:[NSArray arrayWithObject:self] forceSave:YES error:outError];
|
455
|
+
|
456
|
+
if (YES == success) {
|
457
|
+
[unsavedObjects removeAllObjects];
|
458
|
+
success = [self reloadBagWithError:outError];
|
459
|
+
if (YES == success) {
|
460
|
+
hasUnsavedChanges = NO;
|
461
|
+
}
|
462
|
+
return success;
|
463
|
+
}
|
464
|
+
|
465
|
+
return success;
|
466
|
+
}
|
467
|
+
|
468
|
+
- (void)_inflateObjectsWithKeys:(NSArray *)someKeys
|
469
|
+
{
|
470
|
+
if ([someKeys count] != 0) {
|
471
|
+
NSFNanoSearch *search = [NSFNanoSearch searchWithStore:store];
|
472
|
+
NSString *quotedString = [NSFNanoSearch _quoteStrings:someKeys joiningWithDelimiter:@","];
|
473
|
+
NSString *theSQLStatement = [NSString stringWithFormat:@"SELECT NSFKey, NSFPlist, NSFObjectClass FROM NSFKeys WHERE NSFKey IN (%@)", quotedString];
|
474
|
+
|
475
|
+
NSDictionary *results = [search executeSQL:theSQLStatement returnType:NSFReturnObjects error:nil];
|
476
|
+
|
477
|
+
if (nil != results) {
|
478
|
+
[savedObjects addEntriesFromDictionary:results];
|
479
|
+
}
|
480
|
+
}
|
481
|
+
}
|
482
|
+
|
483
|
+
/** \endcond */
|
484
|
+
|
485
|
+
@end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
/*
|
2
|
+
NSFNanoExpression.h
|
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 <Foundation/Foundation.h>
|
28
|
+
|
29
|
+
#import "NSFNanoGlobals.h"
|
30
|
+
|
31
|
+
@class NSFNanoPredicate;
|
32
|
+
|
33
|
+
/*! @file NSFNanoExpression.h
|
34
|
+
@brief A unit that describes a series of predicates and its operators.
|
35
|
+
*/
|
36
|
+
|
37
|
+
/** @class NSFNanoExpression
|
38
|
+
* A unit that describes a series of predicates and its operators.
|
39
|
+
* @details <b>Example:</b>
|
40
|
+
@code
|
41
|
+
// Instantiate a NanoStore and open it
|
42
|
+
NSFNanoStore *nanoStore = [NSFNanoStore createAndOpenStoreWithType:NSFMemoryStoreType path:nil error:nil];
|
43
|
+
|
44
|
+
// Prepare the expression
|
45
|
+
NSFNanoPredicate *attribute = [NSFNanoPredicate predicateWithColumn:NSFAttributeColumn matching:NSFEqualTo value:@"FirstName"];
|
46
|
+
NSFNanoPredicate *value = [NSFNanoPredicate predicateWithColumn:NSFValueColumn matching:NSFEqualTo value:@"Joe"];
|
47
|
+
NSFNanoExpression *expression = [NSFNanoExpression expressionWithPredicate:attribute];
|
48
|
+
[expression addPredicate:value withOperator:NSFAnd];
|
49
|
+
|
50
|
+
// Setup the search with the document store and a given expression
|
51
|
+
NSFNanoSearch *search = [NSFNanoSearch searchWithStore:nanoStore];
|
52
|
+
[search setExpressions:[NSArray arrayWithObject:expression]];
|
53
|
+
|
54
|
+
// Obtain the matching objects
|
55
|
+
NSDictionary *searchResults = [search searchObjectsWithReturnType:NSFReturnObjects error:nil];
|
56
|
+
|
57
|
+
// Close the document store
|
58
|
+
[nanoStore closeWithError:nil];
|
59
|
+
@endcode
|
60
|
+
*/
|
61
|
+
|
62
|
+
@interface NSFNanoExpression : NSObject
|
63
|
+
|
64
|
+
/** * Array of NSFNanoPredicate */
|
65
|
+
@property (nonatomic, readonly) NSArray *predicates;
|
66
|
+
/** * Array of NSNumber wrapping \link NSFGlobals::NSFOperator NSFOperator \endlink */
|
67
|
+
@property (nonatomic, readonly) NSArray *operators;
|
68
|
+
|
69
|
+
/** @name Creating and Initializing Expressions
|
70
|
+
*/
|
71
|
+
|
72
|
+
//@{
|
73
|
+
|
74
|
+
/** * Creates and returns an expression with a given predicate.
|
75
|
+
* @param thePredicate the predicate used to initialize the expression. Must not be nil.
|
76
|
+
* @return An expression upon success, nil otherwise.
|
77
|
+
* @warning The parameter thePredicate must not be nil.
|
78
|
+
* @throws NSFUnexpectedParameterException is thrown if the predicate is nil.
|
79
|
+
* @see \link initWithPredicate: - (id)initWithPredicate:(NSFNanoPredicate *)aPredicate \endlink
|
80
|
+
*/
|
81
|
+
|
82
|
+
+ (NSFNanoExpression*)expressionWithPredicate:(NSFNanoPredicate *)thePredicate;
|
83
|
+
|
84
|
+
/** * Initializes a newly allocated expression with a given expression.
|
85
|
+
* @param thePredicate the predicate used to initialize the expression. Must not be nil.
|
86
|
+
* @return An expression upon success, nil otherwise.
|
87
|
+
* @warning The parameter thePredicate must not be nil.
|
88
|
+
* @throws NSFUnexpectedParameterException is thrown if the predicate is nil.
|
89
|
+
* @see \link expressionWithPredicate: + (NSFNanoExpression*)expressionWithPredicate:(NSFNanoPredicate *)thePredicate \endlink
|
90
|
+
*/
|
91
|
+
|
92
|
+
- (id)initWithPredicate:(NSFNanoPredicate *)thePredicate;
|
93
|
+
|
94
|
+
//@}
|
95
|
+
|
96
|
+
/** @name Adding a Predicate
|
97
|
+
*/
|
98
|
+
|
99
|
+
//@{
|
100
|
+
|
101
|
+
/** * Adds a predicate to the expression.
|
102
|
+
* @param thePredicate is added to the expression.
|
103
|
+
* @param theOperator specifies the operation (AND/OR) to be applied.
|
104
|
+
* @warning The parameter thePredicate must not be nil.
|
105
|
+
* @throws NSFUnexpectedParameterException is thrown if the predicate is nil.
|
106
|
+
*/
|
107
|
+
|
108
|
+
- (void)addPredicate:(NSFNanoPredicate *)thePredicate withOperator:(NSFOperator)theOperator;
|
109
|
+
|
110
|
+
//@}
|
111
|
+
|
112
|
+
/** @name Miscellaneous
|
113
|
+
*/
|
114
|
+
|
115
|
+
//@{
|
116
|
+
|
117
|
+
/** * Returns a string representation of the expression.
|
118
|
+
* @note Check properties predicates and operators to find out the current state of the expression.
|
119
|
+
*/
|
120
|
+
|
121
|
+
- (NSString *)description;
|
122
|
+
|
123
|
+
//@}
|
124
|
+
|
125
|
+
@end
|