Skip to content

feat: experimental custom schemas#187

Merged
Oudwins merged 3 commits intomasterfrom
tristan/feat/custom-schemas
Dec 14, 2025
Merged

feat: experimental custom schemas#187
Oudwins merged 3 commits intomasterfrom
tristan/feat/custom-schemas

Conversation

@Oudwins
Copy link
Owner

@Oudwins Oudwins commented Sep 7, 2025

Summary by CodeRabbit

  • New Features

    • Adds an experimental public API to plug in external/custom schemas for processing, validation, type discovery, and custom coercion.
    • Provides a simple constructor to wrap and use external schema implementations while preserving existing behavior.
  • Tests

    • Adds comprehensive tests exercising custom-schema integration across structs, pointers, slices, coercion paths, nested scenarios, and error path reporting.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 7, 2025

Walkthrough

Adds an experimental public interface for external custom ZOG schemas, a wrapper type delegating to implementations, and a constructor. Also adds a comprehensive test suite exercising the new wrapper, coercion, validation, and nested scenarios.

Changes

Cohort / File(s) Summary
Public custom schema API
custom.go
Added EXPERIMENTAL_PUBLIC_ZOG_SCHEMA interface (Process, Validate, GetType, SetCoercer), CustomSchema wrapper struct, Use(schema EXPERIMENTAL_PUBLIC_ZOG_SCHEMA) *CustomSchema constructor, delegation methods (process, validate, getType, setCoercer), and var _ ZogSchema = &CustomSchema{}. No changes to existing Custom[T] logic.
Tests for experimental API
custom_experimental_test.go
Added comprehensive tests and test helpers validating Use-wrapped custom schemas: processing, validation, GetType, SetCoercer/coercion, nested struct/slice/pointer behaviors, error-path reporting, and integration with existing combinators.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Caller
  participant CS as CustomSchema (wrapper)
  participant Impl as EXPERIMENTAL_PUBLIC_ZOG_SCHEMA (impl)
  participant Ctx as SchemaCtx

  Caller->>CS: Use(impl) -> *CustomSchema
  Caller->>CS: process(ctx)
  CS->>Impl: Process(ctx)

  Caller->>CS: validate(ctx)
  CS->>Impl: Validate(ctx)

  Caller->>CS: getType()
  CS->>Impl: GetType()
  Impl-->>CS: ZogType
  CS-->>Caller: ZogType

  Caller->>CS: setCoercer(func)
  CS->>Impl: SetCoercer(func)

  note over CS,Impl: CustomSchema simply delegates calls to the provided implementation
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Points to review:

  • Ensure delegation method signatures and pointer/value receivers align with existing ZogSchema expectations.
  • Confirm SetCoercer semantics match coercer invocation patterns used elsewhere.
  • Review tests for correctness of path reporting and pointer/slice mutation semantics.

Possibly related PRs

Poem

I’m a rabbit with a tiny key,
I wrap your schema, set it free. 🐇
I call and pass, I coax and type,
Coercions hop and errors gripe.
A gentle bridge from you to me.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 29.17% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: experimental custom schemas' directly and accurately describes the main change: introducing experimental custom schema functionality with a public API.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch tristan/feat/custom-schemas

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Oudwins Oudwins changed the title feat: custom schema feat: experimental custom schemas Sep 7, 2025
@Oudwins Oudwins mentioned this pull request Sep 7, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
custom.go (2)

94-101: Rename and document the exported interface; avoid leaking internals in its signature

  • Go style: exported type names shouldn’t be SCREAM_CASE. Use a clear CamelCase name.
  • Public API shouldn’t expose internals package types directly. Re-export the context type locally and use that in the interface.

Apply this diff:

-// Experimental API
-type EXPERIMENTAL_PUBLIC_ZOG_SCHEMA interface {
-	Process(ctx *p.SchemaCtx)
-	Validate(ctx *p.SchemaCtx)
-	GetType() zconst.ZogType
-	SetCoercer(c CoercerFunc)
-}
+// Experimental: public interface for plugging in external ZOG schemas.
+// Subject to change without notice.
+type ExperimentalSchema interface {
+	Process(ctx *SchemaCtx)
+	Validate(ctx *SchemaCtx)
+	GetType() zconst.ZogType
+	SetCoercer(c CoercerFunc)
+}

Add this alias near the top of the file (outside the changed hunk) to decouple callers from internals:

// Re-export to keep the public API stable and avoid importing internals from user code.
type SchemaCtx = p.SchemaCtx

107-110: Tighten struct type, add short doc, and assert interface conformance

  • Switch field type to the renamed interface.
  • Add a compile-time assertion to prevent regressions.
-// Experimental API
-type CustomSchema struct {
-	schema EXPERIMENTAL_PUBLIC_ZOG_SCHEMA
-}
+// CustomSchema delegates to an underlying ExperimentalSchema.
+type CustomSchema struct {
+	schema ExperimentalSchema
+}

Add this after the struct (outside the changed hunk if needed):

// Compile-time check that CustomSchema implements ExperimentalSchema.
var _ ExperimentalSchema = (*CustomSchema)(nil)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e8f46f8 and 3f4b097.

📒 Files selected for processing (1)
  • custom.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
custom.go (3)
internals/contexts.go (1)
  • SchemaCtx (134-144)
zconst/consts.go (1)
  • ZogType (38-38)
utils.go (1)
  • CoercerFunc (37-37)

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
custom.go (1)

102-105: Critical: guard against nil to prevent runtime panics.

The constructor doesn't validate that schema is non-nil. Passing nil will cause a panic when any method is invoked on c.schema. Additionally, the function name doesn't follow Go naming conventions (prefer NewCustomSchema).

Apply this diff to add nil guard and follow naming conventions:

-// Experimental API
-func Use(schema EXPERIMENTAL_PUBLIC_ZOG_SCHEMA) *CustomSchema {
+// NewCustomSchema wraps an ExperimentalSchema implementation. Panics if schema is nil.
+func NewCustomSchema(schema ExperimentalSchema) *CustomSchema {
+	if schema == nil {
+		panic("NewCustomSchema: schema must not be nil")
+	}
 	return &CustomSchema{schema: schema}
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3f4b097 and 6e41e14.

📒 Files selected for processing (1)
  • custom.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
custom.go (4)
internals/contexts.go (1)
  • SchemaCtx (134-144)
zconst/consts.go (1)
  • ZogType (38-38)
utils.go (1)
  • CoercerFunc (37-37)
zogSchema.go (1)
  • ZogSchema (10-15)
🔇 Additional comments (3)
custom.go (3)

107-110: LGTM!

The struct definition is appropriate with an unexported field to encapsulate the schema implementation.


112-112: LGTM!

The compile-time interface check is a good practice to ensure CustomSchema correctly implements ZogSchema.


114-128: LGTM!

The delegation methods correctly implement the ZogSchema interface by forwarding calls to the wrapped schema's exported methods. This addresses the concern from the previous review about adding unexported adapter methods.

@Oudwins Oudwins force-pushed the tristan/feat/custom-schemas branch from 6e41e14 to 2efe86e Compare December 14, 2025 09:55
@Oudwins Oudwins merged commit 76a1d47 into master Dec 14, 2025
8 of 9 checks passed
@Oudwins Oudwins deleted the tristan/feat/custom-schemas branch December 14, 2025 09:58
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (2)
custom.go (2)

102-105: Guard against nil schema to prevent runtime panics.

If schema is nil, calling any method on CustomSchema will panic. Adding a nil check provides a clearer failure point.

 // Experimental API
 func Use(schema EXPERIMENTAL_PUBLIC_ZOG_SCHEMA) *CustomSchema {
+	if schema == nil {
+		panic("Use: schema must not be nil")
+	}
 	return &CustomSchema{schema: schema}
 }

94-100: Consider renaming to follow Go naming conventions.

The interface name EXPERIMENTAL_PUBLIC_ZOG_SCHEMA violates Go conventions (prefer PascalCase like ExperimentalSchema). Since this is experimental, the internal type exposure may be acceptable, but the naming should follow idiomatic Go.

🧹 Nitpick comments (1)
custom_experimental_test.go (1)

42-48: Consider extracting duplicated validation logic.

The pattern of creating an issue with message/code fallback is repeated three times. For test code this is acceptable, but extracting to a helper would reduce duplication.

func (s *testExperimentalSchema) addValidationIssue(ctx *p.SchemaCtx) {
	issue := ctx.Issue().SetMessage(s.errorMsg)
	if s.errorMsg == "" {
		issue.SetCode(zconst.IssueCodeCustom)
	}
	ctx.AddIssue(issue)
}

Also applies to: 62-68, 103-109

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6e41e14 and 2efe86e.

📒 Files selected for processing (2)
  • custom.go (1 hunks)
  • custom_experimental_test.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
custom_experimental_test.go (8)
zconst/consts.go (4)
  • ZogType (20-20)
  • IssueCodeCustom (41-41)
  • TypeString (23-23)
  • TypeNumber (24-24)
internals/contexts.go (1)
  • SchemaCtx (134-144)
struct.go (2)
  • Struct (42-46)
  • Shape (35-35)
custom.go (1)
  • Use (103-105)
tutils/testIssueMessages.go (1)
  • FindByPath (44-52)
internals/tests.go (1)
  • Required (114-121)
slices.go (1)
  • Slice (44-53)
pointers.go (1)
  • Ptr (31-35)
custom.go (4)
internals/contexts.go (1)
  • SchemaCtx (134-144)
zconst/consts.go (1)
  • ZogType (20-20)
utils.go (1)
  • CoercerFunc (21-21)
zogSchema.go (1)
  • ZogSchema (10-15)
🔇 Additional comments (7)
custom.go (1)

107-128: LGTM!

The CustomSchema struct and its delegation methods correctly implement the ZogSchema interface by forwarding calls to the wrapped schema. The compile-time interface assertion on line 112 is a good practice.

custom_experimental_test.go (6)

116-128: Intentional but note the validator signature inconsistency.

Process passes the dereferenced value (e.g., string) to the validator, while Validate passes ctx.ValPtr (e.g., *string). This is handled in test validators that check for both types, but worth noting for maintainability.


143-180: Good test coverage for basic Use() and CustomSchema functionality.

The tests properly verify both success and failure paths for Parse operations, including custom error messages.


264-298: Good test for zog tag mapping behavior.

The test correctly verifies that when a struct field has a zog:"id" tag, the input data should use the "id" key while the Shape uses the field name "ID".


432-445: Defensive error path checking is reasonable for experimental API.

The test handles uncertainty about whether the error path will be "id" (from zog tag) or "ID" (from field name). This defensive approach is acceptable while the API stabilizes.


727-840: Excellent coverage of complex nested scenarios.

These tests thoroughly exercise the integration of CustomSchema with nested structures, slices, and pointers, verifying correct data propagation through multiple levels of composition.


846-946: Comprehensive error handling test coverage.

The tests properly verify error propagation for coercion failures, validation failures, and correct error path reporting in nested structures. The flexible assertions on lines 870-873 appropriately handle potential variations in error formatting.

@coderabbitai coderabbitai bot mentioned this pull request Jan 9, 2026
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.

1 participant