diff --git a/CouchbaseLite.xcodeproj/project.pbxproj b/CouchbaseLite.xcodeproj/project.pbxproj index a1774e633..d85c63d38 100644 --- a/CouchbaseLite.xcodeproj/project.pbxproj +++ b/CouchbaseLite.xcodeproj/project.pbxproj @@ -1768,6 +1768,10 @@ AE5803F92B9B969D001A1BE3 /* CouchbaseLiteVectorSearch.xcframework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 40086B152B7EDDD400DA6770 /* CouchbaseLiteVectorSearch.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; AE5803FA2B9B96BF001A1BE3 /* CouchbaseLiteVectorSearch.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 40086B152B7EDDD400DA6770 /* CouchbaseLiteVectorSearch.xcframework */; }; AE5803FB2B9B96BF001A1BE3 /* CouchbaseLiteVectorSearch.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 40086B152B7EDDD400DA6770 /* CouchbaseLiteVectorSearch.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + AE5F25582CAC310700AAB7F4 /* UnnestArrayIndexTest.m in Sources */ = {isa = PBXBuildFile; fileRef = AE5F25492CAC30DC00AAB7F4 /* UnnestArrayIndexTest.m */; }; + AE5F25592CAC310800AAB7F4 /* UnnestArrayIndexTest.m in Sources */ = {isa = PBXBuildFile; fileRef = AE5F25492CAC30DC00AAB7F4 /* UnnestArrayIndexTest.m */; }; + AE5F255A2CAC310900AAB7F4 /* UnnestArrayIndexTest.m in Sources */ = {isa = PBXBuildFile; fileRef = AE5F25492CAC30DC00AAB7F4 /* UnnestArrayIndexTest.m */; }; + AE5F255B2CAC311100AAB7F4 /* UnnestArrayIndexTest.m in Sources */ = {isa = PBXBuildFile; fileRef = AE5F25492CAC30DC00AAB7F4 /* UnnestArrayIndexTest.m */; }; AE83D0842C0637ED0055D2CF /* CBLIndexUpdater.h in Headers */ = {isa = PBXBuildFile; fileRef = AE83D0822C0637ED0055D2CF /* CBLIndexUpdater.h */; settings = {ATTRIBUTES = (Public, ); }; }; AE83D0852C0637ED0055D2CF /* CBLIndexUpdater.mm in Sources */ = {isa = PBXBuildFile; fileRef = AE83D0832C0637ED0055D2CF /* CBLIndexUpdater.mm */; }; AE83D0862C0637ED0055D2CF /* CBLIndexUpdater.h in Headers */ = {isa = PBXBuildFile; fileRef = AE83D0822C0637ED0055D2CF /* CBLIndexUpdater.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -1780,6 +1784,10 @@ AEC806BC2C89EA68001C9723 /* CBLArrayIndexConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = AEC806B62C89EA68001C9723 /* CBLArrayIndexConfiguration.m */; }; AEC806BD2C89EA68001C9723 /* CBLArrayIndexConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = AEC806B62C89EA68001C9723 /* CBLArrayIndexConfiguration.m */; }; AEC806BE2C89EA68001C9723 /* CBLArrayIndexConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = AEC806B52C89EA68001C9723 /* CBLArrayIndexConfiguration.h */; settings = {ATTRIBUTES = (Private, ); }; }; + AECA897D2CADADAA00C7B6BE /* UnnestArrayTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = AECA897C2CADADAA00C7B6BE /* UnnestArrayTest.swift */; }; + AECA897E2CADADAA00C7B6BE /* UnnestArrayTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = AECA897C2CADADAA00C7B6BE /* UnnestArrayTest.swift */; }; + AECA897F2CADADAA00C7B6BE /* UnnestArrayTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = AECA897C2CADADAA00C7B6BE /* UnnestArrayTest.swift */; }; + AECA89802CADADAA00C7B6BE /* UnnestArrayTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = AECA897C2CADADAA00C7B6BE /* UnnestArrayTest.swift */; }; AECD5A162C0E21D900B1247E /* CBLIndexUpdater+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = AECD5A0F2C0E21D900B1247E /* CBLIndexUpdater+Internal.h */; }; AECD5A172C0E21D900B1247E /* CBLIndexUpdater+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = AECD5A0F2C0E21D900B1247E /* CBLIndexUpdater+Internal.h */; }; /* End PBXBuildFile section */ @@ -2798,10 +2806,12 @@ AE006DE62B7BB98B00884E2B /* VectorSearchTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VectorSearchTest.m; sourceTree = ""; }; AE5803A32B99C67D001A1BE3 /* VectorSearchTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VectorSearchTest.swift; sourceTree = ""; }; AE5803D72B9B5B2A001A1BE3 /* WordEmbeddingModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WordEmbeddingModel.swift; sourceTree = ""; }; + AE5F25492CAC30DC00AAB7F4 /* UnnestArrayIndexTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UnnestArrayIndexTest.m; sourceTree = ""; }; AE83D0822C0637ED0055D2CF /* CBLIndexUpdater.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CBLIndexUpdater.h; sourceTree = ""; }; AE83D0832C0637ED0055D2CF /* CBLIndexUpdater.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = CBLIndexUpdater.mm; sourceTree = ""; }; AEC806B52C89EA68001C9723 /* CBLArrayIndexConfiguration.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CBLArrayIndexConfiguration.h; sourceTree = ""; }; AEC806B62C89EA68001C9723 /* CBLArrayIndexConfiguration.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CBLArrayIndexConfiguration.m; sourceTree = ""; }; + AECA897C2CADADAA00C7B6BE /* UnnestArrayTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnnestArrayTest.swift; sourceTree = ""; }; AECD59F92C0E137200B1247E /* CBLQueryIndex+Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "CBLQueryIndex+Internal.h"; sourceTree = ""; }; AECD5A0F2C0E21D900B1247E /* CBLIndexUpdater+Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "CBLIndexUpdater+Internal.h"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -3087,6 +3097,7 @@ 1A13DD3328B8809300BC1084 /* URLEndpointListenerTest+Collection.swift */, AE5803A32B99C67D001A1BE3 /* VectorSearchTest.swift */, 406F8DFC2C27F097000223FC /* VectorSearchTest+Lazy.swift */, + AECA897C2CADADAA00C7B6BE /* UnnestArrayTest.swift */, 1AA91DC522B0356000BF0BDE /* CustomLogger.swift */, 93249D81246B99FD000A8A6E /* iOS */, 939B79241E679017009A70EF /* Info.plist */, @@ -4154,6 +4165,7 @@ 40AA72A12C28B1F2007FB1E0 /* VectorSearchTest.h */, AE006DE62B7BB98B00884E2B /* VectorSearchTest.m */, 40AA72972C28B1A3007FB1E0 /* VectorSearchTest+Lazy.m */, + AE5F25492CAC30DC00AAB7F4 /* UnnestArrayIndexTest.m */, 93DECF3E200DBE5800F44953 /* Support */, 936483AA1E4431C6008D08B3 /* iOS */, 275FF5FA1E3FBD3B005F90DD /* Performance */, @@ -6212,6 +6224,7 @@ 1A8F85092893F318008C4333 /* QueryTest+Collection.swift in Sources */, 93E17F151ED4ED4000671CA1 /* NotificationTest.swift in Sources */, 27BE3B4D1E4E51C80012B74A /* DatabaseTest.swift in Sources */, + AECA897D2CADADAA00C7B6BE /* UnnestArrayTest.swift in Sources */, 1A6084F828758AE00037C66F /* CollectionTest.swift in Sources */, 934C2CDE1F4FC0D20010316F /* CBLTestHelper.m in Sources */, 9388CC5521C25CC7005CA66D /* LogTest.swift in Sources */, @@ -6255,6 +6268,7 @@ 93BB1CB4246BB2ED004FFA00 /* ReplicatorTest.swift in Sources */, 1A6084FA28758AE20037C66F /* CollectionTest.swift in Sources */, 93BB1CB1246BB2E4004FFA00 /* PredictiveQueryTest.swift in Sources */, + AECA89802CADADAA00C7B6BE /* UnnestArrayTest.swift in Sources */, 93BB1CBA246BB2F4004FFA00 /* CustomLogger.swift in Sources */, 1A13DD4428B882BA00BC1084 /* URLEndpointListenerTest+Collection.swift in Sources */, 93BB1CA1246BB2CA004FFA00 /* DateTimeQueryFunctionTest.swift in Sources */, @@ -6698,6 +6712,7 @@ 9343F13B207D61EC00F19A89 /* CBLTestCase.m in Sources */, 1A4160DB22836E8C0061A567 /* ReplicatorTest+Main.m in Sources */, 930C7F9220FE4F7500C74A12 /* CBLMockConnectionErrorLogic.m in Sources */, + AE5F255A2CAC310900AAB7F4 /* UnnestArrayIndexTest.m in Sources */, 1AA6744B227924120018CC6D /* QueryTest+Join.m in Sources */, 934EF8312460D0770053A47C /* TLSIdentityTest.m in Sources */, 9343F13C207D61EC00F19A89 /* DatabaseTest.m in Sources */, @@ -6772,6 +6787,7 @@ 930C7F9520FE4F7500C74A12 /* CBLMockConnection.m in Sources */, 9343F179207D633300F19A89 /* QueryTest.m in Sources */, 1A621D7B2887DCFE0017F905 /* QueryTest+Collection.m in Sources */, + AE5F255B2CAC311100AAB7F4 /* UnnestArrayIndexTest.m in Sources */, 933F841E220BA4100093EC88 /* PredictiveQueryTest+CoreML.m in Sources */, 1AA3D78822AB07D80098E16B /* CustomLogger.m in Sources */, 1A2F2C3627FD5B2200084B3C /* TrustCheckTest.m in Sources */, @@ -6800,6 +6816,7 @@ 93EB25A421CDCC160006FB88 /* PredictiveQueryTest.swift in Sources */, 1A6084FB28758AE90037C66F /* CollectionTest.swift in Sources */, 9343F18E207D636300F19A89 /* DocumentTest.swift in Sources */, + AECA897F2CADADAA00C7B6BE /* UnnestArrayTest.swift in Sources */, 1A13DD4328B882BA00BC1084 /* URLEndpointListenerTest+Collection.swift in Sources */, 9343F18F207D636300F19A89 /* ArrayTest.swift in Sources */, 1A690CD7242150DF0084D017 /* ReplicatorTest+PendingDocIds.swift in Sources */, @@ -6877,6 +6894,7 @@ 1ABA63AF28813A8A005835E7 /* ReplicatorTest+Collection.m in Sources */, 1A621D792887DCFC0017F905 /* QueryTest+Collection.m in Sources */, 9388CBAC21BD917D005CA66D /* DocumentExpirationTest.m in Sources */, + AE5F25592CAC310800AAB7F4 /* UnnestArrayIndexTest.m in Sources */, 1AA67439227924110018CC6D /* QueryTest+Meta.m in Sources */, 9385F3041FC645D300032037 /* ConcurrentTest.m in Sources */, 93CD018E1E95546200AFB3FA /* QueryTest.m in Sources */, @@ -7018,6 +7036,7 @@ 9378C5911E25B3F0001BB196 /* DatabaseTest.m in Sources */, 1A4FE76A225ED344009D5F43 /* MiscCppTest.mm in Sources */, 1A908401288027EE006B1885 /* ReplicatorTest+Collection.m in Sources */, + AE5F25582CAC310700AAB7F4 /* UnnestArrayIndexTest.m in Sources */, 1AC83BC821C026D100792098 /* DateTimeQueryFunctionTest.m in Sources */, 938B3702200D7D1D004485D8 /* MigrationTest.m in Sources */, 1AA3D78422AB07C50098E16B /* CustomLogger.m in Sources */, @@ -7051,6 +7070,7 @@ 1A8F85082893F317008C4333 /* QueryTest+Collection.swift in Sources */, 93BB1CAE246BB2DC004FFA00 /* QueryTest.swift in Sources */, 93BB1CAD246BB2DC004FFA00 /* NotificationTest.swift in Sources */, + AECA897E2CADADAA00C7B6BE /* UnnestArrayTest.swift in Sources */, 1A6084F728758ADF0037C66F /* CollectionTest.swift in Sources */, 93BB1CA6246BB2D3004FFA00 /* LogTest.swift in Sources */, 93BB1CB7246BB2F3004FFA00 /* CustomLogger.swift in Sources */, diff --git a/Objective-C/CBLArrayIndexConfiguration.m b/Objective-C/CBLArrayIndexConfiguration.m index d735f607f..64538a205 100644 --- a/Objective-C/CBLArrayIndexConfiguration.m +++ b/Objective-C/CBLArrayIndexConfiguration.m @@ -30,11 +30,9 @@ - (instancetype) initWithPath: (NSString*) path if(!expressions) { self = [super initWithIndexType: kC4ArrayIndex expressions: @[@""]]; - } - - if ([expressions count] == 0) { + } else if ([expressions count] == 0 || [expressions[0] length] == 0) { [NSException raise: NSInvalidArgumentException format: - @"Expressions cannot be empty "]; + @"Empty expressions is not allowed, use nil instead"]; } self = [super initWithIndexType: kC4ArrayIndex @@ -55,7 +53,7 @@ - (instancetype) initWithPath: (NSString*)path { - (C4IndexOptions) indexOptions { C4IndexOptions c4options = { }; - //c4options.unnestPath = _path; + c4options.unnestPath = [_path UTF8String]; return c4options; } diff --git a/Objective-C/CBLCollection.mm b/Objective-C/CBLCollection.mm index 2e19fa14f..8313fd7e7 100644 --- a/Objective-C/CBLCollection.mm +++ b/Objective-C/CBLCollection.mm @@ -473,151 +473,6 @@ - (BOOL) setDocumentExpirationWithID: (NSString*)documentID } } -#pragma mark - Internal - -- (BOOL) checkIsValid: (NSError**)error { - BOOL valid = c4coll_isValid(_c4col); - if (!valid) { - if (error) - *error = CBLCollectionErrorNotOpen; - } - - return valid; -} - -- (BOOL) isValid { - return [self checkIsValid: nil]; -} - -- (BOOL) database: (CBLDatabase*)db isValid: (NSError**)error { - BOOL valid = db != nil; - if (!valid) { - if (error) - *error = CBLDatabaseErrorNotOpen; - } - - return valid; -} - -- (C4CollectionSpec) c4spec { - // Convert to cString directly instead of using CBLStringBytes to avoid - // stack-use-after-scope problem when a small string is kept in the - // _local stack based buffer of the CBLStringBytes - C4Slice name = c4str([_name cStringUsingEncoding: NSUTF8StringEncoding]); - C4Slice scopeName = c4str([_scope.name cStringUsingEncoding: NSUTF8StringEncoding]); - return { .name = name, .scope = scopeName }; -} - -- (BOOL) isEqual: (id)object { - if (self == object) - return YES; - - CBLCollection* other = $castIf(CBLCollection, object); - if (!other) - return NO; - - if (!(other && [self.name isEqual: other.name] && - [self.scope.name isEqual: other.scope.name] && - [self.database.path isEqual: other.database.path])) { - return NO; - } - - if (!self.isValid || !other.isValid) - return NO; - - return YES; -} - -- (id) addCollectionChangeListener: (void (^)(CBLCollectionChange*))listener - queue: (dispatch_queue_t)queue { - if (!_colChangeNotifier) { - _colChangeNotifier = [CBLChangeNotifier new]; - C4Error c4err = {}; - _colObs = c4dbobs_createOnCollection(_c4col, colObserverCallback, (__bridge void *)self, &c4err); - if (!_colObs) { - CBLWarn(Database, @"%@ Failed to create collection obs c4col=%p err=%d/%d", - self, _c4col, c4err.domain, c4err.code); - } - } - - return [_colChangeNotifier addChangeListenerWithQueue: queue listener: listener delegate: self]; -} - -static void colObserverCallback(C4CollectionObserver* obs, void* context) { - CBLCollection *c = (__bridge CBLCollection *)context; - dispatch_async(c.dispatchQueue, ^{ - [c postCollectionChanged]; - }); -} - -- (void) postCollectionChanged { - CBL_LOCK(_mutex) { - if (!_colObs || !_c4col) - return; - - const uint32_t kMaxChanges = 100u; - C4DatabaseChange changes[kMaxChanges]; - bool external = false; - C4CollectionObservation obs = {}; - NSMutableArray* docIDs = [NSMutableArray new]; - do { - // Read changes in batches of kMaxChanges: - obs = c4dbobs_getChanges(_colObs, changes, kMaxChanges); - if (obs.numChanges == 0 || external != obs.external || docIDs.count > 1000) { - if(docIDs.count > 0) { - CBLCollectionChange* change = [[CBLCollectionChange alloc] initWithCollection: self - documentIDs: docIDs - isExternal: external]; - [_colChangeNotifier postChange: change]; - docIDs = [NSMutableArray new]; - } - } - - external = obs.external; - for(uint32_t i = 0; i < obs.numChanges; i++) { - NSString *docID =slice2string(changes[i].docID); - [docIDs addObject: docID]; - } - c4dbobs_releaseChanges(changes, obs.numChanges); - } while(obs.numChanges > 0); - } -} - -- (void) removeToken: (id)token { - CBL_LOCK(_mutex) { - CBLChangeListenerToken* t = (CBLChangeListenerToken*)token; - if (t.context) - [self removeDocumentChangeListenerWithToken: token]; - else { - if ([_colChangeNotifier removeChangeListenerWithToken: token] == 0) { - c4dbobs_free(_colObs); - _colObs = nil; - _colChangeNotifier = nil; - } - } - } -} - -- (void) removeDocumentChangeListenerWithToken: (CBLChangeListenerToken*)token { - CBL_LOCK(_mutex) { - NSString* documentID = (NSString*)token.context; - CBLDocumentChangeNotifier* notifier = _docChangeNotifiers[documentID]; - if (notifier && [notifier removeChangeListenerWithToken: token] == 0) { - [notifier stop]; - [_docChangeNotifiers removeObjectForKey:documentID]; - } - } -} - -- (void) freeC4Observer { - c4dbobs_free(_colObs); - _colObs = nullptr; - _colChangeNotifier = nil; - - [_docChangeNotifiers.allValues makeObjectsPerformSelector: @selector(stop)]; - _docChangeNotifiers = nil; -} - #pragma mark - Document listener - (id) addDocumentChangeListenerWithDocumentID: documentID @@ -976,4 +831,171 @@ - (nullable CBLQueryIndex*) indexWithName: (nonnull NSString*)name } } +#pragma mark - Internal + +- (BOOL) checkIsValid: (NSError**)error { + BOOL valid = c4coll_isValid(_c4col); + if (!valid) { + if (error) + *error = CBLCollectionErrorNotOpen; + } + + return valid; +} + +- (BOOL) isValid { + return [self checkIsValid: nil]; +} + +- (BOOL) database: (CBLDatabase*)db isValid: (NSError**)error { + BOOL valid = db != nil; + if (!valid) { + if (error) + *error = CBLDatabaseErrorNotOpen; + } + + return valid; +} + +- (C4CollectionSpec) c4spec { + // Convert to cString directly instead of using CBLStringBytes to avoid + // stack-use-after-scope problem when a small string is kept in the + // _local stack based buffer of the CBLStringBytes + C4Slice name = c4str([_name cStringUsingEncoding: NSUTF8StringEncoding]); + C4Slice scopeName = c4str([_scope.name cStringUsingEncoding: NSUTF8StringEncoding]); + return { .name = name, .scope = scopeName }; +} + +- (BOOL) isEqual: (id)object { + if (self == object) + return YES; + + CBLCollection* other = $castIf(CBLCollection, object); + if (!other) + return NO; + + if (!(other && [self.name isEqual: other.name] && + [self.scope.name isEqual: other.scope.name] && + [self.database.path isEqual: other.database.path])) { + return NO; + } + + if (!self.isValid || !other.isValid) + return NO; + + return YES; +} + +- (id) addCollectionChangeListener: (void (^)(CBLCollectionChange*))listener + queue: (dispatch_queue_t)queue { + if (!_colChangeNotifier) { + _colChangeNotifier = [CBLChangeNotifier new]; + C4Error c4err = {}; + _colObs = c4dbobs_createOnCollection(_c4col, colObserverCallback, (__bridge void *)self, &c4err); + if (!_colObs) { + CBLWarn(Database, @"%@ Failed to create collection obs c4col=%p err=%d/%d", + self, _c4col, c4err.domain, c4err.code); + } + } + + return [_colChangeNotifier addChangeListenerWithQueue: queue listener: listener delegate: self]; +} + +static void colObserverCallback(C4CollectionObserver* obs, void* context) { + CBLCollection *c = (__bridge CBLCollection *)context; + dispatch_async(c.dispatchQueue, ^{ + [c postCollectionChanged]; + }); +} + +- (void) postCollectionChanged { + CBL_LOCK(_mutex) { + if (!_colObs || !_c4col) + return; + + const uint32_t kMaxChanges = 100u; + C4DatabaseChange changes[kMaxChanges]; + bool external = false; + C4CollectionObservation obs = {}; + NSMutableArray* docIDs = [NSMutableArray new]; + do { + // Read changes in batches of kMaxChanges: + obs = c4dbobs_getChanges(_colObs, changes, kMaxChanges); + if (obs.numChanges == 0 || external != obs.external || docIDs.count > 1000) { + if(docIDs.count > 0) { + CBLCollectionChange* change = [[CBLCollectionChange alloc] initWithCollection: self + documentIDs: docIDs + isExternal: external]; + [_colChangeNotifier postChange: change]; + docIDs = [NSMutableArray new]; + } + } + + external = obs.external; + for(uint32_t i = 0; i < obs.numChanges; i++) { + NSString *docID =slice2string(changes[i].docID); + [docIDs addObject: docID]; + } + c4dbobs_releaseChanges(changes, obs.numChanges); + } while(obs.numChanges > 0); + } +} + +- (void) removeToken: (id)token { + CBL_LOCK(_mutex) { + CBLChangeListenerToken* t = (CBLChangeListenerToken*)token; + if (t.context) + [self removeDocumentChangeListenerWithToken: token]; + else { + if ([_colChangeNotifier removeChangeListenerWithToken: token] == 0) { + c4dbobs_free(_colObs); + _colObs = nil; + _colChangeNotifier = nil; + } + } + } +} + +- (void) removeDocumentChangeListenerWithToken: (CBLChangeListenerToken*)token { + CBL_LOCK(_mutex) { + NSString* documentID = (NSString*)token.context; + CBLDocumentChangeNotifier* notifier = _docChangeNotifiers[documentID]; + if (notifier && [notifier removeChangeListenerWithToken: token] == 0) { + [notifier stop]; + [_docChangeNotifiers removeObjectForKey:documentID]; + } + } +} + +- (void) freeC4Observer { + c4dbobs_free(_colObs); + _colObs = nullptr; + _colChangeNotifier = nil; + + [_docChangeNotifiers.allValues makeObjectsPerformSelector: @selector(stop)]; + _docChangeNotifiers = nil; +} + +- (nullable NSArray*) indexesInfo: (NSError**)error { + CBL_LOCK(_mutex) { + if (![self checkIsValid: error]) + return nil; + + C4Error err = {}; + C4SliceResult res = c4coll_getIndexesInfo(_c4col, &err); + if (err.code != 0){ + convertError(err, error); + return nil; + } + + FLDoc doc = FLDoc_FromResultData(res, kFLTrusted, nullptr, nullslice); + FLSliceResult_Release(res); + + NSArray* indexes = FLValue_GetNSObject(FLDoc_GetRoot(doc), nullptr); + FLDoc_Release(doc); + + return indexes; + } +} + @end diff --git a/Objective-C/Internal/CBLCollection+Internal.h b/Objective-C/Internal/CBLCollection+Internal.h index 2d9d340f7..c2038829e 100644 --- a/Objective-C/Internal/CBLCollection+Internal.h +++ b/Objective-C/Internal/CBLCollection+Internal.h @@ -21,6 +21,7 @@ #import "CBLCollection.h" #import "CBLChangeListenerToken.h" #import "CBLDatabase.h" +#import "c4.h" #define CBLCollectionErrorNotOpen [NSError errorWithDomain: CBLErrorDomain \ code: CBLErrorNotOpen \ @@ -62,6 +63,8 @@ NS_ASSUME_NONNULL_BEGIN - (BOOL) checkIsValid: (NSError**)error; +- (nullable NSArray*) indexesInfo: (NSError**)error; + @end @interface CBLCollectionChange () diff --git a/Objective-C/Internal/CBLCollection+Swift.h b/Objective-C/Internal/CBLCollection+Swift.h index a92e4c1a4..4e9edc917 100644 --- a/Objective-C/Internal/CBLCollection+Swift.h +++ b/Objective-C/Internal/CBLCollection+Swift.h @@ -28,6 +28,8 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, readonly) BOOL isValid; +- (nullable NSArray*) indexesInfo: (NSError**)error; + @end NS_ASSUME_NONNULL_END diff --git a/Objective-C/Internal/CBLQueryIndex+Internal.h b/Objective-C/Internal/CBLQueryIndex+Internal.h index 416df3f76..bd062f706 100644 --- a/Objective-C/Internal/CBLQueryIndex+Internal.h +++ b/Objective-C/Internal/CBLQueryIndex+Internal.h @@ -34,6 +34,7 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype) initWithC4Index: (C4Index*) c4index name: (NSString*) name collection: (CBLCollection*) collection; + @end NS_ASSUME_NONNULL_END diff --git a/Objective-C/Tests/CollectionTest.m b/Objective-C/Tests/CollectionTest.m index 7ec875d14..bf971cc20 100644 --- a/Objective-C/Tests/CollectionTest.m +++ b/Objective-C/Tests/CollectionTest.m @@ -25,14 +25,6 @@ @interface CollectionTest : CBLTestCase @implementation CollectionTest -- (void) setUp { - [super setUp]; -} - -- (void) tearDown { - [super tearDown]; -} - - (void) testGetNonExistingDoc { NSError* error = nil; CBLCollection* col = [self.db defaultCollection: &error]; diff --git a/Objective-C/Tests/Support/profiles_100.json b/Objective-C/Tests/Support/profiles_100.json new file mode 100644 index 000000000..9cfc6319a --- /dev/null +++ b/Objective-C/Tests/Support/profiles_100.json @@ -0,0 +1,100 @@ +{"pid": "p-0001", "name": {"first": "Lue", "last": "Laserna"}, "contacts": [{"address": {"city": "San Pedro", "state": "CA", "street": "19 Deer Loop", "zip": "90732"}, "emails": ["lue.laserna@nosql-matters.org", "laserna@nosql-matters.org"], "phones": [{"numbers": ["310-8268551", "310-7618427"], "preferred": false, "type": "home"}, {"numbers": ["310-9601308"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "San Pedro", "state": "CA", "street": "1820 Maple Ln", "zip": "90732"}, "emails": ["Lue@email.com", "Laserna@email.com"], "phones": [{"numbers": ["310-6653153"], "preferred": false, "type": "home"}, {"numbers": ["310-4833623"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": ["chatting"]} +{"pid": "p-0002", "name": {"first": "Jasper", "last": "Grebel"}, "contacts": [{"address": {"city": "Burns", "state": "KS", "street": "19 Florida Loop", "zip": "66840"}, "emails": ["jasper.grebel@nosql-matters.org"], "phones": [{"numbers": ["316-2417120", "316-2767391"], "preferred": false, "type": "home"}, {"numbers": ["316-8833161"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Burns", "state": "KS", "street": "4795 Willow Loop", "zip": "66840"}, "emails": ["Jasper@email.com", "Grebel@email.com"], "phones": [{"numbers": ["316-9487549"], "preferred": true, "type": "home"}, {"numbers": ["316-4737548"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": ["shopping"]} +{"pid": "p-0003", "name": {"first": "Kandra", "last": "Beichner"}, "contacts": [{"address": {"city": "Tacoma", "state": "WA", "street": "6 John Run", "zip": "98434"}, "emails": ["kandra.beichner@nosql-matters.org", "kandra@nosql-matters.org"], "phones": [{"numbers": ["253-0405964"], "preferred": false, "type": "home"}, {"numbers": ["253-7421842"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Tacoma", "state": "WA", "street": "9509 Cedar Ave", "zip": "98434"}, "emails": ["Kandra@email.com", "Beichner@email.com"], "phones": [{"numbers": ["253-5727806"], "preferred": false, "type": "home"}, {"numbers": ["253-8671217"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": ["swimming"]} +{"pid": "p-0004", "name": {"first": "Jeff", "last": "Schmith"}, "contacts": [{"address": {"city": "Poughkeepsie", "state": "AR", "street": "14 198th St", "zip": "72569"}, "emails": ["jeff.schmith@nosql-matters.org"], "phones": [{"numbers": [], "preferred": false, "type": "home"}, {"numbers": ["870-5974023"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Poughkeepsie", "state": "AR", "street": "9356 Willow Cir", "zip": "72569"}, "emails": ["Jeff@email.com", "Schmith@email.com"], "phones": [{"numbers": ["870-4182309"], "preferred": true, "type": "home"}, {"numbers": ["870-1205865"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": ["chatting", "boxing", "reading"]} +{"pid": "p-0005", "name": {"first": "Tuan", "last": "Climer"}, "contacts": [{"address": {"city": "Bedminster", "state": "NJ", "street": "6 Kansas St", "zip": "07921"}, "emails": ["tuan.climer@nosql-matters.org"], "phones": [{"numbers": ["908-8376478"], "preferred": false, "type": "home"}, {"numbers": ["908-9178111"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Bedminster", "state": "NJ", "street": "4812 Birch Ct", "zip": "07921"}, "emails": ["Tuan@email.com", "Climer@email.com"], "phones": [{"numbers": ["908-8128877"], "preferred": false, "type": "home"}, {"numbers": ["908-7362917"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": ["ironing"]} +{"pid": "p-0006", "name": {"first": "Warner", "last": "Lemaire"}, "contacts": [{"address": {"city": "Spotsylvania", "state": "VA", "street": "14 234th St", "zip": "22553"}, "emails": ["warner.lemaire@nosql-matters.org", "warner@nosql-matters.org"], "phones": [{"numbers": [], "preferred": false, "type": "home"}, {"numbers": ["540-4382519"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Spotsylvania", "state": "VA", "street": "4699 Bear Way", "zip": "22553"}, "emails": ["Warner@email.com", "Lemaire@email.com"], "phones": [{"numbers": ["540-9773061"], "preferred": true, "type": "home"}, {"numbers": ["540-5985360"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": ["driving"]} +{"pid": "p-0007", "name": {"first": "Hugh", "last": "Potash"}, "contacts": [{"address": {"city": "Elmira", "state": "NY", "street": "16 Beechwood Way", "zip": "14902"}, "emails": ["hugh.potash@nosql-matters.org", "potash@nosql-matters.org", "hugh@nosql-matters.org"], "phones": [{"numbers": ["607-5183546"], "preferred": false, "type": "home"}, {"numbers": ["607-9211193"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Elmira", "state": "NY", "street": "6492 Pine St", "zip": "14902"}, "emails": ["Hugh@email.com", "Potash@email.com"], "phones": [{"numbers": ["607-9278334"], "preferred": false, "type": "home"}, {"numbers": ["607-8563742"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": []} +{"pid": "p-0008", "name": {"first": "Jennefer", "last": "Menning"}, "contacts": [{"address": {"city": "Albany", "state": "MN", "street": "1 Euclid Dr", "zip": "56307"}, "emails": ["jennefer.menning@nosql-matters.org", "jennefer@nosql-matters.org"], "phones": [{"numbers": [], "preferred": false, "type": "home"}, {"numbers": ["320-4119897"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Albany", "state": "MN", "street": "734 Deer Ln", "zip": "56307"}, "emails": ["Jennefer@email.com", "Menning@email.com"], "phones": [{"numbers": ["320-9330377"], "preferred": true, "type": "home"}, {"numbers": ["320-9733917"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": []} +{"pid": "p-0009", "name": {"first": "Claude", "last": "Willcott"}, "contacts": [{"address": {"city": "Storm Lake", "state": "IA", "street": "2 Country club Ave", "zip": "50588"}, "emails": ["claude.willcott@nosql-matters.org", "willcott@nosql-matters.org", "claude@nosql-matters.org"], "phones": [{"numbers": ["712-3896363"], "preferred": false, "type": "home"}, {"numbers": ["712-2126890"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Storm Lake", "state": "IA", "street": "7109 Hickory Loop", "zip": "50588"}, "emails": ["Claude@email.com", "Willcott@email.com"], "phones": [{"numbers": ["712-5214269"], "preferred": false, "type": "home"}, {"numbers": ["712-4499777"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": ["chess", "driving"]} +{"pid": "p-0010", "name": {"first": "Maximina", "last": "Kilzer"}, "contacts": [{"address": {"city": "Carmen", "state": "OK", "street": "4 Phillips Ln", "zip": "73726"}, "emails": ["maximina.kilzer@nosql-matters.org", "kilzer@nosql-matters.org"], "phones": [{"numbers": ["580-7678062"], "preferred": false, "type": "home"}, {"numbers": ["580-9283690"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Carmen", "state": "OK", "street": "1956 Bear Ln", "zip": "73726"}, "emails": ["Maximina@email.com", "Kilzer@email.com"], "phones": [{"numbers": ["580-8455552"], "preferred": true, "type": "home"}, {"numbers": ["580-5366847"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": ["shopping", "travelling"]} +{"pid": "p-0011", "name": {"first": "Calvin", "last": "Porro"}, "contacts": [{"address": {"city": "Alberton", "state": "MT", "street": "20 12th Ave", "zip": "59820"}, "emails": ["calvin.porro@nosql-matters.org"], "phones": [{"numbers": ["406-7464035"], "preferred": false, "type": "home"}, {"numbers": ["406-6637752"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Alberton", "state": "MT", "street": "1569 Birch Cir", "zip": "59820"}, "emails": ["Calvin@email.com", "Porro@email.com"], "phones": [{"numbers": ["406-8751787"], "preferred": false, "type": "home"}, {"numbers": ["406-9518454"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": []} +{"pid": "p-0012", "name": {"first": "Diedre", "last": "Clinton"}, "contacts": [{"address": {"city": "Cotopaxi", "state": "CO", "street": "2 Fraser Ave", "zip": "81223"}, "emails": ["diedre.clinton@nosql-matters.org", "clinton@nosql-matters.org", "diedre@nosql-matters.org"], "phones": [{"numbers": ["719-7055896"], "preferred": false, "type": "home"}, {"numbers": ["719-3495060"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Cotopaxi", "state": "CO", "street": "5663 Elm St", "zip": "81223"}, "emails": ["Diedre@email.com", "Clinton@email.com"], "phones": [{"numbers": ["719-2593824"], "preferred": true, "type": "home"}, {"numbers": ["719-3103360"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": ["swimming"]} +{"pid": "p-0013", "name": {"first": "Lavone", "last": "Peery"}, "contacts": [{"address": {"city": "Council", "state": "ID", "street": "7 Wyoming Hwy", "zip": "83612"}, "emails": ["lavone.peery@nosql-matters.org", "lavone@nosql-matters.org"], "phones": [{"numbers": ["208-6845728", "208-9763317"], "preferred": false, "type": "home"}, {"numbers": ["208-7873856"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Council", "state": "ID", "street": "2066 Birch St", "zip": "83612"}, "emails": ["Lavone@email.com", "Peery@email.com"], "phones": [{"numbers": ["208-5765929"], "preferred": false, "type": "home"}, {"numbers": ["208-5891683"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": []} +{"pid": "p-0014", "name": {"first": "Stephen", "last": "Jakovac"}, "contacts": [{"address": {"city": "Alexandria", "state": "MN", "street": "10 4th St", "zip": "56308"}, "emails": ["stephen.jakovac@nosql-matters.org"], "phones": [{"numbers": ["320-2503176", "320-9515697"], "preferred": false, "type": "home"}, {"numbers": ["320-6021769"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Alexandria", "state": "MN", "street": "9428 Oak Loop", "zip": "56308"}, "emails": ["Stephen@email.com", "Jakovac@email.com"], "phones": [{"numbers": ["320-3858702"], "preferred": true, "type": "home"}, {"numbers": ["320-4400953"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": []} +{"pid": "p-0015", "name": {"first": "Cleveland", "last": "Bejcek"}, "contacts": [{"address": {"city": "Santa Cruz", "state": "CA", "street": "14 Patriot Hwy", "zip": "95062"}, "emails": ["cleveland.bejcek@nosql-matters.org", "cleveland@nosql-matters.org"], "phones": [{"numbers": [], "preferred": false, "type": "home"}, {"numbers": ["831-3372818"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Santa Cruz", "state": "CA", "street": "7939 Willow Blvd", "zip": "95062"}, "emails": ["Cleveland@email.com", "Bejcek@email.com"], "phones": [{"numbers": ["831-4379408"], "preferred": false, "type": "home"}, {"numbers": ["831-6416909"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": ["chess", "checkers"]} +{"pid": "p-0016", "name": {"first": "Mickie", "last": "Menchaca"}, "contacts": [{"address": {"city": "Beachwood", "state": "NJ", "street": "1 Kansas Aly", "zip": "08722"}, "emails": ["mickie.menchaca@nosql-matters.org", "mickie@nosql-matters.org"], "phones": [{"numbers": ["732-1143581"], "preferred": false, "type": "home"}, {"numbers": ["732-9452370"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Beachwood", "state": "NJ", "street": "8460 Birch St", "zip": "08722"}, "emails": ["Mickie@email.com", "Menchaca@email.com"], "phones": [{"numbers": ["732-2496198"], "preferred": true, "type": "home"}, {"numbers": ["732-2309811"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": []} +{"pid": "p-0017", "name": {"first": "Jason", "last": "Meneley"}, "contacts": [{"address": {"city": "Cape Vincent", "state": "NY", "street": "9 Spring garden Dr", "zip": "13618"}, "emails": ["jason.meneley@nosql-matters.org", "jason@nosql-matters.org"], "phones": [{"numbers": ["315-7142142", "315-0405535"], "preferred": false, "type": "home"}, {"numbers": ["315-7155449"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Cape Vincent", "state": "NY", "street": "3798 Bear Cir", "zip": "13618"}, "emails": ["Jason@email.com", "Meneley@email.com"], "phones": [{"numbers": ["315-7267568"], "preferred": false, "type": "home"}, {"numbers": ["315-4949930"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": ["climbing"]} +{"pid": "p-0018", "name": {"first": "Fredda", "last": "Persten"}, "contacts": [{"address": {"city": "El Paso", "state": "TX", "street": "6 University Cir", "zip": "88546"}, "emails": ["fredda.persten@nosql-matters.org", "persten@nosql-matters.org"], "phones": [{"numbers": ["915-7112133", "915-5032376"], "preferred": false, "type": "home"}, {"numbers": ["915-8572661"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "El Paso", "state": "TX", "street": "5212 Birch Rd", "zip": "88546"}, "emails": ["Fredda@email.com", "Persten@email.com"], "phones": [{"numbers": ["915-4151393"], "preferred": true, "type": "home"}, {"numbers": ["915-2704319"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": []} +{"pid": "p-0019", "name": {"first": "Ann", "last": "Skaar"}, "contacts": [{"address": {"city": "Bainville", "state": "MT", "street": "6 17th Ave", "zip": "59212"}, "emails": ["ann.skaar@nosql-matters.org", "skaar@nosql-matters.org"], "phones": [{"numbers": [], "preferred": false, "type": "home"}, {"numbers": ["406-7696353"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Bainville", "state": "MT", "street": "3862 Oak Way", "zip": "59212"}, "emails": ["Ann@email.com", "Skaar@email.com"], "phones": [{"numbers": ["406-4877500"], "preferred": false, "type": "home"}, {"numbers": ["406-8219852"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": ["boxing"]} +{"pid": "p-0020", "name": {"first": "Corey", "last": "Shiroma"}, "contacts": [{"address": {"city": "Saint Louis", "state": "MO", "street": "19 Crescent Loop", "zip": "63108"}, "emails": ["corey.shiroma@nosql-matters.org", "shiroma@nosql-matters.org"], "phones": [{"numbers": [], "preferred": false, "type": "home"}, {"numbers": ["314-6388133"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Saint Louis", "state": "MO", "street": "5949 Bear Loop", "zip": "63108"}, "emails": ["Corey@email.com", "Shiroma@email.com"], "phones": [{"numbers": ["314-2267929"], "preferred": true, "type": "home"}, {"numbers": ["314-7981160"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": ["swimming", "driving"]} +{"pid": "p-0021", "name": {"first": "Graig", "last": "Flax"}, "contacts": [{"address": {"city": "Belvidere Center", "state": "VT", "street": "7 Wallick Ln", "zip": "05442"}, "emails": ["graig.flax@nosql-matters.org", "graig@nosql-matters.org"], "phones": [{"numbers": ["802-4827967"], "preferred": false, "type": "home"}, {"numbers": ["802-3309983"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Belvidere Center", "state": "VT", "street": "8133 Hickory St", "zip": "05442"}, "emails": ["Graig@email.com", "Flax@email.com"], "phones": [{"numbers": ["802-5250430"], "preferred": false, "type": "home"}, {"numbers": ["802-9833507"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": ["skiing", "climbing"]} +{"pid": "p-0022", "name": {"first": "Nydia", "last": "Weeden"}, "contacts": [{"address": {"city": "Tampa", "state": "FL", "street": "6 Mozart St", "zip": "33612"}, "emails": ["nydia.weeden@nosql-matters.org"], "phones": [{"numbers": ["813-5324600", "813-4712316"], "preferred": false, "type": "home"}, {"numbers": ["813-1441450"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Tampa", "state": "FL", "street": "774 Eagle Cir", "zip": "33612"}, "emails": ["Nydia@email.com", "Weeden@email.com"], "phones": [{"numbers": ["813-5545153"], "preferred": true, "type": "home"}, {"numbers": ["813-8596825"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": []} +{"pid": "p-0023", "name": {"first": "Minerva", "last": "Reinbold"}, "contacts": [{"address": {"city": "Anthony", "state": "NM", "street": "7 Branchton Ln", "zip": "88021"}, "emails": ["minerva.reinbold@nosql-matters.org"], "phones": [{"numbers": [], "preferred": false, "type": "home"}, {"numbers": ["505-5286000"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Anthony", "state": "NM", "street": "9477 Birch Cir", "zip": "88021"}, "emails": ["Minerva@email.com", "Reinbold@email.com"], "phones": [{"numbers": ["505-1227441"], "preferred": false, "type": "home"}, {"numbers": ["505-6624231"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": ["chess", "climbing"]} +{"pid": "p-0024", "name": {"first": "Lou", "last": "Cheroki"}, "contacts": [{"address": {"city": "Olla", "state": "LA", "street": "10 Connecticut Dr", "zip": "71465"}, "emails": ["lou.cheroki@nosql-matters.org", "cheroki@nosql-matters.org"], "phones": [{"numbers": ["318-5241811"], "preferred": false, "type": "home"}, {"numbers": ["318-8487451"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Olla", "state": "LA", "street": "6357 Pine St", "zip": "71465"}, "emails": ["Lou@email.com", "Cheroki@email.com"], "phones": [{"numbers": ["318-2855580"], "preferred": true, "type": "home"}, {"numbers": ["318-6205083"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": []} +{"pid": "p-0025", "name": {"first": "Frank", "last": "Sedano"}, "contacts": [{"address": {"city": "Scammon", "state": "KS", "street": "17 Woodson Ave", "zip": "66773"}, "emails": ["frank.sedano@nosql-matters.org", "sedano@nosql-matters.org"], "phones": [{"numbers": [], "preferred": false, "type": "home"}, {"numbers": ["316-9962555"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Scammon", "state": "KS", "street": "6535 Eagle St", "zip": "66773"}, "emails": ["Frank@email.com", "Sedano@email.com"], "phones": [{"numbers": ["316-1648710"], "preferred": false, "type": "home"}, {"numbers": ["316-4673223"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": ["ironing"]} +{"pid": "p-0026", "name": {"first": "Tracey", "last": "Braylock"}, "contacts": [{"address": {"city": "Keithsburg", "state": "IL", "street": "10 Wallick Run", "zip": "61442"}, "emails": ["tracey.braylock@nosql-matters.org", "braylock@nosql-matters.org"], "phones": [{"numbers": [], "preferred": false, "type": "home"}, {"numbers": ["309-4732729"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Keithsburg", "state": "IL", "street": "4038 Deer Dr", "zip": "61442"}, "emails": ["Tracey@email.com", "Braylock@email.com"], "phones": [{"numbers": ["309-1271178"], "preferred": true, "type": "home"}, {"numbers": ["309-3335990"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": []} +{"pid": "p-0027", "name": {"first": "Hayden", "last": "Daniel"}, "contacts": [{"address": {"city": "Blue Rapids", "state": "KS", "street": "4 Main Loop", "zip": "66411"}, "emails": ["hayden.daniel@nosql-matters.org", "daniel@nosql-matters.org", "hayden@nosql-matters.org"], "phones": [{"numbers": ["785-4595093", "785-9794490"], "preferred": false, "type": "home"}, {"numbers": ["785-4736562"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Blue Rapids", "state": "KS", "street": "8929 Fox Cir", "zip": "66411"}, "emails": ["Hayden@email.com", "Daniel@email.com"], "phones": [{"numbers": ["785-8082578"], "preferred": false, "type": "home"}, {"numbers": ["785-7408127"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": ["travelling"]} +{"pid": "p-0028", "name": {"first": "Jene", "last": "Sance"}, "contacts": [{"address": {"city": "Fall Branch", "state": "TN", "street": "12 Mound Ln", "zip": "37656"}, "emails": ["jene.sance@nosql-matters.org", "sance@nosql-matters.org", "jene@nosql-matters.org"], "phones": [{"numbers": [], "preferred": false, "type": "home"}, {"numbers": ["423-3516663"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Fall Branch", "state": "TN", "street": "7412 Willow Loop", "zip": "37656"}, "emails": ["Jene@email.com", "Sance@email.com"], "phones": [{"numbers": ["423-7873914"], "preferred": true, "type": "home"}, {"numbers": ["423-8545326"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": []} +{"pid": "p-0029", "name": {"first": "Toccara", "last": "Damato"}, "contacts": [{"address": {"city": "Garneill", "state": "MT", "street": "6 Deer Way", "zip": "59445"}, "emails": ["toccara.damato@nosql-matters.org", "toccara@nosql-matters.org"], "phones": [{"numbers": ["406-4971630"], "preferred": false, "type": "home"}, {"numbers": ["406-2973636"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Garneill", "state": "MT", "street": "801 Bear Dr", "zip": "59445"}, "emails": ["Toccara@email.com", "Damato@email.com"], "phones": [{"numbers": ["406-4298498"], "preferred": false, "type": "home"}, {"numbers": ["406-2089522"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": ["running", "snowboarding"]} +{"pid": "p-0030", "name": {"first": "Josefina", "last": "Hams"}, "contacts": [{"address": {"city": "Croydon", "state": "PA", "street": "7 Center St", "zip": "19021"}, "emails": ["josefina.hams@nosql-matters.org"], "phones": [{"numbers": ["215-9059514", "215-9507320"], "preferred": false, "type": "home"}, {"numbers": ["215-1497624"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Croydon", "state": "PA", "street": "6573 Eagle Ln", "zip": "19021"}, "emails": ["Josefina@email.com", "Hams@email.com"], "phones": [{"numbers": ["215-2107599"], "preferred": true, "type": "home"}, {"numbers": ["215-8140096"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": ["chess", "boxing"]} +{"pid": "p-0031", "name": {"first": "Randy", "last": "Klenovich"}, "contacts": [{"address": {"city": "Davis", "state": "NC", "street": "22 3rd Ave", "zip": "28524"}, "emails": ["randy.klenovich@nosql-matters.org"], "phones": [{"numbers": ["252-4611502", "252-6980326"], "preferred": false, "type": "home"}, {"numbers": ["252-8481195"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Davis", "state": "NC", "street": "7865 Willow Dr", "zip": "28524"}, "emails": ["Randy@email.com", "Klenovich@email.com"], "phones": [{"numbers": ["252-6021954"], "preferred": false, "type": "home"}, {"numbers": ["252-2604763"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": ["chess", "boxing"]} +{"pid": "p-0032", "name": {"first": "Gonzalo", "last": "Boeshore"}, "contacts": [{"address": {"city": "Sterling Heights", "state": "MI", "street": "18 Willard Dr", "zip": "48310"}, "emails": ["gonzalo.boeshore@nosql-matters.org"], "phones": [{"numbers": ["810-6542772"], "preferred": false, "type": "home"}, {"numbers": ["810-9833933"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Sterling Heights", "state": "MI", "street": "3403 Fox Way", "zip": "48310"}, "emails": ["Gonzalo@email.com", "Boeshore@email.com"], "phones": [{"numbers": ["810-8966286"], "preferred": true, "type": "home"}, {"numbers": ["810-2098693"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": []} +{"pid": "p-0033", "name": {"first": "Hai", "last": "Treamer"}, "contacts": [{"address": {"city": "Sioux City", "state": "IA", "street": "6 Deer St", "zip": "51108"}, "emails": ["hai.treamer@nosql-matters.org"], "phones": [{"numbers": ["712-5347242", "712-7460448"], "preferred": false, "type": "home"}, {"numbers": ["712-2797887"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Sioux City", "state": "IA", "street": "648 Willow Pl", "zip": "51108"}, "emails": ["Hai@email.com", "Treamer@email.com"], "phones": [{"numbers": ["712-6251202"], "preferred": false, "type": "home"}, {"numbers": ["712-3580759"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": []} +{"pid": "p-0034", "name": {"first": "Sammy", "last": "Coldivar"}, "contacts": [{"address": {"city": "Buckhorn", "state": "NM", "street": "2 Commercial Way", "zip": "88025"}, "emails": ["sammy.coldivar@nosql-matters.org"], "phones": [{"numbers": ["505-1394678"], "preferred": false, "type": "home"}, {"numbers": ["505-3439790"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Buckhorn", "state": "NM", "street": "2721 Eagle Ln", "zip": "88025"}, "emails": ["Sammy@email.com", "Coldivar@email.com"], "phones": [{"numbers": ["505-7212465"], "preferred": true, "type": "home"}, {"numbers": ["505-3034229"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": []} +{"pid": "p-0035", "name": {"first": "Son", "last": "Dabe"}, "contacts": [{"address": {"city": "Oneida", "state": "KS", "street": "20 Beechwood Ln", "zip": "66522"}, "emails": ["son.dabe@nosql-matters.org"], "phones": [{"numbers": ["785-4240372"], "preferred": false, "type": "home"}, {"numbers": ["785-6830163"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Oneida", "state": "KS", "street": "617 Maple Ln", "zip": "66522"}, "emails": ["Son@email.com", "Dabe@email.com"], "phones": [{"numbers": ["785-2667233"], "preferred": false, "type": "home"}, {"numbers": ["785-8278974"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": ["checkers"]} +{"pid": "p-0036", "name": {"first": "Carlee", "last": "Degenfelder"}, "contacts": [{"address": {"city": "Pasadena", "state": "CA", "street": "22 Laramie Cir", "zip": "91189"}, "emails": ["carlee.degenfelder@nosql-matters.org", "degenfelder@nosql-matters.org", "carlee@nosql-matters.org"], "phones": [{"numbers": ["626-4051264", "626-2789580"], "preferred": false, "type": "home"}, {"numbers": ["626-1024917"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Pasadena", "state": "CA", "street": "3032 Birch Rd", "zip": "91189"}, "emails": ["Carlee@email.com", "Degenfelder@email.com"], "phones": [{"numbers": ["626-7089153"], "preferred": true, "type": "home"}, {"numbers": ["626-1456983"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": []} +{"pid": "p-0037", "name": {"first": "Mose", "last": "Backlund"}, "contacts": [{"address": {"city": "Tennga", "state": "GA", "street": "1 1st Ave", "zip": "30751"}, "emails": ["mose.backlund@nosql-matters.org", "backlund@nosql-matters.org"], "phones": [{"numbers": [], "preferred": false, "type": "home"}, {"numbers": ["706-8671495"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Tennga", "state": "GA", "street": "2147 Birch Blvd", "zip": "30751"}, "emails": ["Mose@email.com", "Backlund@email.com"], "phones": [{"numbers": ["706-1894392"], "preferred": false, "type": "home"}, {"numbers": ["706-6929420"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": ["biking", "travelling"]} +{"pid": "p-0038", "name": {"first": "Clayton", "last": "Hilda"}, "contacts": [{"address": {"city": "Bolivar", "state": "NY", "street": "22 18th St", "zip": "14715"}, "emails": ["clayton.hilda@nosql-matters.org", "clayton@nosql-matters.org"], "phones": [{"numbers": ["716-0043859", "716-7107175"], "preferred": false, "type": "home"}, {"numbers": ["716-7393704"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Bolivar", "state": "NY", "street": "3414 Birch Dr", "zip": "14715"}, "emails": ["Clayton@email.com", "Hilda@email.com"], "phones": [{"numbers": ["716-3463493"], "preferred": true, "type": "home"}, {"numbers": ["716-5087998"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": []} +{"pid": "p-0039", "name": {"first": "Charley", "last": "Demora"}, "contacts": [{"address": {"city": "North Grafton", "state": "MA", "street": "5 6th St", "zip": "01536"}, "emails": ["charley.demora@nosql-matters.org"], "phones": [{"numbers": ["508-9084206", "508-1037607"], "preferred": false, "type": "home"}, {"numbers": ["508-6649354"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "North Grafton", "state": "MA", "street": "9750 Bear Blvd", "zip": "01536"}, "emails": ["Charley@email.com", "Demora@email.com"], "phones": [{"numbers": ["508-5905226"], "preferred": false, "type": "home"}, {"numbers": ["508-7979365"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": []} +{"pid": "p-0040", "name": {"first": "Dorene", "last": "Gunther"}, "contacts": [{"address": {"city": "Lynn", "state": "MA", "street": "4 Main Run", "zip": "01910"}, "emails": ["dorene.gunther@nosql-matters.org", "gunther@nosql-matters.org"], "phones": [{"numbers": ["781-5720472"], "preferred": false, "type": "home"}, {"numbers": ["781-7245064"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Lynn", "state": "MA", "street": "4998 Bear Way", "zip": "01910"}, "emails": ["Dorene@email.com", "Gunther@email.com"], "phones": [{"numbers": ["781-7210246"], "preferred": true, "type": "home"}, {"numbers": ["781-9752653"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": ["chatting", "boxing", "driving", "ironing"]} +{"pid": "p-0041", "name": {"first": "Alane", "last": "Goldade"}, "contacts": [{"address": {"city": "Portland", "state": "OR", "street": "22 Wyoming Ct", "zip": "97206"}, "emails": ["alane.goldade@nosql-matters.org", "alane@nosql-matters.org"], "phones": [{"numbers": ["503-3482925", "503-9205542"], "preferred": false, "type": "home"}, {"numbers": ["503-3702996"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Portland", "state": "OR", "street": "2048 Fox Blvd", "zip": "97206"}, "emails": ["Alane@email.com", "Goldade@email.com"], "phones": [{"numbers": ["503-7592566"], "preferred": false, "type": "home"}, {"numbers": ["503-3775835"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": []} +{"pid": "p-0042", "name": {"first": "Salina", "last": "Sue"}, "contacts": [{"address": {"city": "Minier", "state": "IL", "street": "4 New hampshire Way", "zip": "61759"}, "emails": ["salina.sue@nosql-matters.org"], "phones": [{"numbers": ["309-7368050"], "preferred": false, "type": "home"}, {"numbers": ["309-7718021"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Minier", "state": "IL", "street": "3702 Eagle Ct", "zip": "61759"}, "emails": ["Salina@email.com", "Sue@email.com"], "phones": [{"numbers": ["309-5243282"], "preferred": true, "type": "home"}, {"numbers": ["309-7797062"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": ["running", "shopping"]} +{"pid": "p-0043", "name": {"first": "Rico", "last": "Hoopengardner"}, "contacts": [{"address": {"city": "Downey", "state": "CA", "street": "14 Phillips Hwy", "zip": "90242"}, "emails": ["rico.hoopengardner@nosql-matters.org"], "phones": [{"numbers": ["562-1439117"], "preferred": false, "type": "home"}, {"numbers": ["562-6290832"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Downey", "state": "CA", "street": "3262 Cedar Pl", "zip": "90242"}, "emails": ["Rico@email.com", "Hoopengardner@email.com"], "phones": [{"numbers": ["562-3983851"], "preferred": false, "type": "home"}, {"numbers": ["562-9813323"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": ["biking"]} +{"pid": "p-0044", "name": {"first": "Laurence", "last": "Vahena"}, "contacts": [{"address": {"city": "Medina", "state": "TX", "street": "18 Santa fe Hwy", "zip": "78055"}, "emails": ["laurence.vahena@nosql-matters.org", "laurence@nosql-matters.org"], "phones": [{"numbers": ["830-1060061"], "preferred": false, "type": "home"}, {"numbers": ["830-5366966"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Medina", "state": "TX", "street": "941 Hickory Dr", "zip": "78055"}, "emails": ["Laurence@email.com", "Vahena@email.com"], "phones": [{"numbers": ["830-4168362"], "preferred": true, "type": "home"}, {"numbers": ["830-5227032"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": ["running"]} +{"pid": "p-0045", "name": {"first": "Jasper", "last": "Okorududu"}, "contacts": [{"address": {"city": "Witter", "state": "AR", "street": "7 21st St", "zip": "72776"}, "emails": ["jasper.okorududu@nosql-matters.org", "okorududu@nosql-matters.org"], "phones": [{"numbers": ["501-7977106", "501-7138486"], "preferred": false, "type": "home"}, {"numbers": ["501-8463297"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Witter", "state": "AR", "street": "3569 Willow Dr", "zip": "72776"}, "emails": ["Jasper@email.com", "Okorududu@email.com"], "phones": [{"numbers": ["501-6648246"], "preferred": false, "type": "home"}, {"numbers": ["501-3963422"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": ["boxing", "climbing"]} +{"pid": "p-0046", "name": {"first": "Tyesha", "last": "Loehrer"}, "contacts": [{"address": {"city": "Dittmer", "state": "MO", "street": "9 266th Ave", "zip": "63023"}, "emails": ["tyesha.loehrer@nosql-matters.org", "tyesha@nosql-matters.org"], "phones": [{"numbers": [], "preferred": false, "type": "home"}, {"numbers": ["636-7867764"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Dittmer", "state": "MO", "street": "2719 Fox Ln", "zip": "63023"}, "emails": ["Tyesha@email.com", "Loehrer@email.com"], "phones": [{"numbers": ["636-6152496"], "preferred": true, "type": "home"}, {"numbers": ["636-7218303"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": ["boxing"]} +{"pid": "p-0047", "name": {"first": "Murray", "last": "Zirk"}, "contacts": [{"address": {"city": "San Juan", "state": "PR", "street": "10 Main Ct", "zip": "00936"}, "emails": ["murray.zirk@nosql-matters.org", "zirk@nosql-matters.org"], "phones": [{"numbers": ["787-5001534", "787-8378996"], "preferred": false, "type": "home"}, {"numbers": ["787-5390615"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "San Juan", "state": "PR", "street": "2271 Deer Ct", "zip": "00936"}, "emails": ["Murray@email.com", "Zirk@email.com"], "phones": [{"numbers": ["787-3305480"], "preferred": false, "type": "home"}, {"numbers": ["787-5256476"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": []} +{"pid": "p-0048", "name": {"first": "Virgil", "last": "Mulneix"}, "contacts": [{"address": {"city": "Birmingham", "state": "AL", "street": "12 Woodlawn St", "zip": "35243"}, "emails": ["virgil.mulneix@nosql-matters.org"], "phones": [{"numbers": ["205-9970849"], "preferred": false, "type": "home"}, {"numbers": ["205-2943448"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Birmingham", "state": "AL", "street": "6634 Deer Blvd", "zip": "35243"}, "emails": ["Virgil@email.com", "Mulneix@email.com"], "phones": [{"numbers": ["205-1061163"], "preferred": true, "type": "home"}, {"numbers": ["205-1872718"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": ["chatting", "boxing"]} +{"pid": "p-0049", "name": {"first": "Miles", "last": "Norden"}, "contacts": [{"address": {"city": "West Camp", "state": "NY", "street": "19 Patriot Blvd", "zip": "12490"}, "emails": ["miles.norden@nosql-matters.org"], "phones": [{"numbers": ["914-3581265", "914-5948065"], "preferred": false, "type": "home"}, {"numbers": ["914-8287917"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "West Camp", "state": "NY", "street": "432 Hickory Pl", "zip": "12490"}, "emails": ["Miles@email.com", "Norden@email.com"], "phones": [{"numbers": ["914-1870215"], "preferred": false, "type": "home"}, {"numbers": ["914-1193936"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": []} +{"pid": "p-0050", "name": {"first": "Quinn", "last": "Cote"}, "contacts": [{"address": {"city": "Bassett", "state": "VA", "street": "10 Ottawa Run", "zip": "24055"}, "emails": ["quinn.cote@nosql-matters.org", "cote@nosql-matters.org"], "phones": [{"numbers": ["540-4505047", "540-3769551"], "preferred": false, "type": "home"}, {"numbers": ["540-8296934"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Bassett", "state": "VA", "street": "5135 Willow Ln", "zip": "24055"}, "emails": ["Quinn@email.com", "Cote@email.com"], "phones": [{"numbers": ["540-7833574"], "preferred": true, "type": "home"}, {"numbers": ["540-9963699"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": ["chatting"]} +{"pid": "p-0051", "name": {"first": "Shavonne", "last": "Finchum"}, "contacts": [{"address": {"city": "Salisbury Mills", "state": "NY", "street": "12 Vermont St", "zip": "12577"}, "emails": ["shavonne.finchum@nosql-matters.org", "finchum@nosql-matters.org"], "phones": [{"numbers": ["914-8440818"], "preferred": false, "type": "home"}, {"numbers": ["914-6337776"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Salisbury Mills", "state": "NY", "street": "5849 Maple Pl", "zip": "12577"}, "emails": ["Shavonne@email.com", "Finchum@email.com"], "phones": [{"numbers": ["914-9660079"], "preferred": false, "type": "home"}, {"numbers": ["914-3237506"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": []} +{"pid": "p-0052", "name": {"first": "Justine", "last": "Girone"}, "contacts": [{"address": {"city": "Denver", "state": "MO", "street": "13 Florida Hwy", "zip": "64441"}, "emails": ["justine.girone@nosql-matters.org", "girone@nosql-matters.org"], "phones": [{"numbers": [], "preferred": false, "type": "home"}, {"numbers": ["660-2399853"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Denver", "state": "MO", "street": "8431 Pine Pl", "zip": "64441"}, "emails": ["Justine@email.com", "Girone@email.com"], "phones": [{"numbers": ["660-2378409"], "preferred": true, "type": "home"}, {"numbers": ["660-8469184"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": []} +{"pid": "p-0053", "name": {"first": "Dorthea", "last": "Visnic"}, "contacts": [{"address": {"city": "San Bernardino", "state": "CA", "street": "14 New hampshire Way", "zip": "92402"}, "emails": ["dorthea.visnic@nosql-matters.org", "dorthea@nosql-matters.org"], "phones": [{"numbers": ["909-1143770"], "preferred": false, "type": "home"}, {"numbers": ["909-1659360"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "San Bernardino", "state": "CA", "street": "7809 Fox Ct", "zip": "92402"}, "emails": ["Dorthea@email.com", "Visnic@email.com"], "phones": [{"numbers": ["909-8607765"], "preferred": false, "type": "home"}, {"numbers": ["909-9113178"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": []} +{"pid": "p-0054", "name": {"first": "Rolland", "last": "Rodrigres"}, "contacts": [{"address": {"city": "Cornwall Bridge", "state": "CT", "street": "17 16th Ave", "zip": "06754"}, "emails": ["rolland.rodrigres@nosql-matters.org"], "phones": [{"numbers": ["860-8120488"], "preferred": false, "type": "home"}, {"numbers": ["860-2902140"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Cornwall Bridge", "state": "CT", "street": "563 Willow St", "zip": "06754"}, "emails": ["Rolland@email.com", "Rodrigres@email.com"], "phones": [{"numbers": ["860-3341996"], "preferred": true, "type": "home"}, {"numbers": ["860-4979629"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": []} +{"pid": "p-0055", "name": {"first": "Elias", "last": "Morch"}, "contacts": [{"address": {"city": "Houston", "state": "TX", "street": "13 Deer Ct", "zip": "77248"}, "emails": ["elias.morch@nosql-matters.org", "morch@nosql-matters.org"], "phones": [{"numbers": ["713-2682695"], "preferred": false, "type": "home"}, {"numbers": ["713-9473116"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Houston", "state": "TX", "street": "7198 Pine Ave", "zip": "77248"}, "emails": ["Elias@email.com", "Morch@email.com"], "phones": [{"numbers": ["713-2628966"], "preferred": false, "type": "home"}, {"numbers": ["713-3965086"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": []} +{"pid": "p-0056", "name": {"first": "Ashley", "last": "Byczek"}, "contacts": [{"address": {"city": "Avon by the Sea", "state": "NJ", "street": "18 262nd Ave", "zip": "07717"}, "emails": ["ashley.byczek@nosql-matters.org", "ashley@nosql-matters.org"], "phones": [{"numbers": ["732-7878019", "732-1294501"], "preferred": false, "type": "home"}, {"numbers": ["732-5553585"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Avon by the Sea", "state": "NJ", "street": "4026 Bear Way", "zip": "07717"}, "emails": ["Ashley@email.com", "Byczek@email.com"], "phones": [{"numbers": ["732-9099243"], "preferred": true, "type": "home"}, {"numbers": ["732-6779254"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": ["chess", "boxing", "reading", "snowboarding", "ironing"]} +{"pid": "p-0057", "name": {"first": "Rosella", "last": "Anastos"}, "contacts": [{"address": {"city": "Yantis", "state": "TX", "street": "8 Main St", "zip": "75497"}, "emails": ["rosella.anastos@nosql-matters.org", "anastos@nosql-matters.org"], "phones": [{"numbers": [], "preferred": false, "type": "home"}, {"numbers": ["903-2651753"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Yantis", "state": "TX", "street": "6801 Elm Ct", "zip": "75497"}, "emails": ["Rosella@email.com", "Anastos@email.com"], "phones": [{"numbers": ["903-6061000"], "preferred": false, "type": "home"}, {"numbers": ["903-5885463"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": ["chatting"]} +{"pid": "p-0058", "name": {"first": "Nicky", "last": "Hopkins"}, "contacts": [{"address": {"city": "Hankins", "state": "NY", "street": "20 Liberty Loop", "zip": "12741"}, "emails": ["nicky.hopkins@nosql-matters.org", "hopkins@nosql-matters.org"], "phones": [{"numbers": [], "preferred": false, "type": "home"}, {"numbers": ["914-4065900"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Hankins", "state": "NY", "street": "8249 Eagle Way", "zip": "12741"}, "emails": ["Nicky@email.com", "Hopkins@email.com"], "phones": [{"numbers": ["914-3624991"], "preferred": true, "type": "home"}, {"numbers": ["914-7070720"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": ["shopping"]} +{"pid": "p-0059", "name": {"first": "Marcy", "last": "Bloem"}, "contacts": [{"address": {"city": "Hanover", "state": "WV", "street": "10 Last chance Pl", "zip": "24839"}, "emails": ["marcy.bloem@nosql-matters.org", "marcy@nosql-matters.org"], "phones": [{"numbers": [], "preferred": false, "type": "home"}, {"numbers": ["304-4496505"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Hanover", "state": "WV", "street": "6160 Birch Way", "zip": "24839"}, "emails": ["Marcy@email.com", "Bloem@email.com"], "phones": [{"numbers": ["304-2957533"], "preferred": false, "type": "home"}, {"numbers": ["304-2981108"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": []} +{"pid": "p-0060", "name": {"first": "Long", "last": "Mulinix"}, "contacts": [{"address": {"city": "Ashland", "state": "OH", "street": "17 Swann Way", "zip": "44805"}, "emails": ["long.mulinix@nosql-matters.org"], "phones": [{"numbers": [], "preferred": false, "type": "home"}, {"numbers": ["419-5864638"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Ashland", "state": "OH", "street": "4718 Deer Ave", "zip": "44805"}, "emails": ["Long@email.com", "Mulinix@email.com"], "phones": [{"numbers": ["419-2942582"], "preferred": true, "type": "home"}, {"numbers": ["419-1758355"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": ["travelling", "climbing"]} +{"pid": "p-0061", "name": {"first": "Marlen", "last": "Heusner"}, "contacts": [{"address": {"city": "Hartford", "state": "VT", "street": "16 Industrial Dr", "zip": "05047"}, "emails": ["marlen.heusner@nosql-matters.org", "heusner@nosql-matters.org"], "phones": [{"numbers": ["802-6968411", "802-9326817"], "preferred": false, "type": "home"}, {"numbers": ["802-1405129"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Hartford", "state": "VT", "street": "3158 Fox Pl", "zip": "05047"}, "emails": ["Marlen@email.com", "Heusner@email.com"], "phones": [{"numbers": ["802-8838666"], "preferred": false, "type": "home"}, {"numbers": ["802-5537072"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": ["chatting"]} +{"pid": "p-0062", "name": {"first": "Tonie", "last": "Mauro"}, "contacts": [{"address": {"city": "Neelyville", "state": "MO", "street": "4 Biltmore Ct", "zip": "63954"}, "emails": ["tonie.mauro@nosql-matters.org"], "phones": [{"numbers": ["573-7582822"], "preferred": false, "type": "home"}, {"numbers": ["573-6593161"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Neelyville", "state": "MO", "street": "1095 Deer Rd", "zip": "63954"}, "emails": ["Tonie@email.com", "Mauro@email.com"], "phones": [{"numbers": ["573-8376173"], "preferred": true, "type": "home"}, {"numbers": ["573-7681891"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": ["snowboarding"]} +{"pid": "p-0063", "name": {"first": "Gerard", "last": "Shroyer"}, "contacts": [{"address": {"city": "Clarita", "state": "OK", "street": "14 18th St", "zip": "74535"}, "emails": ["gerard.shroyer@nosql-matters.org", "shroyer@nosql-matters.org"], "phones": [{"numbers": ["580-9002737", "580-2706148"], "preferred": false, "type": "home"}, {"numbers": ["580-1905949"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Clarita", "state": "OK", "street": "1026 Pine Dr", "zip": "74535"}, "emails": ["Gerard@email.com", "Shroyer@email.com"], "phones": [{"numbers": ["580-7365585"], "preferred": false, "type": "home"}, {"numbers": ["580-8734574"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": ["chatting"]} +{"pid": "p-0064", "name": {"first": "Rosina", "last": "Leinen"}, "contacts": [{"address": {"city": "La Quinta", "state": "CA", "street": "3 Palmer Ln", "zip": "92253"}, "emails": ["rosina.leinen@nosql-matters.org", "rosina@nosql-matters.org"], "phones": [{"numbers": ["760-2596242"], "preferred": false, "type": "home"}, {"numbers": ["760-3518333"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "La Quinta", "state": "CA", "street": "1896 Maple Loop", "zip": "92253"}, "emails": ["Rosina@email.com", "Leinen@email.com"], "phones": [{"numbers": ["760-9660550"], "preferred": true, "type": "home"}, {"numbers": ["760-7004175"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": ["chatting", "reading"]} +{"pid": "p-0065", "name": {"first": "Abe", "last": "Troiani"}, "contacts": [{"address": {"city": "Hudson", "state": "IL", "street": "5 Beekman St", "zip": "61748"}, "emails": ["abe.troiani@nosql-matters.org", "troiani@nosql-matters.org", "abe@nosql-matters.org"], "phones": [{"numbers": ["309-4888909", "309-3260513"], "preferred": false, "type": "home"}, {"numbers": ["309-7643768"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Hudson", "state": "IL", "street": "826 Eagle Cir", "zip": "61748"}, "emails": ["Abe@email.com", "Troiani@email.com"], "phones": [{"numbers": ["309-8123217"], "preferred": false, "type": "home"}, {"numbers": ["309-2831187"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": ["shopping"]} +{"pid": "p-0066", "name": {"first": "Carri", "last": "Mickler"}, "contacts": [{"address": {"city": "Reno", "state": "NV", "street": "13 290th St", "zip": "89570"}, "emails": ["carri.mickler@nosql-matters.org"], "phones": [{"numbers": ["775-3352309"], "preferred": false, "type": "home"}, {"numbers": ["775-9517270"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Reno", "state": "NV", "street": "569 Oak Ave", "zip": "89570"}, "emails": ["Carri@email.com", "Mickler@email.com"], "phones": [{"numbers": ["775-7913134"], "preferred": true, "type": "home"}, {"numbers": ["775-9131482"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": []} +{"pid": "p-0067", "name": {"first": "Julissa", "last": "Filosa"}, "contacts": [{"address": {"city": "Creston", "state": "IA", "street": "8 Beechwood Aly", "zip": "50801"}, "emails": ["julissa.filosa@nosql-matters.org"], "phones": [{"numbers": ["515-0629512", "515-7012469"], "preferred": false, "type": "home"}, {"numbers": ["515-7517235"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Creston", "state": "IA", "street": "3672 Pine Loop", "zip": "50801"}, "emails": ["Julissa@email.com", "Filosa@email.com"], "phones": [{"numbers": ["515-5589751"], "preferred": false, "type": "home"}, {"numbers": ["515-4531302"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": ["ironing"]} +{"pid": "p-0068", "name": {"first": "Dusty", "last": "Sistrunk"}, "contacts": [{"address": {"city": "Saint Anthony", "state": "IA", "street": "18 Santa fe Cir", "zip": "50239"}, "emails": ["dusty.sistrunk@nosql-matters.org"], "phones": [{"numbers": ["515-0638915", "515-6682501"], "preferred": false, "type": "home"}, {"numbers": ["515-3141779"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Saint Anthony", "state": "IA", "street": "6391 Eagle Ct", "zip": "50239"}, "emails": ["Dusty@email.com", "Sistrunk@email.com"], "phones": [{"numbers": ["515-1692053"], "preferred": true, "type": "home"}, {"numbers": ["515-5394014"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": ["travelling"]} +{"pid": "p-0069", "name": {"first": "Brandon", "last": "Ulibarri"}, "contacts": [{"address": {"city": "Odenton", "state": "MD", "street": "9 Beechwood Aly", "zip": "21113"}, "emails": ["brandon.ulibarri@nosql-matters.org", "brandon@nosql-matters.org"], "phones": [{"numbers": [], "preferred": false, "type": "home"}, {"numbers": ["410-8239484"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Odenton", "state": "MD", "street": "131 Maple Ave", "zip": "21113"}, "emails": ["Brandon@email.com", "Ulibarri@email.com"], "phones": [{"numbers": ["410-7365666"], "preferred": false, "type": "home"}, {"numbers": ["410-2688666"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": []} +{"pid": "p-0070", "name": {"first": "Angelina", "last": "Mcadoo"}, "contacts": [{"address": {"city": "Kingman", "state": "IN", "street": "20 Ottawa Pl", "zip": "47952"}, "emails": ["angelina.mcadoo@nosql-matters.org"], "phones": [{"numbers": ["765-1949397", "765-4847931"], "preferred": false, "type": "home"}, {"numbers": ["765-2231053"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Kingman", "state": "IN", "street": "5803 Bear Ct", "zip": "47952"}, "emails": ["Angelina@email.com", "Mcadoo@email.com"], "phones": [{"numbers": ["765-3256232"], "preferred": true, "type": "home"}, {"numbers": ["765-8129695"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": []} +{"pid": "p-0071", "name": {"first": "Julio", "last": "Schwanebeck"}, "contacts": [{"address": {"city": "Henderson", "state": "NV", "street": "9 Country club Aly", "zip": "89012"}, "emails": ["julio.schwanebeck@nosql-matters.org", "schwanebeck@nosql-matters.org"], "phones": [{"numbers": ["702-0808220"], "preferred": false, "type": "home"}, {"numbers": ["702-5113648"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Henderson", "state": "NV", "street": "8987 Elm Ln", "zip": "89012"}, "emails": ["Julio@email.com", "Schwanebeck@email.com"], "phones": [{"numbers": ["702-7963128"], "preferred": false, "type": "home"}, {"numbers": ["702-8293004"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": ["checkers"]} +{"pid": "p-0072", "name": {"first": "Mirian", "last": "Guzzardo"}, "contacts": [{"address": {"city": "Santa Clarita", "state": "CA", "street": "10 290th Ave", "zip": "91383"}, "emails": ["mirian.guzzardo@nosql-matters.org", "mirian@nosql-matters.org"], "phones": [{"numbers": ["661-4619498"], "preferred": false, "type": "home"}, {"numbers": ["661-3851332"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Santa Clarita", "state": "CA", "street": "7570 Eagle Rd", "zip": "91383"}, "emails": ["Mirian@email.com", "Guzzardo@email.com"], "phones": [{"numbers": ["661-6114117"], "preferred": true, "type": "home"}, {"numbers": ["661-5194552"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": ["swimming"]} +{"pid": "p-0073", "name": {"first": "Sharri", "last": "Pletsch"}, "contacts": [{"address": {"city": "San Francisco", "state": "CA", "street": "13 Fraser Ln", "zip": "94153"}, "emails": ["sharri.pletsch@nosql-matters.org", "sharri@nosql-matters.org"], "phones": [{"numbers": ["415-0144394"], "preferred": false, "type": "home"}, {"numbers": ["415-1356909"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "San Francisco", "state": "CA", "street": "1120 Pine Ave", "zip": "94153"}, "emails": ["Sharri@email.com", "Pletsch@email.com"], "phones": [{"numbers": ["415-2580482"], "preferred": false, "type": "home"}, {"numbers": ["415-6817947"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": []} +{"pid": "p-0074", "name": {"first": "Brenton", "last": "Lynskey"}, "contacts": [{"address": {"city": "Augusta", "state": "GA", "street": "20 Kearney Way", "zip": "30906"}, "emails": ["brenton.lynskey@nosql-matters.org", "lynskey@nosql-matters.org", "brenton@nosql-matters.org"], "phones": [{"numbers": ["706-9360969"], "preferred": false, "type": "home"}, {"numbers": ["706-7214674"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Augusta", "state": "GA", "street": "3182 Fox Cir", "zip": "30906"}, "emails": ["Brenton@email.com", "Lynskey@email.com"], "phones": [{"numbers": ["706-1098786"], "preferred": true, "type": "home"}, {"numbers": ["706-5765256"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": []} +{"pid": "p-0075", "name": {"first": "Lavern", "last": "Hamlet"}, "contacts": [{"address": {"city": "Silver City", "state": "NV", "street": "12 Calvert Blvd", "zip": "89428"}, "emails": ["lavern.hamlet@nosql-matters.org"], "phones": [{"numbers": ["775-6709905", "775-9088264"], "preferred": false, "type": "home"}, {"numbers": ["775-1665836"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Silver City", "state": "NV", "street": "7718 Birch Cir", "zip": "89428"}, "emails": ["Lavern@email.com", "Hamlet@email.com"], "phones": [{"numbers": ["775-5419798"], "preferred": false, "type": "home"}, {"numbers": ["775-1482134"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": ["running"]} +{"pid": "p-0076", "name": {"first": "Monte", "last": "Mihlfeld"}, "contacts": [{"address": {"city": "Monticello", "state": "MN", "street": "21 5th St", "zip": "55587"}, "emails": ["monte.mihlfeld@nosql-matters.org"], "phones": [{"numbers": ["612-6706220"], "preferred": false, "type": "home"}, {"numbers": ["612-7372636"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Monticello", "state": "MN", "street": "2249 Eagle Way", "zip": "55587"}, "emails": ["Monte@email.com", "Mihlfeld@email.com"], "phones": [{"numbers": ["612-1968599"], "preferred": true, "type": "home"}, {"numbers": ["612-5353412"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": ["swimming"]} +{"pid": "p-0077", "name": {"first": "Bradford", "last": "Imperial"}, "contacts": [{"address": {"city": "Saint Louis", "state": "MO", "street": "3 Belmont Ct", "zip": "63198"}, "emails": ["bradford.imperial@nosql-matters.org", "bradford@nosql-matters.org"], "phones": [{"numbers": ["314-9336935"], "preferred": false, "type": "home"}, {"numbers": ["314-6073952"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Saint Louis", "state": "MO", "street": "8631 Pine Ct", "zip": "63198"}, "emails": ["Bradford@email.com", "Imperial@email.com"], "phones": [{"numbers": ["314-9252274"], "preferred": false, "type": "home"}, {"numbers": ["314-5211657"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": ["ironing"]} +{"pid": "p-0078", "name": {"first": "Eryn", "last": "Daquilante"}, "contacts": [{"address": {"city": "Wellesley Hills", "state": "MA", "street": "11 20th St", "zip": "02481"}, "emails": ["eryn.daquilante@nosql-matters.org", "daquilante@nosql-matters.org"], "phones": [{"numbers": ["781-6373282"], "preferred": false, "type": "home"}, {"numbers": ["781-3944303"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Wellesley Hills", "state": "MA", "street": "6974 Oak Dr", "zip": "02481"}, "emails": ["Eryn@email.com", "Daquilante@email.com"], "phones": [{"numbers": ["781-8321396"], "preferred": true, "type": "home"}, {"numbers": ["781-2809399"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": []} +{"pid": "p-0079", "name": {"first": "Roslyn", "last": "Aerni"}, "contacts": [{"address": {"city": "Peaks Island", "state": "ME", "street": "16 Champlain St", "zip": "04108"}, "emails": ["roslyn.aerni@nosql-matters.org"], "phones": [{"numbers": [], "preferred": false, "type": "home"}, {"numbers": ["207-4178418"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Peaks Island", "state": "ME", "street": "5830 Oak Dr", "zip": "04108"}, "emails": ["Roslyn@email.com", "Aerni@email.com"], "phones": [{"numbers": ["207-1905917"], "preferred": false, "type": "home"}, {"numbers": ["207-9445068"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": ["shopping", "reading"]} +{"pid": "p-0080", "name": {"first": "Chas", "last": "Cefalu"}, "contacts": [{"address": {"city": "Brodhead", "state": "KY", "street": "4 Ontario Rd", "zip": "40409"}, "emails": ["chas.cefalu@nosql-matters.org"], "phones": [{"numbers": ["606-5073368"], "preferred": false, "type": "home"}, {"numbers": ["606-7752094"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Brodhead", "state": "KY", "street": "5822 Maple Cir", "zip": "40409"}, "emails": ["Chas@email.com", "Cefalu@email.com"], "phones": [{"numbers": ["606-6191816"], "preferred": true, "type": "home"}, {"numbers": ["606-6866552"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": []} +{"pid": "p-0081", "name": {"first": "Berneice", "last": "Migliori"}, "contacts": [{"address": {"city": "Orfordville", "state": "WI", "street": "9 4th St", "zip": "53576"}, "emails": ["berneice.migliori@nosql-matters.org"], "phones": [{"numbers": [], "preferred": false, "type": "home"}, {"numbers": ["608-3390083"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Orfordville", "state": "WI", "street": "1872 Eagle St", "zip": "53576"}, "emails": ["Berneice@email.com", "Migliori@email.com"], "phones": [{"numbers": ["608-9758010"], "preferred": false, "type": "home"}, {"numbers": ["608-2279722"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": ["swimming"]} +{"pid": "p-0082", "name": {"first": "Patricia", "last": "Shoji"}, "contacts": [{"address": {"city": "Tippo", "state": "MS", "street": "15 Kansas Dr", "zip": "38962"}, "emails": ["patricia.shoji@nosql-matters.org"], "phones": [{"numbers": ["662-2743361", "662-7499550"], "preferred": false, "type": "home"}, {"numbers": ["662-5478932"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Tippo", "state": "MS", "street": "4524 Fox Rd", "zip": "38962"}, "emails": ["Patricia@email.com", "Shoji@email.com"], "phones": [{"numbers": ["662-8873305"], "preferred": true, "type": "home"}, {"numbers": ["662-2802043"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": []} +{"pid": "p-0083", "name": {"first": "Kenton", "last": "Bagent"}, "contacts": [{"address": {"city": "Omaha", "state": "NE", "street": "22 Wallace Ln", "zip": "68120"}, "emails": ["kenton.bagent@nosql-matters.org", "bagent@nosql-matters.org"], "phones": [{"numbers": [], "preferred": false, "type": "home"}, {"numbers": ["402-9778294"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Omaha", "state": "NE", "street": "3513 Oak Ave", "zip": "68120"}, "emails": ["Kenton@email.com", "Bagent@email.com"], "phones": [{"numbers": ["402-4716492"], "preferred": false, "type": "home"}, {"numbers": ["402-3196381"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": ["running", "snowboarding", "skiing"]} +{"pid": "p-0084", "name": {"first": "Elyse", "last": "Leis"}, "contacts": [{"address": {"city": "Solsberry", "state": "IN", "street": "18 Fuller Ln", "zip": "47459"}, "emails": ["elyse.leis@nosql-matters.org"], "phones": [{"numbers": [], "preferred": false, "type": "home"}, {"numbers": ["812-2168367"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Solsberry", "state": "IN", "street": "373 Hickory Rd", "zip": "47459"}, "emails": ["Elyse@email.com", "Leis@email.com"], "phones": [{"numbers": ["812-1419542"], "preferred": true, "type": "home"}, {"numbers": ["812-3741153"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": ["running"]} +{"pid": "p-0085", "name": {"first": "Maryjo", "last": "Tariq"}, "contacts": [{"address": {"city": "Broad Run", "state": "VA", "street": "6 Morningside Pl", "zip": "20137"}, "emails": ["maryjo.tariq@nosql-matters.org"], "phones": [{"numbers": ["540-7768397"], "preferred": false, "type": "home"}, {"numbers": ["540-1695368"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Broad Run", "state": "VA", "street": "6670 Cedar Loop", "zip": "20137"}, "emails": ["Maryjo@email.com", "Tariq@email.com"], "phones": [{"numbers": ["540-9133623"], "preferred": false, "type": "home"}, {"numbers": ["540-2636703"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": ["swimming", "snowboarding", "skiing", "ironing"]} +{"pid": "p-0086", "name": {"first": "Margaretta", "last": "Ogwynn"}, "contacts": [{"address": {"city": "Faulkton", "state": "SD", "street": "13 Palmer Pl", "zip": "57438"}, "emails": ["margaretta.ogwynn@nosql-matters.org", "ogwynn@nosql-matters.org"], "phones": [{"numbers": ["605-3511227"], "preferred": false, "type": "home"}, {"numbers": ["605-9222296"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Faulkton", "state": "SD", "street": "8802 Pine Pl", "zip": "57438"}, "emails": ["Margaretta@email.com", "Ogwynn@email.com"], "phones": [{"numbers": ["605-6145635"], "preferred": true, "type": "home"}, {"numbers": ["605-8063640"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": []} +{"pid": "p-0087", "name": {"first": "Glory", "last": "Mollenkopf"}, "contacts": [{"address": {"city": "Ridgewood", "state": "NY", "street": "6 1st Ave", "zip": "11386"}, "emails": ["glory.mollenkopf@nosql-matters.org"], "phones": [{"numbers": [], "preferred": false, "type": "home"}, {"numbers": ["718-9211053"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Ridgewood", "state": "NY", "street": "2025 Eagle Ct", "zip": "11386"}, "emails": ["Glory@email.com", "Mollenkopf@email.com"], "phones": [{"numbers": ["718-6115058"], "preferred": false, "type": "home"}, {"numbers": ["718-8964275"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": []} +{"pid": "p-0088", "name": {"first": "Janette", "last": "Nicholes"}, "contacts": [{"address": {"city": "New York", "state": "NY", "street": "7 Rawlins Pl", "zip": "10011"}, "emails": ["janette.nicholes@nosql-matters.org"], "phones": [{"numbers": ["212-6481067"], "preferred": false, "type": "home"}, {"numbers": ["212-1053805"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "New York", "state": "NY", "street": "5084 Birch Loop", "zip": "10011"}, "emails": ["Janette@email.com", "Nicholes@email.com"], "phones": [{"numbers": ["212-4485205"], "preferred": true, "type": "home"}, {"numbers": ["212-4276605"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": ["checkers"]} +{"pid": "p-0089", "name": {"first": "Brandon", "last": "Laidlaw"}, "contacts": [{"address": {"city": "Birmingham", "state": "AL", "street": "21 Cliffbourne Aly", "zip": "35240"}, "emails": ["brandon.laidlaw@nosql-matters.org", "laidlaw@nosql-matters.org"], "phones": [{"numbers": ["205-1673400", "205-0536483"], "preferred": false, "type": "home"}, {"numbers": ["205-7100843"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Birmingham", "state": "AL", "street": "8368 Maple Cir", "zip": "35240"}, "emails": ["Brandon@email.com", "Laidlaw@email.com"], "phones": [{"numbers": ["205-8544438"], "preferred": false, "type": "home"}, {"numbers": ["205-4811936"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": []} +{"pid": "p-0090", "name": {"first": "Arturo", "last": "Kinatyan"}, "contacts": [{"address": {"city": "Rock Point", "state": "AZ", "street": "16 Last chance Run", "zip": "86545"}, "emails": ["arturo.kinatyan@nosql-matters.org"], "phones": [{"numbers": [], "preferred": false, "type": "home"}, {"numbers": ["520-2800014"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Rock Point", "state": "AZ", "street": "4302 Pine Ct", "zip": "86545"}, "emails": ["Arturo@email.com", "Kinatyan@email.com"], "phones": [{"numbers": ["520-9311152"], "preferred": true, "type": "home"}, {"numbers": ["520-8881070"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": ["chatting"]} +{"pid": "p-0091", "name": {"first": "Eddie", "last": "Colangelo"}, "contacts": [{"address": {"city": "Schenectady", "state": "NY", "street": "16 Center Ln", "zip": "12308"}, "emails": ["eddie.colangelo@nosql-matters.org", "colangelo@nosql-matters.org", "eddie@nosql-matters.org"], "phones": [{"numbers": ["518-1453490"], "preferred": false, "type": "home"}, {"numbers": ["518-4608724"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Schenectady", "state": "NY", "street": "5038 Eagle St", "zip": "12308"}, "emails": ["Eddie@email.com", "Colangelo@email.com"], "phones": [{"numbers": ["518-1950063"], "preferred": false, "type": "home"}, {"numbers": ["518-5870179"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": []} +{"pid": "p-0092", "name": {"first": "Margrett", "last": "Heartz"}, "contacts": [{"address": {"city": "Baraboo", "state": "WI", "street": "18 Mintwood Way", "zip": "53913"}, "emails": ["margrett.heartz@nosql-matters.org"], "phones": [{"numbers": [], "preferred": false, "type": "home"}, {"numbers": ["608-9946461"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Baraboo", "state": "WI", "street": "8652 Fox Pl", "zip": "53913"}, "emails": ["Margrett@email.com", "Heartz@email.com"], "phones": [{"numbers": ["608-8619124"], "preferred": true, "type": "home"}, {"numbers": ["608-9788830"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": []} +{"pid": "p-0093", "name": {"first": "Verna", "last": "Wigfield"}, "contacts": [{"address": {"city": "Belmont", "state": "LA", "street": "2 Main Blvd", "zip": "71406"}, "emails": ["verna.wigfield@nosql-matters.org", "wigfield@nosql-matters.org"], "phones": [{"numbers": ["318-5784855", "318-8625864"], "preferred": false, "type": "home"}, {"numbers": ["318-4351938"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Belmont", "state": "LA", "street": "4397 Birch Ct", "zip": "71406"}, "emails": ["Verna@email.com", "Wigfield@email.com"], "phones": [{"numbers": ["318-5731503"], "preferred": false, "type": "home"}, {"numbers": ["318-9241107"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": []} +{"pid": "p-0094", "name": {"first": "Jarrod", "last": "Litwiler"}, "contacts": [{"address": {"city": "Brockway", "state": "PA", "street": "17 Walnut Dr", "zip": "15824"}, "emails": ["jarrod.litwiler@nosql-matters.org", "jarrod@nosql-matters.org"], "phones": [{"numbers": ["814-7395320", "814-1794652"], "preferred": false, "type": "home"}, {"numbers": ["814-6097548"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Brockway", "state": "PA", "street": "5954 Cedar Cir", "zip": "15824"}, "emails": ["Jarrod@email.com", "Litwiler@email.com"], "phones": [{"numbers": ["814-4223653"], "preferred": true, "type": "home"}, {"numbers": ["814-9491935"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": ["running"]} +{"pid": "p-0095", "name": {"first": "Kelley", "last": "Wala"}, "contacts": [{"address": {"city": "Tulsa", "state": "OK", "street": "21 Neosho Ln", "zip": "74129"}, "emails": ["kelley.wala@nosql-matters.org", "kelley@nosql-matters.org"], "phones": [{"numbers": ["918-1081617", "918-4968318"], "preferred": false, "type": "home"}, {"numbers": ["918-1620751"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Tulsa", "state": "OK", "street": "8268 Elm Cir", "zip": "74129"}, "emails": ["Kelley@email.com", "Wala@email.com"], "phones": [{"numbers": ["918-3268600"], "preferred": false, "type": "home"}, {"numbers": ["918-7031002"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": []} +{"pid": "p-0096", "name": {"first": "Shaunta", "last": "Geringer"}, "contacts": [{"address": {"city": "Lehman", "state": "PA", "street": "15 Spring Run", "zip": "18627"}, "emails": ["shaunta.geringer@nosql-matters.org", "shaunta@nosql-matters.org"], "phones": [{"numbers": ["570-4850697"], "preferred": false, "type": "home"}, {"numbers": ["570-4314468"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Lehman", "state": "PA", "street": "2507 Elm Blvd", "zip": "18627"}, "emails": ["Shaunta@email.com", "Geringer@email.com"], "phones": [{"numbers": ["570-6503681"], "preferred": true, "type": "home"}, {"numbers": ["570-8475727"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": ["snowboarding", "travelling"]} +{"pid": "p-0097", "name": {"first": "Ira", "last": "Rechel"}, "contacts": [{"address": {"city": "Lawrenceville", "state": "VA", "street": "9 Riggs Pl", "zip": "23868"}, "emails": ["ira.rechel@nosql-matters.org"], "phones": [{"numbers": ["804-3225311", "804-7803572"], "preferred": false, "type": "home"}, {"numbers": ["804-3483070"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Lawrenceville", "state": "VA", "street": "6335 Eagle Ct", "zip": "23868"}, "emails": ["Ira@email.com", "Rechel@email.com"], "phones": [{"numbers": ["804-1116981"], "preferred": false, "type": "home"}, {"numbers": ["804-6594632"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": ["running", "shopping", "skiing"]} +{"pid": "p-0098", "name": {"first": "Concetta", "last": "Rotondo"}, "contacts": [{"address": {"city": "Vichy", "state": "MO", "street": "9 19th Ave", "zip": "65580"}, "emails": ["concetta.rotondo@nosql-matters.org"], "phones": [{"numbers": [], "preferred": false, "type": "home"}, {"numbers": ["573-7427716"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Vichy", "state": "MO", "street": "7423 Oak Ave", "zip": "65580"}, "emails": ["Concetta@email.com", "Rotondo@email.com"], "phones": [{"numbers": ["573-1182504"], "preferred": true, "type": "home"}, {"numbers": ["573-1194496"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": []} +{"pid": "p-0099", "name": {"first": "Georgetta", "last": "Kolding"}, "contacts": [{"address": {"city": "Marshallville", "state": "OH", "street": "22 290th St", "zip": "44645"}, "emails": ["georgetta.kolding@nosql-matters.org", "kolding@nosql-matters.org"], "phones": [{"numbers": ["330-6429454"], "preferred": false, "type": "home"}, {"numbers": ["330-1989984"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Marshallville", "state": "OH", "street": "2812 Willow Way", "zip": "44645"}, "emails": ["Georgetta@email.com", "Kolding@email.com"], "phones": [{"numbers": ["330-4925907"], "preferred": false, "type": "home"}, {"numbers": ["330-7514225"], "preferred": true, "type": "mobile"}], "type": "secondary"}], "likes": ["running", "boxing", "reading"]} +{"pid": "p-0100", "name": {"first": "Rickie", "last": "Bakaler"}, "contacts": [{"address": {"city": "Wallace", "state": "KS", "street": "20 14th St", "zip": "67761"}, "emails": ["rickie.bakaler@nosql-matters.org"], "phones": [{"numbers": ["785-8179421", "785-2447694"], "preferred": false, "type": "home"}, {"numbers": ["785-4731991"], "preferred": true, "type": "mobile"}], "type": "primary"}, {"address": {"city": "Wallace", "state": "KS", "street": "7867 Hickory Blvd", "zip": "67761"}, "emails": ["Rickie@email.com", "Bakaler@email.com"], "phones": [{"numbers": ["785-8958174"], "preferred": true, "type": "home"}, {"numbers": ["785-6669457"], "preferred": false, "type": "mobile"}], "type": "secondary"}], "likes": ["biking"]} diff --git a/Objective-C/Tests/UnnestArrayIndexTest.m b/Objective-C/Tests/UnnestArrayIndexTest.m new file mode 100644 index 000000000..b7f6048cf --- /dev/null +++ b/Objective-C/Tests/UnnestArrayIndexTest.m @@ -0,0 +1,107 @@ +// +// UnnestArrayIndexTest.m +// CouchbaseLite +// +// Copyright (c) 2024 Couchbase, Inc. All rights reserved. +// +// Licensed under the Couchbase License Agreement (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// https://info.couchbase.com/rs/302-GJY-034/images/2017-10-30_License_Agreement.pdf +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "CBLTestCase.h" +#import "CBLArrayIndexConfiguration.h" +#import "CBLCollection+Internal.h" + +@interface UnnestArrayIndexTest : CBLTestCase + +@end + +@implementation UnnestArrayIndexTest + +/** + Test Spec v1.0.1: + https://github.com/couchbaselabs/couchbase-lite-api/blob/master/spec/tests/T0004-Unnest-Array-Index.md + */ + +/** + 1. TestArrayIndexConfigInvalidExpressions + Description + Test that creating an ArrayIndexConfiguration with invalid expressions which are an empty expressions or contain null. + Steps + 1. Create a ArrayIndexConfiguration object. + - path: "contacts" + - expressions: [] + 2. Check that an invalid arument exception is thrown. + */ + +- (void) testArrayIndexConfigInvalidExpressions { + [self expectException: NSInvalidArgumentException in:^{ + (void) [[CBLArrayIndexConfiguration alloc] initWithPath:@"contacts" expressions: @[]]; + }]; + + [self expectException: NSInvalidArgumentException in:^{ + (void) [[CBLArrayIndexConfiguration alloc] initWithPath:@"contacts" expressions: @[@""]]; + }]; +} + +/** + 2. TestCreateArrayIndexWithPath + Description + Test that creating an array index with only path works as expected. + Steps + 1. Load profiles.json into the collection named "_default.profiles". + 2. Create a ArrayIndexConfiguration object. + - path: "contacts" + - expressions: null + 3. Create an array index named "contacts" in the profiles collection. + 4. Get index names from the profiles collection and check that the index named "contacts" exists. + 5. Get info of the index named "contacts" using an internal API and check that the index has path and expressions as configured. + */ + +- (void) testCreateArrayIndexWithPath { + NSError* err; + CBLCollection* profiles = [self.db createCollectionWithName: @"profiles" scope: nil error: &err]; + [self loadJSONResource: @"profiles_100" toCollection: profiles]; + + CBLArrayIndexConfiguration* config = [[CBLArrayIndexConfiguration alloc] initWithPath: @"contacts" expressions: nil]; + [profiles createIndexWithName: @"contacts" config: config error: &err]; + NSArray* indexes = [profiles indexesInfo: nil]; + AssertEqual(indexes.count, 1u); + AssertEqualObjects(indexes[0][@"expr"], @""); +} + +/** + 3. TestCreateArrayIndexWithPathAndExpressions + Description + Test that creating an array index with path and expressions works as expected. + Steps + 1. Load profiles.json into the collection named "_default.profiles". + 2. Create a ArrayIndexConfiguration object. + - path: "contacts" + - expressions: ["address.city", "address.state"] + 3. Create an array index named "contacts" in the profiles collection. + 4. Get index names from the profiles collection and check that the index named "contacts" exists. + 5. Get info of the index named "contacts" using an internal API and check that the index has path and expressions as configured. + */ +- (void) testCreateArrayIndexWithPathAndExpressions { + NSError* err; + CBLCollection* profiles = [self.db createCollectionWithName: @"profiles" scope: nil error: &err]; + [self loadJSONResource: @"profiles_100" toCollection: profiles]; + + CBLArrayIndexConfiguration* config = [[CBLArrayIndexConfiguration alloc] initWithPath: @"contacts" expressions: @[@"address.city", @"address.state"]]; + [profiles createIndexWithName: @"contacts" config: config error: &err]; + + NSArray* indexes = [profiles indexesInfo: nil]; + AssertEqual(indexes.count, 1u); + AssertEqualObjects(indexes[0][@"expr"], @"address.city,address.state"); +} + +@end diff --git a/Objective-C/Tests/VectorSearchTest+Lazy.m b/Objective-C/Tests/VectorSearchTest+Lazy.m index edf5b6b22..1daec825c 100644 --- a/Objective-C/Tests/VectorSearchTest+Lazy.m +++ b/Objective-C/Tests/VectorSearchTest+Lazy.m @@ -1231,7 +1231,7 @@ - (void) testIndexUpdaterIndexOutOfBounds { } /** - * 26. TestIndexUpdaterCallFinishTwice + * 26. TestIndexUpdaterCallFinishTwice + 27. TestIndexUpdaterUseAfterFinished * * Description * Test that when calling IndexUpdater's finish() after it was finished, @@ -1250,10 +1250,10 @@ - (void) testIndexUpdaterIndexOutOfBounds { * - Convert the vector result which is an array object to a platform's float array. * - Call setVector() with the platform's float array at the index. * 4. Call finish() and check that the finish() is successfully called. - * 5. Call finish() again and check that a CouchbaseLiteException with the code NotOpen is thrown. + * 5. Call finish() again and check that it throws exception. * 6. Count, getValue, setVector, skipVector throw exception. */ -- (void) testIndexUpdaterCallFinishTwice { +- (void) testIndexUpdaterUseAfterFinished { [self createWordsIndexWithConfig: LAZY_VECTOR_INDEX_CONFIG(@"word", 300, 8)]; NSError* error; @@ -1267,6 +1267,11 @@ - (void) testIndexUpdaterCallFinishTwice { Assert([updater setVector: vector atIndex: 0 error: &error]); Assert([updater finishWithError: &error]); + [self expectException: @"NSInternalInconsistencyException" in:^{ + NSError* outError; + [updater finishWithError: &outError]; + }]; + [self expectException: @"NSInternalInconsistencyException" in:^{ [updater count]; }]; @@ -1283,11 +1288,6 @@ - (void) testIndexUpdaterCallFinishTwice { [self expectException: @"NSInternalInconsistencyException" in:^{ [updater skipVectorAtIndex: 0]; }]; - - [self expectException: @"NSInternalInconsistencyException" in:^{ - NSError* outError; - [updater finishWithError: &outError]; - }]; } @end diff --git a/Swift/Collection.swift b/Swift/Collection.swift index 18791674c..50d61b2f0 100644 --- a/Swift/Collection.swift +++ b/Swift/Collection.swift @@ -352,6 +352,10 @@ public final class Collection : CollectionChangeObservable, Indexable, Equatable // MARK: Internal + func indexesInfo() throws -> [[String: Any]]? { + return try impl.indexesInfo() as? [[String: Any]] + } + init(_ impl: CBLCollection, db: Database) { self.impl = impl self.database = db diff --git a/Swift/IndexConfiguration.swift b/Swift/IndexConfiguration.swift index d77f5b847..dfd928060 100644 --- a/Swift/IndexConfiguration.swift +++ b/Swift/IndexConfiguration.swift @@ -88,7 +88,14 @@ public struct ArrayIndexConfiguration: IndexConfiguration, IndexConfigConvertabl /// represents an expression defining the values within the array to be indexed. /// If the array specified by the path contains scalar values, this parameter can be null. /// - Returns The ArrayIndexConfiguration object. - public init(path: String, _ expressions: [String]?) { + public init(path: String, _ expressions: [String]? = nil) { + if let expressions = expressions { + if expressions.isEmpty || (expressions.count == 1 && expressions[0].isEmpty) { + NSException(name: .invalidArgumentException, + reason: "Empty expressions is not allowed, use nil instead", + userInfo: nil).raise() + } + } self.path = path self.expressions = expressions } diff --git a/Swift/Tests/ArrayTest.swift b/Swift/Tests/ArrayTest.swift index d408e01ba..f29427c61 100644 --- a/Swift/Tests/ArrayTest.swift +++ b/Swift/Tests/ArrayTest.swift @@ -235,7 +235,7 @@ class ArrayTest: CBLTestCase { func testUnsavedMutableArrayToJSON() throws { let json = "[{\"unsaved\":\"mutableDoc\"}]" var mArray = try MutableArrayObject(json: json) - expectExcepion(exception: .internalInconsistencyException) { + expectException(exception: .internalInconsistencyException) { let _ = mArray.toJSON() } @@ -244,7 +244,7 @@ class ArrayTest: CBLTestCase { try saveDocument(mDoc) mArray = mDoc.array(forKey: "array")! - expectExcepion(exception: .internalInconsistencyException) { + expectException(exception: .internalInconsistencyException) { let _ = mArray.toJSON() } } @@ -278,7 +278,7 @@ class ArrayTest: CBLTestCase { var blob = mDoc.blob(forKey: "origin") // before save it should throw the exception - expectExcepion(exception: .internalInconsistencyException) { + expectException(exception: .internalInconsistencyException) { print("\(blob!.content?.count ?? 0)") } try self.db.saveDocument(mDoc) diff --git a/Swift/Tests/CBLTestCase.swift b/Swift/Tests/CBLTestCase.swift index f1bfb5696..5aa06eace 100644 --- a/Swift/Tests/CBLTestCase.swift +++ b/Swift/Tests/CBLTestCase.swift @@ -274,7 +274,7 @@ class CBLTestCase: XCTestCase { } } - func expectExcepion(exception: NSExceptionName, block: @escaping () -> Void) { + func expectException(exception: NSExceptionName, block: @escaping () -> Void) { var exceptionThrown = false do { try CBLTestHelper.catchException { diff --git a/Swift/Tests/DictionaryTest.swift b/Swift/Tests/DictionaryTest.swift index 9a2c2ab23..f16d9d82d 100644 --- a/Swift/Tests/DictionaryTest.swift +++ b/Swift/Tests/DictionaryTest.swift @@ -268,7 +268,7 @@ class DictionaryTest: CBLTestCase { mDoc = doc!.toMutable() mDict = dict!.toMutable() mDict.setValue("newValueAppended", forKey: "newKeyAppended") - expectExcepion(exception: .internalInconsistencyException) { + expectException(exception: .internalInconsistencyException) { let _ = mDict.toJSON() } mDoc.setValue(mDict, forKey: "dict") @@ -282,7 +282,7 @@ class DictionaryTest: CBLTestCase { func testUnsavedMutableDictionaryToJSON() throws { let mDict = try MutableDictionaryObject(json: "{\"unsaved\":\"dict\"}") - expectExcepion(exception: .internalInconsistencyException) { + expectException(exception: .internalInconsistencyException) { let _ = mDict.toJSON() } } diff --git a/Swift/Tests/DocumentTest.swift b/Swift/Tests/DocumentTest.swift index cc361e99c..d0a757a88 100644 --- a/Swift/Tests/DocumentTest.swift +++ b/Swift/Tests/DocumentTest.swift @@ -1653,7 +1653,7 @@ class DocumentTest: CBLTestCase { func testUnsavedMutableDocumentToJSON() throws { let mDoc = try MutableDocument(id: "doc", json: "{\"unsaved\":\"doc\"}") - expectExcepion(exception: .internalInconsistencyException) { + expectException(exception: .internalInconsistencyException) { let _ = mDoc.toJSON() } } @@ -1732,7 +1732,7 @@ class DocumentTest: CBLTestCase { func testUnsavedBlob() throws { let content = kTestBlob.data(using: .utf8)! let blob = Blob(contentType: "text/plain", data: content) - expectExcepion(exception: .internalInconsistencyException) { + expectException(exception: .internalInconsistencyException) { let _ = blob.toJSON() } } @@ -1751,7 +1751,7 @@ class DocumentTest: CBLTestCase { try self.db.saveBlob(blob: blob) var b: Blob? - expectExcepion(exception: .invalidArgumentException) { + expectException(exception: .invalidArgumentException) { b = try! self.db.getBlob(properties: [Blob.typeProperty:"bl0b", Blob.blobDigestProperty: blob.digest! as String, Blob.blobContentType: "text/plain", @@ -1759,7 +1759,7 @@ class DocumentTest: CBLTestCase { } XCTAssertNil(b) - expectExcepion(exception: .invalidArgumentException) { + expectException(exception: .invalidArgumentException) { b = try! self.db.getBlob(properties: ["type":Blob.blobType, Blob.blobDigestProperty: blob.digest! as String, Blob.blobContentType: "text/plain", @@ -1767,7 +1767,7 @@ class DocumentTest: CBLTestCase { } XCTAssertNil(b) - expectExcepion(exception: .invalidArgumentException) { + expectException(exception: .invalidArgumentException) { b = try! self.db.getBlob(properties: [Blob.typeProperty:Blob.blobType, Blob.blobDigestProperty: blob.digest! as String, Blob.blobContentType: 1234, @@ -1775,7 +1775,7 @@ class DocumentTest: CBLTestCase { } XCTAssertNil(b) - expectExcepion(exception: .invalidArgumentException) { + expectException(exception: .invalidArgumentException) { b = try! self.db.getBlob(properties: [Blob.typeProperty:Blob.blobType, Blob.blobDigestProperty: blob.digest! as String, Blob.blobContentType: "text/plain", @@ -1783,7 +1783,7 @@ class DocumentTest: CBLTestCase { } XCTAssertNil(b) - expectExcepion(exception: .invalidArgumentException) { + expectException(exception: .invalidArgumentException) { b = try! self.db.getBlob(properties: [Blob.typeProperty:Blob.blobType, Blob.blobDigestProperty: 12, Blob.blobContentType: "text/plain", diff --git a/Swift/Tests/ReplicatorTest+Collection.swift b/Swift/Tests/ReplicatorTest+Collection.swift index 93ee82470..ad8bc9d8a 100644 --- a/Swift/Tests/ReplicatorTest+Collection.swift +++ b/Swift/Tests/ReplicatorTest+Collection.swift @@ -360,7 +360,7 @@ class ReplicatorTest_Collection: ReplicatorTest { let target = URLEndpoint(url: url) var config = ReplicatorConfiguration(target: target) - expectExcepion(exception: .invalidArgumentException) { + expectException(exception: .invalidArgumentException) { config.addCollections([col1a, col1b]) } @@ -371,7 +371,7 @@ class ReplicatorTest_Collection: ReplicatorTest { XCTAssertEqual(config.collections.count, 1) XCTAssert(config.collections.contains(where: { $0.name == "colA" && $0.scope.name == "scopeA" })) - expectExcepion(exception: .invalidArgumentException) { + expectException(exception: .invalidArgumentException) { config.addCollection(col1b) } } @@ -389,7 +389,7 @@ class ReplicatorTest_Collection: ReplicatorTest { let target = URLEndpoint(url: url) var config = ReplicatorConfiguration(target: target) - expectExcepion(exception: .invalidArgumentException) { + expectException(exception: .invalidArgumentException) { config.addCollections([col1a, col1b]) } @@ -400,7 +400,7 @@ class ReplicatorTest_Collection: ReplicatorTest { XCTAssertEqual(config.collections.count, 1) XCTAssert(config.collections.contains(where: { $0.name == "colA" && $0.scope.name == "scopeA" })) - expectExcepion(exception: .invalidArgumentException) { + expectException(exception: .invalidArgumentException) { config.addCollection(col1b) } } diff --git a/Swift/Tests/UnnestArrayTest.swift b/Swift/Tests/UnnestArrayTest.swift new file mode 100644 index 000000000..096d15766 --- /dev/null +++ b/Swift/Tests/UnnestArrayTest.swift @@ -0,0 +1,85 @@ +// +// UnnestArrayTest.swift +// CouchbaseLite +// +// Copyright (c) 2024 Couchbase, Inc. All rights reserved. +// +// Licensed under the Couchbase License Agreement (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// https://info.couchbase.com/rs/302-GJY-034/images/2017-10-30_License_Agreement.pdf +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import XCTest +@testable import CouchbaseLiteSwift + +/// Test Spec v1.0.1: +/// https://github.com/couchbaselabs/couchbase-lite-api/blob/master/spec/tests/T0004-Unnest-Array-Index.md + +class UnnestArrayTest: CBLTestCase { + /// 1. TestArrayIndexConfigInvalidExpressions + /// Description + /// Test that creating an ArrayIndexConfiguration with invalid expressions which are an empty expressions or contain null. + /// Steps + /// 1. Create a ArrayIndexConfiguration object. + /// - path: "contacts" + /// - expressions: [] + /// 2. Check that an invalid arument exception is thrown. + func testArrayIndexConfigInvalidExpressions() throws { + expectException(exception: .invalidArgumentException) { + _ = ArrayIndexConfiguration(path: "contacts", []) + } + + expectException(exception: .invalidArgumentException) { + _ = ArrayIndexConfiguration(path: "contacts", [""]) + } + } + + /// 2. TestCreateArrayIndexWithPath + /// Description + /// Test that creating an ArrayIndexConfiguration with invalid expressions which are an empty expressions or contain null. + /// Steps + /// 1. Load profiles.json into the collection named "_default.profiles". + /// 2. Create a ArrayIndexConfiguration object. + /// - path: "contacts" + /// - expressions: null + /// 3. Create an array index named "contacts" in the profiles collection. + /// 4. Get index names from the profiles collection and check that the index named "contacts" exists. + /// 5. Get info of the index named "contacts" using an internal API and check that the index has path and expressions as configured. + func testCreateArrayIndexWithPath() throws { + let profiles = try db.createCollection(name: "profiles") + try loadJSONResource("profiles_100", collection: profiles) + let config = ArrayIndexConfiguration(path: "contacts") + try profiles.createIndex(withName: "contacts", config: config) + let indexes = try profiles.indexesInfo() + XCTAssertEqual(indexes!.count, 1) + XCTAssertEqual(indexes![0]["expr"] as! String, "") + } + + /// 3. TestCreateArrayIndexWithPathAndExpressions + /// Description + /// Test that creating an array index with path and expressions works as expected. + /// Steps + /// 1. Load profiles.json into the collection named "_default.profiles". + /// 2. Create a ArrayIndexConfiguration object. + /// - path: "contacts" + /// - expressions: ["address.city", "address.state"] + /// 3. Create an array index named "contacts" in the profiles collection. + /// 4. Get index names from the profiles collection and check that the index named "contacts" exists. + /// 5. Get info of the index named "contacts" using an internal API and check that the index has path and expressions as configured. + func testCreateArrayIndexWithPathAndExpressions() throws { + let profiles = try db.createCollection(name: "profiles") + try loadJSONResource("profiles_100", collection: profiles) + let config = ArrayIndexConfiguration(path: "contacts", ["address.city", "address.state"]) + try profiles.createIndex(withName: "contacts", config: config) + let indexes = try profiles.indexesInfo() + XCTAssertEqual(indexes!.count, 1) + XCTAssertEqual(indexes![0]["expr"] as! String, "address.city,address.state") + } +} diff --git a/Swift/Tests/VectorSearchTest+Lazy.swift b/Swift/Tests/VectorSearchTest+Lazy.swift index 260e9230d..5fe62799c 100644 --- a/Swift/Tests/VectorSearchTest+Lazy.swift +++ b/Swift/Tests/VectorSearchTest+Lazy.swift @@ -195,7 +195,7 @@ class VectorSearchTest_Lazy : VectorSearchTest { let index = try wordsIndex() - expectExcepion(exception: .invalidArgumentException) { + expectException(exception: .invalidArgumentException) { _ = try? index.beginUpdate(limit: 0) } } @@ -774,55 +774,55 @@ class VectorSearchTest_Lazy : VectorSearchTest { let updater = try index.beginUpdate(limit: 10)! XCTAssertEqual(updater.count, 1) - expectExcepion(exception: .rangeException) { + expectException(exception: .rangeException) { _ = updater.string(at: 1) } - expectExcepion(exception: .rangeException) { + expectException(exception: .rangeException) { _ = updater.int(at: 1) } - expectExcepion(exception: .rangeException) { + expectException(exception: .rangeException) { _ = updater.int64(at: 1) } - expectExcepion(exception: .rangeException) { + expectException(exception: .rangeException) { _ = updater.float(at: 1) } - expectExcepion(exception: .rangeException) { + expectException(exception: .rangeException) { _ = updater.double(at: 1) } - expectExcepion(exception: .rangeException) { + expectException(exception: .rangeException) { _ = updater.boolean(at: 1) } - expectExcepion(exception: .rangeException) { + expectException(exception: .rangeException) { _ = updater.date(at: 1) } - expectExcepion(exception: .rangeException) { + expectException(exception: .rangeException) { _ = updater.blob(at: 1) } - expectExcepion(exception: .rangeException) { + expectException(exception: .rangeException) { _ = updater.dictionary(at: 1) } - expectExcepion(exception: .rangeException) { + expectException(exception: .rangeException) { _ = updater.array(at: 1) } - expectExcepion(exception: .rangeException) { + expectException(exception: .rangeException) { _ = updater.value(at: 1) } - expectExcepion(exception: .rangeException) { + expectException(exception: .rangeException) { try! updater.setVector([1.0, 2.0, 3.0], at: 1) } - expectExcepion(exception: .rangeException) { + expectException(exception: .rangeException) { updater.skipVector(at: 1) } } diff --git a/Swift/Tests/VectorSearchTest.swift b/Swift/Tests/VectorSearchTest.swift index 57d84bdf2..9bb1e87db 100644 --- a/Swift/Tests/VectorSearchTest.swift +++ b/Swift/Tests/VectorSearchTest.swift @@ -274,11 +274,11 @@ class VectorSearchTest_Main: VectorSearchTest { let config2 = VectorIndexConfiguration(expression: "vector", dimensions: 4096, centroids: 8) try wordsCollection.createIndex(withName: "words_index_2", config: config2) - expectExcepion(exception: .invalidArgumentException) { + expectException(exception: .invalidArgumentException) { _ = VectorIndexConfiguration(expression: "vector", dimensions: 1, centroids: 8) } - expectExcepion(exception: .invalidArgumentException) { + expectException(exception: .invalidArgumentException) { _ = VectorIndexConfiguration(expression: "vector", dimensions: 4097, centroids: 8) } } @@ -305,11 +305,11 @@ class VectorSearchTest_Main: VectorSearchTest { let config2 = VectorIndexConfiguration(expression: "vector", dimensions: 300, centroids: 64000) try wordsCollection.createIndex(withName: "words_index_2", config: config2) - expectExcepion(exception: .invalidArgumentException) { + expectException(exception: .invalidArgumentException) { _ = VectorIndexConfiguration(expression: "vector", dimensions: 300, centroids: 0) } - expectExcepion(exception: .invalidArgumentException) { + expectException(exception: .invalidArgumentException) { _ = VectorIndexConfiguration(expression: "vector", dimensions: 300, centroids: 64001) } } @@ -806,7 +806,7 @@ class VectorSearchTest_Main: VectorSearchTest { for numberOfSubq in [0, 7] { try deleteWordsIndex() config.encoding = .productQuantizer(subquantizers: UInt32(numberOfSubq), bits: 8) - expectExcepion(exception: .invalidArgumentException) { + expectException(exception: .invalidArgumentException) { try? self.createWordsIndex(config: config) } } @@ -874,7 +874,7 @@ class VectorSearchTest_Main: VectorSearchTest { try deleteWordsIndex() config.minTrainingSize = 10 config.maxTrainingSize = 9 - expectExcepion(exception: .invalidArgumentException) { + expectException(exception: .invalidArgumentException) { try? self.createWordsIndex(config: config) } } diff --git a/vendor/couchbase-lite-core b/vendor/couchbase-lite-core index 163b832d9..55ddf2ca9 160000 --- a/vendor/couchbase-lite-core +++ b/vendor/couchbase-lite-core @@ -1 +1 @@ -Subproject commit 163b832d936f795c2c2a3cf15990c03787616294 +Subproject commit 55ddf2ca9410efadb88ed87b6370c07aeb908ef9