Skip to content

Commit

Permalink
Move generation of magic doc metadata props from CBLDatabase to CBLRo…
Browse files Browse the repository at this point in the history
…uter

Moved CBLContentOptions and the code to add metadata properties like
"_revs", "_conflicts", etc. out of the CBL_Storage implementations and
into CBLRouter, since it's only needed by the REST API.
  • Loading branch information
snej committed Mar 25, 2015
1 parent c237c09 commit 503f000
Show file tree
Hide file tree
Showing 27 changed files with 392 additions and 269 deletions.
4 changes: 2 additions & 2 deletions Source/API/CBLDocument.m
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ - (CBLSavedRevision*) currentRevision {
CBLStatus status;
_currentRevision = [self revisionFromRev: [_database getDocumentWithID: _docID
revisionID: nil
options: 0
withBody: YES
status: &status]];
if (!CBLStatusIsError(status))
_currentRevisionKnown = YES;
Expand Down Expand Up @@ -157,7 +157,7 @@ - (CBLSavedRevision*) revisionWithID: (NSString*)revID {
return _currentRevision;
CBLStatus status;
return [self revisionFromRev: [_database getDocumentWithID: _docID revisionID: revID
options: 0
withBody: YES
status: &status]];
}

Expand Down
2 changes: 1 addition & 1 deletion Source/API/CBLRevision.m
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ - (CBLSavedRevision*) parentRevision {

- (bool) loadProperties {
CBLStatus status;
CBL_Revision* rev = [self.database revisionByLoadingBody: _rev options: 0 status: &status];
CBL_Revision* rev = [self.database revisionByLoadingBody: _rev status: &status];
if (!rev) {
Warn(@"Couldn't load body/sequence of %@: %d", self, status);
return false;
Expand Down
2 changes: 1 addition & 1 deletion Source/CBLDatabase+Attachments.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ typedef enum {
attachments (and removing "stub" and "follows".) GZip-encoded attachments will be unzipped
unless options contains the flag kCBLLeaveAttachmentsEncoded. */
- (BOOL) expandAttachmentsIn: (CBL_MutableRevision*)rev
options: (CBLContentOptions)options
decode: (BOOL)decodeAttachments
status: (CBLStatus*)outStatus;

/** Generates a MIME multipart writer for a revision, with separate body parts for each attachment whose "follows" property is set. */
Expand Down
9 changes: 4 additions & 5 deletions Source/CBLDatabase+Attachments.m
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ - (NSDictionary*) attachmentsForDocID: (NSString*)docID
CBL_MutableRevision* mrev = [[CBL_MutableRevision alloc] initWithDocID: docID
revID: revID
deleted: NO];
*outStatus = [self loadRevisionBody: mrev options: 0];
*outStatus = [self loadRevisionBody: mrev];
if (CBLStatusIsError(*outStatus))
return nil;
return mrev.attachments;
Expand Down Expand Up @@ -236,11 +236,10 @@ + (void) stubOutAttachmentsIn: (CBL_MutableRevision*)rev


- (BOOL) expandAttachmentsIn: (CBL_MutableRevision*)rev
options: (CBLContentOptions)options
decode: (BOOL)decodeAttachments
status: (CBLStatus*)outStatus
{
*outStatus = kCBLStatusOK;
BOOL decodeAttachments = !(options & kCBLLeaveAttachmentsEncoded);
[rev mutateAttachments: ^NSDictionary *(NSString *name, NSDictionary *attachment) {
BOOL decodeIt = decodeAttachments && (attachment[@"encoding"] != nil);
if (decodeIt || attachment[@"stub"] || attachment[@"follows"]) {
Expand Down Expand Up @@ -400,10 +399,10 @@ - (CBL_Revision*) updateAttachment: (NSString*)filename
deleted: NO];
if (oldRevID) {
// Load existing revision if this is a replacement:
*outStatus = [self loadRevisionBody: oldRev options: 0];
*outStatus = [self loadRevisionBody: oldRev];
if (CBLStatusIsError(*outStatus)) {
if (*outStatus == kCBLStatusNotFound
&& [self getDocumentWithID: docID revisionID: nil options: kCBLNoBody
&& [self getDocumentWithID: docID revisionID: nil withBody: NO
status: outStatus] != nil) {
*outStatus = kCBLStatusConflict; // if some other revision exists, it's a conflict
}
Expand Down
2 changes: 1 addition & 1 deletion Source/CBLDatabase+Insertion.m
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ - (instancetype) initWithDatabase: (CBLDatabase*)db

- (CBL_Revision*) current_Revision {
if (_currentRevision)
_currentRevision = [_db revisionByLoadingBody: _currentRevision options: 0 status: NULL];
_currentRevision = [_db revisionByLoadingBody: _currentRevision status: NULL];
return _currentRevision;
}

Expand Down
6 changes: 2 additions & 4 deletions Source/CBLDatabase+Internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,17 +103,15 @@ extern NSArray* CBL_RunloopModes;

- (CBL_Revision*) getDocumentWithID: (NSString*)docID
revisionID: (NSString*)revID
options: (CBLContentOptions)options
withBody: (BOOL)withBody
status: (CBLStatus*)outStatus;
#if DEBUG // convenience method for tests
- (CBL_Revision*) getDocumentWithID: (NSString*)docID
revisionID: (NSString*)revID;
#endif

- (CBLStatus) loadRevisionBody: (CBL_MutableRevision*)rev
options: (CBLContentOptions)options;
- (CBLStatus) loadRevisionBody: (CBL_MutableRevision*)rev;
- (CBL_Revision*) revisionByLoadingBody: (CBL_Revision*)rev
options: (CBLContentOptions)options
status: (CBLStatus*)outStatus;
- (SequenceNumber) getRevisionSequence: (CBL_Revision*)rev;

Expand Down
42 changes: 15 additions & 27 deletions Source/CBLDatabase+Internal.m
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
NSString* const CBL_PrivateRunloopMode = @"CouchbaseLitePrivate";
NSArray* CBL_RunloopModes;

const CBLChangesOptions kDefaultCBLChangesOptions = {UINT_MAX, 0, NO, NO, YES};
const CBLChangesOptions kDefaultCBLChangesOptions = {UINT_MAX, NO, NO, YES};

// When this many changes pile up in _changesToNotify, start removing their bodies to save RAM
#define kManyChangesToNotify 5000
Expand All @@ -51,9 +51,6 @@

@implementation CBLDatabase (Internal)

#define kLocalCheckpointDocId @"CBL_LocalCheckpoint"


+ (void) initialize {
if (self == [CBLDatabase class]) {
CBL_RunloopModes = @[NSRunLoopCommonModes, CBL_PrivateRunloopMode];
Expand Down Expand Up @@ -396,15 +393,11 @@ - (void) dbChanged: (NSNotification*)n {

- (CBL_Revision*) getDocumentWithID: (NSString*)docID
revisionID: (NSString*)inRevID
options: (CBLContentOptions)options
withBody: (BOOL)withBody
status: (CBLStatus*)outStatus
{
CBL_MutableRevision* rev = [_storage getDocumentWithID: docID revisionID: inRevID
options: options status: outStatus];
if (rev && (options & kCBLIncludeAttachments))
if (![self expandAttachmentsIn: rev options: options status: outStatus])
rev = nil;
return rev;
return [_storage getDocumentWithID: docID revisionID: inRevID
withBody: withBody status: outStatus];
}


Expand All @@ -413,42 +406,37 @@ - (CBL_Revision*) getDocumentWithID: (NSString*)docID
revisionID: (NSString*)revID
{
CBLStatus status;
return [self getDocumentWithID: docID revisionID: revID options: 0 status: &status];
return [self getDocumentWithID: docID revisionID: revID withBody: YES status: &status];
}
#endif


- (CBLStatus) loadRevisionBody: (CBL_MutableRevision*)rev
options: (CBLContentOptions)options
{
- (CBLStatus) loadRevisionBody: (CBL_MutableRevision*)rev {
// First check for no-op -- if we just need the default properties and already have them:
if (options==0 && rev.sequenceIfKnown) {
if (rev.sequenceIfKnown) {
NSDictionary* props = rev.properties;
if (props.cbl_rev && props.cbl_id)
return kCBLStatusOK;
}
Assert(rev.docID && rev.revID);

CBLStatus status = [_storage loadRevisionBody: rev options: options];

if (status == kCBLStatusOK)
if (options & kCBLIncludeAttachments)
[self expandAttachmentsIn: rev options: options status: &status];
return status;
return [_storage loadRevisionBody: rev];
}

- (CBL_Revision*) revisionByLoadingBody: (CBL_Revision*)rev
options: (CBLContentOptions)options
status: (CBLStatus*)outStatus
{
// First check for no-op -- if we just need the default properties and already have them:
if (options==0 && rev.sequenceIfKnown) {
if (rev.sequenceIfKnown) {
NSDictionary* props = rev.properties;
if (props.cbl_rev && props.cbl_id)
if (props.cbl_rev && props.cbl_id) {
if (outStatus)
*outStatus = kCBLStatusOK;
return rev;
}
}
CBL_MutableRevision* nuRev = rev.mutableCopy;
CBLStatus status = [self loadRevisionBody: nuRev options: options];
CBLStatus status = [self loadRevisionBody: nuRev];
if (outStatus)
*outStatus = status;
if (CBLStatusIsError(status))
Expand Down Expand Up @@ -513,7 +501,7 @@ - (id) getDesignDocFunction: (NSString*)fnName
CBLStatus status;
CBL_Revision* rev = [self getDocumentWithID: [@"_design/" stringByAppendingString: path[0]]
revisionID: nil
options: 0
withBody: YES
status: &status];
if (!rev)
return nil;
Expand Down
9 changes: 3 additions & 6 deletions Source/CBLForestBridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,17 @@ CBLStatus CBLStatusFromForestDBStatus(int fdbStatus);

@interface CBLForestBridge : NSObject

/** Gets the parsed body of a revision, including any metadata specified by the content options. */
+ (NSDictionary*) bodyOfNode: (const forestdb::Revision*)revNode
options: (CBLContentOptions)options;
+ (NSMutableDictionary*) bodyOfNode: (const forestdb::Revision*)revNode;

+ (CBL_MutableRevision*) revisionObjectFromForestDoc: (forestdb::VersionedDocument&)doc
revID: (NSString*)revID
options: (CBLContentOptions)options;
withBody: (BOOL)withBody;
+ (CBL_MutableRevision*) revisionObjectFromForestDoc: (forestdb::VersionedDocument&)doc
sequence: (forestdb::sequence)sequence
options: (CBLContentOptions)options;
withBody: (BOOL)withBody;

/** Stores the body of a revision (including metadata) into a CBL_MutableRevision. */
+ (BOOL) loadBodyOfRevisionObject: (CBL_MutableRevision*)rev
options: (CBLContentOptions)options
doc: (forestdb::VersionedDocument&)doc;

/** Returns the revIDs of all current leaf revisions, in descending order of priority. */
Expand Down
92 changes: 16 additions & 76 deletions Source/CBLForestBridge.mm
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ @implementation CBLForestBridge

+ (CBL_MutableRevision*) revisionObjectFromForestDoc: (VersionedDocument&)doc
revID: (NSString*)revID
options: (CBLContentOptions)options
withBody: (BOOL)withBody
{
CBL_MutableRevision* rev;
NSString* docID = (NSString*)doc.docID();
Expand All @@ -53,51 +53,43 @@ + (CBL_MutableRevision*) revisionObjectFromForestDoc: (VersionedDocument&)doc
deleted: doc.isDeleted()];
rev.sequence = doc.sequence();
}
if (![self loadBodyOfRevisionObject: rev options: options doc: doc])
if (withBody && ![self loadBodyOfRevisionObject: rev doc: doc])
return nil;
return rev;
}


+ (CBL_MutableRevision*) revisionObjectFromForestDoc: (VersionedDocument&)doc
sequence: (forestdb::sequence)sequence
options: (CBLContentOptions)options
withBody: (BOOL)withBody
{
const Revision* revNode = doc.getBySequence(sequence);
if (!revNode)
return nil;
CBL_MutableRevision* rev = [[CBL_MutableRevision alloc] initWithDocID: (NSString*)doc.docID()
revID: (NSString*)revNode->revID
deleted: revNode->isDeleted()];
if (![self loadBodyOfRevisionObject: rev options: options doc: doc])
if (withBody && ![self loadBodyOfRevisionObject: rev doc: doc])
return nil;
rev.sequence = sequence;
return rev;
}


+ (BOOL) loadBodyOfRevisionObject: (CBL_MutableRevision*)rev
options: (CBLContentOptions)options
doc: (VersionedDocument&)doc
{
// If caller wants no body and no metadata props, this is a no-op:
if (options == kCBLNoBody)
return YES;

const Revision* revNode = doc.get(rev.revID);
if (!revNode)
return NO;
NSData* json = nil;
if (!(options & kCBLNoBody)) {
json = dataOfNode(revNode);
if (!json)
return NO;
}
NSData* json = dataOfNode(revNode);
if (!json)
return NO;

rev.sequence = revNode->sequence;

NSMutableDictionary* extra = $mdict();
[self addContentProperties: options into: extra rev: revNode];
[self addContentPropertiesTo: extra fromRev: revNode];
if (json.length > 0)
rev.asJSON = [CBLJSON appendDictionary: extra toJSONDictionaryData: json];
else
Expand All @@ -106,80 +98,29 @@ + (BOOL) loadBodyOfRevisionObject: (CBL_MutableRevision*)rev
}


+ (NSDictionary*) bodyOfNode: (const Revision*)rev
options: (CBLContentOptions)options
{
// If caller wants no body and no metadata props, this is a no-op:
if (options == kCBLNoBody)
return @{};

NSData* json = nil;
if (!(options & kCBLNoBody)) {
json = dataOfNode(rev);
if (!json)
return nil;
}
+ (NSMutableDictionary*) bodyOfNode: (const Revision*)rev {
NSData* json = dataOfNode(rev);
if (!json)
return nil;
NSMutableDictionary* properties = [CBLJSON JSONObjectWithData: json
options: NSJSONReadingMutableContainers
error: NULL];
Assert(properties, @"Unable to parse doc from db: %@", json.my_UTF8ToString);
[self addContentProperties: options into: properties rev: rev];
[self addContentPropertiesTo: properties fromRev: rev];
return properties;
}


+ (void) addContentProperties: (CBLContentOptions)options
into: (NSMutableDictionary*)dst
rev: (const Revision*)rev
+ (void) addContentPropertiesTo: (NSMutableDictionary*)dst
fromRev: (const Revision*)rev
{
NSString* revID = (NSString*)rev->revID;
Assert(revID);
const VersionedDocument* doc = (const VersionedDocument*)rev->owner;
dst[@"_id"] = (NSString*)doc->docID();
dst[@"_rev"] = revID;

if (rev->isDeleted())
dst[@"_deleted"] = $true;

// Get more optional stuff to put in the properties:
if (options & kCBLIncludeLocalSeq)
dst[@"_local_seq"] = @(rev->sequence);

if (options & kCBLIncludeRevs)
dst[@"_revisions"] = [self getRevisionHistoryOfNode: rev startingFromAnyOf: nil];

if (options & kCBLIncludeRevsInfo) {
dst[@"_revs_info"] = [self mapHistoryOfNode: rev
through: ^id(const Revision *rev)
{
NSString* status = @"available";
if (rev->isDeleted())
status = @"deleted";
else if (!rev->isBodyAvailable())
status = @"missing";
return $dict({@"rev", (NSString*)rev->revID},
{@"status", status});
}];
}

if (options & kCBLIncludeConflicts) {
auto revs = doc->currentRevisions();
if (revs.size() > 1) {
NSMutableArray* conflicts = $marray();
for (auto rev = revs.begin(); rev != revs.end(); ++rev) {
if (!(*rev)->isDeleted()) {
NSString* revRevID = (NSString*)(*rev)->revID;
if (!$equal(revRevID, revID))
[conflicts addObject: revRevID];
}
}
if (conflicts.count > 0)
dst[@"_conflicts"] = conflicts;
}
}

if (!options & kCBLIncludeAttachments)
[dst removeObjectForKey: @"_attachments"];
}


Expand All @@ -203,8 +144,7 @@ + (NSArray*) mapHistoryOfNode: (const Revision*)rev
}


+ (NSArray*) getRevisionHistory: (const Revision*)revNode
{
+ (NSArray*) getRevisionHistory: (const Revision*)revNode {
const VersionedDocument* doc = (const VersionedDocument*)revNode->owner;
NSString* docID = (NSString*)doc->docID();
return [self mapHistoryOfNode: revNode
Expand Down
Loading

0 comments on commit 503f000

Please sign in to comment.