Skip to content

Extract shared types and mutation backends from sdk/mpr#233

Closed
retran wants to merge 6 commits intomendixlabs:mainfrom
retran:feature/shared-types
Closed

Extract shared types and mutation backends from sdk/mpr#233
retran wants to merge 6 commits intomendixlabs:mainfrom
retran:feature/shared-types

Conversation

@retran
Copy link
Copy Markdown
Contributor

@retran retran commented Apr 19, 2026

Summary

  • Extract ~15 shared types from sdk/mpr into mdl/types/ so backend interfaces no longer depend on the SDK package
  • Define mutation backend interfaces (PageMutator, WorkflowMutator, WidgetObjectBuilder, DataGrid2Builder) that encapsulate all BSON manipulation behind the mdl/backend abstraction
  • Migrate all executor handlers off direct sdk/mpr imports — the executor now operates entirely through backend interfaces
  • Decouple the executor from the storage layer: remove *mpr.Writer/*mpr.Reader fields from Executor, inject BackendFactory instead

Why

The executor was tightly coupled to sdk/mpr — every handler imported BSON types and manipulated raw documents directly. This made it impossible to swap storage backends (e.g., for WASM compilation where CGO/BSON drivers are unavailable) and made handler testing require real MPR files.

What changed

New packages:

  • mdl/types/ — shared domain types (ID utilities, navigation, java, mapping, EDMX, AsyncAPI, JSON helpers)
  • mdl/bsonutil/ — CGO-free BSON binary conversion utilities

Backend interfaces (mdl/backend/mutation.go):

  • PageMutator — all page/widget BSON manipulation (1554 lines of implementation)
  • WorkflowMutator — workflow activity/branch BSON manipulation (771 lines)
  • WidgetObjectBuilder / WidgetBuilderBackend — widget object construction (1007 lines)
  • DataGrid2Builder — datagrid2 column/filter widget construction (1260 lines)

Executor simplification:

  • ALTER PAGE: 1721 → 256 lines
  • ALTER WORKFLOW: 887 → 178 lines
  • Net ~3000 lines removed from executor, all BSON encapsulated in backend

Commits

  1. Extract shared types and utility functions to mdl/types
  2. Define mutation backend interfaces with stub implementations
  3. Implement mutation backends and migrate handlers off sdk/mpr
  4. Decouple executor from storage layer, extract remaining BSON
  5. Code quality improvements (deterministic output, doc comments, naming consistency)

Depends on

PR #232 (feature/mock-handler-tests) — this branch includes those commits. Merge #232 first, then rebase this PR.

retran added 6 commits April 19, 2026 15:06
Phase 1-8: 85 read/write handler tests with mock backend infrastructure
Error paths: 49 tests covering backend error propagation for all handler groups
Not-connected: 29 tests verifying Connected/ConnectedForWrite guards
JSON format: 26 tests validating JSON output for show/list handlers

Production code changes:
- Added Func fields to MockBackend for 8 agent-editor write methods
- Fixed ContainerID parameter semantics in withContainer and all call sites
Create mdl/types/ package with WASM-safe shared types extracted from
sdk/mpr: domain model types, ID utilities, EDMX/AsyncAPI parsing,
JSON formatting helpers. Migrate all executor handlers to use
mdl/types directly, removing type aliases from sdk/mpr/reader_types.go.

- Extract 16+ domain types to mdl/types/ (infrastructure, java,
  navigation, mapping)
- Extract GenerateID, BlobToUUID, ValidateID to mdl/types/id.go
- Extract ParseEdmx, ParseAsyncAPI to mdl/types/edmx.go, asyncapi.go
- Extract PrettyPrintJSON, BuildJsonElementsFromSnippet to json_utils.go
- Migrate 30+ executor handler files off sdk/mpr type references
- sdk/mpr retains thin delegation wrappers for backward compatibility
Add PageMutator, WorkflowMutator, WidgetSerializationBackend interfaces
to mdl/backend/mutation.go for BSON-free handler decoupling. Extract
BSON ID helpers (IDToBsonBinary, BsonBinaryToID, NewIDBsonBinary) to
mdl/bsonutil/ package. Add panic stubs to MprBackend and mock function
fields to MockBackend for all new interface methods.

- Create mdl/bsonutil/bsonutil.go with BSON ID conversion utilities
- Migrate 10 handler files from mpr.IDToBsonBinary to bsonutil.*
- Define PageMutationBackend, WorkflowMutationBackend interfaces
- Define WidgetSerializationBackend with opaque return types
- Add PluggablePropertyContext for domain-typed widget property input
Implement PageMutator, WorkflowMutator, and WidgetBuilderBackend in
mdl/backend/mpr/. Rewrite ALTER PAGE (1721→256 lines) and ALTER
WORKFLOW (887→178 lines) as thin orchestrators using mutator sessions.
Implement PluggableWidgetEngine with WidgetObjectBuilder interface,
eliminating all BSON from widget_engine.go.

- Create mdl/backend/mpr/page_mutator.go (1554 lines)
- Create mdl/backend/mpr/workflow_mutator.go (771 lines)
- Create mdl/backend/mpr/widget_builder.go (1007 lines)
- Migrate SerializeWidget/ClientAction/DataSource to backend interface
- Add ParseMicroflowFromRaw to MicroflowBackend interface
- Delete widget_operations.go, widget_templates.go, widget_defaults.go
- Move ALTER PAGE/WORKFLOW tests to backend/mpr/ package
Replace *mpr.Reader/*mpr.Writer with backend.FullBackend throughout
executor. Inject BackendFactory to remove mprbackend import from
executor_connect.go. Move all remaining write-path BSON construction
(DataGrid2, filters, cloning, widget property updates) behind backend
interface.

- Remove writer/reader fields from Executor struct
- Add BackendFactory injection pattern for connect/disconnect
- Create mdl/backend/mpr/datagrid_builder.go (1260 lines)
- Add BuildDataGrid2Widget, BuildFilterWidget to WidgetBuilderBackend
- Delete bson_helpers.go, cmd_pages_builder_input_cloning.go,
  cmd_pages_builder_input_datagrid.go, cmd_pages_builder_v3_pluggable.go
- Remaining BSON: 3 read-only files (describe, diff) — WASM-safe
…naming consistency

Ensure deterministic map iteration order for serialization output.
Add doc comments on all exported backend interfaces.
Deduplicate IDToBsonBinary into single mdl/bsonutil implementation.
Rename reader references to backend across executor.
Guard float64-to-int64 cast with safe precision bounds.
Apply go fmt formatting.
Copilot AI review requested due to automatic review settings April 19, 2026 17:32
@retran
Copy link
Copy Markdown
Contributor Author

retran commented Apr 19, 2026

Splitting into stacked PRs for reviewability — diff exceeded GitHub's 20k line limit.

@retran retran closed this Apr 19, 2026
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR decouples the MDL executor and backend interfaces from sdk/mpr by moving shared domain types into mdl/types and introducing backend mutation/builder interfaces so handlers no longer manipulate raw BSON directly.

Changes:

  • Replace direct sdk/mpr type usage across executor/catalog/backend with mdl/types.
  • Route page/workflow/widget mutations through backend mutator/builder interfaces (e.g., OpenPageForMutation, WidgetBuilderBackend).
  • Add extensive mock-backend based executor tests and introduce CGO-free BSON ID conversion helpers (mdl/bsonutil).

Reviewed changes

Copilot reviewed 112 out of 155 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
mdl/executor/cmd_widgets.go Switch widget property updates to PageMutator instead of raw BSON.
mdl/executor/cmd_structure.go Read constants/scheduled events counts via backend instead of reader.
mdl/executor/cmd_settings_mock_test.go Add mock-backend tests for settings output.
mdl/executor/cmd_security_write.go Migrate security write path to mdl/types and adjust error wrapping.
mdl/executor/cmd_security_mock_test.go Add mock-backend tests for security SHOW/DESCRIBE commands.
mdl/executor/cmd_rest_clients_mock_test.go Add mock-backend tests for REST clients.
mdl/executor/cmd_rename.go Replace mpr.RenameHit usage with types.RenameHit.
mdl/executor/cmd_published_rest_mock_test.go Add mock-backend tests for published REST services.
mdl/executor/cmd_pages_mock_test.go Add mock-backend tests for pages/snippets/layouts listing.
mdl/executor/cmd_pages_create_v3.go Build pages/snippets via injected backend + widget backend.
mdl/executor/cmd_pages_builder_v3_pluggable.go Remove BSON-heavy pluggable widget builder implementation.
mdl/executor/cmd_pages_builder_v3_layout.go Generate IDs via types.GenerateID() instead of mpr.GenerateID().
mdl/executor/cmd_pages_builder_input_filters.go Remove BSON filter widget building (moved behind backend builder).
mdl/executor/cmd_pages_builder_input_cloning.go Remove BSON deep-cloning helpers (moved behind backend).
mdl/executor/cmd_pages_builder_input.go Replace reader-based listing with backend-based listing for snippets/microflows.
mdl/executor/cmd_pages_builder.go Refactor pageBuilder to use backend.FullBackend + widget backend abstraction.
mdl/executor/cmd_odata_mock_test.go Add mock-backend tests for OData clients/services.
mdl/executor/cmd_odata.go Use types.GenerateID / types.ParseEdmx to avoid sdk/mpr dependency.
mdl/executor/cmd_notconnected_mock_test.go Add mock-backend “not connected” tests for many handlers.
mdl/executor/cmd_navigation_mock_test.go Add mock-backend tests for navigation output.
mdl/executor/cmd_navigation.go Switch navigation types/specs from mpr to types.
mdl/executor/cmd_modules_mock_test.go Add mock-backend test for SHOW MODULES.
mdl/executor/cmd_misc_mock_test.go Add mock-backend test for SHOW VERSION via types.ProjectVersion.
mdl/executor/cmd_microflows_mock_test.go Add mock-backend tests for microflows/nanoflows show/describe.
mdl/executor/cmd_microflows_helpers.go Switch enum lookup to backend APIs.
mdl/executor/cmd_microflows_create.go Generate IDs via types.GenerateID and pass backend to flow builder.
mdl/executor/cmd_microflows_builder_workflow.go Use types.GenerateID for workflow-related microflow objects.
mdl/executor/cmd_microflows_builder_graph.go Use types.GenerateID for microflow graph objects.
mdl/executor/cmd_microflows_builder_flows.go Use types.GenerateID and pass backend across builder clones.
mdl/executor/cmd_microflows_builder_control.go Use types.GenerateID and pass backend into nested builders.
mdl/executor/cmd_microflows_builder_annotations.go Use types.GenerateID for annotation objects/flows.
mdl/executor/cmd_microflows_builder.go Replace reader *mpr.Reader with backend backend.FullBackend.
mdl/executor/cmd_mermaid_mock_test.go Add mock-backend test for Mermaid domain model output.
mdl/executor/cmd_lint.go Set linter reader through e.Reader() accessor.
mdl/executor/cmd_jsonstructures_mock_test.go Add mock-backend tests for JSON structures.
mdl/executor/cmd_jsonstructures.go Move JSON helpers/element types to mdl/types.
mdl/executor/cmd_javascript_actions_mock_test.go Add mock-backend tests for JavaScript actions.
mdl/executor/cmd_javaactions_mock_test.go Add mock-backend tests for Java actions.
mdl/executor/cmd_javaactions.go Generate action/type IDs via types.GenerateID.
mdl/executor/cmd_import_mappings_mock_test.go Add mock-backend test for import mappings.
mdl/executor/cmd_import_mappings.go Move JSON structure element types to types and pass backend into builders.
mdl/executor/cmd_imagecollections_mock_test.go Add mock-backend tests for image collections.
mdl/executor/cmd_imagecollections.go Switch image collection model types from mpr to types.
mdl/executor/cmd_fragments_mock_test.go Add tests for fragment registry output.
mdl/executor/cmd_folders.go Switch folder info types from mpr to types.
mdl/executor/cmd_features.go Update comment to reflect “not connected” behavior.
mdl/executor/cmd_export_mappings_mock_test.go Add mock-backend test for export mappings.
mdl/executor/cmd_export_mappings.go Move JSON structure element types to types and pass backend into builders.
mdl/executor/cmd_enumerations_mock_test.go Refactor enumeration tests to use mock ctx helpers and add describe tests.
mdl/executor/cmd_entities_mock_test.go Add mock-backend tests for entities.
mdl/executor/cmd_entities.go Use types.GenerateID and adjust error wrapping for calculated microflows.
mdl/executor/cmd_diff_local.go Parse microflows from raw via backend rather than sdk/mpr.
mdl/executor/cmd_dbconnection_mock_test.go Add mock-backend tests for database connections.
mdl/executor/cmd_datatransformer_mock_test.go Add mock-backend tests for data transformers.
mdl/executor/cmd_contract.go Move contract parsing/types to mdl/types and use types.GenerateID/ParseEdmx/ParseAsyncAPI.
mdl/executor/cmd_constants_mock_test.go Add mock-backend tests for constants.
mdl/executor/cmd_catalog.go Update parallel describe comments and wire local executor with backend.
mdl/executor/cmd_businessevents_mock_test.go Add mock-backend tests for business event services.
mdl/executor/cmd_businessevents.go Generate channel names via types.GenerateID.
mdl/executor/cmd_associations_mock_test.go Add mock-backend tests for associations.
mdl/executor/cmd_agenteditor_mock_test.go Add mock-backend tests for Agent Editor documents.
mdl/executor/bugfix_test.go Update flowBuilder test to refer to nil backend instead of reader.
mdl/executor/bugfix_regression_test.go Update comment to refer to “backend” instead of “reader”.
mdl/catalog/builder_references.go Switch navigation menu item types from mpr to types.
mdl/catalog/builder_navigation.go Switch navigation menu item types from mpr to types.
mdl/catalog/builder_contract.go Use types.ParseEdmx/ParseAsyncAPI instead of sdk/mpr.
mdl/catalog/builder.go Replace mpr-typed catalog reader payloads with types equivalents.
mdl/bsonutil/bsonutil.go Add CGO-free UUID<->BSON binary conversion via mdl/types.
mdl/backend/workflow.go Remove unrelated interfaces (moved to infrastructure.go) and drop sdk/mpr dependency.
mdl/backend/security.go Replace mpr member access/revocation types with types.
mdl/backend/page.go Clarify snippet listing comment (no GetSnippet).
mdl/backend/navigation.go Switch navigation backend types/specs to types.
mdl/backend/mpr/datagrid_builder_test.go Move test package to mprbackend and use bsonutil for IDs.
mdl/backend/mpr/convert.go Add conversion helpers between sdk/mpr and mdl/types.
mdl/backend/mock/mock_workflow.go Switch image collection types to types.
mdl/backend/mock/mock_security.go Switch entity access revocation type to types.
mdl/backend/mock/mock_navigation.go Switch navigation types/specs to types.
mdl/backend/mock/mock_mutation.go Add mock implementations for mutation + widget builder/serialization backends.
mdl/backend/mock/mock_module.go Switch folder info type to types.
mdl/backend/mock/mock_microflow.go Add mock hook for ParseMicroflowFromRaw.
mdl/backend/mock/mock_mapping.go Switch JSON structure types to types.
mdl/backend/mock/mock_java.go Switch Java/JS action types to types.
mdl/backend/mock/mock_infrastructure.go Switch raw unit/widget/rename payload types to types and flesh out AgentEditor create/delete hooks.
mdl/backend/mock/mock_connection.go Switch version/project version types to types.
mdl/backend/mock/backend.go Update MockBackend function signatures for types + add mutation/builder function hooks.
mdl/backend/microflow.go Add backend method ParseMicroflowFromRaw.
mdl/backend/mapping.go Switch JSON structure API to types and document ID string convention.
mdl/backend/java.go Switch Java/JS action list/read types to types.
mdl/backend/infrastructure.go Switch raw unit/rename/widget payload types to types and re-home settings/image/scheduled event interfaces.
mdl/backend/doc.go Update package docs to reflect mdl/types decoupling + conversions in mpr backend.
mdl/backend/connection.go Switch connection/module/folder interfaces to types and add clarifying docs.
mdl/backend/backend.go Extend FullBackend to include mutation/serialization/builder interfaces.
examples/create_datagrid2_page/main.go Wire executor to a backend factory (mpr backend).
cmd/mxcli/project_tree.go Switch menu tree node builder to accept types.NavMenuItem.
cmd/mxcli/main.go Wire CLI executor to a backend factory (mpr backend).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 200 to 211
func updateWidgetsInContainer(ctx *ExecContext, containerID string, widgetRefs []widgetRef, assignments []ast.WidgetPropertyAssignment, dryRun bool) (int, error) {
if len(widgetRefs) == 0 {
return 0, nil
}

containerType := widgetRefs[0].ContainerType
containerName := widgetRefs[0].ContainerName

// Load the page or snippet
if strings.ToLower(containerType) == "page" {
return updateWidgetsInPage(ctx, containerID, containerName, widgetRefs, assignments, dryRun)
} else if strings.ToLower(containerType) == "snippet" {
return updateWidgetsInSnippet(ctx, containerID, containerName, widgetRefs, assignments, dryRun)
}

return 0, mdlerrors.NewUnsupported(fmt.Sprintf("unsupported container type: %s", containerType))
}

// updateWidgetsInPage updates widgets in a page using raw BSON.
func updateWidgetsInPage(ctx *ExecContext, containerID, containerName string, widgetRefs []widgetRef, assignments []ast.WidgetPropertyAssignment, dryRun bool) (int, error) {

// Load raw BSON as ordered document (preserves field ordering)
rawBytes, err := ctx.Backend.GetRawUnitBytes(model.ID(containerID))
if err != nil {
return 0, mdlerrors.NewBackend(fmt.Sprintf("load page %s", containerName), err)
}
var rawData bson.D
if err := bson.Unmarshal(rawBytes, &rawData); err != nil {
return 0, mdlerrors.NewBackend(fmt.Sprintf("unmarshal page %s", containerName), err)
}

updated := 0
for _, ref := range widgetRefs {
result := findBsonWidget(rawData, ref.Name)
if result == nil {
fmt.Fprintf(ctx.Output, " Warning: Widget %q not found in page %s\n", ref.Name, containerName)
continue
}
for _, assignment := range assignments {
if dryRun {
fmt.Fprintf(ctx.Output, " Would set '%s' = %v on %s (%s) in %s\n",
assignment.PropertyPath, assignment.Value, ref.Name, ref.WidgetType, containerName)
} else {
if err := setRawWidgetProperty(result.widget, assignment.PropertyPath, assignment.Value); err != nil {
fmt.Fprintf(ctx.Output, " Warning: Failed to set '%s' on %s: %v\n",
assignment.PropertyPath, ref.Name, err)
}
}
}
updated++
}

// Save back via raw BSON (bson.D preserves field ordering)
if !dryRun && updated > 0 {
outBytes, err := bson.Marshal(rawData)
if err != nil {
return updated, mdlerrors.NewBackend(fmt.Sprintf("marshal page %s", containerName), err)
}
if err := ctx.Backend.UpdateRawUnit(containerID, outBytes); err != nil {
return updated, mdlerrors.NewBackend(fmt.Sprintf("save page %s", containerName), err)
}
}

return updated, nil
}

// updateWidgetsInSnippet updates widgets in a snippet using raw BSON.
func updateWidgetsInSnippet(ctx *ExecContext, containerID, containerName string, widgetRefs []widgetRef, assignments []ast.WidgetPropertyAssignment, dryRun bool) (int, error) {

// Load raw BSON as ordered document (preserves field ordering)
rawBytes, err := ctx.Backend.GetRawUnitBytes(model.ID(containerID))
// Open the container (page, layout, or snippet) through the backend mutator.
mutator, err := ctx.Backend.OpenPageForMutation(model.ID(containerID))
if err != nil {
return 0, mdlerrors.NewBackend(fmt.Sprintf("load snippet %s", containerName), err)
}
var rawData bson.D
if err := bson.Unmarshal(rawBytes, &rawData); err != nil {
return 0, mdlerrors.NewBackend(fmt.Sprintf("unmarshal snippet %s", containerName), err)
return 0, mdlerrors.NewBackend(fmt.Sprintf("open %s for mutation", containerName), err)
}
Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

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

This refactor drops the explicit container-type dispatch (and the dedicated unsupported-container error). As a result, invalid/unknown ContainerType values will now surface as a generic backend 'open ... for mutation' error, which is less actionable than the prior NewUnsupported. Consider reintroducing a containerType := strings.ToLower(widgetRefs[0].ContainerType) guard here (e.g., allow only page/snippet/layout) and return mdlerrors.NewUnsupported(...) for anything else.

Copilot uses AI. Check for mistakes.
Comment on lines +207 to 211
// Open the container (page, layout, or snippet) through the backend mutator.
mutator, err := ctx.Backend.OpenPageForMutation(model.ID(containerID))
if err != nil {
return 0, mdlerrors.NewBackend(fmt.Sprintf("load snippet %s", containerName), err)
}
var rawData bson.D
if err := bson.Unmarshal(rawBytes, &rawData); err != nil {
return 0, mdlerrors.NewBackend(fmt.Sprintf("unmarshal snippet %s", containerName), err)
return 0, mdlerrors.NewBackend(fmt.Sprintf("open %s for mutation", containerName), err)
}
Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

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

In dry-run mode, this still opens the container 'for mutation'. If OpenPageForMutation takes write locks or requires write credentials, dry-run could become unexpectedly disruptive or fail in environments where reads are allowed but writes are not. If possible, add a read-only open path for dry-run (or extend OpenPageForMutation to support a non-locking/dry-run option) so dryRun=true doesn't require mutation semantics.

Copilot uses AI. Check for mistakes.
Comment on lines +77 to +83
// getProjectPath returns the project directory path from the underlying reader.
func (pb *pageBuilder) getProjectPath() string {
if pb.backend != nil {
return pb.backend.Path()
}
return ""
}
Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

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

The doc comment references the 'underlying reader', but the implementation now uses pb.backend. Update the comment to match the new abstraction (e.g., 'from the backend').

Copilot uses AI. Check for mistakes.
Comment on lines +351 to 362
func resolveAttributeType(entityQN, attrName string, b backend.DomainModelBackend) string {
if b == nil || entityQN == "" {
return "String"
}
parts := strings.SplitN(entityQN, ".", 2)
if len(parts) != 2 {
return "String"
}
dms, err := reader.ListDomainModels()
dms, err := b.ListDomainModels()
if err != nil {
return "String"
}
Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

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

resolveAttributeType calls ListDomainModels() every time it's invoked. When building large import/export mappings (deep element trees), this can become an O(N) backend roundtrip hotspot, especially now that 'backend' may be remote or more expensive than a local reader. Prefer listing domain models once in the top-level handler and passing a cached lookup (e.g., entityQN+attrName → type) down through the recursive builder.

Copilot uses AI. Check for mistakes.
Comment on lines 28 to +31
out := buf.String()

// Verify table contains our enumeration data.
if !strings.Contains(out, "MyModule.Color") {
t.Errorf("expected qualified name 'MyModule.Color' in output, got:\n%s", out)
}
if !strings.Contains(out, "3") {
t.Errorf("expected value count '3' in output, got:\n%s", out)
}
if !strings.Contains(out, "(1 enumerations)") {
t.Errorf("expected summary '(1 enumerations)' in output, got:\n%s", out)
}
assertContainsStr(t, out, "MyModule.Color")
assertContainsStr(t, out, "| 3")
assertContainsStr(t, out, "(1 enumerations)")
Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

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

The assertion \"| 3\" is tightly coupled to the table renderer's spacing/column formatting; small formatting changes could break the test without any behavioral regression. Consider asserting on a more stable signal (e.g., enumeration name + a substring like "3" in the same row, or switch the test to JSON output for strict structure).

Copilot uses AI. Check for mistakes.
Comment thread mdl/bsonutil/bsonutil.go
Comment on lines +18 to +27
func IDToBsonBinary(id string) primitive.Binary {
blob := types.UUIDToBlob(id)
if blob == nil || len(blob) != 16 {
blob = types.UUIDToBlob(types.GenerateID())
}
return primitive.Binary{
Subtype: 0x00,
Data: blob,
}
}
Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

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

This introduces new ID<->BSON conversion behavior (including 'invalid UUID → generate a new random ID' fallback and a fixed binary subtype). Add unit tests to pin the intended behavior: valid UUID round-trip, invalid UUID fallback producing a 16-byte blob, and subtype expectations, so callers don't observe silent behavioral drift later.

Copilot uses AI. Check for mistakes.
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.

2 participants