Skip to content
Browse files

Use CouchDesignDocument(Embedded) API in demos

Can now register TouchDB map/reduce/validation blocks using the
same CouchCocoa API as for Couchbase Mobile 2.
  • Loading branch information...
1 parent 8c6c5fd commit 9e846a80885ec3aa1840763b9294661f65b2d88a @snej snej committed Jan 5, 2012
View
65 Demo-Mac/DemoAppController.m
@@ -16,10 +16,17 @@
#import "DemoAppController.h"
#import "DemoQuery.h"
#import "Test.h"
-#import "TouchDB.h"
-#import <TouchDBListener/TDListener.h>
#import <CouchCocoa/CouchCocoa.h>
#import <CouchCocoa/CouchTouchDBServer.h>
+#import <CouchCocoa/CouchDesignDocument_Embedded.h>
+
+#define FOR_TESTING_PURPOSES
+#ifdef FOR_TESTING_PURPOSES
+#import <TouchDBListener/TDListener.h>
+@interface DemoAppController () <TDViewCompiler>
+@end
+static TDListener* sListener;
+#endif
#define kChangeGlowDuration 3.0
@@ -31,13 +38,6 @@ int main (int argc, const char * argv[]) {
}
-static TDListener* sListener;
-
-
-@interface DemoAppController () <TDViewCompiler>
-@end
-
-
@implementation DemoAppController
@@ -65,16 +65,15 @@ - (void) applicationDidFinishLaunching: (NSNotification*)n {
NSAssert(op.error.code == 412, @"Error creating db: %@", op.error);
}
- // Create a CouchDB 'view' containing list items sorted by date
- TDDatabase* tdb = [server.touchServer existingDatabaseNamed: dbName];
- NSAssert(tdb, @"Failed to open or create TouchDB database");
- [[tdb viewNamed: @"default/byDate"] setMapBlock: ^(NSDictionary* doc, TDMapEmitBlock emit) {
+ // Create a 'view' containing list items sorted by date:
+ CouchDesignDocument* design = [_database designDocumentWithName: @"default"];
+ [design defineViewNamed: @"byDate" mapBlock: MAPBLOCK({
id date = [doc objectForKey: @"created_at"];
if (date) emit(date, doc);
- } reduceBlock: NULL version: @"1"];
-
- // ...and a validation function requiring parseable dates:
- [tdb addValidation: ^(TDRevision* newRevision, id<TDValidationContext>context) {
+ }) version: @"1.0"];
+
+ // and a validation function requiring parseable dates:
+ design.validationBlock = VALIDATIONBLOCK({
if (newRevision.deleted)
return YES;
id date = [newRevision.properties objectForKey: @"created_at"];
@@ -83,31 +82,31 @@ - (void) applicationDidFinishLaunching: (NSNotification*)n {
return NO;
}
return YES;
- }];
+ });
// And why not a filter, just to allow some simple testing of filtered _changes.
- // For example, try curl -i 'http://localhost:8888/demo-shopping/_changes?filter=checked'
- [tdb defineFilter: @"checked" asBlock: ^BOOL(TDRevision *revision) {
+ // For example, try curl 'http://localhost:8888/demo-shopping/_changes?filter=default/checked'
+ [design defineFilterNamed: @"checked" block: FILTERBLOCK({
return [revision.properties objectForKey: @"check"] == $true;
- }];
+ })];
- CouchQuery* q = [[_database designDocumentWithName: @"default"] queryViewNamed: @"byDate"];
+ CouchQuery* q = [design queryViewNamed: @"byDate"];
q.descending = YES;
self.query = [[[DemoQuery alloc] initWithQuery: q] autorelease];
self.query.modelClass =_tableController.objectClass;
// Enable continuous sync:
[self startContinuousSyncWith: self.syncURL];
- [[NSNotificationCenter defaultCenter] addObserver: self
- selector: @selector(replicationProgressChanged:)
- name: TDReplicatorProgressChangedNotification
- object: nil];
+#ifdef FOR_TESTING_PURPOSES
// Start a listener socket:
- [TDView setCompiler: self];
sListener = [[TDListener alloc] initWithTDServer: server.touchServer port: 8888];
[sListener start];
+
+ // Register support for handling certain JS functions used in the CouchDB unit tests:
+ [TDView setCompiler: self];
+#endif
}
@@ -207,12 +206,12 @@ - (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
}
-- (void) replicationProgressChanged: (NSNotification*)n {
- // This is called on the TouchDB background thread, so redispatch to the main thread:
- [_database.server performSelectorOnMainThread: @selector(checkActiveTasks)
- withObject: nil waitUntilDone: NO];
-}
+#pragma mark - JS MAP/REDUCE FUNCTIONS:
+#ifdef FOR_TESTING_PURPOSES
+
+// These map/reduce functions are used in the CouchDB 'basics.js' unit tests. By recognizing them
+// here and returning equivalent native blocks, we can run those tests.
- (TDMapBlock) compileMapFunction: (NSString*)mapSource language:(NSString *)language {
if (!$equal(language, @"javascript"))
@@ -240,6 +239,8 @@ - (TDReduceBlock) compileReduceFunction: (NSString*)reduceSource language:(NSStr
return [[reduceBlock copy] autorelease];
}
+#endif
+
#pragma mark HIGHLIGHTING NEW ITEMS:
View
3 Demo-iOS/DemoAppDelegate.h
@@ -7,13 +7,12 @@
//
#import <UIKit/UIKit.h>
-@class CouchDatabase, TDDatabase;
+@class CouchDatabase;
@interface DemoAppDelegate : UIResponder <UIApplicationDelegate>
@property (nonatomic, strong) CouchDatabase *database;
-@property (nonatomic, strong) TDDatabase *touchDatabase;
@property (strong, nonatomic) IBOutlet UIWindow *window;
@property (nonatomic, strong) IBOutlet UINavigationController *navigationController;
View
6 Demo-iOS/DemoAppDelegate.m
@@ -15,15 +15,14 @@
#import "DemoAppDelegate.h"
#import "RootViewController.h"
-#import <TouchDB/TouchDB.h>
#import <CouchCocoa/CouchCocoa.h>
#import <CouchCocoa/CouchTouchDBServer.h>
@implementation DemoAppDelegate
-@synthesize window, navigationController, database, touchDatabase;
+@synthesize window, navigationController, database;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
@@ -49,9 +48,6 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
database.tracksChanges = YES;
NSLog(@"...Created CouchDatabase at <%@>", self.database.URL);
- self.touchDatabase = [server.touchServer existingDatabaseNamed: @"grocery-sync"];
- NSAssert(self.touchDatabase, @"Failed to open or create TouchDB database");
-
// Tell the RootViewController:
RootViewController* root = (RootViewController*)navigationController.topViewController;
[root useDatabase: database];
View
31 Demo-iOS/RootViewController.m
@@ -23,7 +23,7 @@
#import "DemoAppDelegate.h"
#import <CouchCocoa/CouchCocoa.h>
-#import <TouchDB/TouchDB.h>
+#import <CouchCocoa/CouchDesignDocument_Embedded.h>
@interface RootViewController ()
@@ -79,10 +79,6 @@ - (void)viewDidLoad {
self.dataSource.query = query;
self.dataSource.labelProperty = @"text"; // Document property to display in the cell label
- [[NSNotificationCenter defaultCenter] addObserver: self
- selector: @selector(replicationProgressChanged:)
- name: TDReplicatorProgressChangedNotification
- object: nil];
[self updateSyncURL];
}
@@ -102,17 +98,15 @@ - (void)viewWillAppear:(BOOL)animated {
- (void)useDatabase:(CouchDatabase*)theDatabase {
self.database = theDatabase;
- // Create a CouchDB 'view' containing list items sorted by date
- DemoAppDelegate* delegate = [[UIApplication sharedApplication] delegate];
- [[delegate.touchDatabase viewNamed: @"default/byDate"]
- setMapBlock: ^(NSDictionary* doc, TDMapEmitBlock emit) {
+ // Create a 'view' containing list items sorted by date:
+ CouchDesignDocument* design = [database designDocumentWithName: @"default"];
+ [design defineViewNamed: @"byDate" mapBlock: MAPBLOCK({
id date = [doc objectForKey: @"created_at"];
if (date) emit(date, doc);
- } reduceBlock: NULL version: @"1"];
-
- // ...and a validation function requiring parseable dates:
- [delegate.touchDatabase addValidation: ^(TDRevision* newRevision,
- id<TDValidationContext>context) {
+ }) version: @"1.0"];
+
+ // and a validation function requiring parseable dates:
+ design.validationBlock = VALIDATIONBLOCK({
if (newRevision.deleted)
return YES;
id date = [newRevision.properties objectForKey: @"created_at"];
@@ -121,7 +115,7 @@ - (void)useDatabase:(CouchDatabase*)theDatabase {
return NO;
}
return YES;
- }];
+ });
}
@@ -320,13 +314,6 @@ - (void) forgetSync {
}
-- (void) replicationProgressChanged: (NSNotification*)n {
- // This is called on the TouchDB background thread, so redispatch to the main thread:
- [database.server performSelectorOnMainThread: @selector(checkActiveTasks)
- withObject: nil waitUntilDone: NO];
-}
-
-
- (void)showSyncButton {
if (!showingSyncButton) {
showingSyncButton = YES;
View
15 Source/TDDatabase+Insertion.m
@@ -413,13 +413,15 @@ + (NSArray*) parseCouchDBRevisionHistory: (NSDictionary*)docProperties {
}
-- (void) addValidation:(TDValidationBlock)validationBlock {
+- (void) defineValidation: (NSString*)validationName asBlock: (TDValidationBlock)validationBlock {
Assert(validationBlock);
if (!_validations)
- _validations = [[NSMutableArray alloc] init];
- id copiedBlock = [validationBlock copy];
- [_validations addObject: copiedBlock];
- [copiedBlock release];
+ _validations = [[NSMutableDictionary alloc] init];
+ [_validations setValue: [[validationBlock copy] autorelease] forKey: validationName];
+}
+
+- (TDValidationBlock) validationNamed: (NSString*)validationName {
+ return [_validations objectForKey: validationName];
}
@@ -429,7 +431,8 @@ - (TDStatus) validateRevision: (TDRevision*)newRev previousRevision: (TDRevision
TDValidationContext* context = [[TDValidationContext alloc] initWithDatabase: self
revision: oldRev];
TDStatus status = 200;
- for (TDValidationBlock validation in _validations) {
+ for (TDValidationBlock validationName in _validations) {
+ TDValidationBlock validation = [self validationNamed: validationName];
if (!validation(newRev, context)) {
status = context.errorType;
break;
View
8 Source/TDDatabase.h
@@ -63,7 +63,7 @@ extern const TDChangesOptions kDefaultTDChangesOptions;
BOOL _open;
NSInteger _transactionLevel;
NSMutableDictionary* _views;
- NSMutableArray* _validations;
+ NSMutableDictionary* _validations;
NSMutableDictionary* _filters;
TDBlobStore* _attachments;
NSMutableArray* _activeReplicators;
@@ -124,7 +124,7 @@ extern const TDChangesOptions kDefaultTDChangesOptions;
options: (const TDChangesOptions*)options
filter: (TDFilterBlock)filter;
-/** Define a named filter function. These aren't used directly by TDDatabase, but they're looked up by TDRouter when a _changes request has a ?filter parameter. */
+/** Define or clear a named filter function. These aren't used directly by TDDatabase, but they're looked up by TDRouter when a _changes request has a ?filter parameter. */
- (void) defineFilter: (NSString*)filterName asBlock: (TDFilterBlock)filterBlock;
- (TDFilterBlock) filterNamed: (NSString*)filterName;
@@ -154,7 +154,9 @@ extern const TDChangesOptions kDefaultTDChangesOptions;
/** Parses the _revisions dict from a document into an array of revision ID strings */
+ (NSArray*) parseCouchDBRevisionHistory: (NSDictionary*)docProperties;
-- (void) addValidation: (TDValidationBlock)validationBlock;
+/** Define or clear a named document validation function. */
+- (void) defineValidation: (NSString*)validationName asBlock: (TDValidationBlock)validationBlock;
+- (TDValidationBlock) validationNamed: (NSString*)validationName;
@end
View
38 Source/TDDatabase.m
@@ -571,26 +571,28 @@ - (TDRevisionList*) changesSinceSequence: (SequenceNumber)lastSequence
TDRevisionList* changes = [[[TDRevisionList alloc] init] autorelease];
int64_t lastDocID = 0;
while ([r next]) {
- if (!options->includeConflicts) {
- // Only count the first rev for a given doc (the rest will be losing conflicts):
- int64_t docNumericID = [r longLongIntForColumnIndex: 1];
- if (docNumericID == lastDocID)
- continue;
- lastDocID = docNumericID;
- }
+ @autoreleasepool {
+ if (!options->includeConflicts) {
+ // Only count the first rev for a given doc (the rest will be losing conflicts):
+ int64_t docNumericID = [r longLongIntForColumnIndex: 1];
+ if (docNumericID == lastDocID)
+ continue;
+ lastDocID = docNumericID;
+ }
- TDRevision* rev = [[TDRevision alloc] initWithDocID: [r stringForColumnIndex: 2]
- revID: [r stringForColumnIndex: 3]
- deleted: [r boolForColumnIndex: 4]];
- rev.sequence = [r longLongIntForColumnIndex: 0];
- if (includeDocs) {
- [self expandStoredJSON: [r dataForColumnIndex: 5]
- intoRevision: rev
- options: options->contentOptions];
+ TDRevision* rev = [[TDRevision alloc] initWithDocID: [r stringForColumnIndex: 2]
+ revID: [r stringForColumnIndex: 3]
+ deleted: [r boolForColumnIndex: 4]];
+ rev.sequence = [r longLongIntForColumnIndex: 0];
+ if (includeDocs) {
+ [self expandStoredJSON: [r dataForColumnIndex: 5]
+ intoRevision: rev
+ options: options->contentOptions];
+ }
+ if (!filter || filter(rev))
+ [changes addRev: rev];
+ [rev release];
}
- if (!filter || filter(rev))
- [changes addRev: rev];
- [rev release];
}
[r close];
View
2 Source/TDView_Tests.m
@@ -366,7 +366,7 @@
if (name)
emit([name substringToIndex:1], [NSNumber numberWithInt:1]);
} reduceBlock:^id(NSArray *keys, NSArray *values, BOOL rereduce) {
- return [NSNumber numberWithInt:[values count]];
+ return [NSNumber numberWithUnsignedInteger:[values count]];
} version:@"1.0"];
TDQueryOptions options = kDefaultTDQueryOptions;

0 comments on commit 9e846a8

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