Skip to content

Commit 26e13f6

Browse files
committed
RDBC-698 TimeSeriesIncludesTest::queryWithIncludeTimeSeries, TimeSeriesIncludesTest::includeTimeSeriesAndMergeWithExistingRangesInCache
1 parent 2cf7452 commit 26e13f6

File tree

2 files changed

+304
-0
lines changed

2 files changed

+304
-0
lines changed

ravendb/documents/session/document_session.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1760,6 +1760,10 @@ def append_single(self, timestamp: datetime, value: float, tag: Optional[str] =
17601760
self.append(timestamp, [value], tag)
17611761

17621762
def append(self, timestamp: datetime, values: List[float], tag: Optional[str] = None) -> None:
1763+
if not isinstance(values, List):
1764+
raise TypeError(
1765+
f"The 'values' arg must be a list. If you want to append single float use 'append_single(..)' instead."
1766+
)
17631767
document_info = self.session.documents_by_id.get_value(self.doc_id)
17641768
if document_info is not None and document_info.entity in self.session.deleted_entities:
17651769
self._throw_document_already_deleted_in_session(self.doc_id, self.name)

ravendb/tests/jvm_migrated_tests/client_tests/time_series_tests/test_time_series_includes.py

Lines changed: 300 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
from datetime import datetime, timedelta
22

3+
from ravendb.documents.session.time_series import TimeSeriesRangeType
34
from ravendb.infrastructure.orders import Company, Order
5+
from ravendb.primitives.time_series import TimeValue
46
from ravendb.tests.test_base import TestBase, User
57

68

@@ -273,3 +275,301 @@ def test_include_multiple_time_series(self):
273275

274276
self.assertEqual(base_line + timedelta(minutes=15), vals[0].timestamp)
275277
self.assertEqual(base_line + timedelta(minutes=25), vals[60].timestamp)
278+
279+
def test_include_time_series_and_merge_with_existing_ranges_in_cache(self):
280+
document_id = "users/gracjan"
281+
base_line = datetime(2023, 8, 20, 21, 30)
282+
ts_name = "Heartrate"
283+
284+
with self.store.open_session() as session:
285+
session.store(User(name="Gracjan"), document_id)
286+
session.save_changes()
287+
288+
with self.store.open_session() as session:
289+
tsf = session.time_series_for(document_id, ts_name)
290+
for i in range(360):
291+
tsf.append_single(base_line + timedelta(seconds=10 * i), 6, "watches/fitbit")
292+
293+
session.save_changes()
294+
295+
with self.store.open_session() as session:
296+
vals = session.time_series_for(document_id, ts_name).get(
297+
base_line + timedelta(minutes=2), base_line + timedelta(minutes=10)
298+
)
299+
self.assertEqual(1, session.advanced.number_of_requests)
300+
self.assertEqual(49, len(vals))
301+
self.assertEqual(base_line + timedelta(minutes=2), vals[0].timestamp)
302+
self.assertEqual(base_line + timedelta(minutes=10), vals[48].timestamp)
303+
304+
user = session.load(
305+
document_id,
306+
User,
307+
lambda i: i.include_time_series(
308+
ts_name, base_line + timedelta(minutes=40), base_line + timedelta(minutes=50)
309+
),
310+
)
311+
self.assertEqual(2, session.advanced.number_of_requests)
312+
313+
# should not go to server
314+
vals = session.time_series_for(document_id, ts_name).get(
315+
base_line + timedelta(minutes=40), base_line + timedelta(minutes=50)
316+
)
317+
self.assertEqual(2, session.advanced.number_of_requests)
318+
319+
self.assertEqual(61, len(vals))
320+
321+
self.assertEqual(base_line + timedelta(minutes=40), vals[0].timestamp)
322+
self.assertEqual(base_line + timedelta(minutes=50), vals[60].timestamp)
323+
324+
cache = session.time_series_by_doc_id.get(document_id)
325+
self.assertIsNotNone(cache)
326+
ranges = cache.get(ts_name)
327+
self.assertEqual(2, len(ranges))
328+
329+
self.assertEqual(base_line + timedelta(minutes=2), ranges[0].from_date)
330+
self.assertEqual(base_line + timedelta(minutes=10), ranges[0].to_date)
331+
self.assertEqual(base_line + timedelta(minutes=40), ranges[1].from_date)
332+
self.assertEqual(base_line + timedelta(minutes=50), ranges[1].to_date)
333+
334+
# we intentionally evict just the document (without it's TS data),
335+
# so that Load request will go to server
336+
337+
session.documents_by_entity.evict(user)
338+
session.documents_by_id.remove(document_id)
339+
340+
# should go to server to get [0, 2] and merge it into existing [2, 10]
341+
user = session.load(
342+
document_id, User, lambda i: i.include_time_series(ts_name, base_line, base_line + timedelta(minutes=2))
343+
)
344+
345+
self.assertEqual(3, session.advanced.number_of_requests)
346+
347+
# should not go to server
348+
349+
vals = session.time_series_for(document_id, ts_name).get(base_line, base_line + timedelta(minutes=2))
350+
351+
self.assertEqual(3, session.advanced.number_of_requests)
352+
353+
self.assertEqual(13, len(vals))
354+
self.assertEqual(base_line, vals[0].timestamp)
355+
self.assertEqual(base_line + timedelta(minutes=2), vals[12].timestamp)
356+
357+
self.assertEqual(2, len(ranges))
358+
self.assertEqual(base_line + timedelta(minutes=0), ranges[0].from_date)
359+
self.assertEqual(base_line + timedelta(minutes=10), ranges[0].to_date)
360+
self.assertEqual(base_line + timedelta(minutes=40), ranges[1].from_date)
361+
self.assertEqual(base_line + timedelta(minutes=50), ranges[1].to_date)
362+
363+
# evict just the document
364+
session.documents_by_entity.evict(user)
365+
session.documents_by_id.remove(document_id)
366+
367+
# should go to server to get [10, 16] and merge it into existing [0, 10]
368+
user = session.load(
369+
document_id,
370+
User,
371+
lambda i: i.include_time_series(
372+
ts_name, base_line + timedelta(minutes=10), base_line + timedelta(minutes=16)
373+
),
374+
)
375+
376+
self.assertEqual(4, session.advanced.number_of_requests)
377+
378+
# should not go to server
379+
vals = session.time_series_for(document_id, ts_name).get(
380+
base_line + timedelta(minutes=10), base_line + timedelta(minutes=16)
381+
)
382+
self.assertEqual(4, session.advanced.number_of_requests)
383+
384+
self.assertEqual(37, len(vals))
385+
self.assertEqual(base_line + timedelta(minutes=10), vals[0].timestamp)
386+
self.assertEqual(base_line + timedelta(minutes=16), vals[36].timestamp)
387+
388+
self.assertEqual(2, len(ranges))
389+
390+
self.assertEqual(base_line, ranges[0].from_date)
391+
self.assertEqual(base_line + timedelta(minutes=16), ranges[0].to_date)
392+
self.assertEqual(base_line + timedelta(minutes=40), ranges[1].from_date)
393+
self.assertEqual(base_line + timedelta(minutes=50), ranges[1].to_date)
394+
395+
# evict just the document
396+
session.documents_by_entity.evict(user)
397+
session.documents_by_id.remove(document_id)
398+
399+
# should go to server to get range [17, 19]
400+
# and add it to cache in between [10, 16] and [40, 50]
401+
402+
user = session.load(
403+
document_id,
404+
User,
405+
lambda i: i.include_time_series(
406+
ts_name, base_line + timedelta(minutes=17), base_line + timedelta(minutes=19)
407+
),
408+
)
409+
410+
self.assertEqual(5, session.advanced.number_of_requests)
411+
412+
# should not go to server
413+
414+
vals = session.time_series_for(document_id, ts_name).get(
415+
base_line + timedelta(minutes=17), base_line + timedelta(minutes=19)
416+
)
417+
418+
self.assertEqual(5, session.advanced.number_of_requests)
419+
420+
self.assertEqual(13, len(vals))
421+
self.assertEqual(base_line + timedelta(minutes=17), vals[0].timestamp)
422+
self.assertEqual(base_line + timedelta(minutes=19), vals[12].timestamp)
423+
424+
self.assertEqual(3, len(ranges))
425+
self.assertEqual(base_line, ranges[0].from_date)
426+
self.assertEqual(base_line + timedelta(minutes=16), ranges[0].to_date)
427+
self.assertEqual(base_line + timedelta(minutes=17), ranges[1].from_date)
428+
self.assertEqual(base_line + timedelta(minutes=19), ranges[1].to_date)
429+
self.assertEqual(base_line + timedelta(minutes=40), ranges[2].from_date)
430+
self.assertEqual(base_line + timedelta(minutes=50), ranges[2].to_date)
431+
432+
# evict just the document
433+
session.documents_by_entity.evict(user)
434+
session.documents_by_id.remove(document_id)
435+
436+
# should go to server to get range [19, 40]
437+
# and merge the result with existing ranges [17, 19] and [40, 50]
438+
# into single range [17, 50]
439+
440+
user = session.load(
441+
document_id,
442+
User,
443+
lambda i: i.include_time_series(
444+
ts_name, base_line + timedelta(minutes=18), base_line + timedelta(minutes=48)
445+
),
446+
)
447+
448+
self.assertEqual(6, session.advanced.number_of_requests)
449+
450+
# should not go to server
451+
452+
vals = session.time_series_for(document_id, ts_name).get(
453+
base_line + timedelta(minutes=18), base_line + timedelta(minutes=48)
454+
)
455+
456+
self.assertEqual(6, session.advanced.number_of_requests)
457+
458+
self.assertEqual(181, len(vals))
459+
self.assertEqual(base_line + timedelta(minutes=18), vals[0].timestamp)
460+
self.assertEqual(base_line + timedelta(minutes=48), vals[180].timestamp)
461+
462+
self.assertEqual(2, len(ranges))
463+
self.assertEqual(base_line, ranges[0].from_date)
464+
self.assertEqual(base_line + timedelta(minutes=16), ranges[0].to_date)
465+
self.assertEqual(base_line + timedelta(minutes=17), ranges[1].from_date)
466+
self.assertEqual(base_line + timedelta(minutes=50), ranges[1].to_date)
467+
468+
# evict just the document
469+
session.documents_by_entity.evict(user)
470+
session.documents_by_id.remove(document_id)
471+
472+
# should go to server to get range [12, 22]
473+
# and merge the result with existing ranges [0, 16] and [17, 50]
474+
# into single range [0, 50]
475+
476+
user = session.load(
477+
document_id,
478+
User,
479+
lambda i: i.include_time_series(
480+
ts_name, base_line + timedelta(minutes=12), base_line + timedelta(minutes=22)
481+
),
482+
)
483+
484+
self.assertEqual(7, session.advanced.number_of_requests)
485+
486+
# should not go to server
487+
488+
vals = session.time_series_for(document_id, ts_name).get(
489+
base_line + timedelta(minutes=12), base_line + timedelta(minutes=22)
490+
)
491+
492+
self.assertEqual(7, session.advanced.number_of_requests)
493+
494+
self.assertEqual(61, len(vals))
495+
self.assertEqual(base_line + timedelta(minutes=12), vals[0].timestamp)
496+
self.assertEqual(base_line + timedelta(minutes=22), vals[60].timestamp)
497+
498+
self.assertEqual(1, len(ranges))
499+
self.assertEqual(base_line, ranges[0].from_date)
500+
self.assertEqual(base_line + timedelta(minutes=50), ranges[0].to_date)
501+
502+
# evict just the document
503+
session.documents_by_entity.evict(user)
504+
session.documents_by_id.remove(document_id)
505+
506+
# should go to server to get range [50, ∞]
507+
# and merge the result with existing range [0, 50] into single range [0, ∞]
508+
509+
user = session.load(
510+
document_id,
511+
User,
512+
lambda i: i.include_time_series_time_value(ts_name, TimeSeriesRangeType.LAST, TimeValue.of_minutes(10)),
513+
)
514+
515+
self.assertEqual(8, session.advanced.number_of_requests)
516+
517+
# should not go to server
518+
519+
vals = session.time_series_for(document_id, ts_name).get(base_line + timedelta(minutes=50), None)
520+
521+
self.assertEqual(8, session.advanced.number_of_requests)
522+
523+
# should not go to server
524+
525+
vals = session.time_series_for(document_id, ts_name).get(base_line + timedelta(minutes=50), None)
526+
527+
self.assertEqual(8, session.advanced.number_of_requests)
528+
529+
self.assertEqual(60, len(vals))
530+
531+
self.assertEqual(base_line + timedelta(minutes=50), vals[0].timestamp)
532+
self.assertEqual(base_line + timedelta(minutes=59, seconds=50), vals[59].timestamp)
533+
534+
self.assertEqual(1, len(ranges))
535+
self.assertEqual(base_line, ranges[0].from_date)
536+
self.assertEqual(None, ranges[0].to_date)
537+
538+
def test_query_with_include_time_series(self):
539+
document_id = "users/gracjan"
540+
base_line = datetime(2023, 8, 20, 21, 30)
541+
ts_name = "Heartrate"
542+
tag = "watches/fitbit"
543+
544+
with self.store.open_session() as session:
545+
session.store(User(name="Gracjan"), document_id)
546+
session.save_changes()
547+
548+
with self.store.open_session() as session:
549+
tsf = session.time_series_for(document_id, ts_name)
550+
551+
for i in range(360):
552+
tsf.append_single(base_line + timedelta(seconds=i * 10), 67, tag)
553+
554+
session.save_changes()
555+
556+
with self.store.open_session() as session:
557+
query = session.query(object_type=User).include(lambda i: i.include_time_series(ts_name))
558+
559+
result = list(query)
560+
561+
self.assertEqual(1, session.advanced.number_of_requests)
562+
563+
self.assertEqual("Gracjan", result[0].name)
564+
565+
# should not go to server
566+
567+
vals = session.time_series_for(document_id, ts_name).get(base_line, base_line + timedelta(minutes=30))
568+
569+
self.assertEqual(1, session.advanced.number_of_requests)
570+
571+
self.assertEqual(181, len(vals))
572+
self.assertEqual(base_line, vals[0].timestamp)
573+
self.assertEqual(tag, vals[0].tag)
574+
self.assertEqual(67, vals[0].values[0])
575+
self.assertEqual(base_line + timedelta(minutes=30), vals[180].timestamp)

0 commit comments

Comments
 (0)