From 87eff8609067b15b0950deff9c24caf22f8543cb Mon Sep 17 00:00:00 2001 From: bot_dev2 Date: Wed, 5 Aug 2026 00:54:58 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=8C=E6=88=90=20issue=20#30=20?= =?UTF-8?q?=E2=91=A1=20PostgreSQL=20=E5=85=B3=E7=B3=BB=E8=A1=A8=20schema?= =?UTF-8?q?=EF=BC=88=E6=A8=A1=E6=9D=BF/=E6=A8=A1=E5=9E=8B/=E7=94=A8?= =?UTF-8?q?=E6=88=B7/=E6=9D=83=E9=99=90=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/data-bus/config/postgres.template.yaml | 23 ++++++++++++ core/data-bus/postgres_schema.py | 38 ++++++++++++++++++++ core/data-bus/tests/test_postgres_schema.py | 40 +++++++++++++++++++-- 3 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 core/data-bus/config/postgres.template.yaml diff --git a/core/data-bus/config/postgres.template.yaml b/core/data-bus/config/postgres.template.yaml new file mode 100644 index 0000000..0c62c49 --- /dev/null +++ b/core/data-bus/config/postgres.template.yaml @@ -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 diff --git a/core/data-bus/postgres_schema.py b/core/data-bus/postgres_schema.py index 5951a91..8b088f3 100644 --- a/core/data-bus/postgres_schema.py +++ b/core/data-bus/postgres_schema.py @@ -114,3 +114,41 @@ def generate_grant_ddl( f"GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA {schema} TO {role_name};" ) 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 diff --git a/core/data-bus/tests/test_postgres_schema.py b/core/data-bus/tests/test_postgres_schema.py index 06672de..2beddcb 100644 --- a/core/data-bus/tests/test_postgres_schema.py +++ b/core/data-bus/tests/test_postgres_schema.py @@ -7,11 +7,22 @@ import unittest sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) import _bootstrap # noqa: F401 -from data_bus.postgres_schema import DEFAULT_TABLES, generate_grant_ddl, generate_schema_ddl -from data_bus.templating import TemplateNaming +from data_bus.postgres_schema import ( # noqa: E402 + 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") +CONFIG = os.path.join( + os.path.dirname(os.path.dirname(os.path.abspath(__file__))), + "config", "postgres.template.yaml", +) + class SchemaDDLTest(unittest.TestCase): 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) +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__": unittest.main()