Files
胡飞 4071882cb1 feat(db): PostgreSQL 外部表与物化视图纳入树、动作与转储
PG 连接的表目录写死 `c.relkind = 'r'`,外部表('f')和分区表('p')根本列不出来,
物化视图也找不到入口(视图走 `information_schema.views`,它不含物化视图)——与
Navicat 的行为不一致,用户已经建好的外部表在 Navop 里等于不存在。

- 列表:`list_tables` / `list_tables_view` 放开 relkind 到 `'r','p','f'`,按 relkind
  映射对象类型('f' → ForeignTable,'p'/'r' → Table),对象列表「类型」列分别显示
  Table / Partitioned Table / Foreign Table;新增 `list_materialized_views`(走
  `pg_class` relkind='m' + `pg_get_viewdef`),物化视图从普通视图里彻底分离。
- 树:新增 `DbNodeType::{ForeignTable, MaterializedViewsFolder, MaterializedView}`,
  外部表与普通表/分区表同处「表」目录(对齐 Navicat),物化视图单独一个目录;目录由
  `supports_materialized_views` 能力位控制,MySQL 等其它驱动不受影响。
- 动作:外部表与物化视图按 node_type 各自 scope 出菜单(Open / Rename / Truncate /
  Drop / Dump / Import / Export 等),删除与重命名按类型分派到 `drop_foreign_table`
  / `rename_foreign_table` / `drop_materialized_view`——不能把 `DROP TABLE` 打到外部表
  上。设计表 / 复制表 / 结构转储等尚无实现的动作不注册,因此不会出现点了没反应的项。
- 结构比较与结构转储:新增 `TableObjectType::ForeignTable`,`is_ddl_comparable()` 只让
  普通表参与,外部表自动从结构比较、数据比较、ER 图、整库 DDL 转储中排除(数据转储
  仍可用);`resolve_sql_dump_target` 补上新类型的映射,避免 Dump 静默报错。
- schema 限定:`rename_foreign_table` / `drop_materialized_view` 接受 schema 并生成
  schema 限定名——执行会话不会切 search_path,非 public schema 下的 DDL 原先会打错
  对象(或直接报错)。

验证:

- `cargo test -p db --lib` 1305 passed / 0 failed;`cargo test -p db_view --lib`
  703 passed / 0 failed / 1 ignored;`cargo check --workspace --all-targets` 无
  error/warning;对新增行做 clippy 比对,无新增告警。
- 新增真实库集成测试 `crates/db/tests/real_databases/postgres/foreign_matview.rs`
  (设置 `ONETCLI_TEST_POSTGRES_PASSWORD` 后才运行):在非 public schema 下真建外部表
  (postgres_fdw)、分区表与物化视图,断言列表类型、对象面板类型与树的归属,并真实
  执行 rename / drop 外部表和 drop 物化视图,最后校验 `list_views` 不混入物化视图。
  `cargo test -p db --test real_postgres` 5 passed;测试自带清理,不在库里留 schema、
  外部服务器或扩展。
- 未验证:GUI 端到端(右键菜单实际点击路径)没有真机回归,只覆盖到事件与 SQL 生成层。
2026-09-21 16:24:44 +08:00
..

Real database integration tests

These tests exercise the built-in database plugins against real database engines rather than mocks. They cover all-type fixtures, direct SQL scripts, errors and transactions, metadata, paginated table data, generated row CRUD, table designer CRUD, import/export, and compare/sync primitives.

Files

  • real_sqlite.rs: SQLite integration flow.
  • real_duckdb.rs: DuckDB integration flow.
  • real_mysql.rs: MySQL integration flow.
  • real_postgres.rs: PostgreSQL integration flow.
  • real_compare.rs: SQLite source/target schema compare, data compare, generated sync SQL, selected statement execution, and destructive statement safety.

Runner

SQLite, the SQLite compare test, and DuckDB run by default:

./script/run-real-db-tests.sh

The script does not start a database server and never provides default credentials. MySQL and PostgreSQL tests skip automatically (with a note on stderr) when their password environment variable is absent, so cargo test --all stays green on machines and CI runners without a local database server. When the variable is present the tests run for real. An empty PostgreSQL password is valid and is handled correctly.

Environment variables

MySQL

export ONETCLI_TEST_MYSQL_HOST=127.0.0.1
export ONETCLI_TEST_MYSQL_PORT=3306
export ONETCLI_TEST_MYSQL_USER=root
export ONETCLI_TEST_MYSQL_PASSWORD='your-password'

All variables except ONETCLI_TEST_MYSQL_PASSWORD have defaults. Tests create and drop isolated navop_real_mysql_<pid>_<flow> databases.

PostgreSQL

export ONETCLI_TEST_POSTGRES_HOST=127.0.0.1
export ONETCLI_TEST_POSTGRES_PORT=5432
export ONETCLI_TEST_POSTGRES_USER=postgres
export ONETCLI_TEST_POSTGRES_PASSWORD='' # empty is intentionally valid
export ONETCLI_TEST_POSTGRES_DATABASE=postgres

All variables except ONETCLI_TEST_POSTGRES_PASSWORD have defaults. Tests create and drop isolated navop_real_pg_<pid>_<flow> schemas.

Direct commands

cargo test -p db --test real_sqlite -- --nocapture
cargo test -p db --test real_compare -- --nocapture
cargo test -p db --features builtin-duckdb --test real_duckdb -- --nocapture
ONETCLI_TEST_MYSQL_PASSWORD='your-password' \
  cargo test -p db --test real_mysql -- --nocapture
ONETCLI_TEST_POSTGRES_PASSWORD='' \
  cargo test -p db --test real_postgres -- --nocapture

Run tests from the repository root. Keep any leaked test databases out of shared servers by dropping them if a test is interrupted.