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
Hide 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,303 +143,536 @@ jIO.addStorageType('replicaterevision', function (spec, my) {
...
@@ -188,303 +143,536 @@ 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
(
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
;
}
if
(
typeof
doc
.
_id
!==
"
string
"
)
{
doc
.
_id
=
priv
.
generateUuid
();
}
if
(
priv
.
post_allowed
===
undefined
)
{
priv
.
post_allowed
=
true
;
}
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
(
doc_env
.
last_revisions
[
i
]
===
"
unique_
"
+
i
||
priv
.
put_only
?
"
put
"
:
"
post
"
,
i
,
cloned_doc
,
command
.
cloneOption
(),
functions
.
checkSendResult
);
}
};
functions
.
checkSendResult
=
function
(
method
,
index
,
err
,
response
)
{
if
(
err
)
{
if
(
err
)
{
if
(
err
.
status
===
409
)
{
error_count
+=
1
;
if
(
method
!==
"
put
"
)
{
last_error
=
err
;
functions
.
sendDocumentIndex
(
if
(
error_count
===
priv
.
storage_list
.
length
)
{
"
put
"
,
return
callback
(
method
,
err
,
response
);
index
,
functions
.
checkSendResult
);
return
;
}
}
}
priv
.
updateEnv
(
doc_env
,
my_rev
,
index
,
null
);
functions
.
error
(
err
);
return
;
}
}
// success
callback
(
method
,
err
,
response
);
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
)
{
for
(
i
=
0
;
i
<
priv
.
storage_list
.
length
;
i
+=
1
)
{
// can be called once
priv
.
send
(
method
,
i
,
doc
,
option
,
callbackWrapper
);
that
.
success
(
response
);
}
functions
.
success
=
priv
.
emptyFunction
;
};
};
functions
.
error_count
=
0
;
/**
functions
.
error
=
function
(
err
)
{
* Use "sendToAll" method, calling "callback" at the last response with
functions
.
error_count
+=
1
;
* the response list
if
(
functions
.
error_count
===
priv
.
storage_list
.
length
)
{
* @method sendToAllGetResponseList
that
.
error
(
err
);
* @param {string} method The request method
functions
.
error
=
priv
.
emptyFunction
;
* @param {object} doc The document object
* @param {object} option The request option
* @return {function} callback The callback. Parameters:
* - {string} The request method
* - {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
);
}
}
};
};
functions
.
begin
(
);
priv
.
sendToAll
(
method
,
doc
,
option
,
wrapper
);
};
};
/**
/**
*
Put the document metadata to all sub storages
*
Checks if the sub storage are identical
* @method
put
* @method
check
* @param {object} command The JIO command
* @param {object} command The JIO command
*/
*/
that
.
put
=
function
(
command
)
{
that
.
check
=
function
(
command
)
{
priv
.
put_only
=
true
;
function
callback
(
err
,
response
)
{
that
.
post
(
command
);
if
(
err
)
{
return
that
.
error
(
err
);
}
that
.
success
(
response
);
}
priv
.
check
(
command
.
cloneDoc
(),
command
.
cloneOption
(),
callback
);
};
};
/**
/**
*
Put an attachment to a document to all sub storages
*
Repair the sub storages to make them identical
* @method
putAttachment
* @method
repair
* @param {object} command The JIO command
* @param {object} command The JIO command
*/
*/
// that.putAttachment = function (command) {
that
.
repair
=
function
(
command
)
{
function
callback
(
err
,
response
)
{
if
(
err
)
{
return
that
.
error
(
err
);
}
that
.
success
(
response
);
}
priv
.
repair
(
command
.
cloneDoc
(),
command
.
cloneOption
(),
true
,
callback
);
};
// };
priv
.
check
=
function
(
doc
,
option
,
success
,
error
)
{
priv
.
repair
(
doc
,
option
,
false
,
success
,
error
);
};
/**
priv
.
repair
=
function
(
doc
,
option
,
repair
,
callback
)
{
* Get the document or attachment from all sub storages, get the fastest.
var
functions
=
{};
* @method get
callback
=
callback
||
priv
.
emptyFunction
;
* @param {object} command The JIO command
option
=
option
||
{};
*/
that
.
get
=
function
(
command
)
{
var
functions
=
{},
doc_env
,
doc
,
my_rev
,
revs_array
=
[];
functions
.
begin
=
function
()
{
functions
.
begin
=
function
()
{
// };
// functions.repairAllSubStorages = function () {
var
i
;
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
)
{
for
(
i
=
0
;
i
<
priv
.
storage_list
.
length
;
i
+=
1
)
{
// request all sub storages
priv
.
send
(
if
(
doc_env
.
my_revisions
[
my_rev
])
{
repair
?
"
repair
"
:
"
check
"
,
// if my_rev exist, convert it to distant revision
i
,
doc
.
_rev
=
doc_env
.
my_revisions
[
my_rev
][
i
];
doc
,
}
option
,
priv
.
send
(
"
get
"
,
i
,
doc
,
command
.
cloneOption
(),
functions
.
callback
);
functions
.
repairAllSubStoragesCallback
);
}
}
};
};
functions
.
update_env
=
true
;
functions
.
repair_sub_storages_count
=
0
;
functions
.
callback
=
function
(
method
,
index
,
err
,
response
)
{
functions
.
repairAllSubStoragesCallback
=
function
(
method
,
index
,
err
,
response
)
{
if
(
err
)
{
if
(
err
)
{
revs_array
[
index
]
=
null
;
return
that
.
error
(
err
);
functions
.
error
(
err
);
return
;
}
}
doc_env
.
last_revisions
[
index
]
=
response
.
_rev
||
"
unique_
"
+
index
;
functions
.
repair_sub_storages_count
+=
1
;
revs_array
[
index
]
=
response
.
_rev
||
"
unique_
"
+
index
;
if
(
functions
.
repair_sub_storages_count
===
priv
.
storage_list
.
length
)
{
if
(
doc_env
.
distant_revisions
[
response
.
_rev
||
"
unique_
"
+
index
])
{
functions
.
getAllDocuments
(
functions
.
newParam
(
// the document revision is already known
doc
,
if
(
functions
.
update_env
===
true
)
{
option
,
my_rev
=
doc_env
.
distant_revisions
[
response
.
_rev
||
repair
"
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
)
{
functions
.
newParam
=
function
(
doc
,
option
,
repair
)
{
var
i
,
start
,
tmp
,
tmp_object
;
var
param
=
{
functions
.
success
=
priv
.
emptyFunction
;
"
doc
"
:
doc
,
// the document to repair
if
(
doc_env
.
my_revisions
[
my_rev
])
{
"
option
"
:
option
,
// this was not a specific revision
"
repair
"
:
repair
,
// we can convert revisions recieved by the sub storage
"
responses
"
:
{
if
(
response
.
_conflicts
)
{
"
count
"
:
0
,
// convert conflicting revisions to replicate revisions
"
list
"
:
[
tmp_object
=
{};
// 0: response0
for
(
i
=
0
;
i
<
response
.
_conflicts
.
length
;
i
+=
1
)
{
// 1: response1
tmp_object
[
doc_env
.
distant_revisions
[
response
.
_conflicts
[
i
]]
||
// 2: response2
response
.
_conflicts
[
i
]]
=
true
;
],
"
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: ..}
}
}
response
.
_conflicts
=
priv
.
dictKeys2Array
(
tmp_object
);
},
"
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
(
response
.
_revisions
)
{
if
(
err
)
{
// convert revisions history to replicate revisions
if
(
err
.
status
!==
404
)
{
tmp_object
=
{};
// get document failed, exit
start
=
response
.
_revisions
.
start
;
param
.
deal_result_state
=
"
error
"
;
for
(
i
=
0
;
i
<
response
.
_revisions
.
ids
.
length
;
i
+=
1
,
start
-=
1
)
{
callback
({
tmp
=
doc_env
.
distant_revisions
[
"
status
"
:
40
,
start
+
"
-
"
+
response
.
_revisions
.
ids
[
i
]
"
statusText
"
:
"
Check Failed
"
,
];
"
error
"
:
"
check_failed
"
,
if
(
tmp
)
{
"
message
"
:
"
An error occured on the sub storage
"
,
response
.
_revisions
.
ids
[
i
]
=
tmp
.
split
(
"
-
"
).
slice
(
1
).
join
(
"
-
"
);
"
reason
"
:
err
.
reason
}
},
undefined
);
return
;
}
}
}
}
if
(
response
.
_revs_info
)
{
// success to get the document
// convert revs info to replicate revisions
// add the response in memory
for
(
i
=
0
;
i
<
response
.
_revs_info
.
length
;
i
+=
1
)
{
param
.
responses
.
count
+=
1
;
tmp
=
doc_env
.
distant_revisions
[
response
.
_revs_info
[
i
].
rev
];
param
.
responses
.
list
[
index
]
=
response
;
if
(
tmp
)
{
response
.
_revs_info
[
i
].
rev
=
tmp
;
// 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
;
}
}
that
.
success
(
response
);
};
};
functions
.
error_count
=
0
;
functions
.
makeResponsesStats
=
function
(
responses
)
{
functions
.
error
=
function
(
err
)
{
var
i
,
str_response
;
functions
.
error_count
+=
1
;
for
(
i
=
0
;
i
<
responses
.
count
;
i
+=
1
)
{
if
(
functions
.
error_count
===
priv
.
storage_list
.
length
)
{
str_response
=
JSON
.
stringify
(
responses
.
list
[
i
]);
that
.
error
(
err
);
if
(
responses
.
stats
[
str_response
]
===
undefined
)
{
functions
.
error
=
priv
.
emptyFunction
;
responses
.
stats
[
str_response
]
=
[];
responses
.
stats_items
.
push
([
str_response
,
responses
.
stats
[
str_response
]
]);
}
responses
.
stats
[
str_response
].
push
(
i
);
}
}
};
};
functions
.
begin
();
functions
.
getAttachments
=
function
(
param
)
{
};
var
response
,
parsed_response
,
attachment
;
for
(
response
in
param
.
responses
.
stats
)
{
/**
if
(
param
.
responses
.
stats
.
hasOwnProperty
(
response
))
{
* Remove the document or attachment from all sub storages.
parsed_response
=
JSON
.
parse
(
response
);
* @method remove
for
(
attachment
in
parsed_response
.
_attachments
)
{
* @param {object} command The JIO command
if
((
parsed_response
.
_attachments
).
hasOwnProperty
(
attachment
))
{
*/
functions
.
get_attachment_count
+=
1
;
that
.
remove
=
function
(
command
)
{
priv
.
send
(
var
functions
=
{},
doc_env
,
revs_info
,
doc
,
my_rev
;
"
get
"
,
functions
.
begin
=
function
()
{
param
.
responses
.
stats
[
response
][
0
],
doc
=
command
.
cloneDoc
();
{
"
_id
"
:
param
.
doc
.
_id
+
"
/
"
+
attachment
,
if
(
typeof
doc
.
_rev
===
"
string
"
&&
!
priv
.
checkRevisionFormat
(
doc
.
_rev
))
{
"
_rev
"
:
JSON
.
parse
(
response
).
_rev
that
.
error
({
},
"
status
"
:
31
,
param
.
option
,
"
statusText
"
:
"
Wrong Revision Format
"
,
functions
.
getAttachmentsCallback
(
"
error
"
:
"
wrong_revision_format
"
,
param
,
"
message
"
:
"
The document previous revision does not match
"
+
attachment
,
"
^[0-9]+-[0-9a-zA-Z]+$
"
,
param
.
responses
.
stats
[
response
]
"
reason
"
:
"
Previous revision is wrong
"
)
});
);
return
;
}
}
}
}
}
doc_env
=
my
.
env
[
doc
.
_id
];
};
if
(
!
doc_env
||
!
doc_env
.
id
)
{
functions
.
get_attachment_count
=
0
;
doc_env
=
priv
.
initEnv
(
doc
.
_id
);
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
;
}
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
]
);
}
}
}
}
my_rev
=
priv
.
generateNextRevision
(
doc
.
_rev
||
0
,
doc
.
_id
);
functions
.
finished_count
-=
1
;
functions
.
sendDocument
();
};
};
functions
.
sendDocument
=
function
()
{
functions
.
synchronizeResponseToSubStorage
=
function
(
var
i
,
cloned_doc
;
param
,
for
(
i
=
0
;
i
<
priv
.
storage_list
.
length
;
i
+=
1
)
{
response
,
cloned_doc
=
priv
.
clone
(
doc
);
storage_list
if
(
typeof
cloned_doc
.
_rev
===
"
string
"
&&
)
{
doc_env
.
my_revisions
[
cloned_doc
.
_rev
]
!==
undefined
)
{
var
i
,
new_doc
,
attachment_to_put
=
[];
cloned_doc
.
_rev
=
doc_env
.
my_revisions
[
cloned_doc
.
_rev
][
i
];
if
(
response
===
undefined
)
{
// no response to sync
return
;
}
new_doc
=
JSON
.
parse
(
response
);
new_doc
.
_revs
=
new_doc
.
_revisions
;
delete
new_doc
.
_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
(
priv
.
send
(
"
remove
"
,
"
put
"
,
i
,
storage_list
[
i
]
,
cloned
_doc
,
new
_doc
,
command
.
cloneOption
()
,
param
.
option
,
functions
.
checkSendResult
functions
.
putAttachments
(
param
,
attachment_to_put
)
);
);
}
}
that
.
end
();
functions
.
finished_count
+=
1
;
functions
.
finished
();
};
};
functions
.
checkSendResult
=
function
(
method
,
index
,
err
,
response
)
{
functions
.
synchronizeConflicts
=
function
(
param
)
{
if
(
err
)
{
var
rev
,
new_doc
,
new_option
;
priv
.
updateEnv
(
doc_env
,
my_rev
,
index
,
null
);
new_option
=
priv
.
clone
(
param
.
option
);
functions
.
error
(
err
);
new_option
.
synchronize_conflict
=
false
;
return
;
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
));
}
}
}
// 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
)
{
functions
.
putAttachments
=
function
(
param
,
attachment_to_put
)
{
// can be called once
return
function
(
method
,
index
,
err
,
response
)
{
that
.
success
(
response
);
var
i
,
attachment
;
functions
.
success
=
priv
.
emptyFunction
;
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
,
attachment
,
option
,
functions
.
putAttachmentCallback
(
param
)
);
}
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
.
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
* @method put
* @param {object} command The JIO command
*/
that
.
put
=
function
(
command
)
{
that
.
genericRequest
(
command
,
"
post
"
);
};
/**
* Put an attachment to a document to all sub storages
* @method putAttachment
* @param {object} command The JIO command
*/
that
.
putAttachment
=
function
(
command
)
{
that
.
genericRequest
(
command
,
"
putAttachment
"
);
};
/**
* Get the document from all sub storages, get the fastest.
* @method get
* @param {object} command The JIO command
*/
that
.
get
=
function
(
command
)
{
that
.
genericRequest
(
command
,
"
get
"
);
};
/**
* 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 from all sub storages.
* @method remove
* @param {object} command The JIO command
*/
that
.
remove
=
function
(
command
)
{
that
.
genericRequest
(
command
,
"
remove
"
);
};
/**
* 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
;
revs_info
.
unshift
({
string
=
JSON
.
stringify
(
doc
)
+
JSON
.
stringify
(
revision_history
)
+
"
rev
"
:
document_tree
.
rev
,
JSON
.
stringify
(
deleted_flag
?
true
:
false
);
"
status
"
:
document_tree
.
status
revision_history
.
start
+=
1
;
});
revision_history
.
ids
.
unshift
(
priv
.
hashCode
(
string
));
if
(
document_tree
.
rev
===
revision
)
{
doc
.
_revs
=
revision_history
;
result
=
revs_info
;
doc
.
_rev
=
revision_history
.
start
+
"
-
"
+
revision_history
.
ids
[
0
];
return
;
revs_info
.
unshift
({
"
rev
"
:
doc
.
_rev
,
"
status
"
:
deleted_flag
?
"
deleted
"
:
"
available
"
});
doc
.
_revs_info
=
revs_info
;
return
doc
;
};
/**
* Gets the revs info from the document tree
* @method getRevisionInfo
* @param {string} revision The revision to search for
* @param {object} doc_tree The document tree
* @return {array} The revs info
*/
priv
.
getRevisionInfo
=
function
(
revision
,
doc_tree
)
{
var
getRevisionInfoRec
;
getRevisionInfoRec
=
function
(
doc_tree
)
{
var
i
,
child
,
revs_info
;
for
(
i
=
0
;
i
<
doc_tree
.
children
.
length
;
i
+=
1
)
{
child
=
doc_tree
.
children
[
i
];
if
(
child
.
rev
===
revision
)
{
return
[{
"
rev
"
:
child
.
rev
,
"
status
"
:
child
.
status
}];
}
}
}
revs_info
=
getRevisionInfoRec
(
child
);
// This node has children
if
(
revs_info
.
length
>
0
||
revision
===
undefined
)
{
for
(
i
=
0
;
i
<
document_tree
.
children
.
length
;
i
+=
1
)
{
revs_info
.
push
({
"
rev
"
:
child
.
rev
,
"
status
"
:
child
.
status
});
// searching deeper to find the good rev
return
revs_info
;
search
(
document_tree
.
children
[
i
]);
if
(
result
.
length
>
0
)
{
// The result is already found
return
;
}
}
revs_info
.
shift
();
}
}
return
[];
};
};
search
(
document_tree
);
return
getRevisionInfoRec
(
doc_tree
);
return
result
;
};
};
/**
priv
.
updateDocumentTree
=
function
(
doc
,
doc_tree
)
{
* Gets the winner revision from a document tree.
var
revs_info
,
updateDocumentTreeRec
,
next_rev
;
* The winner is the deeper revision on the left.
doc
=
priv
.
clone
(
doc
);
* @method getWinnerRevisionFromDocumentTree
revs_info
=
doc
.
_revs_info
;
* @param {object} document_tree The document tree
updateDocumentTreeRec
=
function
(
doc_tree
,
revs_info
)
{
* @return {array} The winner revs info array
var
i
,
child
,
info
;
*/
if
(
revs_info
.
length
===
0
)
{
priv
.
getWinnerRevisionFromDocumentTree
=
function
(
document_tree
)
{
var
result
,
search
,
revs_info
=
[];
result
=
[];
// search method fills "result" with the winner revs info
search
=
function
(
document_tree
,
deep
)
{
var
i
;
if
(
document_tree
.
rev
!==
undefined
)
{
// node is not root
revs_info
.
unshift
({
"
rev
"
:
document_tree
.
rev
,
"
status
"
:
document_tree
.
status
});
}
if
(
document_tree
.
children
.
length
===
0
&&
document_tree
.
status
!==
"
deleted
"
)
{
// This node is a leaf
if
(
result
.
length
<
deep
)
{
// The leaf is deeper than result
result
=
[];
for
(
i
=
0
;
i
<
revs_info
.
length
;
i
+=
1
)
{
result
.
push
(
revs_info
[
i
]);
}
}
return
;
return
;
}
}
// This node has children
info
=
revs_info
.
pop
();
for
(
i
=
0
;
i
<
document_tree
.
children
.
length
;
i
+=
1
)
{
for
(
i
=
0
;
i
<
doc_tree
.
children
.
length
;
i
+=
1
)
{
// searching deeper to find the deeper leaf
child
=
doc_tree
.
children
[
i
];
search
(
document_tree
.
children
[
i
],
deep
+
1
);
if
(
child
.
rev
===
info
.
rev
)
{
revs_info
.
shift
();
return
updateDocumentTreeRec
(
child
,
revs_info
);
}
}
}
doc_tree
.
children
.
unshift
({
"
rev
"
:
info
.
rev
,
"
status
"
:
info
.
status
,
"
children
"
:
[]
});
updateDocumentTreeRec
(
doc_tree
.
children
[
0
],
revs_info
);
};
};
search
(
document_tree
,
0
);
updateDocumentTreeRec
(
doc_tree
,
priv
.
clone
(
revs_info
));
return
result
;
};
};
/**
priv
.
send
=
function
(
method
,
doc
,
option
,
callback
)
{
* Add a document revision branch to the document tree
that
.
addJob
(
* @method updateDocumentTree
method
,
* @param {object} doctree The document tree object
priv
.
sub_storage
,
* @param {object|array} revs The revision history object or a revision array
doc
,
* @param {boolean} deleted The deleted flag
option
,
* @param {array} The document revs_info
function
(
success
)
{
*/
callback
(
undefined
,
success
);
priv
.
updateDocumentTree
=
function
(
doctree
,
revs
,
deleted
)
{
},
var
revs_info
,
doctree_iterator
,
flag
,
i
,
rev
;
function
(
err
)
{
revs_info
=
[];
callback
(
err
,
undefined
);
if
(
revs
.
ids
)
{
// revs is a revision history object
revs
=
priv
.
revisionHistoryToArray
(
revs
);
}
else
{
// revs is an array of revisions
revs
=
priv
.
clone
(
revs
);
}
doctree_iterator
=
doctree
;
while
(
revs
.
length
>
0
)
{
rev
=
revs
.
pop
(
0
);
revs_info
.
unshift
({
"
rev
"
:
rev
,
"
status
"
:
"
missing
"
});
for
(
i
=
0
;
i
<
doctree_iterator
.
children
.
length
;
i
+=
1
)
{
if
(
doctree_iterator
.
children
[
i
].
rev
===
rev
)
{
doctree_iterator
=
doctree_iterator
.
children
[
i
];
revs_info
[
0
].
status
=
doctree_iterator
.
status
;
rev
=
undefined
;
break
;
}
}
if
(
rev
)
{
doctree_iterator
.
children
.
unshift
({
"
rev
"
:
rev
,
"
status
"
:
"
missing
"
,
"
children
"
:
[]
});
doctree_iterator
=
doctree_iterator
.
children
[
0
];
}
}
}
);
flag
=
deleted
===
true
?
"
deleted
"
:
"
available
"
;
revs_info
[
0
].
status
=
flag
;
doctree_iterator
.
status
=
flag
;
return
revs_info
;
};
};
/**
priv
.
getWinnerRevsInfo
=
function
(
doc_tree
)
{
* Add a document revision to the document tree
var
revs_info
=
[],
getWinnerRevsInfoRec
;
* @method postToDocumentTree
getWinnerRevsInfoRec
=
function
(
doc_tree
,
tmp_revs_info
)
{
* @param {object} doctree The document tree object
* @param {object} doc The document object
* @param {boolean} set_node_to_deleted Set the revision to deleted
* @return {array} The added document revs_info
*/
priv
.
postToDocumentTree
=
function
(
doctree
,
doc
,
set_node_to_deleted
)
{
var
i
,
revs_info
,
next_rev
,
next_rev_str
,
selectNode
,
selected_node
,
flag
;
flag
=
set_node_to_deleted
===
true
?
"
deleted
"
:
"
available
"
;
revs_info
=
[];
selected_node
=
doctree
;
selectNode
=
function
(
node
)
{
var
i
;
var
i
;
if
(
node
.
rev
!==
undefined
)
{
if
(
doc_tree
.
rev
)
{
// node is not root
tmp_revs_info
.
unshift
({
"
rev
"
:
doc_tree
.
rev
,
"
status
"
:
doc_tree
.
status
});
revs_info
.
unshift
({
"
rev
"
:
node
.
rev
,
"
status
"
:
node
.
status
});
}
}
if
(
node
.
rev
===
doc
.
_rev
)
{
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
();
}
};
if
(
typeof
doc
.
_rev
===
"
string
"
)
{
// document has a previous revision
if
(
selectNode
(
selected_node
)
!==
"
node_selected
"
)
{
// no node was selected, so add a node with a specific rev
revs_info
.
unshift
({
"
rev
"
:
doc
.
_rev
,
"
status
"
:
"
missing
"
});
selected_node
.
children
.
unshift
(
priv
.
createDocumentTreeNode
(
doc
.
_rev
,
"
missing
"
));
selected_node
=
selected_node
.
children
[
0
];
}
}
}
for
(
i
=
0
;
i
<
doc_tree
.
children
.
length
;
i
+=
1
)
{
next_rev
=
priv
.
generateNextRevision
(
getWinnerRevsInfoRec
(
doc_tree
.
children
[
i
],
tmp_revs_info
);
doc
.
_rev
||
0
,
doc
,
priv
.
revsInfoToHistory
(
revs_info
),
set_node_to_deleted
);
next_rev_str
=
next_rev
.
join
(
"
-
"
);
// don't add if the next rev already exists
for
(
i
=
0
;
i
<
selected_node
.
children
.
length
;
i
+=
1
)
{
if
(
selected_node
.
children
[
i
].
rev
===
next_rev_str
)
{
revs_info
.
unshift
({
"
rev
"
:
next_rev_str
,
"
status
"
:
flag
});
if
(
selected_node
.
children
[
i
].
status
!==
flag
)
{
selected_node
.
children
[
i
].
status
=
flag
;
}
return
revs_info
;
}
}
}
tmp_revs_info
.
shift
();
revs_info
.
unshift
({
};
"
rev
"
:
next_rev
.
join
(
'
-
'
),
getWinnerRevsInfoRec
(
doc_tree
,
[]);
"
status
"
:
flag
});
selected_node
.
children
.
unshift
(
priv
.
createDocumentTreeNode
(
next_rev
.
join
(
'
-
'
),
flag
));
return
revs_info
;
return
revs_info
;
};
};
/**
priv
.
getConflicts
=
function
(
revision
,
doc_tree
)
{
* Gets an array of leaves revisions from document tree
var
conflicts
=
[],
getConflictsRec
;
* @method getLeavesFromDocumentTree
getConflictsRec
=
function
(
doc_tree
)
{
* @param {object} document_tree The document tree
* @param {string} except The revision to except
* @return {array} The array of leaves revisions
*/
priv
.
getLeavesFromDocumentTree
=
function
(
document_tree
,
except
)
{
var
result
,
search
;
result
=
[];
// search method fills [result] with the winner revision
search
=
function
(
document_tree
)
{
var
i
;
var
i
;
if
(
except
!==
undefined
&&
except
===
document_tree
.
rev
)
{
if
(
doc_tree
.
rev
===
revision
)
{
return
;
return
;
}
}
if
(
document_tree
.
children
.
length
===
0
&&
document_tree
.
status
!==
if
(
doc_tree
.
children
.
length
===
0
)
{
"
deleted
"
)
{
if
(
doc_tree
.
status
!==
"
deleted
"
)
{
// This node is a leaf
conflicts
.
push
(
doc_tree
.
rev
);
result
.
push
(
document_tree
.
rev
);
}
return
;
}
}
// This node has children
for
(
i
=
0
;
i
<
doc_tree
.
children
.
length
;
i
+=
1
)
{
for
(
i
=
0
;
i
<
document_tree
.
children
.
length
;
i
+=
1
)
{
getConflictsRec
(
doc_tree
.
children
[
i
]);
// searching deeper to find the deeper leaf
search
(
document_tree
.
children
[
i
]);
}
}
};
};
search
(
document
_tree
);
getConflictsRec
(
doc
_tree
);
return
result
;
return
conflicts
.
length
===
0
?
undefined
:
conflicts
;
};
};
/**
priv
.
get
=
function
(
doc
,
option
,
callback
)
{
* Check if revision is a leaf
priv
.
send
(
"
get
"
,
doc
,
option
,
callback
);
* @method isRevisionALeaf
};
* @param {string} revision revision to check
priv
.
put
=
function
(
doc
,
option
,
callback
)
{
* @param {array} leaves all leaves on tree
priv
.
send
(
"
put
"
,
doc
,
option
,
callback
);
* @return {boolean} true/false
};
*/
priv
.
remove
=
function
(
doc
,
option
,
callback
)
{
priv
.
isRevisionALeaf
=
function
(
document_tree
,
revision
)
{
priv
.
send
(
"
remove
"
,
doc
,
option
,
callback
);
var
result
,
search
;
};
result
=
undefined
;
priv
.
putAttachment
=
function
(
attachment
,
option
,
callback
)
{
// search method fills "result" with the good revs info
priv
.
send
(
"
putAttachment
"
,
attachment
,
option
,
callback
);
search
=
function
(
document_tree
)
{
};
var
i
;
if
(
document_tree
.
rev
!==
undefined
)
{
priv
.
getDocument
=
function
(
doc
,
option
,
callback
)
{
// node is not root
doc
=
priv
.
clone
(
doc
);
if
(
document_tree
.
rev
===
revision
)
{
doc
.
_id
=
doc
.
_id
+
"
.
"
+
doc
.
_rev
;
if
(
document_tree
.
children
.
length
===
0
)
{
delete
doc
.
_attachment
;
// This node is a leaf
delete
doc
.
_rev
;
result
=
true
;
delete
doc
.
_revs
;
return
;
delete
doc
.
_revs_info
;
}
priv
.
get
(
doc
,
option
,
callback
);
result
=
false
;
};
priv
.
getAttachment
=
priv
.
get
;
priv
.
putDocument
=
function
(
doc
,
option
,
callback
)
{
doc
=
priv
.
clone
(
doc
);
doc
.
_id
=
doc
.
_id
+
"
.
"
+
doc
.
_rev
;
delete
doc
.
_attachment
;
delete
doc
.
_data
;
delete
doc
.
_mimetype
;
delete
doc
.
_rev
;
delete
doc
.
_revs
;
delete
doc
.
_revs_info
;
priv
.
put
(
doc
,
option
,
callback
);
};
priv
.
getRevisionTree
=
function
(
doc
,
option
,
callback
)
{
doc
=
priv
.
clone
(
doc
);
doc
.
_id
=
doc
.
_id
+
priv
.
doc_tree_suffix
;
priv
.
get
(
doc
,
option
,
callback
);
};
priv
.
getAttachmentList
=
function
(
doc
,
option
,
callback
)
{
var
attachment_id
,
dealResults
,
state
=
"
ok
"
,
result_list
=
[],
count
=
0
;
dealResults
=
function
(
attachment_id
,
attachment_meta
)
{
return
function
(
err
,
attachment
)
{
if
(
state
!==
"
ok
"
)
{
return
;
return
;
}
}
}
count
-=
1
;
// This node has children
if
(
err
)
{
for
(
i
=
0
;
i
<
document_tree
.
children
.
length
;
i
+=
1
)
{
if
(
err
.
status
===
404
)
{
// searching deeper to find the good rev
result_list
.
push
(
undefined
);
search
(
document_tree
.
children
[
i
]);
}
else
{
if
(
result
!==
undefined
)
{
state
=
"
error
"
;
// The result is already found
return
callback
(
err
,
undefined
);
return
;
}
}
}
}
result_list
.
push
({
"
_attachment
"
:
attachment_id
,
"
_data
"
:
attachment
,
"
_mimetype
"
:
attachment_meta
.
content_type
});
if
(
count
===
0
)
{
state
=
"
finished
"
;
callback
(
undefined
,
result_list
);
}
};
};
};
search
(
document_tree
);
for
(
attachment_id
in
doc
.
_attachments
)
{
return
result
||
false
;
if
(
doc
.
_attachments
.
hasOwnProperty
(
attachment_id
))
{
};
count
+=
1
;
priv
.
get
(
/**
{
"
_id
"
:
doc
.
_id
+
"
/
"
+
attachment_id
},
* Convert revs_info to a simple revisions history
option
,
* @method revsInfoToHistory
dealResults
(
attachment_id
,
doc
.
_attachments
[
attachment_id
])
* @param {array} revs_info The revs info
);
* @return {object} The revisions history
}
*/
priv
.
revsInfoToHistory
=
function
(
revs_info
)
{
var
revisions
=
{
"
start
"
:
0
,
"
ids
"
:
[]
},
i
;
if
(
revs_info
.
length
>
0
)
{
revisions
.
start
=
parseInt
(
revs_info
[
0
].
rev
.
split
(
'
-
'
)[
0
],
10
);
}
}
for
(
i
=
0
;
i
<
revs_info
.
length
;
i
+=
1
)
{
if
(
count
===
0
)
{
revisions
.
ids
.
push
(
revs_info
[
i
].
rev
.
split
(
'
-
'
)[
1
]);
callback
(
undefined
,
[
]);
}
}
return
revisions
;
};
};
/**
priv
.
putAttachmentList
=
function
(
doc
,
option
,
attachment_list
,
callback
)
{
* Returns the revision of the revision position from a revs_info array.
var
i
,
dealResults
,
state
=
"
ok
"
,
count
=
0
,
attachment
;
* @method getRevisionFromPosition
attachment_list
=
attachment_list
||
[];
* @param {array} revs_info The revs_info array
dealResults
=
function
(
index
)
{
* @param {number} rev_pos The revision position number
return
function
(
err
,
response
)
{
* @return {string} The revision of the good position (empty string if fail)
if
(
state
!==
"
ok
"
)
{
*/
return
;
priv
.
getRevisionFromPosition
=
function
(
revs_info
,
rev_pos
)
{
}
var
i
;
count
-=
1
;
for
(
i
=
revs_info
.
length
-
1
;
i
>=
0
;
i
-=
1
)
{
if
(
err
)
{
if
(
priv
.
revisionToArray
(
revs_info
[
i
].
rev
)[
0
]
===
rev_pos
)
{
state
=
"
error
"
;
return
revs_info
[
i
].
rev
;
return
callback
(
err
,
undefined
);
}
if
(
count
===
0
)
{
state
=
"
finished
"
;
callback
(
undefined
,
{
"
id
"
:
doc
.
_id
,
"
ok
"
:
true
});
}
};
};
for
(
i
=
0
;
i
<
attachment_list
.
length
;
i
+=
1
)
{
attachment
=
attachment_list
[
i
];
if
(
attachment
!==
undefined
)
{
count
+=
1
;
attachment
.
_id
=
doc
.
_id
+
"
.
"
+
doc
.
_rev
+
"
/
"
+
attachment
.
_attachment
;
delete
attachment
.
_attachment
;
priv
.
putAttachment
(
attachment
,
option
,
dealResults
(
i
));
}
}
}
}
return
''
;
if
(
count
===
0
)
{
return
callback
(
undefined
,
{
"
id
"
:
doc
.
_id
,
"
ok
"
:
true
});
}
};
};
/**
priv
.
putDocumentTree
=
function
(
doc
,
option
,
doc_tree
,
callback
)
{
* Post the document metadata and create or update a document tree.
doc_tree
=
priv
.
clone
(
doc_tree
);
* Options:
doc_tree
.
_id
=
doc
.
_id
+
priv
.
doc_tree_suffix
;
* - {boolean} keep_revision_history To keep the previous revisions
priv
.
put
(
doc_tree
,
option
,
callback
);
* (false by default) (NYI).
};
* @method post
* @param {object} command The JIO command
*/
that
.
post
=
function
(
command
)
{
var
f
=
{},
doctree
,
revs_info
,
doc
,
docid
,
prev_doc
;
doc
=
command
.
cloneDoc
();
docid
=
command
.
getDocId
();
if
(
typeof
doc
.
_rev
===
"
string
"
&&
!
priv
.
checkRevisionFormat
(
doc
.
_rev
))
{
priv
.
notFoundError
=
function
(
message
,
reason
)
{
that
.
error
({
return
{
"
status
"
:
31
,
"
status
"
:
404
,
"
statusText
"
:
"
Wrong Revision Format
"
,
"
statusText
"
:
"
Not Found
"
,
"
error
"
:
"
wrong_revision_format
"
,
"
error
"
:
"
not_found
"
,
"
message
"
:
"
The document previous revision does not match
"
+
"
message
"
:
message
,
"
^[0-9]+-[0-9a-zA-Z]+$
"
,
"
reason
"
:
reason
"
reason
"
:
"
Previous revision is wrong
"
};
});
};
return
;
priv
.
conflictError
=
function
(
message
,
reason
)
{
return
{
"
status
"
:
409
,
"
statusText
"
:
"
Conflict
"
,
"
error
"
:
"
conflict
"
,
"
message
"
:
message
,
"
reason
"
:
reason
};
};
priv
.
revisionGenericRequest
=
function
(
doc
,
option
,
specific_parameter
,
onEnd
)
{
var
prev_doc
,
doc_tree
,
attachment_list
,
callback
=
{};
if
(
specific_parameter
.
doc_id
)
{
doc
.
_id
=
specific_parameter
.
doc_id
;
}
}
if
(
typeof
docid
!==
"
string
"
)
{
if
(
specific_parameter
.
attachment_id
)
{
doc
.
_id
=
priv
.
generateUuid
();
doc
.
_attachment
=
specific_parameter
.
attachment_id
;
docid
=
doc
.
_id
;
}
}
f
.
getDocumentTree
=
function
()
{
callback
.
begin
=
function
()
{
var
option
=
command
.
cloneOption
();
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
);
}
// check revision format
check_error
=
priv
.
checkDocumentRevisionFormat
(
doc
);
if
(
check_error
!==
undefined
)
{
return
onEnd
(
check_error
,
undefined
);
}
priv
.
getRevisionTree
(
doc
,
option
,
callback
.
getRevisionTree
);
};
callback
.
getRevisionTree
=
function
(
err
,
response
)
{
var
winner_info
,
previous_revision
=
doc
.
_rev
,
generate_new_revision
=
doc
.
_revs
||
doc
.
_revs_info
?
false
:
true
;
if
(
err
)
{
if
(
err
.
status
!==
404
)
{
err
.
message
=
"
Cannot get document revision tree
"
;
return
onEnd
(
err
,
undefined
);
}
}
}
that
.
addJob
(
doc_tree
=
response
||
priv
.
newDocTree
();
"
get
"
,
if
(
specific_parameter
.
get
||
specific_parameter
.
getAttachment
)
{
priv
.
substorage
,
if
(
!
doc
.
_rev
)
{
docid
+
priv
.
doctree_suffix
,
winner_info
=
priv
.
getWinnerRevsInfo
(
doc_tree
);
option
,
if
(
winner_info
.
length
===
0
)
{
function
(
response
)
{
return
onEnd
(
priv
.
notFoundError
(
doctree
=
response
;
"
Document not found
"
,
f
.
updateRevsInfo
();
"
missing
"
f
.
getDocument
();
),
undefined
);
},
function
(
err
)
{
switch
(
err
.
status
)
{
case
404
:
doctree
=
priv
.
createDocumentTree
();
f
.
updateRevsInfo
();
f
.
getDocument
();
break
;
default
:
err
.
message
=
"
Cannot get document revision tree
"
;
f
.
error
(
err
);
break
;
}
}
}
if
(
winner_info
[
0
].
status
===
"
deleted
"
)
{
);
return
onEnd
(
priv
.
notFoundError
(
};
"
Document not found
"
,
f
.
getDocument
=
function
()
{
"
deleted
"
if
(
revs_info
[
1
]
===
undefined
)
{
),
undefined
);
f
.
postDocument
([]);
}
else
{
that
.
addJob
(
"
get
"
,
priv
.
substorage
,
command
.
getDocId
()
+
"
.
"
+
revs_info
[
1
].
rev
,
command
.
getOption
(),
function
(
response
)
{
var
attachment_list
=
[],
i
;
prev_doc
=
response
;
for
(
i
in
response
.
_attachments
)
{
if
(
response
.
_attachments
.
hasOwnProperty
(
i
))
{
attachment_list
.
push
({
"
id
"
:
i
,
"
attachment
"
:
{
"
_id
"
:
command
.
getDocId
()
+
"
.
"
+
revs_info
[
0
].
rev
+
"
/
"
+
i
,
"
_mimetype
"
:
response
.
_attachments
[
i
].
content_type
,
"
_data
"
:
undefined
}});
}
}
f
.
postDocument
(
attachment_list
);
},
function
(
err
)
{
if
(
err
.
status
===
404
)
{
f
.
postDocument
([]);
return
;
}
err
.
message
=
"
Cannot retrieve document
"
;
f
.
error
(
err
);
}
}
doc
.
_rev
=
winner_info
[
0
].
rev
;
}
priv
.
fillDocumentRevisionProperties
(
doc
,
doc_tree
);
return
priv
.
getDocument
(
doc
,
option
,
callback
.
getDocument
);
}
priv
.
fillDocumentRevisionProperties
(
doc
,
doc_tree
);
if
(
generate_new_revision
)
{
if
(
previous_revision
&&
doc
.
_revs_info
.
length
===
0
)
{
// the document history has changed, it means that the document
// revision was wrong. Add a pseudo history to the document
doc
.
_rev
=
previous_revision
;
doc
.
_revs
=
{
"
start
"
:
parseInt
(
previous_revision
.
split
(
"
-
"
)[
0
],
10
),
"
ids
"
:
[
previous_revision
.
split
(
"
-
"
)[
1
]]
};
doc
.
_revs_info
=
[{
"
rev
"
:
previous_revision
,
"
status
"
:
"
missing
"
}];
}
doc
=
priv
.
generateNextRevision
(
doc
,
specific_parameter
.
remove
);
);
}
}
if
(
doc
.
_revs_info
.
length
>
1
)
{
prev_doc
=
{
"
_id
"
:
doc
.
_id
,
"
_rev
"
:
doc
.
_revs_info
[
1
].
rev
};
if
(
!
generate_new_revision
&&
specific_parameter
.
putAttachment
)
{
prev_doc
.
_rev
=
doc
.
_revs_info
[
0
].
rev
;
}
}
// 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
.
updateRevsInfo
=
function
()
{
callback
.
getDocument
=
function
(
err
,
res_doc
)
{
if
(
doc
.
_revs
)
{
var
k
,
conflicts
;
revs_info
=
priv
.
updateDocumentTree
(
doctree
,
doc
.
_revs
);
if
(
err
)
{
if
(
err
.
status
===
404
)
{
if
(
specific_parameter
.
remove
||
specific_parameter
.
removeAttachment
)
{
return
onEnd
(
priv
.
conflictError
(
"
Document update conflict
"
,
"
Document is missing
"
),
undefined
);
}
if
(
specific_parameter
.
get
)
{
return
onEnd
(
priv
.
notFoundError
(
"
Unable to find the document
"
,
"
missing
"
),
undefined
);
}
res_doc
=
{};
}
else
{
err
.
message
=
"
Cannot get document
"
;
return
onEnd
(
err
,
undefined
);
}
}
if
(
specific_parameter
.
get
)
{
res_doc
.
_id
=
doc
.
_id
;
res_doc
.
_rev
=
doc
.
_rev
;
if
(
option
.
conflicts
===
true
)
{
conflicts
=
priv
.
getConflicts
(
doc
.
_rev
,
doc_tree
);
if
(
conflicts
)
{
res_doc
.
_conflicts
=
conflicts
;
}
}
if
(
option
.
revs
===
true
)
{
res_doc
.
_revisions
=
doc
.
_revs
;
}
if
(
option
.
revs_info
===
true
)
{
res_doc
.
_revs_info
=
doc
.
_revs_info
;
}
return
onEnd
(
undefined
,
res_doc
);
}
if
(
specific_parameter
.
putAttachment
||
specific_parameter
.
removeAttachment
)
{
// copy metadata (not beginning by "_" to document
for
(
k
in
res_doc
)
{
if
(
res_doc
.
hasOwnProperty
(
k
)
&&
!
k
.
match
(
"
^_
"
))
{
doc
[
k
]
=
res_doc
[
k
];
}
}
}
if
(
specific_parameter
.
remove
)
{
priv
.
putDocumentTree
(
doc
,
option
,
doc_tree
,
callback
.
putDocumentTree
);
}
else
{
}
else
{
revs_info
=
priv
.
postToDocumentTree
(
doctree
,
doc
);
priv
.
getAttachmentList
(
res_doc
,
option
,
callback
.
getAttachmentList
);
}
}
};
};
f
.
postDocument
=
function
(
attachment_list
)
{
callback
.
getAttachmentList
=
function
(
err
,
res_list
)
{
doc
.
_id
=
docid
+
"
.
"
+
revs_info
[
0
].
rev
;
var
i
,
attachment_found
=
false
;
delete
doc
.
_rev
;
if
(
err
)
{
delete
doc
.
_revs
;
err
.
message
=
"
Cannot get attachment
"
;
that
.
addJob
(
return
onEnd
(
err
,
undefined
);
"
post
"
,
}
priv
.
substorage
,
attachment_list
=
res_list
||
[];
doc
,
if
(
specific_parameter
.
getAttachment
)
{
command
.
cloneOption
(),
// getting specific attachment
function
()
{
for
(
i
=
0
;
i
<
attachment_list
.
length
;
i
+=
1
)
{
var
i
;
if
(
attachment_list
[
i
]
&&
if
(
attachment_list
.
length
===
0
)
{
doc
.
_attachment
===
f
.
sendDocumentTree
();
attachment_list
[
i
].
_attachment
)
{
}
else
{
return
onEnd
(
undefined
,
attachment_list
[
i
].
_data
);
f
.
send_document_tree_count
=
attachment_list
.
length
;
for
(
i
=
0
;
i
<
attachment_list
.
length
;
i
+=
1
)
{
f
.
copyAttachment
(
attachment_list
[
i
].
id
,
attachment_list
[
i
].
attachment
);
}
}
}
},
}
function
(
err
)
{
return
onEnd
(
priv
.
notFoundError
(
switch
(
err
.
status
)
{
"
Unable to get an inexistent attachment
"
,
case
409
:
"
missing
"
// file already exists
),
undefined
);
f
.
sendDocumentTree
();
}
break
;
if
(
specific_parameter
.
remove_from_attachment_list
)
{
default
:
// removing specific attachment
err
.
message
=
"
Cannot upload document
"
;
for
(
i
=
0
;
i
<
attachment_list
.
length
;
i
+=
1
)
{
f
.
error
(
err
);
if
(
attachment_list
[
i
]
&&
specific_parameter
.
remove_from_attachment_list
.
_attachment
===
attachment_list
[
i
].
_attachment
)
{
attachment_found
=
true
;
attachment_list
[
i
]
=
undefined
;
break
;
break
;
}
}
}
}
);
if
(
!
attachment_found
)
{
return
onEnd
(
priv
.
notFoundError
(
"
Unable to remove an inexistent attachment
"
,
"
missing
"
),
undefined
);
}
}
priv
.
putDocument
(
doc
,
option
,
callback
.
putDocument
);
};
};
f
.
copyAttachment
=
function
(
attachmentid
,
attachment
)
{
callback
.
putDocument
=
function
(
err
,
response
)
{
that
.
addJob
(
var
i
,
attachment_found
=
false
;
"
get
"
,
if
(
err
)
{
priv
.
substorage
,
err
.
message
=
"
Cannot post the document
"
;
prev_doc
.
_id
+
"
/
"
+
attachmentid
,
return
onEnd
(
err
,
undefined
);
command
.
cloneOption
(),
}
function
(
response
)
{
if
(
specific_parameter
.
add_to_attachment_list
)
{
attachment
.
_data
=
response
;
// adding specific attachment
that
.
addJob
(
attachment_list
=
attachment_list
||
[];
"
putAttachment
"
,
for
(
i
=
0
;
i
<
attachment_list
.
length
;
i
+=
1
)
{
priv
.
substorage
,
if
(
attachment_list
[
i
]
&&
attachment
,
specific_parameter
.
add_to_attachment_list
.
_attachment
===
command
.
cloneOption
(),
attachment_list
[
i
].
_attachment
)
{
function
(
response
)
{
attachment_found
=
true
;
f
.
sendDocumentTree
();
attachment_list
[
i
]
=
specific_parameter
.
add_to_attachment_list
;
},
break
;
function
(
err
)
{
}
err
.
message
=
"
Cannot copy previous attachment
"
;
}
f
.
error
(
err
);
if
(
!
attachment_found
)
{
}
attachment_list
.
unshift
(
specific_parameter
.
add_to_attachment_list
);
);
},
function
(
err
)
{
err
.
message
=
"
Cannot get previous attachment
"
;
f
.
error
(
err
);
}
}
}
priv
.
putAttachmentList
(
doc
,
option
,
attachment_list
,
callback
.
putAttachmentList
);
);
};
};
f
.
send_document_tree_count
=
0
;
callback
.
putAttachmentList
=
function
(
err
,
response
)
{
f
.
sendDocumentTree
=
function
()
{
if
(
err
)
{
f
.
send_document_tree_count
-=
1
;
err
.
message
=
"
Cannot copy attacments to the document
"
;
if
(
f
.
send_document_tree_count
>
0
)
{
return
onEnd
(
err
,
undefined
);
return
;
}
}
doctree
.
_id
=
docid
+
priv
.
doctree_suffix
;
priv
.
putDocumentTree
(
doc
,
option
,
doc_tree
,
callback
.
putDocumentTree
);
that
.
addJob
(
"
put
"
,
priv
.
substorage
,
doctree
,
command
.
cloneOption
(),
function
()
{
that
.
success
({
"
ok
"
:
true
,
"
id
"
:
docid
,
"
rev
"
:
revs_info
[
0
].
rev
});
},
function
(
err
)
{
// xxx do we try to delete the posted document ?
err
.
message
=
"
Cannot save document revision tree
"
;
f
.
error
(
err
);
}
);
};
};
f
.
error
=
function
(
err
)
{
callback
.
putDocumentTree
=
function
(
err
,
response
)
{
f
.
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
// // });
// }
};
};
f
.
getDocumentTree
();
callback
.
begin
();
};
};
/**
/**
*
Update the document metadata and
update a document tree.
*
Post 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
* (false by default) (NYI).
* (false by default) (NYI).
* @method p
u
t
* @method p
os
t
* @param {object} command The JIO command
* @param {object} command The JIO command
*/
*/
that
.
put
=
function
(
command
)
{
that
.
post
=
function
(
command
)
{
that
.
post
(
command
);
priv
.
revisionGenericRequest
(
command
.
cloneDoc
(),
command
.
cloneOption
(),
{},
function
(
err
,
response
)
{
if
(
err
)
{
return
that
.
error
(
err
);
}
that
.
success
(
response
);
}
);
};
};
/**
/**
*
Create/Update the document attachment and
update a document tree.
*
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
* (false by default) (NYI).
* (false by default) (NYI).
* @method put
Attachment
* @method put
* @param {object} command The JIO command
* @param {object} command The JIO command
*/
*/
that
.
putAttachment
=
function
(
command
)
{
that
.
put
=
function
(
command
)
{
var
functions
=
{},
doc
,
doctree
,
revs_info
,
prev_doc
;
priv
.
revisionGenericRequest
(
doc
=
command
.
cloneDoc
();
command
.
cloneDoc
(),
functions
.
begin
=
function
()
{
command
.
cloneOption
(),
if
(
typeof
doc
.
_rev
===
"
string
"
&&
!
priv
.
checkRevisionFormat
(
doc
.
_rev
))
{
{},
that
.
error
({
function
(
err
,
response
)
{
"
status
"
:
31
,
if
(
err
)
{
"
statusText
"
:
"
Wrong Revision Format
"
,
return
that
.
error
(
err
);
"
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
;
}
}
);
};
functions
.
updateRevsInfo
=
function
()
{
if
(
doc
.
_revs
)
{
revs_info
=
priv
.
updateDocumentTree
(
doctree
,
doc
.
_revs
);
}
else
{
revs_info
=
priv
.
postToDocumentTree
(
doctree
,
doc
);
}
};
functions
.
postEmptyDocument
=
function
()
{
that
.
addJob
(
"
post
"
,
priv
.
substorage
,
{
"
_id
"
:
command
.
getDocId
()
+
"
.
"
+
revs_info
[
0
].
rev
},
command
.
getOption
(),
function
(
response
)
{
doc
.
_rev
=
response
.
rev
;
functions
.
postAttachment
();
},
function
(
err
)
{
err
.
message
=
"
Cannot upload document
"
;
that
.
error
(
err
);
}
);
};
functions
.
getDocument
=
function
()
{
if
(
revs_info
[
1
]
===
undefined
)
{
functions
.
postEmptyDocument
();
}
else
{
that
.
addJob
(
"
get
"
,
priv
.
substorage
,
command
.
getDocId
()
+
"
.
"
+
revs_info
[
1
].
rev
,
command
.
getOption
(),
function
(
response
)
{
var
attachment_list
=
[],
i
;
prev_doc
=
response
;
for
(
i
in
response
.
_attachments
)
{
if
(
response
.
_attachments
.
hasOwnProperty
(
i
))
{
attachment_list
.
push
({
"
id
"
:
i
,
"
attachment
"
:
{
"
_id
"
:
command
.
getDocId
()
+
"
.
"
+
revs_info
[
0
].
rev
+
"
/
"
+
i
,
"
_mimetype
"
:
response
.
_attachments
[
i
].
content_type
,
"
_data
"
:
undefined
}});
}
}
functions
.
postDocument
(
attachment_list
);
},
function
(
err
)
{
if
(
err
.
status
===
404
)
{
functions
.
postDocument
([]);
return
;
}
err
.
message
=
"
Cannot upload document
"
;
that
.
error
(
err
);
}
);
}
};
functions
.
postDocument
=
function
(
attachment_list
)
{
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
)
{
functions
.
copyAttachment
(
attachment_list
[
i
].
id
,
attachment_list
[
i
].
attachment
);
}
}
},
function
(
err
)
{
err
.
message
=
"
Cannot upload document
"
;
that
.
error
(
err
);
}
);
};
functions
.
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
)
{
functions
.
postAttachment
();
},
function
(
err
)
{
err
.
message
=
"
Cannot copy previous attachment
"
;
functions
.
error
(
err
);
}
);
},
function
(
err
)
{
err
.
message
=
"
Cannot copy previous attachment
"
;
functions
.
error
(
err
);
}
}
);
that
.
success
(
response
);
};
functions
.
post_attachment_count
=
0
;
functions
.
postAttachment
=
function
()
{
functions
.
post_attachment_count
-=
1
;
if
(
functions
.
post_attachment_count
>
0
)
{
return
;
}
}
that
.
addJob
(
);
"
putAttachment
"
,
};
priv
.
substorage
,
{
"
_id
"
:
command
.
getDocId
()
+
"
.
"
+
revs_info
[
0
].
rev
+
"
/
"
+
that
.
putAttachment
=
function
(
command
)
{
command
.
getAttachmentId
(),
priv
.
revisionGenericRequest
(
command
.
cloneDoc
(),
command
.
cloneOption
(),
{
"
doc_id
"
:
command
.
getDocId
(),
"
attachment_id
"
:
command
.
getAttachmentId
(),
"
add_to_attachment_list
"
:
{
"
_attachment
"
:
command
.
getAttachmentId
(),
"
_mimetype
"
:
command
.
getAttachmentMimeType
(),
"
_mimetype
"
:
command
.
getAttachmentMimeType
(),
"
_data
"
:
command
.
getAttachmentData
()
"
_data
"
:
command
.
getAttachmentData
()
},
},
command
.
cloneOption
(),
"
putAttachment
"
:
true
function
()
{
},
functions
.
sendDocumentTree
();
function
(
err
,
response
)
{
},
if
(
err
)
{
function
(
err
)
{
return
that
.
error
(
err
);
switch
(
err
.
status
)
{
case
409
:
// file already exists
functions
.
sendDocumentTree
();
break
;
default
:
err
.
message
=
"
Cannot upload attachment
"
;
functions
.
error
(
err
);
break
;
}
}
);
};
functions
.
sendDocumentTree
=
function
()
{
doctree
.
_id
=
command
.
getDocId
()
+
priv
.
doctree_suffix
;
that
.
addJob
(
"
put
"
,
priv
.
substorage
,
doctree
,
command
.
cloneOption
(),
function
()
{
that
.
success
({
"
ok
"
:
true
,
"
id
"
:
command
.
getDocId
()
+
"
/
"
+
command
.
getAttachmentId
(),
"
rev
"
:
revs_info
[
0
].
rev
});
},
function
(
err
)
{
// xxx do we try to delete the posted document ?
err
.
message
=
"
Cannot save document revision tree
"
;
functions
.
error
(
err
);
}
}
);
that
.
success
(
response
);
};
functions
.
error
=
function
(
err
)
{
functions
.
error
=
function
()
{};
that
.
error
(
err
);
};
functions
.
begin
();
};
/**
* Get the document metadata or attachment.
* Options:
* - {boolean} revs Add simple revision history (false by default).
* - {boolean} revs_info Add revs info (false by default).
* - {boolean} conflicts Add conflict object (false by default).
* @method get
* @param {object} command The JIO command
*/
that
.
get
=
function
(
command
)
{
var
f
=
{},
doctree
,
revs_info
,
prev_rev
,
option
;
option
=
command
.
cloneOption
();
if
(
option
.
max_retry
===
0
)
{
option
.
max_retry
=
3
;
}
prev_rev
=
command
.
getDocInfo
(
"
_rev
"
);
if
(
typeof
prev_rev
===
"
string
"
)
{
if
(
!
priv
.
checkRevisionFormat
(
prev_rev
))
{
that
.
error
({
"
status
"
:
31
,
"
statusText
"
:
"
Wrong Revision Format
"
,
"
error
"
:
"
wrong_revision_format
"
,
"
message
"
:
"
The document previous revision does not match
"
+
"
[0-9]+-[0-9a-zA-Z]+
"
,
"
reason
"
:
"
Previous revision is wrong
"
});
return
;
}
}
}
);
f
.
getDocumentTree
=
function
()
{
that
.
addJob
(
"
get
"
,
priv
.
substorage
,
{
"
_id
"
:
command
.
getDocId
()
+
priv
.
doctree_suffix
,
"
_rev
"
:
command
.
getDocInfo
(
"
_rev
"
)
},
option
,
function
(
response
)
{
doctree
=
response
;
if
(
prev_rev
===
undefined
)
{
revs_info
=
priv
.
getWinnerRevisionFromDocumentTree
(
doctree
);
if
(
revs_info
.
length
>
0
)
{
prev_rev
=
revs_info
[
0
].
rev
;
}
else
{
that
.
error
({
"
status
"
:
404
,
"
statusText
"
:
"
Not Found
"
,
"
error
"
:
"
not_found
"
,
"
message
"
:
"
Cannot find the document
"
,
"
reason
"
:
"
Document is deleted
"
});
return
;
}
}
else
{
revs_info
=
priv
.
getRevisionFromDocumentTree
(
doctree
,
prev_rev
);
}
f
.
getDocument
(
command
.
getDocId
()
+
"
.
"
+
prev_rev
,
command
.
getAttachmentId
());
},
function
(
err
)
{
switch
(
err
.
status
)
{
case
404
:
that
.
error
(
err
);
break
;
default
:
err
.
message
=
"
Cannot get document revision tree
"
;
that
.
error
(
err
);
break
;
}
}
);
};
f
.
getDocument
=
function
(
docid
,
attmtid
)
{
that
.
addJob
(
"
get
"
,
priv
.
substorage
,
{
"
_id
"
:
docid
,
"
_rev
"
:
command
.
getDocInfo
(
"
_rev
"
)},
option
,
function
(
response
)
{
var
attmt
;
if
(
typeof
response
!==
"
string
"
)
{
if
(
attmtid
!==
undefined
)
{
if
(
response
.
_attachments
!==
undefined
)
{
attmt
=
response
.
_attachments
[
attmtid
];
if
(
attmt
!==
undefined
)
{
prev_rev
=
priv
.
getRevisionFromPosition
(
revs_info
,
attmt
.
revpos
);
f
.
getDocument
(
command
.
getDocId
()
+
"
.
"
+
prev_rev
+
"
/
"
+
attmtid
);
return
;
}
}
that
.
error
({
"
status
"
:
404
,
"
statusText
"
:
"
Not Found
"
,
"
error
"
:
"
not_found
"
,
"
message
"
:
"
Cannot find the attachment
"
,
"
reason
"
:
"
Attachment is missing
"
});
return
;
}
response
.
_id
=
command
.
getDocId
();
response
.
_rev
=
prev_rev
;
if
(
command
.
getOption
(
"
revs
"
)
===
true
)
{
response
.
_revisions
=
priv
.
revsInfoToHistory
(
revs_info
);
}
if
(
command
.
getOption
(
"
revs_info
"
)
===
true
)
{
response
.
_revs_info
=
revs_info
;
}
if
(
command
.
getOption
(
"
conflicts
"
)
===
true
)
{
response
.
_conflicts
=
priv
.
getLeavesFromDocumentTree
(
doctree
,
prev_rev
);
if
(
response
.
_conflicts
.
length
===
0
)
{
delete
response
.
_conflicts
;
}
}
}
that
.
success
(
response
);
},
function
(
err
)
{
that
.
error
(
err
);
}
);
};
if
(
command
.
getAttachmentId
()
&&
prev_rev
!==
undefined
)
{
f
.
getDocument
(
command
.
getDocId
()
+
"
.
"
+
prev_rev
+
"
/
"
+
command
.
getAttachmentId
());
}
else
{
f
.
getDocumentTree
();
}
};
};
/**
* Remove document or attachment.
* Options:
* - {boolean} keep_revision_history To keep the previous revisions
* @method remove
* @param {object} command The JIO command
*/
that
.
remove
=
function
(
command
)
{
that
.
remove
=
function
(
command
)
{
var
f
=
{},
del_rev
,
option
,
new_doc
,
revs_info
;
if
(
command
.
getAttachmentId
())
{
option
=
command
.
cloneOption
();
return
that
.
removeAttachment
(
command
);
if
(
option
.
max_retry
===
0
)
{
option
.
max_retry
=
3
;
}
}
del_rev
=
command
.
getDoc
().
_rev
;
priv
.
revisionGenericRequest
(
command
.
cloneDoc
(),
f
.
removeDocument
=
function
(
docid
,
doctree
)
{
command
.
cloneOption
(),
if
(
command
.
getOption
(
"
keep_revision_history
"
)
!==
true
)
{
{
if
(
command
.
getAttachmentId
()
===
undefined
)
{
"
revision_needed
"
:
true
,
// update tree
"
remove
"
:
true
revs_info
=
priv
.
postToDocumentTree
(
},
doctree
,
function
(
err
,
response
)
{
command
.
getDoc
(),
if
(
err
)
{
true
return
that
.
error
(
err
);
);
// remove revision
that
.
addJob
(
"
remove
"
,
priv
.
substorage
,
docid
,
option
,
function
()
{
// put tree
doctree
.
_id
=
command
.
getDocId
()
+
priv
.
doctree_suffix
;
that
.
addJob
(
"
put
"
,
priv
.
substorage
,
doctree
,
command
.
cloneOption
(),
function
()
{
that
.
success
({
"
ok
"
:
true
,
"
id
"
:
command
.
getDocId
(),
"
rev
"
:
revs_info
[
0
].
rev
});
},
function
()
{
that
.
error
({
"
status
"
:
409
,
"
statusText
"
:
"
Conflict
"
,
"
error
"
:
"
conflict
"
,
"
message
"
:
"
Document update conflict.
"
,
"
reason
"
:
"
Cannot update document tree
"
});
return
;
}
);
},
function
()
{
that
.
error
({
"
status
"
:
404
,
"
statusText
"
:
"
Not Found
"
,
"
error
"
:
"
not_found
"
,
"
message
"
:
"
File not found
"
,
"
reason
"
:
"
Document was not found
"
});
return
;
}
);
}
else
{
// get previsous document
that
.
addJob
(
"
get
"
,
priv
.
substorage
,
command
.
getDocId
()
+
"
.
"
+
del_rev
,
option
,
function
(
response
)
{
// update tree
revs_info
=
priv
.
postToDocumentTree
(
doctree
,
command
.
getDoc
());
new_doc
=
response
;
delete
new_doc
.
_attachments
;
new_doc
.
_id
=
new_doc
.
_id
+
"
.
"
+
revs_info
[
0
].
rev
;
// post new document version
that
.
addJob
(
"
post
"
,
priv
.
substorage
,
new_doc
,
command
.
cloneOption
(),
function
()
{
// put tree
doctree
.
_id
=
command
.
getDocId
()
+
priv
.
doctree_suffix
;
that
.
addJob
(
"
put
"
,
priv
.
substorage
,
doctree
,
command
.
cloneOption
(),
function
()
{
that
.
success
({
"
ok
"
:
true
,
"
id
"
:
new_doc
.
_id
,
"
rev
"
:
revs_info
[
0
].
rev
});
},
function
(
err
)
{
err
.
message
=
"
Cannot save document revision tree
"
;
that
.
error
(
err
);
}
);
},
function
()
{
that
.
error
({
"
status
"
:
409
,
"
statusText
"
:
"
Conflict
"
,
"
error
"
:
"
conflict
"
,
"
message
"
:
"
Document update conflict.
"
,
"
reason
"
:
"
Cannot update document
"
});
return
;
}
);
},
function
()
{
that
.
error
({
"
status
"
:
404
,
"
statusText
"
:
"
Not Found
"
,
"
error
"
:
"
not_found
"
,
"
message
"
:
"
File not found
"
,
"
reason
"
:
"
Document was not found
"
});
return
;
}
);
}
}
that
.
success
(
response
);
}
}
};
);
if
(
typeof
del_rev
===
"
string
"
)
{
};
if
(
!
priv
.
checkRevisionFormat
(
del_rev
))
{
that
.
error
({
"
status
"
:
31
,
"
statusText
"
:
"
Wrong Revision Format
"
,
"
error
"
:
"
wrong_revision_format
"
,
"
message
"
:
"
The document previous revision does not match
"
+
"
[0-9]+-[0-9a-zA-Z]+
"
,
"
reason
"
:
"
Previous revision is wrong
"
});
return
;
}
}
// get doctree
that
.
addJob
(
"
get
"
,
priv
.
substorage
,
command
.
getDocId
()
+
priv
.
doctree_suffix
,
option
,
function
(
response
)
{
response
.
_conflicts
=
priv
.
getLeavesFromDocumentTree
(
response
);
if
(
del_rev
===
undefined
)
{
that
.
removeAttachment
=
function
(
command
)
{
// no revision provided
priv
.
revisionGenericRequest
(
that
.
error
({
command
.
cloneDoc
(),
"
status
"
:
409
,
command
.
cloneOption
(),
"
statusText
"
:
"
Conflict
"
,
{
"
error
"
:
"
conflict
"
,
"
doc_id
"
:
command
.
getDocId
(),
"
message
"
:
"
Document update conflict.
"
,
"
attachment_id
"
:
command
.
getAttachmentId
(),
"
reason
"
:
"
Cannot delete a document without revision
"
"
revision_needed
"
:
true
,
});
"
removeAttachment
"
:
true
,
return
;
"
remove_from_attachment_list
"
:
{
"
_attachment
"
:
command
.
getAttachmentId
()
}
}
// revision provided
},
if
(
priv
.
isRevisionALeaf
(
response
,
del_rev
)
===
true
)
{
function
(
err
,
response
)
{
if
(
typeof
command
.
getAttachmentId
()
===
"
string
"
)
{
if
(
err
)
{
f
.
removeDocument
(
command
.
getDocId
()
+
"
.
"
+
del_rev
+
return
that
.
error
(
err
);
"
/
"
+
command
.
getAttachmentId
(),
response
);
}
else
{
f
.
removeDocument
(
command
.
getDocId
()
+
"
.
"
+
del_rev
,
response
);
}
}
else
{
that
.
error
({
"
status
"
:
409
,
"
statusText
"
:
"
Conflict
"
,
"
error
"
:
"
conflict
"
,
"
message
"
:
"
Document update conflict.
"
,
"
reason
"
:
"
Trying to remove non-latest revision
"
});
return
;
}
}
that
.
success
(
response
);
}
);
};
that
.
get
=
function
(
command
)
{
if
(
command
.
getAttachmentId
())
{
return
that
.
getAttachment
(
command
);
}
priv
.
revisionGenericRequest
(
command
.
cloneDoc
(),
command
.
cloneOption
(),
{
"
get
"
:
true
},
},
function
()
{
function
(
err
,
response
)
{
that
.
error
({
if
(
err
)
{
"
status
"
:
404
,
return
that
.
error
(
err
);
"
statusText
"
:
"
Not Found
"
,
}
"
error
"
:
"
not_found
"
,
that
.
success
(
response
);
"
message
"
:
"
Document tree not found, please checkdocument ID
"
,
"
reason
"
:
"
Incorrect document ID
"
});
return
;
}
}
);
);
};
};
/**
that
.
getAttachment
=
function
(
command
)
{
* Get all documents
priv
.
revisionGenericRequest
(
* @method allDocs
command
.
cloneDoc
(),
* @param {object} command The JIO command
command
.
cloneOption
(),
*/
{
that
.
allDocs
=
function
()
{
"
doc_id
"
:
command
.
getDocId
(),
setTimeout
(
function
()
{
"
attachment_id
"
:
command
.
getAttachmentId
(),
that
.
error
({
"
getAttachment
"
:
true
"
status
"
:
405
,
},
"
statusText
"
:
"
Method Not Allowed
"
,
function
(
err
,
response
)
{
"
error
"
:
"
method_not_allowed
"
,
if
(
err
)
{
"
message
"
:
"
Your are not allowed to use this command
"
,
return
that
.
error
(
err
);
"
reason
"
:
"
LocalStorage forbids AllDocs command executions
"
}
});
that
.
success
(
response
);
});
}
);
};
};
// END //
priv
.
RevisionStorage
();
return
that
;
return
that
;
});
});
// end RevisionStorage
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,9 +34,14 @@ clone = function (obj) {
...
@@ -34,9 +34,14 @@ clone = function (obj) {
// generates a revision hash from document metadata, revision history
// generates a revision hash from document metadata, revision history
// and the deleted_flag
// and the deleted_flag
generateRevisionHash
=
function
(
doc
,
revisions
,
deleted_flag
)
{
generateRevisionHash
=
function
(
doc
,
revisions
,
deleted_flag
)
{
var
string
=
JSON
.
stringify
(
doc
)
+
JSON
.
stringify
(
revisions
)
+
var
string
;
JSON
.
stringify
(
deleted_flag
?
true
:
false
);
doc
=
clone
(
doc
);
return
hex_sha256
(
string
);
delete
doc
.
_rev
;
delete
doc
.
_revs
;
delete
doc
.
_revs_info
;
string
=
JSON
.
stringify
(
doc
)
+
JSON
.
stringify
(
revisions
)
+
JSON
.
stringify
(
deleted_flag
?
true
:
false
);
return
hex_sha256
(
string
);
},
},
// localStorage wrapper
// localStorage wrapper
localstorage
=
{
localstorage
=
{
...
@@ -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
"
,
"
content_type
"
:
"
oh/yeah
"
"
revpos
"
:
1
}
},
o
.
attachment_remove3
=
{
"
length
"
:
5
,
"
digest
"
:
"
md5-865f5cc7fbd7854902eae9d8211f178a
"
,
"
content_type
"
:
"
he/ho
"
}
o
.
doc_myremove1
.
_attachments
=
{
"
remove2
"
:
o
.
attachment_remove2
,
"
remove3
"
:
o
.
attachment_remove3
};
};
o
.
doc_myremove1
=
{
"
_id
"
:
"
remove1
"
,
"
title
"
:
"
myRemove1
"
,
"
_attachments
"
:
o
.
attmt_myremove1
};
o
.
revisions
=
{
"
start
"
:
1
,
"
ids
"
:[
o
.
very_old_rev
.
split
(
'
-
'
),[
1
]]}
o
.
old_rev
=
"
2-
"
+
generateRevisionHash
(
o
.
doc_myremove1
,
o
.
revisions
);
localstorage
.
setItem
(
o
.
localpath
+
"
/remove1.
"
+
o
.
old_rev
,
o
.
doc_myremove1
);
localstorage
.
setItem
(
o
.
localpath
+
"
/remove1.2-oldrev
"
,
localstorage
.
setItem
(
o
.
localpath
+
"
/remove1.
"
+
o
.
old_rev
+
"
/remove2
"
,
"
xyz
"
);
o
.
doc_myremove1
);
localstorage
.
setItem
(
o
.
localpath
+
"
/remove1.2-oldrev/remove2
"
,
"
abc
"
);
localstorage
.
setItem
(
o
.
localpath
+
"
/remove1.2-oldrev/remove3
"
,
"
defgh
"
);
o
.
doctree
=
{
"
children
"
:[{
// add document tree
"
rev
"
:
o
.
very_old_rev
,
"
status
"
:
"
available
"
,
"
children
"
:
[{
o
.
doctree
=
{
"
rev
"
:
o
.
old_rev
,
"
status
"
:
"
available
"
,
"
children
"
:
[]
"
children
"
:
[{
"
rev
"
:
"
1-veryoldrev
"
,
"
status
"
:
"
available
"
,
"
children
"
:
[{
"
rev
"
:
"
2-oldrev
"
,
"
status
"
:
"
available
"
,
"
children
"
:
[]
}]
}]
},{
}]
"
rev
"
:
"
1-rev2
"
,
"
status
"
:
"
available
"
,
"
children
"
:
[]
};
}]};
localstorage
.
setItem
(
o
.
localpath
+
"
/remove1.revision_tree.json
"
,
localstorage
.
setItem
(
o
.
localpath
+
"
/remove1.revision_tree.json
"
,
o
.
doctree
);
o
.
doctree
);
// 3. remove non existing attachment with revision
o
.
spy
(
o
,
"
status
"
,
404
,
"
Remove NON-existing attachment (revision)
"
);
o
.
jio
.
remove
({
"
_id
"
:
"
remove1.1-rev2/remove0
"
,
"
_rev
"
:
o
.
old_rev
},
o
.
f
);
o
.
tick
(
o
);
o
.
revisions
=
{
"
start
"
:
2
,
"
ids
"
:[
o
.
old_rev
.
split
(
'
-
'
)[
1
],
o
.
very_old_rev
.
split
(
'
-
'
)[
1
]
]};
o
.
doc_myremove1
=
{
"
_id
"
:
"
remove1/remove2
"
,
"
_rev
"
:
o
.
old_rev
};
o
.
rev
=
"
3-
"
+
generateRevisionHash
(
o
.
doc_myremove1
,
o
.
revisions
);
// 4. remove existing attachment with revision
// 3. remove inexistent attachment
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
remove1.
"
+
o
.
rev
,
"
rev
"
:
o
.
rev
},
o
.
spy
(
o
,
"
status
"
,
404
,
"
Remove inexistent attachment -> 404 Not Found
"
);
"
Remove existing attachment (revision)
"
);
o
.
jio
.
remove
({
"
_id
"
:
"
remove1/remove0
"
,
"
_rev
"
:
"
2-oldrev
"
},
o
.
f
);
o
.
jio
.
remove
({
"
_id
"
:
"
remove1/remove2
"
,
"
_rev
"
:
o
.
old_rev
},
o
.
f
);
o
.
tick
(
o
);
o
.
tick
(
o
);
o
.
testtree
=
{
"
children
"
:[{
// 4. remove existing attachment
"
rev
"
:
o
.
very_old_rev
,
"
status
"
:
"
available
"
,
"
children
"
:
[{
o
.
rev_hash
=
generateRevisionHash
({
"
rev
"
:
o
.
old_rev
,
"
status
"
:
"
available
"
,
"
children
"
:
[{
"
_id
"
:
"
remove1
"
,
"
rev
"
:
o
.
rev
,
"
status
"
:
"
available
"
,
"
children
"
:
[]
"
_attachment
"
:
"
remove2
"
,
}]
},
{
"
start
"
:
2
,
"
ids
"
:
[
"
oldrev
"
,
"
veryoldrev
"
]});
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
remove1/remove2
"
,
"
rev
"
:
"
3-
"
+
o
.
rev_hash
},
"
Remove existing attachment
"
);
o
.
jio
.
remove
({
"
_id
"
:
"
remove1/remove2
"
,
"
_rev
"
:
"
2-oldrev
"
},
o
.
f
);
o
.
tick
(
o
);
o
.
doctree
=
{
"
children
"
:[{
"
rev
"
:
"
1-veryoldrev
"
,
"
status
"
:
"
available
"
,
"
children
"
:
[{
"
rev
"
:
"
2-oldrev
"
,
"
status
"
:
"
available
"
,
"
children
"
:
[{
"
rev
"
:
"
3-
"
+
o
.
rev_hash
,
"
status
"
:
"
available
"
,
"
children
"
:
[]
}]
}]
}]
},{
}]
"
rev
"
:
"
1-rev2
"
,
"
status
"
:
"
available
"
,
"
children
"
:
[]
};
}]};
// 5. check if document tree has been updated correctly
// 5. check if document tree has been updated correctly
deepEqual
(
localstorage
.
getItem
(
deepEqual
(
localstorage
.
getItem
(
"
jio/localstorage/urevrem/arevrem
/remove1.revision_tree.json
"
o
.
localpath
+
"
/remove1.revision_tree.json
"
),
o
.
test
tree
,
"
Check document tree
"
);
),
o
.
doc
tree
,
"
Check document tree
"
);
// 6. check if
attachment has been removed
// 6. check if
the attachment still exists
deepEqual
(
localstorage
.
getItem
(
deepEqual
(
localstorage
.
getItem
(
"
jio/localstorage/urevrem/arevrem/remove1.
"
+
o
.
rev
+
"
/remove2
"
o
.
localpath
+
"
/remove1.2-oldrev
/remove2
"
),
null
,
"
Check attachment
"
);
),
"
abc
"
,
"
Check attachment -> still exists
"
);
// 7. check if document is updated
// 7. check if document is updated
deepEqual
(
localstorage
.
getItem
(
deepEqual
(
localstorage
.
getItem
(
"
jio/localstorage/urevrem/arevrem/remove1.
"
+
o
.
rev
o
.
localpath
+
"
/remove1.3-
"
+
o
.
rev_hash
),
{
"
_id
"
:
"
remove1.
"
+
o
.
rev
,
"
title
"
:
"
myRemove1
"
},
"
Check document
"
);
),
{
"
_id
"
:
"
remove1.3-
"
+
o
.
rev_hash
,
// add another attachment
"
title
"
:
"
myRemove1
"
,
o
.
attmt_myremove2
=
{
"
_attachments
"
:
{
"
remove3
"
:
o
.
attachment_remove3
}
"
remove3
"
:
{
},
"
Check document
"
);
"
length
"
:
3
,
"
digest
"
:
"
md5-hello123
"
// 8. remove document with wrong revision
},
o
.
spy
(
o
,
"
status
"
,
409
,
"
Remove document with wrong revision
"
+
"
revpos
"
:
1
"
-> 409 Conflict
"
);
};
o
.
jio
.
remove
({
"
_id
"
:
"
remove1
"
,
"
_rev
"
:
"
1-a
"
},
o
.
f
);
o
.
doc_myremove2
=
{
"
_id
"
:
"
remove1
"
,
"
title
"
:
"
myRemove2
"
,
o
.
tick
(
o
);
"
_attachments
"
:
o
.
attmt_myremove2
};
o
.
revisions
=
{
"
start
"
:
1
,
"
ids
"
:[
"
rev2
"
]
};
// 9. remove attachment wrong revision
o
.
second_old_rev
=
"
2-
"
+
generateRevisionHash
(
o
.
doc_myremove2
,
o
.
revisions
);
o
.
spy
(
o
,
"
status
"
,
409
,
"
Remove attachment with wrong revision
"
+
"
-> 409 Conflict
"
);
localstorage
.
setItem
(
o
.
localpath
+
"
/remove1.
"
+
o
.
second_old_rev
,
o
.
jio
.
remove
({
"
_id
"
:
"
remove1/remove2
"
,
"
_rev
"
:
"
1-a
"
},
o
.
f
);
o
.
doc_myremove2
);
o
.
tick
(
o
);
localstorage
.
setItem
(
o
.
localpath
+
"
/remove1.
"
+
o
.
second_old_rev
+
"
/remove3
"
,
"
stu
"
);
// 10. remove document
o
.
last_rev
=
"
3-
"
+
o
.
rev_hash
;
o
.
doctree
=
{
"
children
"
:[{
o
.
rev_hash
=
generateRevisionHash
(
"
rev
"
:
o
.
very_old_rev
,
"
status
"
:
"
available
"
,
"
children
"
:
[{
{
"
_id
"
:
"
remove1
"
},
"
rev
"
:
o
.
old_rev
,
"
status
"
:
"
available
"
,
"
children
"
:
[{
{
"
start
"
:
3
,
"
ids
"
:
[
o
.
rev_hash
,
"
oldrev
"
,
"
veryoldrev
"
]},
"
rev
"
:
o
.
rev
,
"
status
"
:
"
available
"
,
"
children
"
:[]
true
}]
);
}]
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
remove1
"
,
"
rev
"
:
"
4-
"
+
o
.
rev_hash
},
},{
"
Remove document
"
);
"
rev
"
:
"
1-rev2
"
,
"
status
"
:
"
available
"
,
"
children
"
:
[{
o
.
jio
.
remove
({
"
_id
"
:
"
remove1
"
,
"
_rev
"
:
o
.
last_rev
},
o
.
f
);
"
rev
"
:
o
.
second_old_rev
,
"
status
"
:
"
available
"
,
"
children
"
:[]
}]
}]};
localstorage
.
setItem
(
o
.
localpath
+
"
/remove1.revision_tree.json
"
,
o
.
doctree
);
// 8. remove non existing attachment without revision
o
.
spy
(
o
,
"
status
"
,
409
,
"
409 - Removing non-existing-attachment (no revision)
"
);
o
.
jio
.
remove
({
"
_id
"
:
"
remove1/remove0
"
},
o
.
f
);
o
.
tick
(
o
);
o
.
revisions
=
{
"
start
"
:
2
,
"
ids
"
:[
o
.
second_old_rev
.
split
(
'
-
'
)[
1
],
"
rev2
"
]};
o
.
doc_myremove3
=
{
"
_id
"
:
"
remove1/remove3
"
,
"
_rev
"
:
o
.
second_old_rev
};
o
.
second_rev
=
"
3-
"
+
generateRevisionHash
(
o
.
doc_myremove3
,
o
.
revisions
);
// 9. remove existing attachment without revision
o
.
spy
(
o
,
"
status
"
,
409
,
"
409 - Removing existing attachment (no revision)
"
);
o
.
jio
.
remove
({
"
_id
"
:
"
remove1/remove3
"
},
o
.
f
);
o
.
tick
(
o
);
// 10. remove wrong revision
o
.
spy
(
o
,
"
status
"
,
409
,
"
409 - Removing document (false revision)
"
);
o
.
jio
.
remove
({
"
_id
"
:
"
remove1
"
,
"
_rev
"
:
"
1-rev2
"
},
o
.
f
);
o
.
tick
(
o
);
o
.
revisions
=
{
"
start
"
:
3
,
"
ids
"
:[
o
.
rev
.
split
(
'
-
'
)[
1
],
o
.
old_rev
.
split
(
'
-
'
)[
1
],
o
.
very_old_rev
.
split
(
'
-
'
)[
1
]
]};
o
.
doc_myremove4
=
{
"
_id
"
:
"
remove1
"
,
"
_rev
"
:
o
.
rev
};
o
.
second_new_rev
=
"
4-
"
+
generateRevisionHash
(
o
.
doc_myremove4
,
o
.
revisions
,
true
);
// 11. remove document version with revision
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
remove1
"
,
"
rev
"
:
o
.
second_new_rev
},
"
Remove document (with revision)
"
);
o
.
jio
.
remove
({
"
_id
"
:
"
remove1
"
,
"
_rev
"
:
o
.
rev
},
o
.
f
);
o
.
tick
(
o
);
o
.
tick
(
o
);
o
.
testtree
[
"
children
"
][
0
][
"
children
"
][
0
][
"
children
"
][
0
][
"
children
"
].
push
({
// 11. check document tree
"
rev
"
:
o
.
second_new_rev
,
o
.
doctree
.
children
[
0
].
children
[
0
].
children
[
0
].
children
.
unshift
({
"
status
"
:
"
deleted
"
,
"
rev
"
:
"
4-
"
+
o
.
rev_hash
,
"
children
"
:
[]
"
status
"
:
"
deleted
"
,
});
"
children
"
:
[]
o
.
testtree
[
"
children
"
][
1
][
"
children
"
].
push
({
"
rev
"
:
o
.
second_old_rev
,
"
status
"
:
"
available
"
,
"
children
"
:[]
});
});
deepEqual
(
localstorage
.
getItem
(
o
.
localpath
+
"
/remove1.revision_tree.json
"
),
deepEqual
(
localstorage
.
getItem
(
o
.
doctree
,
"
Check document tree
"
);
"
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
);
o
.
tick
(
o
);
// remove document
// get inexistent attachment
o
.
rev
=
"
2-8
"
;
o
.
spy
(
o
,
"
status
"
,
404
,
"
Get inexistent winner attachment
"
+
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1
"
,
"
rev
"
:
o
.
rev
},
"
-> 404 Not Found
"
);
"
Remove document
"
);
o
.
jio
.
get
({
"
_id
"
:
"
doc1/attachment1
"
},
o
.
f
);
o
.
jio
.
remove
({
"
_id
"
:
"
doc1
"
,
"
_rev
"
:
"
1-1
"
},
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
o
.
doc
=
{
"
_id
"
:
"
doc1
"
,
"
_rev
"
:
o
.
rev5_8
};
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
);
// ___/____
// / | \
// 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