Skip to main content

moltendb_core/handlers/
process_delete.rs

1use tracing::debug;
2use serde_json::{Value, json};
3use crate::validation;
4use crate::engine;
5
6/// Handle a DELETE request.
7///
8/// Three modes:
9///   - Single key:  { "collection": "users", "keys": "u1" }
10///   - Batch keys:  { "collection": "users", "keys": ["u1", "u2"] }
11///   - Drop all:    { "collection": "users", "drop": true }
12pub fn process_delete(db: &engine::Db, payload: &Value, max_body_size: usize, max_keys_per_request: usize) -> (u16, Value) {
13    if let Err(e) = validation::validate_request(payload, max_body_size, max_keys_per_request) {
14        return (400, json!({ "error": e.to_string(), "statusCode": 400 }));
15    }
16    // Only "collection", "keys", and "drop" are valid for a delete request.
17    const DELETE_ALLOWED: &[&str] = &["collection", "keys", "drop"];
18    if let Err(e) = validation::validate_allowed_properties(payload, DELETE_ALLOWED) {
19        return (400, json!({ "error": e.to_string(), "statusCode": 400 }));
20    }
21
22    let col = payload["collection"].as_str().unwrap_or("default");
23
24    // Check for drop: true — this removes the entire collection.
25    if payload["drop"].as_bool().unwrap_or(false) {
26        return match db.delete_collection(col) {
27            Ok(_)  => (200, json!({ "status": "ok", "dropped": true })),
28            Err(e) => (500, json!({ "error": "Failed to drop collection", "details": e.to_string(), "statusCode": 500 }))
29        };
30    }
31
32    match payload.get("keys") {
33        // Single key delete.
34        Some(Value::String(k)) => {
35            // Check collection size for auto-eviction (Hybrid Bitcask).
36            if let Ok(count) = db.evict_collection(col, db.hot_threshold) {
37                if count > 0 {
38                    debug!("❄️  Auto-evicted {} documents from {} to disk", count, col);
39                }
40            }
41            match db.delete(col, vec![k.to_string()]) {
42                Ok(_)  => (200, json!({ "status": "ok", "deleted": 1 })),
43                Err(e) => (500, json!({ "error": "Failed to delete key", "details": e.to_string(), "statusCode": 500 }))
44            }
45        },
46
47        // Batch key delete — collect all keys then delete in one call.
48        Some(Value::Array(arr)) => {
49            let mut keys = Vec::new();
50            for k in arr {
51                if let Some(s) = k.as_str() { keys.push(s.to_string()); }
52            }
53            let count = keys.len();
54            // ── Check collection size for auto-eviction ──────────────────────────────
55            // If the collection is getting large, evict old documents to disk.
56            // Configurable limit: db.hot_threshold documents per collection.
57            if let Ok(count) = db.evict_collection(col, db.hot_threshold) {
58                if count > 0 {
59                    debug!("❄️  Auto-evicted {} documents from {} to disk", count, col);
60                }
61            }
62
63            match db.delete(col, keys) {
64                Ok(_)  => (200, json!({ "status": "ok", "deleted": count })),
65                Err(e) => (500, json!({ "error": "Failed to delete batch", "details": e.to_string(), "statusCode": 500 }))
66            }
67        },
68        // Neither keys nor drop:true — invalid request.
69        _ => (400, json!({ "error": "Missing 'keys' (string or array) or 'drop': true", "statusCode": 400 }))
70    }
71}