Conversation
|
Warning Rate limit exceeded@Oudwins has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 4 minutes and 21 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (1)
WalkthroughAdds a generic BoxedSchema wrapper that boxes/unboxes values around an inner ZogSchema, implements Parse/Validate flows, forwards type/coercer behavior to the inner schema, integrates with execution context and issue handling, and includes extensive tests and documentation for boxed patterns and examples. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
boxedSchema.go(1 hunks)boxedSchema_parse_test.go(1 hunks)boxedSchema_validate_test.go(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
boxedSchema_parse_test.go (10)
boxedSchema.go (1)
Boxed(20-22)string.go (1)
String(83-91)boxedSchema_validate_test.go (18)
StringBox(13-15)BoolBox(25-27)IntBox(29-31)Float64Box(33-35)TimeBox(37-39)StringValuer(55-57)IntValuer(59-61)SliceBox(41-43)UserBox(50-52)BoxedUser(45-48)SliceValuer(63-65)NullString(102-105)StringPtrBox(519-521)IntPtrBox(575-577)StringValuerBox(21-23)ContainerStruct(811-814)ValuerBox(899-901)ContainerWithSlice(911-914)boolean.go (1)
Bool(34-42)numbers.go (2)
Int(93-101)Float64(63-71)internals/tests.go (2)
GT(236-247)Required(114-121)time.go (1)
Time(37-45)slices.go (1)
Slice(44-53)struct.go (2)
Struct(42-46)Shape(35-35)pointers.go (1)
Ptr(31-35)
boxedSchema_validate_test.go (9)
time.go (1)
Time(37-45)string.go (1)
String(83-91)boxedSchema.go (1)
Boxed(20-22)boolean.go (1)
Bool(34-42)numbers.go (2)
Int(93-101)Float64(63-71)internals/tests.go (2)
GT(236-247)Required(114-121)slices.go (1)
Slice(44-53)struct.go (2)
Struct(42-46)Shape(35-35)pointers.go (1)
Ptr(31-35)
🔇 Additional comments (16)
boxedSchema.go (4)
1-22: LGTM! Clean generic type definitions and constructor.The type definitions, interface compliance check, and constructor are well-structured. The generic type parameters
B(box type) andT(inner type) are clearly documented through usage.
24-38: LGTM! Proper resource management in Parse method.The deferred
Free()calls ensure proper cleanup of pooled resources (errs,ctx,path,sctx). The execution flow correctly applies options before processing.
40-54: LGTM! Validate method follows same pattern as Parse.Consistent resource management and option handling. Correctly passes
*destas data anddestas valPtr.
130-136: LGTM! Correctly delegates to inner schema.Both
getType()andsetCoercer()appropriately forward to the wrapped schema.boxedSchema_validate_test.go (6)
12-105: LGTM! Well-designed test fixtures covering diverse boxing scenarios.The type definitions provide good coverage:
- Struct-based boxes (
StringBox,IntBox, etc.)- Interface-based Valuer patterns
- Error-returning implementations for testing error paths
- Nullable pattern mirroring
sql.NullStringThese serve as effective shared fixtures for the test suite.
111-201: LGTM! Thorough primitive type validation tests.Tests cover all major primitive types with both success and failure scenarios. The assertions verify both the error state and that original values are preserved appropriately.
207-337: LGTM! Good coverage of interface-based boxing and complex types.The Valuer pattern tests demonstrate flexibility for database/sql-like interfaces. Complex type tests (Slice, Struct) verify nested schema handling.
343-513: LGTM! Critical error handling and catch propagation tests.The tests verify:
- Unbox errors are properly surfaced
- Nullable patterns work as expected
- Catch values correctly propagate back to the boxed type
These are essential for the BoxedSchema's reliability.
519-805: LGTM! Comprehensive tests for value modification scenarios.Excellent coverage of:
- Pointer schemas with nil/NotNil handling
- Transform propagation back to boxed types
- Default value propagation
- Required vs Optional semantics
- Interaction between Required and Catch
These tests validate the core value-flow mechanics of BoxedSchema.
811-938: LGTM! Essential nested schema composition tests.The tests for BoxedSchema inside Struct validate critical composition scenarios including catch value propagation, transform propagation, and validation failures in nested contexts. The
ContainerWithSlicetest with interface-based boxing is a good real-world scenario.boxedSchema_parse_test.go (6)
1-104: LGTM! Solid primitive type parsing tests.Good coverage of parsing raw data into boxed types, including the time parsing test which verifies string-to-time coercion works through the BoxedSchema.
110-181: LGTM! Important input path coverage.These tests validate the type switch logic in
process()handles bothBand*Binputs correctly, ensuring the unboxing path works for all input forms.
187-358: LGTM! Comprehensive interface and complex type parsing tests.Good coverage of Valuer-pattern parsing and complex types (Slice, Struct). The error handling tests ensure both unbox and box errors are properly surfaced during parsing.
364-578: LGTM! Real-world pattern and pointer parsing tests.The nullable pattern tests (lines 364-412) are particularly valuable for database integration scenarios. Pointer schema parsing with nil handling (lines 518-578) ensures optional field semantics work correctly during parsing.
584-791: LGTM! Transform, default, and required parsing tests.Excellent coverage of value modification during parsing:
- Trim transform properly propagates back to boxed output
- Default values work with nil input
- Required fails on zero values while Optional allows them
- Required + Catch interaction works correctly
797-926: LGTM! Nested schema parsing tests complete the coverage.The BoxedSchema-inside-Struct parsing tests validate composition scenarios including:
- Raw data to nested boxed fields
- Box input to nested boxed fields
- Catch and Transform propagation in nested contexts
- Slice with inner catch in boxed context
This provides confidence that BoxedSchema integrates correctly with other schema types.
Deploying zog with
|
| Latest commit: |
047a860
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://58a32925.zog-3a0.pages.dev |
| Branch Preview URL: | https://feat-boxed-values.zog-3a0.pages.dev |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
docs/docs/reference.md (1)
223-318: Excellent documentation with minor formatting issue.The Boxed Types documentation is comprehensive and includes clear examples that match the test implementations. The function signatures, parameters, and usage patterns are well-explained.
Minor formatting cleanup:
The code examples use hard tabs instead of spaces (lines 253-305). While this doesn't affect functionality, it's flagged by the markdown linter. Consider replacing tabs with spaces for consistency:
schema := z.Boxed( - z.String().Min(3), - func(b StringValuer, ctx z.Ctx) (string, error) { return b.Value() }, - func(s string, ctx z.Ctx) (StringValuer, error) { return myStringValuer{v: s}, nil }, + z.String().Min(3), + func(b StringValuer, ctx z.Ctx) (string, error) { return b.Value() }, + func(s string, ctx z.Ctx) (StringValuer, error) { return myStringValuer{v: s}, nil }, )Apply this pattern to all code examples in the section (lines 253-305).
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
boxedSchema_docs_examples_test.go(1 hunks)docs/docs/reference.md(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
boxedSchema_docs_examples_test.go (3)
boxedSchema.go (1)
Boxed(20-22)string.go (1)
String(83-91)pointers.go (1)
Ptr(31-35)
🪛 markdownlint-cli2 (0.18.1)
docs/docs/reference.md
253-253: Hard tabs
Column: 1
(MD010, no-hard-tabs)
257-257: Hard tabs
Column: 1
(MD010, no-hard-tabs)
258-258: Hard tabs
Column: 1
(MD010, no-hard-tabs)
259-259: Hard tabs
Column: 1
(MD010, no-hard-tabs)
270-270: Hard tabs
Column: 1
(MD010, no-hard-tabs)
271-271: Hard tabs
Column: 1
(MD010, no-hard-tabs)
275-275: Hard tabs
Column: 1
(MD010, no-hard-tabs)
276-276: Hard tabs
Column: 1
(MD010, no-hard-tabs)
277-277: Hard tabs
Column: 1
(MD010, no-hard-tabs)
278-278: Hard tabs
Column: 1
(MD010, no-hard-tabs)
279-279: Hard tabs
Column: 1
(MD010, no-hard-tabs)
280-280: Hard tabs
Column: 1
(MD010, no-hard-tabs)
281-281: Hard tabs
Column: 1
(MD010, no-hard-tabs)
282-282: Hard tabs
Column: 1
(MD010, no-hard-tabs)
283-283: Hard tabs
Column: 1
(MD010, no-hard-tabs)
284-284: Hard tabs
Column: 1
(MD010, no-hard-tabs)
290-290: Hard tabs
Column: 1
(MD010, no-hard-tabs)
291-291: Hard tabs
Column: 1
(MD010, no-hard-tabs)
295-295: Hard tabs
Column: 1
(MD010, no-hard-tabs)
296-296: Hard tabs
Column: 1
(MD010, no-hard-tabs)
297-297: Hard tabs
Column: 1
(MD010, no-hard-tabs)
298-298: Hard tabs
Column: 1
(MD010, no-hard-tabs)
299-299: Hard tabs
Column: 1
(MD010, no-hard-tabs)
300-300: Hard tabs
Column: 1
(MD010, no-hard-tabs)
301-301: Hard tabs
Column: 1
(MD010, no-hard-tabs)
302-302: Hard tabs
Column: 1
(MD010, no-hard-tabs)
303-303: Hard tabs
Column: 1
(MD010, no-hard-tabs)
304-304: Hard tabs
Column: 1
(MD010, no-hard-tabs)
305-305: Hard tabs
Column: 1
(MD010, no-hard-tabs)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Cloudflare Pages
🔇 Additional comments (6)
boxedSchema_docs_examples_test.go (5)
15-42: LGTM!The Omittable pattern implementation is clean and correctly handles both set and unset cases.
48-74: Test logic is sound.The test properly exercises both Parse and Validate flows for the driver.Valuer pattern, assuming
myStringValueris defined elsewhere in the codebase.
76-110: LGTM!The nullable pattern test is self-contained and thoroughly tests both Parse and Validate flows with proper assertions.
120-161: Comprehensive test coverage.The test thoroughly validates all four scenarios (Parse/Validate × set/unset) with correct assertions for the Omittable pattern.
10-13: ThemyStringValuertype is defined inboxedSchema_validate_test.goin the same package, so there is no compilation error. Test files in the same package have access to all package-level symbols, including those defined in other test files. ThecreateValuerfunction will compile and run correctly.Likely an incorrect or invalid review comment.
docs/docs/reference.md (1)
83-83: LGTM!The Boxed schema type is properly documented in the Schema Types section with a clear comment.
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
boxedSchema.go (1)
56-60: Fix type parameter order in panic messages (matches earlier review)Both
validateandprocesspanic messages printBoxedSchema[%T, %T]but passnew(T), new(B), even thoughBoxedSchemais defined asBoxedSchema[B, T]. This is just a diagnostics mismatch, but it can be confusing when debugging.You can align the messages with the type parameter order like this:
func (s *BoxedSchema[B, T]) validate(ctx *p.SchemaCtx) { boxPtr, ok := ctx.ValPtr.(*B) if !ok { - p.Panicf("BoxedSchema[%T, %T]: Expected valPtr type to correspond with type defined in schema. But it does not. Expected type: %T, got: %T", new(T), new(B), new(*B), ctx.ValPtr) + p.Panicf("BoxedSchema[%T, %T]: Expected valPtr type to correspond with type defined in schema. But it does not. Expected type: %T, got: %T", new(B), new(T), new(*B), ctx.ValPtr) } } func (s *BoxedSchema[B, T]) process(ctx *p.SchemaCtx) { boxPtr, ok := ctx.ValPtr.(*B) if !ok { - p.Panicf("BoxedSchema[%T, %T]: Expected valPtr type to correspond with type defined in schema. But it does not. Expected type: %T, got: %T", new(T), new(B), new(*B), ctx.ValPtr) + p.Panicf("BoxedSchema[%T, %T]: Expected valPtr type to correspond with type defined in schema. But it does not. Expected type: %T, got: %T", new(B), new(T), new(*B), ctx.ValPtr) } }Also applies to: 81-85
🧹 Nitpick comments (3)
boxedSchema.go (3)
20-22: Guard against nilunboxFuncto avoid silent panics on misuseRight now
Boxedaccepts a potentially nilunboxFunc, and bothvalidateandprocessunconditionally calls.unbox, which would panic if a caller accidentally passednil.If you want to keep misuse from turning into a hard-to-diagnose panic, consider a constructor-time guard:
func Boxed[B any, T any](schema ZogSchema, unboxFunc UnboxFunc[B, T], boxFunc CreateBoxFunc[T, B]) *BoxedSchema[B, T] { - return &BoxedSchema[B, T]{schema: schema, unbox: unboxFunc, box: boxFunc} + if unboxFunc == nil { + p.Panicf("BoxedSchema[%T, %T]: unboxFunc must not be nil", new(B), new(T)) + } + return &BoxedSchema[B, T]{schema: schema, unbox: unboxFunc, box: boxFunc} }This keeps the API contract explicit and fails fast if violated.
40-54:Validatewill panic on nildest; consider making this precondition explicit or guarding it
Validatedereferencesdestunconditionally:sctx := ctx.NewSchemaCtx(*dest, dest, path, s.getType())If a caller passes
nil(e.g.var b *B; schema.Validate(b)), this will panic before any validation happens. If the library contract is “destmust be non-nil”, it’d help to either (a) document that clearly, or (b) add a runtime guard that panics with a more descriptive message.For example:
func (s *BoxedSchema[B, T]) Validate(dest *B, options ...ExecOption) ZogIssueMap { + if dest == nil { + p.Panicf("BoxedSchema[%T, %T]: Validate dest must not be nil", new(B), new(T)) + } errs := p.NewErrsMap() defer errs.Free() ctx := p.NewExecCtx(errs, conf.IssueFormatter) defer ctx.Free() // ... }This keeps the failure mode intentional and easier to debug.
87-129: process flow (unbox → inner parse → re-box) is solid; consider clarifying behavior whenboxFuncis nilThe
processflow looks good:
- Assert
ctx.ValPtris*Band keep that pointer to write back.- Normalize
ctx.Databy:
- Unboxing when
dataisBor*B.- Passing raw data through otherwise.
- Allocate a temporary
inner T, setctx.ValPtr = &inner, and delegate tos.schema.process(ctx).- Re-box via
s.box(inner, ctx)and assign back to*boxPtrwhens.box != nil.This matches the documented Parse semantics for boxed types. The TODO:
// TODO maybe some kind of flag that you executed process with boxFunc is nilsuggests you might want observability when
boxFuncis nil and nothing is written back to*boxPtr. If that matters, a lightweight option would be to add debug-only instrumentation or a small helper onBoxedSchema(e.g.,hasBox()or a comment near the constructor) rather than a runtime flag inprocessitself.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
boxedSchema.go(1 hunks)docs/docs/reference.md(2 hunks)
🧰 Additional context used
🪛 markdownlint-cli2 (0.18.1)
docs/docs/reference.md
253-253: Hard tabs
Column: 1
(MD010, no-hard-tabs)
257-257: Hard tabs
Column: 1
(MD010, no-hard-tabs)
258-258: Hard tabs
Column: 1
(MD010, no-hard-tabs)
259-259: Hard tabs
Column: 1
(MD010, no-hard-tabs)
270-270: Hard tabs
Column: 1
(MD010, no-hard-tabs)
271-271: Hard tabs
Column: 1
(MD010, no-hard-tabs)
275-275: Hard tabs
Column: 1
(MD010, no-hard-tabs)
276-276: Hard tabs
Column: 1
(MD010, no-hard-tabs)
277-277: Hard tabs
Column: 1
(MD010, no-hard-tabs)
278-278: Hard tabs
Column: 1
(MD010, no-hard-tabs)
279-279: Hard tabs
Column: 1
(MD010, no-hard-tabs)
280-280: Hard tabs
Column: 1
(MD010, no-hard-tabs)
281-281: Hard tabs
Column: 1
(MD010, no-hard-tabs)
282-282: Hard tabs
Column: 1
(MD010, no-hard-tabs)
283-283: Hard tabs
Column: 1
(MD010, no-hard-tabs)
284-284: Hard tabs
Column: 1
(MD010, no-hard-tabs)
290-290: Hard tabs
Column: 1
(MD010, no-hard-tabs)
291-291: Hard tabs
Column: 1
(MD010, no-hard-tabs)
295-295: Hard tabs
Column: 1
(MD010, no-hard-tabs)
296-296: Hard tabs
Column: 1
(MD010, no-hard-tabs)
297-297: Hard tabs
Column: 1
(MD010, no-hard-tabs)
298-298: Hard tabs
Column: 1
(MD010, no-hard-tabs)
299-299: Hard tabs
Column: 1
(MD010, no-hard-tabs)
300-300: Hard tabs
Column: 1
(MD010, no-hard-tabs)
301-301: Hard tabs
Column: 1
(MD010, no-hard-tabs)
302-302: Hard tabs
Column: 1
(MD010, no-hard-tabs)
303-303: Hard tabs
Column: 1
(MD010, no-hard-tabs)
304-304: Hard tabs
Column: 1
(MD010, no-hard-tabs)
305-305: Hard tabs
Column: 1
(MD010, no-hard-tabs)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Cloudflare Pages
🔇 Additional comments (5)
boxedSchema.go (3)
9-22: Boxed API surface and type aliases look consistent and idiomatic
CreateBoxFunc/UnboxFunc, theBoxedSchema[B, T]definition, and theBoxedconstructor all follow the “B = box, T = inner” convention and match the docs. The interface conformance check viavar _ ComplexZogSchema = &BoxedSchema[any, any]{}is a nice guardrail.
24-38: Parse wiring into ExecCtx/SchemaCtx matches existing patternsThe
Parseimplementation correctly mirrors other complex schemas: allocate/freeErrsMapandExecCtx, applyExecOptions, build aPathBuilder, then allocate aSchemaCtxand delegate toprocess. This should integrate smoothly with existing issue formatting and path handling.
131-137: Delegating type and coercer behavior to the inner schema is appropriate
getTypeandsetCoercersimply forward to the wrapped schema, which keepsBoxedSchematransparent to callers and lets it participate correctly in any type-based or coercion-based logic elsewhere.docs/docs/reference.md (2)
83-84: Schema Types list correctly advertisesz.BoxedAdding
z.Boxed[B, T](schema, unboxFunc, boxFunc) // boxed type wrapperhere keeps the reference section aligned with the new API and mirrors the implementation signature.
223-318: Boxed Types section is clear and matches the implementation semanticsThis section does a good job of:
- Defining
UnboxFunc,CreateBoxFunc, andz.Boxed[B, T]consistently with the Go implementation.- Explaining the roles of
B(box) andT(inner) and the responsibilities ofschema,unboxFunc, andboxFunc.- Providing realistic patterns:
driver.Valuer-style wrappers, a nullable wrapper, and an Omittable wrapper.- Explicitly documenting the behavioral difference between Parse (handling raw/boxed inputs) and Validate (validating and re-boxing an existing box).
The examples should give users enough guidance to implement their own boxing patterns.
| ```go | ||
| // | ||
| // | ||
| // Example 1: driver.Valuer pattern | ||
| // | ||
| // | ||
|
|
||
| type StringValuer interface { | ||
| Value() (string, error) | ||
| } | ||
|
|
||
| schema := z.Boxed( | ||
| z.String().Min(3), | ||
| func(b StringValuer, ctx z.Ctx) (string, error) { return b.Value() }, | ||
| func(s string, ctx z.Ctx) (StringValuer, error) { return myStringValuer{v: s}, nil }, // you can pass nil here if you don't need to box values. | ||
| ) | ||
|
|
||
| var valuer StringValuer | ||
| schema.Parse("hello", &valuer) // valuer.Value() will be "hello" | ||
| valuer = createValuer("hello2") | ||
| schema.Validate(&valuer) // valuer.Value() will be "hello2" | ||
|
|
||
|
|
||
| // Example 2: Nullable pattern (like sql.NullString) | ||
| type NullString struct { | ||
| String string | ||
| Valid bool | ||
| } | ||
|
|
||
| schema := z.Boxed( | ||
| z.String().Min(3), | ||
| func(ns NullString, ctx z.Ctx) (string, error) { | ||
| if !ns.Valid { | ||
| return "", errors.New("null string is not valid") | ||
| } | ||
| return ns.String, nil | ||
| }, | ||
| func(s string, ctx z.Ctx) (NullString, error) { | ||
| return NullString{String: s, Valid: true}, nil | ||
| }, | ||
| ) | ||
|
|
||
| // Example 3: Omittable pattern | ||
|
|
||
| type Omittable[T any] interface { | ||
| Value() T | ||
| IsSet() bool | ||
| } | ||
|
|
||
| schema := z.Boxed( | ||
| z.Ptr(z.String().Min(3)), | ||
| func(o Omittable[string], ctx z.Ctx) (*string, error) { | ||
| if o.IsSet() { | ||
| val := o.Value() | ||
| return &val, nil | ||
| } | ||
| return nil, nil | ||
| }, | ||
| func(s *string, ctx z.Ctx) (Omittable[string], error) { | ||
| return createOmittable(s), nil | ||
| }, | ||
| ) | ||
| ``` |
There was a problem hiding this comment.
Resolve markdownlint MD010 “no-hard-tabs” warnings in new code examples
markdownlint is flagging hard tabs in this new Boxed examples block (e.g., around the StringValuer, NullString, and Omittable definitions). To keep docs lint-clean, it’s worth normalizing indentation to spaces inside these code fences.
For example:
-type StringValuer interface {
- Value() (string, error)
-}
+type StringValuer interface {
+ Value() (string, error)
+}and similarly for the other indented lines in the Boxed examples. Using spaces throughout will satisfy MD010 without changing how the snippets render.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ```go | |
| // | |
| // | |
| // Example 1: driver.Valuer pattern | |
| // | |
| // | |
| type StringValuer interface { | |
| Value() (string, error) | |
| } | |
| schema := z.Boxed( | |
| z.String().Min(3), | |
| func(b StringValuer, ctx z.Ctx) (string, error) { return b.Value() }, | |
| func(s string, ctx z.Ctx) (StringValuer, error) { return myStringValuer{v: s}, nil }, // you can pass nil here if you don't need to box values. | |
| ) | |
| var valuer StringValuer | |
| schema.Parse("hello", &valuer) // valuer.Value() will be "hello" | |
| valuer = createValuer("hello2") | |
| schema.Validate(&valuer) // valuer.Value() will be "hello2" | |
| // Example 2: Nullable pattern (like sql.NullString) | |
| type NullString struct { | |
| String string | |
| Valid bool | |
| } | |
| schema := z.Boxed( | |
| z.String().Min(3), | |
| func(ns NullString, ctx z.Ctx) (string, error) { | |
| if !ns.Valid { | |
| return "", errors.New("null string is not valid") | |
| } | |
| return ns.String, nil | |
| }, | |
| func(s string, ctx z.Ctx) (NullString, error) { | |
| return NullString{String: s, Valid: true}, nil | |
| }, | |
| ) | |
| // Example 3: Omittable pattern | |
| type Omittable[T any] interface { | |
| Value() T | |
| IsSet() bool | |
| } | |
| schema := z.Boxed( | |
| z.Ptr(z.String().Min(3)), | |
| func(o Omittable[string], ctx z.Ctx) (*string, error) { | |
| if o.IsSet() { | |
| val := o.Value() | |
| return &val, nil | |
| } | |
| return nil, nil | |
| }, | |
| func(s *string, ctx z.Ctx) (Omittable[string], error) { | |
| return createOmittable(s), nil | |
| }, | |
| ) | |
| ``` |
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)
253-253: Hard tabs
Column: 1
(MD010, no-hard-tabs)
257-257: Hard tabs
Column: 1
(MD010, no-hard-tabs)
258-258: Hard tabs
Column: 1
(MD010, no-hard-tabs)
259-259: Hard tabs
Column: 1
(MD010, no-hard-tabs)
270-270: Hard tabs
Column: 1
(MD010, no-hard-tabs)
271-271: Hard tabs
Column: 1
(MD010, no-hard-tabs)
275-275: Hard tabs
Column: 1
(MD010, no-hard-tabs)
276-276: Hard tabs
Column: 1
(MD010, no-hard-tabs)
277-277: Hard tabs
Column: 1
(MD010, no-hard-tabs)
278-278: Hard tabs
Column: 1
(MD010, no-hard-tabs)
279-279: Hard tabs
Column: 1
(MD010, no-hard-tabs)
280-280: Hard tabs
Column: 1
(MD010, no-hard-tabs)
281-281: Hard tabs
Column: 1
(MD010, no-hard-tabs)
282-282: Hard tabs
Column: 1
(MD010, no-hard-tabs)
283-283: Hard tabs
Column: 1
(MD010, no-hard-tabs)
284-284: Hard tabs
Column: 1
(MD010, no-hard-tabs)
290-290: Hard tabs
Column: 1
(MD010, no-hard-tabs)
291-291: Hard tabs
Column: 1
(MD010, no-hard-tabs)
295-295: Hard tabs
Column: 1
(MD010, no-hard-tabs)
296-296: Hard tabs
Column: 1
(MD010, no-hard-tabs)
297-297: Hard tabs
Column: 1
(MD010, no-hard-tabs)
298-298: Hard tabs
Column: 1
(MD010, no-hard-tabs)
299-299: Hard tabs
Column: 1
(MD010, no-hard-tabs)
300-300: Hard tabs
Column: 1
(MD010, no-hard-tabs)
301-301: Hard tabs
Column: 1
(MD010, no-hard-tabs)
302-302: Hard tabs
Column: 1
(MD010, no-hard-tabs)
303-303: Hard tabs
Column: 1
(MD010, no-hard-tabs)
304-304: Hard tabs
Column: 1
(MD010, no-hard-tabs)
305-305: Hard tabs
Column: 1
(MD010, no-hard-tabs)
🤖 Prompt for AI Agents
In docs/docs/reference.md around lines 245 to 307, the fenced Go code examples
contain hard tab characters triggering markdownlint MD010; replace all hard tabs
inside the code block with spaces (use consistent indentation, e.g., 2 or 4
spaces) so every indented line (type definitions, schema assignments, function
params and bodies) uses spaces only, and re-run lint to confirm the MD010
warning is resolved.
* wp * wp * test: initial validate boxed schema tests * wp * wp * wp * wp * wp * feat: parse boxed schema * wp * wp * wp * fix: review
This PR adds support for boxed schema which should allow you to use any/all optional types with Zog!
Summary by CodeRabbit
New Features
Tests
Documentation
✏️ Tip: You can customize this high-level summary in your review settings.