Skip to content

Target naming phase 1#2809

Open
jshearer wants to merge 2 commits intomasterfrom
jshearer/target_naming
Open

Target naming phase 1#2809
jshearer wants to merge 2 commits intomasterfrom
jshearer/target_naming

Conversation

@jshearer
Copy link
Copy Markdown
Contributor

@jshearer jshearer commented Mar 25, 2026

Summary

Phase 1 of the target naming redesign (#2780). This PR adds TargetNamingStrategy as a new top-level field on MaterializationDef, decoupling naming behavior from SourceDef so that materializations without a sourceCapture can express a naming preference.

What changed

TargetNamingStrategy is a tagged-object enum with three variants:

  • matchSourceStructure: schema from collection name, table is the final component
  • singleSchema { schema }: all tables in one named schema
  • prefixTableNames { schema, skipCommonDefaults }: schema component prefixed to table name

The existing SourceDef.target_naming enum is preserved as a fallback. When both MaterializationDef.target_naming and source.target_naming are present, the top-level field wins for naming; delta_updates is always read from source. The next phase of work is a migration to populate the remaining materializations' root target_naming based on knowledge of each connector's endpoint-config schema location and default.

Auto-promotion on publish

When a materialization has source.targetNaming: withSchema and no top-level target_naming, the validation layer promotes it to targetNaming: { strategy: "matchSourceStructure" } as a model fix. This is the only variant that doesn't require extracting a schema value from the connector's endpoint config, so it's the only one promoted in this phase. Other variants (noSchema, prefixSchema, prefixNonDefaultSchema) remain on SourceDef.target_naming until Phase 2 extracts the endpoint config schema.

WASM API

The update_materialization_resource_spec WASM function now accepts targetNaming alongside sourceCapture, both optional. sourceCapture is optional because not all materializations have one, not because it's being replaced. Existing UI code that sends sourceCapture continues to work unchanged.

Note on flow.schema.json

The regenerated schema includes Triggers, TriggerConfig, and HttpMethod types that were already in the models but missing from the previously-stale flow.schema.json. These are unrelated to this PR.

@jshearer jshearer self-assigned this Mar 25, 2026
@jshearer jshearer marked this pull request as ready for review March 25, 2026 16:42
@jshearer jshearer force-pushed the jshearer/target_naming branch 2 times, most recently from 6ae3c5a to a9348ac Compare March 25, 2026 19:00
`TargetNaming` lives inside `SourceDef`, so materializations without a sourceCapture cannot express a naming preference, and the string-enum variants carry no schema parameter. This adds `target_naming: Option<TargetNamingStrategy>` directly on `MaterializationDef` with three variants: `matchSourceStructure`, `singleSchema { schema }`, and `prefixTableNames { schema, skipCommonDefaults }`.

* All variants require the connector to support `x-schema-name` in its resource config schema. The old `SourceDef.target_naming` is preserved as a legacy fallback for unmigrated specs.
* On publish, `source.targetNaming: withSchema` is auto-promoted to `targetNaming: matchSourceStructure`
@jshearer jshearer force-pushed the jshearer/target_naming branch from a9348ac to ba73cac Compare March 25, 2026 19:52
@jshearer jshearer requested review from a team and mdibaiee March 30, 2026 16:52
Comment on lines +130 to +139
if target_naming.is_none() {
if let Some(source) = &sources {
if source.to_normalized_def().target_naming == models::TargetNaming::WithSchema {
target_naming = Some(models::TargetNamingStrategy::MatchSourceStructure);
model_fixes.push(
"promoted source.targetNaming 'withSchema' to top-level targetNaming 'matchSourceStructure'".to_string(),
);
}
}
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

am I right that this is going to still retain source.targetNaming while adding the new top-level targetNaming? Can we get rid of the old one automatically as well?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The intent is that it will leave source.targetNaming alone specifically in order to allow this to be progressively released. For example, in update_materialization_resource_spec() we first check if the new targetNaming exists, then fall back to the original check against source.targetNaming.

The intent is to allow this PR to be released, then the UI to be updated to use the new targetNaming, though I'm realizing as I write that that we actually need to split this up even further: we need to introduce the new targetNaming without even this trivial upgrade, then the UI needs to be updated to handle it, then we can introduce the model fix(es). Reason being, otherwise we would do this one-time upgrade, but the UI would continue to use source.targetNaming.

I will remove this model fix until the UI is updated

@travjenkins
Copy link
Copy Markdown
Member

I have not yet fully taken a look here or messed with it locally. But want to know about the auto promotion during publish.

If this literally moves the setting our of source I think that will be an issue if the UI is not also released around the same time. Moving that up would mean we do not know what to show as the option.

Also - we renamed that prop a bit ago - so we might also want to promote fromSourceName (not sure anyone is actually using that one anymore).
image

We need to ship the pure model update so that clients can be updated to use it progressively (i.e the UI should present and edit it if present, otherwise it should use the existing field)
@jshearer
Copy link
Copy Markdown
Contributor Author

jshearer commented Mar 31, 2026

@travjenkins does this answer your question? The intent is to thread the needle of deploying this without breaking anything:

  1. First, we'll merge this PR which will add MaterializationDef.targetNaming as a field. If present, it will be used by the control plane over source.targetNaming, for example to figure out what schema to use for auto-discovered bindings. If it's not present but source.targetNaming is, the control plane will continue to use that behavior as a fallback.
  2. Then, we'll need to update the UI. If targetNaming is present on the root of the materialization, it should use that instead of source.targetNaming (i.e opt into the new way of presenting target naming). Otherwise, it should use the existing source.targetNaming flow as it currently does. This will allow us to both automatically upgrade some tasks (what the model fix was doing in this PR originally), and run the migration to progressively upgrade.
    • Eventually, the UI should also start showing this new target naming flow for newly created materializations, but so long as we support both, we can always migrate tasks later as we want to
  3. Then we'll update the control plane to automatically upgrade those tasks that are trivial to auto-upgrade
  4. Then we'll run the migration to upgrade all of the remaining tasks
  5. Then the UI can start to ignore source.targetNaming
  6. then the control plane can remove it

@travjenkins
Copy link
Copy Markdown
Member

Okay - that generally tracks in my mind and basically how we did this before. And I will try to ensure the UI uses the new stuff in create all the time.

The UI also previously migrated things if a user edited a task. We can chat about if we want to do that or not.

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.

3 participants