use remdb::memory::allocator::init_global_allocator;
use remdb::{
config::{DbConfig, WALConfig},
time_series::TimeSeriesConfig,
DdlExecutor, RemDb,
};
#[derive(Debug, Clone, remdb::MemdbTable)]
#[memdb_schema(ddl = "
CREATE TIMESERIES TABLE sensor_readings (
time TIMESTAMP,
value FLOAT64,
sensor_id VARCHAR(32),
location VARCHAR(64),
unit VARCHAR(16)
);")]
struct SensorReading {
time: u64,
value: f64,
sensor_id: String,
location: String,
unit: String,
}
static mut DEFAULT_ALLOCATOR: remdb::config::DefaultMemoryAllocator =
remdb::config::DefaultMemoryAllocator;
static mut DB_CONFIG: Option<DbConfig> = None;
fn main() {
let mut memory = vec![0u8; 1024 * 1024 * 32];
init_global_allocator(memory.as_mut_ptr(), memory.len()).unwrap();
let config = DbConfig {
tables: vec![],
total_memory: memory.len(),
low_power_mode_supported: false,
low_power_max_records: None,
default_max_records: 10000,
memory_allocator: unsafe { &DEFAULT_ALLOCATOR },
wal_config: WALConfig {
log_path: "./wal",
log_mode: remdb::config::LogMode::Sync,
checkpoint_interval_ms: 60000,
log_file_size_limit: 16 * 1024 * 1024,
log_prealloc_size: 1 * 1024 * 1024,
log_segment_size: 16 * 1024 * 1024,
retained_checkpoints: 3,
max_consecutive_invalid: 100,
skip_threshold: 1000,
skip_block_size: 1024 * 1024,
max_skip_attempts: 3,
compression_type: remdb::config::WALCompressionType::None,
compression_level: 3,
},
time_series_defaults: TimeSeriesConfig::DEFAULT,
#[cfg(feature = "pubsub")]
pubsub_config: None,
#[cfg(feature = "ha")]
ha_config: Some(remdb::config::HAConfig {
node_id: 1,
ha_role: remdb::ha::HARole::Auto,
replication_mode: remdb::ha::ReplicationMode::Async,
heartbeat_interval_ms: 1000,
failure_detection_ms: 3000,
sync_timeout_ms: 2000,
master_address: None,
master_port: None,
replication_port: 5556,
}),
model_worker_config: Default::default(),
};
unsafe {
DB_CONFIG = Some(config);
}
let mut db = unsafe { RemDb::new(DB_CONFIG.as_ref().unwrap()) };
db.init().unwrap();
println!("=== RemDB 时序表 DDL 使用示例 ===");
println!("\n1. 使用DdlExecutor trait创建时序表:");
let result = db.create_time_series_table(
"temperature_data",
"time",
"value",
&["sensor_id", "room"],
None,
);
match result {
Ok(_) => println!("✓ 成功创建时序表 'temperature_data'"),
Err(e) => println!("✗ 创建失败: {:?}", e),
}
println!("\n2. 使用SQL CREATE TIMESERIES TABLE语句:");
let sql = "CREATE TIMESERIES TABLE humidity_data (\n time TIMESTAMP,\n value FLOAT64,\n sensor_id VARCHAR(32),\n floor INT32,\n building VARCHAR(64)\n);";
match db.sql_query(sql) {
Ok(_) => println!("✓ 成功创建时序表 'humidity_data'"),
Err(e) => println!("✗ SQL执行失败: {:?}", e),
}
println!("\n3. 使用derive(MemdbTable)宏:");
println!("✓ SensorReading结构体已通过宏定义为时序表");
println!(" - 表名: sensor_readings");
println!(" - 时间字段: time");
println!(" - 值字段: value");
println!(" - 标签字段: sensor_id, location, unit");
println!("\n4. 插入和查询时序数据:");
let insert_sql = "INSERT INTO humidity_data (time, value, sensor_id, floor, building) VALUES \
(1609459200000, 45.5, 'hum_sensor_001', 1, 'Building A'), \
(1609459260000, 46.2, 'hum_sensor_001', 1, 'Building A'), \
(1609459320000, 45.8, 'hum_sensor_001', 1, 'Building A');";
match db.sql_query(insert_sql) {
Ok(_) => println!("✓ 成功插入3条时序数据"),
Err(e) => println!("✗ 插入失败: {:?}", e),
}
let select_sql = "SELECT time, value, sensor_id FROM humidity_data WHERE floor = 1 ORDER BY time DESC LIMIT 2;";
match db.sql_query(select_sql) {
Ok(result_set) => {
println!("✓ 成功查询时序数据,返回 {} 行", result_set.rows.len());
for (i, row) in result_set.rows.iter().enumerate() {
println!(" 行 {}: {:?}", i + 1, row.values);
}
}
Err(e) => println!("✗ 查询失败: {:?}", e),
}
println!("\n=== 使用示例完成 ===");
println!("\n支持的时序表DDL语法:");
println!(" CREATE TIMESERIES TABLE table_name (");
println!(" time TIMESTAMP,");
println!(" value FLOAT64,");
println!(" tag1 VARCHAR(32),");
println!(" tag2 INT32");
println!(" );");
println!("\n时序表特点:");
println!(" - 必须包含时间字段(通常命名为time或timestamp)");
println!(" - 必须包含值字段(通常命名为value)");
println!(" - 可以包含多个标签字段");
println!(" - 自动优化时序数据存储和查询");
println!(" - 支持高效的时间范围查询");
}