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
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Xiaowu Zhang
jio
Commits
d54f3480
Commit
d54f3480
authored
Mar 11, 2013
by
Tristan Cavelier
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'replicaterevisionstorage2'
parents
c048fd03
8e7efe86
Changes
6
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
2176 additions
and
1645 deletions
+2176
-1645
src/jio.storage/replicaterevisionstorage.js
src/jio.storage/replicaterevisionstorage.js
+477
-289
src/jio.storage/revisionstorage.js
src/jio.storage/revisionstorage.js
+708
-1072
src/jio/commands/command.js
src/jio/commands/command.js
+4
-1
src/jio/jio.core.js
src/jio/jio.core.js
+65
-5
src/jio/storages/storage.js
src/jio/storages/storage.js
+12
-0
test/jiotests.js
test/jiotests.js
+910
-278
No files found.
src/jio.storage/replicaterevisionstorage.js
View file @
d54f3480
...
@@ -20,13 +20,11 @@ jIO.addStorageType('replicaterevision', function (spec, my) {
...
@@ -20,13 +20,11 @@ jIO.addStorageType('replicaterevision', function (spec, my) {
priv
.
storage_list_key
=
"
storage_list
"
;
priv
.
storage_list_key
=
"
storage_list
"
;
priv
.
storage_list
=
spec
[
priv
.
storage_list_key
];
priv
.
storage_list
=
spec
[
priv
.
storage_list_key
];
my
.
env
=
my
.
env
||
spec
.
env
||
{};
priv
.
emptyFunction
=
function
()
{};
priv
.
emptyFunction
=
function
()
{};
that
.
specToStore
=
function
()
{
that
.
specToStore
=
function
()
{
var
o
=
{};
var
o
=
{};
o
[
priv
.
storage_list_key
]
=
priv
.
storage_list
;
o
[
priv
.
storage_list_key
]
=
priv
.
storage_list
;
o
.
env
=
my
.
env
;
return
o
;
return
o
;
};
};
...
@@ -68,21 +66,6 @@ jIO.addStorageType('replicaterevision', function (spec, my) {
...
@@ -68,21 +66,6 @@ jIO.addStorageType('replicaterevision', function (spec, my) {
return
newlist
;
return
newlist
;
};
};
/**
* Generates the next revision
* @method generateNextRevision
* @param {number|string} previous_revision The previous revision
* @param {string} docid The document id
* @return {string} The next revision
*/
priv
.
generateNextRevision
=
function
(
previous_revision
,
docid
)
{
my
.
env
[
docid
].
id
+=
1
;
if
(
typeof
previous_revision
===
"
string
"
)
{
previous_revision
=
parseInt
(
previous_revision
.
split
(
"
-
"
)[
0
],
10
);
}
return
(
previous_revision
+
1
)
+
"
-
"
+
my
.
env
[
docid
].
id
.
toString
();
};
/**
/**
* Checks a revision format
* Checks a revision format
* @method checkRevisionFormat
* @method checkRevisionFormat
...
@@ -93,34 +76,6 @@ jIO.addStorageType('replicaterevision', function (spec, my) {
...
@@ -93,34 +76,6 @@ jIO.addStorageType('replicaterevision', function (spec, my) {
return
(
/^
[
0-9
]
+-
[
0-9a-zA-Z_
]
+$/
.
test
(
revision
));
return
(
/^
[
0-9
]
+-
[
0-9a-zA-Z_
]
+$/
.
test
(
revision
));
};
};
/**
* Initalize document environment object
* @method initEnv
* @param {string} docid The document id
* @return {object} The reference to the environment
*/
priv
.
initEnv
=
function
(
docid
)
{
my
.
env
[
docid
]
=
{
"
id
"
:
0
,
"
distant_revisions
"
:
{},
"
my_revisions
"
:
{},
"
last_revisions
"
:
[]
};
return
my
.
env
[
docid
];
};
priv
.
updateEnv
=
function
(
doc_env
,
doc_env_rev
,
index
,
doc_rev
)
{
doc_env
.
last_revisions
[
index
]
=
doc_rev
;
if
(
doc_rev
!==
undefined
)
{
if
(
!
doc_env
.
my_revisions
[
doc_env_rev
])
{
doc_env
.
my_revisions
[
doc_env_rev
]
=
[];
doc_env
.
my_revisions
[
doc_env_rev
].
length
=
priv
.
storage_list
.
length
;
}
doc_env
.
my_revisions
[
doc_env_rev
][
index
]
=
doc_rev
;
doc_env
.
distant_revisions
[
doc_rev
]
=
doc_env_rev
;
}
};
/**
/**
* Clones an object in deep (without functions)
* Clones an object in deep (without functions)
* @method clone
* @method clone
...
@@ -188,106 +143,490 @@ jIO.addStorageType('replicaterevision', function (spec, my) {
...
@@ -188,106 +143,490 @@ jIO.addStorageType('replicaterevision', function (spec, my) {
};
};
/**
/**
* Post the document metadata to all sub storages
* Use "send" method to all sub storages.
* @method post
* Calling "callback" only with the first response
* @param {object} command The JIO command
* @method sendToAllFastestResponseOnly
* @param {string} method The request method
* @param {object} doc The document object
* @param {object} option The request option
* @param {function} callback The callback. Parameters:
* - {string} The request method
* - {object} The error object
* - {object} The response object
*/
*/
that
.
post
=
function
(
command
)
{
priv
.
sendToAllFastestResponseOnly
=
function
(
method
,
doc
,
option
,
callback
)
{
var
functions
=
{},
doc_env
,
revs_info
,
doc
,
my_rev
;
var
i
,
callbackWrapper
,
error_count
,
last_error
;
functions
.
begin
=
function
()
{
error_count
=
0
;
doc
=
command
.
cloneDoc
();
callbackWrapper
=
function
(
method
,
index
,
err
,
response
)
{
if
(
err
)
{
error_count
+=
1
;
last_error
=
err
;
if
(
error_count
===
priv
.
storage_list
.
length
)
{
return
callback
(
method
,
err
,
response
);
}
}
callback
(
method
,
err
,
response
);
};
for
(
i
=
0
;
i
<
priv
.
storage_list
.
length
;
i
+=
1
)
{
priv
.
send
(
method
,
i
,
doc
,
option
,
callbackWrapper
);
}
};
if
(
typeof
doc
.
_rev
===
"
string
"
&&
!
priv
.
checkRevisionFormat
(
doc
.
_rev
))
{
/**
that
.
error
({
* Use "sendToAll" method, calling "callback" at the last response with
"
status
"
:
31
,
* the response list
"
statusText
"
:
"
Wrong Revision Format
"
,
* @method sendToAllGetResponseList
"
error
"
:
"
wrong_revision_format
"
,
* @param {string} method The request method
"
message
"
:
"
The document previous revision does not match
"
+
* @param {object} doc The document object
"
^[0-9]+-[0-9a-zA-Z]+$
"
,
* @param {object} option The request option
"
reason
"
:
"
Previous revision is wrong
"
* @return {function} callback The callback. Parameters:
});
* - {string} The request method
return
;
* - {object} The error object
* - {object} The response object
*/
priv
.
sendToAllGetResponseList
=
function
(
method
,
doc
,
option
,
callback
)
{
var
wrapper
,
callback_count
=
0
,
response_list
=
[],
error_list
=
[];
response_list
.
length
=
priv
.
storage_list
.
length
;
wrapper
=
function
(
method
,
index
,
err
,
response
)
{
error_list
[
index
]
=
err
;
response_list
[
index
]
=
response
;
callback_count
+=
1
;
if
(
callback_count
===
priv
.
storage_list
.
length
)
{
callback
(
error_list
,
response_list
);
}
}
if
(
typeof
doc
.
_id
!==
"
string
"
)
{
};
doc
.
_id
=
priv
.
generateUuid
();
priv
.
sendToAll
(
method
,
doc
,
option
,
wrapper
);
};
/**
* Checks if the sub storage are identical
* @method check
* @param {object} command The JIO command
*/
that
.
check
=
function
(
command
)
{
function
callback
(
err
,
response
)
{
if
(
err
)
{
return
that
.
error
(
err
);
}
that
.
success
(
response
);
}
}
if
(
priv
.
post_allowed
===
undefined
)
{
priv
.
check
(
priv
.
post_allowed
=
true
;
command
.
cloneDoc
(),
command
.
cloneOption
(),
callback
);
};
/**
* Repair the sub storages to make them identical
* @method repair
* @param {object} command The JIO command
*/
that
.
repair
=
function
(
command
)
{
function
callback
(
err
,
response
)
{
if
(
err
)
{
return
that
.
error
(
err
);
}
}
doc_env
=
my
.
env
[
doc
.
_id
];
that
.
success
(
response
);
if
(
!
doc_env
||
!
doc_env
.
id
)
{
doc_env
=
priv
.
initEnv
(
doc
.
_id
);
}
}
my_rev
=
priv
.
generateNextRevision
(
doc
.
_rev
||
0
,
doc
.
_id
);
priv
.
repair
(
functions
.
sendDocument
();
command
.
cloneDoc
(),
command
.
cloneOption
(),
true
,
callback
);
};
};
functions
.
sendDocument
=
function
()
{
var
i
,
cloned_doc
;
priv
.
check
=
function
(
doc
,
option
,
success
,
error
)
{
priv
.
repair
(
doc
,
option
,
false
,
success
,
error
);
};
priv
.
repair
=
function
(
doc
,
option
,
repair
,
callback
)
{
var
functions
=
{};
callback
=
callback
||
priv
.
emptyFunction
;
option
=
option
||
{};
functions
.
begin
=
function
()
{
// };
// functions.repairAllSubStorages = function () {
var
i
;
for
(
i
=
0
;
i
<
priv
.
storage_list
.
length
;
i
+=
1
)
{
for
(
i
=
0
;
i
<
priv
.
storage_list
.
length
;
i
+=
1
)
{
cloned_doc
=
priv
.
clone
(
doc
);
if
(
typeof
cloned_doc
.
_rev
===
"
string
"
&&
doc_env
.
my_revisions
[
cloned_doc
.
_rev
]
!==
undefined
)
{
cloned_doc
.
_rev
=
doc_env
.
my_revisions
[
cloned_doc
.
_rev
][
i
];
}
priv
.
send
(
priv
.
send
(
doc_env
.
last_revisions
[
i
]
===
"
unique_
"
+
i
||
repair
?
"
repair
"
:
"
check
"
,
priv
.
put_only
?
"
put
"
:
"
post
"
,
i
,
i
,
cloned_
doc
,
doc
,
command
.
cloneOption
()
,
option
,
functions
.
checkSendResult
functions
.
repairAllSubStoragesCallback
);
);
}
}
};
};
functions
.
checkSendResult
=
function
(
method
,
index
,
err
,
response
)
{
functions
.
repair_sub_storages_count
=
0
;
functions
.
repairAllSubStoragesCallback
=
function
(
method
,
index
,
err
,
response
)
{
if
(
err
)
{
if
(
err
)
{
if
(
err
.
status
===
409
)
{
return
that
.
error
(
err
);
if
(
method
!==
"
put
"
)
{
}
functions
.
sendDocumentIndex
(
functions
.
repair_sub_storages_count
+=
1
;
"
put
"
,
if
(
functions
.
repair_sub_storages_count
===
priv
.
storage_list
.
length
)
{
index
,
functions
.
getAllDocuments
(
functions
.
newParam
(
functions
.
checkSendResult
doc
,
option
,
repair
));
}
};
functions
.
newParam
=
function
(
doc
,
option
,
repair
)
{
var
param
=
{
"
doc
"
:
doc
,
// the document to repair
"
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]]
],
"
attachments
"
:
{
// attachmentA : {_id: attachmentA, _revs_info, _mimetype: ..}
// attachmentB : {_id: attachmentB, _revs_info, _mimetype: ..}
}
},
"
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
)
{
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
)
{
return
function
(
method
,
index
,
err
,
response
)
{
var
response_object
=
{};
if
(
param
.
deal_result_state
!==
"
ok
"
)
{
// deal result is in a wrong state, exit
return
;
}
if
(
err
)
{
if
(
err
.
status
!==
404
)
{
// get document failed, exit
param
.
deal_result_state
=
"
error
"
;
callback
({
"
status
"
:
40
,
"
statusText
"
:
"
Check Failed
"
,
"
error
"
:
"
check_failed
"
,
"
message
"
:
"
An error occured on the sub storage
"
,
"
reason
"
:
err
.
reason
},
undefined
);
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
return
;
}
// this is now the last response
functions
.
makeResponsesStats
(
param
.
responses
);
if
(
param
.
responses
.
stats_items
.
length
===
1
)
{
// the responses are equals!
response_object
.
ok
=
true
;
response_object
.
id
=
param
.
doc
.
_id
;
if
(
doc
.
_rev
)
{
response_object
.
rev
=
doc
.
_rev
;
// "rev": (typeof param.responses.list[0] === "object" ?
// param.responses.list[0]._rev : undefined)
}
callback
(
undefined
,
response_object
);
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
"
},
undefined
);
return
;
}
// repair
functions
.
getAttachments
(
param
);
};
};
functions
.
addConflicts
=
function
(
param
,
list
)
{
var
i
;
list
=
list
||
[];
for
(
i
=
0
;
i
<
list
.
length
;
i
+=
1
)
{
param
.
conflicts
[
list
[
i
]]
=
true
;
}
};
functions
.
makeResponsesStats
=
function
(
responses
)
{
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
.
getAttachments
=
function
(
param
)
{
var
response
,
parsed_response
,
attachment
;
for
(
response
in
param
.
responses
.
stats
)
{
if
(
param
.
responses
.
stats
.
hasOwnProperty
(
response
))
{
parsed_response
=
JSON
.
parse
(
response
);
for
(
attachment
in
parsed_response
.
_attachments
)
{
if
((
parsed_response
.
_attachments
).
hasOwnProperty
(
attachment
))
{
functions
.
get_attachment_count
+=
1
;
priv
.
send
(
"
get
"
,
param
.
responses
.
stats
[
response
][
0
],
{
"
_id
"
:
param
.
doc
.
_id
+
"
/
"
+
attachment
,
"
_rev
"
:
JSON
.
parse
(
response
).
_rev
},
param
.
option
,
functions
.
getAttachmentsCallback
(
param
,
attachment
,
param
.
responses
.
stats
[
response
]
)
);
);
}
}
}
}
};
functions
.
get_attachment_count
=
0
;
functions
.
getAttachmentsCallback
=
function
(
param
,
attachment_id
,
index_list
)
{
return
function
(
method
,
index
,
err
,
response
)
{
if
(
err
)
{
callback
({
"
status
"
:
40
,
"
statusText
"
:
"
Check Failed
"
,
"
error
"
:
"
check_failed
"
,
"
message
"
:
"
Unable to retreive attachments
"
,
"
reason
"
:
err
.
reason
},
undefined
);
return
;
return
;
}
}
functions
.
get_attachment_count
-=
1
;
param
.
responses
.
attachments
[
attachment_id
]
=
response
;
if
(
functions
.
get_attachment_count
===
0
)
{
functions
.
synchronizeAllSubStorage
(
param
);
if
(
param
.
option
.
synchronize_conflicts
!==
false
)
{
functions
.
synchronizeConflicts
(
param
);
}
}
};
};
functions
.
synchronizeAllSubStorage
=
function
(
param
)
{
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
]
);
}
}
}
priv
.
updateEnv
(
doc_env
,
my_rev
,
index
,
null
);
}
functions
.
error
(
err
);
functions
.
finished_count
-=
1
;
};
functions
.
synchronizeResponseToSubStorage
=
function
(
param
,
response
,
storage_list
)
{
var
i
,
new_doc
,
attachment_to_put
=
[];
if
(
response
===
undefined
)
{
// no response to sync
return
;
return
;
}
}
// success
new_doc
=
JSON
.
parse
(
response
);
priv
.
updateEnv
(
new_doc
.
_revs
=
new_doc
.
_revisions
;
doc_env
,
delete
new_doc
.
_rev
;
my_rev
,
delete
new_doc
.
_revisions
;
delete
new_doc
.
_conflicts
;
for
(
i
in
new_doc
.
_attachments
)
{
if
(
new_doc
.
_attachments
.
hasOwnProperty
(
i
))
{
attachment_to_put
.
push
({
"
_id
"
:
i
,
"
_mimetype
"
:
new_doc
.
_attachments
[
i
].
content_type
,
"
_revs_info
"
:
new_doc
.
_revs_info
});
}
}
for
(
i
=
0
;
i
<
storage_list
.
length
;
i
+=
1
)
{
functions
.
finished_count
+=
attachment_to_put
.
length
||
1
;
priv
.
send
(
"
put
"
,
storage_list
[
i
],
new_doc
,
param
.
option
,
functions
.
putAttachments
(
param
,
attachment_to_put
)
);
}
functions
.
finished_count
+=
1
;
functions
.
finished
();
};
functions
.
synchronizeConflicts
=
function
(
param
)
{
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
.
putAttachments
=
function
(
param
,
attachment_to_put
)
{
return
function
(
method
,
index
,
err
,
response
)
{
var
i
,
attachment
;
if
(
err
)
{
return
callback
({
"
status
"
:
40
,
"
statusText
"
:
"
Check Failed
"
,
"
error
"
:
"
check_failed
"
,
"
message
"
:
"
Unable to copy attachments
"
,
"
reason
"
:
err
.
reason
},
undefined
);
}
for
(
i
=
0
;
i
<
attachment_to_put
.
length
;
i
+=
1
)
{
attachment
=
{
"
_id
"
:
param
.
doc
.
_id
,
"
_attachment
"
:
attachment_to_put
[
i
].
_id
,
"
_mimetype
"
:
attachment_to_put
[
i
].
_mimetype
,
"
_revs_info
"
:
attachment_to_put
[
i
].
_revs_info
,
// "_revs_info": param.responses.list[index]._revs_info,
"
_data
"
:
param
.
responses
.
attachments
[
attachment_to_put
[
i
].
_id
]
};
attachment
.
_id
+=
"
/
"
+
attachment
.
_attachment
;
delete
attachment
.
_attachment
;
priv
.
send
(
"
putAttachment
"
,
index
,
index
,
response
.
rev
||
"
unique_
"
+
index
attachment
,
option
,
functions
.
putAttachmentCallback
(
param
)
);
);
functions
.
success
({
"
ok
"
:
true
,
"
id
"
:
doc
.
_id
,
"
rev
"
:
my_rev
});
}
if
(
attachment_to_put
.
length
===
0
)
{
functions
.
finished
();
}
};
};
functions
.
putAttachmentCallback
=
function
(
param
)
{
return
function
(
method
,
index
,
err
,
response
)
{
if
(
err
)
{
return
callback
(
err
,
undefined
);
}
functions
.
finished
();
};
};
functions
.
success
=
function
(
response
)
{
// can be called once
that
.
success
(
response
);
functions
.
success
=
priv
.
emptyFunction
;
};
};
functions
.
error_count
=
0
;
functions
.
finished_count
=
0
;
functions
.
error
=
function
(
err
)
{
functions
.
finished
=
function
()
{
functions
.
error_count
+=
1
;
var
response_object
=
{};
if
(
functions
.
error_count
===
priv
.
storage_list
.
length
)
{
functions
.
finished_count
-=
1
;
that
.
error
(
err
);
if
(
functions
.
finished_count
===
0
)
{
functions
.
error
=
priv
.
emptyFunction
;
response_object
.
ok
=
true
;
response_object
.
id
=
doc
.
_id
;
if
(
doc
.
_rev
)
{
response_object
.
rev
=
doc
.
_rev
;
}
callback
(
undefined
,
response_object
);
}
}
};
};
functions
.
begin
();
functions
.
begin
();
};
};
/**
* The generic method to use
* @method genericRequest
* @param {object} command The JIO command
* @param {string} method The method to use
*/
that
.
genericRequest
=
function
(
command
,
method
)
{
var
doc
=
command
.
cloneDoc
();
doc
.
_id
=
doc
.
_id
||
priv
.
generateUuid
();
priv
.
sendToAllFastestResponseOnly
(
method
,
doc
,
command
.
cloneOption
(),
function
(
method
,
err
,
response
)
{
if
(
err
)
{
return
that
.
error
(
err
);
}
that
.
success
(
response
);
}
);
};
/**
* Post the document metadata to all sub storages
* @method post
* @param {object} command The JIO command
*/
that
.
post
=
function
(
command
)
{
that
.
genericRequest
(
command
,
"
put
"
);
};
/**
/**
* Put the document metadata to all sub storages
* Put the document metadata to all sub storages
* @method put
* @method put
* @param {object} command The JIO command
* @param {object} command The JIO command
*/
*/
that
.
put
=
function
(
command
)
{
that
.
put
=
function
(
command
)
{
priv
.
put_only
=
true
;
that
.
genericRequest
(
command
,
"
post
"
);
that
.
post
(
command
);
};
};
/**
/**
...
@@ -295,195 +634,44 @@ jIO.addStorageType('replicaterevision', function (spec, my) {
...
@@ -295,195 +634,44 @@ jIO.addStorageType('replicaterevision', function (spec, my) {
* @method putAttachment
* @method putAttachment
* @param {object} command The JIO command
* @param {object} command The JIO command
*/
*/
//
that.putAttachment = function (command) {
that
.
putAttachment
=
function
(
command
)
{
that
.
genericRequest
(
command
,
"
putAttachment
"
);
//
};
};
/**
/**
* Get the document
or attachment
from all sub storages, get the fastest.
* Get the document from all sub storages, get the fastest.
* @method get
* @method get
* @param {object} command The JIO command
* @param {object} command The JIO command
*/
*/
that
.
get
=
function
(
command
)
{
that
.
get
=
function
(
command
)
{
var
functions
=
{},
doc_env
,
doc
,
my_rev
,
revs_array
=
[];
that
.
genericRequest
(
command
,
"
get
"
);
functions
.
begin
=
function
()
{
var
i
;
doc
=
command
.
cloneDoc
();
doc_env
=
my
.
env
[
doc
.
_id
];
if
(
!
doc_env
||
!
doc_env
.
id
)
{
// document environment is not set
doc_env
=
priv
.
initEnv
(
doc
.
_id
);
}
// document environment is set now
revs_array
.
length
=
priv
.
storage_list
.
length
;
my_rev
=
doc
.
_rev
;
if
(
my_rev
)
{
functions
.
update_env
=
false
;
}
for
(
i
=
0
;
i
<
priv
.
storage_list
.
length
;
i
+=
1
)
{
// request all sub storages
if
(
doc_env
.
my_revisions
[
my_rev
])
{
// if my_rev exist, convert it to distant revision
doc
.
_rev
=
doc_env
.
my_revisions
[
my_rev
][
i
];
}
priv
.
send
(
"
get
"
,
i
,
doc
,
command
.
cloneOption
(),
functions
.
callback
);
}
};
functions
.
update_env
=
true
;
functions
.
callback
=
function
(
method
,
index
,
err
,
response
)
{
if
(
err
)
{
revs_array
[
index
]
=
null
;
functions
.
error
(
err
);
return
;
}
doc_env
.
last_revisions
[
index
]
=
response
.
_rev
||
"
unique_
"
+
index
;
revs_array
[
index
]
=
response
.
_rev
||
"
unique_
"
+
index
;
if
(
doc_env
.
distant_revisions
[
response
.
_rev
||
"
unique_
"
+
index
])
{
// the document revision is already known
if
(
functions
.
update_env
===
true
)
{
my_rev
=
doc_env
.
distant_revisions
[
response
.
_rev
||
"
unique_
"
+
index
];
}
}
else
{
// the document revision is unknown
if
(
functions
.
update_env
===
true
)
{
my_rev
=
priv
.
generateNextRevision
(
0
,
doc
.
_id
);
doc_env
.
my_revisions
[
my_rev
]
=
revs_array
;
doc_env
.
distant_revisions
[
response
.
_rev
||
"
unique_
"
+
index
]
=
my_rev
;
}
functions
.
update_env
=
false
;
}
response
.
_rev
=
my_rev
;
functions
.
success
(
response
);
};
functions
.
success
=
function
(
response
)
{
var
i
,
start
,
tmp
,
tmp_object
;
functions
.
success
=
priv
.
emptyFunction
;
if
(
doc_env
.
my_revisions
[
my_rev
])
{
// this was not a specific revision
// we can convert revisions recieved by the sub storage
if
(
response
.
_conflicts
)
{
// convert conflicting revisions to replicate revisions
tmp_object
=
{};
for
(
i
=
0
;
i
<
response
.
_conflicts
.
length
;
i
+=
1
)
{
tmp_object
[
doc_env
.
distant_revisions
[
response
.
_conflicts
[
i
]]
||
response
.
_conflicts
[
i
]]
=
true
;
}
response
.
_conflicts
=
priv
.
dictKeys2Array
(
tmp_object
);
}
if
(
response
.
_revisions
)
{
// convert revisions history to replicate revisions
tmp_object
=
{};
start
=
response
.
_revisions
.
start
;
for
(
i
=
0
;
i
<
response
.
_revisions
.
ids
.
length
;
i
+=
1
,
start
-=
1
)
{
tmp
=
doc_env
.
distant_revisions
[
start
+
"
-
"
+
response
.
_revisions
.
ids
[
i
]
];
if
(
tmp
)
{
response
.
_revisions
.
ids
[
i
]
=
tmp
.
split
(
"
-
"
).
slice
(
1
).
join
(
"
-
"
);
}
}
}
if
(
response
.
_revs_info
)
{
// convert revs info to replicate revisions
for
(
i
=
0
;
i
<
response
.
_revs_info
.
length
;
i
+=
1
)
{
tmp
=
doc_env
.
distant_revisions
[
response
.
_revs_info
[
i
].
rev
];
if
(
tmp
)
{
response
.
_revs_info
[
i
].
rev
=
tmp
;
}
}
}
}
that
.
success
(
response
);
};
functions
.
error_count
=
0
;
functions
.
error
=
function
(
err
)
{
functions
.
error_count
+=
1
;
if
(
functions
.
error_count
===
priv
.
storage_list
.
length
)
{
that
.
error
(
err
);
functions
.
error
=
priv
.
emptyFunction
;
}
};
};
functions
.
begin
();
/**
* Get the attachment from all sub storages, get the fastest.
* @method getAttachment
* @param {object} command The JIO command
*/
that
.
getAttachment
=
function
(
command
)
{
that
.
genericRequest
(
command
,
"
getAttachment
"
);
};
};
/**
/**
* Remove the document
or attachment
from all sub storages.
* Remove the document from all sub storages.
* @method remove
* @method remove
* @param {object} command The JIO command
* @param {object} command The JIO command
*/
*/
that
.
remove
=
function
(
command
)
{
that
.
remove
=
function
(
command
)
{
var
functions
=
{},
doc_env
,
revs_info
,
doc
,
my_rev
;
that
.
genericRequest
(
command
,
"
remove
"
);
functions
.
begin
=
function
()
{
doc
=
command
.
cloneDoc
();
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
;
}
doc_env
=
my
.
env
[
doc
.
_id
];
if
(
!
doc_env
||
!
doc_env
.
id
)
{
doc_env
=
priv
.
initEnv
(
doc
.
_id
);
}
my_rev
=
priv
.
generateNextRevision
(
doc
.
_rev
||
0
,
doc
.
_id
);
functions
.
sendDocument
();
};
functions
.
sendDocument
=
function
()
{
var
i
,
cloned_doc
;
for
(
i
=
0
;
i
<
priv
.
storage_list
.
length
;
i
+=
1
)
{
cloned_doc
=
priv
.
clone
(
doc
);
if
(
typeof
cloned_doc
.
_rev
===
"
string
"
&&
doc_env
.
my_revisions
[
cloned_doc
.
_rev
]
!==
undefined
)
{
cloned_doc
.
_rev
=
doc_env
.
my_revisions
[
cloned_doc
.
_rev
][
i
];
}
priv
.
send
(
"
remove
"
,
i
,
cloned_doc
,
command
.
cloneOption
(),
functions
.
checkSendResult
);
}
that
.
end
();
};
functions
.
checkSendResult
=
function
(
method
,
index
,
err
,
response
)
{
if
(
err
)
{
priv
.
updateEnv
(
doc_env
,
my_rev
,
index
,
null
);
functions
.
error
(
err
);
return
;
}
// success
priv
.
updateEnv
(
doc_env
,
my_rev
,
index
,
response
.
rev
||
"
unique_
"
+
index
);
functions
.
success
({
"
ok
"
:
true
,
"
id
"
:
doc
.
_id
,
"
rev
"
:
my_rev
});
};
functions
.
success
=
function
(
response
)
{
// can be called once
that
.
success
(
response
);
functions
.
success
=
priv
.
emptyFunction
;
};
functions
.
error_count
=
0
;
functions
.
error
=
function
(
err
)
{
functions
.
error_count
+=
1
;
if
(
functions
.
error_count
===
priv
.
storage_list
.
length
)
{
that
.
error
(
err
);
functions
.
error
=
priv
.
emptyFunction
;
}
};
};
functions
.
begin
();
/**
* Remove the attachment from all sub storages.
* @method remove
* @param {object} command The JIO command
*/
that
.
removeAttachment
=
function
(
command
)
{
that
.
genericRequest
(
command
,
"
removeAttachment
"
);
};
};
return
that
;
return
that
;
...
...
src/jio.storage/revisionstorage.js
View file @
d54f3480
...
@@ -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,825 @@ jIO.addStorageType('revision', function (spec, my) {
...
@@ -70,1200 +81,825 @@ 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
);
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
)
{
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
)
{
var
attachment_id
,
dealResults
,
state
=
"
ok
"
,
result_list
=
[],
count
=
0
;
var
result
,
search
;
dealResults
=
function
(
attachment_id
,
attachment_meta
)
{
result
=
[];
return
function
(
err
,
attachment
)
{
// search method fills [result] with the winner revision
if
(
state
!==
"
ok
"
)
{
search
=
function
(
document_tree
)
{
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
]);
var
i
,
dealResults
,
state
=
"
ok
"
,
count
=
0
,
attachment
;
if
(
result
!==
undefined
)
{
attachment_list
=
attachment_list
||
[];
// The result is already found
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
(
typeof
docid
!==
"
string
"
)
{
if
(
specific_parameter
.
attachment_id
)
{
doc
.
_id
=
priv
.
generateUuid
();
doc
.
_attachment
=
specific_parameter
.
attachment_id
;
docid
=
doc
.
_id
;
}
}
f
.
getDocumentTree
=
function
()
{
callback
.
begin
=
function
()
{
var
option
=
command
.
cloneOption
();
var
check_error
;
if
(
option
.
max_retry
===
0
)
{
doc
.
_id
=
doc
.
_id
||
priv
.
generateUuid
();
option
.
max_retry
=
3
;
if
(
specific_parameter
.
revision_needed
&&
!
doc
.
_rev
)
{
return
onEnd
(
priv
.
conflictError
(
"
Document update conflict
"
,
"
No document revision was provided
"
),
undefined
);
}
}
that
.
addJob
(
// check revision format
"
get
"
,
check_error
=
priv
.
checkDocumentRevisionFormat
(
doc
);
priv
.
substorage
,
if
(
check_error
!==
undefined
)
{
docid
+
priv
.
doctree_suffix
,
return
onEnd
(
check_error
,
undefined
);
option
,
}
function
(
response
)
{
priv
.
getRevisionTree
(
doc
,
option
,
callback
.
getRevisionTree
);
doctree
=
response
;
};
f
.
updateRevsInfo
();
callback
.
getRevisionTree
=
function
(
err
,
response
)
{
f
.
getDocument
();
var
winner_info
,
previous_revision
=
doc
.
_rev
,
},
generate_new_revision
=
doc
.
_revs
||
doc
.
_revs_info
?
false
:
true
;
function
(
err
)
{
if
(
err
)
{
switch
(
err
.
status
)
{
if
(
err
.
status
!==
404
)
{
case
404
:
doctree
=
priv
.
createDocumentTree
();
f
.
updateRevsInfo
();
f
.
getDocument
();
break
;
default
:
err
.
message
=
"
Cannot get document revision tree
"
;
err
.
message
=
"
Cannot get document revision tree
"
;
f
.
error
(
err
);
return
onEnd
(
err
,
undefined
);
break
;
}
}
}
}
);
doc_tree
=
response
||
priv
.
newDocTree
();
};
if
(
specific_parameter
.
get
||
specific_parameter
.
getAttachment
)
{
f
.
getDocument
=
function
()
{
if
(
!
doc
.
_rev
)
{
if
(
revs_info
[
1
]
===
undefined
)
{
winner_info
=
priv
.
getWinnerRevsInfo
(
doc_tree
);
f
.
postDocument
([]);
if
(
winner_info
.
length
===
0
)
{
}
else
{
return
onEnd
(
priv
.
notFoundError
(
that
.
addJob
(
"
Document not found
"
,
"
get
"
,
"
missing
"
priv
.
substorage
,
),
undefined
);
command
.
getDocId
()
+
"
.
"
+
revs_info
[
1
].
rev
,
}
command
.
getOption
(),
if
(
winner_info
[
0
].
status
===
"
deleted
"
)
{
function
(
response
)
{
return
onEnd
(
priv
.
notFoundError
(
var
attachment_list
=
[],
i
;
"
Document not found
"
,
prev_doc
=
response
;
"
deleted
"
for
(
i
in
response
.
_attachments
)
{
),
undefined
);
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
"
;
doc
.
_rev
=
winner_info
[
0
].
rev
;
f
.
error
(
err
);
}
}
priv
.
fillDocumentRevisionProperties
(
doc
,
doc_tree
);
return
priv
.
getDocument
(
doc
,
option
,
callback
.
getDocument
);
}
priv
.
fillDocumentRevisionProperties
(
doc
,
doc_tree
);
if
(
generate_new_revision
)
{
if
(
previous_revision
&&
doc
.
_revs_info
.
length
===
0
)
{
// the document history has changed, it means that the document
// revision was wrong. Add a pseudo history to the document
doc
.
_rev
=
previous_revision
;
doc
.
_revs
=
{
"
start
"
:
parseInt
(
previous_revision
.
split
(
"
-
"
)[
0
],
10
),
"
ids
"
:
[
previous_revision
.
split
(
"
-
"
)[
1
]]
};
doc
.
_revs_info
=
[{
"
rev
"
:
previous_revision
,
"
status
"
:
"
missing
"
}];
}
doc
=
priv
.
generateNextRevision
(
doc
,
specific_parameter
.
remove
);
);
}
}
if
(
doc
.
_revs_info
.
length
>
1
)
{
prev_doc
=
{
"
_id
"
:
doc
.
_id
,
"
_rev
"
:
doc
.
_revs_info
[
1
].
rev
};
};
f
.
updateRevsInfo
=
function
()
{
if
(
!
generate_new_revision
&&
specific_parameter
.
putAttachment
)
{
if
(
doc
.
_revs
)
{
prev_doc
.
_rev
=
doc
.
_revs_info
[
0
].
rev
;
revs_info
=
priv
.
updateDocumentTree
(
doctree
,
doc
.
_revs
);
}
}
else
{
}
revs_info
=
priv
.
postToDocumentTree
(
doctree
,
doc
);
// force revs_info status
doc
.
_revs_info
[
0
].
status
=
(
specific_parameter
.
remove
?
"
deleted
"
:
"
available
"
);
priv
.
updateDocumentTree
(
doc
,
doc_tree
);
if
(
prev_doc
)
{
return
priv
.
getDocument
(
prev_doc
,
option
,
callback
.
getDocument
);
}
if
(
specific_parameter
.
remove
||
specific_parameter
.
removeAttachment
)
{
return
onEnd
(
priv
.
notFoundError
(
"
Unable to remove an inexistent document
"
,
"
missing
"
),
undefined
);
}
}
priv
.
putDocument
(
doc
,
option
,
callback
.
putDocument
);
};
};
f
.
postDocument
=
function
(
attachment_list
)
{
callback
.
getDocument
=
function
(
err
,
res_doc
)
{
doc
.
_id
=
docid
+
"
.
"
+
revs_info
[
0
].
rev
;
var
k
,
conflicts
;
delete
doc
.
_rev
;
if
(
err
)
{
delete
doc
.
_revs
;
if
(
err
.
status
===
404
)
{
that
.
addJob
(
if
(
specific_parameter
.
remove
||
"
post
"
,
specific_parameter
.
removeAttachment
)
{
priv
.
substorage
,
return
onEnd
(
priv
.
conflictError
(
doc
,
"
Document update conflict
"
,
command
.
cloneOption
(),
"
Document is missing
"
function
()
{
),
undefined
);
var
i
;
}
if
(
attachment_list
.
length
===
0
)
{
if
(
specific_parameter
.
get
)
{
f
.
sendDocumentTree
();
return
onEnd
(
priv
.
notFoundError
(
"
Unable to find the document
"
,
"
missing
"
),
undefined
);
}
res_doc
=
{};
}
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
.
putAttachment
||
that
.
addJob
(
specific_parameter
.
removeAttachment
)
{
"
put
"
,
// copy metadata (not beginning by "_" to document
priv
.
substorage
,
for
(
k
in
res_doc
)
{
doctree
,
if
(
res_doc
.
hasOwnProperty
(
k
)
&&
!
k
.
match
(
"
^_
"
))
{
command
.
cloneOption
(),
doc
[
k
]
=
res_doc
[
k
];
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
);
priv
.
getAttachmentList
(
res_doc
,
option
,
callback
.
getAttachmentList
);
}
}
};
};
functions
.
postEmptyDocument
=
function
()
{
callback
.
getAttachmentList
=
function
(
err
,
res_list
)
{
that
.
addJob
(
var
i
,
attachment_found
=
false
;
"
post
"
,
if
(
err
)
{
priv
.
substorage
,
err
.
message
=
"
Cannot get attachment
"
;
{
"
_id
"
:
command
.
getDocId
()
+
"
.
"
+
revs_info
[
0
].
rev
},
return
onEnd
(
err
,
undefined
);
command
.
getOption
(),
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
(
undefined
,
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
()
{
var
i
,
attachment_found
=
false
;
functions
.
post_attachment_count
-=
1
;
if
(
err
)
{
if
(
functions
.
post_attachment_count
>
0
)
{
err
.
message
=
"
Cannot post the document
"
;
return
;
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
(
attachment_list
[
i
]
&&
command
.
getAttachmentId
(),
specific_parameter
.
add_to_attachment_list
.
_attachment
===
"
_mimetype
"
:
command
.
getAttachmentMimeType
(),
attachment_list
[
i
].
_attachment
)
{
"
_data
"
:
command
.
getAttachmentData
()
attachment_found
=
true
;
},
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
;
if
(
err
)
{
that
.
addJob
(
err
.
message
=
"
Cannot copy attacments to the document
"
;
"
put
"
,
return
onEnd
(
err
,
undefined
);
priv
.
substorage
,
doctree
,
command
.
cloneOption
(),
function
()
{
that
.
success
({
"
ok
"
:
true
,
"
id
"
:
command
.
getDocId
()
+
"
/
"
+
command
.
getAttachmentId
(),
"
rev
"
:
revs_info
[
0
].
rev
});
},
function
(
err
)
{
// xxx do we try to delete the posted document ?
err
.
message
=
"
Cannot save document revision tree
"
;
functions
.
error
(
err
);
}
}
);
priv
.
putDocumentTree
(
doc
,
option
,
doc_tree
,
callback
.
putDocumentTree
);
};
};
functions
.
error
=
function
(
err
)
{
callback
.
putDocumentTree
=
function
(
err
,
response
)
{
functions
.
error
=
function
()
{};
if
(
err
)
{
that
.
error
(
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
.
addJob
(
"
get
"
,
priv
.
substorage
,
command
.
getDocId
()
+
priv
.
doctree_suffix
,
option
,
function
(
response
)
{
response
.
_conflicts
=
priv
.
getLeavesFromDocumentTree
(
response
);
if
(
del_rev
===
undefined
)
{
that
.
get
=
function
(
command
)
{
// no revision provided
if
(
command
.
getAttachmentId
())
{
that
.
error
({
return
that
.
getAttachment
(
command
);
"
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
src/jio/commands/command.js
View file @
d54f3480
...
@@ -2,6 +2,7 @@
...
@@ -2,6 +2,7 @@
/*global postCommand: true, putCommand: true, getCommand: true,
/*global postCommand: true, putCommand: true, getCommand: true,
removeCommand: true, allDocsCommand: true,
removeCommand: true, allDocsCommand: true,
putAttachmentCommand: true, failStatus: true, doneStatus: true,
putAttachmentCommand: true, failStatus: true, doneStatus: true,
checkCommand: true, repairCommand: true,
hex_md5: true */
hex_md5: true */
var
command
=
function
(
spec
,
my
)
{
var
command
=
function
(
spec
,
my
)
{
var
that
=
{},
var
that
=
{},
...
@@ -16,7 +17,9 @@ var command = function (spec, my) {
...
@@ -16,7 +17,9 @@ var command = function (spec, my) {
'
get
'
:
getCommand
,
'
get
'
:
getCommand
,
'
remove
'
:
removeCommand
,
'
remove
'
:
removeCommand
,
'
allDocs
'
:
allDocsCommand
,
'
allDocs
'
:
allDocsCommand
,
'
putAttachment
'
:
putAttachmentCommand
'
putAttachment
'
:
putAttachmentCommand
,
'
check
'
:
checkCommand
,
'
repair
'
:
repairCommand
};
};
// creates the good command thanks to his label
// creates the good command thanks to his label
if
(
spec
.
label
&&
priv
.
commandlist
[
spec
.
label
])
{
if
(
spec
.
label
&&
priv
.
commandlist
[
spec
.
label
])
{
...
...
src/jio/jio.core.js
View file @
d54f3480
...
@@ -4,7 +4,7 @@
...
@@ -4,7 +4,7 @@
storage_type_object: true, invalidStorageType: true, jobRules: true,
storage_type_object: true, invalidStorageType: true, jobRules: true,
job: true, postCommand: true, putCommand: true, getCommand:true,
job: true, postCommand: true, putCommand: true, getCommand:true,
allDocsCommand: true, putAttachmentCommand: true,
allDocsCommand: true, putAttachmentCommand: true,
removeCommand: true */
removeCommand: true
, checkCommand: true, repairCommand: true
*/
// Class jio
// Class jio
var
that
=
{},
priv
=
{},
jio_id_array_name
=
'
jio/id_array
'
;
var
that
=
{},
priv
=
{},
jio_id_array_name
=
'
jio/id_array
'
;
spec
=
spec
||
{};
spec
=
spec
||
{};
...
@@ -377,10 +377,10 @@ Object.defineProperty(that, "allDocs", {
...
@@ -377,10 +377,10 @@ Object.defineProperty(that, "allDocs", {
* Put an attachment to a document.
* Put an attachment to a document.
* @method putAttachment
* @method putAttachment
* @param {object} doc The document object. Contains at least:
* @param {object} doc The document object. Contains at least:
* - {string} id The document id: "doc_id/attchment_id"
* - {string}
_
id The document id: "doc_id/attchment_id"
* - {string} data Base64 attachment data
* - {string}
_
data Base64 attachment data
* - {string} mimetype The attachment mimetype
* - {string}
_
mimetype The attachment mimetype
* - {string} rev The attachment revision
* - {string}
_
rev The attachment revision
* @param {object} options (optional) Contains some options:
* @param {object} options (optional) Contains some options:
* - {number} max_retry The number max of retries, 0 = infinity.
* - {number} max_retry The number max of retries, 0 = infinity.
* - {boolean} revs Include revision history of the document.
* - {boolean} revs Include revision history of the document.
...
@@ -408,3 +408,63 @@ Object.defineProperty(that, "putAttachment", {
...
@@ -408,3 +408,63 @@ Object.defineProperty(that, "putAttachment", {
});
});
}
}
});
});
/**
* Check a document.
* @method check
* @param {object} doc The document object. Contains at least:
* - {string} _id The document id
* @param {object} options (optional) Contains some options:
* - {number} max_retry The number max of retries, 0 = infinity.
* @param {function} callback (optional) The callback(err,response).
* @param {function} error (optional) The callback on error, if this
* callback is given in parameter, "callback" is changed as "success",
* called on success.
*/
Object
.
defineProperty
(
that
,
"
check
"
,
{
configurable
:
false
,
enumerable
:
false
,
writable
:
false
,
value
:
function
(
doc
,
options
,
success
,
callback
)
{
var
param
=
priv
.
parametersToObject
(
[
options
,
success
,
callback
],
{
max_retry
:
3
}
);
priv
.
addJob
(
checkCommand
,
{
doc
:
doc
,
options
:
param
.
options
,
callbacks
:
{
success
:
param
.
success
,
error
:
param
.
error
}
});
}
});
/**
* Repair a document.
* @method repair
* @param {object} doc The document object. Contains at least:
* - {string} _id The document id
* @param {object} options (optional) Contains some options:
* - {number} max_retry The number max of retries, 0 = infinity.
* @param {function} callback (optional) The callback(err,response).
* @param {function} error (optional) The callback on error, if this
* callback is given in parameter, "callback" is changed as "success",
* called on success.
*/
Object
.
defineProperty
(
that
,
"
repair
"
,
{
configurable
:
false
,
enumerable
:
false
,
writable
:
false
,
value
:
function
(
doc
,
options
,
success
,
callback
)
{
var
param
=
priv
.
parametersToObject
(
[
options
,
success
,
callback
],
{
max_retry
:
3
}
);
priv
.
addJob
(
repairCommand
,
{
doc
:
doc
,
options
:
param
.
options
,
callbacks
:
{
success
:
param
.
success
,
error
:
param
.
error
}
});
}
});
src/jio/storages/storage.js
View file @
d54f3480
...
@@ -159,6 +159,18 @@ var storage = function (spec, my) {
...
@@ -159,6 +159,18 @@ var storage = function (spec, my) {
});
});
};
};
that
.
check
=
function
(
command
)
{
setTimeout
(
function
()
{
that
.
success
({
"
ok
"
:
true
,
"
id
"
:
command
.
getDocId
()});
});
};
that
.
repair
=
function
(
command
)
{
setTimeout
(
function
()
{
that
.
success
({
"
ok
"
:
true
,
"
id
"
:
command
.
getDocId
()});
});
};
that
.
success
=
function
()
{};
that
.
success
=
function
()
{};
that
.
retry
=
function
()
{};
that
.
retry
=
function
()
{};
that
.
error
=
function
()
{};
that
.
error
=
function
()
{};
...
...
test/jiotests.js
View file @
d54f3480
...
@@ -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
);
},
},
...
@@ -646,7 +651,6 @@ test ("Similar Jobs at the same time (Update)", function () {
...
@@ -646,7 +651,6 @@ test ("Similar Jobs at the same time (Update)", function () {
o
.
jio
.
put
({
"
_id
"
:
"
file
"
,
"
content
"
:
"
content
"
},
o
.
f2
);
// 2
o
.
jio
.
put
({
"
_id
"
:
"
file
"
,
"
content
"
:
"
content
"
},
o
.
f2
);
// 2
o
.
jio
.
put
({
"
_id
"
:
"
file
"
,
"
content
"
:
"
content
"
},
o
.
f3
);
// 3
o
.
jio
.
put
({
"
_id
"
:
"
file
"
,
"
content
"
:
"
content
"
},
o
.
f3
);
// 3
deepEqual
(
getLastJob
(
o
.
jio
.
getId
()).
id
,
1
,
"
Check job queue
"
);
deepEqual
(
getLastJob
(
o
.
jio
.
getId
()).
id
,
1
,
"
Check job queue
"
);
console
.
log
(
JSON
.
parse
(
JSON
.
stringify
(
localStorage
)));
o
.
tick
(
o
,
1000
,
"
f
"
);
o
.
tick
(
o
,
1000
,
"
f
"
);
o
.
tick
(
o
,
"
f2
"
);
o
.
tick
(
o
,
"
f2
"
);
o
.
tick
(
o
,
"
f3
"
);
o
.
tick
(
o
,
"
f3
"
);
...
@@ -1264,7 +1268,8 @@ test ("Post", function(){
...
@@ -1264,7 +1268,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 +1298,92 @@ test ("Post", function(){
...
@@ -1293,8 +1298,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
(){
...
@@ -1550,19 +1639,21 @@ test("Put Attachment", function () {
...
@@ -1550,19 +1639,21 @@ test("Put Attachment", function () {
// putAttachment without doc id
// putAttachment without doc id
// error 20 -> document id required
// error 20 -> document id required
o
.
spy
(
o
,
"
status
"
,
20
,
"
PutAttachment without doc id
"
);
o
.
spy
(
o
,
"
status
"
,
20
,
"
PutAttachment without doc id
"
+
"
-> 20 document id required
"
);
o
.
jio
.
putAttachment
({},
o
.
f
);
o
.
jio
.
putAttachment
({},
o
.
f
);
o
.
tick
(
o
);
o
.
tick
(
o
);
// putAttachment without attachment id
// putAttachment without attachment id
// erorr 22 -> attachment id required
// erorr 22 -> attachment id required
o
.
spy
(
o
,
"
status
"
,
22
,
"
PutAttachment without attachment id
"
);
o
.
spy
(
o
,
"
status
"
,
22
,
"
PutAttachment without attachment id
"
+
"
-> 22 attachment id required
"
);
o
.
jio
.
putAttachment
({
"
_id
"
:
"
putattmt1
"
},
o
.
f
);
o
.
jio
.
putAttachment
({
"
_id
"
:
"
putattmt1
"
},
o
.
f
);
o
.
tick
(
o
);
o
.
tick
(
o
);
// 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
},
...
@@ -1596,14 +1687,23 @@ test("Put Attachment", function () {
...
@@ -1596,14 +1687,23 @@ test("Put Attachment", function () {
),
),
""
,
"
Check attachment
"
""
,
"
Check attachment
"
);
);
// adding a metadata to the document
o
.
doc
=
localstorage
.
getItem
(
"
jio/localstorage/urevputattmt/arevputattmt/doc1.
"
+
o
.
rev
);
o
.
doc
.
title
=
"
My Title
"
;
localstorage
.
setItem
(
"
jio/localstorage/urevputattmt/arevputattmt/doc1.
"
+
o
.
rev
,
o
.
doc
);
// update attachment
// update attachment
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
},
...
@@ -1622,6 +1722,7 @@ test("Put Attachment", function () {
...
@@ -1622,6 +1722,7 @@ test("Put Attachment", function () {
),
),
{
{
"
_id
"
:
"
doc1.
"
+
o
.
rev
,
"
_id
"
:
"
doc1.
"
+
o
.
rev
,
"
title
"
:
"
My Title
"
,
"
_attachments
"
:
{
"
_attachments
"
:
{
"
attmt1
"
:
{
"
attmt1
"
:
{
"
length
"
:
3
,
"
length
"
:
3
,
...
@@ -1646,9 +1747,9 @@ test("Put Attachment", function () {
...
@@ -1646,9 +1747,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
},
...
@@ -1667,6 +1768,7 @@ test("Put Attachment", function () {
...
@@ -1667,6 +1768,7 @@ test("Put Attachment", function () {
),
),
{
{
"
_id
"
:
"
doc1.
"
+
o
.
rev
,
"
_id
"
:
"
doc1.
"
+
o
.
rev
,
"
title
"
:
"
My Title
"
,
"
_attachments
"
:
{
"
_attachments
"
:
{
"
attmt1
"
:
{
"
attmt1
"
:
{
"
length
"
:
3
,
"
length
"
:
3
,
...
@@ -1710,12 +1812,14 @@ test ("Get", function(){
...
@@ -1710,12 +1812,14 @@ test ("Get", function(){
o
.
localpath
=
"
jio/localstorage/urevget/arevget
"
;
o
.
localpath
=
"
jio/localstorage/urevget/arevget
"
;
// get inexistent document
// get inexistent document
o
.
spy
(
o
,
"
status
"
,
404
,
"
Get inexistent document (winner)
"
);
o
.
spy
(
o
,
"
status
"
,
404
,
"
Get inexistent document (winner)
"
+
"
-> 404 Not Found
"
);
o
.
jio
.
get
({
"
_id
"
:
"
get1
"
},
o
.
f
);
o
.
jio
.
get
({
"
_id
"
:
"
get1
"
},
o
.
f
);
o
.
tick
(
o
);
o
.
tick
(
o
);
// get inexistent attachment
// get inexistent attachment
o
.
spy
(
o
,
"
status
"
,
404
,
"
Get inexistent attachment (winner)
"
);
o
.
spy
(
o
,
"
status
"
,
404
,
"
Get inexistent attachment (winner)
"
+
"
-> 404 Not Found
"
);
o
.
jio
.
get
({
"
_id
"
:
"
get1/get2
"
},
o
.
f
);
o
.
jio
.
get
({
"
_id
"
:
"
get1/get2
"
},
o
.
f
);
o
.
tick
(
o
);
o
.
tick
(
o
);
...
@@ -1723,15 +1827,16 @@ test ("Get", function(){
...
@@ -1723,15 +1827,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 +1853,15 @@ test ("Get", function(){
...
@@ -1748,14 +1853,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
"
]
=
[{
...
@@ -1772,7 +1878,8 @@ test ("Get", function(){
...
@@ -1772,7 +1878,8 @@ test ("Get", function(){
o
.
tick
(
o
);
o
.
tick
(
o
);
// get inexistent specific document
// get inexistent specific document
o
.
spy
(
o
,
"
status
"
,
404
,
"
Get document (inexistent specific revision)
"
);
o
.
spy
(
o
,
"
status
"
,
404
,
"
Get document (inexistent specific revision)
"
+
"
-> 404 Not Found
"
);
o
.
jio
.
get
({
"
_id
"
:
"
get1
"
,
"
_rev
"
:
"
1-rev0
"
},
{
o
.
jio
.
get
({
"
_id
"
:
"
get1
"
,
"
_rev
"
:
"
1-rev0
"
},
{
"
revs_info
"
:
true
,
"
revs
"
:
true
,
"
conflicts
"
:
true
,
"
revs_info
"
:
true
,
"
revs
"
:
true
,
"
conflicts
"
:
true
,
},
o
.
f
);
},
o
.
f
);
...
@@ -1780,6 +1887,7 @@ test ("Get", function(){
...
@@ -1780,6 +1887,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 +1901,16 @@ test ("Get", function(){
...
@@ -1793,18 +1901,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)
"
);
...
@@ -1812,7 +1918,8 @@ test ("Get", function(){
...
@@ -1812,7 +1918,8 @@ test ("Get", function(){
o
.
tick
(
o
);
o
.
tick
(
o
);
// get inexistent attachment specific rev
// get inexistent attachment specific rev
o
.
spy
(
o
,
"
status
"
,
404
,
"
Get inexistent attachment (specific revision)
"
);
o
.
spy
(
o
,
"
status
"
,
404
,
"
Get inexistent attachment (specific revision)
"
+
"
-> 404 Not Found
"
);
o
.
jio
.
get
({
"
_id
"
:
"
get1/get2
"
,
"
_rev
"
:
"
1-rev1
"
},
{
o
.
jio
.
get
({
"
_id
"
:
"
get1/get2
"
,
"
_rev
"
:
"
1-rev1
"
},
{
"
revs_info
"
:
true
,
"
revs
"
:
true
,
"
conflicts
"
:
true
,
"
revs_info
"
:
true
,
"
revs
"
:
true
,
"
conflicts
"
:
true
,
},
o
.
f
);
},
o
.
f
);
...
@@ -1820,13 +1927,13 @@ test ("Get", function(){
...
@@ -1820,13 +1927,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 +1942,7 @@ test ("Get", function(){
...
@@ -1835,7 +1942,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,194 +1969,139 @@ test ("Remove", function(){
...
@@ -1862,194 +1969,139 @@ 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
();
});
});
module
(
"
Jio Revision Storage + Local Storage
"
);
test
(
"
Scenario
"
,
function
(){
test
(
"
Scenario
"
,
function
(){
var
o
=
generateTools
(
this
);
var
o
=
generateTools
(
this
);
...
@@ -2196,9 +2248,7 @@ test ("Scenario", function(){
...
@@ -2196,9 +2248,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
;
...
@@ -2253,15 +2303,15 @@ module ("JIO Replicate Revision Storage");
...
@@ -2253,15 +2303,15 @@ module ("JIO Replicate Revision Storage");
// check document
// check document
o
.
doc
.
_id
=
o
.
uuid
;
o
.
doc
.
_id
=
o
.
uuid
;
o
.
revision
=
{
"
start
"
:
0
,
"
ids
"
:
[]};
o
.
revision
s
=
{
"
start
"
:
0
,
"
ids
"
:
[]};
o
.
rev
=
"
1-1
"
;
o
.
rev
_hash
=
generateRevisionHash
(
o
.
doc
,
o
.
revisions
)
;
o
.
local_rev
=
"
1-
"
+
generateRevisionHash
(
o
.
doc
,
o
.
revision
)
;
o
.
rev
=
"
1-
"
+
o
.
rev_hash
;
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
)
{
deepEqual
(
o
.
response_rev
,
o
.
rev
,
"
Check revision
"
);
deepEqual
(
o
.
response_rev
,
o
.
rev
,
"
Check revision
"
);
doc
.
_id
+=
"
.
"
+
o
.
local_
rev
;
doc
.
_id
+=
"
.
"
+
o
.
rev
;
suffix
=
"
.
"
+
o
.
local_
rev
;
suffix
=
"
.
"
+
o
.
rev
;
}
}
deepEqual
(
deepEqual
(
localstorage
.
getItem
(
generateLocalPath
(
storage_description
)
+
localstorage
.
getItem
(
generateLocalPath
(
storage_description
)
+
...
@@ -2274,10 +2324,10 @@ module ("JIO Replicate Revision Storage");
...
@@ -2274,10 +2324,10 @@ module ("JIO Replicate Revision Storage");
o
.
spy
(
o
,
"
value
"
,
{
o
.
spy
(
o
,
"
value
"
,
{
"
_id
"
:
o
.
uuid
,
"
_id
"
:
o
.
uuid
,
"
title
"
:
"
post document without id
"
,
"
title
"
:
"
post document without id
"
,
"
_rev
"
:
"
1-1
"
,
"
_rev
"
:
o
.
rev
,
"
_revisions
"
:
{
"
start
"
:
1
,
"
ids
"
:
[
"
1
"
]},
"
_revisions
"
:
{
"
start
"
:
1
,
"
ids
"
:
[
o
.
rev_hash
]},
"
_revs_info
"
:
[{
"
rev
"
:
"
1-1
"
,
"
status
"
:
"
available
"
}]
"
_revs_info
"
:
[{
"
rev
"
:
o
.
rev
,
"
status
"
:
"
available
"
}]
},
"
Get the
previous document (without revision)
"
);
},
"
Get the
generated document, the winner
"
);
o
.
jio
.
get
({
"
_id
"
:
o
.
uuid
},
{
o
.
jio
.
get
({
"
_id
"
:
o
.
uuid
},
{
"
conflicts
"
:
true
,
"
conflicts
"
:
true
,
"
revs
"
:
true
,
"
revs
"
:
true
,
...
@@ -2287,8 +2337,12 @@ module ("JIO Replicate Revision Storage");
...
@@ -2287,8 +2337,12 @@ module ("JIO Replicate Revision Storage");
// 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
.
rev1_1_hash
=
generateRevisionHash
(
o
.
doc
,
o
.
revisions
);
"
Post document (with id)
"
);
o
.
rev1_1
=
"
1-
"
+
o
.
rev1_1_hash
;
o
.
rev1_1_history
=
{
"
start
"
:
1
,
"
ids
"
:
[
o
.
rev1_1_hash
]};
o
.
rev1_1_revs_info
=
[{
"
rev
"
:
o
.
rev1_1
,
"
status
"
:
"
available
"
}];
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1
"
,
"
rev
"
:
o
.
rev1_1
},
"
Post new document with an id
"
);
o
.
jio
.
post
(
o
.
doc
,
o
.
f
);
o
.
jio
.
post
(
o
.
doc
,
o
.
f
);
o
.
tick
(
o
);
o
.
tick
(
o
);
...
@@ -2297,15 +2351,11 @@ module ("JIO Replicate Revision Storage");
...
@@ -2297,15 +2351,11 @@ module ("JIO Replicate Revision Storage");
// 1-1
// 1-1
// check document
// check document
o
.
local_rev_hash
=
generateRevisionHash
(
o
.
doc
,
o
.
revision
);
o
.
local_rev
=
"
1-
"
+
o
.
local_rev_hash
;
o
.
specific_rev_hash
=
o
.
local_rev_hash
;
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
.
rev1_1
;
suffix
=
"
.
"
+
o
.
local_rev
;
suffix
=
"
.
"
+
o
.
rev1_1
;
}
}
deepEqual
(
deepEqual
(
localstorage
.
getItem
(
generateLocalPath
(
storage_description
)
+
localstorage
.
getItem
(
generateLocalPath
(
storage_description
)
+
...
@@ -2318,9 +2368,9 @@ module ("JIO Replicate Revision Storage");
...
@@ -2318,9 +2368,9 @@ module ("JIO Replicate Revision Storage");
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
"
:
o
.
rev1_1
,
"
_revisions
"
:
{
"
start
"
:
1
,
"
ids
"
:
[
"
1
"
]},
"
_revisions
"
:
{
"
start
"
:
1
,
"
ids
"
:
[
o
.
rev1_1_hash
]},
"
_revs_info
"
:
[{
"
rev
"
:
"
1-1
"
,
"
status
"
:
"
available
"
}]
"
_revs_info
"
:
[{
"
rev
"
:
o
.
rev1_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
,
...
@@ -2331,8 +2381,11 @@ module ("JIO Replicate Revision Storage");
...
@@ -2331,8 +2381,11 @@ module ("JIO Replicate Revision Storage");
// 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
.
rev1_2_hash
=
generateRevisionHash
(
o
.
doc
,
o
.
revisions
);
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1
"
,
"
rev
"
:
o
.
rev
},
o
.
rev1_2
=
"
1-
"
+
o
.
rev1_2_hash
;
o
.
rev1_2_history
=
{
"
start
"
:
1
,
"
ids
"
:
[
o
.
rev1_2_hash
]};
o
.
rev1_2_revs_info
=
[{
"
rev
"
:
o
.
rev1_2
,
"
status
"
:
"
available
"
}];
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1
"
,
"
rev
"
:
o
.
rev1_2
},
"
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
);
...
@@ -2342,12 +2395,11 @@ module ("JIO Replicate Revision Storage");
...
@@ -2342,12 +2395,11 @@ module ("JIO Replicate Revision Storage");
// 1-1 1-2
// 1-1 1-2
// check document
// check document
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
.
rev1_2
;
suffix
=
"
.
"
+
o
.
local_rev
;
suffix
=
"
.
"
+
o
.
rev1_2
;
}
}
deepEqual
(
deepEqual
(
localstorage
.
getItem
(
generateLocalPath
(
storage_description
)
+
localstorage
.
getItem
(
generateLocalPath
(
storage_description
)
+
...
@@ -2357,9 +2409,17 @@ module ("JIO Replicate Revision Storage");
...
@@ -2357,9 +2409,17 @@ module ("JIO Replicate Revision Storage");
});
});
// 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
.
rev1_2
};
o
.
rev
=
"
2-3
"
;
o
.
revisions
.
start
+=
1
;
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1
"
,
"
rev
"
:
o
.
rev
},
o
.
revisions
.
ids
.
unshift
(
o
.
rev1_2_hash
);
o
.
rev2_3_hash
=
generateRevisionHash
(
o
.
doc
,
o
.
revisions
);
o
.
rev2_3
=
"
2-
"
+
o
.
rev2_3_hash
;
o
.
rev2_3_history
=
clone
(
o
.
rev1_2_history
);
o
.
rev2_3_history
.
start
+=
1
;
o
.
rev2_3_history
.
ids
.
unshift
(
o
.
rev2_3_hash
);
o
.
rev2_3_revs_info
=
clone
(
o
.
rev1_2_revs_info
);
o
.
rev2_3_revs_info
.
unshift
({
"
rev
"
:
o
.
rev2_3
,
"
status
"
:
"
available
"
});
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1
"
,
"
rev
"
:
o
.
rev2_3
},
"
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
);
...
@@ -2371,17 +2431,12 @@ module ("JIO Replicate Revision Storage");
...
@@ -2371,17 +2431,12 @@ module ("JIO Replicate Revision Storage");
// 2-3
// 2-3
// check document
// check document
o
.
revision
.
start
+=
1
;
o
.
revision
.
ids
.
unshift
(
o
.
local_rev
.
split
(
"
-
"
).
slice
(
1
).
join
(
"
-
"
));
o
.
doc
.
_rev
=
o
.
local_rev
;
o
.
local_rev
=
"
2-
"
+
generateRevisionHash
(
o
.
doc
,
o
.
revision
);
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
.
rev2_3
;
suffix
=
"
.
"
+
o
.
local_rev
;
suffix
=
"
.
"
+
o
.
rev2_3
;
}
}
deepEqual
(
deepEqual
(
localstorage
.
getItem
(
generateLocalPath
(
storage_description
)
+
localstorage
.
getItem
(
generateLocalPath
(
storage_description
)
+
...
@@ -2394,31 +2449,15 @@ module ("JIO Replicate Revision Storage");
...
@@ -2394,31 +2449,15 @@ module ("JIO Replicate Revision Storage");
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
"
:
o
.
rev1_2
,
"
_revisions
"
:
{
"
start
"
:
1
,
"
ids
"
:
[
"
2
"
]},
"
_revisions
"
:
{
"
start
"
:
1
,
"
ids
"
:
[
o
.
rev1_2_hash
]},
"
_revs_info
"
:
[{
"
rev
"
:
"
1-2
"
,
"
status
"
:
"
available
"
}],
"
_revs_info
"
:
[{
"
rev
"
:
o
.
rev1_2
,
"
status
"
:
"
available
"
}],
"
_conflicts
"
:
[
"
1-1
"
]
"
_conflicts
"
:
[
o
.
rev1_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
"
:
o
.
rev1_2
},
{
"
conflicts
"
:
true
,
"
revs
"
:
true
,
"
revs_info
"
:
true
,
},
o
.
f
);
o
.
tick
(
o
);
// get the post document with specific revision
o
.
spy
(
o
,
"
value
"
,
{
"
_id
"
:
"
doc1
"
,
"
title
"
:
"
post new doc with id
"
,
"
_rev
"
:
o
.
specific_rev
,
"
_revisions
"
:
{
"
start
"
:
1
,
"
ids
"
:
[
o
.
specific_rev_hash
]},
"
_revs_info
"
:
[{
"
rev
"
:
o
.
specific_rev
,
"
status
"
:
"
available
"
}],
"
_conflicts
"
:
[
o
.
specific_rev_conflict
]
},
"
Get a previous document (with local storage revision)
"
);
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
);
...
@@ -2429,8 +2468,11 @@ module ("JIO Replicate Revision Storage");
...
@@ -2429,8 +2468,11 @@ module ("JIO Replicate Revision Storage");
// 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
.
rev1_4_hash
=
generateRevisionHash
(
o
.
doc
,
{
"
start
"
:
0
,
"
ids
"
:
[]});
o
.
spy
(
o
,
"
value
"
,
{
"
id
"
:
"
doc1
"
,
"
ok
"
:
true
,
"
rev
"
:
o
.
rev
},
o
.
rev1_4
=
"
1-
"
+
o
.
rev1_4_hash
;
o
.
rev1_4_history
=
{
"
start
"
:
1
,
"
ids
"
:
[
o
.
rev1_4_hash
]};
o
.
rev1_4_revs_info
=
[{
"
rev
"
:
o
.
rev1_4
,
"
status
"
:
"
available
"
}];
o
.
spy
(
o
,
"
value
"
,
{
"
id
"
:
"
doc1
"
,
"
ok
"
:
true
,
"
rev
"
:
o
.
rev1_4
},
"
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
);
...
@@ -2442,10 +2484,14 @@ module ("JIO Replicate Revision Storage");
...
@@ -2442,10 +2484,14 @@ module ("JIO Replicate Revision Storage");
// 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
"
:
o
.
rev1_4
};
o
.
rev
=
"
2-5
"
;
o
.
rev2_5_hash
=
generateRevisionHash
(
o
.
doc
,
o
.
rev1_4_history
);
o
.
spy
(
o
,
"
value
"
,
{
"
id
"
:
"
doc1
"
,
"
ok
"
:
true
,
"
rev
"
:
o
.
rev
},
o
.
rev2_5
=
"
2-
"
+
o
.
rev2_5_hash
"
Put document without rev
"
)
o
.
rev2_5_history
=
{
"
start
"
:
2
,
"
ids
"
:
[
o
.
rev2_5_hash
,
o
.
rev1_4_hash
]};
o
.
rev2_5_revs_info
=
clone
(
o
.
rev1_4_revs_info
);
o
.
rev2_5_revs_info
.
unshift
({
"
rev
"
:
o
.
rev2_5
,
"
status
"
:
"
available
"
});
o
.
spy
(
o
,
"
value
"
,
{
"
id
"
:
"
doc1
"
,
"
ok
"
:
true
,
"
rev
"
:
o
.
rev2_5
},
"
Put new revision
"
)
o
.
jio
.
put
(
o
.
doc
,
o
.
f
);
o
.
jio
.
put
(
o
.
doc
,
o
.
f
);
o
.
tick
(
o
);
o
.
tick
(
o
);
...
@@ -2456,39 +2502,362 @@ module ("JIO Replicate Revision Storage");
...
@@ -2456,39 +2502,362 @@ module ("JIO Replicate Revision Storage");
// 2-3 2-5
// 2-3 2-5
// putAttachment to inexistent document
// putAttachment to inexistent document
o
.
doc
=
{
"
_id
"
:
"
doc2
"
,
"
_mimetype
"
:
"
text/plain
"
,
"
_data
"
:
"
doc 2 - attachment 1
"
,
"
_attachment
"
:
"
attachment1
"
};
o
.
rev_hash
=
generateRevisionHash
(
o
.
doc
,
{
"
start
"
:
0
,
"
ids
"
:
[]});
o
.
rev
=
"
1-
"
+
o
.
rev_hash
;
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc2/attachment1
"
,
"
rev
"
:
o
.
rev
},
"
Put an attachment to an inexistent document
"
);
o
.
doc
.
_id
+=
"
/
"
+
o
.
doc
.
_attachment
;
delete
o
.
doc
.
_attachment
;
o
.
jio
.
putAttachment
(
o
.
doc
,
o
.
f
);
o
.
tick
(
o
);
// putAttachment
// putAttachment
o
.
doc
=
{
"
_id
"
:
"
doc1
"
,
"
_mimetype
"
:
"
text/plain
"
,
"
_data
"
:
"
doc 1 - attachment 1
"
,
"
_attachment
"
:
"
attachment1
"
,
"
_rev
"
:
o
.
rev2_5
};
o
.
rev3_6_hash
=
generateRevisionHash
(
o
.
doc
,
o
.
rev2_5_history
);
o
.
rev3_6
=
"
3-
"
+
o
.
rev3_6_hash
;
o
.
rev3_6_history
=
clone
(
o
.
rev2_5_history
);
o
.
rev3_6_history
.
start
+=
1
;
o
.
rev3_6_history
.
ids
.
unshift
(
o
.
rev3_6_hash
);
o
.
rev3_6_revs_info
=
clone
(
o
.
rev2_5_revs_info
);
o
.
rev3_6_revs_info
.
unshift
({
"
rev
"
:
o
.
rev3_6
,
"
status
"
:
"
available
"
});
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1/attachment1
"
,
"
rev
"
:
o
.
rev3_6
},
"
Put an attachment to the first document
"
);
o
.
doc
.
_id
+=
"
/
"
+
o
.
doc
.
_attachment
;
delete
o
.
doc
.
_attachment
;
o
.
jio
.
putAttachment
(
o
.
doc
,
o
.
f
);
o
.
tick
(
o
);
// __/__
// / | \
// 1-1 1-2 1-4
// | |
// 2-3 2-5
// |
// 3-6+a1
// get document
// get document
o
.
doc
=
{
"
_id
"
:
"
doc1
"
,
"
_rev
"
:
o
.
rev3_6
,
"
_revisions
"
:
o
.
rev3_6_history
,
"
_revs_info
"
:
o
.
rev3_6_revs_info
,
"
_conflicts
"
:
[
o
.
rev2_3
,
o
.
rev1_1
],
"
_attachments
"
:
{
"
attachment1
"
:
{
"
length
"
:
"
doc 1 - attachment 1
"
.
length
,
"
content_type
"
:
"
text/plain
"
,
"
digest
"
:
"
md5-0505c1fb6aae02dd1695d33841726564
"
}
},
"
title
"
:
"
put new revision
"
};
o
.
spy
(
o
,
"
value
"
,
o
.
doc
,
"
Get document, the winner
"
);
o
.
jio
.
get
({
"
_id
"
:
"
doc1
"
},
{
"
conflicts
"
:
true
,
"
revs
"
:
true
,
"
revs_info
"
:
true
},
o
.
f
);
o
.
tick
(
o
);
// get attachment
// get attachment
o
.
doc
=
{
"
_id
"
:
"
doc1
"
,
"
_attachment
"
:
"
attachment1
"
};
o
.
spy
(
o
,
"
value
"
,
"
doc 1 - attachment 1
"
,
"
Get the winner's attachment
"
);
o
.
doc
.
_id
+=
"
/
"
+
o
.
doc
.
_attachment
;
delete
o
.
doc
.
_attachment
;
o
.
jio
.
get
(
o
.
doc
,
o
.
f
);
o
.
tick
(
o
);
// put document
// put document
// get document
o
.
doc
=
{
"
_id
"
:
"
doc1
"
,
"
_rev
"
:
o
.
rev3_6
,
"
title
"
:
"
Put revision, attachment must be copied
"
};
o
.
rev4_7_hash
=
generateRevisionHash
(
o
.
doc
,
o
.
rev3_6_history
);
o
.
rev4_7
=
"
4-
"
+
o
.
rev4_7_hash
;
o
.
rev4_7_history
=
clone
(
o
.
rev3_6_history
);
o
.
rev4_7_history
.
start
+=
1
;
o
.
rev4_7_history
.
ids
.
unshift
(
o
.
rev4_7_hash
);
o
.
rev4_7_revs_info
=
clone
(
o
.
rev3_6_revs_info
);
o
.
rev4_7_revs_info
.
unshift
({
"
rev
"
:
o
.
rev4_7
,
"
status
"
:
"
available
"
});
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1
"
,
"
rev
"
:
o
.
rev4_7
},
"
Update document, attachment should be copied
"
);
o
.
jio
.
put
(
o
.
doc
,
o
.
f
);
o
.
tick
(
o
);
// __/__
// / | \
// 1-1 1-2 1-4
// | |
// 2-3 2-5
// |
// 3-6+a1
// |
// 4-7+a1
// get document, attachment must be copied
o
.
doc
=
{
"
_id
"
:
"
doc1
"
,
"
_rev
"
:
o
.
rev4_7
,
"
title
"
:
o
.
doc
.
title
,
"
_attachments
"
:
{
"
attachment1
"
:
{
"
length
"
:
"
doc 1 - attachment 1
"
.
length
,
"
content_type
"
:
"
text/plain
"
,
"
digest
"
:
"
md5-0505c1fb6aae02dd1695d33841726564
"
}
},
"
_conflicts
"
:
[
o
.
rev2_3
,
o
.
rev1_1
],
"
_revisions
"
:
o
.
rev4_7_history
,
"
_revs_info
"
:
o
.
rev4_7_revs_info
};
o
.
spy
(
o
,
"
value
"
,
o
.
doc
,
"
Get the new winner document and its attachment metadata
"
);
o
.
jio
.
get
({
"
_id
"
:
"
doc1
"
},
{
"
conflicts
"
:
true
,
"
revs
"
:
true
,
"
revs_info
"
:
true
},
o
.
f
);
o
.
tick
(
o
);
// get attachment
// get attachment
o
.
doc
=
{
"
_id
"
:
"
doc1
"
,
"
_attachment
"
:
"
attachment1
"
};
o
.
spy
(
o
,
"
value
"
,
"
doc 1 - attachment 1
"
,
"
Get the winner's attachment again
"
);
o
.
doc
.
_id
+=
"
/
"
+
o
.
doc
.
_attachment
;
delete
o
.
doc
.
_attachment
;
o
.
jio
.
get
(
o
.
doc
,
o
.
f
);
o
.
tick
(
o
);
// remove attachment
// remove attachment
// get document
o
.
doc
=
{
// get inexistent attachment
"
_id
"
:
"
doc1
"
,
"
_attachment
"
:
"
attachment1
"
,
"
_rev
"
:
o
.
rev4_7
};
o
.
rev5_8_hash
=
generateRevisionHash
(
o
.
doc
,
o
.
rev4_7_history
);
o
.
rev5_8
=
"
5-
"
+
o
.
rev5_8_hash
;
o
.
rev5_8_history
=
clone
(
o
.
rev4_7_history
);
o
.
rev5_8_history
.
start
+=
1
;
o
.
rev5_8_history
.
ids
.
unshift
(
o
.
rev5_8_hash
);
o
.
rev5_8_revs_info
=
clone
(
o
.
rev4_7_revs_info
);
o
.
rev5_8_revs_info
.
unshift
({
"
rev
"
:
o
.
rev5_8
,
"
status
"
:
"
available
"
});
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1/attachment1
"
,
"
rev
"
:
o
.
rev5_8
},
"
Remove attachment
"
);
o
.
doc
.
_id
+=
"
/
"
+
o
.
doc
.
_attachment
;
delete
o
.
doc
.
_attachment
;
o
.
jio
.
remove
(
o
.
doc
,
o
.
f
);
o
.
tick
(
o
);
// remove document and conflict
o
.
rev
=
"
3-6
"
;
// __/__
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1
"
,
"
rev
"
:
o
.
rev
},
// / | \
"
Remove document
"
);
// 1-1 1-2 1-4
o
.
jio
.
remove
({
"
_id
"
:
"
doc1
"
,
"
_rev
"
:
"
2-5
"
},
o
.
f
);
// | |
// 2-3 2-5
// |
// 3-6+a1
// |
// 4-7+a1
// |
// 5-8
// get document to check attachment existence
o
.
doc
=
{
"
_id
"
:
"
doc1
"
,
"
_rev
"
:
o
.
rev5_8
,
"
title
"
:
"
Put revision, attachment must be copied
"
,
"
_conflicts
"
:
[
o
.
rev2_3
,
o
.
rev1_1
],
"
_revisions
"
:
o
.
rev5_8_history
,
"
_revs_info
"
:
o
.
rev5_8_revs_info
};
o
.
spy
(
o
,
"
value
"
,
o
.
doc
,
"
Get the new winner document, no attachment must be provided
"
);
o
.
jio
.
get
({
"
_id
"
:
"
doc1
"
},
{
"
conflicts
"
:
true
,
"
revs
"
:
true
,
"
revs_info
"
:
true
},
o
.
f
);
o
.
tick
(
o
);
o
.
tick
(
o
);
// remove document and conflict
// get specific document
o
.
rev
=
"
3-7
"
;
o
.
doc
=
{
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1
"
,
"
rev
"
:
o
.
rev
},
"
_id
"
:
"
doc1
"
,
"
Remove document
"
);
"
_rev
"
:
o
.
rev4_7
,
o
.
jio
.
remove
({
"
_id
"
:
"
doc1
"
,
"
_rev
"
:
"
2-3
"
},
o
.
f
);
"
title
"
:
o
.
doc
.
title
,
"
_attachments
"
:
{
"
attachment1
"
:
{
"
length
"
:
"
doc 1 - attachment 1
"
.
length
,
"
content_type
"
:
"
text/plain
"
,
"
digest
"
:
"
md5-0505c1fb6aae02dd1695d33841726564
"
}
},
"
_conflicts
"
:
[
o
.
rev2_3
,
o
.
rev1_1
],
"
_revisions
"
:
o
.
rev4_7_history
,
"
_revs_info
"
:
o
.
rev4_7_revs_info
};
o
.
spy
(
o
,
"
value
"
,
o
.
doc
,
"
Get the new winner document and its attachment metadata
"
);
o
.
jio
.
get
({
"
_id
"
:
"
doc1
"
,
"
_rev
"
:
o
.
rev4_7
},
{
"
conflicts
"
:
true
,
"
revs
"
:
true
,
"
revs_info
"
:
true
},
o
.
f
);
o
.
tick
(
o
);
// get inexistent attachment
o
.
spy
(
o
,
"
status
"
,
404
,
"
Get inexistent winner attachment
"
+
"
-> 404 Not Found
"
);
o
.
jio
.
get
({
"
_id
"
:
"
doc1/attachment1
"
},
o
.
f
);
o
.
tick
(
o
);
// get specific attachment
o
.
doc
=
{
"
_id
"
:
"
doc1
"
,
"
_attachment
"
:
"
attachment1
"
,
"
_rev
"
:
o
.
rev3_6
};
o
.
spy
(
o
,
"
value
"
,
"
doc 1 - attachment 1
"
,
"
Get a specific attachment
"
);
o
.
doc
.
_id
+=
"
/
"
+
o
.
doc
.
_attachment
;
delete
o
.
doc
.
_attachment
;
o
.
jio
.
get
(
o
.
doc
,
o
.
f
);
o
.
tick
(
o
);
// remove specific document and conflict
o
.
doc
=
{
"
_id
"
:
"
doc1
"
,
"
_rev
"
:
o
.
rev1_1
};
// generate with deleted_flag
o
.
rev2_9_hash
=
generateRevisionHash
(
o
.
doc
,
o
.
rev1_1_history
,
true
);
o
.
rev2_9
=
"
2-
"
+
o
.
rev2_9_hash
;
o
.
rev2_9_history
=
clone
(
o
.
rev1_1_history
);
o
.
rev2_9_history
.
start
+=
1
;
o
.
rev2_9_history
.
ids
.
unshift
(
o
.
rev2_9_hash
);
o
.
rev2_9_revs_info
=
clone
(
o
.
rev1_1_revs_info
);
o
.
rev2_9_revs_info
.
unshift
({
"
rev
"
:
o
.
rev2_9
,
"
status
"
:
"
available
"
});
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1
"
,
"
rev
"
:
o
.
rev2_9
},
"
Remove specific document, and one conflict
"
);
o
.
jio
.
remove
(
o
.
doc
,
o
.
f
);
o
.
tick
(
o
);
// __/___
// / | \
// 1-1 1-2 1-4
// | | |
// D2-9 2-3 2-5
// |
// 3-6+a1
// |
// 4-7+a1
// |
// 5-8
// remove specific document and conflict
o
.
doc
=
{
"
_id
"
:
"
doc1
"
,
"
_rev
"
:
o
.
rev2_3
};
o
.
rev3_10_hash
=
generateRevisionHash
(
o
.
doc
,
o
.
rev2_3_history
,
true
);
o
.
rev3_10
=
"
3-
"
+
o
.
rev3_10_hash
;
o
.
rev3_10_history
=
clone
(
o
.
rev2_3_history
);
o
.
rev3_10_history
.
start
+=
1
;
o
.
rev3_10_history
.
ids
.
unshift
(
o
.
rev3_10_hash
);
o
.
rev3_10_revs_info
=
clone
(
o
.
rev2_3_revs_info
);
o
.
rev3_10_revs_info
.
unshift
({
"
rev
"
:
o
.
rev3_10
,
"
status
"
:
"
available
"
});
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1
"
,
"
rev
"
:
o
.
rev3_10
},
"
Remove specific document, and one conflict
"
);
o
.
jio
.
remove
(
o
.
doc
,
o
.
f
);
o
.
tick
(
o
);
// ___/____
// / | \
// 1-1 1-2 1-4
// | | |
// D2-9 2-3 2-5
// | |
// D3-10 3-6+a1
// |
// 4-7+a1
// |
// 5-8
// get document no more conflict
o
.
doc
=
{
"
_id
"
:
"
doc1
"
,
"
_rev
"
:
o
.
rev5_8
,
"
title
"
:
"
Put revision, attachment must be copied
"
,
"
_revisions
"
:
o
.
rev5_8_history
,
"
_revs_info
"
:
o
.
rev5_8_revs_info
};
o
.
spy
(
o
,
"
value
"
,
o
.
doc
,
"
Get the new winner document, no more conflicts
"
);
o
.
jio
.
get
({
"
_id
"
:
"
doc1
"
},
{
"
conflicts
"
:
true
,
"
revs
"
:
true
,
"
revs_info
"
:
true
},
o
.
f
);
o
.
tick
(
o
);
o
.
tick
(
o
);
// remove document
// remove document
o
.
rev
=
"
2-8
"
;
o
.
doc
=
{
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1
"
,
"
rev
"
:
o
.
rev
},
"
_id
"
:
"
doc1
"
,
"
Remove document
"
);
"
_rev
"
:
o
.
rev5_8
o
.
jio
.
remove
({
"
_id
"
:
"
doc1
"
,
"
_rev
"
:
"
1-1
"
},
o
.
f
);
};
o
.
rev6_11_hash
=
generateRevisionHash
(
o
.
doc
,
o
.
rev5_8_history
,
true
);
o
.
rev6_11
=
"
6-
"
+
o
.
rev6_11_hash
;
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1
"
,
"
rev
"
:
o
.
rev6_11
},
"
Remove the last document
"
);
o
.
jio
.
remove
(
o
.
doc
,
o
.
f
);
o
.
tick
(
o
);
o
.
tick
(
o
);
// ___/____
// / | \
// 1-1 1-2 1-4
// | | |
// D2-9 2-3 2-5
// | |
// D3-10 3-6+a1
// |
// 4-7+a1
// |
// 5-8
// |
// D6-11
// get inexistent document
// get inexistent document
o
.
spy
(
o
,
"
status
"
,
404
,
"
Get inexistent document
"
);
o
.
spy
(
o
,
"
status
"
,
404
,
"
Get inexistent document -> 404 Not Found
"
);
o
.
jio
.
get
({
"
_id
"
:
"
doc3
"
},
{
"
conflicts
"
:
true
,
"
revs
"
:
true
,
"
revisions
"
:
true
},
o
.
f
);
o
.
tick
(
o
);
// get specific deleted document
o
.
spy
(
o
,
"
status
"
,
404
,
"
Get deleted document -> 404 Not Found
"
);
o
.
jio
.
get
({
"
_id
"
:
"
doc1
"
,
"
rev
"
:
o
.
rev3_10
},
{
"
conflicts
"
:
true
,
"
revs
"
:
true
,
"
revs_info
"
:
true
},
o
.
f
);
o
.
tick
(
o
);
// get specific deleted document
o
.
spy
(
o
,
"
status
"
,
404
,
"
Get deleted document -> 404 Not Found
"
);
o
.
jio
.
get
({
"
_id
"
:
"
doc1
"
},
{
o
.
jio
.
get
({
"
_id
"
:
"
doc1
"
},
{
"
conflicts
"
:
true
,
"
conflicts
"
:
true
,
"
revs
"
:
true
,
"
revs
"
:
true
,
...
@@ -2501,7 +2870,7 @@ module ("JIO Replicate Revision Storage");
...
@@ -2501,7 +2870,7 @@ module ("JIO Replicate Revision Storage");
};
};
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 +2883,7 @@ module ("JIO Replicate Revision Storage");
...
@@ -2514,7 +2883,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 +2899,27 @@ module ("JIO Replicate Revision Storage");
...
@@ -2530,27 +2899,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 +2958,269 @@ module ("JIO Replicate Revision Storage");
...
@@ -2589,6 +2958,269 @@ module ("JIO Replicate Revision Storage");
}]
}]
});
});
});
});
var
replicateStorageSynchronisationGenerator
=
function
(
that
,
description
,
index
)
{
var
o
=
generateTools
(
that
);
o
.
jio
=
JIO
.
newJio
(
description
);
o
.
localpath1
=
"
jio/localstorage/usyncreprevlocloc1/
"
+
index
;
o
.
localpath2
=
"
jio/localstorage/usyncreprevlocloc2/
"
+
index
;
o
.
localpath3
=
"
jio/localstorage/usyncreprevlocloc3/
"
+
index
;
o
.
localpath4
=
"
jio/localstorage/usyncreprevlocloc4/
"
+
index
;
// 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
.
localpath3
+
"
/doc1.revision_tree.json
"
,
o
.
doctree1_1
);
localstorage
.
setItem
(
o
.
localpath4
+
"
/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
);
localstorage
.
setItem
(
o
.
localpath3
+
"
/
"
+
o
.
doc1_1
.
_id
,
o
.
doc1_1
);
localstorage
.
setItem
(
o
.
localpath4
+
"
/
"
+
o
.
doc1_1
.
_id
,
o
.
doc1_1
);
// no synchronisation
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1
"
},
"
Check document
"
);
o
.
jio
.
check
({
"
_id
"
:
"
doc1
"
},
o
.
f
);
o
.
tick
(
o
);
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1
"
},
"
Repair document
"
);
o
.
jio
.
repair
({
"
_id
"
:
"
doc1
"
},
o
.
f
);
o
.
tick
(
o
);
// check documents from localstorage
deepEqual
(
localstorage
.
getItem
(
o
.
localpath1
+
"
/doc1.revision_tree.json
"
),
o
.
doctree1_1
,
"
Check revision tree 1, no synchro done
"
);
deepEqual
(
localstorage
.
getItem
(
o
.
localpath2
+
"
/doc1.revision_tree.json
"
),
o
.
doctree1_1
,
"
Check revision tree 2, no synchro done
"
);
deepEqual
(
localstorage
.
getItem
(
o
.
localpath3
+
"
/doc1.revision_tree.json
"
),
o
.
doctree1_1
,
"
Check revision tree 3, no synchro done
"
);
deepEqual
(
localstorage
.
getItem
(
o
.
localpath4
+
"
/doc1.revision_tree.json
"
),
o
.
doctree1_1
,
"
Check revision tree 4, no synchro done
"
);
// 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
"
,
"
_attachments
"
:
{
"
haha
"
:
{
"
length
"
:
3
,
"
digest
"
:
"
md5-900150983cd24fb0d6963f7d28e17f72
"
,
"
content_type
"
:
"
text/plain
"
}
}
};
localstorage
.
setItem
(
o
.
localpath1
+
"
/doc1.revision_tree.json
"
,
o
.
doctree2_2
);
localstorage
.
setItem
(
o
.
localpath1
+
"
/
"
+
o
.
doc2_2
.
_id
,
o
.
doc2_2
)
localstorage
.
setItem
(
o
.
localpath1
+
"
/
"
+
o
.
doc2_2
.
_id
+
"
/haha
"
,
"
abc
"
);
// document synchronisation without conflict
o
.
spy
(
o
,
"
status
"
,
41
,
"
Check document
"
);
o
.
jio
.
check
({
"
_id
"
:
"
doc1
"
},
o
.
f
);
o
.
tick
(
o
,
50000
);
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1
"
},
"
Repair document
"
);
o
.
jio
.
repair
({
"
_id
"
:
"
doc1
"
},
o
.
f
);
o
.
tick
(
o
,
50000
);
// check documents from localstorage
deepEqual
(
localstorage
.
getItem
(
o
.
localpath1
+
"
/doc1.revision_tree.json
"
),
o
.
doctree2_2
,
"
Check revision tree 1, no synchro done
"
);
deepEqual
(
localstorage
.
getItem
(
o
.
localpath2
+
"
/doc1.revision_tree.json
"
),
o
.
doctree2_2
,
"
Check revision tree 2, revision synchro done
"
);
deepEqual
(
localstorage
.
getItem
(
o
.
localpath3
+
"
/doc1.revision_tree.json
"
),
o
.
doctree2_2
,
"
Check revision tree 3, revision synchro done
"
);
deepEqual
(
localstorage
.
getItem
(
o
.
localpath3
+
"
/doc1.2-222
"
),
o
.
doc2_2
,
"
Check document 3
"
);
deepEqual
(
localstorage
.
getItem
(
o
.
localpath3
+
"
/doc1.2-222/haha
"
),
"
abc
"
,
"
Check attachment 3
"
);
deepEqual
(
localstorage
.
getItem
(
o
.
localpath4
+
"
/doc1.revision_tree.json
"
),
o
.
doctree2_2
,
"
Check revision tree 4, revision synchro done
"
);
// add documents to localstorage
o
.
doctree2_3
=
clone
(
o
.
doctree2_2
);
o
.
doctree2_3
.
children
[
0
].
children
.
unshift
({
"
rev
"
:
"
2-223
"
,
"
status
"
:
"
available
"
,
"
children
"
:
[]
});
o
.
doc2_3
=
{
"
_id
"
:
"
doc1.2-223
"
,
"
title
"
:
"
C
"
};
localstorage
.
setItem
(
o
.
localpath1
+
"
/doc1.revision_tree.json
"
,
o
.
doctree2_3
);
localstorage
.
setItem
(
o
.
localpath1
+
"
/
"
+
o
.
doc2_3
.
_id
,
o
.
doc2_3
);
// document synchronisation with conflict
o
.
spy
(
o
,
"
status
"
,
41
,
"
Check document
"
);
o
.
jio
.
check
({
"
_id
"
:
"
doc1
"
},
o
.
f
);
o
.
tick
(
o
,
50000
);
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1
"
},
"
Repair document
"
);
o
.
jio
.
repair
({
"
_id
"
:
"
doc1
"
},
o
.
f
);
o
.
tick
(
o
,
50000
);
// check documents from localstorage
deepEqual
(
localstorage
.
getItem
(
o
.
localpath1
+
"
/doc1.revision_tree.json
"
),
o
.
doctree2_3
,
"
Check revision tree 1, rev synchro
"
);
deepEqual
(
localstorage
.
getItem
(
o
.
localpath2
+
"
/doc1.revision_tree.json
"
),
o
.
doctree2_3
,
"
Check revision tree 2, rev synchro
"
);
deepEqual
(
localstorage
.
getItem
(
o
.
localpath3
+
"
/doc1.revision_tree.json
"
),
o
.
doctree2_3
,
"
Check revision tree 3, rev synchro
"
);
deepEqual
(
localstorage
.
getItem
(
o
.
localpath3
+
"
/doc1.2-223
"
),
o
.
doc2_3
,
"
Check document 3
"
);
deepEqual
(
localstorage
.
getItem
(
o
.
localpath4
+
"
/doc1.revision_tree.json
"
),
o
.
doctree2_3
,
"
Check revision tree 4, rev synchro
"
);
o
.
jio
.
stop
();
};
test
(
"
Storage Synchronisation (Repair) 4x [Rev + Local]
"
,
function
()
{
replicateStorageSynchronisationGenerator
(
this
,
{
"
type
"
:
"
replicaterevision
"
,
"
storage_list
"
:
[{
"
type
"
:
"
revision
"
,
"
sub_storage
"
:
{
"
type
"
:
"
local
"
,
"
username
"
:
"
usyncreprevlocloc1
"
,
"
application_name
"
:
"
1
"
}
},
{
"
type
"
:
"
revision
"
,
"
sub_storage
"
:
{
"
type
"
:
"
local
"
,
"
username
"
:
"
usyncreprevlocloc2
"
,
"
application_name
"
:
"
1
"
}
},
{
"
type
"
:
"
revision
"
,
"
sub_storage
"
:
{
"
type
"
:
"
local
"
,
"
username
"
:
"
usyncreprevlocloc3
"
,
"
application_name
"
:
"
1
"
}
},
{
"
type
"
:
"
revision
"
,
"
sub_storage
"
:
{
"
type
"
:
"
local
"
,
"
username
"
:
"
usyncreprevlocloc4
"
,
"
application_name
"
:
"
1
"
}
}]
},
"
1
"
);
});
test
(
"
Storage Synchronisation (Repair) 2x [Rep 2x [Rev + Local]]
"
,
function
()
{
replicateStorageSynchronisationGenerator
(
this
,
{
"
type
"
:
"
replicaterevision
"
,
"
storage_list
"
:
[{
"
type
"
:
"
replicaterevision
"
,
"
storage_list
"
:
[{
"
type
"
:
"
revision
"
,
"
sub_storage
"
:
{
"
type
"
:
"
local
"
,
"
username
"
:
"
usyncreprevlocloc1
"
,
"
application_name
"
:
"
2
"
}
},
{
"
type
"
:
"
revision
"
,
"
sub_storage
"
:
{
"
type
"
:
"
local
"
,
"
username
"
:
"
usyncreprevlocloc2
"
,
"
application_name
"
:
"
2
"
}
}]
},
{
"
type
"
:
"
replicaterevision
"
,
"
storage_list
"
:
[{
"
type
"
:
"
revision
"
,
"
sub_storage
"
:
{
"
type
"
:
"
local
"
,
"
username
"
:
"
usyncreprevlocloc3
"
,
"
application_name
"
:
"
2
"
}
},
{
"
type
"
:
"
revision
"
,
"
sub_storage
"
:
{
"
type
"
:
"
local
"
,
"
username
"
:
"
usyncreprevlocloc4
"
,
"
application_name
"
:
"
2
"
}
}]
}]
},
"
2
"
);
});
/*
/*
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