Skip to content

[codex] Add Postgres/Neon DATABASE_URL support#77

Open
ZeroPointSix wants to merge 17 commits into
mainfrom
codex/postgres-neon-database-url
Open

[codex] Add Postgres/Neon DATABASE_URL support#77
ZeroPointSix wants to merge 17 commits into
mainfrom
codex/postgres-neon-database-url

Conversation

@ZeroPointSix

@ZeroPointSix ZeroPointSix commented Jun 5, 2026

Copy link
Copy Markdown
Owner

What changed

Fixes #23 by adding a first-stage PostgreSQL/Neon database mode while keeping SQLite as the default.

  • Keeps the existing SQLite DATABASE_PATH behavior when DATABASE_URL is empty or SQLite-like.
  • Adds DATABASE_URL=postgresql://... / postgres://... detection at package startup.
  • Adds a sqlite3.connect compatibility adapter backed by psycopg, so existing code can keep using sqlite-style rows, ? placeholders, BEGIN IMMEDIATE, PRAGMA table_info, INSERT OR IGNORE, and the current settings/temp-message upsert patterns.
  • Handles the app's SQLite-specific initialization paths that Postgres would otherwise reject, including the sqlite_master table-schema lookup and ISO strftime(..., 'now') default expression.
  • Adds psycopg[binary] to runtime dependencies.
  • Adds Neon/PostgreSQL deployment docs and notes that existing SQLite data is not copied automatically.
  • Adds focused unit coverage for URL handling, SQL translation, compatibility rows/cursors, special SQLite statements, and the reviewed initialization blockers.

CI/CD validation

Latest PR head: 521b8fe109bfd94fe1264c8fbef04cad3fba649f

  • Code Quality: passed.
  • Python Tests: passed on Python 3.11, 3.12, and 3.13.
  • SonarCloud Scan: passed.
  • SonarCloud Quality Gate: passed with 0 Security Hotspots, 92.3% coverage on new code, and 0.0% duplication on new code.

Local validation in the workspace:

  • python -m py_compile outlook_web/db_postgres_compat.py tests/test_db_postgres_compat.py
  • Focused unit tests for tests.test_db_postgres_compat passed with a dummy app module, because the workspace checkout only contains the files needed for this PR.

Notes / follow-up

This does not perform SQLite-to-Postgres data migration. Production users should export or migrate existing SQLite data separately before switching traffic to DATABASE_URL.

A later larger refactor can replace this compatibility bridge with a formal migration layer such as SQLAlchemy/Alembic if the project wants deeper multi-database support.

@ZeroPointSix ZeroPointSix left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

审查结果(针对 Postgres/Neon DATABASE_URL 支持):

发现 2 个需要修复的阻断级问题:

  1. Postgres 模式初始化会被 sqlite_master 查询卡住。
    outlook_web/db.py 里的 temp_email_messages 迁移段会执行 SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'temp_email_messages'。新增的兼容适配器目前只特殊处理了 PRAGMA table_info(...) / PRAGMA index_list(...) 等,未拦截或翻译 sqlite_master 查询,所以这条 SQL 会原样发给 PostgreSQL,并触发类似 relation "sqlite_master" does not exist 的错误。结果是设置 DATABASE_URL=postgresql://... 后,应用初始化数据库时会失败。建议要么在适配器里模拟这类 schema 查询,要么把这段迁移改成基于 information_schema / pg_constraint 的可移植唯一约束检测。

  2. SQLite strftime 默认值没有完整翻译,初始化会遇到 PostgreSQL 语法错误。
    现有 schema 创建 telegram_push_log 时使用 pushed_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%S', 'now'))。当前 translate_sqlite_sql() 只覆盖了 strftime('%s','now')unixepoch('now'),没有覆盖这个日期格式;PostgreSQL 不支持 SQLite 的 strftime(...),因此创建该表时会失败。建议覆盖该格式,或把 schema 默认值改成 PostgreSQL 可接受的 CURRENT_TIMESTAMP / to_char(...) 等表达式。

建议补一个覆盖真实启动路径的测试:在 DATABASE_URL=postgresql://... 下执行 init_db() 到完成(可以用 fake psycopg 捕获最终 SQL,或使用临时 Postgres 容器)。当前新增测试主要验证 SQL 翻译片段,还没有覆盖 init_db() 的完整迁移路径,所以这些阻断问题没有被测出来。

@ZeroPointSix ZeroPointSix marked this pull request as ready for review June 5, 2026 15:49

Copy link
Copy Markdown
Owner Author

总体结论:本轮复核看到前一次 review 提到的两个阻断点已经有针对性修复:sqlite_master 查询被 special-case,strftime('%Y-%m-%dT%H:%M:%S', 'now') 也被翻译为 PostgreSQL 可接受的表达式;不过这类 sqlite3 shim 风险面较大,合并前仍建议补一个完整启动/初始化路径测试,而不只验证片段翻译。

关键发现:

  • 中:新增测试覆盖了 _sqlite_master_table_name()temp_email_messages 的 schema 返回,以及 ISO strftime 默认值翻译,能回应前一次审查的两个具体阻断问题。
  • 中:当前测试主要围绕 translate_sqlite_sql()、特殊 cursor 路径和 fake cursor 行为。PR 描述提到 focused unit tests 通过,但我没有看到一个直接把 DATABASE_URL=postgresql://...install_postgres_sqlite_compat() 和应用 init_db() 串起来跑完的测试。影响是未来 db.py 里任何新的 SQLite-only schema/迁移语句仍可能绕过翻译层,直到部署到 Postgres/Neon 才暴露。建议增加一个 fake psycopg 驱动的启动路径测试,至少捕获 init_db() 执行到完成时发出的 SQL,并断言没有残留 sqlite_masterPRAGMAstrftimeINSERT OR REPLACE 等 PostgreSQL 不支持片段。
  • 低:sqlite3.connect 是进程级 monkey patch,测试里已有 restore_sqlite_connect_for_tests(),这是必要的。建议后续新增测试都放在 try/finally 或 tearDown 中恢复,避免其他测试被 Postgres shim 污染。
  • 低:该方案明确是第一阶段兼容桥,不做 SQLite 数据迁移;PR 文档已经写清楚,这一点合理。

优先级建议:

  • 阻塞:无明确新增阻断项。
  • 高:补一个真实初始化路径级别的回归测试,覆盖从安装 shim 到数据库初始化完成。
  • 中:合并前最好在真实 Postgres/Neon 或容器化 Postgres 上跑一次 smoke test,验证 psycopg 连接、DDL 和初始化迁移能完整完成。

后续建议:

  • 如果后续继续扩展多数据库支持,建议逐步从兼容 shim 迁移到显式 migration layer;当前桥接方案可作为第一阶段,但不宜长期承载越来越多 SQL 方言转换。

@ZeroPointSix

Copy link
Copy Markdown
Owner Author

CodeXWeb 本轮自动巡检已认领,正在处理本 PR 的 review 修改意见。

本轮只会处理这一项:#77。接下来会先对照 PR diff、review 评论、相关 Issue/Workspace 记录和现有实现约束,只做最小必要修复;完成后会在本 PR 回写改动、验证结果和风险,不会自动合并。

@ZeroPointSix

Copy link
Copy Markdown
Owner Author

CodeXWeb 本轮自动巡检处理完成,本轮只处理 PR #77

处理对象:review 评论 4670508474 提到的 fake psycopg 启动路径补测。

提交:2c026314dc974517dc75a1b4f963e84922ba8e47,message 为 test: cover postgres init path。

改动:补齐 email 相关 SQLite 函数到 PostgreSQL POSITION 和 SPLIT_PART 的翻译;新增完整 DATABASE_URL 到 init_db 的 fake psycopg 回归测试;更新 WORKSPACE 记录。

验证:Postgres compat 单测 21 passed;py_compile passed;git diff check passed;完整 pytest 在沙箱补装 pytest 和 Playwright、启动本地服务后运行,结果为 1544 passed, 7 skipped, 31 subtests passed, 4 failed。4 个失败均为真实 Cloudflare Worker E2E,上游返回 HTTP 400 和 UPSTREAM_BAD_PAYLOAD,和本次 Postgres Neon SQL 翻译及启动路径补测不相邻。

剩余风险:本轮没有连接真实 Neon 或 PostgreSQL 实例做 smoke test;review 建议的 fake psycopg 启动路径回归已补齐并通过。

@sonarqubecloud

Copy link
Copy Markdown

@ZeroPointSix ZeroPointSix left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

总体结论:本轮针对最新提交 2c026314dc974517dc75a1b4f963e84922ba8e47 复核新增的 Postgres 兼容层补测和 SQL 翻译改动,未发现新的阻塞问题;上一轮要求的 fake psycopg 启动路径覆盖已经补上。

关键发现:

  • 已核对新增 test_postgres_shim_runs_full_init_db_without_sqlite_only_sql,它会在 DATABASE_URL=postgresql://... 下安装 shim 并直接执行 db.init_db(),覆盖了前次 review 要求的从配置到初始化的完整路径,比单独测试 SQL 片段更能防止 SQLite-only 语句漏到 PostgreSQL。
  • 已核对新增的 instr(email, '@') / substr(...) / LOWER(SUBSTR(...)) 翻译,当前覆盖了初始化路径中出现的 email prefix/domain 维护语句,并在测试中断言最终 SQL 不再包含 instr( / substr( 等 PostgreSQL 不支持片段。
  • 已核对 sqlite_masterPRAGMAstrftimeINSERT OR REPLACEINSERT OR IGNOREAUTOINCREMENTCOLLATE NOCASEunixepoch 等风险片段的启动路径断言,能覆盖前两轮审查中指出的主要兼容性缺口。
  • 仍需注意:本轮测试使用 fake psycopg 证明应用初始化会发出 PostgreSQL 风格 SQL,但不能替代真实 Neon/PostgreSQL 实例上的 DDL/约束/事务行为 smoke test。

优先级建议:

  • 阻塞:无。
  • 中:合并前如条件允许,仍建议用真实 PostgreSQL 或 Neon 临时库跑一次启动 smoke,确认 psycopg 连接、DDL、唯一约束和 upsert 行为在真实数据库上完整通过。
  • 低:后续如果继续新增 SQLite 方言语句,建议同步扩展这个 init_db 路径测试的禁止片段列表,避免兼容层只覆盖旧 schema。

后续建议:

  • 当前补测已经回应前次 review 的高优先级建议;剩余风险主要是真实数据库环境验证,而不是当前 fake 初始化路径覆盖不足。

ZeroPointSix commented Jun 11, 2026

Copy link
Copy Markdown
Owner Author

CodeXWeb 本轮自动巡检已核对 PR #77

检查结果:最新 head 2c026314dc974517dc75a1b4f963e84922ba8e47 已在 review 4478075715 中覆盖,且该 review 之后没有新的提交或新增 diff;因此本轮不会对 #77 重复发布 code review,也不会自动合并。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: 希望增加第三方数据库接入

1 participant