Ryker_Feng
063d62c3c3
feat(persistence): support custom postgres schema ( #3442 )
...
* feat(persistence): support custom postgres schema
* fix(persistence): address CI lint/test failures and review feedback
- Map missing psycopg import to actionable POSTGRES_INSTALL guidance in
sync/async schema-creation helpers
- Accept SQLAlchemy compound DSN schemes (postgresql+asyncpg) when
injecting search_path, normalizing to a libpq-consumable DSN
- Guard keyword-DSN tests with importorskip so they skip without psycopg
- Set database=None in sync checkpointer none-fix test to avoid MagicMock
backend resolution
- Apply ruff import sort and format
* fix(persistence): address pg-schema review feedback
- Restrict postgres_schema regex to lowercase-only so the quoted CREATE
SCHEMA matches the unquoted search_path (PG case-folds it), fixing the
mixed-case bug where tables silently fell back to public.
- Replace shlex.join/split with libpq-correct backslash escaping for the
options parameter so values containing spaces survive intact.
- Add normalize_libpq_dsn() and route the async checkpointer pool through
dsn_with_search_path() so a +asyncpg suffix is stripped and existing DSN
options (e.g. statement_timeout) are merged instead of overridden.
- Extract shared ensure_postgres_schema()/ensure_postgres_schema_async()
helpers (mapping missing psycopg to the install hint) used by all four
provider sites.
- Tests: reject mixed-case schemas, preserve space-containing libpq option,
cover normalize_libpq_dsn, and assert pool search_path via DSN.
* fix(persistence): align pg-schema test with merged store API
The main merge moved the sync Store factory to the single-path
_resolve_store_config/_sync_store_cm design, dropping the PR's
_sync_store_from_database helper. The integration test still imported
the removed symbol, breaking test collection (backend-unit-tests).
Resolve the store config from a DatabaseConfig and drive it through
_sync_store_cm instead.
* fix(persistence): address pg-schema review feedback
- reject trailing/leading whitespace in postgres_schema via re.fullmatch
(a $-anchored re.match let "deerflow\n" through, silently landing tables
in public)
- re-escape all whitespace (TAB/CR/LF) when re-joining libpq options so a
caller's pre-existing options value round-trips losslessly
- re-validate the identifier inside create_schema_sql as defense-in-depth
at the SQL-emitting boundary
- accept the postgres:// short scheme in the alembic search_path injection
- close the sync psycopg connection explicitly (psycopg3 __exit__ does not
close()), mirroring the async path
- drop the partial checkpointer/store reset on a database config change;
database is restart-required and the ORM engine is not rebuilt, so a
partial reset would half-migrate the deployment
* docs(config): complete the postgres_schema migration checklist
Address PR review (P1): the documented `public`->schema migration only
moved runs, run_events, threads_meta, feedback, and users. That strands
every other DeerFlow-owned table -- the four channel_* tables, both
scheduled_* tables, agents, and (critically) alembic_version -- in
`public`. On restart bootstrap treats the partially-populated target
schema as unversioned, re-baselines it, and replays migrations while the
real rows stay invisible in `public`.
List the full owned set explicitly, call out alembic_version as required,
and keep the "discover the rest" query for version-drift safety.
* refactor(checkpointer): drop test-only _sync_checkpointer_from_database
Address PR review: the helper was only reached by the env-gated
integration test and re-implemented the DatabaseConfig->CheckpointerConfig
backend resolution that _resolve_checkpointer_config already owns, so a
future backend added there would silently miss this path. Mirror the store
side of the same test, which reuses the production path directly:
_resolve_checkpointer_config(...) + _sync_checkpointer_cm(...).
2026-07-30 13:51:17 +08:00
..
2026-07-29 18:52:32 +08:00
2026-07-22 14:02:56 +08:00
2026-07-19 18:26:26 +08:00
2026-07-29 22:33:45 +08:00
2026-05-12 23:18:54 +08:00
2026-07-26 14:43:08 +08:00
2026-04-26 15:09:25 +08:00
2026-06-01 15:50:39 +08:00
2026-07-28 23:21:23 +08:00
2026-07-21 11:46:33 +08:00
2026-06-21 20:56:42 +08:00
2026-06-08 12:35:03 +08:00
2026-07-22 14:47:08 +08:00
2026-07-17 15:11:15 +08:00
2026-07-22 13:44:55 +08:00
2026-07-23 08:03:21 +08:00
2026-07-23 08:03:21 +08:00
2026-07-22 13:44:55 +08:00
2026-07-21 09:09:40 +08:00
2026-07-30 07:12:07 +08:00
2026-07-27 07:47:39 +08:00
2026-07-30 07:53:10 +08:00
2026-06-23 10:39:40 +08:00
2026-07-30 13:51:17 +08:00
2026-07-19 07:31:29 +08:00
2026-05-29 23:05:59 +08:00
2026-05-16 09:24:40 +08:00
2026-04-26 11:08:11 +08:00
2026-07-27 14:19:04 +08:00
2026-07-18 22:17:15 +08:00
2026-07-26 09:52:16 +08:00
2026-07-23 22:51:35 +08:00
2026-07-17 14:49:51 +08:00
2026-07-17 14:49:51 +08:00
2026-07-27 14:19:04 +08:00
2026-07-23 22:51:35 +08:00
2026-07-23 22:51:35 +08:00
2026-06-24 13:57:12 +08:00
2026-07-28 23:21:23 +08:00
2026-07-28 23:21:23 +08:00
2026-07-27 11:47:49 +08:00
2026-07-30 07:53:10 +08:00
2026-07-26 08:00:48 +08:00
2026-07-02 11:00:49 +08:00
2026-07-21 11:46:33 +08:00
2026-07-21 11:46:33 +08:00
2026-07-28 07:56:04 +08:00
2026-07-14 07:37:59 +08:00
2026-06-16 23:04:39 +08:00
2026-06-18 10:15:31 +08:00
2026-07-12 08:54:03 +08:00
2026-07-25 21:55:31 +08:00
2026-07-17 14:49:51 +08:00
2026-06-18 10:45:33 +08:00
2026-07-27 23:07:40 +08:00
2026-07-29 08:08:33 +08:00
2026-07-28 22:12:27 +08:00
2026-07-28 23:21:23 +08:00
2026-07-26 10:44:50 +08:00
2026-07-28 23:21:23 +08:00
2026-07-12 08:15:32 +08:00
2026-07-30 13:51:17 +08:00
2026-07-28 19:43:56 +08:00
2026-03-30 07:41:18 +08:00
2026-04-25 19:40:06 +08:00
2026-04-07 18:21:22 +08:00
2026-07-22 14:02:56 +08:00
2026-07-23 22:51:35 +08:00
2026-07-29 22:16:48 +08:00
2026-07-29 22:16:48 +08:00
2026-05-04 09:56:16 +08:00
2026-07-28 23:21:23 +08:00
2026-05-02 15:04:11 +08:00
2026-06-10 21:36:25 +08:00
2026-07-22 08:33:29 +08:00
2026-07-29 22:24:04 +08:00
2026-07-26 07:39:39 +08:00
2026-04-26 11:05:47 +08:00
2026-07-05 09:54:55 +08:00
2026-03-29 15:31:18 +08:00
2026-07-22 08:33:29 +08:00
2026-05-07 16:15:15 +08:00
2026-06-12 15:24:58 +08:00
2026-07-22 07:46:03 +08:00
2026-07-23 22:56:12 +08:00
2026-07-17 19:16:42 +08:00
2026-06-08 07:59:50 +08:00
2026-07-29 06:50:19 +08:00
2026-07-13 17:57:34 +08:00
2026-06-02 22:43:22 +08:00
2026-06-05 15:21:41 +08:00
2026-07-12 00:17:11 +08:00
2026-07-04 23:09:29 +08:00
2026-06-02 22:43:22 +08:00
2026-07-01 22:49:17 +08:00
2026-07-13 19:26:07 +08:00
2026-07-22 08:33:29 +08:00
2026-07-28 23:21:23 +08:00
2026-07-04 09:21:19 +08:00
2026-07-22 13:55:40 +08:00
2026-07-29 22:33:45 +08:00
2026-07-26 09:56:17 +08:00
2026-07-29 22:33:45 +08:00
2026-06-09 15:29:40 +08:00
2026-07-27 14:19:39 +08:00
2026-06-12 15:24:58 +08:00
2026-06-13 23:27:17 +08:00
2026-03-31 22:19:27 +08:00
2026-07-29 08:08:33 +08:00
2026-07-26 07:39:39 +08:00
2026-07-28 22:59:14 +08:00
2026-07-30 07:53:10 +08:00
2026-04-26 11:09:56 +08:00
2026-07-29 07:04:26 +08:00
2026-04-08 17:13:39 +08:00
2026-07-05 09:54:55 +08:00
2026-07-21 11:46:33 +08:00
2026-07-14 10:43:13 +08:00
2026-07-17 11:18:20 +08:00
2026-07-02 08:24:15 +08:00
2026-07-04 21:31:01 +08:00
2026-07-19 22:12:30 +08:00
2026-07-14 11:57:48 +08:00
2026-07-25 23:18:34 +08:00
2026-07-22 08:33:29 +08:00
2026-07-29 00:09:02 +08:00
2026-07-26 08:09:17 +08:00
2026-07-27 23:17:18 +08:00
2026-07-28 23:21:23 +08:00
2026-07-28 23:21:23 +08:00
2026-07-18 17:50:20 +08:00
2026-07-28 23:21:23 +08:00
2026-07-04 22:56:24 +08:00
2026-07-04 22:56:24 +08:00
2026-07-04 22:56:24 +08:00
2026-07-27 23:07:40 +08:00
2026-07-04 22:56:24 +08:00
2026-07-14 22:56:50 +08:00
2026-07-04 22:56:24 +08:00
2026-07-04 22:56:24 +08:00
2026-07-16 09:12:29 +08:00
2026-07-23 14:32:49 +08:00
2026-07-15 22:30:34 +08:00
2026-07-28 21:45:20 +08:00
2026-06-21 15:55:10 +08:00
2026-07-23 21:33:57 +08:00
2026-03-14 22:55:52 +08:00
2026-07-06 07:21:12 +08:00
2026-07-27 22:46:51 +08:00
2026-07-27 14:05:31 +08:00
2026-07-10 11:08:30 +08:00
2026-07-27 23:07:40 +08:00
2026-03-26 14:20:18 +08:00
2026-06-28 16:10:44 +08:00
2026-07-08 17:10:27 +08:00
2026-07-22 14:02:56 +08:00
2026-07-04 13:54:04 +08:00
2026-06-17 15:29:22 +08:00
2026-07-22 14:47:08 +08:00
2026-06-08 23:25:29 +08:00
2026-07-12 11:51:31 +08:00
2026-06-10 16:11:00 +08:00
2026-07-28 22:54:44 +08:00
2026-07-28 22:54:44 +08:00
2026-07-29 07:11:20 +08:00
2026-07-30 07:21:55 +08:00
2026-07-28 23:21:23 +08:00
2026-07-23 08:22:15 +08:00
2026-07-23 22:56:12 +08:00
2026-04-11 16:52:10 +08:00
2026-07-20 23:33:09 +08:00
2026-07-09 17:21:25 +08:00
2026-07-03 07:51:22 +08:00
2026-07-13 00:01:22 +08:00
2026-07-30 07:53:10 +08:00
2026-07-13 00:01:22 +08:00
2026-07-04 13:54:04 +08:00
2026-07-03 08:01:46 +08:00
2026-04-30 22:27:14 +08:00
2026-05-07 16:15:15 +08:00
2026-07-19 17:13:44 +08:00
2026-07-26 14:43:08 +08:00
2026-07-19 22:12:30 +08:00
2026-07-03 15:39:12 +08:00
2026-07-09 16:26:31 +08:00
2026-04-25 09:18:13 +08:00
2026-07-25 21:43:33 +08:00
2026-07-22 19:58:43 +08:00
2026-07-10 07:54:36 +08:00
2026-07-09 16:26:31 +08:00
2026-07-09 16:26:31 +08:00
2026-07-28 22:59:14 +08:00
2026-07-28 21:31:23 +08:00
2026-06-25 22:57:00 +08:00
2026-07-14 09:49:43 +08:00
2026-07-29 07:11:20 +08:00
2026-07-26 21:16:36 +08:00
2026-07-22 14:40:57 +08:00
2026-07-26 21:16:36 +08:00
2026-07-22 07:46:03 +08:00
2026-07-28 22:59:14 +08:00
2026-07-15 11:21:04 +08:00
2026-07-26 21:16:36 +08:00
2026-07-26 21:16:36 +08:00
2026-07-27 23:17:18 +08:00
2026-07-29 07:11:20 +08:00
2026-07-15 11:21:04 +08:00
2026-07-26 21:16:36 +08:00
2026-07-22 07:46:03 +08:00
2026-07-22 07:46:03 +08:00
2026-07-22 07:46:03 +08:00
2026-04-26 11:09:55 +08:00
2026-07-29 07:11:20 +08:00
2026-07-15 11:21:04 +08:00
2026-07-28 23:14:00 +08:00
2026-07-22 14:02:56 +08:00
2026-07-26 21:16:36 +08:00
2026-07-26 21:16:36 +08:00
2026-07-28 21:45:20 +08:00
2026-07-28 21:45:20 +08:00
2026-07-27 23:07:40 +08:00
2026-07-04 13:54:04 +08:00
2026-07-17 14:23:44 +08:00
2026-03-22 20:39:26 +08:00
2026-07-22 13:44:55 +08:00
2026-07-26 14:43:08 +08:00
2026-07-26 14:43:08 +08:00
2026-07-24 22:41:07 +08:00
2026-07-27 23:07:40 +08:00
2026-07-26 21:45:47 +08:00
2026-07-28 21:45:20 +08:00
2026-06-22 18:55:20 +08:00
2026-07-18 17:48:42 +08:00
2026-06-21 15:47:53 +08:00
2026-05-28 08:20:52 +08:00
2026-07-29 07:24:55 +08:00
2026-07-11 16:05:30 +08:00
2026-07-04 21:44:22 +08:00
2026-05-28 18:24:32 +08:00
2026-06-08 22:04:38 +08:00
2026-03-26 15:07:05 +08:00
2026-06-09 18:01:43 +08:00
2026-07-26 08:09:17 +08:00
2026-06-24 13:57:12 +08:00
2026-07-28 21:45:20 +08:00
2026-06-24 13:57:12 +08:00
2026-07-28 21:45:20 +08:00
2026-06-24 13:57:12 +08:00
2026-07-30 13:51:17 +08:00
2026-07-28 21:45:20 +08:00
2026-07-30 13:51:17 +08:00
2026-06-24 13:57:12 +08:00
2026-07-30 13:51:17 +08:00
2026-05-21 16:22:09 +08:00
2026-07-30 13:51:17 +08:00
2026-07-29 08:08:33 +08:00
2026-07-30 13:51:17 +08:00
2026-04-26 11:13:01 +08:00
2026-07-20 07:24:34 +08:00
2026-04-10 20:40:30 +08:00
2026-07-26 08:09:17 +08:00
2026-07-28 22:54:44 +08:00
2026-07-14 07:51:59 +08:00
2026-07-21 09:23:14 +08:00
2026-07-06 20:57:41 +08:00
2026-07-30 07:53:10 +08:00
2026-07-30 07:53:10 +08:00
2026-03-14 22:55:52 +08:00
2026-03-14 22:55:52 +08:00
2026-07-03 08:01:46 +08:00
2026-07-28 22:54:44 +08:00
2026-06-08 17:32:41 +08:00
2026-06-09 21:58:31 +08:00
2026-07-14 23:08:33 +08:00
2026-07-11 15:58:07 +08:00
2026-07-25 23:50:21 +08:00
2026-06-24 17:47:04 +08:00
2026-07-02 07:43:09 +08:00
2026-04-26 15:09:25 +08:00
2026-07-26 21:45:47 +08:00
2026-07-23 21:33:57 +08:00
2026-07-28 21:31:23 +08:00
2026-07-28 23:29:14 +08:00
2026-07-26 21:57:39 +08:00
2026-07-28 21:31:23 +08:00
2026-05-21 14:48:28 +08:00
2026-07-28 21:45:20 +08:00
2026-07-27 22:27:16 +08:00
2026-07-27 22:27:16 +08:00
2026-07-27 11:32:10 +08:00
2026-07-28 21:45:20 +08:00
2026-07-20 07:54:15 +08:00
2026-06-24 10:24:36 +08:00
2026-07-22 08:33:29 +08:00
2026-07-19 22:12:30 +08:00
2026-07-23 22:56:12 +08:00
2026-07-23 22:56:12 +08:00
2026-05-22 21:20:28 +08:00
2026-06-25 22:43:28 +08:00
2026-06-03 22:02:27 +08:00
2026-07-30 07:53:10 +08:00
2026-04-09 17:21:23 +08:00
2026-07-26 09:47:57 +08:00
2026-07-21 09:09:40 +08:00
2026-07-13 18:34:41 +08:00
2026-06-25 08:06:17 +08:00
2026-07-28 07:49:13 +08:00
2026-07-30 07:53:10 +08:00
2026-07-04 13:54:04 +08:00
2026-06-12 10:20:38 +08:00
2026-07-04 21:51:57 +08:00
2026-07-24 21:41:09 +08:00
2026-07-04 21:51:57 +08:00
2026-07-04 21:51:57 +08:00
2026-07-24 21:41:09 +08:00
2026-07-04 21:51:57 +08:00
2026-07-04 21:51:57 +08:00
2026-07-04 21:51:57 +08:00
2026-07-29 23:12:41 +08:00
2026-06-12 09:45:26 +08:00
2026-07-21 23:41:07 +08:00
2026-06-19 11:23:07 +08:00
2026-03-26 14:20:18 +08:00
2026-07-21 08:15:33 +08:00
2026-06-27 23:30:54 +08:00
2026-07-07 23:09:06 +08:00
2026-07-23 08:03:21 +08:00
2026-05-12 23:18:54 +08:00
2026-07-23 08:03:21 +08:00
2026-07-05 19:55:39 +08:00
2026-06-19 21:57:03 +08:00
2026-07-04 23:09:29 +08:00
2026-07-04 11:27:19 +08:00
2026-07-04 11:27:19 +08:00
2026-07-04 23:09:29 +08:00
2026-07-20 08:18:23 +08:00
2026-07-13 10:40:22 +08:00
2026-05-28 15:48:32 +08:00
2026-07-17 14:39:35 +08:00
2026-07-28 21:31:23 +08:00
2026-07-24 21:25:53 +08:00
2026-07-11 15:58:07 +08:00
2026-07-04 13:54:04 +08:00
2026-07-16 14:12:02 +08:00
2026-03-25 16:28:33 +08:00
2026-07-16 14:12:02 +08:00
2026-07-07 21:44:28 +08:00
2026-07-19 22:36:15 +08:00
2026-07-16 14:12:02 +08:00
2026-07-04 23:09:29 +08:00
2026-07-17 23:22:16 +08:00
2026-07-21 09:39:44 +08:00
2026-07-24 21:25:53 +08:00
2026-07-21 00:02:16 +08:00
2026-06-18 10:09:46 +08:00
2026-07-08 21:58:33 +08:00
2026-07-29 22:39:48 +08:00
2026-07-28 22:59:14 +08:00
2026-03-30 16:02:23 +08:00
2026-06-12 15:24:58 +08:00
2026-07-22 09:20:54 +08:00
2026-07-27 07:13:06 +08:00
2026-06-14 10:30:45 +08:00
2026-06-08 23:17:22 +08:00
2026-07-14 08:14:21 +08:00
2026-07-28 23:29:14 +08:00
2026-07-24 21:56:11 +08:00
2026-07-30 07:21:55 +08:00
2026-07-30 07:21:55 +08:00
2026-05-02 06:37:49 +08:00
2026-07-11 15:41:57 +08:00
2026-07-11 15:41:57 +08:00
2026-07-13 19:26:07 +08:00
2026-06-19 21:42:42 +08:00
2026-07-28 19:35:21 +08:00
2026-07-26 07:39:39 +08:00
2026-07-07 19:55:33 +08:00
2026-07-27 11:47:49 +08:00
2026-07-27 11:47:49 +08:00
2026-07-29 08:08:33 +08:00
2026-06-24 07:28:17 +08:00
2026-07-23 22:56:12 +08:00
2026-05-21 21:18:10 +08:00
2026-06-18 10:15:31 +08:00
2026-07-28 07:49:13 +08:00
2026-07-11 15:53:14 +08:00
2026-07-28 22:59:14 +08:00
2026-07-27 22:46:51 +08:00
2026-07-27 22:46:51 +08:00
2026-07-27 22:18:02 +08:00
2026-07-28 22:15:09 +08:00
2026-07-29 12:47:30 +08:00
2026-07-27 22:46:51 +08:00
2026-06-02 22:43:22 +08:00
2026-07-22 08:33:29 +08:00
2026-05-22 21:42:14 +08:00
2026-07-28 23:21:23 +08:00
2026-07-29 12:47:30 +08:00
2026-07-08 14:41:16 +08:00
2026-07-15 11:21:04 +08:00
2026-03-14 22:55:52 +08:00
2026-07-11 23:15:03 +08:00
2026-06-12 22:48:47 +08:00
2026-07-08 22:26:06 +08:00
2026-07-04 23:14:46 +08:00
2026-05-10 22:00:57 +08:00
2026-06-23 23:37:41 +08:00
2026-07-28 23:21:23 +08:00
2026-07-27 22:46:51 +08:00
2026-05-19 22:11:46 +08:00
2026-07-28 23:29:14 +08:00
2026-07-04 11:27:19 +08:00
2026-07-16 16:41:04 +08:00
2026-04-06 15:09:57 +08:00
2026-07-06 20:57:41 +08:00
2026-07-06 20:57:41 +08:00
2026-07-12 11:24:24 +08:00
2026-07-14 09:49:43 +08:00
2026-07-19 09:13:51 +08:00
2026-07-19 09:13:51 +08:00
2026-07-14 08:58:06 +08:00
2026-07-14 08:58:06 +08:00
2026-07-03 08:01:46 +08:00
2026-07-22 07:53:50 +08:00
2026-06-25 20:10:49 +08:00
2026-06-25 20:10:49 +08:00
2026-07-22 07:53:50 +08:00
2026-06-25 20:10:49 +08:00
2026-06-25 20:10:49 +08:00
2026-06-25 20:10:49 +08:00
2026-06-25 20:10:49 +08:00
2026-06-25 20:10:49 +08:00
2026-06-25 20:10:49 +08:00
2026-06-25 20:10:49 +08:00
2026-06-25 20:10:49 +08:00
2026-07-15 22:27:00 +08:00
2026-06-25 20:10:49 +08:00
2026-07-20 23:56:37 +08:00
2026-05-12 23:18:54 +08:00
2026-07-23 08:03:21 +08:00
2026-07-26 21:16:36 +08:00
2026-07-26 21:16:36 +08:00
2026-07-01 16:43:56 +08:00
2026-07-28 22:59:14 +08:00
2026-07-28 23:41:14 +08:00
2026-07-28 22:59:14 +08:00
2026-07-29 22:39:48 +08:00
2026-07-11 09:18:12 +08:00
2026-07-14 10:43:13 +08:00
2026-05-02 15:16:16 +08:00
2026-06-09 15:29:40 +08:00
2026-07-22 08:41:50 +08:00
2026-07-24 13:12:43 +08:00
2026-07-28 19:56:40 +08:00
2026-07-27 07:13:06 +08:00
2026-07-06 07:21:12 +08:00
2026-07-20 23:05:47 +08:00
2026-07-18 17:53:30 +08:00
2026-07-12 07:52:45 +08:00
2026-07-28 21:45:20 +08:00
2026-07-28 21:45:20 +08:00
2026-07-12 11:51:31 +08:00
2026-07-27 22:27:16 +08:00
2026-06-07 17:47:11 +08:00