Coverage for autocrud/storage.py: 64%
131 statements
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-23 23:00 +0800
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-23 23:00 +0800
1"""存儲抽象層"""
3import os
4from abc import ABC, abstractmethod
5from typing import Any, Dict, List, Optional
6from .serializer import Serializer, SerializerFactory
9class Storage(ABC):
10 """存儲抽象基類"""
12 def __init__(self, serializer: Optional[Serializer] = None):
13 if serializer is None:
14 serializer = SerializerFactory.create("json")
15 self.serializer = serializer
17 @abstractmethod
18 def get(self, key: str) -> Optional[Any]:
19 """獲取數據"""
20 pass
22 @abstractmethod
23 def set(self, key: str, value: Any) -> None:
24 """存儲數據"""
25 pass
27 @abstractmethod
28 def delete(self, key: str) -> bool:
29 """刪除數據"""
30 pass
32 @abstractmethod
33 def exists(self, key: str) -> bool:
34 """檢查鍵是否存在"""
35 pass
37 @abstractmethod
38 def list_keys(self) -> List[str]:
39 """列出所有鍵"""
40 pass
43class MemoryStorage(Storage):
44 """純內存存儲實現(重啟後數據消失,適合測試和演示)"""
46 def __init__(self, serializer: Optional[Serializer] = None):
47 super().__init__(serializer)
48 self._data: Dict[str, bytes] = {}
50 def get(self, key: str) -> Optional[Any]:
51 if key not in self._data:
52 return None
54 serialized_data = self._data[key]
55 return self.serializer.deserialize(serialized_data)
57 def set(self, key: str, value: Any) -> None:
58 serialized_data = self.serializer.serialize(value)
59 self._data[key] = serialized_data
61 def delete(self, key: str) -> bool:
62 if key in self._data:
63 del self._data[key]
64 return True
65 return False
67 def exists(self, key: str) -> bool:
68 return key in self._data
70 def list_keys(self) -> List[str]:
71 return list(self._data.keys())
73 def clear(self) -> None:
74 """清空所有數據"""
75 self._data.clear()
77 def size(self) -> int:
78 """獲取存儲的條目數量"""
79 return len(self._data)
82class DiskStorage(Storage):
83 """磁碟文件存儲實現(真正的持久化存儲)"""
85 def __init__(self, base_dir: str, serializer: Optional[Serializer] = None):
86 super().__init__(serializer)
87 self.base_dir = base_dir
89 # 確保基礎目錄存在
90 os.makedirs(self.base_dir, exist_ok=True)
92 def _get_file_path(self, key: str) -> str:
93 """獲取鍵對應的文件路徑"""
94 # 將鍵轉換為安全的文件名
95 safe_key = key.replace(":", "_").replace("/", "_")
96 return os.path.join(self.base_dir, f"{safe_key}.data")
98 def get(self, key: str) -> Optional[Any]:
99 file_path = self._get_file_path(key)
100 if not os.path.exists(file_path):
101 return None
103 try:
104 with open(file_path, "rb") as f:
105 serialized_data = f.read()
106 return self.serializer.deserialize(serialized_data)
107 except Exception as e:
108 print(f"讀取文件失敗 {file_path}: {e}")
109 return None
111 def set(self, key: str, value: Any) -> None:
112 file_path = self._get_file_path(key)
114 try:
115 serialized_data = self.serializer.serialize(value)
116 with open(file_path, "wb") as f:
117 f.write(serialized_data)
118 except Exception as e:
119 print(f"寫入文件失敗 {file_path}: {e}")
120 raise
122 def delete(self, key: str) -> bool:
123 file_path = self._get_file_path(key)
124 if os.path.exists(file_path):
125 try:
126 os.remove(file_path)
127 return True
128 except Exception as e:
129 print(f"刪除文件失敗 {file_path}: {e}")
130 return False
131 return False
133 def exists(self, key: str) -> bool:
134 file_path = self._get_file_path(key)
135 return os.path.exists(file_path)
137 def list_keys(self) -> List[str]:
138 """列出所有鍵"""
139 keys = []
140 try:
141 for filename in os.listdir(self.base_dir):
142 if filename.endswith(".data"):
143 # 將文件名轉換回鍵名
144 key = filename[:-5].replace("_", ":") # 移除 .data 後綴
145 keys.append(key)
146 except Exception as e:
147 print(f"列出文件失敗: {e}")
149 return keys
151 def clear(self) -> None:
152 """清空所有數據"""
153 try:
154 for filename in os.listdir(self.base_dir):
155 if filename.endswith(".data"):
156 file_path = os.path.join(self.base_dir, filename)
157 os.remove(file_path)
158 except Exception as e:
159 print(f"清空目錄失敗: {e}")
161 def size(self) -> int:
162 """獲取存儲的條目數量"""
163 return len(self.list_keys())
166# 使用範例
167if __name__ == "__main__":
168 # 測試純內存存儲
169 print("=== 測試純內存存儲 ===")
170 memory_storage = MemoryStorage()
172 # 測試數據
173 test_data = {"name": "Alice", "age": 30}
175 # 存儲數據
176 memory_storage.set("user:1", test_data)
177 print(f"內存存儲成功: {memory_storage.exists('user:1')}")
179 # 獲取數據
180 retrieved_data = memory_storage.get("user:1")
181 print(f"內存獲取數據: {retrieved_data}")
183 print(f"內存存儲大小: {memory_storage.size()}")
185 # 測試磁碟存儲
186 print("\n=== 測試磁碟存儲 ===")
187 import tempfile
189 temp_dir = tempfile.mkdtemp()
190 disk_storage = DiskStorage(temp_dir)
192 # 存儲數據
193 disk_storage.set("user:1", test_data)
194 print(f"磁碟存儲成功: {disk_storage.exists('user:1')}")
196 # 獲取數據
197 retrieved_data = disk_storage.get("user:1")
198 print(f"磁碟獲取數據: {retrieved_data}")
200 print(f"磁碟存儲大小: {disk_storage.size()}")
201 print(f"磁碟所有鍵: {disk_storage.list_keys()}")
203 # 清理
204 disk_storage.clear()
205 os.rmdir(temp_dir)