diff --git a/rslib/src/lib.rs b/rslib/src/lib.rs index da4d91107..87253f998 100644 --- a/rslib/src/lib.rs +++ b/rslib/src/lib.rs @@ -28,5 +28,5 @@ pub mod storage; pub mod template; pub mod template_filters; pub mod text; -pub mod time; +pub mod timestamp; pub mod types; diff --git a/rslib/src/notes.rs b/rslib/src/notes.rs index cad1f614c..7b70659bc 100644 --- a/rslib/src/notes.rs +++ b/rslib/src/notes.rs @@ -5,10 +5,10 @@ /// the media DB check. use crate::err::{AnkiError, DBErrorKind, Result}; use crate::text::strip_html_preserving_image_filenames; -use crate::time::i64_unix_secs; +use crate::timestamp::TimestampSecs; use crate::{ notetypes::NoteType, - types::{ObjID, Timestamp, Usn}, + types::{ObjID, Usn}, }; use rusqlite::{params, Connection, Row, NO_PARAMS}; use std::convert::TryInto; @@ -17,7 +17,7 @@ use std::convert::TryInto; pub(super) struct Note { pub id: ObjID, pub mid: ObjID, - pub mtime_secs: Timestamp, + pub mtime: TimestampSecs, pub usn: Usn, fields: Vec, } @@ -73,7 +73,7 @@ fn row_to_note(row: &Row) -> Result { Ok(Note { id: row.get(0)?, mid: row.get(1)?, - mtime_secs: row.get(2)?, + mtime: row.get(2)?, usn: row.get(3)?, fields: row .get_raw(4) @@ -85,7 +85,7 @@ fn row_to_note(row: &Row) -> Result { } pub(super) fn set_note(db: &Connection, note: &mut Note, note_type: &NoteType) -> Result<()> { - note.mtime_secs = i64_unix_secs(); + note.mtime = TimestampSecs::now(); // hard-coded for now note.usn = -1; let field1_nohtml = strip_html_preserving_image_filenames(¬e.fields()[0]); @@ -106,7 +106,7 @@ pub(super) fn set_note(db: &Connection, note: &mut Note, note_type: &NoteType) - let mut stmt = db.prepare_cached("update notes set mod=?,usn=?,flds=?,sfld=?,csum=? where id=?")?; stmt.execute(params![ - note.mtime_secs, + note.mtime, note.usn, note.fields().join("\x1f"), sort_field, diff --git a/rslib/src/storage/mod.rs b/rslib/src/storage/mod.rs index 2ed04892c..a84013282 100644 --- a/rslib/src/storage/mod.rs +++ b/rslib/src/storage/mod.rs @@ -1,3 +1,4 @@ mod sqlite; +mod timestamp; pub(crate) use sqlite::{SqliteStorage, StorageContext}; diff --git a/rslib/src/storage/sqlite.rs b/rslib/src/storage/sqlite.rs index b56510717..083b55e00 100644 --- a/rslib/src/storage/sqlite.rs +++ b/rslib/src/storage/sqlite.rs @@ -5,7 +5,7 @@ use crate::collection::CollectionOp; use crate::config::Config; use crate::err::Result; use crate::err::{AnkiError, DBErrorKind}; -use crate::time::{i64_unix_millis, i64_unix_secs}; +use crate::timestamp::{TimestampMillis, TimestampSecs}; use crate::{ decks::Deck, notetypes::NoteType, @@ -168,7 +168,10 @@ impl SqliteStorage { if create { db.prepare_cached("begin exclusive")?.execute(NO_PARAMS)?; db.execute_batch(include_str!("schema11.sql"))?; - db.execute("update col set crt=?, ver=?", params![i64_unix_secs(), ver])?; + db.execute( + "update col set crt=?, ver=?", + params![TimestampSecs::now(), ver], + )?; db.prepare_cached("commit")?.execute(NO_PARAMS)?; } else { if ver > SCHEMA_MAX_VERSION { @@ -278,7 +281,7 @@ impl StorageContext<'_> { pub(crate) fn mark_modified(&self) -> Result<()> { self.db .prepare_cached("update col set mod=?")? - .execute(params![i64_unix_millis()])?; + .execute(params![TimestampMillis::now()])?; Ok(()) } @@ -339,7 +342,7 @@ impl StorageContext<'_> { self.timing_today = Some(sched_timing_today( crt, - i64_unix_secs(), + TimestampSecs::now().0, conf.creation_offset, now_offset, conf.rollover, diff --git a/rslib/src/storage/timestamp.rs b/rslib/src/storage/timestamp.rs new file mode 100644 index 000000000..74fc40965 --- /dev/null +++ b/rslib/src/storage/timestamp.rs @@ -0,0 +1,40 @@ +// Copyright: Ankitects Pty Ltd and contributors +// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html + +use crate::timestamp::{TimestampMillis, TimestampSecs}; +use rusqlite::{ + types::{FromSql, FromSqlError, ToSqlOutput, Value, ValueRef}, + ToSql, +}; + +impl FromSql for TimestampSecs { + fn column_result(value: ValueRef<'_>) -> std::result::Result { + if let ValueRef::Integer(i) = value { + Ok(TimestampSecs(i)) + } else { + Err(FromSqlError::InvalidType) + } + } +} + +impl ToSql for TimestampSecs { + fn to_sql(&self) -> rusqlite::Result> { + Ok(ToSqlOutput::Owned(Value::Integer(self.0))) + } +} + +impl FromSql for TimestampMillis { + fn column_result(value: ValueRef<'_>) -> std::result::Result { + if let ValueRef::Integer(i) = value { + Ok(TimestampMillis(i)) + } else { + Err(FromSqlError::InvalidType) + } + } +} + +impl ToSql for TimestampMillis { + fn to_sql(&self) -> rusqlite::Result> { + Ok(ToSqlOutput::Owned(Value::Integer(self.0))) + } +} diff --git a/rslib/src/time.rs b/rslib/src/timestamp.rs similarity index 68% rename from rslib/src/time.rs rename to rslib/src/timestamp.rs index e392cbb6e..35089b36f 100644 --- a/rslib/src/time.rs +++ b/rslib/src/timestamp.rs @@ -3,12 +3,24 @@ use std::time; -pub(crate) fn i64_unix_secs() -> i64 { - elapsed().as_secs() as i64 +#[repr(transparent)] +#[derive(Debug, Clone)] +pub struct TimestampSecs(pub i64); + +impl TimestampSecs { + pub fn now() -> Self { + Self(elapsed().as_secs() as i64) + } } -pub(crate) fn i64_unix_millis() -> i64 { - elapsed().as_millis() as i64 +#[repr(transparent)] +#[derive(Debug, Clone)] +pub struct TimestampMillis(pub i64); + +impl TimestampMillis { + pub fn now() -> Self { + Self(elapsed().as_millis() as i64) + } } #[cfg(not(test))] diff --git a/rslib/src/types.rs b/rslib/src/types.rs index 0ae6e2a83..51d66858c 100644 --- a/rslib/src/types.rs +++ b/rslib/src/types.rs @@ -6,4 +6,3 @@ pub type ObjID = i64; pub type Usn = i32; -pub type Timestamp = i64;