feat: 完成 issue #30 ② PostgreSQL 关系表 schema(模板/模型/用户/权限)
This commit is contained in:
@@ -0,0 +1,23 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# 模板「PostgreSQL 关系库」配置资产示例:ti-cl4(氯化车间/海绵钛,Template-Ti 一期)。
|
||||||
|
#
|
||||||
|
# 说明(issue #30 / PRD 5.2「② 数据总线 + 时序库」):
|
||||||
|
# - 隔离 schema:`tpl_{template}`,内含基础关系表(模板/模型/用户/权限);
|
||||||
|
# - schema_tables:可选子集/扩展(缺省使用内核默认四表,见 postgres_schema.py);
|
||||||
|
# - roles:关系角色声明(生成 {role}_ro / {role}_rw 授权语句);
|
||||||
|
# - 换行业只改本文件(template / roles / schema_tables),内核零改动。
|
||||||
|
template: ti-cl4
|
||||||
|
version: 1.0.0
|
||||||
|
|
||||||
|
postgres:
|
||||||
|
# 关系角色:每个角色生成 `{role}_ro`(只读)与 `{role}_rw`(读写)
|
||||||
|
roles:
|
||||||
|
- databus
|
||||||
|
- modeler
|
||||||
|
# 基础关系表(缺省 = templates / models / users / permissions;
|
||||||
|
# 此处仅声明,列定义用内核默认,避免与实现漂移)
|
||||||
|
schema_tables:
|
||||||
|
- templates
|
||||||
|
- models
|
||||||
|
- users
|
||||||
|
- permissions
|
||||||
@@ -114,3 +114,41 @@ def generate_grant_ddl(
|
|||||||
f"GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA {schema} TO {role_name};"
|
f"GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA {schema} TO {role_name};"
|
||||||
)
|
)
|
||||||
return grants
|
return grants
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# 模板配置资产加载(issue #30:换行业只改 config/postgres.template.yaml)
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
def load_postgres_config(path: str) -> dict:
|
||||||
|
"""加载模板配置资产(config/postgres.template.yaml)。"""
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
with open(path, "r", encoding="utf-8") as fh:
|
||||||
|
return yaml.safe_load(fh) or {}
|
||||||
|
|
||||||
|
|
||||||
|
def generate_from_config(
|
||||||
|
path: str,
|
||||||
|
naming: Optional[TemplateNaming] = None,
|
||||||
|
) -> tuple:
|
||||||
|
"""按模板配置生成 PostgreSQL schema DDL 与授权语句。
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path: 模板配置资产路径(config/postgres.template.yaml)。
|
||||||
|
naming: 模板命名器(缺省按资产 template 字段构造)。
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
(schema_ddl, grant_statements):DDL 文本与 GRANT 语句列表。
|
||||||
|
"""
|
||||||
|
raw = load_postgres_config(path)
|
||||||
|
pg = raw.get("postgres", {}) or {}
|
||||||
|
naming = naming or TemplateNaming(template=str(raw.get("template", "default")))
|
||||||
|
ddl = generate_schema_ddl(
|
||||||
|
naming,
|
||||||
|
tables=pg.get("schema_tables") or None,
|
||||||
|
table_columns=None, # 列定义用内核默认,避免与实现漂移
|
||||||
|
)
|
||||||
|
grants = generate_grant_ddl(naming, roles=pg.get("roles") or None)
|
||||||
|
return ddl, grants
|
||||||
|
|||||||
@@ -7,11 +7,22 @@ import unittest
|
|||||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||||
import _bootstrap # noqa: F401
|
import _bootstrap # noqa: F401
|
||||||
|
|
||||||
from data_bus.postgres_schema import DEFAULT_TABLES, generate_grant_ddl, generate_schema_ddl
|
from data_bus.postgres_schema import ( # noqa: E402
|
||||||
from data_bus.templating import TemplateNaming
|
DEFAULT_TABLES,
|
||||||
|
generate_from_config,
|
||||||
|
generate_grant_ddl,
|
||||||
|
generate_schema_ddl,
|
||||||
|
load_postgres_config,
|
||||||
|
)
|
||||||
|
from data_bus.templating import TemplateNaming # noqa: E402
|
||||||
|
|
||||||
NAMING = TemplateNaming(template="ti-cl4")
|
NAMING = TemplateNaming(template="ti-cl4")
|
||||||
|
|
||||||
|
CONFIG = os.path.join(
|
||||||
|
os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
|
||||||
|
"config", "postgres.template.yaml",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class SchemaDDLTest(unittest.TestCase):
|
class SchemaDDLTest(unittest.TestCase):
|
||||||
def test_schema_and_tables(self):
|
def test_schema_and_tables(self):
|
||||||
@@ -35,5 +46,30 @@ class GrantDDLTest(unittest.TestCase):
|
|||||||
self.assertIn("GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA tpl_ti_cl4 TO databus_rw;", text)
|
self.assertIn("GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA tpl_ti_cl4 TO databus_rw;", text)
|
||||||
|
|
||||||
|
|
||||||
|
class ConfigDrivenTest(unittest.TestCase):
|
||||||
|
"""模板配置资产(issue #30):换行业只改配置生成 schema/授权。"""
|
||||||
|
|
||||||
|
def test_config_parses(self):
|
||||||
|
raw = load_postgres_config(CONFIG)
|
||||||
|
self.assertEqual(raw["template"], "ti-cl4")
|
||||||
|
self.assertIn("databus", raw["postgres"]["roles"])
|
||||||
|
self.assertEqual(raw["postgres"]["schema_tables"], DEFAULT_TABLES)
|
||||||
|
|
||||||
|
def test_generate_from_config(self):
|
||||||
|
ddl, grants = generate_from_config(CONFIG)
|
||||||
|
# schema 按资产 template 推导
|
||||||
|
self.assertIn("CREATE SCHEMA IF NOT EXISTS tpl_ti_cl4;", ddl)
|
||||||
|
for table in DEFAULT_TABLES:
|
||||||
|
self.assertIn(f"CREATE TABLE IF NOT EXISTS tpl_ti_cl4.{table} (", ddl)
|
||||||
|
# 角色来自资产声明(databus / modeler → 4 个角色)
|
||||||
|
text = "\n".join(grants)
|
||||||
|
for role in ("databus_ro", "databus_rw", "modeler_ro", "modeler_rw"):
|
||||||
|
self.assertIn(f"TO {role};", text)
|
||||||
|
|
||||||
|
def test_generate_from_config_with_naming_override(self):
|
||||||
|
ddl, grants = generate_from_config(CONFIG, naming=TemplateNaming("resin"))
|
||||||
|
self.assertIn("CREATE SCHEMA IF NOT EXISTS tpl_resin;", ddl)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|||||||
Reference in New Issue
Block a user