299 lines
10 KiB
Rust
299 lines
10 KiB
Rust
use heromodels::db::postgres::Config;
|
|
use heromodels::db::{Collection, Db};
|
|
use heromodels::models::userexample::user::user_index::{email, username};
|
|
use heromodels::models::{Comment, User};
|
|
use heromodels_core::Model;
|
|
// For demonstrating embedded/nested indexes
|
|
use heromodels::models::grid4::node::{ComputeSlice, DeviceInfo, Node};
|
|
use heromodels::models::grid4::node::node_index::{country as node_country, pubkey as node_pubkey};
|
|
|
|
// Helper function to print user details
|
|
fn print_user_details(user: &User) {
|
|
println!("\n--- User Details ---");
|
|
println!("ID: {}", user.get_id());
|
|
println!("Username: {}", user.username);
|
|
println!("Email: {}", user.email);
|
|
println!("Full Name: {}", user.full_name);
|
|
println!("Active: {}", user.is_active);
|
|
println!("Created At: {}", user.base_data.created_at);
|
|
println!("Modified At: {}", user.base_data.modified_at);
|
|
println!("Comments: {:?}", user.base_data.comments);
|
|
}
|
|
|
|
// Helper function to print comment details
|
|
fn print_comment_details(comment: &Comment) {
|
|
println!("\n--- Comment Details ---");
|
|
println!("ID: {}", comment.get_id());
|
|
println!("User ID: {}", comment.user_id);
|
|
println!("Content: {}", comment.content);
|
|
println!("Created At: {}", comment.base_data.created_at);
|
|
println!("Modified At: {}", comment.base_data.modified_at);
|
|
}
|
|
|
|
fn main() {
|
|
let db = heromodels::db::postgres::Postgres::new(
|
|
Config::new()
|
|
.user(Some("postgres".into()))
|
|
.password(Some("test123".into()))
|
|
.host(Some("localhost".into()))
|
|
.port(Some(5432)),
|
|
)
|
|
.expect("Can connect to postgress");
|
|
|
|
// Unique suffix to avoid collisions with legacy rows from prior runs
|
|
use std::time::{SystemTime, UNIX_EPOCH};
|
|
let ts = SystemTime::now()
|
|
.duration_since(UNIX_EPOCH)
|
|
.unwrap()
|
|
.as_secs();
|
|
let user1_name = format!("johndoe_{}", ts);
|
|
let user2_name = format!("janesmith_{}", ts);
|
|
let user3_name = format!("willism_{}", ts);
|
|
let user4_name = format!("carrols_{}", ts);
|
|
let user1_email = format!("john.doe+{}@example.com", ts);
|
|
let user2_email = format!("jane.smith+{}@example.com", ts);
|
|
let user3_email = format!("willis.masters+{}@example.com", ts);
|
|
let user4_email = format!("carrol.smith+{}@example.com", ts);
|
|
|
|
println!("Hero Models - Basic Usage Example");
|
|
println!("================================");
|
|
|
|
// Clean up any existing data to ensure consistent results
|
|
println!("Cleaning up existing data...");
|
|
let user_collection = db.collection::<User>().expect("can open user collection");
|
|
let comment_collection = db
|
|
.collection::<Comment>()
|
|
.expect("can open comment collection");
|
|
|
|
// Clear all existing users and comments
|
|
if let Ok(existing_users) = user_collection.get_all() {
|
|
for user in existing_users {
|
|
let _ = user_collection.delete_by_id(user.get_id());
|
|
}
|
|
}
|
|
if let Ok(existing_comments) = comment_collection.get_all() {
|
|
for comment in existing_comments {
|
|
let _ = comment_collection.delete_by_id(comment.get_id());
|
|
}
|
|
}
|
|
println!("Database cleaned.\n");
|
|
|
|
// Create users with auto-generated IDs
|
|
|
|
// User 1
|
|
let user1 = User::new()
|
|
.username(&user1_name)
|
|
.email(&user1_email)
|
|
.full_name("John Doe")
|
|
.is_active(false)
|
|
.build();
|
|
|
|
// User 2
|
|
let user2 = User::new()
|
|
.username(&user2_name)
|
|
.email(&user2_email)
|
|
.full_name("Jane Smith")
|
|
.is_active(true)
|
|
.build();
|
|
|
|
// User 3
|
|
let user3 = User::new()
|
|
.username(&user3_name)
|
|
.email(&user3_email)
|
|
.full_name("Willis Masters")
|
|
.is_active(true)
|
|
.build();
|
|
|
|
// User 4
|
|
let user4 = User::new()
|
|
.username(&user4_name)
|
|
.email(&user4_email)
|
|
.full_name("Carrol Smith")
|
|
.is_active(false)
|
|
.build();
|
|
|
|
// Save all users to database and get their assigned IDs and updated models
|
|
let (user1_id, db_user1) = db
|
|
.collection()
|
|
.expect("can open user collection")
|
|
.set(&user1)
|
|
.expect("can set user");
|
|
let (user2_id, db_user2) = db
|
|
.collection()
|
|
.expect("can open user collection")
|
|
.set(&user2)
|
|
.expect("can set user");
|
|
let (user3_id, db_user3) = db
|
|
.collection()
|
|
.expect("can open user collection")
|
|
.set(&user3)
|
|
.expect("can set user");
|
|
let (user4_id, db_user4) = db
|
|
.collection()
|
|
.expect("can open user collection")
|
|
.set(&user4)
|
|
.expect("can set user");
|
|
|
|
println!("User 1 assigned ID: {user1_id}");
|
|
println!("User 2 assigned ID: {user2_id}");
|
|
println!("User 3 assigned ID: {user3_id}");
|
|
println!("User 4 assigned ID: {user4_id}");
|
|
|
|
// We already have the updated models from the set method, so we don't need to retrieve them again
|
|
|
|
// Print all users retrieved from database
|
|
println!("\n--- Users Retrieved from Database ---");
|
|
println!("\n1. First user:");
|
|
print_user_details(&db_user1);
|
|
|
|
println!("\n2. Second user:");
|
|
print_user_details(&db_user2);
|
|
|
|
println!("\n3. Third user:");
|
|
print_user_details(&db_user3);
|
|
|
|
println!("\n4. Fourth user:");
|
|
print_user_details(&db_user4);
|
|
|
|
// Demonstrate different ways to retrieve users from the database
|
|
|
|
// 1. Retrieve by username index
|
|
println!("\n--- Retrieving Users by Different Methods ---");
|
|
println!("\n1. By Username Index:");
|
|
let stored_users = db
|
|
.collection::<User>()
|
|
.expect("can open user collection")
|
|
.get::<username, _>(&user1_name)
|
|
.expect("can load stored user");
|
|
|
|
assert_eq!(stored_users.len(), 1);
|
|
print_user_details(&stored_users[0]);
|
|
|
|
// 2. Retrieve by email index
|
|
println!("\n2. By Email Index:");
|
|
let by_email = db
|
|
.collection::<User>()
|
|
.expect("can open user collection")
|
|
.get::<email, _>(&user2_email)
|
|
.expect("can load stored user by email");
|
|
assert_eq!(by_email.len(), 1);
|
|
print_user_details(&by_email[0]);
|
|
|
|
// 3. Delete a user and show the updated results
|
|
println!("\n3. After Deleting a User:");
|
|
let user_to_delete_id = stored_users[0].get_id();
|
|
println!("Deleting user with ID: {user_to_delete_id}");
|
|
db.collection::<User>()
|
|
.expect("can open user collection")
|
|
.delete_by_id(user_to_delete_id)
|
|
.expect("can delete existing user");
|
|
|
|
// Verify deletion by querying the same username again
|
|
let should_be_empty = db
|
|
.collection::<User>()
|
|
.expect("can open user collection")
|
|
.get::<username, _>(&user1_name)
|
|
.expect("can query by username after delete");
|
|
println!(" a. Query by username '{}' after delete -> {} results", user1_name, should_be_empty.len());
|
|
assert_eq!(should_be_empty.len(), 0);
|
|
|
|
// Delete a user based on an index for good measure
|
|
db.collection::<User>()
|
|
.expect("can open user collection")
|
|
.delete::<username, _>(&user4_name)
|
|
.expect("can delete existing user");
|
|
|
|
// Demonstrate embedded/nested indexes with Grid4 Node
|
|
println!("\n--- Demonstrating Embedded/Nested Indexes (Grid4::Node) ---");
|
|
println!("Node indexed fields: {:?}", Node::indexed_fields());
|
|
|
|
// Build a minimal node with nested data and persist it
|
|
let cs = ComputeSlice::new()
|
|
.nodeid(42)
|
|
.slice_id(1)
|
|
.mem_gb(32.0)
|
|
.storage_gb(512.0)
|
|
.passmark(6000)
|
|
.vcores(16)
|
|
.gpus(1)
|
|
.price_cc(0.33);
|
|
let dev = DeviceInfo { vendor: "ACME".into(), ..Default::default() };
|
|
let node = Node::new()
|
|
.nodegroupid(101)
|
|
.uptime(99)
|
|
.add_compute_slice(cs)
|
|
.devices(dev)
|
|
.country("BE")
|
|
.pubkey("EX_NODE_PK_1")
|
|
.build();
|
|
let (node_id, _stored_node) = db
|
|
.collection::<Node>()
|
|
.expect("can open node collection")
|
|
.set(&node)
|
|
.expect("can set node");
|
|
println!("Stored node id: {}", node_id);
|
|
|
|
// Query by top-level indexes
|
|
let be_nodes = db
|
|
.collection::<Node>()
|
|
.expect("can open node collection")
|
|
.get::<node_country, _>("BE")
|
|
.expect("can query nodes by country");
|
|
println!("Nodes in BE (count may include legacy rows): {}", be_nodes.len());
|
|
|
|
let by_pk = db
|
|
.collection::<Node>()
|
|
.expect("can open node collection")
|
|
.get::<node_pubkey, _>("EX_NODE_PK_1")
|
|
.expect("can query node by pubkey");
|
|
assert!(by_pk.iter().any(|n| n.get_id() == node_id));
|
|
|
|
// Note: Nested path indexes (e.g., devices.vendor, computeslices.passmark) are created and used
|
|
// for DB-side indexing, but are not yet exposed as typed Index keys in the API. They appear in
|
|
// Node::indexed_fields() and contribute to Model::db_keys(), enabling performant JSONB GIN indexes.
|
|
|
|
println!("\n--- User Model Information ---");
|
|
println!("User DB Prefix: {}", User::db_prefix());
|
|
|
|
// Demonstrate comment creation and association with a user
|
|
println!("\n--- Working with Comments ---");
|
|
|
|
// 1. Create and save a comment
|
|
println!("\n1. Creating a Comment:");
|
|
let comment = Comment::new()
|
|
.user_id(db_user2.get_id()) // commenter's user ID (use an existing user)
|
|
.content("This is a comment on the user")
|
|
.build();
|
|
|
|
// Save the comment and get its assigned ID and updated model
|
|
let (comment_id, db_comment) = db
|
|
.collection()
|
|
.expect("can open comment collection")
|
|
.set(&comment)
|
|
.expect("can set comment");
|
|
|
|
println!("Comment assigned ID: {comment_id}");
|
|
|
|
println!(" a. Comment Retrieved from Database:");
|
|
print_comment_details(&db_comment);
|
|
|
|
// 3. Associate the comment with a user
|
|
println!("\n2. Associating Comment with User:");
|
|
let mut updated_user = db_user2.clone();
|
|
updated_user.base_data.add_comment(db_comment.get_id());
|
|
|
|
// Save the updated user and get the new version
|
|
let (_, user_with_comment) = db
|
|
.collection::<User>()
|
|
.expect("can open user collection")
|
|
.set(&updated_user)
|
|
.expect("can set updated user");
|
|
|
|
println!(" a. User with Associated Comment:");
|
|
print_user_details(&user_with_comment);
|
|
|
|
println!("\n--- Model Information ---");
|
|
println!("User DB Prefix: {}", User::db_prefix());
|
|
println!("Comment DB Prefix: {}", Comment::db_prefix());
|
|
}
|