Add SearchIndex entity and Search Management API#1391
Draft
BryanFauble wants to merge 1 commit into
Draft
Conversation
- New SearchIndex entity model wired through entity_factory and the async-job URI map; columns are derived read-only from defining_sql. - Search Management API surface in api/search_services.py: TextAnalyzer, ColumnAnalyzerOverride, SynonymSet, SearchConfiguration, SearchConfigBinding, autocomplete_search. - SearchIndexQuery dataclass riding the AsynchronousCommunicator mixin for /search/query/async, plus SearchQuery and supporting filter/facet dataclasses. - Internal models/services/search_setup helpers for upserting the synonym-aware analyzer chain (SynonymSet -> TextAnalyzer clone -> SearchConfiguration). - Unit coverage for every public function and dataclass round-trip. - Integration coverage for the SearchIndex entity lifecycle and the read-only Search Management endpoints; write endpoints gated behind SYNAPSE_SAGE_EMPLOYEE_TOKEN.
Contributor
There was a problem hiding this comment.
Pull request overview
Adds first-class client support for Synapse’s new OpenSearch-backed SearchIndex entity, along with a thin async Search Management API surface, corresponding request/response dataclasses, and helper utilities for synonym-aware analyzer/configuration setup.
Changes:
- Introduces
SearchIndexentity model plus async job modelSearchIndexQueryfor/search/query/async. - Adds
api/search_services.py(SearchManagementController endpoints) and internalmodels/services/search_setup.pyhelpers for synonym/analyzer/config stitching. - Registers new concrete types and wires them into entity factory + async job routing, with unit/integration test coverage.
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
synapseclient/api/__init__.py |
Re-exports new Search Management service functions from the API surface. |
synapseclient/api/entity_factory.py |
Registers SEARCH_INDEX_ENTITY → SearchIndex in entity type dispatch. |
synapseclient/api/search_services.py |
Adds thin async wrappers for SearchManagementController endpoints + autocomplete. |
synapseclient/core/constants/concrete_types.py |
Adds concrete types for SearchIndex entity and SearchIndexQuery async job. |
synapseclient/models/__init__.py |
Exports SearchIndex and search management/query models publicly. |
synapseclient/models/mixins/asynchronous_job.py |
Routes SEARCH_INDEX_QUERY to /search/query/async in async job URI map. |
synapseclient/models/mixins/table_components.py |
Marks SearchIndex as having read-only schema in table mixin config. |
synapseclient/models/search_index.py |
Implements the new SearchIndex entity model and async CRUD behavior. |
synapseclient/models/search_management.py |
Adds dataclasses/enums for search management resources and async query request/response shapes. |
synapseclient/models/services/search_setup.py |
Adds idempotent helpers to create/find synonym sets, analyzers, and search configurations. |
tests/integration/synapseclient/models/async/test_search_index_async.py |
Integration coverage for SearchIndex lifecycle + read-only search management endpoints. |
tests/unit/synapseclient/api/unit_test_search_services.py |
Unit tests validating verb/URI/body shapes for the new service functions. |
tests/unit/synapseclient/models/async/unit_test_search_index_async.py |
Unit tests for SearchIndex serialization, change tracking, and store validation. |
tests/unit/synapseclient/models/async/unit_test_search_management_async.py |
Unit tests for search management dataclass round-trips and async communicator wiring. |
tests/unit/synapseclient/models/async/unit_test_search_setup_async.py |
Unit tests for analyzer/synonym setup helper behaviors and error paths. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+119
to
+126
| overrides: List[Tuple[str, str]] = [] | ||
| for column_name, column_type in columns.items(): | ||
| system_default = COLUMN_TYPE_TO_DEFAULT_ANALYZER_QNAME.get(column_type) | ||
| if system_default is None: | ||
| continue | ||
| target = substitutions.get(system_default, system_default) | ||
| if system_default == default_substitutes_system_qname: | ||
| continue |
Comment on lines
+139
to
+141
| if kind == EQUIVALENT: | ||
| synonyms.append(", ".join(terms)) | ||
| elif kind == EXPLICIT: |
| for token in ( | ||
| "unsupported entity type", | ||
| "concretetype", | ||
| "not allowed", |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds support for the new
SearchIndexSynapse entity (an OpenSearch-backed full-text / faceted / autocomplete index over a SQL-defined view of any table-like Synapse entity), theSearchManagementControllerREST surface that powers it, and an internal helper module for stitching its analyzer/synonym configuration together.Production changes
New
api/search_services.py— 20 thin async functions over theSearchManagementController:create_/get_/update_/list_text_analyzer{,s}create_/get_/update_/list_column_analyzer_override{,s}create_/get_/update_/list_synonym_set{,s}create_/get_/update_/list_search_configuration{,s}bind_search_config_to_entity,get_search_config_binding,clear_search_config_bindingautocomplete_searchNew
models/search_index.py—SearchIndexentity dataclass following the existingVirtualTable/MaterializedViewpattern: dataclass +@async_to_sync, inlineSearchIndexSynchronousProtocol, mixin composition (AccessControllable,TableBase,TableStoreMixin,DeleteMixin,GetMixin,QueryMixin). Columns are read-only and derived fromdefining_sql.store_asyncraisesValueErrorifdefining_sqlis missing.New
models/search_management.py— 14 dataclasses + 5 enums covering the request/response shapes:TextAnalyzer,ColumnAnalyzerOverride{,Entry},SynonymSet,SearchConfiguration,SearchConfigBindingSearchIndexStatus,SearchIndexStateSearchQuery,SearchQueryType,SearchQueryPart,KeyValues,KeyRange,FacetRequest,FacetSortField,SortField,SortDirection,SearchHit,SearchFieldValueSearchIndexQueryriding theAsynchronousCommunicatormixin for/search/query/asyncNew
models/services/search_setup.py— internal-only helpers for the synonym-aware analyzer chain (SynonymSet → cloned TextAnalyzer with $ref → SearchConfiguration with column overrides). Includesclone_settings_with_search_synonymsfor splicing the synonym filter into a system analyzer'sdefault_searchchain so synonyms are expanded at search time only.3-way registration per the existing concrete-type convention:
core/constants/concrete_types.py— addsSEARCH_INDEX_ENTITYandSEARCH_INDEX_QUERYapi/entity_factory.py— addsSEARCH_INDEX_ENTITY → SearchIndexin the type dispatch mapmodels/mixins/asynchronous_job.py— addsSEARCH_INDEX_QUERY → /search/query/asyncinASYNC_JOB_URISmodels/mixins/table_components.py— addsSearchIndextoCLASSES_WITH_READ_ONLY_SCHEMAmodels/__init__.py— public exports for the new symbolsapi/__init__.py— re-exports the new service functionsTest plan
Unit tests (98 new, all passing)
tests/unit/synapseclient/api/unit_test_search_services.py— 21 tests covering URI/body/verb for every service function andNone-stripping for list endpointstests/unit/synapseclient/models/async/unit_test_search_index_async.py— 11 tests covering field defaults,fill_from_dictround-trip,to_synapse_requestshape,store_asyncvalidation, super-method delegationtests/unit/synapseclient/models/async/unit_test_search_management_async.py— 41 tests covering every dataclass round-trip, enum coercion,$refnormalization, and theSearchIndexQuery → AsynchronousCommunicatorwiringtests/unit/synapseclient/models/async/unit_test_search_setup_async.py— 25 tests covering rule rendering, settings cloning (with all error-path branches), column override derivation, paginated find-by-name, idempotentensure_*helpersIntegration tests (
tests/integration/synapseclient/models/async/test_search_index_async.py)TestSearchIndexEntity— full create/get/update/delete lifecycle against a live server, with feature-detection skip if the server doesn't yet expose the entity typeTestSearchManagementReadEndpoints—list_text_analyzers+get_text_analyzeragainst the bootstrappedorg.sagebionetworkssystem analyzers (any authenticated caller can hit these)TestSearchManagementWriteEndpoints— gated behindSYNAPSE_SAGE_EMPLOYEE_TOKEN; placeholder for when Sage-employee CI auth is wired uppre-commit run --all-files— clean (ruff, isort, black, bandit)pytest -sv tests/unit/synapseclient/api tests/unit/synapseclient/models— 1167 passing, 0 regressionsNotes
project_setting_servicesimports inapi/__init__.pythat had been accidentally deleted in the original feature branch.SearchManagementControllerwrite endpoints (create/update of TextAnalyzer / ColumnAnalyzerOverride / SynonymSet / SearchConfiguration) are restricted to Sage Bionetworks employees server-side. Integration coverage for those endpoints is gated behindSYNAPSE_SAGE_EMPLOYEE_TOKEN; the unit tests cover the wire format unconditionally.