Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
J
jio
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Tristan Cavelier
jio
Commits
d7fcbbaf
Commit
d7fcbbaf
authored
Mar 01, 2013
by
Tristan Cavelier
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Revision storage redesigned to avoid some unknown errors
parent
049ea125
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
1555 additions
and
1469 deletions
+1555
-1469
src/jio.storage/replicaterevisionstorage.js
src/jio.storage/replicaterevisionstorage.js
+250
-0
src/jio.storage/revisionstorage.js
src/jio.storage/revisionstorage.js
+719
-1072
test/jiotests.js
test/jiotests.js
+586
-397
No files found.
src/jio.storage/replicaterevisionstorage.js
View file @
d7fcbbaf
...
@@ -187,6 +187,253 @@ jIO.addStorageType('replicaterevision', function (spec, my) {
...
@@ -187,6 +187,253 @@ jIO.addStorageType('replicaterevision', function (spec, my) {
}
}
};
};
////////////////////////////////////////////////////////////////////////////////
that
.
check
=
function
(
command
)
{
priv
.
check
(
command
.
cloneDoc
(),
command
.
cloneOption
(),
that
.
success
,
that
.
error
);
};
that
.
repair
=
function
(
command
)
{
priv
.
repair
(
command
.
cloneDoc
(),
command
.
cloneOption
(),
true
,
that
.
success
,
that
.
error
);
};
priv
.
check
=
function
(
doc
,
option
,
success
,
error
)
{
priv
.
repair
(
doc
,
option
,
false
,
success
,
error
);
};
priv
.
repair
=
function
(
doc
,
option
,
repair
,
callback
)
{
var
functions
=
{};
// console.log("priv.repair");
callback
=
callback
||
priv
.
emptyFunction
;
option
=
option
||
{};
functions
.
begin
=
function
()
{
// console.log("repair begin");
functions
.
getAllDocuments
(
functions
.
newParam
(
doc
,
option
,
repair
));
};
functions
.
newParam
=
function
(
doc
,
option
,
repair
)
{
// console.log("repair new param");
var
param
=
{
"
doc
"
:
doc
,
"
option
"
:
option
,
"
repair
"
:
repair
,
"
responses
"
:
{
"
count
"
:
0
,
"
list
"
:
[
// 0: response0
// 1: response1
// 2: response2
],
"
stats
"
:
{
// responseA: [0, 1]
// responseB: [2]
},
"
stats_items
"
:
[
// 0: [responseA, [0, 1]]
// 1: [responseB, [2]]
]
},
"
conflicts
"
:
{
// revC: true
// revD: true
},
"
deal_result_state
"
:
"
ok
"
,
"
my_rev
"
:
undefined
};
param
.
responses
.
list
.
length
=
priv
.
storage_list
.
length
;
return
param
;
};
functions
.
getAllDocuments
=
function
(
param
)
{
// console.log("repair getAllDocument");
var
i
,
doc
=
priv
.
clone
(
param
.
doc
),
option
=
priv
.
clone
(
param
.
option
);
option
.
conflicts
=
true
;
option
.
revs
=
true
;
option
.
revs_info
=
true
;
for
(
i
=
0
;
i
<
priv
.
storage_list
.
length
;
i
+=
1
)
{
// if the document is not loaded
priv
.
send
(
"
get
"
,
i
,
doc
,
option
,
functions
.
dealResults
(
param
));
}
functions
.
finished_count
+=
1
;
};
functions
.
dealResults
=
function
(
param
)
{
// console.log("repair dealResults");
return
function
(
method
,
index
,
err
,
response
)
{
if
(
param
.
deal_result_state
!==
"
ok
"
)
{
// deal result is in a wrong state, exit
// console.log("repair dealResults wrong state");
return
;
}
if
(
err
)
{
if
(
err
.
status
!==
404
)
{
// get document failed, exit
param
.
deal_result_state
=
"
error
"
;
// console.log("repair dealResults error");
callback
({
"
status
"
:
40
,
"
statusText
"
:
"
Check Failed
"
,
"
error
"
:
"
check_failed
"
,
"
message
"
:
"
An error occured on the sub storage
"
,
"
reason
"
:
err
.
reason
});
return
;
}
}
// success to get the document
// add the response in memory
param
.
responses
.
count
+=
1
;
param
.
responses
.
list
[
index
]
=
response
;
// add the conflicting revision for other synchronizations
functions
.
addConflicts
(
param
,
(
response
||
{}).
_conflicts
);
if
(
param
.
responses
.
count
!==
param
.
responses
.
list
.
length
)
{
// this is not the last response, wait for the next response
// console.log("repair dealResults not last");
return
;
}
// console.log("repair dealResults last");
// this is now the last response
functions
.
makeResponsesStats
(
param
.
responses
);
if
(
param
.
responses
.
stats_items
.
length
===
1
)
{
// the responses are equals!
// console.log("repair dealResults OK");
callback
(
undefined
,
{
"
ok
"
:
true
,
"
id
"
:
param
.
doc
.
_id
,
"
rev
"
:
(
typeof
param
.
responses
.
list
[
0
]
===
"
object
"
?
param
.
responses
.
list
[
0
].
_rev
:
undefined
)
});
return
;
}
// the responses are different
if
(
param
.
repair
===
false
)
{
// do not repair
callback
({
"
status
"
:
41
,
"
statusText
"
:
"
Check Not Ok
"
,
"
error
"
:
"
check_not_ok
"
,
"
message
"
:
"
Some documents are different in the sub storages
"
,
"
reason
"
:
"
Storage contents differ
"
});
return
;
}
// repair
functions
.
synchronizeAllSubStorage
(
param
);
if
(
param
.
option
.
synchronize_conflicts
!==
false
)
{
functions
.
synchronizeConflicts
(
param
);
}
};
};
functions
.
addConflicts
=
function
(
param
,
list
)
{
// console.log("repair addConflicts");
var
i
;
list
=
list
||
[];
for
(
i
=
0
;
i
<
list
.
length
;
i
+=
1
)
{
param
.
conflicts
[
list
[
i
]]
=
true
;
}
};
functions
.
makeResponsesStats
=
function
(
responses
)
{
// console.log("repair makeResponseStats");
var
i
,
str_response
;
for
(
i
=
0
;
i
<
responses
.
count
;
i
+=
1
)
{
str_response
=
JSON
.
stringify
(
responses
.
list
[
i
]);
if
(
responses
.
stats
[
str_response
]
===
undefined
)
{
responses
.
stats
[
str_response
]
=
[];
responses
.
stats_items
.
push
([
str_response
,
responses
.
stats
[
str_response
]
]);
}
responses
.
stats
[
str_response
].
push
(
i
);
}
};
functions
.
synchronizeAllSubStorage
=
function
(
param
)
{
// console.log("repair synchronizeAllSubStorage");
var
i
,
j
,
len
=
param
.
responses
.
stats_items
.
length
;
for
(
i
=
0
;
i
<
len
;
i
+=
1
)
{
// browsing responses
for
(
j
=
0
;
j
<
len
;
j
+=
1
)
{
// browsing storage list
if
(
i
!==
j
)
{
functions
.
synchronizeResponseToSubStorage
(
param
,
param
.
responses
.
stats_items
[
i
][
0
],
param
.
responses
.
stats_items
[
j
][
1
]
);
}
}
}
functions
.
finished_count
-=
1
;
};
functions
.
synchronizeResponseToSubStorage
=
function
(
param
,
response
,
storage_list
)
{
// console.log("repair synchronizeResponseToSubStorage");
var
i
,
new_doc
;
if
(
response
===
undefined
)
{
// no response to sync
return
;
}
for
(
i
=
0
;
i
<
storage_list
.
length
;
i
+=
1
)
{
new_doc
=
JSON
.
parse
(
response
);
new_doc
.
_revs
=
new_doc
.
_revisions
;
delete
new_doc
.
_rev
;
delete
new_doc
.
_revisions
;
delete
new_doc
.
_conflicts
;
functions
.
finished_count
+=
1
;
priv
.
send
(
"
put
"
,
storage_list
[
i
],
new_doc
,
param
.
option
,
functions
.
finished
);
}
};
functions
.
synchronizeConflicts
=
function
(
param
)
{
// console.log("repair synchronizeConflicts");
var
rev
,
new_doc
,
new_option
;
new_option
=
priv
.
clone
(
param
.
option
);
new_option
.
synchronize_conflict
=
false
;
for
(
rev
in
param
.
conflicts
)
{
if
(
param
.
conflicts
.
hasOwnProperty
(
rev
))
{
new_doc
=
priv
.
clone
(
param
.
doc
);
new_doc
.
_rev
=
rev
;
// no need to synchronize all the conflicts again, do it once
functions
.
getAllDocuments
(
functions
.
newParam
(
new_doc
,
new_option
,
param
.
repair
));
}
}
};
functions
.
finished_count
=
0
;
functions
.
finished
=
function
()
{
// console.log("repair finished " + functions.finished_count);
functions
.
finished_count
-=
1
;
if
(
functions
.
finished_count
===
0
)
{
// console.log("repair ended");
callback
(
undefined
,
{
"
ok
"
:
true
,
"
id
"
:
doc
.
_id
});
}
};
functions
.
begin
();
};
////////////////////////////////////////////////////////////////////////////////
/**
/**
* Post the document metadata to all sub storages
* Post the document metadata to all sub storages
* @method post
* @method post
...
@@ -397,6 +644,9 @@ jIO.addStorageType('replicaterevision', function (spec, my) {
...
@@ -397,6 +644,9 @@ jIO.addStorageType('replicaterevision', function (spec, my) {
}
}
}
}
that
.
success
(
response
);
that
.
success
(
response
);
setTimeout
(
function
()
{
priv
.
repair
({
"
_id
"
:
doc
.
_id
},
command
.
cloneOption
(),
true
);
});
};
};
functions
.
error_count
=
0
;
functions
.
error_count
=
0
;
functions
.
error
=
function
(
err
)
{
functions
.
error
=
function
(
err
)
{
...
...
src/jio.storage/revisionstorage.js
View file @
d7fcbbaf
...
@@ -9,20 +9,31 @@
...
@@ -9,20 +9,31 @@
* "sub_storage": <sub storage description>
* "sub_storage": <sub storage description>
* }
* }
*/
*/
jIO
.
addStorageType
(
'
revision
'
,
function
(
spec
,
my
)
{
jIO
.
addStorageType
(
"
revision
"
,
function
(
spec
,
my
)
{
"
use strict
"
;
"
use strict
"
;
var
that
,
priv
=
{};
var
that
=
{}
,
priv
=
{};
spec
=
spec
||
{};
spec
=
spec
||
{};
that
=
my
.
basicStorage
(
spec
,
my
);
that
=
my
.
basicStorage
(
spec
,
my
);
// ATTRIBUTES //
priv
.
doc_tree_suffix
=
"
.revision_tree.json
"
;
priv
.
sub_storage
=
spec
.
sub_storage
;
// METHODS //
/**
* Constructor
*/
priv
.
RevisionStorage
=
function
()
{
// no init
};
priv
.
substorage_key
=
"
sub_storage
"
;
/**
priv
.
doctree_suffix
=
"
.revision_tree.json
"
;
* Description to store in order to be restored later
priv
.
substorage
=
spec
[
priv
.
substorage_key
];
* @method specToStore
* @return {object} Descriptions to store
*/
that
.
specToStore
=
function
()
{
that
.
specToStore
=
function
()
{
var
o
=
{};
return
{
o
[
priv
.
substorage_key
]
=
priv
.
substorage
;
"
sub_storage
"
:
priv
.
sub_storage
return
o
;
}
;
};
};
/**
/**
...
@@ -70,1200 +81,836 @@ jIO.addStorageType('revision', function (spec, my) {
...
@@ -70,1200 +81,836 @@ jIO.addStorageType('revision', function (spec, my) {
};
};
/**
/**
*
Returns an array version of a revision string
*
Checks a revision format
* @method
revisionToArray
* @method
checkDocumentRevisionFormat
* @param {
string} revision The revision string
* @param {
object} doc The document object
* @return {
array} Array containing a revision number and a hash
* @return {
object} null if ok, else error object
*/
*/
priv
.
revisionToArray
=
function
(
revision
)
{
priv
.
checkDocumentRevisionFormat
=
function
(
doc
)
{
if
(
typeof
revision
===
"
string
"
)
{
var
send_error
=
function
(
message
)
{
return
[
parseInt
(
revision
.
split
(
'
-
'
)[
0
],
10
),
return
{
revision
.
split
(
'
-
'
)[
1
]];
"
status
"
:
31
,
"
statusText
"
:
"
Wrong Revision Format
"
,
"
error
"
:
"
wrong_revision_format
"
,
"
message
"
:
message
,
"
reason
"
:
"
Revision is wrong
"
};
};
if
(
typeof
doc
.
_rev
===
"
string
"
)
{
if
(
/^
[
0-9
]
+-
[
0-9a-zA-Z
]
+$/
.
test
(
doc
.
_rev
)
===
false
)
{
return
send_error
(
"
The document revision does not match
"
+
"
^[0-9]+-[0-9a-zA-Z]+$
"
);
}
}
if
(
typeof
doc
.
_revs
===
"
object
"
)
{
if
(
typeof
doc
.
_revs
.
start
!==
"
number
"
||
typeof
doc
.
_revs
.
ids
!==
"
object
"
||
typeof
doc
.
_revs
.
ids
.
length
!==
"
number
"
)
{
return
send_error
(
"
The document revision history is not well formated
"
);
}
}
if
(
typeof
doc
.
_revs_info
===
"
object
"
)
{
if
(
typeof
doc
.
_revs_info
.
length
!==
"
number
"
)
{
return
send_error
(
"
The document revision information
"
+
"
is not well formated
"
);
}
}
}
return
revision
;
};
};
/**
/**
* Convert the revision history object to an array of revisions.
* Creates a new document tree
* @method revisionHistoryToArray
* @method newDocTree
* @param {object} revs The revision history
* @return {object} The new document tree
* @return {array} The revision array
*/
*/
priv
.
revisionHistoryToArray
=
function
(
revs
)
{
priv
.
newDocTree
=
function
()
{
var
i
,
start
=
revs
.
start
,
newlist
=
[];
return
{
"
children
"
:
[]};
for
(
i
=
0
;
i
<
revs
.
ids
.
length
;
i
+=
1
,
start
-=
1
)
{
newlist
.
push
(
start
+
"
-
"
+
revs
.
ids
[
i
]);
}
return
newlist
;
};
};
/**
/**
* Generates the next revision of [previous_revision]. [string] helps us
* Convert revs_info to a simple revisions history
* to generate a hash code.
* @method revsInfoToHistory
* @methode generateNextRev
* @param {array} revs_info The revs info
* @param {string} previous_revision The previous revision
* @return {object} The revisions history
* @param {object} doc The document metadata
* @param {object} revisions The revision history
* @param {boolean} deleted_flag The deleted flag
* @return {array} 0:The next revision number and 1:the hash code
*/
*/
priv
.
generateNextRevision
=
function
(
previous_revision
,
priv
.
revsInfoToHistory
=
function
(
revs_info
)
{
doc
,
revisions
,
deleted_flag
)
{
var
i
,
revisions
=
{
var
string
=
JSON
.
stringify
(
doc
)
+
JSON
.
stringify
(
revisions
)
+
"
start
"
:
0
,
JSON
.
stringify
(
deleted_flag
?
true
:
false
);
"
ids
"
:
[]
if
(
typeof
previous_revision
===
"
number
"
)
{
};
return
[
previous_revision
+
1
,
priv
.
hashCode
(
string
)];
revs_info
=
revs_info
||
[];
if
(
revs_info
.
length
>
0
)
{
revisions
.
start
=
parseInt
(
revs_info
[
0
].
rev
.
split
(
'
-
'
)[
0
],
10
);
}
for
(
i
=
0
;
i
<
revs_info
.
length
;
i
+=
1
)
{
revisions
.
ids
.
push
(
revs_info
[
i
].
rev
.
split
(
'
-
'
)[
1
]);
}
}
previous_revision
=
priv
.
revisionToArray
(
previous_revision
);
return
revisions
;
return
[
previous_revision
[
0
]
+
1
,
priv
.
hashCode
(
string
)];
};
};
/**
/**
* C
hecks a revision format
* C
onvert the revision history object to an array of revisions.
* @method
checkRevisionForma
t
* @method
revisionHistoryToLis
t
* @param {
string} revision The revision string
* @param {
object} revs The revision history
* @return {
boolean} True if ok, else false
* @return {
array} The revision array
*/
*/
priv
.
checkRevisionFormat
=
function
(
revision
)
{
priv
.
revisionHistoryToList
=
function
(
revs
)
{
return
(
/^
[
0-9
]
+-
[
0-9a-zA-Z
]
+$/
.
test
(
revision
));
var
i
,
start
=
revs
.
start
,
new_list
=
[];
for
(
i
=
0
;
i
<
revs
.
ids
.
length
;
i
+=
1
,
start
-=
1
)
{
new_list
.
push
(
start
+
"
-
"
+
revs
.
ids
[
i
]);
}
return
new_list
;
};
};
/**
/**
* Creates an empty document tree
* Convert revision list to revs info.
* @method createDocumentTree
* @method revisionListToRevsInfo
* @param {array} children An array of children (optional)
* @param {array} revision_list The revision list
* @return {object} The new document tree
* @param {object} doc_tree The document tree
* @return {array} The document revs info
*/
*/
priv
.
createDocumentTree
=
function
(
children
)
{
priv
.
revisionListToRevsInfo
=
function
(
revision_list
,
doc_tree
)
{
return
{
var
revisionListToRevsInfoRec
,
revs_info
=
[],
j
;
"
children
"
:
children
||
[]
for
(
j
=
0
;
j
<
revision_list
.
length
;
j
+=
1
)
{
revs_info
.
push
({
"
rev
"
:
revision_list
[
j
],
"
status
"
:
"
missing
"
});
}
revisionListToRevsInfoRec
=
function
(
index
,
doc_tree
)
{
var
child
,
i
;
if
(
index
<
0
)
{
return
;
}
for
(
i
=
0
;
i
<
doc_tree
.
children
.
length
;
i
+=
1
)
{
child
=
doc_tree
.
children
[
i
];
if
(
child
.
rev
===
revision_list
[
index
])
{
revs_info
[
index
].
status
=
child
.
status
;
revisionListToRevsInfoRec
(
index
-
1
,
child
);
}
}
};
};
revisionListToRevsInfoRec
(
revision_list
.
length
-
1
,
doc_tree
);
return
revs_info
;
};
};
/**
/**
* Creates a new document tree node
* Update a document metadata revision properties
* @method createDocumentTreeNode
* @method fillDocumentRevisionProperties
* @param {string} revision The node revision
* @param {object} doc The document object
* @param {string} status The node status
* @param {object} doc_tree The document tree
* @param {array} children An array of children (optional)
* @return {object} The new document tree node
*/
*/
priv
.
createDocumentTreeNode
=
function
(
revision
,
status
,
children
)
{
priv
.
fillDocumentRevisionProperties
=
function
(
doc
,
doc_tree
)
{
return
{
if
(
doc
.
_revs_info
)
{
"
rev
"
:
revision
,
doc
.
_revs
=
priv
.
revsInfoToHistory
(
doc
.
_revs_info
);
"
status
"
:
status
,
}
else
if
(
doc
.
_revs
)
{
"
children
"
:
children
||
[]
doc
.
_revs_info
=
priv
.
revisionListToRevsInfo
(
};
priv
.
revisionHistoryToList
(
doc
.
_revs
),
doc_tree
);
}
else
if
(
doc
.
_rev
)
{
doc
.
_revs_info
=
priv
.
getRevisionInfo
(
doc
.
_rev
,
doc_tree
);
doc
.
_revs
=
priv
.
revsInfoToHistory
(
doc
.
_revs_info
);
}
else
{
doc
.
_revs_info
=
[];
doc
.
_revs
=
{
"
start
"
:
0
,
"
ids
"
:
[]};
}
if
(
doc
.
_revs
.
start
>
0
)
{
doc
.
_rev
=
doc
.
_revs
.
start
+
"
-
"
+
doc
.
_revs
.
ids
[
0
];
}
else
{
delete
doc
.
_rev
;
}
};
};
/**
/**
* Ge
ts the specific revision from a document tree
.
* Ge
nerates the next revision of a document
.
* @method
getRevisionFromDocumentTree
* @method
e generateNextRevision
* @param {object} doc
ument_tree The document tree
* @param {object} doc
The document metadata
* @param {
string} revision The specific revision
* @param {
boolean} deleted_flag The deleted flag
* @return {array}
The good revs info array
* @return {array}
0:The next revision number and 1:the hash code
*/
*/
priv
.
getRevisionFromDocumentTree
=
function
(
document_tree
,
revision
)
{
priv
.
generateNextRevision
=
function
(
doc
,
deleted_flag
)
{
var
result
,
search
,
revs_info
=
[];
var
string
,
revision_history
,
revs_info
,
pseudo_revision
;
result
=
[];
doc
=
priv
.
clone
(
doc
)
||
{};
// search method fills "result" with the good revs info
revision_history
=
doc
.
_revs
;
search
=
function
(
document_tree
)
{
revs_info
=
doc
.
_revs_info
;
var
i
;
delete
doc
.
_rev
;
if
(
document_tree
.
rev
!==
undefined
)
{
delete
doc
.
_revs
;
// node is not root
delete
doc
.
_revs_info
;
revs_info
.
unshift
({
string
=
JSON
.
stringify
(
doc
)
+
JSON
.
stringify
(
revision_history
)
+
"
rev
"
:
document_tree
.
rev
,
JSON
.
stringify
(
deleted_flag
?
true
:
false
);
"
status
"
:
document_tree
.
status
console
.
log
(
string
);
});
revision_history
.
start
+=
1
;
if
(
document_tree
.
rev
===
revision
)
{
revision_history
.
ids
.
unshift
(
priv
.
hashCode
(
string
));
result
=
revs_info
;
doc
.
_revs
=
revision_history
;
return
;
doc
.
_rev
=
revision_history
.
start
+
"
-
"
+
revision_history
.
ids
[
0
];
revs_info
.
unshift
({
"
rev
"
:
doc
.
_rev
,
"
status
"
:
deleted_flag
?
"
deleted
"
:
"
available
"
});
doc
.
_revs_info
=
revs_info
;
return
doc
;
};
/**
* Gets the revs info from the document tree
* @method getRevisionInfo
* @param {string} revision The revision to search for
* @param {object} doc_tree The document tree
* @return {array} The revs info
*/
priv
.
getRevisionInfo
=
function
(
revision
,
doc_tree
)
{
var
getRevisionInfoRec
;
getRevisionInfoRec
=
function
(
doc_tree
)
{
var
i
,
child
,
revs_info
;
for
(
i
=
0
;
i
<
doc_tree
.
children
.
length
;
i
+=
1
)
{
child
=
doc_tree
.
children
[
i
];
if
(
child
.
rev
===
revision
)
{
return
[{
"
rev
"
:
child
.
rev
,
"
status
"
:
child
.
status
}];
}
}
}
revs_info
=
getRevisionInfoRec
(
child
);
// This node has children
if
(
revs_info
.
length
>
0
||
revision
===
undefined
)
{
for
(
i
=
0
;
i
<
document_tree
.
children
.
length
;
i
+=
1
)
{
revs_info
.
push
({
"
rev
"
:
child
.
rev
,
"
status
"
:
child
.
status
});
// searching deeper to find the good rev
return
revs_info
;
search
(
document_tree
.
children
[
i
]);
if
(
result
.
length
>
0
)
{
// The result is already found
return
;
}
}
revs_info
.
shift
();
}
}
return
[];
};
};
search
(
document_tree
);
return
getRevisionInfoRec
(
doc_tree
);
return
result
;
};
};
/**
priv
.
updateDocumentTree
=
function
(
doc
,
doc_tree
)
{
* Gets the winner revision from a document tree.
var
revs_info
,
updateDocumentTreeRec
,
next_rev
;
* The winner is the deeper revision on the left.
doc
=
priv
.
clone
(
doc
);
* @method getWinnerRevisionFromDocumentTree
revs_info
=
doc
.
_revs_info
;
* @param {object} document_tree The document tree
updateDocumentTreeRec
=
function
(
doc_tree
,
revs_info
)
{
* @return {array} The winner revs info array
var
i
,
child
,
info
;
*/
if
(
revs_info
.
length
===
0
)
{
priv
.
getWinnerRevisionFromDocumentTree
=
function
(
document_tree
)
{
var
result
,
search
,
revs_info
=
[];
result
=
[];
// search method fills "result" with the winner revs info
search
=
function
(
document_tree
,
deep
)
{
var
i
;
if
(
document_tree
.
rev
!==
undefined
)
{
// node is not root
revs_info
.
unshift
({
"
rev
"
:
document_tree
.
rev
,
"
status
"
:
document_tree
.
status
});
}
if
(
document_tree
.
children
.
length
===
0
&&
document_tree
.
status
!==
"
deleted
"
)
{
// This node is a leaf
if
(
result
.
length
<
deep
)
{
// The leaf is deeper than result
result
=
[];
for
(
i
=
0
;
i
<
revs_info
.
length
;
i
+=
1
)
{
result
.
push
(
revs_info
[
i
]);
}
}
return
;
return
;
}
}
// This node has children
info
=
revs_info
.
pop
();
for
(
i
=
0
;
i
<
document_tree
.
children
.
length
;
i
+=
1
)
{
for
(
i
=
0
;
i
<
doc_tree
.
children
.
length
;
i
+=
1
)
{
// searching deeper to find the deeper leaf
child
=
doc_tree
.
children
[
i
];
search
(
document_tree
.
children
[
i
],
deep
+
1
);
if
(
child
.
rev
===
info
.
rev
)
{
revs_info
.
shift
();
return
updateDocumentTreeRec
(
child
,
revs_info
);
}
}
}
doc_tree
.
children
.
unshift
({
"
rev
"
:
info
.
rev
,
"
status
"
:
info
.
status
,
"
children
"
:
[]
});
updateDocumentTreeRec
(
doc_tree
.
children
[
0
],
revs_info
);
};
};
search
(
document_tree
,
0
);
updateDocumentTreeRec
(
doc_tree
,
priv
.
clone
(
revs_info
));
return
result
;
};
};
/**
priv
.
send
=
function
(
method
,
doc
,
option
,
callback
)
{
* Add a document revision branch to the document tree
that
.
addJob
(
* @method updateDocumentTree
method
,
* @param {object} doctree The document tree object
priv
.
sub_storage
,
* @param {object|array} revs The revision history object or a revision array
doc
,
* @param {boolean} deleted The deleted flag
option
,
* @param {array} The document revs_info
function
(
success
)
{
*/
callback
(
undefined
,
success
);
priv
.
updateDocumentTree
=
function
(
doctree
,
revs
,
deleted
)
{
},
var
revs_info
,
doctree_iterator
,
flag
,
i
,
rev
;
function
(
err
)
{
revs_info
=
[];
callback
(
err
,
undefined
);
if
(
revs
.
ids
)
{
// revs is a revision history object
revs
=
priv
.
revisionHistoryToArray
(
revs
);
}
else
{
// revs is an array of revisions
revs
=
priv
.
clone
(
revs
);
}
doctree_iterator
=
doctree
;
while
(
revs
.
length
>
0
)
{
rev
=
revs
.
pop
(
0
);
revs_info
.
unshift
({
"
rev
"
:
rev
,
"
status
"
:
"
missing
"
});
for
(
i
=
0
;
i
<
doctree_iterator
.
children
.
length
;
i
+=
1
)
{
if
(
doctree_iterator
.
children
[
i
].
rev
===
rev
)
{
doctree_iterator
=
doctree_iterator
.
children
[
i
];
revs_info
[
0
].
status
=
doctree_iterator
.
status
;
rev
=
undefined
;
break
;
}
}
if
(
rev
)
{
doctree_iterator
.
children
.
unshift
({
"
rev
"
:
rev
,
"
status
"
:
"
missing
"
,
"
children
"
:
[]
});
doctree_iterator
=
doctree_iterator
.
children
[
0
];
}
}
}
);
flag
=
deleted
===
true
?
"
deleted
"
:
"
available
"
;
revs_info
[
0
].
status
=
flag
;
doctree_iterator
.
status
=
flag
;
return
revs_info
;
};
};
/**
priv
.
getWinnerRevsInfo
=
function
(
doc_tree
)
{
* Add a document revision to the document tree
var
revs_info
=
[],
getWinnerRevsInfoRec
;
* @method postToDocumentTree
getWinnerRevsInfoRec
=
function
(
doc_tree
,
tmp_revs_info
)
{
* @param {object} doctree The document tree object
* @param {object} doc The document object
* @param {boolean} set_node_to_deleted Set the revision to deleted
* @return {array} The added document revs_info
*/
priv
.
postToDocumentTree
=
function
(
doctree
,
doc
,
set_node_to_deleted
)
{
var
i
,
revs_info
,
next_rev
,
next_rev_str
,
selectNode
,
selected_node
,
flag
;
flag
=
set_node_to_deleted
===
true
?
"
deleted
"
:
"
available
"
;
revs_info
=
[];
selected_node
=
doctree
;
selectNode
=
function
(
node
)
{
var
i
;
var
i
;
if
(
node
.
rev
!==
undefined
)
{
if
(
doc_tree
.
rev
)
{
// node is not root
tmp_revs_info
.
unshift
({
"
rev
"
:
doc_tree
.
rev
,
"
status
"
:
doc_tree
.
status
});
revs_info
.
unshift
({
"
rev
"
:
node
.
rev
,
"
status
"
:
node
.
status
});
}
if
(
node
.
rev
===
doc
.
_rev
)
{
selected_node
=
node
;
return
"
node_selected
"
;
}
}
for
(
i
=
0
;
i
<
node
.
children
.
length
;
i
+=
1
)
{
if
(
doc_tree
.
children
.
length
===
0
)
{
if
(
selectNode
(
node
.
children
[
i
])
===
"
node_selected
"
)
{
if
(
revs_info
.
length
<
tmp_revs_info
.
length
||
return
"
node_selected
"
;
(
revs_info
.
length
>
0
&&
revs_info
[
0
].
status
===
"
deleted
"
))
{
revs_info
=
priv
.
clone
(
tmp_revs_info
);
}
}
revs_info
.
shift
();
}
};
if
(
typeof
doc
.
_rev
===
"
string
"
)
{
// document has a previous revision
if
(
selectNode
(
selected_node
)
!==
"
node_selected
"
)
{
// no node was selected, so add a node with a specific rev
revs_info
.
unshift
({
"
rev
"
:
doc
.
_rev
,
"
status
"
:
"
missing
"
});
selected_node
.
children
.
unshift
(
priv
.
createDocumentTreeNode
(
doc
.
_rev
,
"
missing
"
));
selected_node
=
selected_node
.
children
[
0
];
}
}
}
for
(
i
=
0
;
i
<
doc_tree
.
children
.
length
;
i
+=
1
)
{
next_rev
=
priv
.
generateNextRevision
(
getWinnerRevsInfoRec
(
doc_tree
.
children
[
i
],
tmp_revs_info
);
doc
.
_rev
||
0
,
doc
,
priv
.
revsInfoToHistory
(
revs_info
),
set_node_to_deleted
);
next_rev_str
=
next_rev
.
join
(
"
-
"
);
// don't add if the next rev already exists
for
(
i
=
0
;
i
<
selected_node
.
children
.
length
;
i
+=
1
)
{
if
(
selected_node
.
children
[
i
].
rev
===
next_rev_str
)
{
revs_info
.
unshift
({
"
rev
"
:
next_rev_str
,
"
status
"
:
flag
});
if
(
selected_node
.
children
[
i
].
status
!==
flag
)
{
selected_node
.
children
[
i
].
status
=
flag
;
}
return
revs_info
;
}
}
}
tmp_revs_info
.
shift
();
revs_info
.
unshift
({
};
"
rev
"
:
next_rev
.
join
(
'
-
'
),
getWinnerRevsInfoRec
(
doc_tree
,
[]);
"
status
"
:
flag
});
selected_node
.
children
.
unshift
(
priv
.
createDocumentTreeNode
(
next_rev
.
join
(
'
-
'
),
flag
));
return
revs_info
;
return
revs_info
;
};
};
/**
priv
.
getConflicts
=
function
(
revision
,
doc_tree
)
{
* Gets an array of leaves revisions from document tree
var
conflicts
=
[],
getConflictsRec
;
* @method getLeavesFromDocumentTree
getConflictsRec
=
function
(
doc_tree
)
{
* @param {object} document_tree The document tree
* @param {string} except The revision to except
* @return {array} The array of leaves revisions
*/
priv
.
getLeavesFromDocumentTree
=
function
(
document_tree
,
except
)
{
var
result
,
search
;
result
=
[];
// search method fills [result] with the winner revision
search
=
function
(
document_tree
)
{
var
i
;
var
i
;
if
(
except
!==
undefined
&&
except
===
document_tree
.
rev
)
{
if
(
doc_tree
.
rev
===
revision
)
{
return
;
return
;
}
}
if
(
document_tree
.
children
.
length
===
0
&&
document_tree
.
status
!==
if
(
doc_tree
.
children
.
length
===
0
)
{
"
deleted
"
)
{
if
(
doc_tree
.
status
!==
"
deleted
"
)
{
// This node is a leaf
conflicts
.
push
(
doc_tree
.
rev
);
result
.
push
(
document_tree
.
rev
);
}
return
;
}
}
// This node has children
for
(
i
=
0
;
i
<
doc_tree
.
children
.
length
;
i
+=
1
)
{
for
(
i
=
0
;
i
<
document_tree
.
children
.
length
;
i
+=
1
)
{
getConflictsRec
(
doc_tree
.
children
[
i
]);
// searching deeper to find the deeper leaf
search
(
document_tree
.
children
[
i
]);
}
}
};
};
search
(
document
_tree
);
getConflictsRec
(
doc
_tree
);
return
result
;
return
conflicts
.
length
===
0
?
undefined
:
conflicts
;
};
};
/**
priv
.
get
=
function
(
doc
,
option
,
callback
)
{
* Check if revision is a leaf
priv
.
send
(
"
get
"
,
doc
,
option
,
callback
);
* @method isRevisionALeaf
};
* @param {string} revision revision to check
priv
.
put
=
function
(
doc
,
option
,
callback
)
{
* @param {array} leaves all leaves on tree
console
.
log
(
doc
);
* @return {boolean} true/false
priv
.
send
(
"
put
"
,
doc
,
option
,
callback
);
*/
};
priv
.
isRevisionALeaf
=
function
(
document_tree
,
revision
)
{
priv
.
remove
=
function
(
doc
,
option
,
callback
)
{
var
result
,
search
;
priv
.
send
(
"
remove
"
,
doc
,
option
,
callback
);
result
=
undefined
;
};
// search method fills "result" with the good revs info
priv
.
putAttachment
=
function
(
attachment
,
option
,
callback
)
{
search
=
function
(
document_tree
)
{
priv
.
send
(
"
putAttachment
"
,
attachment
,
option
,
callback
);
var
i
;
};
if
(
document_tree
.
rev
!==
undefined
)
{
// node is not root
priv
.
getDocument
=
function
(
doc
,
option
,
callback
)
{
if
(
document_tree
.
rev
===
revision
)
{
doc
=
priv
.
clone
(
doc
);
if
(
document_tree
.
children
.
length
===
0
)
{
doc
.
_id
=
doc
.
_id
+
"
.
"
+
doc
.
_rev
;
// This node is a leaf
delete
doc
.
_attachment
;
result
=
true
;
delete
doc
.
_rev
;
return
;
delete
doc
.
_revs
;
}
delete
doc
.
_revs_info
;
result
=
false
;
priv
.
get
(
doc
,
option
,
callback
);
};
priv
.
getAttachment
=
priv
.
get
;
priv
.
putDocument
=
function
(
doc
,
option
,
callback
)
{
doc
=
priv
.
clone
(
doc
);
doc
.
_id
=
doc
.
_id
+
"
.
"
+
doc
.
_rev
;
delete
doc
.
_attachment
;
delete
doc
.
_data
;
delete
doc
.
_mimetype
;
delete
doc
.
_rev
;
delete
doc
.
_revs
;
delete
doc
.
_revs_info
;
priv
.
put
(
doc
,
option
,
callback
);
};
priv
.
getRevisionTree
=
function
(
doc
,
option
,
callback
)
{
doc
=
priv
.
clone
(
doc
);
doc
.
_id
=
doc
.
_id
+
priv
.
doc_tree_suffix
;
priv
.
get
(
doc
,
option
,
callback
);
};
priv
.
getAttachmentList
=
function
(
doc
,
option
,
callback
)
{
console
.
log
(
"
p getAttachmentList
"
);
var
attachment_id
,
dealResults
,
state
=
"
ok
"
,
result_list
=
[],
count
=
0
;
dealResults
=
function
(
attachment_id
,
attachment_meta
)
{
return
function
(
err
,
attachment
)
{
if
(
state
!==
"
ok
"
)
{
return
;
return
;
}
}
}
count
-=
1
;
// This node has children
if
(
err
)
{
for
(
i
=
0
;
i
<
document_tree
.
children
.
length
;
i
+=
1
)
{
if
(
err
.
status
===
404
)
{
// searching deeper to find the good rev
result_list
.
push
(
undefined
);
search
(
document_tree
.
children
[
i
]);
}
else
{
if
(
result
!==
undefined
)
{
state
=
"
error
"
;
// The result is already found
return
callback
(
err
,
undefined
);
return
;
}
}
}
}
result_list
.
push
({
"
_attachment
"
:
attachment_id
,
"
_data
"
:
attachment
,
"
_mimetype
"
:
attachment_meta
.
content_type
});
if
(
count
===
0
)
{
state
=
"
finished
"
;
callback
(
undefined
,
result_list
);
}
};
};
};
search
(
document_tree
);
for
(
attachment_id
in
doc
.
_attachments
)
{
return
result
||
false
;
if
(
doc
.
_attachments
.
hasOwnProperty
(
attachment_id
))
{
};
count
+=
1
;
priv
.
get
(
/**
{
"
_id
"
:
doc
.
_id
+
"
/
"
+
attachment_id
},
* Convert revs_info to a simple revisions history
option
,
* @method revsInfoToHistory
dealResults
(
attachment_id
,
doc
.
_attachments
[
attachment_id
])
* @param {array} revs_info The revs info
);
* @return {object} The revisions history
}
*/
priv
.
revsInfoToHistory
=
function
(
revs_info
)
{
var
revisions
=
{
"
start
"
:
0
,
"
ids
"
:
[]
},
i
;
if
(
revs_info
.
length
>
0
)
{
revisions
.
start
=
parseInt
(
revs_info
[
0
].
rev
.
split
(
'
-
'
)[
0
],
10
);
}
}
for
(
i
=
0
;
i
<
revs_info
.
length
;
i
+=
1
)
{
if
(
count
===
0
)
{
revisions
.
ids
.
push
(
revs_info
[
i
].
rev
.
split
(
'
-
'
)[
1
]);
callback
(
undefined
,
[
]);
}
}
return
revisions
;
};
};
/**
priv
.
putAttachmentList
=
function
(
doc
,
option
,
attachment_list
,
callback
)
{
* Returns the revision of the revision position from a revs_info array.
console
.
log
(
"
p putAttachmentList
"
);
* @method getRevisionFromPosition
var
i
,
dealResults
,
state
=
"
ok
"
,
count
=
0
,
attachment
;
* @param {array} revs_info The revs_info array
attachment_list
=
attachment_list
||
[];
* @param {number} rev_pos The revision position number
dealResults
=
function
(
index
)
{
* @return {string} The revision of the good position (empty string if fail)
return
function
(
err
,
response
)
{
*/
if
(
state
!==
"
ok
"
)
{
priv
.
getRevisionFromPosition
=
function
(
revs_info
,
rev_pos
)
{
return
;
var
i
;
}
for
(
i
=
revs_info
.
length
-
1
;
i
>=
0
;
i
-=
1
)
{
count
-=
1
;
if
(
priv
.
revisionToArray
(
revs_info
[
i
].
rev
)[
0
]
===
rev_pos
)
{
if
(
err
)
{
return
revs_info
[
i
].
rev
;
state
=
"
error
"
;
return
callback
(
err
,
undefined
);
}
if
(
count
===
0
)
{
state
=
"
finished
"
;
callback
(
undefined
,
{
"
id
"
:
doc
.
_id
,
"
ok
"
:
true
});
}
};
};
for
(
i
=
0
;
i
<
attachment_list
.
length
;
i
+=
1
)
{
attachment
=
attachment_list
[
i
];
if
(
attachment
!==
undefined
)
{
count
+=
1
;
attachment
.
_id
=
doc
.
_id
+
"
.
"
+
doc
.
_rev
+
"
/
"
+
attachment
.
_attachment
;
delete
attachment
.
_attachment
;
priv
.
putAttachment
(
attachment
,
option
,
dealResults
(
i
));
}
}
}
}
return
''
;
if
(
count
===
0
)
{
return
callback
(
undefined
,
{
"
id
"
:
doc
.
_id
,
"
ok
"
:
true
});
}
};
};
/**
priv
.
putDocumentTree
=
function
(
doc
,
option
,
doc_tree
,
callback
)
{
* Post the document metadata and create or update a document tree.
doc_tree
=
priv
.
clone
(
doc_tree
);
* Options:
doc_tree
.
_id
=
doc
.
_id
+
priv
.
doc_tree_suffix
;
* - {boolean} keep_revision_history To keep the previous revisions
priv
.
put
(
doc_tree
,
option
,
callback
);
* (false by default) (NYI).
};
* @method post
* @param {object} command The JIO command
*/
that
.
post
=
function
(
command
)
{
var
f
=
{},
doctree
,
revs_info
,
doc
,
docid
,
prev_doc
;
doc
=
command
.
cloneDoc
();
docid
=
command
.
getDocId
();
if
(
typeof
doc
.
_rev
===
"
string
"
&&
!
priv
.
checkRevisionFormat
(
doc
.
_rev
))
{
priv
.
notFoundError
=
function
(
message
,
reason
)
{
that
.
error
({
return
{
"
status
"
:
31
,
"
status
"
:
404
,
"
statusText
"
:
"
Wrong Revision Format
"
,
"
statusText
"
:
"
Not Found
"
,
"
error
"
:
"
wrong_revision_format
"
,
"
error
"
:
"
not_found
"
,
"
message
"
:
"
The document previous revision does not match
"
+
"
message
"
:
message
,
"
^[0-9]+-[0-9a-zA-Z]+$
"
,
"
reason
"
:
reason
"
reason
"
:
"
Previous revision is wrong
"
};
});
};
return
;
priv
.
conflictError
=
function
(
message
,
reason
)
{
return
{
"
status
"
:
409
,
"
statusText
"
:
"
Conflict
"
,
"
error
"
:
"
conflict
"
,
"
message
"
:
message
,
"
reason
"
:
reason
};
};
priv
.
revisionGenericRequest
=
function
(
doc
,
option
,
specific_parameter
,
onEnd
)
{
var
prev_doc
,
doc_tree
,
attachment_list
,
callback
=
{};
if
(
specific_parameter
.
doc_id
)
{
doc
.
_id
=
specific_parameter
.
doc_id
;
}
}
if
(
typeof
docid
!==
"
string
"
)
{
if
(
specific_parameter
.
attachment_id
)
{
doc
.
_id
=
priv
.
generateUuid
();
doc
.
_attachment
=
specific_parameter
.
attachment_id
;
docid
=
doc
.
_id
;
}
}
f
.
getDocumentTree
=
function
()
{
callback
.
begin
=
function
()
{
var
option
=
command
.
cloneOption
();
console
.
log
(
"
c begin
"
);
if
(
option
.
max_retry
===
0
)
{
var
check_error
;
option
.
max_retry
=
3
;
doc
.
_id
=
doc
.
_id
||
priv
.
generateUuid
();
if
(
specific_parameter
.
revision_needed
&&
!
doc
.
_rev
)
{
return
onEnd
(
priv
.
conflictError
(
"
Document update conflict
"
,
"
No document revision was provided
"
),
undefined
);
}
// check revision format
check_error
=
priv
.
checkDocumentRevisionFormat
(
doc
);
if
(
check_error
!==
undefined
)
{
return
onEnd
(
check_error
,
undefined
);
}
priv
.
getRevisionTree
(
doc
,
option
,
callback
.
getRevisionTree
);
};
callback
.
getRevisionTree
=
function
(
err
,
response
)
{
console
.
log
(
"
c getRevisionTree
"
);
var
winner_info
,
previous_revision
=
doc
.
_rev
,
generate_new_revision
=
doc
.
_revs
||
doc
.
_revs_info
?
false
:
true
;
if
(
err
)
{
if
(
err
.
status
!==
404
)
{
err
.
message
=
"
Cannot get document revision tree
"
;
return
onEnd
(
err
,
undefined
);
}
}
}
that
.
addJob
(
doc_tree
=
response
||
priv
.
newDocTree
();
"
get
"
,
if
(
specific_parameter
.
get
||
specific_parameter
.
getAttachment
)
{
priv
.
substorage
,
if
(
!
doc
.
_rev
)
{
docid
+
priv
.
doctree_suffix
,
console
.
log
(
JSON
.
stringify
(
doc_tree
));
option
,
winner_info
=
priv
.
getWinnerRevsInfo
(
doc_tree
);
function
(
response
)
{
console
.
log
(
winner_info
);
doctree
=
response
;
if
(
winner_info
.
length
===
0
)
{
f
.
updateRevsInfo
();
return
onEnd
(
priv
.
notFoundError
(
f
.
getDocument
();
"
Document not found
"
,
},
"
missing
"
function
(
err
)
{
),
undefined
);
switch
(
err
.
status
)
{
case
404
:
doctree
=
priv
.
createDocumentTree
();
f
.
updateRevsInfo
();
f
.
getDocument
();
break
;
default
:
err
.
message
=
"
Cannot get document revision tree
"
;
f
.
error
(
err
);
break
;
}
}
}
if
(
winner_info
[
0
].
status
===
"
deleted
"
)
{
);
return
onEnd
(
priv
.
notFoundError
(
};
"
Document not found
"
,
f
.
getDocument
=
function
()
{
"
deleted
"
if
(
revs_info
[
1
]
===
undefined
)
{
),
undefined
);
f
.
postDocument
([]);
}
else
{
that
.
addJob
(
"
get
"
,
priv
.
substorage
,
command
.
getDocId
()
+
"
.
"
+
revs_info
[
1
].
rev
,
command
.
getOption
(),
function
(
response
)
{
var
attachment_list
=
[],
i
;
prev_doc
=
response
;
for
(
i
in
response
.
_attachments
)
{
if
(
response
.
_attachments
.
hasOwnProperty
(
i
))
{
attachment_list
.
push
({
"
id
"
:
i
,
"
attachment
"
:
{
"
_id
"
:
command
.
getDocId
()
+
"
.
"
+
revs_info
[
0
].
rev
+
"
/
"
+
i
,
"
_mimetype
"
:
response
.
_attachments
[
i
].
content_type
,
"
_data
"
:
undefined
}});
}
}
f
.
postDocument
(
attachment_list
);
},
function
(
err
)
{
if
(
err
.
status
===
404
)
{
f
.
postDocument
([]);
return
;
}
err
.
message
=
"
Cannot retrieve document
"
;
f
.
error
(
err
);
}
}
doc
.
_rev
=
winner_info
[
0
].
rev
;
}
priv
.
fillDocumentRevisionProperties
(
doc
,
doc_tree
);
return
priv
.
getDocument
(
doc
,
option
,
callback
.
getDocument
);
}
priv
.
fillDocumentRevisionProperties
(
doc
,
doc_tree
);
if
(
generate_new_revision
)
{
if
(
previous_revision
&&
doc
.
_revs_info
.
length
===
0
)
{
// the document history has changed, it means that the document
// revision was wrong. Add a pseudo history to the document
doc
.
_rev
=
previous_revision
;
doc
.
_revs
=
{
"
start
"
:
parseInt
(
previous_revision
.
split
(
"
-
"
)[
0
],
10
),
"
ids
"
:
[
previous_revision
.
split
(
"
-
"
)[
1
]]
};
doc
.
_revs_info
=
[{
"
rev
"
:
previous_revision
,
"
status
"
:
"
missing
"
}];
}
doc
=
priv
.
generateNextRevision
(
doc
,
specific_parameter
.
remove
);
);
}
}
};
if
(
doc
.
_revs_info
.
length
>
1
)
{
f
.
updateRevsInfo
=
function
()
{
prev_doc
=
{
if
(
doc
.
_revs
)
{
"
_id
"
:
doc
.
_id
,
revs_info
=
priv
.
updateDocumentTree
(
doctree
,
doc
.
_revs
);
"
_rev
"
:
doc
.
_revs_info
[
1
].
rev
}
else
{
};
revs_info
=
priv
.
postToDocumentTree
(
doctree
,
doc
);
}
// force revs_info status
doc
.
_revs_info
[
0
].
status
=
(
specific_parameter
.
remove
?
"
deleted
"
:
"
available
"
);
priv
.
updateDocumentTree
(
doc
,
doc_tree
);
if
(
prev_doc
)
{
return
priv
.
getDocument
(
prev_doc
,
option
,
callback
.
getDocument
);
}
if
(
specific_parameter
.
remove
||
specific_parameter
.
removeAttachment
)
{
console
.
log
(
"
this one
"
);
return
onEnd
(
priv
.
notFoundError
(
"
Unable to remove an inexistent document
"
,
"
missing
"
),
undefined
);
}
}
priv
.
putDocument
(
doc
,
option
,
callback
.
putDocument
);
};
};
f
.
postDocument
=
function
(
attachment_list
)
{
callback
.
getDocument
=
function
(
err
,
res_doc
)
{
doc
.
_id
=
docid
+
"
.
"
+
revs_info
[
0
].
rev
;
console
.
log
(
"
c getDocument
"
);
delete
doc
.
_rev
;
var
k
,
conflicts
;
delete
doc
.
_revs
;
if
(
err
)
{
that
.
addJob
(
if
(
err
.
status
===
404
)
{
"
post
"
,
if
(
specific_parameter
.
remove
||
priv
.
substorage
,
specific_parameter
.
removeAttachment
)
{
doc
,
return
onEnd
(
priv
.
conflictError
(
command
.
cloneOption
(),
"
Document update conflict
"
,
function
()
{
"
Document is missing
"
var
i
;
),
undefined
);
if
(
attachment_list
.
length
===
0
)
{
f
.
sendDocumentTree
();
}
else
{
f
.
send_document_tree_count
=
attachment_list
.
length
;
for
(
i
=
0
;
i
<
attachment_list
.
length
;
i
+=
1
)
{
f
.
copyAttachment
(
attachment_list
[
i
].
id
,
attachment_list
[
i
].
attachment
);
}
}
}
},
if
(
specific_parameter
.
get
)
{
function
(
err
)
{
return
onEnd
(
priv
.
notFoundError
(
switch
(
err
.
status
)
{
"
Unable to find the document
"
,
case
409
:
"
missing
"
// file already exists
),
undefined
);
f
.
sendDocumentTree
();
break
;
default
:
err
.
message
=
"
Cannot upload document
"
;
f
.
error
(
err
);
break
;
}
}
res_doc
=
{};
}
else
{
err
.
message
=
"
Cannot get document
"
;
return
onEnd
(
err
,
undefined
);
}
}
);
};
f
.
copyAttachment
=
function
(
attachmentid
,
attachment
)
{
that
.
addJob
(
"
get
"
,
priv
.
substorage
,
prev_doc
.
_id
+
"
/
"
+
attachmentid
,
command
.
cloneOption
(),
function
(
response
)
{
attachment
.
_data
=
response
;
that
.
addJob
(
"
putAttachment
"
,
priv
.
substorage
,
attachment
,
command
.
cloneOption
(),
function
(
response
)
{
f
.
sendDocumentTree
();
},
function
(
err
)
{
err
.
message
=
"
Cannot copy previous attachment
"
;
f
.
error
(
err
);
}
);
},
function
(
err
)
{
err
.
message
=
"
Cannot get previous attachment
"
;
f
.
error
(
err
);
}
);
};
f
.
send_document_tree_count
=
0
;
f
.
sendDocumentTree
=
function
()
{
f
.
send_document_tree_count
-=
1
;
if
(
f
.
send_document_tree_count
>
0
)
{
return
;
}
}
doctree
.
_id
=
docid
+
priv
.
doctree_suffix
;
if
(
specific_parameter
.
get
)
{
that
.
addJob
(
res_doc
.
_id
=
doc
.
_id
;
"
put
"
,
res_doc
.
_rev
=
doc
.
_rev
;
priv
.
substorage
,
if
(
option
.
conflicts
===
true
)
{
doctree
,
conflicts
=
priv
.
getConflicts
(
doc
.
_rev
,
doc_tree
);
command
.
cloneOption
(),
if
(
conflicts
)
{
function
()
{
res_doc
.
_conflicts
=
conflicts
;
that
.
success
({
}
"
ok
"
:
true
,
"
id
"
:
docid
,
"
rev
"
:
revs_info
[
0
].
rev
});
},
function
(
err
)
{
// xxx do we try to delete the posted document ?
err
.
message
=
"
Cannot save document revision tree
"
;
f
.
error
(
err
);
}
}
);
if
(
option
.
revs
===
true
)
{
};
res_doc
.
_revisions
=
doc
.
_revs
;
f
.
error
=
function
(
err
)
{
}
f
.
error
=
function
()
{};
if
(
option
.
revs_info
===
true
)
{
that
.
error
(
err
);
res_doc
.
_revs_info
=
doc
.
_revs_info
;
};
}
f
.
getDocumentTree
();
return
onEnd
(
undefined
,
res_doc
);
};
/**
* Update the document metadata and update a document tree.
* Options:
* - {boolean} keep_revision_history To keep the previous revisions
* (false by default) (NYI).
* @method put
* @param {object} command The JIO command
*/
that
.
put
=
function
(
command
)
{
that
.
post
(
command
);
};
/**
* Create/Update the document attachment and update a document tree.
* Options:
* - {boolean} keep_revision_history To keep the previous revisions
* (false by default) (NYI).
* @method putAttachment
* @param {object} command The JIO command
*/
that
.
putAttachment
=
function
(
command
)
{
var
functions
=
{},
doc
,
doctree
,
revs_info
,
prev_doc
;
doc
=
command
.
cloneDoc
();
functions
.
begin
=
function
()
{
if
(
typeof
doc
.
_rev
===
"
string
"
&&
!
priv
.
checkRevisionFormat
(
doc
.
_rev
))
{
that
.
error
({
"
status
"
:
31
,
"
statusText
"
:
"
Wrong Revision Format
"
,
"
error
"
:
"
wrong_revision_format
"
,
"
message
"
:
"
The document previous revision does not match
"
+
"
^[0-9]+-[0-9a-zA-Z]+$
"
,
"
reason
"
:
"
Previous revision is wrong
"
});
return
;
}
functions
.
getDocumentTree
();
};
functions
.
getDocumentTree
=
function
()
{
var
option
=
command
.
cloneOption
();
if
(
option
.
max_retry
===
0
)
{
option
.
max_retry
=
3
;
}
}
that
.
addJob
(
if
(
specific_parameter
.
removeAttachment
)
{
"
get
"
,
// copy metadata (not beginning by "_" to document
priv
.
substorage
,
for
(
k
in
res_doc
)
{
command
.
getDocId
()
+
priv
.
doctree_suffix
,
if
(
res_doc
.
hasOwnProperty
(
k
)
&&
!
k
.
match
(
"
^_
"
))
{
option
,
doc
[
k
]
=
res_doc
[
k
];
function
(
response
)
{
doctree
=
response
;
functions
.
updateRevsInfo
();
functions
.
getDocument
();
},
function
(
err
)
{
switch
(
err
.
status
)
{
case
404
:
doctree
=
priv
.
createDocumentTree
();
functions
.
updateRevsInfo
();
functions
.
getDocument
();
break
;
default
:
err
.
message
=
"
Cannot get document revision tree
"
;
that
.
error
(
err
);
break
;
}
}
}
}
);
};
functions
.
updateRevsInfo
=
function
()
{
if
(
doc
.
_revs
)
{
revs_info
=
priv
.
updateDocumentTree
(
doctree
,
doc
.
_revs
);
}
else
{
revs_info
=
priv
.
postToDocumentTree
(
doctree
,
doc
);
}
}
};
if
(
specific_parameter
.
remove
)
{
functions
.
postEmptyDocument
=
function
()
{
priv
.
putDocumentTree
(
doc
,
option
,
doc_tree
,
callback
.
putDocumentTree
);
that
.
addJob
(
"
post
"
,
priv
.
substorage
,
{
"
_id
"
:
command
.
getDocId
()
+
"
.
"
+
revs_info
[
0
].
rev
},
command
.
getOption
(),
function
(
response
)
{
doc
.
_rev
=
response
.
rev
;
functions
.
postAttachment
();
},
function
(
err
)
{
err
.
message
=
"
Cannot upload document
"
;
that
.
error
(
err
);
}
);
};
functions
.
getDocument
=
function
()
{
if
(
revs_info
[
1
]
===
undefined
)
{
functions
.
postEmptyDocument
();
}
else
{
}
else
{
that
.
addJob
(
console
.
log
(
"
res_doc
"
);
"
get
"
,
console
.
log
(
res_doc
);
priv
.
substorage
,
priv
.
getAttachmentList
(
res_doc
,
option
,
callback
.
getAttachmentList
);
command
.
getDocId
()
+
"
.
"
+
revs_info
[
1
].
rev
,
command
.
getOption
(),
function
(
response
)
{
var
attachment_list
=
[],
i
;
prev_doc
=
response
;
for
(
i
in
response
.
_attachments
)
{
if
(
response
.
_attachments
.
hasOwnProperty
(
i
))
{
attachment_list
.
push
({
"
id
"
:
i
,
"
attachment
"
:
{
"
_id
"
:
command
.
getDocId
()
+
"
.
"
+
revs_info
[
0
].
rev
+
"
/
"
+
i
,
"
_mimetype
"
:
response
.
_attachments
[
i
].
content_type
,
"
_data
"
:
undefined
}});
}
}
functions
.
postDocument
(
attachment_list
);
},
function
(
err
)
{
if
(
err
.
status
===
404
)
{
functions
.
postDocument
([]);
return
;
}
err
.
message
=
"
Cannot upload document
"
;
that
.
error
(
err
);
}
);
}
}
};
};
functions
.
postDocument
=
function
(
attachment_list
)
{
callback
.
getAttachmentList
=
function
(
err
,
res_list
)
{
that
.
addJob
(
console
.
log
(
"
c getAttachmentList
"
);
"
post
"
,
var
i
,
attachment_found
=
false
;
priv
.
substorage
,
if
(
err
)
{
command
.
getDocId
()
+
"
.
"
+
revs_info
[
0
].
rev
,
err
.
message
=
"
Cannot get attachment
"
;
command
.
getOption
(),
return
onEnd
(
err
,
undefined
);
function
(
response
)
{
}
var
i
;
attachment_list
=
res_list
||
[];
if
(
attachment_list
.
length
===
0
)
{
if
(
specific_parameter
.
getAttachment
)
{
functions
.
postAttachment
();
// getting specific attachment
}
else
{
for
(
i
=
0
;
i
<
attachment_list
.
length
;
i
+=
1
)
{
functions
.
post_attachment_count
=
attachment_list
.
length
;
if
(
attachment_list
[
i
]
&&
for
(
i
=
0
;
i
<
attachment_list
.
length
;
i
+=
1
)
{
doc
.
_attachment
===
functions
.
copyAttachment
(
attachment_list
[
i
].
id
,
attachment_list
[
i
].
_attachment
)
{
attachment_list
[
i
].
attachment
);
return
onEnd
(
attachment_list
[
i
].
_data
);
}
}
}
},
function
(
err
)
{
err
.
message
=
"
Cannot upload document
"
;
that
.
error
(
err
);
}
}
);
return
onEnd
(
priv
.
notFoundError
(
};
"
Unable to get an inexistent attachment
"
,
functions
.
copyAttachment
=
function
(
attachmentid
,
attachment
)
{
"
missing
"
that
.
addJob
(
),
undefined
);
"
get
"
,
}
priv
.
substorage
,
if
(
specific_parameter
.
remove_from_attachment_list
)
{
prev_doc
.
_id
+
"
/
"
+
attachmentid
,
// removing specific attachment
command
.
cloneOption
(),
for
(
i
=
0
;
i
<
attachment_list
.
length
;
i
+=
1
)
{
function
(
response
)
{
if
(
attachment_list
[
i
]
&&
attachment
.
_data
=
response
;
specific_parameter
.
remove_from_attachment_list
.
_attachment
===
that
.
addJob
(
attachment_list
[
i
].
_attachment
)
{
"
putAttachment
"
,
attachment_found
=
true
;
priv
.
substorage
,
attachment_list
[
i
]
=
undefined
;
attachment
,
break
;
command
.
cloneOption
(),
}
function
(
response
)
{
}
functions
.
postAttachment
();
if
(
!
attachment_found
)
{
},
return
onEnd
(
priv
.
notFoundError
(
function
(
err
)
{
"
Unable to remove an inexistent attachment
"
,
err
.
message
=
"
Cannot copy previous attachment
"
;
"
missing
"
functions
.
error
(
err
);
),
undefined
);
}
);
},
function
(
err
)
{
err
.
message
=
"
Cannot copy previous attachment
"
;
functions
.
error
(
err
);
}
}
);
};
functions
.
post_attachment_count
=
0
;
functions
.
postAttachment
=
function
()
{
functions
.
post_attachment_count
-=
1
;
if
(
functions
.
post_attachment_count
>
0
)
{
return
;
}
}
that
.
addJob
(
priv
.
putDocument
(
doc
,
option
,
callback
.
putDocument
);
"
putAttachment
"
,
};
priv
.
substorage
,
callback
.
putDocument
=
function
(
err
,
response
)
{
{
console
.
log
(
"
c putDocument
"
);
"
_id
"
:
command
.
getDocId
()
+
"
.
"
+
revs_info
[
0
].
rev
+
"
/
"
+
var
i
,
attachment_found
=
false
;
command
.
getAttachmentId
(),
if
(
err
)
{
"
_mimetype
"
:
command
.
getAttachmentMimeType
(),
err
.
message
=
"
Cannot post the document
"
;
"
_data
"
:
command
.
getAttachmentData
()
return
onEnd
(
err
,
undefined
);
},
}
command
.
cloneOption
(),
if
(
specific_parameter
.
add_to_attachment_list
)
{
function
()
{
// adding specific attachment
functions
.
sendDocumentTree
();
attachment_list
=
attachment_list
||
[];
},
for
(
i
=
0
;
i
<
attachment_list
.
length
;
i
+=
1
)
{
function
(
err
)
{
if
(
specific_parameter
.
add_to_attachment_list
.
_attachment
===
switch
(
err
.
status
)
{
attachment_list
[
i
].
_attachment
)
{
case
409
:
attachment_found
=
true
;
// file already exists
attachment_list
[
i
]
=
specific_parameter
.
add_to_attachment_list
;
functions
.
sendDocumentTree
();
break
;
default
:
err
.
message
=
"
Cannot upload attachment
"
;
functions
.
error
(
err
);
break
;
break
;
}
}
}
}
);
if
(
!
attachment_found
)
{
};
attachment_list
.
unshift
(
specific_parameter
.
add_to_attachment_list
);
functions
.
sendDocumentTree
=
function
()
{
doctree
.
_id
=
command
.
getDocId
()
+
priv
.
doctree_suffix
;
that
.
addJob
(
"
put
"
,
priv
.
substorage
,
doctree
,
command
.
cloneOption
(),
function
()
{
that
.
success
({
"
ok
"
:
true
,
"
id
"
:
command
.
getDocId
()
+
"
/
"
+
command
.
getAttachmentId
(),
"
rev
"
:
revs_info
[
0
].
rev
});
},
function
(
err
)
{
// xxx do we try to delete the posted document ?
err
.
message
=
"
Cannot save document revision tree
"
;
functions
.
error
(
err
);
}
}
}
priv
.
putAttachmentList
(
doc
,
option
,
attachment_list
,
callback
.
putAttachmentList
);
);
};
};
functions
.
error
=
function
(
err
)
{
callback
.
putAttachmentList
=
function
(
err
,
response
)
{
functions
.
error
=
function
()
{};
console
.
log
(
"
c putAttachmentList
"
);
that
.
error
(
err
);
if
(
err
)
{
err
.
message
=
"
Cannot copy attacments to the document
"
;
return
onEnd
(
err
,
undefined
);
}
priv
.
putDocumentTree
(
doc
,
option
,
doc_tree
,
callback
.
putDocumentTree
);
};
callback
.
putDocumentTree
=
function
(
err
,
response
)
{
console
.
log
(
"
c putDocumentTree
"
);
if
(
err
)
{
err
.
message
=
"
Cannot update the document history
"
;
return
onEnd
(
err
,
undefined
);
}
onEnd
(
undefined
,
{
"
ok
"
:
true
,
"
id
"
:
doc
.
_id
+
(
specific_parameter
.
putAttachment
||
specific_parameter
.
removeAttachment
||
specific_parameter
.
getAttachment
?
"
/
"
+
doc
.
_attachment
:
""
),
"
rev
"
:
doc
.
_rev
});
// if (option.keep_revision_history !== true) {
// // priv.remove(prev_doc, option, function () {
// // - change "available" status to "deleted"
// // - remove attachments
// // - done, no callback
// // });
// }
};
};
functions
.
begin
();
callback
.
begin
();
};
};
/**
/**
*
Get the document metadata or attachment
.
*
Post the document metadata and create or update a document tree
.
* Options:
* Options:
* - {boolean} revs Add simple revision history (false by default).
* - {boolean} keep_revision_history To keep the previous revisions
* - {boolean} revs_info Add revs info (false by default).
* (false by default) (NYI).
* - {boolean} conflicts Add conflict object (false by default).
* @method post
* @method get
* @param {object} command The JIO command
* @param {object} command The JIO command
*/
*/
that
.
get
=
function
(
command
)
{
that
.
post
=
function
(
command
)
{
var
f
=
{},
doctree
,
revs_info
,
prev_rev
,
option
;
priv
.
revisionGenericRequest
(
option
=
command
.
cloneOption
();
command
.
cloneDoc
(),
if
(
option
.
max_retry
===
0
)
{
command
.
cloneOption
(),
option
.
max_retry
=
3
;
{},
}
function
(
err
,
response
)
{
prev_rev
=
command
.
getDocInfo
(
"
_rev
"
);
if
(
err
)
{
if
(
typeof
prev_rev
===
"
string
"
)
{
return
that
.
error
(
err
);
if
(
!
priv
.
checkRevisionFormat
(
prev_rev
))
{
that
.
error
({
"
status
"
:
31
,
"
statusText
"
:
"
Wrong Revision Format
"
,
"
error
"
:
"
wrong_revision_format
"
,
"
message
"
:
"
The document previous revision does not match
"
+
"
[0-9]+-[0-9a-zA-Z]+
"
,
"
reason
"
:
"
Previous revision is wrong
"
});
return
;
}
}
f
.
getDocumentTree
=
function
()
{
that
.
addJob
(
"
get
"
,
priv
.
substorage
,
{
"
_id
"
:
command
.
getDocId
()
+
priv
.
doctree_suffix
,
"
_rev
"
:
command
.
getDocInfo
(
"
_rev
"
)
},
option
,
function
(
response
)
{
doctree
=
response
;
if
(
prev_rev
===
undefined
)
{
revs_info
=
priv
.
getWinnerRevisionFromDocumentTree
(
doctree
);
if
(
revs_info
.
length
>
0
)
{
prev_rev
=
revs_info
[
0
].
rev
;
}
else
{
that
.
error
({
"
status
"
:
404
,
"
statusText
"
:
"
Not Found
"
,
"
error
"
:
"
not_found
"
,
"
message
"
:
"
Cannot find the document
"
,
"
reason
"
:
"
Document is deleted
"
});
return
;
}
}
else
{
revs_info
=
priv
.
getRevisionFromDocumentTree
(
doctree
,
prev_rev
);
}
f
.
getDocument
(
command
.
getDocId
()
+
"
.
"
+
prev_rev
,
command
.
getAttachmentId
());
},
function
(
err
)
{
switch
(
err
.
status
)
{
case
404
:
that
.
error
(
err
);
break
;
default
:
err
.
message
=
"
Cannot get document revision tree
"
;
that
.
error
(
err
);
break
;
}
}
);
};
f
.
getDocument
=
function
(
docid
,
attmtid
)
{
that
.
addJob
(
"
get
"
,
priv
.
substorage
,
{
"
_id
"
:
docid
,
"
_rev
"
:
command
.
getDocInfo
(
"
_rev
"
)},
option
,
function
(
response
)
{
var
attmt
;
if
(
typeof
response
!==
"
string
"
)
{
if
(
attmtid
!==
undefined
)
{
if
(
response
.
_attachments
!==
undefined
)
{
attmt
=
response
.
_attachments
[
attmtid
];
if
(
attmt
!==
undefined
)
{
prev_rev
=
priv
.
getRevisionFromPosition
(
revs_info
,
attmt
.
revpos
);
f
.
getDocument
(
command
.
getDocId
()
+
"
.
"
+
prev_rev
+
"
/
"
+
attmtid
);
return
;
}
}
that
.
error
({
"
status
"
:
404
,
"
statusText
"
:
"
Not Found
"
,
"
error
"
:
"
not_found
"
,
"
message
"
:
"
Cannot find the attachment
"
,
"
reason
"
:
"
Attachment is missing
"
});
return
;
}
response
.
_id
=
command
.
getDocId
();
response
.
_rev
=
prev_rev
;
if
(
command
.
getOption
(
"
revs
"
)
===
true
)
{
response
.
_revisions
=
priv
.
revsInfoToHistory
(
revs_info
);
}
if
(
command
.
getOption
(
"
revs_info
"
)
===
true
)
{
response
.
_revs_info
=
revs_info
;
}
if
(
command
.
getOption
(
"
conflicts
"
)
===
true
)
{
response
.
_conflicts
=
priv
.
getLeavesFromDocumentTree
(
doctree
,
prev_rev
);
if
(
response
.
_conflicts
.
length
===
0
)
{
delete
response
.
_conflicts
;
}
}
}
that
.
success
(
response
);
},
function
(
err
)
{
that
.
error
(
err
);
}
}
);
that
.
success
(
response
);
};
}
if
(
command
.
getAttachmentId
()
&&
prev_rev
!==
undefined
)
{
);
f
.
getDocument
(
command
.
getDocId
()
+
"
.
"
+
prev_rev
+
"
/
"
+
command
.
getAttachmentId
());
}
else
{
f
.
getDocumentTree
();
}
};
};
/**
/**
*
Remove document or attachment
.
*
Put the document metadata and create or update a document tree
.
* Options:
* Options:
* - {boolean} keep_revision_history To keep the previous revisions
* - {boolean} keep_revision_history To keep the previous revisions
* @method remove
* (false by default) (NYI).
* @method put
* @param {object} command The JIO command
* @param {object} command The JIO command
*/
*/
that
.
remove
=
function
(
command
)
{
that
.
put
=
function
(
command
)
{
var
f
=
{},
del_rev
,
option
,
new_doc
,
revs_info
;
priv
.
revisionGenericRequest
(
option
=
command
.
cloneOption
();
command
.
cloneDoc
(),
if
(
option
.
max_retry
===
0
)
{
command
.
cloneOption
(),
option
.
max_retry
=
3
;
{},
}
function
(
err
,
response
)
{
del_rev
=
command
.
getDoc
().
_rev
;
if
(
err
)
{
return
that
.
error
(
err
);
}
that
.
success
(
response
);
}
);
};
f
.
removeDocument
=
function
(
docid
,
doctree
)
{
if
(
command
.
getOption
(
"
keep_revision_history
"
)
!==
true
)
{
if
(
command
.
getAttachmentId
()
===
undefined
)
{
// update tree
revs_info
=
priv
.
postToDocumentTree
(
doctree
,
command
.
getDoc
(),
true
);
// remove revision
that
.
addJob
(
"
remove
"
,
priv
.
substorage
,
docid
,
option
,
function
()
{
// put tree
doctree
.
_id
=
command
.
getDocId
()
+
priv
.
doctree_suffix
;
that
.
addJob
(
"
put
"
,
priv
.
substorage
,
doctree
,
command
.
cloneOption
(),
function
()
{
that
.
success
({
"
ok
"
:
true
,
"
id
"
:
command
.
getDocId
(),
"
rev
"
:
revs_info
[
0
].
rev
});
},
function
()
{
that
.
error
({
"
status
"
:
409
,
"
statusText
"
:
"
Conflict
"
,
"
error
"
:
"
conflict
"
,
"
message
"
:
"
Document update conflict.
"
,
"
reason
"
:
"
Cannot update document tree
"
});
return
;
}
);
},
function
()
{
that
.
error
({
"
status
"
:
404
,
"
statusText
"
:
"
Not Found
"
,
"
error
"
:
"
not_found
"
,
"
message
"
:
"
File not found
"
,
"
reason
"
:
"
Document was not found
"
});
return
;
}
);
}
else
{
// get previsous document
that
.
addJob
(
"
get
"
,
priv
.
substorage
,
command
.
getDocId
()
+
"
.
"
+
del_rev
,
option
,
function
(
response
)
{
// update tree
revs_info
=
priv
.
postToDocumentTree
(
doctree
,
command
.
getDoc
());
new_doc
=
response
;
delete
new_doc
.
_attachments
;
new_doc
.
_id
=
new_doc
.
_id
+
"
.
"
+
revs_info
[
0
].
rev
;
// post new document version
that
.
putAttachment
=
function
(
command
)
{
that
.
addJob
(
priv
.
revisionGenericRequest
(
"
post
"
,
command
.
cloneDoc
(),
priv
.
substorage
,
command
.
cloneOption
(),
new_doc
,
{
command
.
cloneOption
(),
"
doc_id
"
:
command
.
getDocId
(),
function
()
{
"
attachment_id
"
:
command
.
getAttachmentId
(),
// put tree
"
add_to_attachment_list
"
:
{
doctree
.
_id
=
command
.
getDocId
()
+
priv
.
doctree_suffix
;
"
_attachment
"
:
command
.
getAttachmentId
(),
that
.
addJob
(
"
_mimetype
"
:
command
.
getAttachmentMimeType
(),
"
put
"
,
"
_data
"
:
command
.
getAttachmentData
()
priv
.
substorage
,
},
doctree
,
"
putAttachment
"
:
true
command
.
cloneOption
(),
},
function
()
{
function
(
err
,
response
)
{
that
.
success
({
if
(
err
)
{
"
ok
"
:
true
,
return
that
.
error
(
err
);
"
id
"
:
new_doc
.
_id
,
"
rev
"
:
revs_info
[
0
].
rev
});
},
function
(
err
)
{
err
.
message
=
"
Cannot save document revision tree
"
;
that
.
error
(
err
);
}
);
},
function
()
{
that
.
error
({
"
status
"
:
409
,
"
statusText
"
:
"
Conflict
"
,
"
error
"
:
"
conflict
"
,
"
message
"
:
"
Document update conflict.
"
,
"
reason
"
:
"
Cannot update document
"
});
return
;
}
);
},
function
()
{
that
.
error
({
"
status
"
:
404
,
"
statusText
"
:
"
Not Found
"
,
"
error
"
:
"
not_found
"
,
"
message
"
:
"
File not found
"
,
"
reason
"
:
"
Document was not found
"
});
return
;
}
);
}
}
that
.
success
(
response
);
}
}
};
);
if
(
typeof
del_rev
===
"
string
"
)
{
};
if
(
!
priv
.
checkRevisionFormat
(
del_rev
))
{
that
.
error
({
"
status
"
:
31
,
"
statusText
"
:
"
Wrong Revision Format
"
,
"
error
"
:
"
wrong_revision_format
"
,
"
message
"
:
"
The document previous revision does not match
"
+
"
[0-9]+-[0-9a-zA-Z]+
"
,
"
reason
"
:
"
Previous revision is wrong
"
});
return
;
}
}
// get doctree
that
.
remove
=
function
(
command
)
{
that
.
addJob
(
if
(
command
.
getAttachmentId
())
{
"
get
"
,
return
that
.
removeAttachment
(
command
);
priv
.
substorage
,
}
command
.
getDocId
()
+
priv
.
doctree_suffix
,
priv
.
revisionGenericRequest
(
option
,
command
.
cloneDoc
(),
function
(
response
)
{
command
.
cloneOption
(),
response
.
_conflicts
=
priv
.
getLeavesFromDocumentTree
(
response
);
{
"
revision_needed
"
:
true
,
"
remove
"
:
true
},
function
(
err
,
response
)
{
if
(
err
)
{
return
that
.
error
(
err
);
}
that
.
success
(
response
);
}
);
};
if
(
del_rev
===
undefined
)
{
that
.
removeAttachment
=
function
(
command
)
{
// no revision provided
priv
.
revisionGenericRequest
(
that
.
error
({
command
.
cloneDoc
(),
"
status
"
:
409
,
command
.
cloneOption
(),
"
statusText
"
:
"
Conflict
"
,
{
"
error
"
:
"
conflict
"
,
"
doc_id
"
:
command
.
getDocId
(),
"
message
"
:
"
Document update conflict.
"
,
"
attachment_id
"
:
command
.
getAttachmentId
(),
"
reason
"
:
"
Cannot delete a document without revision
"
"
revision_needed
"
:
true
,
});
"
removeAttachment
"
:
true
,
return
;
"
remove_from_attachment_list
"
:
{
"
_attachment
"
:
command
.
getAttachmentId
()
}
}
// revision provided
},
if
(
priv
.
isRevisionALeaf
(
response
,
del_rev
)
===
true
)
{
function
(
err
,
response
)
{
if
(
typeof
command
.
getAttachmentId
()
===
"
string
"
)
{
if
(
err
)
{
f
.
removeDocument
(
command
.
getDocId
()
+
"
.
"
+
del_rev
+
return
that
.
error
(
err
);
"
/
"
+
command
.
getAttachmentId
(),
response
);
}
else
{
f
.
removeDocument
(
command
.
getDocId
()
+
"
.
"
+
del_rev
,
response
);
}
}
else
{
that
.
error
({
"
status
"
:
409
,
"
statusText
"
:
"
Conflict
"
,
"
error
"
:
"
conflict
"
,
"
message
"
:
"
Document update conflict.
"
,
"
reason
"
:
"
Trying to remove non-latest revision
"
});
return
;
}
}
that
.
success
(
response
);
}
);
};
that
.
get
=
function
(
command
)
{
if
(
command
.
getAttachmentId
())
{
return
that
.
getAttachment
(
command
);
}
priv
.
revisionGenericRequest
(
command
.
cloneDoc
(),
command
.
cloneOption
(),
{
"
get
"
:
true
},
},
function
()
{
function
(
err
,
response
)
{
that
.
error
({
if
(
err
)
{
"
status
"
:
404
,
return
that
.
error
(
err
);
"
statusText
"
:
"
Not Found
"
,
}
"
error
"
:
"
not_found
"
,
that
.
success
(
response
);
"
message
"
:
"
Document tree not found, please checkdocument ID
"
,
"
reason
"
:
"
Incorrect document ID
"
});
return
;
}
}
);
);
};
};
/**
that
.
getAttachment
=
function
(
command
)
{
* Get all documents
priv
.
revisionGenericRequest
(
* @method allDocs
command
.
cloneDoc
(),
* @param {object} command The JIO command
command
.
cloneOption
(),
*/
{
that
.
allDocs
=
function
()
{
"
doc_id
"
:
command
.
getDocId
(),
setTimeout
(
function
()
{
"
attachment_id
"
:
command
.
getAttachmentId
(),
that
.
error
({
"
getAttachment
"
:
true
"
status
"
:
405
,
},
"
statusText
"
:
"
Method Not Allowed
"
,
function
(
err
,
response
)
{
"
error
"
:
"
method_not_allowed
"
,
if
(
err
)
{
"
message
"
:
"
Your are not allowed to use this command
"
,
return
that
.
error
(
err
);
"
reason
"
:
"
LocalStorage forbids AllDocs command executions
"
}
});
that
.
success
(
response
);
});
}
);
};
};
// END //
priv
.
RevisionStorage
();
return
that
;
return
that
;
});
});
// end RevisionStorage
test/jiotests.js
View file @
d7fcbbaf
...
@@ -34,9 +34,14 @@ clone = function (obj) {
...
@@ -34,9 +34,14 @@ clone = function (obj) {
// generates a revision hash from document metadata, revision history
// generates a revision hash from document metadata, revision history
// and the deleted_flag
// and the deleted_flag
generateRevisionHash
=
function
(
doc
,
revisions
,
deleted_flag
)
{
generateRevisionHash
=
function
(
doc
,
revisions
,
deleted_flag
)
{
var
string
=
JSON
.
stringify
(
doc
)
+
JSON
.
stringify
(
revisions
)
+
var
string
;
JSON
.
stringify
(
deleted_flag
?
true
:
false
);
doc
=
clone
(
doc
);
return
hex_sha256
(
string
);
delete
doc
.
_rev
;
delete
doc
.
_revs
;
delete
doc
.
_revs_info
;
string
=
JSON
.
stringify
(
doc
)
+
JSON
.
stringify
(
revisions
)
+
JSON
.
stringify
(
deleted_flag
?
true
:
false
);
return
hex_sha256
(
string
);
},
},
// localStorage wrapper
// localStorage wrapper
localstorage
=
{
localstorage
=
{
...
@@ -1264,7 +1269,8 @@ test ("Post", function(){
...
@@ -1264,7 +1269,8 @@ test ("Post", function(){
o
.
doc
=
{
"
_id
"
:
"
post1
"
,
"
_rev
"
:
o
.
rev
,
"
title
"
:
"
myPost2
"
};
o
.
doc
=
{
"
_id
"
:
"
post1
"
,
"
_rev
"
:
o
.
rev
,
"
title
"
:
"
myPost2
"
};
o
.
revisions
=
{
"
start
"
:
1
,
"
ids
"
:
[
o
.
rev
.
split
(
'
-
'
)[
1
]]};
o
.
revisions
=
{
"
start
"
:
1
,
"
ids
"
:
[
o
.
rev
.
split
(
'
-
'
)[
1
]]};
o
.
rev
=
"
2-
"
+
generateRevisionHash
(
o
.
doc
,
o
.
revisions
);
o
.
rev
=
"
2-
"
+
generateRevisionHash
(
o
.
doc
,
o
.
revisions
);
o
.
spy
(
o
,
"
status
"
,
undefined
,
"
Post + revision
"
);
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
post1
"
,
"
rev
"
:
o
.
rev
},
"
Post + revision
"
);
o
.
jio
.
post
(
o
.
doc
,
o
.
f
);
o
.
jio
.
post
(
o
.
doc
,
o
.
f
);
o
.
tick
(
o
);
o
.
tick
(
o
);
...
@@ -1293,8 +1299,92 @@ test ("Post", function(){
...
@@ -1293,8 +1299,92 @@ test ("Post", function(){
"
Check document tree
"
"
Check document tree
"
);
);
o
.
jio
.
stop
();
// add attachment
o
.
doc
.
_attachments
=
{
"
attachment_test
"
:
{
"
length
"
:
35
,
"
digest
"
:
"
A
"
,
"
content_type
"
:
"
oh/yeah
"
}
};
localstorage
.
setItem
(
o
.
localpath
+
"
/post1.
"
+
o
.
rev
,
o
.
doc
);
localstorage
.
setItem
(
o
.
localpath
+
"
/post1.
"
+
o
.
rev
+
"
/attachment_test
"
,
"
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
"
);
// post + attachment copy
o
.
doc
=
{
"
_id
"
:
"
post1
"
,
"
_rev
"
:
o
.
rev
,
"
title
"
:
"
myPost2
"
};
o
.
revisions
=
{
"
start
"
:
2
,
"
ids
"
:
[
o
.
rev
.
split
(
'
-
'
)[
1
],
o
.
revisions
.
ids
[
0
]]
};
o
.
rev
=
"
3-
"
+
generateRevisionHash
(
o
.
doc
,
o
.
revisions
);
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
post1
"
,
"
rev
"
:
o
.
rev
},
"
Post + attachment copy
"
);
o
.
jio
.
post
(
o
.
doc
,
o
.
f
);
o
.
tick
(
o
);
// check attachment
deepEqual
(
localstorage
.
getItem
(
o
.
localpath
+
"
/post1.
"
+
o
.
rev
+
"
/attachment_test
"
),
"
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
"
,
"
Check Attachment
"
);
// check document tree
o
.
doc_tree
.
_id
=
"
post1.revision_tree.json
"
;
o
.
doc_tree
.
children
[
0
].
children
[
0
].
children
.
unshift
({
"
rev
"
:
o
.
rev
,
"
status
"
:
"
available
"
,
"
children
"
:
[]
});
deepEqual
(
localstorage
.
getItem
(
o
.
localpath
+
"
/post1.revision_tree.json
"
),
o
.
doc_tree
,
"
Check document tree
"
);
// post + wrong revision
o
.
doc
=
{
"
_id
"
:
"
post1
"
,
"
_rev
"
:
"
3-wr3
"
,
"
title
"
:
"
myPost3
"
};
o
.
revisions
=
{
"
start
"
:
3
,
"
ids
"
:
[
"
wr3
"
]};
o
.
rev
=
"
4-
"
+
generateRevisionHash
(
o
.
doc
,
o
.
revisions
);
o
.
spy
(
o
,
"
value
"
,
{
"
id
"
:
"
post1
"
,
"
ok
"
:
true
,
"
rev
"
:
o
.
rev
},
"
Postt + wrong revision
"
);
o
.
jio
.
post
(
o
.
doc
,
o
.
f
);
o
.
tick
(
o
);
// check document
deepEqual
(
localstorage
.
getItem
(
o
.
localpath
+
"
/post1.3-wr3
"
),
null
,
"
Check document
"
);
// check document
o
.
doc
.
_id
=
"
post1.
"
+
o
.
rev
;
delete
o
.
doc
.
_rev
;
deepEqual
(
localstorage
.
getItem
(
o
.
localpath
+
"
/post1.
"
+
o
.
rev
),
o
.
doc
,
"
Check document
"
);
// check document tree
o
.
doc_tree
.
_id
=
"
post1.revision_tree.json
"
;
o
.
doc_tree
.
children
.
unshift
({
"
rev
"
:
"
3-wr3
"
,
"
status
"
:
"
missing
"
,
"
children
"
:
[{
"
rev
"
:
o
.
rev
,
"
status
"
:
"
available
"
,
"
children
"
:
[]
}]
});
deepEqual
(
localstorage
.
getItem
(
o
.
localpath
+
"
/post1.revision_tree.json
"
),
o
.
doc_tree
,
"
Check document tree
"
);
o
.
jio
.
stop
();
});
});
test
(
"
Put
"
,
function
(){
test
(
"
Put
"
,
function
(){
...
@@ -1562,7 +1652,7 @@ test("Put Attachment", function () {
...
@@ -1562,7 +1652,7 @@ test("Put Attachment", function () {
// putAttachment without document
// putAttachment without document
o
.
revisions
=
{
"
start
"
:
0
,
"
ids
"
:
[]}
o
.
revisions
=
{
"
start
"
:
0
,
"
ids
"
:
[]}
o
.
rev_hash
=
generateRevisionHash
({
"
_id
"
:
"
doc1
/
attmt1
"
},
o
.
rev_hash
=
generateRevisionHash
({
"
_id
"
:
"
doc1
"
,
"
_attachment
"
:
"
attmt1
"
},
o
.
revisions
);
o
.
revisions
);
o
.
rev
=
"
1-
"
+
o
.
rev_hash
;
o
.
rev
=
"
1-
"
+
o
.
rev_hash
;
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1/attmt1
"
,
"
rev
"
:
o
.
rev
},
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1/attmt1
"
,
"
rev
"
:
o
.
rev
},
...
@@ -1601,9 +1691,9 @@ test("Put Attachment", function () {
...
@@ -1601,9 +1691,9 @@ test("Put Attachment", function () {
o
.
prev_rev
=
o
.
rev
;
o
.
prev_rev
=
o
.
rev
;
o
.
revisions
=
{
"
start
"
:
1
,
"
ids
"
:
[
o
.
rev_hash
]}
o
.
revisions
=
{
"
start
"
:
1
,
"
ids
"
:
[
o
.
rev_hash
]}
o
.
rev_hash
=
generateRevisionHash
({
o
.
rev_hash
=
generateRevisionHash
({
"
_id
"
:
"
doc1
/attmt1
"
,
"
_id
"
:
"
doc1
"
,
"
_data
"
:
"
abc
"
,
"
_data
"
:
"
abc
"
,
"
_
rev
"
:
o
.
prev_rev
"
_
attachment
"
:
"
attmt1
"
,
},
o
.
revisions
);
},
o
.
revisions
);
o
.
rev
=
"
2-
"
+
o
.
rev_hash
;
o
.
rev
=
"
2-
"
+
o
.
rev_hash
;
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1/attmt1
"
,
"
rev
"
:
o
.
rev
},
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1/attmt1
"
,
"
rev
"
:
o
.
rev
},
...
@@ -1646,9 +1736,9 @@ test("Put Attachment", function () {
...
@@ -1646,9 +1736,9 @@ test("Put Attachment", function () {
o
.
prev_rev
=
o
.
rev
;
o
.
prev_rev
=
o
.
rev
;
o
.
revisions
=
{
"
start
"
:
2
,
"
ids
"
:
[
o
.
rev_hash
,
o
.
revisions
.
ids
[
0
]]}
o
.
revisions
=
{
"
start
"
:
2
,
"
ids
"
:
[
o
.
rev_hash
,
o
.
revisions
.
ids
[
0
]]}
o
.
rev_hash
=
generateRevisionHash
({
o
.
rev_hash
=
generateRevisionHash
({
"
_id
"
:
"
doc1
/attmt2
"
,
"
_id
"
:
"
doc1
"
,
"
_data
"
:
"
def
"
,
"
_data
"
:
"
def
"
,
"
_
rev
"
:
o
.
prev_rev
"
_
attachment
"
:
"
attmt2
"
,
},
o
.
revisions
);
},
o
.
revisions
);
o
.
rev
=
"
3-
"
+
o
.
rev_hash
;
o
.
rev
=
"
3-
"
+
o
.
rev_hash
;
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1/attmt2
"
,
"
rev
"
:
o
.
rev
},
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1/attmt2
"
,
"
rev
"
:
o
.
rev
},
...
@@ -1723,15 +1813,16 @@ test ("Get", function(){
...
@@ -1723,15 +1813,16 @@ test ("Get", function(){
o
.
doctree
=
{
"
children
"
:[{
o
.
doctree
=
{
"
children
"
:[{
"
rev
"
:
"
1-rev1
"
,
"
status
"
:
"
available
"
,
"
children
"
:
[]
"
rev
"
:
"
1-rev1
"
,
"
status
"
:
"
available
"
,
"
children
"
:
[]
}]};
}]};
o
.
doc_myget1
=
{
"
_id
"
:
"
get1
"
,
"
title
"
:
"
myGet1
"
};
o
.
doc_myget1
=
{
"
_id
"
:
"
get1
.1-rev1
"
,
"
title
"
:
"
myGet1
"
};
localstorage
.
setItem
(
o
.
localpath
+
"
/get1.revision_tree.json
"
,
o
.
doctree
);
localstorage
.
setItem
(
o
.
localpath
+
"
/get1.revision_tree.json
"
,
o
.
doctree
);
localstorage
.
setItem
(
o
.
localpath
+
"
/get1.1-rev1
"
,
o
.
doc_myget1
);
localstorage
.
setItem
(
o
.
localpath
+
"
/get1.1-rev1
"
,
o
.
doc_myget1
);
// get document
// get document
o
.
doc_myget1_cloned
=
clone
(
o
.
doc_myget1
);
o
.
doc_myget1_cloned
=
clone
(
o
.
doc_myget1
);
o
.
doc_myget1_cloned
[
"
_rev
"
]
=
"
1-rev1
"
;
o
.
doc_myget1_cloned
.
_id
=
"
get1
"
;
o
.
doc_myget1_cloned
[
"
_revisions
"
]
=
{
"
start
"
:
1
,
"
ids
"
:
[
"
rev1
"
]};
o
.
doc_myget1_cloned
.
_rev
=
"
1-rev1
"
;
o
.
doc_myget1_cloned
[
"
_revs_info
"
]
=
[{
o
.
doc_myget1_cloned
.
_revisions
=
{
"
start
"
:
1
,
"
ids
"
:
[
"
rev1
"
]};
o
.
doc_myget1_cloned
.
_revs_info
=
[{
"
rev
"
:
"
1-rev1
"
,
"
status
"
:
"
available
"
"
rev
"
:
"
1-rev1
"
,
"
status
"
:
"
available
"
}];
}];
o
.
spy
(
o
,
"
value
"
,
o
.
doc_myget1_cloned
,
"
Get document (winner)
"
);
o
.
spy
(
o
,
"
value
"
,
o
.
doc_myget1_cloned
,
"
Get document (winner)
"
);
...
@@ -1748,14 +1839,15 @@ test ("Get", function(){
...
@@ -1748,14 +1839,15 @@ test ("Get", function(){
"
rev
"
:
"
2-rev3
"
,
"
status
"
:
"
available
"
,
"
children
"
:
[]
"
rev
"
:
"
2-rev3
"
,
"
status
"
:
"
available
"
,
"
children
"
:
[]
}]
}]
}]};
}]};
o
.
doc_myget2
=
{
"
_id
"
:
"
get1
"
,
"
title
"
:
"
myGet2
"
};
o
.
doc_myget2
=
{
"
_id
"
:
"
get1
.1-rev2
"
,
"
title
"
:
"
myGet2
"
};
o
.
doc_myget3
=
{
"
_id
"
:
"
get1
"
,
"
title
"
:
"
myGet3
"
};
o
.
doc_myget3
=
{
"
_id
"
:
"
get1
.2-rev3
"
,
"
title
"
:
"
myGet3
"
};
localstorage
.
setItem
(
o
.
localpath
+
"
/get1.revision_tree.json
"
,
o
.
doctree
);
localstorage
.
setItem
(
o
.
localpath
+
"
/get1.revision_tree.json
"
,
o
.
doctree
);
localstorage
.
setItem
(
o
.
localpath
+
"
/get1.1-rev2
"
,
o
.
doc_myget2
);
localstorage
.
setItem
(
o
.
localpath
+
"
/get1.1-rev2
"
,
o
.
doc_myget2
);
localstorage
.
setItem
(
o
.
localpath
+
"
/get1.2-rev3
"
,
o
.
doc_myget3
);
localstorage
.
setItem
(
o
.
localpath
+
"
/get1.2-rev3
"
,
o
.
doc_myget3
);
// get document
// get document
o
.
doc_myget3_cloned
=
clone
(
o
.
doc_myget3
);
o
.
doc_myget3_cloned
=
clone
(
o
.
doc_myget3
);
o
.
doc_myget3_cloned
.
_id
=
"
get1
"
;
o
.
doc_myget3_cloned
[
"
_rev
"
]
=
"
2-rev3
"
;
o
.
doc_myget3_cloned
[
"
_rev
"
]
=
"
2-rev3
"
;
o
.
doc_myget3_cloned
[
"
_revisions
"
]
=
{
"
start
"
:
2
,
"
ids
"
:
[
"
rev3
"
,
"
rev2
"
]};
o
.
doc_myget3_cloned
[
"
_revisions
"
]
=
{
"
start
"
:
2
,
"
ids
"
:
[
"
rev3
"
,
"
rev2
"
]};
o
.
doc_myget3_cloned
[
"
_revs_info
"
]
=
[{
o
.
doc_myget3_cloned
[
"
_revs_info
"
]
=
[{
...
@@ -1780,6 +1872,7 @@ test ("Get", function(){
...
@@ -1780,6 +1872,7 @@ test ("Get", function(){
// get specific document
// get specific document
o
.
doc_myget2_cloned
=
clone
(
o
.
doc_myget2
);
o
.
doc_myget2_cloned
=
clone
(
o
.
doc_myget2
);
o
.
doc_myget2_cloned
.
_id
=
"
get1
"
;
o
.
doc_myget2_cloned
[
"
_rev
"
]
=
"
1-rev2
"
;
o
.
doc_myget2_cloned
[
"
_rev
"
]
=
"
1-rev2
"
;
o
.
doc_myget2_cloned
[
"
_revisions
"
]
=
{
"
start
"
:
1
,
"
ids
"
:
[
"
rev2
"
]};
o
.
doc_myget2_cloned
[
"
_revisions
"
]
=
{
"
start
"
:
1
,
"
ids
"
:
[
"
rev2
"
]};
o
.
doc_myget2_cloned
[
"
_revs_info
"
]
=
[{
o
.
doc_myget2_cloned
[
"
_revs_info
"
]
=
[{
...
@@ -1793,18 +1886,16 @@ test ("Get", function(){
...
@@ -1793,18 +1886,16 @@ test ("Get", function(){
o
.
tick
(
o
);
o
.
tick
(
o
);
// adding an attachment
// adding an attachment
o
.
attmt_myget
2
=
{
o
.
attmt_myget
3
=
{
"
get2
"
:
{
"
get2
"
:
{
"
length
"
:
3
,
"
length
"
:
3
,
"
digest
"
:
"
md5-dontcare
"
,
"
digest
"
:
"
md5-dontcare
"
,
"
revpos
"
:
1
"
content_type
"
:
"
oh/yeah
"
}
}
};
};
o
.
doc_myget2
[
"
_attachments
"
]
=
o
.
attmt_myget2
;
o
.
doc_myget3
.
_attachments
=
o
.
attmt_myget3
;
o
.
doc_myget3
[
"
_attachments
"
]
=
o
.
attmt_myget2
;
localstorage
.
setItem
(
o
.
localpath
+
"
/get1.1-rev2
"
,
o
.
doc_myget2
);
localstorage
.
setItem
(
o
.
localpath
+
"
/get1.2-rev3
"
,
o
.
doc_myget3
);
localstorage
.
setItem
(
o
.
localpath
+
"
/get1.2-rev3
"
,
o
.
doc_myget3
);
localstorage
.
setItem
(
o
.
localpath
+
"
/get1.
1-rev2
/get2
"
,
"
abc
"
);
localstorage
.
setItem
(
o
.
localpath
+
"
/get1.
2-rev3
/get2
"
,
"
abc
"
);
// get attachment winner
// get attachment winner
o
.
spy
(
o
,
"
value
"
,
"
abc
"
,
"
Get attachment (winner)
"
);
o
.
spy
(
o
,
"
value
"
,
"
abc
"
,
"
Get attachment (winner)
"
);
...
@@ -1820,13 +1911,13 @@ test ("Get", function(){
...
@@ -1820,13 +1911,13 @@ test ("Get", function(){
// get attachment specific rev
// get attachment specific rev
o
.
spy
(
o
,
"
value
"
,
"
abc
"
,
"
Get attachment (specific revision)
"
);
o
.
spy
(
o
,
"
value
"
,
"
abc
"
,
"
Get attachment (specific revision)
"
);
o
.
jio
.
get
({
"
_id
"
:
"
get1/get2
"
,
"
_rev
"
:
"
1-rev2
"
},
{
o
.
jio
.
get
({
"
_id
"
:
"
get1/get2
"
,
"
_rev
"
:
"
2-rev3
"
},
{
"
revs_info
"
:
true
,
"
revs
"
:
true
,
"
conflicts
"
:
true
,
"
revs_info
"
:
true
,
"
revs
"
:
true
,
"
conflicts
"
:
true
,
},
o
.
f
);
},
o
.
f
);
o
.
tick
(
o
);
o
.
tick
(
o
);
// get document with attachment (specific revision)
// get document with attachment (specific revision)
o
.
doc_myget2_cloned
[
"
_attachments
"
]
=
o
.
attmt_myget2
;
delete
o
.
doc_myget2_cloned
.
_attachments
;
o
.
spy
(
o
,
"
value
"
,
o
.
doc_myget2_cloned
,
o
.
spy
(
o
,
"
value
"
,
o
.
doc_myget2_cloned
,
"
Get document which have an attachment (specific revision)
"
);
"
Get document which have an attachment (specific revision)
"
);
o
.
jio
.
get
({
"
_id
"
:
"
get1
"
,
"
_rev
"
:
"
1-rev2
"
},
{
o
.
jio
.
get
({
"
_id
"
:
"
get1
"
,
"
_rev
"
:
"
1-rev2
"
},
{
...
@@ -1835,7 +1926,7 @@ test ("Get", function(){
...
@@ -1835,7 +1926,7 @@ test ("Get", function(){
o
.
tick
(
o
);
o
.
tick
(
o
);
// get document with attachment (winner)
// get document with attachment (winner)
o
.
doc_myget3_cloned
[
"
_attachments
"
]
=
o
.
attmt_myget2
;
o
.
doc_myget3_cloned
.
_attachments
=
o
.
attmt_myget3
;
o
.
spy
(
o
,
"
value
"
,
o
.
doc_myget3_cloned
,
o
.
spy
(
o
,
"
value
"
,
o
.
doc_myget3_cloned
,
"
Get document which have an attachment (winner)
"
);
"
Get document which have an attachment (winner)
"
);
o
.
jio
.
get
({
"
_id
"
:
"
get1
"
},
o
.
jio
.
get
({
"
_id
"
:
"
get1
"
},
...
@@ -1862,188 +1953,135 @@ test ("Remove", function(){
...
@@ -1862,188 +1953,135 @@ test ("Remove", function(){
o
.
localpath
=
"
jio/localstorage/urevrem/arevrem
"
;
o
.
localpath
=
"
jio/localstorage/urevrem/arevrem
"
;
// 1. remove document without revision
// 1. remove document without revision
o
.
spy
(
o
,
"
status
"
,
404
,
o
.
spy
(
o
,
"
status
"
,
409
,
"
Remove document without revision
"
+
"
Remove document (no doctree, no revision)
"
);
"
-> 409 Conflict
"
);
o
.
jio
.
remove
({
"
_id
"
:
"
remove1
"
},
o
.
f
);
o
.
jio
.
remove
({
"
_id
"
:
"
remove1
"
},
o
.
f
);
o
.
tick
(
o
);
o
.
tick
(
o
);
// 2. remove attachment without revision
// 2. remove attachment without revision
o
.
spy
(
o
,
"
status
"
,
404
,
o
.
spy
(
o
,
"
status
"
,
409
,
"
Remove attachment without revision
"
+
"
Remove attachment (no doctree, no revision)
"
);
"
-> 409 Conflict
"
);
o
.
jio
.
remove
({
"
_id
"
:
"
remove1/remove2
"
},
o
.
f
);
o
.
jio
.
remove
({
"
_id
"
:
"
remove1/remove2
"
},
o
.
f
);
o
.
tick
(
o
);
o
.
tick
(
o
);
// adding
two docu
ments
// adding
a document with attach
ments
o
.
doc_myremove1
=
{
"
_id
"
:
"
remove1
"
,
"
title
"
:
"
myRemove1
"
};
o
.
doc_myremove1
=
{
o
.
doc_myremove2
=
{
"
_id
"
:
"
remove1
"
,
"
title
"
:
"
myRemove2
"
};
"
_id
"
:
"
remove1.1-veryoldrev
"
,
"
title
"
:
"
myRemove1
"
o
.
very_old_rev
=
"
1-veryoldrev
"
;
}
;
localstorage
.
setItem
(
o
.
localpath
+
"
/remove1.
"
+
o
.
very_old_rev
,
localstorage
.
setItem
(
o
.
localpath
+
"
/remove1.1-veryoldrev
"
,
o
.
doc_myremove1
);
o
.
doc_myremove1
);
localstorage
.
setItem
(
o
.
localpath
+
"
/remove1.1-rev2
"
,
o
.
doc_myremove1
);
// add attachment
o
.
doc_myremove1
.
_id
=
"
remove1.2-oldrev
"
;
o
.
attmt_myremove1
=
{
o
.
attachment_remove2
=
{
"
remove2
"
:
{
"
length
"
:
3
,
"
length
"
:
3
,
"
digest
"
:
"
md5-dontcare
"
,
"
digest
"
:
"
md5-dontcare
"
,
"
content_type
"
:
"
oh/yeah
"
"
revpos
"
:
1
}
},
o
.
attachment_remove3
=
{
"
length
"
:
5
,
"
digest
"
:
"
md5-865f5cc7fbd7854902eae9d8211f178a
"
,
"
content_type
"
:
"
he/ho
"
}
o
.
doc_myremove1
.
_attachments
=
{
"
remove2
"
:
o
.
attachment_remove2
,
"
remove3
"
:
o
.
attachment_remove3
};
};
o
.
doc_myremove1
=
{
"
_id
"
:
"
remove1
"
,
"
title
"
:
"
myRemove1
"
,
"
_attachments
"
:
o
.
attmt_myremove1
};
o
.
revisions
=
{
"
start
"
:
1
,
"
ids
"
:[
o
.
very_old_rev
.
split
(
'
-
'
),[
1
]]}
o
.
old_rev
=
"
2-
"
+
generateRevisionHash
(
o
.
doc_myremove1
,
o
.
revisions
);
localstorage
.
setItem
(
o
.
localpath
+
"
/remove1.
"
+
o
.
old_rev
,
o
.
doc_myremove1
);
localstorage
.
setItem
(
o
.
localpath
+
"
/remove1.2-oldrev
"
,
localstorage
.
setItem
(
o
.
localpath
+
"
/remove1.
"
+
o
.
old_rev
+
"
/remove2
"
,
"
xyz
"
);
o
.
doc_myremove1
);
localstorage
.
setItem
(
o
.
localpath
+
"
/remove1.2-oldrev/remove2
"
,
"
abc
"
);
localstorage
.
setItem
(
o
.
localpath
+
"
/remove1.2-oldrev/remove3
"
,
"
defgh
"
);
o
.
doctree
=
{
"
children
"
:[{
// add document tree
"
rev
"
:
o
.
very_old_rev
,
"
status
"
:
"
available
"
,
"
children
"
:
[{
o
.
doctree
=
{
"
rev
"
:
o
.
old_rev
,
"
status
"
:
"
available
"
,
"
children
"
:
[]
"
children
"
:
[{
"
rev
"
:
"
1-veryoldrev
"
,
"
status
"
:
"
available
"
,
"
children
"
:
[{
"
rev
"
:
"
2-oldrev
"
,
"
status
"
:
"
available
"
,
"
children
"
:
[]
}]
}]
},{
}]
"
rev
"
:
"
1-rev2
"
,
"
status
"
:
"
available
"
,
"
children
"
:
[]
};
}]};
localstorage
.
setItem
(
o
.
localpath
+
"
/remove1.revision_tree.json
"
,
localstorage
.
setItem
(
o
.
localpath
+
"
/remove1.revision_tree.json
"
,
o
.
doctree
);
o
.
doctree
);
// 3. remove non existing attachment with revision
o
.
spy
(
o
,
"
status
"
,
404
,
"
Remove NON-existing attachment (revision)
"
);
o
.
jio
.
remove
({
"
_id
"
:
"
remove1.1-rev2/remove0
"
,
"
_rev
"
:
o
.
old_rev
},
o
.
f
);
o
.
tick
(
o
);
o
.
revisions
=
{
"
start
"
:
2
,
"
ids
"
:[
o
.
old_rev
.
split
(
'
-
'
)[
1
],
o
.
very_old_rev
.
split
(
'
-
'
)[
1
]
]};
o
.
doc_myremove1
=
{
"
_id
"
:
"
remove1/remove2
"
,
"
_rev
"
:
o
.
old_rev
};
o
.
rev
=
"
3-
"
+
generateRevisionHash
(
o
.
doc_myremove1
,
o
.
revisions
);
// 4. remove existing attachment with revision
// 3. remove inexistent attachment
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
remove1.
"
+
o
.
rev
,
"
rev
"
:
o
.
rev
},
o
.
spy
(
o
,
"
status
"
,
404
,
"
Remove inexistent attachment -> 404 Not Found
"
);
"
Remove existing attachment (revision)
"
);
o
.
jio
.
remove
({
"
_id
"
:
"
remove1/remove0
"
,
"
_rev
"
:
"
2-oldrev
"
},
o
.
f
);
o
.
jio
.
remove
({
"
_id
"
:
"
remove1/remove2
"
,
"
_rev
"
:
o
.
old_rev
},
o
.
f
);
o
.
tick
(
o
);
o
.
tick
(
o
);
o
.
testtree
=
{
"
children
"
:[{
// 4. remove existing attachment
"
rev
"
:
o
.
very_old_rev
,
"
status
"
:
"
available
"
,
"
children
"
:
[{
o
.
rev_hash
=
generateRevisionHash
({
"
rev
"
:
o
.
old_rev
,
"
status
"
:
"
available
"
,
"
children
"
:
[{
"
_id
"
:
"
remove1
"
,
"
rev
"
:
o
.
rev
,
"
status
"
:
"
available
"
,
"
children
"
:
[]
"
_attachment
"
:
"
remove2
"
,
}]
},
{
"
start
"
:
2
,
"
ids
"
:
[
"
oldrev
"
,
"
veryoldrev
"
]});
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
remove1/remove2
"
,
"
rev
"
:
"
3-
"
+
o
.
rev_hash
},
"
Remove existing attachment
"
);
o
.
jio
.
remove
({
"
_id
"
:
"
remove1/remove2
"
,
"
_rev
"
:
"
2-oldrev
"
},
o
.
f
);
o
.
tick
(
o
);
o
.
doctree
=
{
"
children
"
:[{
"
rev
"
:
"
1-veryoldrev
"
,
"
status
"
:
"
available
"
,
"
children
"
:
[{
"
rev
"
:
"
2-oldrev
"
,
"
status
"
:
"
available
"
,
"
children
"
:
[{
"
rev
"
:
"
3-
"
+
o
.
rev_hash
,
"
status
"
:
"
available
"
,
"
children
"
:
[]
}]
}]
}]
},{
}]
"
rev
"
:
"
1-rev2
"
,
"
status
"
:
"
available
"
,
"
children
"
:
[]
};
}]};
// 5. check if document tree has been updated correctly
// 5. check if document tree has been updated correctly
deepEqual
(
localstorage
.
getItem
(
deepEqual
(
localstorage
.
getItem
(
"
jio/localstorage/urevrem/arevrem
/remove1.revision_tree.json
"
o
.
localpath
+
"
/remove1.revision_tree.json
"
),
o
.
test
tree
,
"
Check document tree
"
);
),
o
.
doc
tree
,
"
Check document tree
"
);
// 6. check if
attachment has been removed
// 6. check if
the attachment still exists
deepEqual
(
localstorage
.
getItem
(
deepEqual
(
localstorage
.
getItem
(
"
jio/localstorage/urevrem/arevrem/remove1.
"
+
o
.
rev
+
"
/remove2
"
o
.
localpath
+
"
/remove1.2-oldrev
/remove2
"
),
null
,
"
Check attachment
"
);
),
"
abc
"
,
"
Check attachment -> still exists
"
);
// 7. check if document is updated
// 7. check if document is updated
deepEqual
(
localstorage
.
getItem
(
deepEqual
(
localstorage
.
getItem
(
"
jio/localstorage/urevrem/arevrem/remove1.
"
+
o
.
rev
o
.
localpath
+
"
/remove1.3-
"
+
o
.
rev_hash
),
{
"
_id
"
:
"
remove1.
"
+
o
.
rev
,
"
title
"
:
"
myRemove1
"
},
"
Check document
"
);
),
{
"
_id
"
:
"
remove1.3-
"
+
o
.
rev_hash
,
// add another attachment
"
title
"
:
"
myRemove1
"
,
o
.
attmt_myremove2
=
{
"
_attachments
"
:
{
"
remove3
"
:
o
.
attachment_remove3
}
"
remove3
"
:
{
},
"
Check document
"
);
"
length
"
:
3
,
"
digest
"
:
"
md5-hello123
"
// 8. remove document with wrong revision
},
o
.
spy
(
o
,
"
status
"
,
409
,
"
Remove document with wrong revision
"
+
"
revpos
"
:
1
"
-> 409 Conflict
"
);
};
o
.
jio
.
remove
({
"
_id
"
:
"
remove1
"
,
"
_rev
"
:
"
1-a
"
},
o
.
f
);
o
.
doc_myremove2
=
{
"
_id
"
:
"
remove1
"
,
"
title
"
:
"
myRemove2
"
,
o
.
tick
(
o
);
"
_attachments
"
:
o
.
attmt_myremove2
};
o
.
revisions
=
{
"
start
"
:
1
,
"
ids
"
:[
"
rev2
"
]
};
// 9. remove attachment wrong revision
o
.
second_old_rev
=
"
2-
"
+
generateRevisionHash
(
o
.
doc_myremove2
,
o
.
revisions
);
o
.
spy
(
o
,
"
status
"
,
409
,
"
Remove attachment with wrong revision
"
+
"
-> 409 Conflict
"
);
localstorage
.
setItem
(
o
.
localpath
+
"
/remove1.
"
+
o
.
second_old_rev
,
o
.
jio
.
remove
({
"
_id
"
:
"
remove1/remove2
"
,
"
_rev
"
:
"
1-a
"
},
o
.
f
);
o
.
doc_myremove2
);
o
.
tick
(
o
);
localstorage
.
setItem
(
o
.
localpath
+
"
/remove1.
"
+
o
.
second_old_rev
+
"
/remove3
"
,
"
stu
"
);
// 10. remove document
o
.
last_rev
=
"
3-
"
+
o
.
rev_hash
;
o
.
doctree
=
{
"
children
"
:[{
o
.
rev_hash
=
generateRevisionHash
(
"
rev
"
:
o
.
very_old_rev
,
"
status
"
:
"
available
"
,
"
children
"
:
[{
{
"
_id
"
:
"
remove1
"
},
"
rev
"
:
o
.
old_rev
,
"
status
"
:
"
available
"
,
"
children
"
:
[{
{
"
start
"
:
3
,
"
ids
"
:
[
o
.
rev_hash
,
"
oldrev
"
,
"
veryoldrev
"
]},
"
rev
"
:
o
.
rev
,
"
status
"
:
"
available
"
,
"
children
"
:[]
true
}]
);
}]
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
remove1
"
,
"
rev
"
:
"
4-
"
+
o
.
rev_hash
},
},{
"
Remove document
"
);
"
rev
"
:
"
1-rev2
"
,
"
status
"
:
"
available
"
,
"
children
"
:
[{
o
.
jio
.
remove
({
"
_id
"
:
"
remove1
"
,
"
_rev
"
:
o
.
last_rev
},
o
.
f
);
"
rev
"
:
o
.
second_old_rev
,
"
status
"
:
"
available
"
,
"
children
"
:[]
}]
}]};
localstorage
.
setItem
(
o
.
localpath
+
"
/remove1.revision_tree.json
"
,
o
.
doctree
);
// 8. remove non existing attachment without revision
o
.
spy
(
o
,
"
status
"
,
409
,
"
409 - Removing non-existing-attachment (no revision)
"
);
o
.
jio
.
remove
({
"
_id
"
:
"
remove1/remove0
"
},
o
.
f
);
o
.
tick
(
o
);
o
.
revisions
=
{
"
start
"
:
2
,
"
ids
"
:[
o
.
second_old_rev
.
split
(
'
-
'
)[
1
],
"
rev2
"
]};
o
.
doc_myremove3
=
{
"
_id
"
:
"
remove1/remove3
"
,
"
_rev
"
:
o
.
second_old_rev
};
o
.
second_rev
=
"
3-
"
+
generateRevisionHash
(
o
.
doc_myremove3
,
o
.
revisions
);
// 9. remove existing attachment without revision
o
.
spy
(
o
,
"
status
"
,
409
,
"
409 - Removing existing attachment (no revision)
"
);
o
.
jio
.
remove
({
"
_id
"
:
"
remove1/remove3
"
},
o
.
f
);
o
.
tick
(
o
);
// 10. remove wrong revision
o
.
spy
(
o
,
"
status
"
,
409
,
"
409 - Removing document (false revision)
"
);
o
.
jio
.
remove
({
"
_id
"
:
"
remove1
"
,
"
_rev
"
:
"
1-rev2
"
},
o
.
f
);
o
.
tick
(
o
);
o
.
revisions
=
{
"
start
"
:
3
,
"
ids
"
:[
o
.
rev
.
split
(
'
-
'
)[
1
],
o
.
old_rev
.
split
(
'
-
'
)[
1
],
o
.
very_old_rev
.
split
(
'
-
'
)[
1
]
]};
o
.
doc_myremove4
=
{
"
_id
"
:
"
remove1
"
,
"
_rev
"
:
o
.
rev
};
o
.
second_new_rev
=
"
4-
"
+
generateRevisionHash
(
o
.
doc_myremove4
,
o
.
revisions
,
true
);
// 11. remove document version with revision
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
remove1
"
,
"
rev
"
:
o
.
second_new_rev
},
"
Remove document (with revision)
"
);
o
.
jio
.
remove
({
"
_id
"
:
"
remove1
"
,
"
_rev
"
:
o
.
rev
},
o
.
f
);
o
.
tick
(
o
);
o
.
tick
(
o
);
o
.
testtree
[
"
children
"
][
0
][
"
children
"
][
0
][
"
children
"
][
0
][
"
children
"
].
push
({
// 11. check document tree
"
rev
"
:
o
.
second_new_rev
,
o
.
doctree
.
children
[
0
].
children
[
0
].
children
[
0
].
children
.
unshift
({
"
status
"
:
"
deleted
"
,
"
rev
"
:
"
4-
"
+
o
.
rev_hash
,
"
children
"
:
[]
"
status
"
:
"
deleted
"
,
"
children
"
:
[]
});
});
o
.
testtree
[
"
children
"
][
1
][
"
children
"
].
push
({
deepEqual
(
localstorage
.
getItem
(
o
.
localpath
+
"
/remove1.revision_tree.json
"
),
"
rev
"
:
o
.
second_old_rev
,
o
.
doctree
,
"
Check document tree
"
);
"
status
"
:
"
available
"
,
"
children
"
:[]
});
deepEqual
(
localstorage
.
getItem
(
"
jio/localstorage/urevrem/arevrem/remove1.revision_tree.json
"
),
o
.
testtree
,
"
Check document tree
"
);
deepEqual
(
localstorage
.
getItem
(
"
jio/localstorage/urevrem/arevrem/remove1.
"
+
o
.
second_new_rev
+
"
/remove2
"
),
null
,
"
Check attachment
"
);
deepEqual
(
localstorage
.
getItem
(
"
jio/localstorage/urevrem/arevrem/remove1.
"
+
o
.
second_new_rev
),
null
,
"
Check document
"
);
// remove document without revision
o
.
spy
(
o
,
"
status
"
,
409
,
"
409 - Removing document (no revision)
"
);
o
.
jio
.
remove
({
"
_id
"
:
"
remove1
"
},
o
.
f
);
o
.
tick
(
o
);
o
.
jio
.
stop
();
o
.
jio
.
stop
();
});
});
...
@@ -2196,9 +2234,7 @@ test ("Scenario", function(){
...
@@ -2196,9 +2234,7 @@ test ("Scenario", function(){
module
(
"
JIO Replicate Revision Storage
"
);
module
(
"
JIO Replicate Revision Storage
"
);
var
testReplicateRevisionStorageGenerator
=
function
(
var
testReplicateRevisionStorage
=
function
(
sinon
,
jio_description
)
{
sinon
,
jio_description
,
document_name_have_revision
)
{
var
o
=
generateTools
(
sinon
),
leavesAction
,
generateLocalPath
;
var
o
=
generateTools
(
sinon
),
leavesAction
,
generateLocalPath
;
...
@@ -2285,223 +2321,223 @@ module ("JIO Replicate Revision Storage");
...
@@ -2285,223 +2321,223 @@ module ("JIO Replicate Revision Storage");
},
o
.
f
);
},
o
.
f
);
o
.
tick
(
o
);
o
.
tick
(
o
);
// post a new document with id
//
//
post a new document with id
o
.
doc
=
{
"
_id
"
:
"
doc1
"
,
"
title
"
:
"
post new doc with id
"
};
//
o.doc = {"_id": "doc1", "title": "post new doc with id"};
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1
"
,
"
rev
"
:
o
.
rev
},
//
o.spy(o, "value", {"ok": true, "id": "doc1", "rev": o.rev},
"
Post document (with id)
"
);
//
"Post document (with id)");
o
.
jio
.
post
(
o
.
doc
,
o
.
f
);
//
o.jio.post(o.doc, o.f);
o
.
tick
(
o
);
//
o.tick(o);
// /
//
//
/
// |
//
//
|
// 1-1
//
//
1-1
// check document
//
//
check document
o
.
local_rev_hash
=
generateRevisionHash
(
o
.
doc
,
o
.
revision
);
//
o.local_rev_hash = generateRevisionHash(o.doc, o.revision);
o
.
local_rev
=
"
1-
"
+
o
.
local_rev_hash
;
//
o.local_rev = "1-" + o.local_rev_hash;
o
.
specific_rev_hash
=
o
.
local_rev_hash
;
//
o.specific_rev_hash = o.local_rev_hash;
o
.
specific_rev
=
o
.
local_rev
;
//
o.specific_rev = o.local_rev;
o
.
leavesAction
(
function
(
storage_description
,
param
)
{
//
o.leavesAction(function (storage_description, param) {
var
suffix
=
""
,
doc
=
clone
(
o
.
doc
);
//
var suffix = "", doc = clone(o.doc);
if
(
param
.
revision
)
{
//
if (param.revision) {
doc
.
_id
+=
"
.
"
+
o
.
local_rev
;
//
doc._id += "." + o.local_rev;
suffix
=
"
.
"
+
o
.
local_rev
;
//
suffix = "." + o.local_rev;
}
//
}
deepEqual
(
//
deepEqual(
localstorage
.
getItem
(
generateLocalPath
(
storage_description
)
+
//
localstorage.getItem(generateLocalPath(storage_description) +
"
/doc1
"
+
suffix
),
//
"/doc1" + suffix),
doc
,
"
Check document
"
//
doc, "Check document"
);
//
);
});
//
});
// get the post document without revision
//
//
get the post document without revision
o
.
spy
(
o
,
"
value
"
,
{
//
o.spy(o, "value", {
"
_id
"
:
"
doc1
"
,
//
"_id": "doc1",
"
title
"
:
"
post new doc with id
"
,
//
"title": "post new doc with id",
"
_rev
"
:
"
1-1
"
,
//
"_rev": "1-1",
"
_revisions
"
:
{
"
start
"
:
1
,
"
ids
"
:
[
"
1
"
]},
//
"_revisions": {"start": 1, "ids": ["1"]},
"
_revs_info
"
:
[{
"
rev
"
:
"
1-1
"
,
"
status
"
:
"
available
"
}]
//
"_revs_info": [{"rev": "1-1", "status": "available"}]
},
"
Get the previous document (without revision)
"
);
//
}, "Get the previous document (without revision)");
o
.
jio
.
get
({
"
_id
"
:
"
doc1
"
},
{
//
o.jio.get({"_id": "doc1"}, {
"
conflicts
"
:
true
,
//
"conflicts": true,
"
revs
"
:
true
,
//
"revs": true,
"
revs_info
"
:
true
//
"revs_info": true
},
o
.
f
);
//
}, o.f);
o
.
tick
(
o
);
//
o.tick(o);
// post same document without revision
//
//
post same document without revision
o
.
doc
=
{
"
_id
"
:
"
doc1
"
,
"
title
"
:
"
post same document without revision
"
};
//
o.doc = {"_id": "doc1", "title": "post same document without revision"};
o
.
rev
=
"
1-2
"
;
//
o.rev = "1-2";
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1
"
,
"
rev
"
:
o
.
rev
},
//
o.spy(o, "value", {"ok": true, "id": "doc1", "rev": o.rev},
"
Post same document (without revision)
"
);
//
"Post same document (without revision)");
o
.
jio
.
post
(
o
.
doc
,
o
.
f
);
//
o.jio.post(o.doc, o.f);
o
.
tick
(
o
);
//
o.tick(o);
// /
//
//
/
// / \
//
//
/ \
// 1-1 1-2
//
//
1-1 1-2
// check document
//
//
check document
o
.
local_rev
=
"
1-
"
+
generateRevisionHash
(
o
.
doc
,
o
.
revision
);
//
o.local_rev = "1-" + generateRevisionHash(o.doc, o.revision);
o
.
leavesAction
(
function
(
storage_description
,
param
)
{
//
o.leavesAction(function (storage_description, param) {
var
suffix
=
""
,
doc
=
clone
(
o
.
doc
);
//
var suffix = "", doc = clone(o.doc);
if
(
param
.
revision
)
{
//
if (param.revision) {
doc
.
_id
+=
"
.
"
+
o
.
local_rev
;
//
doc._id += "." + o.local_rev;
suffix
=
"
.
"
+
o
.
local_rev
;
//
suffix = "." + o.local_rev;
}
//
}
deepEqual
(
//
deepEqual(
localstorage
.
getItem
(
generateLocalPath
(
storage_description
)
+
//
localstorage.getItem(generateLocalPath(storage_description) +
"
/doc1
"
+
suffix
),
//
"/doc1" + suffix),
doc
,
"
Check document
"
//
doc, "Check document"
);
//
);
});
//
});
// post a new revision
//
//
post a new revision
o
.
doc
=
{
"
_id
"
:
"
doc1
"
,
"
title
"
:
"
post new revision
"
,
"
_rev
"
:
o
.
rev
};
//
o.doc = {"_id": "doc1", "title": "post new revision", "_rev": o.rev};
o
.
rev
=
"
2-3
"
;
//
o.rev = "2-3";
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1
"
,
"
rev
"
:
o
.
rev
},
//
o.spy(o, "value", {"ok": true, "id": "doc1", "rev": o.rev},
"
Post document (with revision)
"
);
//
"Post document (with revision)");
o
.
jio
.
post
(
o
.
doc
,
o
.
f
);
//
o.jio.post(o.doc, o.f);
o
.
tick
(
o
);
//
o.tick(o);
// /
//
//
/
// / \
//
//
/ \
// 1-1 1-2
//
//
1-1 1-2
// |
//
//
|
// 2-3
//
//
2-3
// check document
//
//
check document
o
.
revision
.
start
+=
1
;
//
o.revision.start += 1;
o
.
revision
.
ids
.
unshift
(
o
.
local_rev
.
split
(
"
-
"
).
slice
(
1
).
join
(
"
-
"
));
//
o.revision.ids.unshift(o.local_rev.split("-").slice(1).join("-"));
o
.
doc
.
_rev
=
o
.
local_rev
;
//
o.doc._rev = o.local_rev;
o
.
local_rev
=
"
2-
"
+
generateRevisionHash
(
o
.
doc
,
o
.
revision
);
//
o.local_rev = "2-" + generateRevisionHash(o.doc, o.revision);
o
.
specific_rev_conflict
=
o
.
local_rev
;
//
o.specific_rev_conflict = o.local_rev;
o
.
leavesAction
(
function
(
storage_description
,
param
)
{
//
o.leavesAction(function (storage_description, param) {
var
suffix
=
""
,
doc
=
clone
(
o
.
doc
);
//
var suffix = "", doc = clone(o.doc);
delete
doc
.
_rev
;
//
delete doc._rev;
if
(
param
.
revision
)
{
//
if (param.revision) {
doc
.
_id
+=
"
.
"
+
o
.
local_rev
;
//
doc._id += "." + o.local_rev;
suffix
=
"
.
"
+
o
.
local_rev
;
//
suffix = "." + o.local_rev;
}
//
}
deepEqual
(
//
deepEqual(
localstorage
.
getItem
(
generateLocalPath
(
storage_description
)
+
//
localstorage.getItem(generateLocalPath(storage_description) +
"
/doc1
"
+
suffix
),
//
"/doc1" + suffix),
doc
,
"
Check document
"
//
doc, "Check document"
);
//
);
});
//
});
// get the post document with revision
//
//
get the post document with revision
o
.
spy
(
o
,
"
value
"
,
{
//
o.spy(o, "value", {
"
_id
"
:
"
doc1
"
,
//
"_id": "doc1",
"
title
"
:
"
post same document without revision
"
,
//
"title": "post same document without revision",
"
_rev
"
:
"
1-2
"
,
//
"_rev": "1-2",
"
_revisions
"
:
{
"
start
"
:
1
,
"
ids
"
:
[
"
2
"
]},
//
"_revisions": {"start": 1, "ids": ["2"]},
"
_revs_info
"
:
[{
"
rev
"
:
"
1-2
"
,
"
status
"
:
"
available
"
}],
//
"_revs_info": [{"rev": "1-2", "status": "available"}],
"
_conflicts
"
:
[
"
1-1
"
]
//
"_conflicts": ["1-1"]
},
"
Get the previous document (with revision)
"
);
//
}, "Get the previous document (with revision)");
o
.
jio
.
get
({
"
_id
"
:
"
doc1
"
,
"
_rev
"
:
"
1-2
"
},
{
//
o.jio.get({"_id": "doc1", "_rev": "1-2"}, {
"
conflicts
"
:
true
,
//
"conflicts": true,
"
revs
"
:
true
,
//
"revs": true,
"
revs_info
"
:
true
,
//
"revs_info": true,
},
o
.
f
);
//
}, o.f);
o
.
tick
(
o
);
//
o.tick(o);
// get the post document with specific revision
//
//
get the post document with specific revision
o
.
spy
(
o
,
"
value
"
,
{
//
o.spy(o, "value", {
"
_id
"
:
"
doc1
"
,
//
"_id": "doc1",
"
title
"
:
"
post new doc with id
"
,
//
"title": "post new doc with id",
"
_rev
"
:
o
.
specific_rev
,
//
"_rev": o.specific_rev,
"
_revisions
"
:
{
"
start
"
:
1
,
"
ids
"
:
[
o
.
specific_rev_hash
]},
//
"_revisions": {"start": 1, "ids": [o.specific_rev_hash]},
"
_revs_info
"
:
[{
"
rev
"
:
o
.
specific_rev
,
"
status
"
:
"
available
"
}],
//
"_revs_info": [{"rev": o.specific_rev, "status": "available"}],
"
_conflicts
"
:
[
o
.
specific_rev_conflict
]
//
"_conflicts": [o.specific_rev_conflict]
},
"
Get a previous document (with local storage revision)
"
);
//
}, "Get a previous document (with local storage revision)");
o
.
jio
.
get
({
"
_id
"
:
"
doc1
"
,
"
_rev
"
:
o
.
specific_rev
},
{
//
o.jio.get({"_id": "doc1", "_rev": o.specific_rev}, {
"
conflicts
"
:
true
,
//
"conflicts": true,
"
revs
"
:
true
,
//
"revs": true,
"
revs_info
"
:
true
,
//
"revs_info": true,
},
o
.
f
);
//
}, o.f);
o
.
tick
(
o
);
//
o.tick(o);
// put document without id
//
//
put document without id
o
.
spy
(
o
,
"
status
"
,
20
,
"
Put document without id
"
)
//
o.spy(o, "status", 20, "Put document without id")
o
.
jio
.
put
({},
o
.
f
);
//
o.jio.put({}, o.f);
o
.
tick
(
o
);
//
o.tick(o);
// put document without rev
//
//
put document without rev
o
.
doc
=
{
"
_id
"
:
"
doc1
"
,
"
title
"
:
"
put new document
"
};
//
o.doc = {"_id": "doc1", "title": "put new document"};
o
.
rev
=
"
1-4
"
;
//
o.rev = "1-4";
o
.
spy
(
o
,
"
value
"
,
{
"
id
"
:
"
doc1
"
,
"
ok
"
:
true
,
"
rev
"
:
o
.
rev
},
//
o.spy(o, "value", {"id": "doc1", "ok": true, "rev": o.rev},
"
Put document without rev
"
)
//
"Put document without rev")
o
.
jio
.
put
(
o
.
doc
,
o
.
f
);
//
o.jio.put(o.doc, o.f);
o
.
tick
(
o
);
//
o.tick(o);
// __/__
//
//
__/__
// / | \
//
//
/ | \
// 1-1 1-2 1-4
//
//
1-1 1-2 1-4
// |
//
//
|
// 2-3
//
//
2-3
// put new revision
//
//
put new revision
o
.
doc
=
{
"
_id
"
:
"
doc1
"
,
"
title
"
:
"
put new revision
"
,
"
_rev
"
:
"
1-4
"
};
//
o.doc = {"_id": "doc1", "title": "put new revision", "_rev": "1-4"};
o
.
rev
=
"
2-5
"
;
//
o.rev = "2-5";
o
.
spy
(
o
,
"
value
"
,
{
"
id
"
:
"
doc1
"
,
"
ok
"
:
true
,
"
rev
"
:
o
.
rev
},
//
o.spy(o, "value", {"id": "doc1", "ok": true, "rev": o.rev},
"
Put document without rev
"
)
//
"Put document without rev")
o
.
jio
.
put
(
o
.
doc
,
o
.
f
);
//
o.jio.put(o.doc, o.f);
o
.
tick
(
o
);
//
o.tick(o);
// __/__
//
//
__/__
// / | \
//
//
/ | \
// 1-1 1-2 1-4
//
//
1-1 1-2 1-4
// | |
//
//
| |
// 2-3 2-5
//
//
2-3 2-5
// putAttachment to inexistent document
//
//
putAttachment to inexistent document
// putAttachment
//
//
putAttachment
// get document
//
//
get document
// get attachment
//
//
get attachment
// put document
//
//
put document
// get document
//
//
get document
// get attachment
//
//
get attachment
// remove attachment
//
//
remove attachment
// get document
//
//
get document
// get inexistent attachment
//
//
get inexistent attachment
// remove document and conflict
//
//
remove document and conflict
o
.
rev
=
"
3-6
"
;
//
o.rev = "3-6";
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1
"
,
"
rev
"
:
o
.
rev
},
//
o.spy(o, "value", {"ok": true, "id": "doc1", "rev": o.rev},
"
Remove document
"
);
//
"Remove document");
o
.
jio
.
remove
({
"
_id
"
:
"
doc1
"
,
"
_rev
"
:
"
2-5
"
},
o
.
f
);
//
o.jio.remove({"_id": "doc1", "_rev": "2-5"}, o.f);
o
.
tick
(
o
);
//
o.tick(o);
// remove document and conflict
//
//
remove document and conflict
o
.
rev
=
"
3-7
"
;
//
o.rev = "3-7";
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1
"
,
"
rev
"
:
o
.
rev
},
//
o.spy(o, "value", {"ok": true, "id": "doc1", "rev": o.rev},
"
Remove document
"
);
//
"Remove document");
o
.
jio
.
remove
({
"
_id
"
:
"
doc1
"
,
"
_rev
"
:
"
2-3
"
},
o
.
f
);
//
o.jio.remove({"_id": "doc1", "_rev": "2-3"}, o.f);
o
.
tick
(
o
);
//
o.tick(o);
// remove document
//
//
remove document
o
.
rev
=
"
2-8
"
;
//
o.rev = "2-8";
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1
"
,
"
rev
"
:
o
.
rev
},
//
o.spy(o, "value", {"ok": true, "id": "doc1", "rev": o.rev},
"
Remove document
"
);
//
"Remove document");
o
.
jio
.
remove
({
"
_id
"
:
"
doc1
"
,
"
_rev
"
:
"
1-1
"
},
o
.
f
);
//
o.jio.remove({"_id": "doc1", "_rev": "1-1"}, o.f);
o
.
tick
(
o
);
//
o.tick(o);
// get inexistent document
//
//
get inexistent document
o
.
spy
(
o
,
"
status
"
,
404
,
"
Get inexistent document
"
);
//
o.spy(o, "status", 404, "Get inexistent document");
o
.
jio
.
get
({
"
_id
"
:
"
doc1
"
},
{
//
o.jio.get({"_id": "doc1"}, {
"
conflicts
"
:
true
,
//
"conflicts": true,
"
revs
"
:
true
,
//
"revs": true,
"
revs_info
"
:
true
//
"revs_info": true
},
o
.
f
);
//
}, o.f);
o
.
tick
(
o
);
//
o.tick(o);
o
.
jio
.
stop
();
o
.
jio
.
stop
();
};
};
test
(
"
[Revision + Local Storage] Scenario
"
,
function
()
{
test
(
"
[Revision + Local Storage] Scenario
"
,
function
()
{
testReplicateRevisionStorage
Generator
(
this
,
{
testReplicateRevisionStorage
(
this
,
{
"
type
"
:
"
replicaterevision
"
,
"
type
"
:
"
replicaterevision
"
,
"
storage_list
"
:
[{
"
storage_list
"
:
[{
"
type
"
:
"
revision
"
,
"
type
"
:
"
revision
"
,
...
@@ -2514,7 +2550,7 @@ module ("JIO Replicate Revision Storage");
...
@@ -2514,7 +2550,7 @@ module ("JIO Replicate Revision Storage");
});
});
});
});
test
(
"
[Replicate Revision + Revision + Local Storage] Scenario
"
,
function
()
{
test
(
"
[Replicate Revision + Revision + Local Storage] Scenario
"
,
function
()
{
testReplicateRevisionStorage
Generator
(
this
,
{
testReplicateRevisionStorage
(
this
,
{
"
type
"
:
"
replicaterevision
"
,
"
type
"
:
"
replicaterevision
"
,
"
storage_list
"
:
[{
"
storage_list
"
:
[{
"
type
"
:
"
replicaterevision
"
,
"
type
"
:
"
replicaterevision
"
,
...
@@ -2530,27 +2566,27 @@ module ("JIO Replicate Revision Storage");
...
@@ -2530,27 +2566,27 @@ module ("JIO Replicate Revision Storage");
});
});
});
});
test
(
"
2x [Revision + Local Storage] Scenario
"
,
function
()
{
test
(
"
2x [Revision + Local Storage] Scenario
"
,
function
()
{
testReplicateRevisionStorage
Generator
(
this
,
{
testReplicateRevisionStorage
(
this
,
{
"
type
"
:
"
replicaterevision
"
,
"
type
"
:
"
replicaterevision
"
,
"
storage_list
"
:
[{
"
storage_list
"
:
[{
"
type
"
:
"
revision
"
,
"
type
"
:
"
revision
"
,
"
sub_storage
"
:
{
"
sub_storage
"
:
{
"
type
"
:
"
local
"
,
"
type
"
:
"
local
"
,
"
username
"
:
"
ureprevlocloc1
"
,
"
username
"
:
"
ureprevlocloc1
"
,
"
application_name
"
:
"
areprevloc1
"
"
application_name
"
:
"
areprevloc
loc
1
"
}
}
},
{
},
{
"
type
"
:
"
revision
"
,
"
type
"
:
"
revision
"
,
"
sub_storage
"
:
{
"
sub_storage
"
:
{
"
type
"
:
"
local
"
,
"
type
"
:
"
local
"
,
"
username
"
:
"
ureprevlocloc2
"
,
"
username
"
:
"
ureprevlocloc2
"
,
"
application_name
"
:
"
areprevloc2
"
"
application_name
"
:
"
areprevloc
loc
2
"
}
}
}]
}]
});
});
});
});
test
(
"
2x [Replicate Rev + 2x [Rev + Local]] Scenario
"
,
function
()
{
test
(
"
2x [Replicate Rev + 2x [Rev + Local]] Scenario
"
,
function
()
{
testReplicateRevisionStorage
Generator
(
this
,
{
testReplicateRevisionStorage
(
this
,
{
"
type
"
:
"
replicaterevision
"
,
"
type
"
:
"
replicaterevision
"
,
"
storage_list
"
:
[{
"
storage_list
"
:
[{
"
type
"
:
"
replicaterevision
"
,
"
type
"
:
"
replicaterevision
"
,
...
@@ -2589,6 +2625,159 @@ module ("JIO Replicate Revision Storage");
...
@@ -2589,6 +2625,159 @@ module ("JIO Replicate Revision Storage");
}]
}]
});
});
});
});
test
(
"
Synchronisation
"
,
function
()
{
var
o
=
generateTools
(
this
);
o
.
jio
=
JIO
.
newJio
({
"
type
"
:
"
replicaterevision
"
,
"
storage_list
"
:
[{
"
type
"
:
"
revision
"
,
"
sub_storage
"
:
{
"
type
"
:
"
local
"
,
"
username
"
:
"
usyncreprevlocloc1
"
,
"
application_name
"
:
"
asyncreprevlocloc1
"
}
},
{
"
type
"
:
"
revision
"
,
"
sub_storage
"
:
{
"
type
"
:
"
local
"
,
"
username
"
:
"
usyncreprevlocloc2
"
,
"
application_name
"
:
"
asyncreprevlocloc2
"
}
}]
});
o
.
localpath1
=
"
jio/localstorage/usyncreprevlocloc1/asyncreprevlocloc1
"
;
o
.
localpath2
=
"
jio/localstorage/usyncreprevlocloc2/asyncreprevlocloc2
"
;
// add documents to localstorage
o
.
doctree1_1
=
{
"
children
"
:
[{
"
rev
"
:
"
1-111
"
,
"
status
"
:
"
available
"
,
"
children
"
:
[],
}]
};
o
.
doc1_1
=
{
"
_id
"
:
"
doc1.1-111
"
,
"
title
"
:
"
A
"
};
localstorage
.
setItem
(
o
.
localpath1
+
"
/doc1.revision_tree.json
"
,
o
.
doctree1_1
);
localstorage
.
setItem
(
o
.
localpath2
+
"
/doc1.revision_tree.json
"
,
o
.
doctree1_1
);
localstorage
.
setItem
(
o
.
localpath1
+
"
/
"
+
o
.
doc1_1
.
_id
,
o
.
doc1_1
);
localstorage
.
setItem
(
o
.
localpath2
+
"
/
"
+
o
.
doc1_1
.
_id
,
o
.
doc1_1
);
// no synchronisation
o
.
spy
(
o
,
"
value
"
,
{
"
_id
"
:
"
doc1
"
,
"
_rev
"
:
"
1-1
"
,
"
title
"
:
"
A
"
},
"
Get document
"
);
o
.
jio
.
get
({
"
_id
"
:
"
doc1
"
},
o
.
f
);
o
.
tick
(
o
);
// check documents from localstorage
deepEqual
([
localstorage
.
getItem
(
o
.
localpath1
+
"
/doc1.revision_tree.json
"
),
localstorage
.
getItem
(
o
.
localpath2
+
"
/doc1.revision_tree.json
"
),
],
[
o
.
doctree1_1
,
o
.
doctree1_1
],
"
Check revision trees, no synchro
"
);
// add documents to localstorage
o
.
doctree2_2
=
clone
(
o
.
doctree1_1
);
o
.
doctree2_2
.
children
[
0
].
children
.
push
({
"
rev
"
:
"
2-222
"
,
"
status
"
:
"
available
"
,
"
children
"
:
[]
});
o
.
doc2_2
=
{
"
_id
"
:
"
doc1.2-222
"
,
"
title
"
:
"
B
"
};
localstorage
.
setItem
(
o
.
localpath1
+
"
/doc1.revision_tree.json
"
,
o
.
doctree2_2
);
localstorage
.
setItem
(
o
.
localpath1
+
"
/
"
+
o
.
doc2_2
.
_id
,
o
.
doc2_2
);
// document synchronisation without conflict
o
.
spy
(
o
,
"
value
"
,
{
"
_id
"
:
"
doc1
"
,
"
_rev
"
:
"
1-2
"
,
"
title
"
:
"
B
"
},
"
Get document
"
);
o
.
jio
.
get
({
"
_id
"
:
"
doc1
"
},
o
.
f
);
o
.
tick
(
o
,
50000
);
// check documents from localstorage
deepEqual
([
localstorage
.
getItem
(
o
.
localpath1
+
"
/doc1.revision_tree.json
"
),
localstorage
.
getItem
(
o
.
localpath2
+
"
/doc1.revision_tree.json
"
),
],
[
o
.
doctree2_2
,
o
.
doctree2_2
],
"
Check revision trees, rev synchro
"
);
// add documents to localstorage
o
.
doctree2_2
.
children
[
0
].
children
.
unshift
({
"
rev
"
:
"
2-223
"
,
"
status
"
:
"
available
"
,
"
children
"
:
[]
});
o
.
doc2_2
=
{
"
_id
"
:
"
doc1.2-223
"
,
"
title
"
:
"
B
"
};
localstorage
.
setItem
(
o
.
localpath1
+
"
/doc1.revision_tree.json
"
,
o
.
doctree2_2
);
localstorage
.
setItem
(
o
.
localpath1
+
"
/
"
+
o
.
doc2_2
.
_id
,
o
.
doc2_2
);
// document synchronisation with conflict
o
.
spy
(
o
,
"
value
"
,
{
"
_id
"
:
"
doc1
"
,
"
_rev
"
:
"
1-2
"
,
"
title
"
:
"
B
"
},
"
Get document
"
);
o
.
jio
.
get
({
"
_id
"
:
"
doc1
"
},
o
.
f
);
o
.
tick
(
o
,
50000
);
// check documents from localstorage
deepEqual
([
localstorage
.
getItem
(
o
.
localpath1
+
"
/doc1.revision_tree.json
"
),
localstorage
.
getItem
(
o
.
localpath2
+
"
/doc1.revision_tree.json
"
),
],
[
o
.
doctree2_2
,
o
.
doctree2_2
],
"
Check revision trees, rev synchro
"
);
////////////////////////////////////////////////////////////////////////////////
// // add documents to localstorage
// o.doctree2_2 = clone(o.doctree1_1);
// o.doctree2_2.children[0].children.push({
// "rev": "2-222",
// "status": "available",
// "children": []
// });
// o.doc2_2 = {"_id": "doc1.2-222", "title": "B"};
// localstorage.setItem(o.localpath1 + "/doc1.revision_tree.json",
// o.doctree2_2);
// localstorage.setItem(o.localpath1 + "/" + o.doc2_2._id, o.doc2_2);
// // document synchronisation without conflict
// o.spy(o, "value", {"_id": "doc1", "_rev": "1-2", "title": "B"},
// "Get document");
// o.jio.get({"_id": "doc1"}, o.f);
// o.tick(o, 50000);
// // check documents from localstorage
// deepEqual([
// localstorage.getItem(o.localpath1 + "/doc1.revision_tree.json"),
// localstorage.getItem(o.localpath2 + "/doc1.revision_tree.json"),
// ], [o.doctree2_2, o.doctree2_2], "Check revision trees, rev synchro");
// // add documents to localstorage
// o.doctree2_2.children[0].children.unshift({
// "rev": "2-223",
// "status": "available",
// "children": []
// });
// o.doc2_2 = {"_id": "doc1.2-223", "title": "B"};
// localstorage.setItem(o.localpath1 + "/doc1.revision_tree.json",
// o.doctree2_2);
// localstorage.setItem(o.localpath1 + "/" + o.doc2_2._id, o.doc2_2);
// // document synchronisation with conflict
// o.spy(o, "value", {"_id": "doc1", "_rev": "1-2", "title": "B"},
// "Get document");
// o.jio.get({"_id": "doc1"}, o.f);
// o.tick(o, 50000);
// // check documents from localstorage
// deepEqual([
// localstorage.getItem(o.localpath1 + "/doc1.revision_tree.json"),
// localstorage.getItem(o.localpath2 + "/doc1.revision_tree.json"),
// ], [o.doctree2_2, o.doctree2_2], "Check revision trees, rev synchro");
o
.
jio
.
stop
();
});
/*
/*
module ("Jio DAVStorage");
module ("Jio DAVStorage");
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment