Skip to main content

thingd_core/
lib.rs

1//! Core primitives for thingd.
2//!
3//! This crate owns the durable engine boundary: object storage, append-only
4//! events, and queue storage. The default implementation is in-memory, with a
5//! feature-gated `SQLite` adapter available for durable object, event, and
6//! queue storage.
7//!
8//! # Example
9//!
10//! ```rust
11//! use thingd_core::{MemoryEngine, ObjectStore, EventLog, MemoryObject, MemoryEvent};
12//!
13//! let mut engine = MemoryEngine::new();
14//!
15//! // Store an object
16//! let obj = MemoryObject::new("users", "alice", r#"{"name":"Alice"}"#);
17//! engine.put_object(obj).unwrap();
18//!
19//! // Retrieve it
20//! let user = engine.get_object("users", "alice").unwrap();
21//! assert_eq!(user.unwrap().body, r#"{"name":"Alice"}"#);
22//!
23//! // Append an event
24//! let event = MemoryEvent::new("audit", "user.created", r#"{"user":"alice"}"#);
25//! engine.append_event(event).unwrap();
26//! ```
27
28#![forbid(unsafe_code)]
29#![warn(missing_docs)]
30
31use std::time::{SystemTime, UNIX_EPOCH};
32
33#[cfg(feature = "connectors")]
34pub mod connector;
35mod error;
36mod in_memory;
37mod model;
38#[cfg(feature = "sqlite")]
39mod sqlite;
40mod store;
41
42#[cfg(feature = "connectors")]
43pub use connector::{
44    Column, ColumnType, Connector, ConnectorConfig, FileConnector, Schema, SyncStrategy,
45};
46pub use error::{ThingdError, ThingdResult};
47pub use in_memory::MemoryEngine;
48pub use model::{
49    DEFAULT_QUEUE_LEASE_MS, Link, LinkDirection, LinkQueryOptions, ListEventsOptions, MemoryEvent,
50    MemoryObject, ObjectKey, QueueClaimOptions, QueueJob, QueueJobStatus, QueueNackOptions,
51    SearchHit, SearchOptions,
52};
53#[cfg(feature = "sqlite")]
54pub use sqlite::{SQLITE_SCHEMA_VERSION, SqliteThingStore};
55pub use store::{EventLog, LinkStore, ObjectStore, QueueStore, Searcher, ThingStore};
56
57pub(crate) fn unix_timestamp_millis() -> i64 {
58    let Ok(duration) = SystemTime::now().duration_since(UNIX_EPOCH) else {
59        return 0;
60    };
61
62    i64::try_from(duration.as_millis()).unwrap_or(i64::MAX)
63}
64
65pub(crate) fn u64_to_i64(value: u64) -> i64 {
66    i64::try_from(value).unwrap_or(i64::MAX)
67}
68
69pub(crate) fn now_iso_string() -> String {
70    chrono::Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Millis, true)
71}