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
Tomáš Peterka
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
Show 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
;
string
=
JSON
.
stringify
(
doc
)
+
JSON
.
stringify
(
revision_history
)
+
JSON
.
stringify
(
deleted_flag
?
true
:
false
);
console
.
log
(
string
);
revision_history
.
start
+=
1
;
revision_history
.
ids
.
unshift
(
priv
.
hashCode
(
string
));
doc
.
_revs
=
revision_history
;
doc
.
_rev
=
revision_history
.
start
+
"
-
"
+
revision_history
.
ids
[
0
];
revs_info
.
unshift
({
revs_info
.
unshift
({
"
rev
"
:
document_tree
.
rev
,
"
rev
"
:
doc
.
_
rev
,
"
status
"
:
document_tree
.
status
"
status
"
:
deleted_flag
?
"
deleted
"
:
"
available
"
});
});
if
(
document_tree
.
rev
===
revision
)
{
doc
.
_revs_info
=
revs_info
;
result
=
revs_info
;
return
doc
;
return
;
}
}
// This node has children
for
(
i
=
0
;
i
<
document_tree
.
children
.
length
;
i
+=
1
)
{
// searching deeper to find the good rev
search
(
document_tree
.
children
[
i
]);
if
(
result
.
length
>
0
)
{
// The result is already found
return
;
}
revs_info
.
shift
();
}
};
search
(
document_tree
);
return
result
;
};
};
/**
/**
* Gets the
winner revision from a document tree.
* Gets the
revs info from the document tree
*
The winner is the deeper revision on the left.
*
@method getRevisionInfo
* @
method getWinnerRevisionFromDocumentTree
* @
param {string} revision The revision to search for
* @param {object} doc
ument
_tree The document tree
* @param {object} doc_tree The document tree
* @return {array} The
winner revs info array
* @return {array} The
revs info
*/
*/
priv
.
getWinnerRevisionFromDocumentTree
=
function
(
document_tree
)
{
priv
.
getRevisionInfo
=
function
(
revision
,
doc_tree
)
{
var
result
,
search
,
revs_info
=
[];
var
getRevisionInfoRec
;
result
=
[];
getRevisionInfoRec
=
function
(
doc_tree
)
{
// search method fills "result" with the winner revs info
var
i
,
child
,
revs_info
;
search
=
function
(
document_tree
,
deep
)
{
for
(
i
=
0
;
i
<
doc_tree
.
children
.
length
;
i
+=
1
)
{
var
i
;
child
=
doc_tree
.
children
[
i
];
if
(
document_tree
.
rev
!==
undefined
)
{
if
(
child
.
rev
===
revision
)
{
// node is not root
return
[{
"
rev
"
:
child
.
rev
,
"
status
"
:
child
.
status
}];
revs_info
.
unshift
({
}
"
rev
"
:
document_tree
.
rev
,
revs_info
=
getRevisionInfoRec
(
child
);
"
status
"
:
document_tree
.
status
if
(
revs_info
.
length
>
0
||
revision
===
undefined
)
{
});
revs_info
.
push
({
"
rev
"
:
child
.
rev
,
"
status
"
:
child
.
status
});
}
return
revs_info
;
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
;
}
}
// This node has children
for
(
i
=
0
;
i
<
document_tree
.
children
.
length
;
i
+=
1
)
{
// searching deeper to find the deeper leaf
search
(
document_tree
.
children
[
i
],
deep
+
1
);
revs_info
.
shift
();
}
}
return
[];
};
};
search
(
document_tree
,
0
);
return
getRevisionInfoRec
(
doc_tree
);
return
result
;
};
};
/**
priv
.
updateDocumentTree
=
function
(
doc
,
doc_tree
)
{
* Add a document revision branch to the document tree
var
revs_info
,
updateDocumentTreeRec
,
next_rev
;
* @method updateDocumentTree
doc
=
priv
.
clone
(
doc
);
* @param {object} doctree The document tree object
revs_info
=
doc
.
_revs_info
;
* @param {object|array} revs The revision history object or a revision array
updateDocumentTreeRec
=
function
(
doc_tree
,
revs_info
)
{
* @param {boolean} deleted The deleted flag
var
i
,
child
,
info
;
* @param {array} The document revs_info
if
(
revs_info
.
length
===
0
)
{
*/
return
;
priv
.
updateDocumentTree
=
function
(
doctree
,
revs
,
deleted
)
{
var
revs_info
,
doctree_iterator
,
flag
,
i
,
rev
;
revs_info
=
[];
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
;
info
=
revs_info
.
pop
();
while
(
revs
.
length
>
0
)
{
for
(
i
=
0
;
i
<
doc_tree
.
children
.
length
;
i
+=
1
)
{
rev
=
revs
.
pop
(
0
);
child
=
doc_tree
.
children
[
i
];
revs_info
.
unshift
({
if
(
child
.
rev
===
info
.
rev
)
{
"
rev
"
:
rev
,
return
updateDocumentTreeRec
(
child
,
revs_info
);
"
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
)
{
doc_tree
.
children
.
unshift
({
doctree_iterator
.
children
.
unshift
({
"
rev
"
:
info
.
rev
,
"
rev
"
:
rev
,
"
status
"
:
info
.
status
,
"
status
"
:
"
missing
"
,
"
children
"
:
[]
"
children
"
:
[]
});
});
doctree_iterator
=
doctree_iterator
.
children
[
0
];
updateDocumentTreeRec
(
doc_tree
.
children
[
0
],
revs_info
);
}
};
updateDocumentTreeRec
(
doc_tree
,
priv
.
clone
(
revs_info
));
};
priv
.
send
=
function
(
method
,
doc
,
option
,
callback
)
{
that
.
addJob
(
method
,
priv
.
sub_storage
,
doc
,
option
,
function
(
success
)
{
callback
(
undefined
,
success
);
},
function
(
err
)
{
callback
(
err
,
undefined
);
}
}
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
)
{
if
(
doc_tree
.
children
.
length
===
0
)
{
selected_node
=
node
;
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
);
}
}
for
(
i
=
0
;
i
<
node
.
children
.
length
;
i
+=
1
)
{
if
(
selectNode
(
node
.
children
[
i
])
===
"
node_selected
"
)
{
return
"
node_selected
"
;
}
}
revs_info
.
shift
();
for
(
i
=
0
;
i
<
doc_tree
.
children
.
length
;
i
+=
1
)
{
getWinnerRevsInfoRec
(
doc_tree
.
children
[
i
],
tmp_revs_info
);
}
}
tmp_revs_info
.
shift
();
};
};
if
(
typeof
doc
.
_rev
===
"
string
"
)
{
getWinnerRevsInfoRec
(
doc_tree
,
[]);
// document has a previous revision
return
revs_info
;
if
(
selectNode
(
selected_node
)
!==
"
node_selected
"
)
{
};
// no node was selected, so add a node with a specific rev
revs_info
.
unshift
({
priv
.
getConflicts
=
function
(
revision
,
doc_tree
)
{
"
rev
"
:
doc
.
_rev
,
var
conflicts
=
[],
getConflictsRec
;
"
status
"
:
"
missing
"
getConflictsRec
=
function
(
doc_tree
)
{
});
var
i
;
selected_node
.
children
.
unshift
(
priv
.
createDocumentTreeNode
(
if
(
doc_tree
.
rev
===
revision
)
{
doc
.
_rev
,
return
;
"
missing
"
));
selected_node
=
selected_node
.
children
[
0
];
}
}
}
next_rev
=
priv
.
generateNextRevision
(
if
(
doc_tree
.
children
.
length
===
0
)
{
doc
.
_rev
||
0
,
if
(
doc_tree
.
status
!==
"
deleted
"
)
{
doc
,
conflicts
.
push
(
doc_tree
.
rev
);
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
;
}
}
for
(
i
=
0
;
i
<
doc_tree
.
children
.
length
;
i
+=
1
)
{
getConflictsRec
(
doc_tree
.
children
[
i
]);
}
}
revs_info
.
unshift
({
};
"
rev
"
:
next_rev
.
join
(
'
-
'
),
getConflictsRec
(
doc_tree
);
"
status
"
:
flag
return
conflicts
.
length
===
0
?
undefined
:
conflicts
;
})
;
}
;
selected_node
.
children
.
unshift
(
priv
.
createDocumentTreeNode
(
priv
.
get
=
function
(
doc
,
option
,
callback
)
{
next_rev
.
join
(
'
-
'
),
priv
.
send
(
"
get
"
,
doc
,
option
,
callback
);
flag
};
));
priv
.
put
=
function
(
doc
,
option
,
callback
)
{
console
.
log
(
doc
);
priv
.
send
(
"
put
"
,
doc
,
option
,
callback
);
};
priv
.
remove
=
function
(
doc
,
option
,
callback
)
{
priv
.
send
(
"
remove
"
,
doc
,
option
,
callback
);
};
priv
.
putAttachment
=
function
(
attachment
,
option
,
callback
)
{
priv
.
send
(
"
putAttachment
"
,
attachment
,
option
,
callback
);
};
return
revs_info
;
priv
.
getDocument
=
function
(
doc
,
option
,
callback
)
{
doc
=
priv
.
clone
(
doc
);
doc
.
_id
=
doc
.
_id
+
"
.
"
+
doc
.
_rev
;
delete
doc
.
_attachment
;
delete
doc
.
_rev
;
delete
doc
.
_revs
;
delete
doc
.
_revs_info
;
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
)
{
* Gets an array of leaves revisions from document tree
doc
=
priv
.
clone
(
doc
);
* @method getLeavesFromDocumentTree
doc
.
_id
=
doc
.
_id
+
priv
.
doc_tree_suffix
;
* @param {object} document_tree The document tree
priv
.
get
(
doc
,
option
,
callback
);
* @param {string} except The revision to except
};
* @return {array} The array of leaves revisions
*/
priv
.
getAttachmentList
=
function
(
doc
,
option
,
callback
)
{
priv
.
getLeavesFromDocumentTree
=
function
(
document_tree
,
except
)
{
console
.
log
(
"
p getAttachmentList
"
);
var
result
,
search
;
var
attachment_id
,
dealResults
,
state
=
"
ok
"
,
result_list
=
[],
count
=
0
;
result
=
[];
dealResults
=
function
(
attachment_id
,
attachment_meta
)
{
// search method fills [result] with the winner revision
return
function
(
err
,
attachment
)
{
search
=
function
(
document_tree
)
{
if
(
state
!==
"
ok
"
)
{
var
i
;
if
(
except
!==
undefined
&&
except
===
document_tree
.
rev
)
{
return
;
return
;
}
}
if
(
document_tree
.
children
.
length
===
0
&&
document_tree
.
status
!==
count
-=
1
;
"
deleted
"
)
{
if
(
err
)
{
// This node is a leaf
if
(
err
.
status
===
404
)
{
result
.
push
(
document_tree
.
rev
);
result_list
.
push
(
undefined
);
return
;
}
else
{
state
=
"
error
"
;
return
callback
(
err
,
undefined
);
}
}
// This node has children
}
for
(
i
=
0
;
i
<
document_tree
.
children
.
length
;
i
+=
1
)
{
result_list
.
push
({
// searching deeper to find the deeper leaf
"
_attachment
"
:
attachment_id
,
search
(
document_tree
.
children
[
i
]);
"
_data
"
:
attachment
,
"
_mimetype
"
:
attachment_meta
.
content_type
});
if
(
count
===
0
)
{
state
=
"
finished
"
;
callback
(
undefined
,
result_list
);
}
}
};
};
search
(
document_tree
);
return
result
;
};
};
for
(
attachment_id
in
doc
.
_attachments
)
{
/**
if
(
doc
.
_attachments
.
hasOwnProperty
(
attachment_id
))
{
* Check if revision is a leaf
count
+=
1
;
* @method isRevisionALeaf
priv
.
get
(
* @param {string} revision revision to check
{
"
_id
"
:
doc
.
_id
+
"
/
"
+
attachment_id
},
* @param {array} leaves all leaves on tree
option
,
* @return {boolean} true/false
dealResults
(
attachment_id
,
doc
.
_attachments
[
attachment_id
])
*/
);
priv
.
isRevisionALeaf
=
function
(
document_tree
,
revision
)
{
var
result
,
search
;
result
=
undefined
;
// search method fills "result" with the good revs info
search
=
function
(
document_tree
)
{
var
i
;
if
(
document_tree
.
rev
!==
undefined
)
{
// node is not root
if
(
document_tree
.
rev
===
revision
)
{
if
(
document_tree
.
children
.
length
===
0
)
{
// This node is a leaf
result
=
true
;
return
;
}
}
result
=
false
;
return
;
}
}
if
(
count
===
0
)
{
callback
(
undefined
,
[]);
}
}
// This node has children
};
for
(
i
=
0
;
i
<
document_tree
.
children
.
length
;
i
+=
1
)
{
// searching deeper to find the good rev
priv
.
putAttachmentList
=
function
(
doc
,
option
,
attachment_list
,
callback
)
{
search
(
document_tree
.
children
[
i
]);
console
.
log
(
"
p putAttachmentList
"
);
if
(
result
!==
undefined
)
{
var
i
,
dealResults
,
state
=
"
ok
"
,
count
=
0
,
attachment
;
// The result is already found
attachment_list
=
attachment_list
||
[];
dealResults
=
function
(
index
)
{
return
function
(
err
,
response
)
{
if
(
state
!==
"
ok
"
)
{
return
;
return
;
}
}
count
-=
1
;
if
(
err
)
{
state
=
"
error
"
;
return
callback
(
err
,
undefined
);
}
if
(
count
===
0
)
{
state
=
"
finished
"
;
callback
(
undefined
,
{
"
id
"
:
doc
.
_id
,
"
ok
"
:
true
});
}
}
};
};
search
(
document_tree
);
return
result
||
false
;
};
};
for
(
i
=
0
;
i
<
attachment_list
.
length
;
i
+=
1
)
{
/**
attachment
=
attachment_list
[
i
];
* Convert revs_info to a simple revisions history
if
(
attachment
!==
undefined
)
{
* @method revsInfoToHistory
count
+=
1
;
* @param {array} revs_info The revs info
attachment
.
_id
=
doc
.
_id
+
"
.
"
+
doc
.
_rev
+
"
/
"
+
* @return {object} The revisions history
attachment
.
_attachment
;
*/
delete
attachment
.
_attachment
;
priv
.
revsInfoToHistory
=
function
(
revs_info
)
{
priv
.
putAttachment
(
attachment
,
option
,
dealResults
(
i
));
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
)
{
revisions
.
ids
.
push
(
revs_info
[
i
].
rev
.
split
(
'
-
'
)[
1
]);
}
}
return
revisions
;
if
(
count
===
0
)
{
return
callback
(
undefined
,
{
"
id
"
:
doc
.
_id
,
"
ok
"
:
true
});
}
};
};
/**
priv
.
putDocumentTree
=
function
(
doc
,
option
,
doc_tree
,
callback
)
{
* Returns the revision of the revision position from a revs_info array.
doc_tree
=
priv
.
clone
(
doc_tree
);
* @method getRevisionFromPosition
doc_tree
.
_id
=
doc
.
_id
+
priv
.
doc_tree_suffix
;
* @param {array} revs_info The revs_info array
priv
.
put
(
doc_tree
,
option
,
callback
);
* @param {number} rev_pos The revision position number
* @return {string} The revision of the good position (empty string if fail)
*/
priv
.
getRevisionFromPosition
=
function
(
revs_info
,
rev_pos
)
{
var
i
;
for
(
i
=
revs_info
.
length
-
1
;
i
>=
0
;
i
-=
1
)
{
if
(
priv
.
revisionToArray
(
revs_info
[
i
].
rev
)[
0
]
===
rev_pos
)
{
return
revs_info
[
i
].
rev
;
}
}
return
''
;
};
};
/**
priv
.
notFoundError
=
function
(
message
,
reason
)
{
* Post the document metadata and create or update a document tree.
return
{
* Options:
"
status
"
:
404
,
* - {boolean} keep_revision_history To keep the previous revisions
"
statusText
"
:
"
Not Found
"
,
* (false by default) (NYI).
"
error
"
:
"
not_found
"
,
* @method post
"
message
"
:
message
,
* @param {object} command The JIO command
"
reason
"
:
reason
*/
};
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
.
conflictError
=
function
(
message
,
reason
)
{
that
.
error
({
return
{
"
status
"
:
31
,
"
status
"
:
409
,
"
statusText
"
:
"
Wrong Revision Format
"
,
"
statusText
"
:
"
Conflict
"
,
"
error
"
:
"
wrong_revision_format
"
,
"
error
"
:
"
conflict
"
,
"
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
.
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
(
specific_parameter
.
attachment_id
)
{
doc
.
_attachment
=
specific_parameter
.
attachment_id
;
}
callback
.
begin
=
function
()
{
console
.
log
(
"
c begin
"
);
var
check_error
;
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
);
}
}
doc_tree
=
response
||
priv
.
newDocTree
();
if
(
specific_parameter
.
get
||
specific_parameter
.
getAttachment
)
{
if
(
!
doc
.
_rev
)
{
console
.
log
(
JSON
.
stringify
(
doc_tree
));
winner_info
=
priv
.
getWinnerRevsInfo
(
doc_tree
);
console
.
log
(
winner_info
);
if
(
winner_info
.
length
===
0
)
{
return
onEnd
(
priv
.
notFoundError
(
"
Document not found
"
,
"
missing
"
),
undefined
);
}
}
if
(
typeof
docid
!==
"
string
"
)
{
if
(
winner_info
[
0
].
status
===
"
deleted
"
)
{
doc
.
_id
=
priv
.
generateUuid
();
return
onEnd
(
priv
.
notFoundError
(
docid
=
doc
.
_id
;
"
Document not found
"
,
"
deleted
"
),
undefined
);
}
}
f
.
getDocumentTree
=
function
()
{
doc
.
_rev
=
winner_info
[
0
].
rev
;
var
option
=
command
.
cloneOption
();
if
(
option
.
max_retry
===
0
)
{
option
.
max_retry
=
3
;
}
}
that
.
addJob
(
priv
.
fillDocumentRevisionProperties
(
doc
,
doc_tree
);
"
get
"
,
return
priv
.
getDocument
(
doc
,
option
,
callback
.
getDocument
);
priv
.
substorage
,
docid
+
priv
.
doctree_suffix
,
option
,
function
(
response
)
{
doctree
=
response
;
f
.
updateRevsInfo
();
f
.
getDocument
();
},
function
(
err
)
{
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
;
}
}
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
)
{
prev_doc
=
{
"
_id
"
:
doc
.
_id
,
"
_rev
"
:
doc
.
_revs_info
[
1
].
rev
};
};
f
.
getDocument
=
function
()
{
if
(
revs_info
[
1
]
===
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
"
;
// force revs_info status
f
.
error
(
err
);
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
.
updateRevsInfo
=
function
()
{
callback
.
getDocument
=
function
(
err
,
res_doc
)
{
if
(
doc
.
_revs
)
{
console
.
log
(
"
c getDocument
"
);
revs_info
=
priv
.
updateDocumentTree
(
doctree
,
doc
.
_revs
);
var
k
,
conflicts
;
}
else
{
if
(
err
)
{
revs_info
=
priv
.
postToDocumentTree
(
doctree
,
doc
);
if
(
err
.
status
===
404
)
{
if
(
specific_parameter
.
remove
||
specific_parameter
.
removeAttachment
)
{
return
onEnd
(
priv
.
conflictError
(
"
Document update conflict
"
,
"
Document is missing
"
),
undefined
);
}
if
(
specific_parameter
.
get
)
{
return
onEnd
(
priv
.
notFoundError
(
"
Unable to find the document
"
,
"
missing
"
),
undefined
);
}
}
};
res_doc
=
{};
f
.
postDocument
=
function
(
attachment_list
)
{
doc
.
_id
=
docid
+
"
.
"
+
revs_info
[
0
].
rev
;
delete
doc
.
_rev
;
delete
doc
.
_revs
;
that
.
addJob
(
"
post
"
,
priv
.
substorage
,
doc
,
command
.
cloneOption
(),
function
()
{
var
i
;
if
(
attachment_list
.
length
===
0
)
{
f
.
sendDocumentTree
();
}
else
{
}
else
{
f
.
send_document_tree_count
=
attachment_list
.
length
;
err
.
message
=
"
Cannot get document
"
;
for
(
i
=
0
;
i
<
attachment_list
.
length
;
i
+=
1
)
{
return
onEnd
(
err
,
undefined
);
f
.
copyAttachment
(
attachment_list
[
i
].
id
,
attachment_list
[
i
].
attachment
);
}
}
}
}
},
if
(
specific_parameter
.
get
)
{
function
(
err
)
{
res_doc
.
_id
=
doc
.
_id
;
switch
(
err
.
status
)
{
res_doc
.
_rev
=
doc
.
_rev
;
case
409
:
if
(
option
.
conflicts
===
true
)
{
// file already exists
conflicts
=
priv
.
getConflicts
(
doc
.
_rev
,
doc_tree
);
f
.
sendDocumentTree
();
if
(
conflicts
)
{
break
;
res_doc
.
_conflicts
=
conflicts
;
default
:
err
.
message
=
"
Cannot upload document
"
;
f
.
error
(
err
);
break
;
}
}
}
}
);
if
(
option
.
revs
===
true
)
{
};
res_doc
.
_revisions
=
doc
.
_revs
;
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
);
}
}
);
if
(
option
.
revs_info
===
true
)
{
},
res_doc
.
_revs_info
=
doc
.
_revs_info
;
function
(
err
)
{
err
.
message
=
"
Cannot get previous attachment
"
;
f
.
error
(
err
);
}
}
);
return
onEnd
(
undefined
,
res_doc
);
};
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
.
removeAttachment
)
{
that
.
addJob
(
// copy metadata (not beginning by "_" to document
"
put
"
,
for
(
k
in
res_doc
)
{
priv
.
substorage
,
if
(
res_doc
.
hasOwnProperty
(
k
)
&&
!
k
.
match
(
"
^_
"
))
{
doctree
,
doc
[
k
]
=
res_doc
[
k
];
command
.
cloneOption
(),
function
()
{
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
);
}
}
);
};
f
.
error
=
function
(
err
)
{
f
.
error
=
function
()
{};
that
.
error
(
err
);
};
f
.
getDocumentTree
();
};
/**
* 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
(
"
get
"
,
priv
.
substorage
,
command
.
getDocId
()
+
priv
.
doctree_suffix
,
option
,
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
;
}
}
}
}
);
if
(
specific_parameter
.
remove
)
{
};
priv
.
putDocumentTree
(
doc
,
option
,
doc_tree
,
callback
.
putDocumentTree
);
functions
.
updateRevsInfo
=
function
()
{
if
(
doc
.
_revs
)
{
revs_info
=
priv
.
updateDocumentTree
(
doctree
,
doc
.
_revs
);
}
else
{
}
else
{
revs_info
=
priv
.
postToDocumentTree
(
doctree
,
doc
);
console
.
log
(
"
res_doc
"
);
console
.
log
(
res_doc
);
priv
.
getAttachmentList
(
res_doc
,
option
,
callback
.
getAttachmentList
);
}
}
};
};
functions
.
postEmptyDocument
=
function
()
{
callback
.
getAttachmentList
=
function
(
err
,
res_list
)
{
that
.
addJob
(
console
.
log
(
"
c getAttachmentList
"
);
"
post
"
,
var
i
,
attachment_found
=
false
;
priv
.
substorage
,
if
(
err
)
{
{
"
_id
"
:
command
.
getDocId
()
+
"
.
"
+
revs_info
[
0
].
rev
},
err
.
message
=
"
Cannot get attachment
"
;
command
.
getOption
(),
return
onEnd
(
err
,
undefined
);
function
(
response
)
{
doc
.
_rev
=
response
.
rev
;
functions
.
postAttachment
();
},
function
(
err
)
{
err
.
message
=
"
Cannot upload document
"
;
that
.
error
(
err
);
}
}
);
attachment_list
=
res_list
||
[];
};
if
(
specific_parameter
.
getAttachment
)
{
functions
.
getDocument
=
function
()
{
// getting specific attachment
if
(
revs_info
[
1
]
===
undefined
)
{
for
(
i
=
0
;
i
<
attachment_list
.
length
;
i
+=
1
)
{
functions
.
postEmptyDocument
();
if
(
attachment_list
[
i
]
&&
}
else
{
doc
.
_attachment
===
that
.
addJob
(
attachment_list
[
i
].
_attachment
)
{
"
get
"
,
return
onEnd
(
attachment_list
[
i
].
_data
);
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
}});
}
}
functions
.
postDocument
(
attachment_list
);
},
function
(
err
)
{
if
(
err
.
status
===
404
)
{
functions
.
postDocument
([]);
return
;
}
}
err
.
message
=
"
Cannot upload document
"
;
that
.
error
(
err
);
}
}
);
return
onEnd
(
priv
.
notFoundError
(
"
Unable to get an inexistent attachment
"
,
"
missing
"
),
undefined
);
}
}
};
if
(
specific_parameter
.
remove_from_attachment_list
)
{
functions
.
postDocument
=
function
(
attachment_list
)
{
// removing specific attachment
that
.
addJob
(
"
post
"
,
priv
.
substorage
,
command
.
getDocId
()
+
"
.
"
+
revs_info
[
0
].
rev
,
command
.
getOption
(),
function
(
response
)
{
var
i
;
if
(
attachment_list
.
length
===
0
)
{
functions
.
postAttachment
();
}
else
{
functions
.
post_attachment_count
=
attachment_list
.
length
;
for
(
i
=
0
;
i
<
attachment_list
.
length
;
i
+=
1
)
{
for
(
i
=
0
;
i
<
attachment_list
.
length
;
i
+=
1
)
{
functions
.
copyAttachment
(
attachment_list
[
i
].
id
,
if
(
attachment_list
[
i
]
&&
attachment_list
[
i
].
attachment
);
specific_parameter
.
remove_from_attachment_list
.
_attachment
===
}
attachment_list
[
i
].
_attachment
)
{
attachment_found
=
true
;
attachment_list
[
i
]
=
undefined
;
break
;
}
}
},
function
(
err
)
{
err
.
message
=
"
Cannot upload document
"
;
that
.
error
(
err
);
}
}
);
if
(
!
attachment_found
)
{
};
return
onEnd
(
priv
.
notFoundError
(
functions
.
copyAttachment
=
function
(
attachmentid
,
attachment
)
{
"
Unable to remove an inexistent attachment
"
,
that
.
addJob
(
"
missing
"
"
get
"
,
),
undefined
);
priv
.
substorage
,
prev_doc
.
_id
+
"
/
"
+
attachmentid
,
command
.
cloneOption
(),
function
(
response
)
{
attachment
.
_data
=
response
;
that
.
addJob
(
"
putAttachment
"
,
priv
.
substorage
,
attachment
,
command
.
cloneOption
(),
function
(
response
)
{
functions
.
postAttachment
();
},
function
(
err
)
{
err
.
message
=
"
Cannot copy previous attachment
"
;
functions
.
error
(
err
);
}
}
);
},
function
(
err
)
{
err
.
message
=
"
Cannot copy previous attachment
"
;
functions
.
error
(
err
);
}
}
);
priv
.
putDocument
(
doc
,
option
,
callback
.
putDocument
);
};
};
functions
.
post_attachment_count
=
0
;
callback
.
putDocument
=
function
(
err
,
response
)
{
functions
.
postAttachment
=
function
()
{
console
.
log
(
"
c putDocument
"
);
functions
.
post_attachment_count
-=
1
;
var
i
,
attachment_found
=
false
;
if
(
functions
.
post_attachment_count
>
0
)
{
if
(
err
)
{
return
;
err
.
message
=
"
Cannot post the document
"
;
return
onEnd
(
err
,
undefined
);
}
}
that
.
addJob
(
if
(
specific_parameter
.
add_to_attachment_list
)
{
"
putAttachment
"
,
// adding specific attachment
priv
.
substorage
,
attachment_list
=
attachment_list
||
[];
{
for
(
i
=
0
;
i
<
attachment_list
.
length
;
i
+=
1
)
{
"
_id
"
:
command
.
getDocId
()
+
"
.
"
+
revs_info
[
0
].
rev
+
"
/
"
+
if
(
specific_parameter
.
add_to_attachment_list
.
_attachment
===
command
.
getAttachmentId
(),
attachment_list
[
i
].
_attachment
)
{
"
_mimetype
"
:
command
.
getAttachmentMimeType
(),
attachment_found
=
true
;
"
_data
"
:
command
.
getAttachmentData
()
attachment_list
[
i
]
=
specific_parameter
.
add_to_attachment_list
;
},
command
.
cloneOption
(),
function
()
{
functions
.
sendDocumentTree
();
},
function
(
err
)
{
switch
(
err
.
status
)
{
case
409
:
// file already exists
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
);
}
}
priv
.
putAttachmentList
(
doc
,
option
,
attachment_list
,
callback
.
putAttachmentList
);
);
};
};
functions
.
sendDocumentTree
=
function
()
{
callback
.
putAttachmentList
=
function
(
err
,
response
)
{
doctree
.
_id
=
command
.
getDocId
()
+
priv
.
doctree_suffix
;
console
.
log
(
"
c putAttachmentList
"
);
that
.
addJob
(
if
(
err
)
{
"
put
"
,
err
.
message
=
"
Cannot copy attacments to the document
"
;
priv
.
substorage
,
return
onEnd
(
err
,
undefined
);
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
.
putDocumentTree
(
doc
,
option
,
doc_tree
,
callback
.
putDocumentTree
);
};
};
functions
.
error
=
function
(
err
)
{
callback
.
putDocumentTree
=
function
(
err
,
response
)
{
functions
.
error
=
function
()
{};
console
.
log
(
"
c putDocumentTree
"
);
that
.
error
(
err
);
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
);
that
.
success
(
response
);
},
function
(
err
)
{
that
.
error
(
err
);
}
}
);
);
};
};
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
)
{
if
(
err
)
{
return
that
.
error
(
err
);
}
that
.
success
(
response
);
}
}
del_rev
=
command
.
getDoc
().
_rev
;
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
,
that
.
putAttachment
=
function
(
command
)
{
docid
,
priv
.
revisionGenericRequest
(
option
,
command
.
cloneDoc
(),
function
()
{
// put tree
doctree
.
_id
=
command
.
getDocId
()
+
priv
.
doctree_suffix
;
that
.
addJob
(
"
put
"
,
priv
.
substorage
,
doctree
,
command
.
cloneOption
(),
command
.
cloneOption
(),
function
()
{
{
that
.
success
({
"
doc_id
"
:
command
.
getDocId
(),
"
ok
"
:
true
,
"
attachment_id
"
:
command
.
getAttachmentId
(),
"
id
"
:
command
.
getDocId
(),
"
add_to_attachment_list
"
:
{
"
rev
"
:
revs_info
[
0
].
rev
"
_attachment
"
:
command
.
getAttachmentId
(),
});
"
_mimetype
"
:
command
.
getAttachmentMimeType
(),
"
_data
"
:
command
.
getAttachmentData
()
},
},
function
()
{
"
putAttachment
"
:
true
that
.
error
({
"
status
"
:
409
,
"
statusText
"
:
"
Conflict
"
,
"
error
"
:
"
conflict
"
,
"
message
"
:
"
Document update conflict.
"
,
"
reason
"
:
"
Cannot update document tree
"
});
return
;
}
);
},
},
function
()
{
function
(
err
,
response
)
{
that
.
error
({
if
(
err
)
{
"
status
"
:
404
,
return
that
.
error
(
err
);
"
statusText
"
:
"
Not Found
"
,
}
"
error
"
:
"
not_found
"
,
that
.
success
(
response
);
"
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
.
remove
=
function
(
command
)
{
that
.
addJob
(
if
(
command
.
getAttachmentId
())
{
"
post
"
,
return
that
.
removeAttachment
(
command
);
priv
.
substorage
,
}
new_doc
,
priv
.
revisionGenericRequest
(
command
.
cloneOption
(),
command
.
cloneDoc
(),
function
()
{
// put tree
doctree
.
_id
=
command
.
getDocId
()
+
priv
.
doctree_suffix
;
that
.
addJob
(
"
put
"
,
priv
.
substorage
,
doctree
,
command
.
cloneOption
(),
command
.
cloneOption
(),
function
()
{
{
that
.
success
({
"
revision_needed
"
:
true
,
"
ok
"
:
true
,
"
remove
"
:
true
"
id
"
:
new_doc
.
_id
,
"
rev
"
:
revs_info
[
0
].
rev
});
},
},
function
(
err
)
{
function
(
err
,
response
)
{
err
.
message
=
if
(
err
)
{
"
Cannot save document revision tree
"
;
return
that
.
error
(
err
);
that
.
error
(
err
);
}
}
);
that
.
success
(
response
);
},
function
()
{
that
.
error
({
"
status
"
:
409
,
"
statusText
"
:
"
Conflict
"
,
"
error
"
:
"
conflict
"
,
"
message
"
:
"
Document update conflict.
"
,
"
reason
"
:
"
Cannot update document
"
});
return
;
}
}
);
);
},
};
function
()
{
that
.
error
({
that
.
removeAttachment
=
function
(
command
)
{
"
status
"
:
404
,
priv
.
revisionGenericRequest
(
"
statusText
"
:
"
Not Found
"
,
command
.
cloneDoc
(),
"
error
"
:
"
not_found
"
,
command
.
cloneOption
(),
"
message
"
:
"
File not found
"
,
{
"
reason
"
:
"
Document was not found
"
"
doc_id
"
:
command
.
getDocId
(),
});
"
attachment_id
"
:
command
.
getAttachmentId
(),
return
;
"
revision_needed
"
:
true
,
"
removeAttachment
"
:
true
,
"
remove_from_attachment_list
"
:
{
"
_attachment
"
:
command
.
getAttachmentId
()
}
}
);
},
function
(
err
,
response
)
{
if
(
err
)
{
return
that
.
error
(
err
);
}
}
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
.
get
=
function
(
command
)
{
that
.
addJob
(
if
(
command
.
getAttachmentId
())
{
"
get
"
,
return
that
.
getAttachment
(
command
);
priv
.
substorage
,
command
.
getDocId
()
+
priv
.
doctree_suffix
,
option
,
function
(
response
)
{
response
.
_conflicts
=
priv
.
getLeavesFromDocumentTree
(
response
);
if
(
del_rev
===
undefined
)
{
// no revision provided
that
.
error
({
"
status
"
:
409
,
"
statusText
"
:
"
Conflict
"
,
"
error
"
:
"
conflict
"
,
"
message
"
:
"
Document update conflict.
"
,
"
reason
"
:
"
Cannot delete a document without revision
"
});
return
;
}
// revision provided
if
(
priv
.
isRevisionALeaf
(
response
,
del_rev
)
===
true
)
{
if
(
typeof
command
.
getAttachmentId
()
===
"
string
"
)
{
f
.
removeDocument
(
command
.
getDocId
()
+
"
.
"
+
del_rev
+
"
/
"
+
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
;
}
}
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,7 +34,12 @@ clone = function (obj) {
...
@@ -34,7 +34,12 @@ 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
;
doc
=
clone
(
doc
);
delete
doc
.
_rev
;
delete
doc
.
_revs
;
delete
doc
.
_revs_info
;
string
=
JSON
.
stringify
(
doc
)
+
JSON
.
stringify
(
revisions
)
+
JSON
.
stringify
(
deleted_flag
?
true
:
false
);
JSON
.
stringify
(
deleted_flag
?
true
:
false
);
return
hex_sha256
(
string
);
return
hex_sha256
(
string
);
},
},
...
@@ -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
"
,
"
revpos
"
:
1
"
content_type
"
:
"
oh/yeah
"
},
}
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
({
"
rev
"
:
"
4-
"
+
o
.
rev_hash
,
"
status
"
:
"
deleted
"
,
"
status
"
:
"
deleted
"
,
"
children
"
:
[]
"
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