Files
fst_data_pipeline-feature-e…/scripts/fst_sql_tool/print_tree.py

87 lines
2.4 KiB
Python
Raw Normal View History

2026-04-16 15:44:32 +08:00
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import psycopg2
import os
import sys
from dotenv import load_dotenv
load_dotenv("../../.env", override=True)
DB_CONFIG = {
"host": os.getenv("ROOT_DB_HOST", "localhost"),
"port": os.getenv("ROOT_DB_PORT", "5432"),
"dbname": os.getenv("ROOT_DB_NAME", "mydb"),
"user": os.getenv("ROOT_DB_USER", "postgres"),
"password": os.getenv("ROOT_DB_PASSWD", "postgres"),
}
def fetch_nodes():
conn = psycopg2.connect(**DB_CONFIG)
cur = conn.cursor()
cur.execute("SELECT id, name, parent_id FROM fst")
rows = cur.fetchall()
cur.close()
conn.close()
return rows
def build_tree(rows):
nodes = {}
for id_, name, parent_id in rows:
nodes[id_] = {"id": id_, "name": name, "parent_id": parent_id, "children": []}
roots = []
for n in nodes.values():
if n["parent_id"] is None or n["parent_id"] not in nodes:
roots.append(n)
else:
nodes[n["parent_id"]]["children"].append(n)
def sort_rec(n):
n["children"].sort(key=lambda x: x["name"])
for c in n["children"]:
sort_rec(c)
for r in roots:
sort_rec(r)
return roots
def print_subtree(node, prefix="", is_last=True, depth=0):
# depth==0: 根节点depth>=1: 各层子节点
if depth == 0:
# 根直接打印名字
print(node["name"])
else:
# 非根:打印前置 prefix + 连接符 + 名字
connector = "└── " if is_last else "├── "
print(prefix + connector + node["name"])
# 计算传给下一层孩子的前缀
if depth == 0:
# 第一层孩子不缩进prefix 仍然空
child_prefix = ""
else:
# depth>=1如果我是本层最后一个用空格填充否则保留竖线
child_prefix = prefix + (" " if is_last else "")
# 递归打印子节点
cnt = len(node["children"])
for idx, child in enumerate(node["children"]):
last = idx == cnt - 1
print_subtree(child, child_prefix, last, depth + 1)
def main():
rows = fetch_nodes()
if not rows:
print("fst 表中没有数据。", file=sys.stderr)
sys.exit(1)
roots = build_tree(rows)
for idx, r in enumerate(roots):
last_root = idx == len(roots) - 1
print_subtree(r, prefix="", is_last=last_root, depth=0)
if __name__ == "__main__":
main()