【Python】NoSQL【Rust】

import json
import os
from typing import List, Dict, Any

class SimpleNoSQL:
    def __init__(self, db_path: str= "db.json"):
        self.db_path = db_path
        if os.path.exists(self.db_path):
            with open(self.db_path, "r") as f:
                self.data = json.load(f)
        else:
            self.data = []

    def save(self):
        with open(self.db_path, "w") as f:
            json.dump(self.data, f, indent=2)

    def insert(self, document: Dict[str, Any]):
        self.data.append(document)
        self.save()

    def find(self, query: Dict[str, Any]) -> List[Dict[str, Any]]:
        def match(doc):
            return all(doc.get(k) == v for k, v in query.items())
        return [doc for doc in self.data if match(doc)]

    def update(self, query: Dict [str, Any], update_fields: Dict[str, Any]):
        for doc in self.data:
            if all(doc.get(k) == v for k, v in query.items()):
                 doc.update(update_fields)
        self.save()

    def delete(self, query: Dict[str, Any]):
        self.data = [doc for doc in self.data if not all(doc.get(k) == v for k, v in query.items())]
        self.save

db = SimpleNoSQL()

db.insert({
    "session_id": "abc123",
    "code": "fn main() { println!(\"Hello\"); }",
    "output": "Hello",
    "status": "success"
})

results = db.find({"session_id": "abc123"})
print("検索結果:", results)

db.update({"session_id": "abc123"}, {"status": "reviewed"})

[
{
“session_id”: “abc123”,
“code”: “fn main() { println!(\”Hello\”); }”,
“output”: “Hello”,
“status”: “reviewed”
}
]

これをRustでやりたい

### Rustでのjsonの保存

use std::collections::HashMap;
use std::fs::File;
use std::io::Write;
use serde::{Serialize, Deserialize};

fn json_w() -> std::io::Result<()> {
    let mut map = HashMap::new();
    map.insert("name", "Alice");
    map.insert("city", "Tokyo");
    map.insert("language", "Rust");

    let json = serde_json::to_string_pretty(&map).expect("Failed to serialize");
    let mut file = File::create("output.json")?;
    file.write_all(json.as_bytes())?;
    
    println!("{:?}", json);
    Ok(())
}

fn main() {
    let _ = json_w();
}

### jsonの読み取り

fn json_r() {
    let data = fs::read_to_string("output.json").expect("Failed to read file");
    let map: HashMap<String, String> = serde_json::from_str(&data).expect("Failed to deserialize");

    println!("{:#?}", map);    
}

{
“name”: “Alice”,
“language”: “Rust”,
“city”: “Tokyo”,
}

### 改修
レコードごとに保存する必要があるので HashMap から Vec> に変更

fn json_w() -> std::io::Result<()> {
    let mut data: Vec<HashMap<String, String>> = match File::open("output.json") {
        Ok(mut file) => {
            let mut contents = String::new();
            file.read_to_string(&mut contents)?;
            serde_json::from_str(&contents).unwrap_or_else(|_| Vec::new())
        },
        Err(_) => Vec::new(),
    };

    let mut map = HashMap::new();
    // map.insert("name".to_string(), "Alice".to_string());
    // map.insert("city".to_string(), "Tokyo".to_string());
    // map.insert("language".to_string(), "Rust".to_string());

    map.insert("name".to_string(), "Bob".to_string());
    map.insert("city".to_string(), "Osaka".to_string());
    map.insert("language".to_string(), "Go".to_string());

    data.push(map);

    let json = serde_json::to_string_pretty(&data).expect("Failed to serialize");
    let mut file = File::create("output.json")?;
    file.write_all(json.as_bytes())?;

    println!("{:?}", json);
    Ok(())
}

fn json_r() {
    let data = fs::read_to_string("output.json").expect("Failed to read file");
    let v: Vec<HashMap<String, String>> = serde_json::from_str(&data).expect("Failed to deserialize");

    println!("{:#?}", v);    
}

fn main() {
    // 
    // let _ = json_w();
    let _ = json_r();
}

[
{
“language”: “Rust”,
“name”: “Alice”,
“city”: “Tokyo”,
},
{
“city”: “Osaka”,
“language”: “Go”,
“name”: “Bob”,
},
]

### implで表現する
関数をinsert, selectとする

use std::collections::HashMap;
use std::fs;
use std::fs::{File};
use std::io::{Read, Write};
use serde::{Serialize, Deserialize};

pub static FILE_NAME : &'static str = "output.json";

struct NoSQL {
    data: Vec<HashMap<String, String>>,
}

impl NoSQL {
    fn insert(&mut self, map: HashMap<String, String>) -> std::io::Result<()> {
        self.data = match File::open(FILE_NAME) {
            Ok(mut file) => {
                let mut contents = String::new();
                file.read_to_string(&mut contents)?;
                serde_json::from_str(&contents).unwrap_or_else(|_| Vec::new())
            },
            Err(_) => Vec::new(),
        };        
        self.data.push(map);

        let json = serde_json::to_string_pretty(&self.data).expect("Failed to serialize");
        let mut file = File::create(FILE_NAME)?;
        file.write_all(json.as_bytes())?;

        println!("{:?}", json);
        Ok(())
    }

    fn select(&self) {
        let data = fs::read_to_string(FILE_NAME).expect("Failed to read file");
        let v: Vec<HashMap<String, String>> = serde_json::from_str(&data).expect("Failed to deserialize");
    
        println!("{:#?}", v);    
    }
}

fn main() {
    let mut sql = NoSQL{ data: Vec::new() };

    let mut map = HashMap::new();
    map.insert("name".to_string(), "Bob".to_string());
    map.insert("city".to_string(), "Osaka".to_string());
    map.insert("language".to_string(), "Go".to_string());

    sql.insert(map);
    sql.select();
}

こうすると、nosqlは単純にVec>,と言える。
インメモリデータベースの場合は、メモリに保存するので、jsonではなく、単純にデータとして持っておくだけになる。その場合、サイズが動的なので、スタックではなく、ヒープに保存される。