Skip to content

Commit

Permalink
Merge pull request #1909 from couchbase/couchbase-lite-ios/feature/ma…
Browse files Browse the repository at this point in the history
…p_version

Fixed #1758 Updated designed doc’s map function not get re-compiled
  • Loading branch information
snej committed Oct 4, 2017
2 parents dd319bf + ee4d554 commit 0ab34be
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 8 deletions.
6 changes: 4 additions & 2 deletions Source/API/CBLView.m
Expand Up @@ -92,7 +92,7 @@ - (instancetype) initWithDatabase: (CBLDatabase*)db name: (NSString*)name create
}


@synthesize name=_name, storage=_storage, collation=_collation;
@synthesize name=_name, storage=_storage, collation=_collation, isDesignDoc=_isDesignDoc;


- (NSString*) description {
Expand Down Expand Up @@ -153,9 +153,11 @@ - (CBLMapBlock) registeredMapBlock {
- (CBLMapBlock) mapBlock {
CBLMapBlock map = self.registeredMapBlock;
// Invoke view compiler if it's available:
if (!map && [self respondsToSelector: @selector(compileFromDesignDoc)])
if (self.isDesignDoc ||
(!map && [self respondsToSelector: @selector(compileFromDesignDoc)])) {
if ([self compileFromDesignDoc] == kCBLStatusOK)
map = self.registeredMapBlock;
}
return map;
}

Expand Down
2 changes: 2 additions & 0 deletions Source/CBLView+Internal.h
Expand Up @@ -53,6 +53,8 @@ BOOL CBLQueryRowValueIsEntireDoc(id value);

@property (readonly) NSArray* viewsInGroup;

@property (nonatomic) BOOL isDesignDoc;

/** Updates the view's index (incrementally) if necessary.
If the index is updated, the other views in the viewGroup will be updated as a bonus.
@return 200 if updated, 304 if already up-to-date, else an error code */
Expand Down
23 changes: 17 additions & 6 deletions Source/CBLView+REST.m
Expand Up @@ -16,16 +16,17 @@ @implementation CBLView (REST)


- (CBLStatus) compileFromDesignDoc {
if (self.registeredMapBlock != nil)
if (!self.isDesignDoc && self.registeredMapBlock) /* Native design doc like view */
return kCBLStatusOK;

// see if there's a design doc with a CouchDB-style view definition we can compile:
NSString* language;
NSDictionary* viewProps = $castIf(NSDictionary, [self.database getDesignDocFunction: self.name
key: @"views"
language: &language]);
if (!viewProps)
return kCBLStatusNotFound;

LogTo(View, @"%@: Attempting to compile %@ from design doc", self.name, language);
if (![CBLView compiler])
return kCBLStatusNotImplemented;
Expand All @@ -34,6 +35,15 @@ - (CBLStatus) compileFromDesignDoc {


- (CBLStatus) compileFromProperties: (NSDictionary*)viewProps language: (NSString*)language {
// Version string is based on a digest of the properties:
NSError* error;
NSString* version = CBLHexSHA1Digest([CBJSONEncoder canonicalEncoding: viewProps error: &error]);
if (!version)
Warn(@"View %@ could not generate version string from the view properties: %@", self, error);

if ([version isEqualToString: self.mapVersion])
return kCBLStatusOK; // Same as the current version

if (!language)
language = @"javascript";
NSString* mapSource = viewProps[@"map"];
Expand All @@ -53,16 +63,17 @@ - (CBLStatus) compileFromProperties: (NSDictionary*)viewProps language: (NSStrin
return kCBLStatusCallbackError;
}
}

// Version string is based on a digest of the properties:
NSError* error;
NSString* version = CBLHexSHA1Digest([CBJSONEncoder canonicalEncoding: viewProps error: &error]);

[self setMapBlock: mapBlock reduceBlock: reduceBlock version: version];

self.documentType = $castIf(NSString, viewProps[@"documentType"]);
NSDictionary* options = $castIf(NSDictionary, viewProps[@"options"]);
self.collation = ($equal(options[@"collation"], @"raw")) ? kCBLViewCollationRaw
: kCBLViewCollationUnicode;

// Mark as a design doc view:
self.isDesignDoc = YES;

return kCBLStatusOK;
}

Expand Down
49 changes: 49 additions & 0 deletions Unit-Tests/Router_Tests.m
Expand Up @@ -578,6 +578,55 @@ - (void) test_JSViews {
}


- (void) test_UpdateMapFunction {
[CBLView setCompiler: [[CBLJSViewCompiler alloc] init]];
[CBLDatabase setFilterCompiler: [[CBLJSFilterCompiler alloc] init]];

// PUT:
SendBody(self, @"PUT", @"/db/doc1", $dict({@"message", @"hello"}), kCBLStatusCreated, nil);
SendBody(self, @"PUT", @"/db/doc2", $dict({@"message", @"bonjour"}), kCBLStatusCreated, nil);
SendBody(self, @"PUT", @"/db/doc3", $dict({@"message", @"hello"}), kCBLStatusCreated, nil);

NSString* designDoc = @"/db/_design/design";
NSDictionary* result = SendBody(self, @"PUT", designDoc,
@{@"views":
@{@"view":
@{@"map":
@"function(doc){if(doc.message == 'hello') emit(doc.message, null);}"
}
}
}, kCBLStatusCreated, nil);

// Query view and check the result:
id null = [NSNull null];
Send(self, @"GET", @"/db/_design/design/_view/view", kCBLStatusOK,
$dict({@"offset", @0},
{@"rows", $array($dict({@"id", @"doc1"}, {@"key", @"hello"}, {@"value", null}),
$dict({@"id", @"doc3"}, {@"key", @"hello"}, {@"value", null}) )},
{@"total_rows", @2}));

// Update Map function:
designDoc = [designDoc stringByAppendingFormat: @"?rev=%@", result[@"rev"]];
result = SendBody(self, @"PUT", designDoc,
@{@"views":
@{@"view":
@{@"map":
@"function(doc){if(doc.message == 'bonjour') emit(doc.message, null);}"
}
}
},
kCBLStatusCreated, nil);

Send(self, @"GET", @"/db/_design/design/_view/view", kCBLStatusOK,
$dict({@"offset", @0},
{@"rows", $array($dict({@"id", @"doc2"}, {@"key", @"bonjour"}, {@"value", null}))},
{@"total_rows", @1}));

[CBLView setCompiler: nil];
[CBLDatabase setFilterCompiler: nil];
}


- (void) test_NoMappedSelectors {
__unused NSDictionary* response = nil;

Expand Down

0 comments on commit 0ab34be

Please sign in to comment.