Skip to content

Improve & Test expiration #42

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions src/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ impl Database {
}
}

/// Returns the time, if any, at which a given document will expire and be purged.
/// Returns the time, if any, at which a given document will expire and be purged in milliseconds since the Unix epoch (1/1/1970.).
/// Documents don't normally expire; you have to call `set_document_expiration`
/// to set a document's expiration time.
#[deprecated(note = "please use `document_expiration` on default collection instead")]
Expand All @@ -250,7 +250,7 @@ impl Database {
);
match exp {
0 => Ok(None),
_ if exp > 0 => Ok(Some(Timestamp(exp))),
_ if exp > 0 => Ok(Some(Timestamp::new(exp))),
_ => failure(error),
}
}
Expand All @@ -260,7 +260,7 @@ impl Database {
#[deprecated(note = "please use `set_document_expiration` on default collection instead")]
pub fn set_document_expiration(&mut self, doc_id: &str, when: Option<Timestamp>) -> Result<()> {
let exp: i64 = match when {
Some(Timestamp(n)) => n,
Some(Timestamp { timestamp }) => timestamp,
_ => 0,
};
unsafe {
Expand Down Expand Up @@ -448,7 +448,7 @@ impl Collection {
}
}

/// Returns the time, if any, at which a given document will expire and be purged.
/// Returns the time, if any, at which a given document will expire and be purged in milliseconds since the Unix epoch (1/1/1970.).
/// Documents don't normally expire; you have to call set_document_expiration
/// to set a document's expiration time.
pub fn document_expiration(&self, doc_id: &str) -> Result<Option<Timestamp>> {
Expand All @@ -461,16 +461,16 @@ impl Collection {
);
match exp {
0 => Ok(None),
_ if exp > 0 => Ok(Some(Timestamp(exp))),
_ if exp > 0 => Ok(Some(Timestamp::new(exp))),
_ => failure(error),
}
}
}

/// Sets or clears the expiration time of a document.
/// Sets or clears the expiration time of a document in milliseconds since the Unix epoch (1/1/1970.).
pub fn set_document_expiration(&mut self, doc_id: &str, when: Option<Timestamp>) -> Result<()> {
let exp: i64 = match when {
Some(Timestamp(n)) => n,
Some(Timestamp { timestamp }) => timestamp,
_ => 0,
};
unsafe {
Expand Down
2 changes: 1 addition & 1 deletion src/fleece.rs
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ impl Value {
if t == 0 {
return None;
}
Some(Timestamp(t))
Some(Timestamp::new(t))
}
}

Expand Down
31 changes: 27 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,11 @@ mod c_api;

use self::c_api::{
CBLListenerToken, CBLRefCounted, CBL_DumpInstances, CBL_InstanceCount, CBL_Release, CBL_Retain,
CBLListener_Remove, CBLITE_VERSION,
CBLListener_Remove, CBL_Now, CBLITE_VERSION,
};
#[cfg(target_os = "android")]
use self::c_api::{CBLError, CBLInitContext, CBL_Init};
use std::ffi::CStr;
use std::{ffi::CStr, time::Duration};

//////// RE-EXPORT:

Expand All @@ -78,9 +78,32 @@ pub trait CblRef {
fn get_ref(&self) -> Self::Output;
}

#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, PartialEq)]
/// A time value for document expiration. Defined as milliseconds since the Unix epoch (1/1/1970.)
pub struct Timestamp(pub i64);
pub struct Timestamp {
pub(crate) timestamp: i64,
}

impl Timestamp {
pub fn now() -> Timestamp {
Timestamp {
timestamp: unsafe { CBL_Now() },
}
}

/// Create a Timestamp from milliseconds since the Unix epoch (1/1/1970.)
pub(crate) fn new(milliseconds_from_epoch: i64) -> Self {
Timestamp {
timestamp: milliseconds_from_epoch,
}
}

pub fn add(&self, duration: Duration) -> Self {
Timestamp {
timestamp: self.timestamp + duration.as_millis() as i64,
}
}
}

pub struct Listener<T> {
pub listener_token: ListenerToken,
Expand Down
34 changes: 29 additions & 5 deletions tests/document_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ extern crate core;
extern crate couchbase_lite;

use self::couchbase_lite::*;
use std::time::Duration;
use std::{thread::sleep, time::Duration};
use utils::{init_logging, LeakChecker};

pub mod utils;
Expand Down Expand Up @@ -296,12 +296,36 @@ fn database_document_expiration() {
let mut document = Document::new_with_id("foo");
db.save_document_with_concurency_control(&mut document, ConcurrencyControl::FailOnConflict)
.expect("save_document");

// No expiration by default
let expiration = db.document_expiration("foo").expect("document_expiration");
assert!(expiration.is_none());
db.set_document_expiration("foo", Some(Timestamp(1000000000)))

// Set expiration in 2 seconds
let expiration = Timestamp::now().add(Duration::from_secs(2));
db.set_document_expiration("foo", Some(expiration))
.expect("set_document_expiration");
let expiration = db.document_expiration("foo").expect("document_expiration");
assert!(expiration.is_some());
assert_eq!(expiration.unwrap().0, 1000000000);

// Check expiration is set up
let doc_expiration = db.document_expiration("foo").expect("document_expiration");
assert_eq!(doc_expiration.unwrap(), expiration);

// Check the document is still present after 1 second
sleep(Duration::from_secs(1));
assert!(db.get_document("foo").is_ok());

// Move to expiration time
sleep(Duration::from_secs(1));

// Check documents disappears
for _ in 0..5 {
let doc = db.get_document("foo");
if doc.is_err() || doc.unwrap().is_deleted() {
return;
}

sleep(Duration::from_secs(1));
}
panic!("The document is still present 10 seconds after its expiration time");
});
}