Skip to content
Browse files

Make sure views compiled from JS get rebuilt if the map/reduce fn cha…

…nges

…Although currently this only takes effect next time the app is launched, i.e.
it isn't watching for edits of the design docs while running.

Also moved the code that triggers the compilation out of TDRouter and into
TD_View and TD_Database.
  • Loading branch information...
1 parent 75b9ceb commit 57ddb43811c1f9e36e9930ebdb046c5dddc08e06 @snej snej committed Jan 28, 2013
Showing with 87 additions and 51 deletions.
  1. +9 −51 Source/TDRouter+Handlers.m
  2. +5 −0 Source/TD_Database.h
  3. +35 −0 Source/TD_Database.m
  4. +3 −0 Source/TD_View.h
  5. +35 −0 Source/TD_View.m
View
60 Source/TDRouter+Handlers.m
@@ -892,63 +892,20 @@ - (TDStatus) do_DELETE: (TD_Database*)db docID: (NSString*)docID attachment: (NS
#pragma mark - VIEW QUERIES:
-- (TD_View*) compileView: (NSString*)viewName fromProperties: (NSDictionary*)viewProps {
- NSString* language = viewProps[@"language"] ?: @"javascript";
- NSString* mapSource = viewProps[@"map"];
- if (!mapSource)
- return nil;
- TDMapBlock mapBlock = [[TD_View compiler] compileMapFunction: mapSource language: language];
- if (!mapBlock) {
- Warn(@"View %@ has unknown map function: %@", viewName, mapSource);
- return nil;
- }
- NSString* reduceSource = viewProps[@"reduce"];
- TDReduceBlock reduceBlock = NULL;
- if (reduceSource) {
- reduceBlock =[[TD_View compiler] compileReduceFunction: reduceSource language: language];
- if (!reduceBlock) {
- Warn(@"View %@ has unknown reduce function: %@", viewName, reduceSource);
- return nil;
- }
- }
-
- TD_View* view = [_db viewNamed: viewName];
- [view setMapBlock: mapBlock reduceBlock: reduceBlock version: @"1"];
-
- NSDictionary* options = $castIf(NSDictionary, viewProps[@"options"]);
- if ($equal(options[@"collation"], @"raw"))
- view.collation = kTDViewCollationRaw;
- return view;
-}
-
-
- (TDStatus) queryDesignDoc: (NSString*)designDoc view: (NSString*)viewName keys: (NSArray*)keys {
NSString* tdViewName = $sprintf(@"%@/%@", designDoc, viewName);
- TD_View* view = [_db existingViewNamed: tdViewName];
- if (!view || !view.mapBlock) {
- // No TouchDB view is defined, or it hasn't had a map block assigned;
- // see if there's a CouchDB view definition we can compile:
- TD_Revision* rev = [_db getDocumentWithID: [@"_design/" stringByAppendingString: designDoc]
- revisionID: nil];
- if (!rev)
- return kTDStatusNotFound;
- NSDictionary* views = $castIf(NSDictionary, rev[@"views"]);
- NSDictionary* viewProps = $castIf(NSDictionary, views[viewName]);
- if (!viewProps)
- return kTDStatusNotFound;
- // If there is a CouchDB view, see if it can be compiled from source:
- view = [self compileView: tdViewName fromProperties: viewProps];
- if (!view)
- return kTDStatusDBError;
- }
+ TDStatus status;
+ TD_View* view = [_db compileViewNamed: tdViewName status: &status];
+ if (!view)
+ return status;
TDQueryOptions options;
if (![self getQueryOptions: &options])
return kTDStatusBadRequest;
if (keys)
options.keys = keys;
- TDStatus status = [view updateIndex];
+ status = [view updateIndex];
if (status >= kTDStatusBadRequest)
return status;
SequenceNumber lastSequenceIndexed = view.lastSequenceIndexed;
@@ -1002,9 +959,10 @@ - (TDStatus) do_POST_temp_view: (TD_Database*)db {
if ([self cacheWithEtag: $sprintf(@"%lld", _db.lastSequence)]) // conditional GET
return kTDStatusNotModified;
- TD_View* view = [self compileView: @"@@TEMPVIEW@@" fromProperties: props];
- if (!view)
- return kTDStatusDBError;
+ TD_View* view = [_db viewNamed: @"@@TEMPVIEW@@"];
+ if (![view compileFromProperties: props])
+ return kTDStatusBadRequest;
+
@try {
TDStatus status = [view updateIndex];
if (status >= kTDStatusBadRequest)
View
5 Source/TD_Database.h
@@ -161,6 +161,11 @@ extern const TDChangesOptions kDefaultTDChangesOptions;
- (TD_View*) existingViewNamed: (NSString*)name;
+/** Returns the view with the given name. If there is none, and the name is in CouchDB
+ format ("designdocname/viewname"), it attempts to load the view properties from the
+ design document and compile them with the TDViewCompiler. */
+- (TD_View*) compileViewNamed: (NSString*)name status: (TDStatus*)outStatus;
+
@property (readonly) NSArray* allViews;
- (TD_RevisionList*) changesSinceSequence: (SequenceNumber)lastSequence
View
35 Source/TD_Database.m
@@ -916,6 +916,41 @@ - (TDStatus) deleteViewNamed: (NSString*)name {
}
+- (TD_View*) compileViewNamed: (NSString*)tdViewName status: (TDStatus*)outStatus {
+ TD_View* view = [self existingViewNamed: tdViewName];
+ if (view && view.mapBlock)
+ return view;
+
+ // No TouchDB view is defined, or it hasn't had a map block assigned;
+ // see if there's a CouchDB view definition we can compile:
+ NSArray* path = [tdViewName componentsSeparatedByString: @"/"];
+ if (path.count != 2) {
+ *outStatus = kTDStatusNotFound;
+ return nil;
+ }
+ TD_Revision* rev = [self getDocumentWithID: [@"_design/" stringByAppendingString: path[0]]
+ revisionID: nil];
+ if (!rev) {
+ *outStatus = kTDStatusNotFound;
+ return nil;
+ }
+ NSDictionary* views = $castIf(NSDictionary, rev[@"views"]);
+ NSDictionary* viewProps = $castIf(NSDictionary, views[path[1]]);
+ if (!viewProps) {
+ *outStatus = kTDStatusNotFound;
+ return nil;
+ }
+
+ // If there is a CouchDB view, see if it can be compiled from source:
+ view = [self viewNamed: tdViewName];
+ if (![view compileFromProperties: viewProps]) {
+ *outStatus = kTDStatusCallbackError;
+ return nil;
+ }
+ return view;
+}
+
+
//FIX: This has a lot of code in common with -[TD_View queryWithOptions:status:]. Unify the two!
- (NSDictionary*) getDocsWithIDs: (NSArray*)docIDs options: (const TDQueryOptions*)options {
if (!options)
View
3 Source/TD_View.h
@@ -88,6 +88,9 @@ typedef enum {
reduceBlock: (TDReduceBlock)reduceBlock
version: (NSString*)version;
+/** Compiles a view (using the registered TDViewCompiler) from the properties found in a CouchDB-style design document. */
+- (BOOL) compileFromProperties: (NSDictionary*)viewProps;
+
- (void) removeIndex;
/** Is the view's index currently out of date? */
View
35 Source/TD_View.m
@@ -16,6 +16,8 @@
#import "TD_View.h"
#import "TDInternal.h"
#import "TDCollateJSON.h"
+#import "TDCanonicalJSON.h"
+#import "TDMisc.h"
#import "FMDatabase.h"
#import "FMDatabaseAdditions.h"
@@ -97,6 +99,39 @@ - (BOOL) setMapBlock: (TDMapBlock)mapBlock
}
+- (BOOL) compileFromProperties: (NSDictionary*)viewProps {
+ NSString* language = viewProps[@"language"] ?: @"javascript";
+ NSString* mapSource = viewProps[@"map"];
+ if (!mapSource)
+ return NO;
+ TDMapBlock mapBlock = [[TD_View compiler] compileMapFunction: mapSource language: language];
+ if (!mapBlock) {
+ Warn(@"View %@ has unknown map function: %@", _name, mapSource);
+ return NO;
+ }
+ NSString* reduceSource = viewProps[@"reduce"];
+ TDReduceBlock reduceBlock = NULL;
+ if (reduceSource) {
+ reduceBlock =[[TD_View compiler] compileReduceFunction: reduceSource language: language];
+ if (!reduceBlock) {
+ Warn(@"View %@ has unknown reduce function: %@", _name, reduceSource);
+ return NO;
+ }
+ }
+
+ // Version string is based on a digest of the properties:
+ NSString* version = TDHexSHA1Digest([TDCanonicalJSON canonicalData: viewProps]);
+
+ [self setMapBlock: mapBlock reduceBlock: reduceBlock version: version];
+
+ NSDictionary* options = $castIf(NSDictionary, viewProps[@"options"]);
+ self.collation = ($equal(options[@"collation"], @"raw")) ? kTDViewCollationRaw
+ : kTDViewCollationUnicode;
+ return YES;
+}
+
+
+
- (void) removeIndex {
if (self.viewID <= 0)
return;

0 comments on commit 57ddb43

Please sign in to comment.
Something went wrong with that request. Please try again.