Resolve the Couchbase scope and collection through a single helper built on
compute_table_id, so that with registry.enable_online_feature_view_versioning
enabled each feature view version gets its own scope and collection
(test_project_driver_stats_v2_scope) instead of all versions sharing one.
Couchbase already namespaced by {project}_{table.name}, so this follows the
same compute_table_id convention as the Milvus and FAISS stores and the name
is unchanged when versioning is disabled.
Document ids are deliberately left unversioned: a Couchbase collection is
already a namespace, so partitioning at the collection level is enough to keep
versions from colliding, and existing ids stay stable.
Couchbase's online_read honours the OnlineStore contract - one entry per
requested entity key, in order, holding ValueProto values, (None, None) on a
miss - so CouchbaseOnlineStore is added to the versioned-read allowlist.
Also adds Milvus to the VersionedOnlineReadNotSupported message, which has
listed it as unsupported since it was allowlisted.
Part of feast-dev#2728. Closes feast-dev#6171
Signed-off-by: arose26 <145766958+arose26@users.noreply.github.com>
Closes #6171. Part of #2728.
What this does
Resolves the Couchbase scope and collection through a single _scope_and_collection
helper, so that with registry.enable_online_feature_view_versioning: true each feature
view version gets its own scope and collection
(test_project_driver_stats_v2_scope / ..._v2_collection) instead of all versions
sharing one. Applied to all four call sites — online_write_batch, online_read,
update, teardown.
Couchbase already namespaced by {project}_{table.name}, so this uses
compute_table_id, the same convention as the merged Milvus (#6330) and FAISS
(#6256) stores. With versioning disabled the names are byte-identical to today's, which
the versioning=False cases pin.
Two decisions worth calling out
Document ids are left unversioned. _document_id still returns
{project}:{table.name}:{entity_key}:{feature}. A Couchbase collection is already a
namespace, so partitioning at the collection level is sufficient to keep versions from
colliding, and leaving ids alone keeps them stable for existing data. Happy to version
them too if you'd rather have the version visible in the key.
Couchbase is added to the versioned-read allowlist in
OnlineStore._is_versioned_read_supported(). I checked the read path rather than
assuming: CouchbaseOnlineStore.online_read honours the OnlineStore contract as
sqlite.py defines it — one entry per requested entity key, in request order, holding
ValueProto values parsed from the stored payload, and (None, None) on
DocumentNotFoundException. So versioned reads genuinely work here once the collection
is version-scoped.
Drive-by: a stale error message
VersionedOnlineReadNotSupported listed "SQLite, PostgreSQL, MySQL, FAISS, Redis, and
DynamoDB" — but _is_versioned_read_supported() has included MilvusOnlineStore since
#6330, which updated online_store.py without touching errors.py. So the message has
been telling Milvus users their store is unsupported while the code supported it. Added
Milvus alongside Couchbase. Happy to split this into its own PR if you'd prefer.
Tests
New sdk/python/tests/unit/infra/online_store/test_couchbase_versioning.py, 11 tests,
MagicMock-based in the same style as the merged test_milvus_versioning.py, and
importorskip-guarded on couchbase.
projection.version_tag takes priority over current_version_number; version 0 gets
no suffix; two versions never collide
versioned scope — parametrized so the unversioned case is asserted as the control
no longer raises for a version-qualified ref
Verified red-before/green-after: with the three source files reverted, the four
behavioural tests fail and the versioning=False control still passes, so they test the
change rather than the setup.
Regression check across the 55 unit test files touching online stores or versioning: the
set of failing and erroring tests is identical with and without this change (diff of
the sorted FAILED/ERROR lines is empty). Those pre-existing failures are missing
optional dependencies in my environment. ruff check, ruff format and mypy are clean
on all four files.
🤖 Written with Claude Code (Claude Opus 5), reviewed by @arose26.