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
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Romain Courteaud
jio
Commits
c6db8c50
Commit
c6db8c50
authored
Jun 27, 2018
by
Bryan Kaperick
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Made changes to simplify buildQuery revision queries allowing any property names possible.
parent
4306f29f
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
632 additions
and
346 deletions
+632
-346
src/jio.storage/historystorage.js
src/jio.storage/historystorage.js
+179
-168
test/jio.storage/historystorage.tests.js
test/jio.storage/historystorage.tests.js
+453
-178
No files found.
src/jio.storage/historystorage.js
View file @
c6db8c50
...
...
@@ -4,7 +4,7 @@
"
use strict
"
;
// Used to distinguish between operations done within the same millisecond
var
unique_timestamp
=
function
(
time
)
{
function
generateUniqueTimestamp
(
time
)
{
// XXX: replace this with UUIDStorage function call to S4() when it becomes
// publicly accessible
...
...
@@ -13,15 +13,28 @@
//timestamp = Date.now().toString();
timestamp
=
time
.
toString
();
return
timestamp
+
"
-
"
+
uuid
;
}
,
looks_like_timestamp
=
function
(
id
)
{
//1529928772623-02e6
}
function
isTimestamp
(
id
)
{
//A timestamp is of the form
//"[13 digit number]-[4 numbers/lowercase letters]"
var
re
=
/^
[
0-9
]{13}
-
[
a-z0-9
]{4}
$/
;
return
re
.
test
(
id
);
};
}
function
throwCantFindError
(
id
)
{
throw
new
jIO
.
util
.
jIOError
(
"
HistoryStorage: cannot find object '
"
+
id
+
"
'
"
,
404
);
}
function
throwRemovedError
(
id
)
{
throw
new
jIO
.
util
.
jIOError
(
"
HistoryStorage: cannot find object '
"
+
id
+
"
' (removed)
"
,
404
);
}
/**
* The jIO HistoryStorage extension
...
...
@@ -31,11 +44,28 @@
*/
function
HistoryStorage
(
spec
)
{
this
.
_sub_storage
=
jIO
.
createJIO
(
spec
.
sub_storage
);
this
.
_timestamps
=
{};
}
HistoryStorage
.
prototype
.
get
=
function
(
id_in
)
{
if
(
isTimestamp
(
id_in
))
{
// Try to treat id_in as a timestamp instead of a name
return
this
.
_sub_storage
.
get
(
id_in
)
.
push
(
function
(
result
)
{
if
(
result
.
op
===
"
put
"
)
{
return
result
.
doc
;
}
throwCantFindError
(
id_in
);
},
function
(
error
)
{
if
(
error
.
status_code
===
404
&&
error
instanceof
jIO
.
util
.
jIOError
)
{
throwRemovedError
(
id_in
);
}
throw
error
;
});
}
// Query to get the last edit made to this document
var
substorage
=
this
.
_sub_storage
,
...
...
@@ -66,65 +96,23 @@
return
substorage
.
get
(
results
.
data
.
rows
[
0
].
id
)
.
push
(
function
(
result
)
{
return
result
.
doc
;
},
function
(
error
)
{
if
(
error
.
status_code
===
400
&&
error
instanceof
jIO
.
util
.
jIOError
)
{
throw
new
jIO
.
util
.
jIOError
(
"
HistoryStorage: cannot find object '
"
+
id_in
+
"
'
"
,
404
);
}
});
}
throw
new
jIO
.
util
.
jIOError
(
"
HistoryStorage: cannot find object '
"
+
id_in
+
"
' (removed)
"
,
404
);
}
// Try again by treating id_in as a timestamp instead of a name
return
substorage
.
get
(
id_in
)
.
push
(
function
(
result
)
{
if
(
result
.
op
===
"
put
"
)
{
return
result
.
doc
;
}
throw
new
jIO
.
util
.
jIOError
(
"
HistoryStorage: cannot find object '
"
+
id_in
+
"
' (removed)
"
,
404
);
},
function
(
error
)
{
if
(
error
.
status_code
===
400
&&
error
instanceof
jIO
.
util
.
jIOError
)
{
throw
new
jIO
.
util
.
jIOError
(
"
HistoryStorage: cannot find object '
"
+
id_in
+
"
'
"
,
404
);
throwRemovedError
(
id_in
);
}
}
);
throwCantFindError
(
id_in
);
});
};
HistoryStorage
.
prototype
.
put
=
function
(
id
,
data
)
{
if
(
data
.
hasOwnProperty
(
"
_timestamp
"
))
{
throw
new
jIO
.
util
.
jIOError
(
"
Document cannot have metadata attribute '_timestamp'
"
,
422
);
}
if
(
data
.
hasOwnProperty
(
"
_doc_id
"
))
{
throw
new
jIO
.
util
.
jIOError
(
"
Document cannot have metadata attribute '_doc_id'
"
,
422
);
}
if
(
looks_like_timestamp
(
id
))
{
if
(
isTimestamp
(
id
))
{
throw
new
jIO
.
util
.
jIOError
(
"
Document cannot have id of the same form as a timestamp
"
,
422
);
}
var
timestamp
=
unique_t
imestamp
(
Date
.
now
()),
var
timestamp
=
generateUniqueT
imestamp
(
Date
.
now
()),
metadata
=
{
// XXX: remove this attribute once query can sort_on id
timestamp
:
timestamp
,
...
...
@@ -132,37 +120,58 @@
doc
:
data
,
op
:
"
put
"
};
if
(
this
.
_timestamps
.
hasOwnProperty
(
id
))
{
this
.
_timestamps
[
id
].
push
(
timestamp
);
}
else
{
this
.
_timestamps
[
id
]
=
[
timestamp
];
}
return
this
.
_sub_storage
.
put
(
timestamp
,
metadata
);
};
HistoryStorage
.
prototype
.
remove
=
function
(
id
)
{
var
timestamp
=
unique_t
imestamp
(
Date
.
now
()
-
1
),
var
timestamp
=
generateUniqueT
imestamp
(
Date
.
now
()
-
1
),
metadata
=
{
// XXX: remove this attribute once query can sort_on id
timestamp
:
timestamp
,
doc_id
:
id
,
op
:
"
remove
"
};
this
.
_timestamps
[
id
].
push
(
timestamp
);
return
this
.
_sub_storage
.
put
(
timestamp
,
metadata
);
};
HistoryStorage
.
prototype
.
allAttachments
=
function
(
id
)
{
// XXX: If instead you passed a timestamp in as `id`, we could retrieve all
// the attachments of the document at that point in time. Not sure if this
// would be useful.
// XXX: allAttachments with timestamp:
// should return all non-removed attachments at this point in time
var
substorage
=
this
.
_sub_storage
,
// Include id as value in query object for safety (as opposed to string
// concatenation)
query_obj
,
query_removed_check
,
options
,
query_doc_id
,
options_remcheck
;
if
(
isTimestamp
(
id
))
{
query_doc_id
=
new
SimpleQuery
({
operator
:
"
<=
"
,
key
:
"
timestamp
"
,
value
:
id
});
}
else
{
query_doc_id
=
new
SimpleQuery
({
key
:
"
doc_id
"
,
value
:
id
});
}
query_removed_check
=
new
ComplexQuery
({
operator
:
"
AND
"
,
query_list
:
[
query_doc_id
,
new
ComplexQuery
({
operator
:
"
OR
"
,
query_list
:
[
new
SimpleQuery
({
key
:
"
op
"
,
value
:
"
put
"
}),
new
SimpleQuery
({
key
:
"
op
"
,
value
:
"
remove
"
})
]
})
]
});
query_obj
=
new
ComplexQuery
({
operator
:
"
AND
"
,
query_list
:
[
new
SimpleQuery
({
key
:
"
doc_id
"
,
value
:
id
})
,
query_doc_id
,
new
ComplexQuery
({
operator
:
"
OR
"
,
query_list
:
[
...
...
@@ -171,21 +180,42 @@
]
})
]
}),
});
// Only query for attachment edits
options_remcheck
=
{
query
:
query_removed_check
,
select_list
:
[
"
op
"
,
"
timestamp
"
],
//limit: [0, 1],
sort_on
:
[[
"
timestamp
"
,
"
descending
"
]]
};
options
=
{
query
:
query_obj
,
sort_on
:
[[
"
timestamp
"
,
"
descending
"
]],
select_list
:
[
"
op
"
,
"
timestam
p
"
,
"
name
"
]
select_list
:
[
"
o
p
"
,
"
name
"
]
};
return
this
.
_sub_storage
.
allDocs
(
options
)
return
this
.
_sub_storage
.
allDocs
(
options_remcheck
)
.
push
(
function
(
results
)
{
if
(
results
.
data
.
total_rows
>
0
)
{
if
(
results
.
data
.
rows
[
0
].
value
.
op
===
"
remove
"
)
{
throwRemovedError
(
id
);
}
}
else
{
throwCantFindError
(
id
);
}
})
.
push
(
function
()
{
return
substorage
.
allDocs
(
options
);
})
.
push
(
function
(
results
)
{
var
seen
=
{},
attachments
=
[],
attachment_promises
=
[],
ind
,
entry
;
// Only return attachments if:
// (it is the most recent revision) AND (it is a putAttachment)
attachments
=
results
.
data
.
rows
.
filter
(
function
(
docum
)
{
if
(
!
seen
.
hasOwnProperty
(
docum
.
value
.
name
))
{
var
output
=
(
docum
.
value
.
op
===
"
putAttachment
"
);
...
...
@@ -193,17 +223,19 @@
return
output
;
}
});
// Assembles object of attachment_name: attachment_object
for
(
ind
=
0
;
ind
<
attachments
.
length
;
ind
+=
1
)
{
entry
=
attachments
[
ind
];
attachment_promises
[
entry
.
value
.
name
]
=
substorage
.
getAttachment
(
entry
.
id
,
entry
.
value
.
name
);
}
return
RSVP
.
hash
(
attachment_promises
);
});
};
HistoryStorage
.
prototype
.
putAttachment
=
function
(
id
,
name
,
blob
)
{
var
timestamp
=
unique_t
imestamp
(
Date
.
now
()),
var
timestamp
=
generateUniqueT
imestamp
(
Date
.
now
()),
metadata
=
{
// XXX: remove this attribute once query can sort_on id
timestamp
:
timestamp
,
...
...
@@ -212,11 +244,6 @@
op
:
"
putAttachment
"
},
substorage
=
this
.
_sub_storage
;
if
(
this
.
_timestamps
[
id
].
hasOwnProperty
(
name
))
{
this
.
_timestamps
[
id
][
name
].
push
(
timestamp
);
}
else
{
this
.
_timestamps
[
id
][
name
]
=
[
timestamp
];
}
return
this
.
_sub_storage
.
put
(
timestamp
,
metadata
)
.
push
(
function
()
{
return
substorage
.
putAttachment
(
timestamp
,
name
,
blob
);
...
...
@@ -225,6 +252,17 @@
HistoryStorage
.
prototype
.
getAttachment
=
function
(
id
,
name
)
{
if
(
isTimestamp
(
id
))
{
return
this
.
_sub_storage
.
getAttachment
(
id
,
name
)
.
push
(
undefined
,
function
(
error
)
{
if
(
error
.
status_code
===
404
&&
error
instanceof
jIO
.
util
.
jIOError
)
{
throwCantFindError
(
id
);
}
throw
error
;
});
}
// Query to get the last edit made to this document
var
substorage
=
this
.
_sub_storage
,
...
...
@@ -268,39 +306,16 @@
if
(
results
.
data
.
rows
.
length
>
0
)
{
if
(
results
.
data
.
rows
[
0
].
value
.
op
===
"
remove
"
||
results
.
data
.
rows
[
0
].
value
.
op
===
"
removeAttachment
"
)
{
throw
new
jIO
.
util
.
jIOError
(
"
HistoryStorage: cannot find object '
"
+
id
+
"
' (removed)
"
,
404
);
throwRemovedError
(
id
);
}
return
substorage
.
getAttachment
(
results
.
data
.
rows
[
0
].
id
,
name
)
.
push
(
undefined
,
function
(
error
)
{
if
(
error
.
status_code
===
404
&&
error
instanceof
jIO
.
util
.
jIOError
)
{
throw
new
jIO
.
util
.
jIOError
(
"
HistoryStorage: cannot find object '
"
+
id
+
"
'
"
,
404
);
return
substorage
.
getAttachment
(
results
.
data
.
rows
[
0
].
id
,
name
);
}
throw
error
;
});
}
return
substorage
.
getAttachment
(
id
,
name
)
.
push
(
undefined
,
function
(
error
)
{
if
(
error
.
status_code
===
404
&&
error
instanceof
jIO
.
util
.
jIOError
)
{
throw
new
jIO
.
util
.
jIOError
(
"
HistoryStorage: cannot find object '
"
+
id
+
"
'
"
,
404
);
}
throw
error
;
});
throwCantFindError
(
id
);
});
};
HistoryStorage
.
prototype
.
removeAttachment
=
function
(
id
,
name
)
{
var
timestamp
=
unique_t
imestamp
(
Date
.
now
()),
var
timestamp
=
generateUniqueT
imestamp
(
Date
.
now
()),
metadata
=
{
// XXX: remove this attribute once query can sort_on id
timestamp
:
timestamp
,
...
...
@@ -308,7 +323,6 @@
name
:
name
,
op
:
"
removeAttachment
"
};
this
.
_timestamps
[
id
][
name
].
push
(
timestamp
);
return
this
.
_sub_storage
.
put
(
timestamp
,
metadata
);
};
HistoryStorage
.
prototype
.
repair
=
function
()
{
...
...
@@ -319,49 +333,27 @@
};
HistoryStorage
.
prototype
.
buildQuery
=
function
(
options
)
{
// XXX: if include_revisions, we should also include the document results
// for different edits of attachments
// Set default values
if
(
options
===
undefined
)
{
options
=
{};
}
if
(
options
.
query
===
undefined
)
{
options
.
query
=
""
;
}
if
(
options
.
sort_on
===
undefined
)
{
options
.
sort_on
=
[];
}
if
(
options
.
select_list
===
undefined
)
{
options
.
select_list
=
[];
if
(
options
===
undefined
)
{
options
=
{};
}
if
(
options
.
query
===
undefined
)
{
options
.
query
=
""
;
}
if
(
options
.
sort_on
===
undefined
)
{
options
.
sort_on
=
[];
}
if
(
options
.
select_list
===
undefined
)
{
options
.
select_list
=
[];
}
if
(
options
.
include_revisions
===
undefined
)
{
options
.
include_revisions
=
false
;
}
options
.
sort_on
.
push
([
"
timestamp
"
,
"
descending
"
]);
options
.
query
=
jIO
.
QueryFactory
.
create
(
options
.
query
);
var
meta_options
,
substorage
=
this
.
_sub_storage
,
// Check if query involved _REVISION. If not, we will later place a
// (*) AND (_REVISION: =0) as the default handling of revisions
rev_query
=
false
,
query_obj
=
options
.
query
,
query_stack
=
[],
ind
;
if
(
query_obj
instanceof
ComplexQuery
)
{
query_stack
.
push
(
query_obj
);
}
else
{
rev_query
=
(
query_obj
.
key
===
"
_timestamp
"
);
}
// Traverse through query tree to find mentions of _timestamp
// and stop as soon as it is found once
while
(
query_stack
.
length
>
0
&&
(
!
rev_query
))
{
query_obj
=
query_stack
.
pop
();
for
(
ind
=
0
;
ind
<
query_obj
.
query_list
.
length
;
ind
+=
1
)
{
if
(
query_obj
.
query_list
[
ind
].
hasOwnProperty
(
"
query_list
"
))
{
query_stack
.
push
(
query_obj
.
query_list
[
ind
]);
}
else
if
(
query_obj
.
query_list
[
ind
].
key
===
"
_timestamp
"
)
{
rev_query
=
true
;
break
;
}
}
}
// Check if query involved _timestamp.
// If not, use default behavior and only query on latest revisions
rev_query
=
options
.
include_revisions
,
doc_id_name
,
timestamp_name
;
// Query for all edits putting or removing documents (and nothing about
// attachments)
...
...
@@ -382,7 +374,8 @@
.
push
(
function
(
results
)
{
var
seen
=
{},
query_matches
,
docs_to_query
;
docs_to_query
,
i
;
// If !rev_query, then by default only consider latest revisions of
// documents
results
=
results
.
filter
(
function
(
docum
)
{
...
...
@@ -395,29 +388,47 @@
}
return
false
;
});
// If any documents have property _doc_id, __doc_id, etc, then set
// doc_id_name to the first string which is not a property of any
// of the documents
doc_id_name
=
"
_doc_id
"
;
timestamp_name
=
"
_timestamp
"
;
for
(
i
=
0
;
i
<
results
.
length
;
i
+=
1
)
{
while
(
results
[
i
].
doc
.
hasOwnProperty
(
doc_id_name
))
{
doc_id_name
=
"
_
"
+
doc_id_name
;
}
while
(
results
[
i
].
doc
.
hasOwnProperty
(
timestamp_name
))
{
timestamp_name
=
"
_
"
+
timestamp_name
;
}
}
docs_to_query
=
results
.
map
(
function
(
docum
)
{
// If it's a "remove" operation
// If it's a "remove" operation
then it has no doc property
if
(
!
docum
.
hasOwnProperty
(
"
doc
"
))
{
docum
.
doc
=
{};
}
docum
.
doc
.
_doc_id
=
docum
.
doc_id
;
docum
.
doc
.
_timestamp
=
docum
.
timestamp
;
docum
.
doc
[
doc_id_name
]
=
docum
.
doc_id
;
docum
.
doc
[
timestamp_name
]
=
docum
.
timestamp
;
return
docum
.
doc
;
});
options
.
select_list
.
push
(
"
_doc_id
"
);
options
.
select_list
.
push
(
doc_id_name
);
options
.
select_list
.
push
(
timestamp_name
);
query_matches
=
options
.
query
.
exec
(
docs_to_query
,
options
);
return
query_matches
;
})
// Format the results of the query, and return
.
push
(
function
(
query_matches
)
{
return
query_matches
.
map
(
function
(
docum
)
{
var
doc_id
=
docum
.
_doc_id
;
delete
docum
.
_timestamp
;
delete
docum
.
_doc_id
;
var
doc_id
=
docum
[
doc_id_name
],
time
=
docum
[
timestamp_name
];
delete
docum
[
timestamp_name
];
delete
docum
[
doc_id_name
];
return
{
doc
:
{},
value
:
docum
,
id
:
doc_id
id
:
doc_id
,
timestamp
:
time
};
});
});
...
...
test/jio.storage/historystorage.tests.js
View file @
c6db8c50
...
...
@@ -64,36 +64,47 @@
test
(
"
Testing proper adding/removing attachments
"
,
function
()
{
stop
();
expect
(
9
);
expect
(
10
);
var
jio
=
this
.
jio
,
timestamps
=
this
.
jio
.
__storage
.
_timestamps
,
not_history
=
this
.
not_history
,
timestamps
,
blob2
=
this
.
blob2
,
blob1
=
this
.
blob1
,
other_blob
=
this
.
other_blob
,
otherother_blob
=
new
Blob
([
'
abcabc
'
]);
jio
.
put
(
"
doc
"
,
{
title
:
"
foo0
"
})
jio
.
put
(
"
doc
"
,
{
title
:
"
foo0
"
})
// 0
.
push
(
function
()
{
return
jio
.
put
(
"
doc2
"
,
{
key
:
"
val
"
});
return
jio
.
put
(
"
doc2
"
,
{
key
:
"
val
"
});
// 1
})
.
push
(
function
()
{
return
jio
.
putAttachment
(
"
doc
"
,
"
attacheddata
"
,
blob1
);
return
jio
.
putAttachment
(
"
doc
"
,
"
attacheddata
"
,
blob1
);
// 2
})
.
push
(
function
()
{
return
jio
.
putAttachment
(
"
doc
"
,
"
attacheddata
"
,
blob2
);
return
jio
.
putAttachment
(
"
doc
"
,
"
attacheddata
"
,
blob2
);
// 3
})
.
push
(
function
()
{
return
jio
.
putAttachment
(
"
doc
"
,
"
other_attacheddata
"
,
other_blob
);
return
jio
.
putAttachment
(
"
doc
"
,
"
other_attacheddata
"
,
other_blob
);
// 4
})
.
push
(
function
()
{
return
jio
.
putAttachment
(
return
jio
.
putAttachment
(
// 5
"
doc
"
,
"
otherother_attacheddata
"
,
otherother_blob
);
})
.
push
(
function
()
{
return
jio
.
removeAttachment
(
"
doc
"
,
"
otherother_attacheddata
"
);
return
jio
.
removeAttachment
(
"
doc
"
,
"
otherother_attacheddata
"
);
// 6
})
.
push
(
function
()
{
return
not_history
.
allDocs
({
sort_on
:
[[
"
timestamp
"
,
"
ascending
"
]]
});
})
.
push
(
function
(
results
)
{
timestamps
=
results
.
data
.
rows
.
map
(
function
(
d
)
{
return
d
.
id
;
});
})
.
push
(
function
()
{
return
jio
.
get
(
"
doc
"
);
...
...
@@ -110,7 +121,7 @@
"
Return the attachment information with getAttachment
"
);
return
jio
.
getAttachment
(
timestamps
.
doc
.
attacheddata
[
1
],
timestamps
[
3
],
"
attacheddata
"
);
})
...
...
@@ -121,7 +132,7 @@
"
current revision
"
);
return
jio
.
getAttachment
(
timestamps
.
doc
.
attacheddata
[
0
],
timestamps
[
2
],
"
attacheddata
"
);
},
function
(
error
)
{
...
...
@@ -134,7 +145,7 @@
"
Return the attachment information with getAttachment for
"
+
"
previous revision
"
);
return
jio
.
getAttachment
(
timestamps
.
doc
[
0
],
"
attached
"
);
return
jio
.
getAttachment
(
timestamps
[
0
],
"
attached
"
);
},
function
(
error
)
{
ok
(
false
,
error
);
})
...
...
@@ -146,6 +157,9 @@
deepEqual
(
error
.
status_code
,
404
,
"
Error if you try to go back to a nonexistent timestamp
"
);
deepEqual
(
error
.
message
,
"
HistoryStorage: cannot find object '
"
+
timestamps
[
0
]
+
"
'
"
,
"
Error caught by history storage correctly
"
);
return
jio
.
getAttachment
(
"
doc
"
,
"
other_attacheddata
"
);
})
.
push
(
function
(
result
)
{
...
...
@@ -208,10 +222,10 @@
.
always
(
function
()
{
start
();
});
});
test
(
"
Correctness of allAttachments method
"
,
test
(
"
Correctness of allAttachments method
on current attachments
"
,
function
()
{
stop
();
expect
(
1
1
);
expect
(
1
4
);
var
jio
=
this
.
jio
,
not_history
=
this
.
not_history
,
blob1
=
this
.
blob1
,
...
...
@@ -317,7 +331,7 @@
}));
})
.
push
(
function
(
results
)
{
equal
(
results
.
length
,
7
,
"
Seven document revisions in storage
(17)
"
);
equal
(
results
.
length
,
7
,
"
Seven document revisions in storage
"
);
return
jio
.
remove
(
"
doc
"
);
})
.
push
(
function
()
{
...
...
@@ -332,6 +346,132 @@
404
,
"
Cannot get the attachment of a removed document
"
);
})
.
push
(
function
()
{
return
jio
.
allAttachments
(
"
doc
"
);
})
.
push
(
function
()
{
ok
(
false
,
"
This query should have thrown a 404 error
"
);
},
function
(
error
)
{
ok
(
error
instanceof
jIO
.
util
.
jIOError
,
"
throws a jio error
"
);
deepEqual
(
error
.
status_code
,
404
,
"
allAttachments of a removed document throws a 404 error
"
);
deepEqual
(
error
.
message
,
"
HistoryStorage: cannot find object 'doc' (removed)
"
,
"
Error is handled by Historystorage.
"
);
})
.
fail
(
function
(
error
)
{
//console.log(error);
ok
(
false
,
error
);
})
.
always
(
function
()
{
start
();
});
});
test
(
"
Correctness of allAttachments method on older revisions
"
,
function
()
{
stop
();
expect
(
8
);
var
jio
=
this
.
jio
,
not_history
=
this
.
not_history
,
blob1
=
new
Blob
([
'
a
'
]),
blob11
=
new
Blob
([
'
ab
'
]),
blob2
=
new
Blob
([
'
abc
'
]),
blob22
=
new
Blob
([
'
abcd
'
]),
timestamps
;
jio
.
put
(
"
doc
"
,
{
title
:
"
foo0
"
})
// 0
.
push
(
function
()
{
return
jio
.
putAttachment
(
"
doc
"
,
"
data
"
,
blob1
);
})
.
push
(
function
()
{
return
jio
.
putAttachment
(
"
doc
"
,
"
data2
"
,
blob2
);
})
.
push
(
function
()
{
return
jio
.
put
(
"
doc
"
,
{
title
:
"
foo1
"
});
// 1
})
.
push
(
function
()
{
return
jio
.
removeAttachment
(
"
doc
"
,
"
data2
"
);
})
.
push
(
function
()
{
return
jio
.
put
(
"
doc
"
,
{
title
:
"
foo2
"
});
// 2
})
.
push
(
function
()
{
return
jio
.
putAttachment
(
"
doc
"
,
"
data
"
,
blob11
);
})
.
push
(
function
()
{
return
jio
.
remove
(
"
doc
"
);
// 3
})
.
push
(
function
()
{
return
jio
.
put
(
"
doc
"
,
{
title
:
"
foo3
"
});
// 4
})
.
push
(
function
()
{
return
jio
.
putAttachment
(
"
doc
"
,
"
data2
"
,
blob22
);
})
.
push
(
function
()
{
return
not_history
.
allDocs
({
query
:
"
op: put OR op: remove
"
,
sort_on
:
[[
"
timestamp
"
,
"
ascending
"
]],
select_list
:
[
"
timestamp
"
]
});
})
.
push
(
function
(
results
)
{
timestamps
=
results
.
data
.
rows
.
map
(
function
(
d
)
{
return
d
.
value
.
timestamp
;
});
})
.
push
(
function
()
{
return
jio
.
allAttachments
(
"
doc
"
);
})
.
push
(
function
(
results
)
{
deepEqual
(
results
,
{
"
data
"
:
blob11
,
"
data2
"
:
blob22
},
"
Current state of document is correct
"
);
return
jio
.
allAttachments
(
timestamps
[
0
]);
})
.
push
(
function
(
results
)
{
deepEqual
(
results
,
{},
"
First version of document has 0 attachments
"
);
return
jio
.
allAttachments
(
timestamps
[
1
]);
})
.
push
(
function
(
results
)
{
deepEqual
(
results
,
{
data
:
blob1
,
data2
:
blob2
},
"
Both attachments are included in allAttachments
"
);
return
jio
.
allAttachments
(
timestamps
[
2
]);
})
.
push
(
function
(
results
)
{
deepEqual
(
results
,
{
data
:
blob1
},
"
Removed attachment does not show up in allAttachments
"
);
return
jio
.
allAttachments
(
timestamps
[
3
]);
})
.
push
(
function
()
{
ok
(
false
,
"
This query should have thrown a 404 error
"
);
},
function
(
error
)
{
ok
(
error
instanceof
jIO
.
util
.
jIOError
,
"
throws a jio error
"
);
deepEqual
(
error
.
status_code
,
404
,
"
allAttachments of a removed document throws a 404 error
"
);
deepEqual
(
error
.
message
,
"
HistoryStorage: cannot find object '
"
+
timestamps
[
3
]
+
"
' (removed)
"
,
"
Error is handled by Historystorage.
"
);
})
.
push
(
function
()
{
return
jio
.
allAttachments
(
timestamps
[
4
]);
})
.
push
(
function
(
results
)
{
deepEqual
(
results
,
{
data
:
blob11
});
})
.
fail
(
function
(
error
)
{
//console.log(error);
ok
(
false
,
error
);
...
...
@@ -377,49 +517,48 @@
test
(
"
Handling bad input
"
,
function
()
{
stop
();
expect
(
6
);
expect
(
2
);
var
jio
=
this
.
jio
,
BADINPUT_ERRCODE
=
422
;
jio
.
put
(
"
doc
"
,
{
"
_timestamp
"
:
3
,
"
other_attr
"
:
"
other_val
"
})
jio
.
put
(
"
1234567891123-ab7d
"
,
{})
.
push
(
function
()
{
ok
(
false
,
"
This statement should not be reached
"
);
},
function
(
error
)
{
ok
(
error
instanceof
jIO
.
util
.
jIOError
,
"
Correct type of error
"
);
deepEqual
(
error
.
status_code
,
BADINPUT_ERRCODE
,
"
Can't save a document with a
reserved keywor
d
"
"
Can't save a document with a
timestamp-formatted i
d
"
);
})
.
push
(
function
()
{
return
jio
.
put
(
"
doc
"
,
{
"
_doc_id
"
:
3
,
"
other_attr
"
:
"
other_val
"
});
})
.
push
(
function
()
{
ok
(
false
,
"
This statement should not be reached
"
);
},
function
(
error
)
{
ok
(
error
instanceof
jIO
.
util
.
jIOError
,
"
Correct type of error
"
);
deepEqual
(
error
.
status_code
,
BADINPUT_ERRCODE
,
"
Can't save a document with a reserved keyword
"
);
.
fail
(
function
(
error
)
{
//console.log(error);
ok
(
false
,
error
);
})
.
always
(
function
()
{
start
();
});
});
test
(
"
Getting a non-existent document
"
,
function
()
{
stop
();
expect
(
3
);
var
jio
=
this
.
jio
;
jio
.
put
(
"
not_doc
"
,
{})
.
push
(
function
()
{
return
jio
.
put
(
"
1234567891123-ab7d
"
,
{}
);
return
jio
.
get
(
"
doc
"
);
})
.
push
(
function
()
{
ok
(
false
,
"
This statement should not be reached
"
);
},
function
(
error
)
{
//console.log(error);
ok
(
error
instanceof
jIO
.
util
.
jIOError
,
"
Correct type of error
"
);
deepEqual
(
error
.
status_code
,
BADINPUT_ERRCODE
,
"
C
an't save a document with a timestamp-formatted id
"
404
,
"
C
orrect status code for getting a non-existent document
"
);
deepEqual
(
error
.
message
,
"
HistoryStorage: cannot find object 'doc'
"
,
"
Error is handled by history storage before reaching console
"
);
})
.
fail
(
function
(
error
)
{
//console.log(error);
...
...
@@ -431,31 +570,39 @@
test
(
"
Creating a document with put and retrieving it with get
"
,
function
()
{
stop
();
expect
(
4
);
expect
(
7
);
var
jio
=
this
.
jio
,
not_history
=
this
.
not_history
,
timestamps
=
jio
.
__storage
.
_timestamps
;
timestamps
;
jio
.
put
(
"
doc
"
,
{
title
:
"
version0
"
})
.
push
(
function
()
{
ok
(
timestamps
.
hasOwnProperty
(
"
doc
"
),
"
jio._timestamps is updated with new document.
"
);
equal
(
timestamps
.
doc
.
length
,
return
not_history
.
allDocs
({
select_list
:
[
"
timestamp
"
]
});
})
.
push
(
function
(
results
)
{
timestamps
=
results
.
data
.
rows
.
map
(
function
(
d
)
{
return
d
.
value
.
timestamp
;
});
})
.
push
(
function
()
{
equal
(
timestamps
.
length
,
1
,
"
One revision is
logged in jio._timestamps
"
"
One revision is
saved in storage
"
);
return
jio
.
get
(
timestamps
.
doc
[
0
]);
return
jio
.
get
(
timestamps
[
0
]);
})
.
push
(
function
(
result
)
{
deepEqual
(
result
,
{
title
:
"
version0
"
},
"
Get document from history storage
"
);
return
not_history
.
get
(
timestamps
.
doc
[
0
]
timestamps
[
0
]
);
})
.
push
(
function
(
result
)
{
deepEqual
(
result
,
{
timestamp
:
timestamps
.
doc
[
0
],
timestamp
:
timestamps
[
0
],
op
:
"
put
"
,
doc_id
:
"
doc
"
,
doc
:
{
...
...
@@ -463,6 +610,31 @@
}
},
"
Get document from non-history storage
"
);
})
.
push
(
function
()
{
return
jio
.
get
(
"
non-existent-doc
"
);
})
.
push
(
function
()
{
ok
(
false
,
"
This should have thrown an error
"
);
},
function
(
error
)
{
//console.log(error);
ok
(
error
instanceof
jIO
.
util
.
jIOError
,
"
Correct type of error
"
);
deepEqual
(
error
.
status_code
,
404
,
"
Can't access non-existent document
"
);
})
.
push
(
function
()
{
return
jio
.
get
(
"
1234567891123-abcd
"
);
})
.
push
(
function
()
{
ok
(
false
,
"
Trying to get a non-existent id should have raised 404
"
);
},
function
(
error
)
{
ok
(
error
instanceof
jIO
.
util
.
jIOError
,
"
Correct type of error
"
);
deepEqual
(
error
.
status_code
,
404
,
"
Can't access document by getting with non-existent id
"
);
})
.
fail
(
function
(
error
)
{
//console.log(error);
ok
(
false
,
error
);
...
...
@@ -475,7 +647,8 @@
stop
();
expect
(
7
);
var
jio
=
this
.
jio
,
timestamps
=
this
.
jio
.
__storage
.
_timestamps
;
not_history
=
this
.
not_history
,
timestamps
;
return
jio
.
put
(
"
doc
"
,
{
title
:
"
t0
"
,
subtitle
:
"
s0
"
})
.
push
(
function
()
{
...
...
@@ -490,6 +663,17 @@
.
push
(
function
()
{
return
jio
.
put
(
"
doc
"
,
{
title
:
"
t3
"
,
subtitle
:
"
s3
"
});
})
.
push
(
function
()
{
return
not_history
.
allDocs
({
select_list
:
[
"
timestamp
"
],
sort_on
:
[[
"
timestamp
"
,
"
ascending
"
]]
});
})
.
push
(
function
(
results
)
{
timestamps
=
results
.
data
.
rows
.
map
(
function
(
d
)
{
return
d
.
value
.
timestamp
;
});
})
.
push
(
function
()
{
return
jio
.
get
(
"
doc
"
);
})
...
...
@@ -498,7 +682,7 @@
title
:
"
t3
"
,
subtitle
:
"
s3
"
},
"
Get returns latest revision
"
);
return
jio
.
get
(
timestamps
.
doc
[
0
]);
return
jio
.
get
(
timestamps
[
0
]);
},
function
(
err
)
{
ok
(
false
,
err
);
})
...
...
@@ -507,14 +691,14 @@
title
:
"
t0
"
,
subtitle
:
"
s0
"
},
"
Get returns first version
"
);
return
jio
.
get
(
timestamps
.
doc
[
1
]);
return
jio
.
get
(
timestamps
[
1
]);
})
.
push
(
function
(
result
)
{
deepEqual
(
result
,
{
title
:
"
t1
"
,
subtitle
:
"
s1
"
},
"
Get returns second version
"
);
return
jio
.
get
(
timestamps
.
doc
[
2
]);
return
jio
.
get
(
timestamps
[
2
]);
},
function
(
err
)
{
ok
(
false
,
err
);
})
...
...
@@ -523,20 +707,20 @@
title
:
"
t2
"
,
subtitle
:
"
s2
"
},
"
Get returns third version
"
);
return
jio
.
get
(
timestamps
.
doc
[
3
]);
return
jio
.
get
(
timestamps
[
3
]);
},
function
(
err
)
{
ok
(
false
,
err
);
})
.
push
(
function
()
{
ok
(
false
,
"
This should have thrown a 404 error
"
);
return
jio
.
get
(
timestamps
.
doc
[
4
]);
return
jio
.
get
(
timestamps
[
4
]);
},
function
(
error
)
{
ok
(
error
instanceof
jIO
.
util
.
jIOError
,
"
Correct type of error
"
);
deepEqual
(
error
.
status_code
,
404
,
"
Error if you try to go back more revisions than what exists
"
);
return
jio
.
get
(
timestamps
.
doc
[
4
]);
return
jio
.
get
(
timestamps
[
4
]);
})
.
push
(
function
(
result
)
{
deepEqual
(
result
,
{
...
...
@@ -674,8 +858,18 @@
stop
();
expect
(
7
);
var
jio
=
this
.
jio
,
not_history
=
this
.
not_history
;
not_history
=
this
.
not_history
,
timestamp
;
jio
.
put
(
"
doc
"
,
{
title
:
"
version0
"
})
.
push
(
function
()
{
return
not_history
.
allDocs
({
query
:
"
doc_id: doc
"
,
select_list
:
[
"
timestamp
"
]
});
})
.
push
(
function
(
results
)
{
timestamp
=
results
.
data
.
rows
[
0
].
value
.
timestamp
;
})
.
push
(
function
()
{
return
RSVP
.
all
([
jio
.
allDocs
(),
...
...
@@ -701,7 +895,8 @@
deepEqual
(
results
.
data
.
rows
[
0
],
{
doc
:
{},
value
:
{},
id
:
"
doc
"
id
:
"
doc
"
,
timestamp
:
timestamp
},
"
Correct document format is returned.
"
);
...
...
@@ -715,7 +910,7 @@
})
.
push
(
function
(
result
)
{
deepEqual
(
result
,
{
timestamp
:
jio
.
__storage
.
_timestamps
.
doc
[
0
]
,
timestamp
:
timestamp
,
doc_id
:
"
doc
"
,
doc
:
{
title
:
"
version0
"
...
...
@@ -733,14 +928,69 @@
.
always
(
function
()
{
start
();
});
});
test
(
"
Putting doc with _doc_id and _timestamp properties
"
+
"
and retrieving them with allDocs
"
,
function
()
{
stop
();
expect
(
1
);
var
jio
=
this
.
jio
,
not_history
=
this
.
not_history
,
timestamp
;
jio
.
put
(
"
doc
"
,
{
title
:
"
version0
"
,
_doc_id
:
"
bar
"
,
__doc_id
:
"
bar2
"
,
___doc_id
:
"
bar3
"
,
_timestamp
:
"
foo
"
,
____timestamp
:
"
foo2
"
})
.
push
(
function
()
{
return
not_history
.
allDocs
({
query
:
"
doc_id: doc
"
,
select_list
:
[
"
timestamp
"
]
});
})
.
push
(
function
(
results
)
{
timestamp
=
results
.
data
.
rows
[
0
].
value
.
timestamp
;
})
.
push
(
function
()
{
return
jio
.
allDocs
({
query
:
"
title: version0 AND _timestamp: >= 0
"
,
select_list
:
[
"
title
"
,
"
_doc_id
"
,
"
__doc_id
"
,
"
___doc_id
"
,
"
_timestamp
"
,
"
____timestamp
"
]
});
})
.
push
(
function
(
results
)
{
deepEqual
(
results
.
data
.
rows
,
[
{
doc
:
{},
id
:
"
doc
"
,
value
:
{
title
:
"
version0
"
,
_doc_id
:
"
bar
"
,
__doc_id
:
"
bar2
"
,
___doc_id
:
"
bar3
"
,
_timestamp
:
"
foo
"
,
____timestamp
:
"
foo2
"
},
timestamp
:
timestamp
}],
"
_doc_id properties are not overwritten in allDocs call
"
);
})
.
fail
(
function
(
error
)
{
//console.log(error);
ok
(
false
,
error
);
})
.
always
(
function
()
{
start
();
});
});
test
(
"
Putting a document, revising it, and retrieving revisions with allDocs
"
,
function
()
{
stop
();
expect
(
1
4
);
expect
(
1
0
);
var
jio
=
this
.
jio
,
not_history
=
this
.
not_history
,
timestamps
=
this
.
jio
.
__storage
.
_timestamps
;
timestamps
;
jio
.
put
(
"
doc
"
,
{
title
:
"
version0
"
,
subtitle
:
"
subvers0
"
...
...
@@ -757,6 +1007,17 @@
subtitle
:
"
subvers2
"
});
})
.
push
(
function
()
{
return
not_history
.
allDocs
({
select_list
:
[
"
timestamp
"
],
sort_on
:
[[
"
timestamp
"
,
"
ascending
"
]]
});
})
.
push
(
function
(
results
)
{
timestamps
=
results
.
data
.
rows
.
map
(
function
(
d
)
{
return
d
.
value
.
timestamp
;
});
})
.
push
(
function
()
{
return
RSVP
.
all
([
jio
.
allDocs
({
select_list
:
[
"
title
"
,
"
subtitle
"
]}),
...
...
@@ -803,73 +1064,52 @@
subtitle
:
"
subvers2
"
},
doc
:
{},
id
:
"
doc
"
id
:
"
doc
"
,
timestamp
:
timestamps
[
2
]
},
"
Correct document format is returned.
"
);
})
.
push
(
function
()
{
// These are all equivalent queries in that they should return the
// same documents in the correct order
return
RSVP
.
all
([
jio
.
allDocs
({
query
:
"
_timestamp:
"
+
timestamps
.
doc
[
1
],
select_list
:
[
"
title
"
,
"
subtitle
"
]
}),
jio
.
allDocs
({
query
:
"
_timestamp: =
"
+
timestamps
.
doc
[
1
],
select_list
:
[
"
title
"
,
"
subtitle
"
]
}),
jio
.
allDocs
({
query
:
"
_timestamp: >
"
+
timestamps
.
doc
[
0
]
+
"
AND title: version1
"
,
select_list
:
[
"
title
"
,
"
subtitle
"
]
}),
jio
.
allDocs
({
query
:
"
_timestamp: >
"
+
timestamps
.
doc
[
0
]
+
"
AND _timestamp: <
"
+
timestamps
.
doc
[
2
],
select_list
:
[
"
title
"
,
"
subtitle
"
]
})
]);
})
.
push
(
function
(
results
)
{
equal
(
results
[
0
].
data
.
rows
.
length
,
1
,
"
Querying a specific timestamp retrieves one document
"
);
var
ind
=
0
;
for
(
ind
=
0
;
ind
<
results
.
length
-
1
;
ind
+=
1
)
{
deepEqual
(
results
[
ind
],
results
[
ind
+
1
],
"
Each query returns exactly the same correct output
"
);
}
return
results
[
0
];
return
jio
.
allDocs
({
query
:
""
,
select_list
:
[
"
title
"
,
"
subtitle
"
],
include_revisions
:
true
});
})
.
push
(
function
(
results
)
{
deepEqual
(
results
.
data
.
rows
[
0
],
{
equal
(
results
.
data
.
rows
.
length
,
3
,
"
Querying with include_revisions retrieves all versions
"
);
deepEqual
(
results
.
data
.
rows
,
[
{
id
:
"
doc
"
,
value
:
{
title
:
"
version2
"
,
subtitle
:
"
subvers2
"
},
doc
:
{},
timestamp
:
timestamps
[
2
]
},
{
id
:
"
doc
"
,
value
:
{
title
:
"
version1
"
,
subtitle
:
"
subvers1
"
},
doc
:
{}
});
return
jio
.
allDocs
({
query
:
"
_timestamp:
"
+
timestamps
.
doc
[
0
],
select_list
:
[
"
title
"
,
"
subtitle
"
]
});
})
.
push
(
function
(
results
)
{
deepEqual
(
results
.
data
.
rows
,
[
doc
:
{},
timestamp
:
timestamps
[
1
]
},
{
id
:
"
doc
"
,
value
:
{
title
:
"
version0
"
,
subtitle
:
"
subvers0
"
},
doc
:
{},
id
:
"
doc
"
timestamp
:
timestamps
[
0
]
}
],
"
Query requesting one timestamp works
.
"
);
],
"
Full version history is included
.
"
);
return
not_history
.
allDocs
({
sort_on
:
[[
"
title
"
,
"
ascending
"
]]
...
...
@@ -883,7 +1123,7 @@
.
push
(
function
(
results
)
{
deepEqual
(
results
,
[
{
timestamp
:
timestamps
.
doc
[
0
],
timestamp
:
timestamps
[
0
],
op
:
"
put
"
,
doc_id
:
"
doc
"
,
doc
:
{
...
...
@@ -892,7 +1132,7 @@
}
},
{
timestamp
:
timestamps
.
doc
[
1
],
timestamp
:
timestamps
[
1
],
op
:
"
put
"
,
doc_id
:
"
doc
"
,
doc
:
{
...
...
@@ -901,7 +1141,7 @@
}
},
{
timestamp
:
timestamps
.
doc
[
2
],
timestamp
:
timestamps
[
2
],
op
:
"
put
"
,
doc_id
:
"
doc
"
,
doc
:
{
...
...
@@ -924,43 +1164,54 @@
"
Putting and removing documents, latest revisions and no removed documents
"
,
function
()
{
stop
();
expect
(
5
);
var
history
=
this
.
jio
,
timestamps
=
this
.
jio
.
__storage
.
_timestamps
;
expect
(
3
);
var
jio
=
this
.
jio
,
not_history
=
this
.
not_history
,
timestamps
;
history
.
put
(
"
doc_a
"
,
{
jio
.
put
(
"
doc_a
"
,
{
title_a
:
"
rev0
"
,
subtitle_a
:
"
subrev0
"
})
.
push
(
function
()
{
return
history
.
put
(
"
doc_a
"
,
{
return
jio
.
put
(
"
doc_a
"
,
{
title_a
:
"
rev1
"
,
subtitle_a
:
"
subrev1
"
});
})
.
push
(
function
()
{
return
history
.
put
(
"
doc_b
"
,
{
return
jio
.
put
(
"
doc_b
"
,
{
title_b
:
"
rev0
"
,
subtitle_b
:
"
subrev0
"
});
})
.
push
(
function
()
{
return
history
.
remove
(
"
doc_b
"
);
return
jio
.
remove
(
"
doc_b
"
);
})
.
push
(
function
()
{
return
history
.
put
(
"
doc_c
"
,
{
return
jio
.
put
(
"
doc_c
"
,
{
title_c
:
"
rev0
"
,
subtitle_c
:
"
subrev0
"
});
})
.
push
(
function
()
{
return
history
.
put
(
"
doc_c
"
,
{
return
jio
.
put
(
"
doc_c
"
,
{
title_c
:
"
rev1
"
,
subtitle_c
:
"
subrev1
"
});
})
.
push
(
function
()
{
return
history
.
allDocs
({
sort_on
:
[[
"
timestamp
"
,
"
descending
"
]]});
return
not_history
.
allDocs
({
sort_on
:
[[
"
timestamp
"
,
"
ascending
"
]]
});
})
.
push
(
function
(
results
)
{
timestamps
=
results
.
data
.
rows
.
map
(
function
(
d
)
{
return
d
.
id
;
});
})
.
push
(
function
()
{
return
jio
.
allDocs
({
sort_on
:
[[
"
timestamp
"
,
"
descending
"
]]});
})
.
push
(
function
(
results
)
{
equal
(
results
.
data
.
rows
.
length
,
...
...
@@ -971,24 +1222,20 @@
{
id
:
"
doc_c
"
,
value
:
{},
doc
:
{}
doc
:
{},
timestamp
:
timestamps
[
5
]
},
{
id
:
"
doc_a
"
,
value
:
{},
doc
:
{}
doc
:
{},
timestamp
:
timestamps
[
1
]
}
],
"
Empty query returns latest revisions (and no removed documents)
"
);
equal
(
timestamps
.
doc_a
.
length
,
2
,
"
Correct number of revisions logged in doc_a
"
);
equal
(
timestamps
.
doc_b
.
length
,
2
,
"
Correct number of revisions logged in doc_b
"
);
equal
(
timestamps
.
doc_c
.
length
,
2
,
"
Correct number of revisions logged in doc_c
"
);
equal
(
timestamps
.
length
,
6
,
"
Correct number of revisions logged
"
);
})
.
fail
(
function
(
error
)
{
//console.log(error);
...
...
@@ -1006,7 +1253,9 @@
function
()
{
stop
();
expect
(
2
);
var
history
=
this
.
jio
,
var
jio
=
this
.
jio
,
not_history
=
this
.
not_history
,
timestamps
,
docs
=
[
{
"
date
"
:
1
,
...
...
@@ -1029,19 +1278,29 @@
new
Blob
([
'
bcd
'
]),
new
Blob
([
'
eeee
'
])
];
history
.
put
(
"
doc
"
,
{})
jio
.
put
(
"
doc
"
,
{})
// 0
.
push
(
function
()
{
return
putFullDoc
(
history
,
"
doc
"
,
docs
[
0
],
"
data
"
,
blobs
[
0
]);
return
putFullDoc
(
jio
,
"
doc
"
,
docs
[
0
],
"
data
"
,
blobs
[
0
]);
// 1,2
})
.
push
(
function
()
{
return
putFullDoc
(
history
,
"
second_doc
"
,
docs
[
1
],
"
data
"
,
blobs
[
1
]);
return
putFullDoc
(
jio
,
"
second_doc
"
,
docs
[
1
],
"
data
"
,
blobs
[
1
]);
// 3,4
})
.
push
(
function
()
{
return
putFullDoc
(
history
,
"
third_doc
"
,
docs
[
2
],
"
data
"
,
blobs
[
2
]);
return
putFullDoc
(
jio
,
"
third_doc
"
,
docs
[
2
],
"
data
"
,
blobs
[
2
]);
// 5,6
})
.
push
(
function
()
{
return
history
.
allDocs
({
query
:
"
(date: <= 2)
"
,
return
not_history
.
allDocs
({
sort_on
:
[[
"
timestamp
"
,
"
ascending
"
]]
});
})
.
push
(
function
(
results
)
{
timestamps
=
results
.
data
.
rows
.
map
(
function
(
d
)
{
return
d
.
id
;
});
})
.
push
(
function
()
{
return
jio
.
allDocs
({
query
:
"
NOT (date: > 2)
"
,
select_list
:
[
"
date
"
,
"
non-existent-key
"
],
sort_on
:
[[
"
date
"
,
"
ascending
"
],
[
"
non-existent-key
"
,
"
ascending
"
]
...
...
@@ -1054,17 +1313,20 @@
{
doc
:
{},
id
:
"
doc
"
,
value
:
{
date
:
1
}
value
:
{
date
:
1
},
timestamp
:
timestamps
[
1
]
},
{
doc
:
{},
id
:
"
third_doc
"
,
value
:
{
date
:
2
}
value
:
{
date
:
2
},
timestamp
:
timestamps
[
5
]
},
{
doc
:
{},
id
:
"
second_doc
"
,
value
:
{
date
:
2
}
value
:
{
date
:
2
},
timestamp
:
timestamps
[
3
]
}
],
"
Query gives correct results in correct order
"
);
...
...
@@ -1086,7 +1348,7 @@
expect
(
3
);
var
jio
=
this
.
jio
,
not_history
=
this
.
not_history
,
timestamps
=
this
.
jio
.
__storage
.
_timestamps
,
timestamps
,
docs
=
[
{
"
date
"
:
1
,
...
...
@@ -1106,11 +1368,11 @@
new
Blob
([
'
bcd2
'
]),
new
Blob
([
'
a3
'
])
];
jio
.
put
(
"
doc
"
,
{})
.
push
(
function
()
{
jio
.
put
(
"
doc
"
,
{})
// 0
.
push
(
function
()
{
// 1,2
return
putFullDoc
(
jio
,
"
doc
"
,
docs
[
0
],
"
data
"
,
blobs
[
0
]);
})
.
push
(
function
()
{
.
push
(
function
()
{
// 3,4
return
putFullDoc
(
jio
,
"
second_doc
"
,
docs
[
1
],
"
data
"
,
blobs
[
1
]);
})
.
push
(
function
()
{
...
...
@@ -1119,15 +1381,25 @@
docs
[
1
].
date
=
4
;
docs
[
1
].
type
=
"
bar2
"
;
})
.
push
(
function
()
{
.
push
(
function
()
{
// 5,6
return
putFullDoc
(
jio
,
"
doc
"
,
docs
[
0
],
"
data
"
,
blobs
[
2
]);
})
.
push
(
function
()
{
.
push
(
function
()
{
// 7
return
jio
.
remove
(
"
second_doc
"
);
})
.
push
(
function
()
{
.
push
(
function
()
{
// 8,9
return
putFullDoc
(
jio
,
"
second_doc
"
,
docs
[
1
],
"
data
"
,
blobs
[
3
]);
})
.
push
(
function
()
{
return
not_history
.
allDocs
({
sort_on
:
[[
"
timestamp
"
,
"
ascending
"
]]
});
})
.
push
(
function
(
results
)
{
timestamps
=
results
.
data
.
rows
.
map
(
function
(
d
)
{
return
d
.
id
;
});
})
.
push
(
function
()
{
return
not_history
.
allDocs
({
sort_on
:
[[
"
timestamp
"
,
"
descending
"
]],
...
...
@@ -1138,92 +1410,92 @@
deepEqual
(
results
.
data
.
rows
,
[
{
doc
:
{},
id
:
timestamps
.
second_doc
.
data
[
1
],
id
:
timestamps
[
9
],
value
:
{
"
op
"
:
"
putAttachment
"
,
"
doc_id
"
:
"
second_doc
"
,
"
timestamp
"
:
timestamps
.
second_doc
.
data
[
1
]
"
timestamp
"
:
timestamps
[
9
]
}
},
{
doc
:
{},
id
:
timestamps
.
second_doc
[
2
],
id
:
timestamps
[
8
],
value
:
{
"
op
"
:
"
put
"
,
"
doc_id
"
:
"
second_doc
"
,
"
timestamp
"
:
timestamps
.
second_doc
[
2
]
"
timestamp
"
:
timestamps
[
8
]
}
},
{
doc
:
{},
id
:
timestamps
.
second_doc
[
1
],
id
:
timestamps
[
7
],
value
:
{
"
op
"
:
"
remove
"
,
"
doc_id
"
:
"
second_doc
"
,
"
timestamp
"
:
timestamps
.
second_doc
[
1
]
"
timestamp
"
:
timestamps
[
7
]
}
},
{
doc
:
{},
id
:
timestamps
.
doc
.
data
[
1
],
id
:
timestamps
[
6
],
value
:
{
"
op
"
:
"
putAttachment
"
,
"
doc_id
"
:
"
doc
"
,
"
timestamp
"
:
timestamps
.
doc
.
data
[
1
]
"
timestamp
"
:
timestamps
[
6
]
}
},
{
doc
:
{},
id
:
timestamps
.
doc
[
2
],
id
:
timestamps
[
5
],
value
:
{
"
op
"
:
"
put
"
,
"
doc_id
"
:
"
doc
"
,
"
timestamp
"
:
timestamps
.
doc
[
2
]
"
timestamp
"
:
timestamps
[
5
]
}
},
{
doc
:
{},
id
:
timestamps
.
second_doc
.
data
[
0
],
id
:
timestamps
[
4
],
value
:
{
"
op
"
:
"
putAttachment
"
,
"
doc_id
"
:
"
second_doc
"
,
"
timestamp
"
:
timestamps
.
second_doc
.
data
[
0
]
"
timestamp
"
:
timestamps
[
4
]
}
},
{
doc
:
{},
id
:
timestamps
.
second_doc
[
0
],
id
:
timestamps
[
3
],
value
:
{
"
op
"
:
"
put
"
,
"
doc_id
"
:
"
second_doc
"
,
"
timestamp
"
:
timestamps
.
second_doc
[
0
]
"
timestamp
"
:
timestamps
[
3
]
}
},
{
doc
:
{},
id
:
timestamps
.
doc
.
data
[
0
],
id
:
timestamps
[
2
],
value
:
{
"
op
"
:
"
putAttachment
"
,
"
doc_id
"
:
"
doc
"
,
"
timestamp
"
:
timestamps
.
doc
.
data
[
0
]
"
timestamp
"
:
timestamps
[
2
]
}
},
{
doc
:
{},
id
:
timestamps
.
doc
[
1
],
id
:
timestamps
[
1
],
value
:
{
"
op
"
:
"
put
"
,
"
doc_id
"
:
"
doc
"
,
"
timestamp
"
:
timestamps
.
doc
[
1
]
"
timestamp
"
:
timestamps
[
1
]
}
},
{
doc
:
{},
id
:
timestamps
.
doc
[
0
],
id
:
timestamps
[
0
],
value
:
{
"
op
"
:
"
put
"
,
"
doc_id
"
:
"
doc
"
,
"
timestamp
"
:
timestamps
.
doc
[
0
]
"
timestamp
"
:
timestamps
[
0
]
}
}
],
"
All operations are logged correctly
"
);
...
...
@@ -1269,14 +1541,13 @@
})
.
push
(
function
()
{
return
jio
.
allDocs
({
query
:
"
(_timestamp: >=
"
+
timestamps
.
second_doc
[
0
]
+
"
OR _timestamp: <=
"
+
timestamps
.
doc
[
1
]
+
"
) AND NOT (date: = 2)
"
,
query
:
"
NOT (date: >= 2 AND date: <= 3)
"
,
select_list
:
[
"
date
"
,
"
non-existent-key
"
,
"
type
"
,
"
title
"
],
sort_on
:
[[
"
date
"
,
"
descending
"
],
[
"
non-existent-key
"
,
"
ascending
"
],
[
"
_timestamp
"
,
"
ascending
"
]
]
],
include_revisions
:
true
});
})
.
push
(
function
(
results
)
{
...
...
@@ -1288,7 +1559,8 @@
date
:
4
,
title
:
"
doc
"
,
type
:
"
foo2
"
}
},
timestamp
:
timestamps
[
5
]
},
{
doc
:
{},
...
...
@@ -1297,7 +1569,8 @@
date
:
4
,
title
:
"
second_doc
"
,
type
:
"
bar2
"
}
},
timestamp
:
timestamps
[
8
]
},
{
doc
:
{},
...
...
@@ -1306,12 +1579,14 @@
date
:
1
,
title
:
"
doc
"
,
type
:
"
foo
"
}
},
timestamp
:
timestamps
[
1
]
},
{
doc
:
{},
id
:
"
doc
"
,
value
:
{}
value
:
{},
timestamp
:
timestamps
[
0
]
}
],
"
Query gives correct results in correct order
"
);
...
...
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