這幾天寫了一些有趣的代碼:
規格設計
把git當作 json 數據庫。做法是這樣的:
- 創建一個git倉庫
- 爲每個最小粒度的數據創建一個獨立的json文件({table}.json)
- 客戶端通過 Python寫git操作代碼,實現幾個數據庫操作接口。
數據庫操作接口最小集:
- 初始化:把git倉庫拉下來(這個後面可以優化爲只拉取指定json文件) git init, git fetch, git checkout branch
- 連接:要更新的時候,同步下最新,git checkout . + git clean -df . + git pull
- 查詢:直接讀取倉庫內的json文件, json.load(f)
- 更新:比對並寫入倉庫內json文件, json.dump(table,f,indent=4)
- 提交:推送, git add {table}.json, git commit -m f"update {table}", git push
對於 table 的設計:
- 拆分足夠小的粒度,使得不同table之間相對獨立,避免衝突,這種隔離使得,git push可以自動合併本地和遠程倉庫的不同(不同文件之間無衝突可自動合併)。
- 同table在更新機制上只要滿足最終一致性即可,因此即使同文件發生併發導致某次push失敗,也會被後續的更新解決。
- 對於性能要求不高,只要最終一致性滿足即可
使用這樣的方式好處是:
- 使用一個 git 倉庫就可以做分佈式有狀態功能
- 獲得 json table 的版本化支持,通過git的日誌可以非常清晰地看到不同table的版本更新,方便比對
- 無需引入獨立的數據庫
GPT編寫的代碼
我們把需求提給GPT,得到初版代碼:
import os
import json
from git import Repo, exc
class GitJsonDatabase:
def __init__(self, repo_path, remote_url=None, branch='master'):
self.repo_path = repo_path
self.remote_url = remote_url
self.branch = branch
self.repo = None
def init_repo(self):
"""
初始化 Git 倉庫,如果遠程 URL 存在,則從該遠程地址克隆倉庫。
否則,在本地創建一個新的倉庫。
"""
if self.remote_url:
self.repo = Repo.clone_from(self.remote_url, self.repo_path)
else:
self.repo = Repo.init(self.repo_path)
# Checkout the desired branch
try:
self.repo.git.checkout(self.branch)
except exc.GitCommandError:
# If branch doesn't exist, create it.
self.repo.git.checkout('-b', self.branch)
def connect(self):
"""
連接到倉庫,並更新最新版本。
"""
if self.repo is None:
raise Exception("Repository not initialized.")
# Reset local changes and clean up untracked files
self.repo.git.checkout('--', '.')
self.repo.git.clean('-df')
# Pull latest changes from the remote
origin = self.repo.remotes.origin
origin.pull(self.branch)
def query(self, table):
"""
查詢指定的 JSON 文件。
"""
file_path = os.path.join(self.repo_path, f"{table}.json")
if not os.path.exists(file_path):
return None
with open(file_path, 'r') as f:
return json.load(f)
def update(self, table, data):
"""
更新指定的 JSON 文件。
"""
file_path = os.path.join(self.repo_path, f"{table}.json")
with open(file_path, 'w') as f:
json.dump(data, f, indent=4)
def commit(self, table, message=None):
"""
提交更改並推送到遠端。
"""
if self.repo is None:
raise Exception("Repository not initialized.")
file_path = f"{table}.json"
message = message or f"Update {table}"
# Stage the file and commit
self.repo.git.add(file_path)
self.repo.index.commit(message)
# Push to the remote
origin = self.repo.remotes.origin
origin.push(self.branch)
# 使用示例
# 創建 GitJsonDatabase 實例時需指定本地倉庫路徑和遠程倉庫 URL
db = GitJsonDatabase('/path/to/repo', 'https://github.com/user/repo.git')
# 初始化倉庫(克隆或創建)
db.init_repo()
# 連接到倉庫,同步最新內容
db.connect()
# 查詢數據
data = db.query('my_table')
# 更新數據
data['new_key'] = 'new_value'
db.update('my_table', data)
# 提交併推送更改
db.commit('my_table', 'Added new_key to my_table')
--end--