Skip to content

Commit f446f79

Browse files
JustinASmithclaude
andcommitted
source-shopify-native: persist migrated endpoint config to control plane
When legacy single-store config is transformed to multi-store format, emit a config_update event so the control plane persists the new format. This ensures the UI shows the correct format when editing the capture. - Add _was_migrated PrivateAttr to track config migration - Update model_validator to set migration flag when transforming - Emit config_update event in open() when config was migrated 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 8ed143f commit f446f79

File tree

2 files changed

+29
-4
lines changed

2 files changed

+29
-4
lines changed

source-shopify-native/source_shopify_native/__init__.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
from logging import Logger
2+
3+
from estuary_cdk.logger import FlowLogger
24
from typing import Callable, Awaitable
35

46
from estuary_cdk.flow import (
@@ -206,17 +208,28 @@ async def validate(
206208

207209
async def open(
208210
self,
209-
log: Logger,
211+
log: FlowLogger,
210212
open: request.Open[EndpointConfig, ResourceConfig, ConnectorState],
211213
) -> tuple[response.Opened, Callable[[Task], Awaitable[None]]]:
214+
config = open.capture.config
215+
216+
# Persist migrated config so UI shows the new format
217+
if config._was_migrated:
218+
log.info("Persisting migrated config to multi-store format")
219+
encrypted_config = await self._encrypt_config(log, config)
220+
log.event.config_update(
221+
"Migrating legacy single-store config to multi-store format.",
222+
encrypted_config
223+
)
224+
212225
# Determine key structure from existing bindings
213226
use_multi_store_keys = _should_use_multi_store_keys(
214227
open.capture.bindings,
215-
len(open.capture.config.stores),
228+
len(config.stores),
216229
)
217230

218231
resources = await all_resources(
219-
log, self, open.capture.config,
232+
log, self, config,
220233
should_cancel_ongoing_job=True,
221234
use_multi_store_keys=use_multi_store_keys,
222235
)

source-shopify-native/source_shopify_native/models.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
TypeVar,
1313
Generic,
1414
)
15-
from pydantic import AwareDatetime, BaseModel, Field, model_validator
15+
from pydantic import AwareDatetime, BaseModel, Field, PrivateAttr, model_validator
1616

1717
from estuary_cdk.capture.common import (
1818
AccessToken,
@@ -132,6 +132,10 @@ class Advanced(BaseModel):
132132
json_schema_extra={"advanced": True},
133133
)
134134

135+
# Track whether config was migrated from legacy format.
136+
# Used to persist the new format back to the control plane.
137+
_was_migrated: bool = PrivateAttr(default=False)
138+
135139
@model_validator(mode="before")
136140
@classmethod
137141
def transform_legacy_config(cls, data: Any) -> Any:
@@ -142,6 +146,8 @@ def transform_legacy_config(cls, data: Any) -> Any:
142146
143147
New format:
144148
{"stores": [{"store": "mystore", "credentials": {...}}], "start_date": "..."}
149+
150+
Sets _was_migrated flag so the connector can persist the new format.
145151
"""
146152
if not isinstance(data, dict):
147153
return data
@@ -154,9 +160,15 @@ def transform_legacy_config(cls, data: Any) -> Any:
154160
store = data.pop("store")
155161
credentials = data.pop("credentials")
156162
data["stores"] = [{"store": store, "credentials": credentials}]
163+
data["_was_migrated"] = True
157164

158165
return data
159166

167+
def __init__(self, **data: Any) -> None:
168+
was_migrated = data.pop("_was_migrated", False)
169+
super().__init__(**data)
170+
self._was_migrated = was_migrated
171+
160172

161173
ConnectorState = GenericConnectorState[ResourceState]
162174

0 commit comments

Comments
 (0)