mirror of
https://github.com/IBM/fp-go.git
synced 2026-01-29 10:36:04 +02:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
df07599a9e | ||
|
|
30ad0e4dd8 | ||
|
|
2374d7f1e4 |
@@ -536,9 +536,9 @@ func extractEmbeddedFields(embedType ast.Expr, fileImports map[string]string, fi
|
||||
}
|
||||
|
||||
for _, name := range field.Names {
|
||||
// Only export lenses for exported fields
|
||||
if name.IsExported() {
|
||||
fieldTypeName := getTypeName(field.Type)
|
||||
// Generate lenses for both exported and unexported fields
|
||||
fieldTypeName := getTypeName(field.Type)
|
||||
if true { // Keep the block structure for minimal changes
|
||||
isOptional := false
|
||||
baseType := fieldTypeName
|
||||
|
||||
@@ -698,9 +698,9 @@ func parseFile(filename string) ([]structInfo, string, error) {
|
||||
continue
|
||||
}
|
||||
for _, name := range field.Names {
|
||||
// Only export lenses for exported fields
|
||||
if name.IsExported() {
|
||||
typeName := getTypeName(field.Type)
|
||||
// Generate lenses for both exported and unexported fields
|
||||
typeName := getTypeName(field.Type)
|
||||
if true { // Keep the block structure for minimal changes
|
||||
isOptional := false
|
||||
baseType := typeName
|
||||
isComparable := false
|
||||
|
||||
@@ -1086,3 +1086,255 @@ type ComparableBox[T comparable] struct {
|
||||
// Verify that MakeLensRef is NOT used (since both fields are comparable)
|
||||
assert.NotContains(t, contentStr, "__lens.MakeLensRefWithName(", "Should not use MakeLensRefWithName when all fields are comparable")
|
||||
}
|
||||
|
||||
func TestParseFileWithUnexportedFields(t *testing.T) {
|
||||
// Create a temporary test file
|
||||
tmpDir := t.TempDir()
|
||||
testFile := filepath.Join(tmpDir, "test.go")
|
||||
|
||||
testCode := `package testpkg
|
||||
|
||||
// fp-go:Lens
|
||||
type Config struct {
|
||||
PublicName string
|
||||
privateName string
|
||||
PublicValue int
|
||||
privateValue *int
|
||||
}
|
||||
`
|
||||
|
||||
err := os.WriteFile(testFile, []byte(testCode), 0o644)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Parse the file
|
||||
structs, pkg, err := parseFile(testFile)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify results
|
||||
assert.Equal(t, "testpkg", pkg)
|
||||
assert.Len(t, structs, 1)
|
||||
|
||||
// Check Config struct
|
||||
config := structs[0]
|
||||
assert.Equal(t, "Config", config.Name)
|
||||
assert.Len(t, config.Fields, 4, "Should include both exported and unexported fields")
|
||||
|
||||
// Check exported field
|
||||
assert.Equal(t, "PublicName", config.Fields[0].Name)
|
||||
assert.Equal(t, "string", config.Fields[0].TypeName)
|
||||
assert.False(t, config.Fields[0].IsOptional)
|
||||
|
||||
// Check unexported field
|
||||
assert.Equal(t, "privateName", config.Fields[1].Name)
|
||||
assert.Equal(t, "string", config.Fields[1].TypeName)
|
||||
assert.False(t, config.Fields[1].IsOptional)
|
||||
|
||||
// Check exported int field
|
||||
assert.Equal(t, "PublicValue", config.Fields[2].Name)
|
||||
assert.Equal(t, "int", config.Fields[2].TypeName)
|
||||
assert.False(t, config.Fields[2].IsOptional)
|
||||
|
||||
// Check unexported pointer field
|
||||
assert.Equal(t, "privateValue", config.Fields[3].Name)
|
||||
assert.Equal(t, "*int", config.Fields[3].TypeName)
|
||||
assert.True(t, config.Fields[3].IsOptional)
|
||||
}
|
||||
|
||||
func TestGenerateLensHelpersWithUnexportedFields(t *testing.T) {
|
||||
// Create a temporary directory with test files
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
testCode := `package testpkg
|
||||
|
||||
// fp-go:Lens
|
||||
type MixedStruct struct {
|
||||
PublicField string
|
||||
privateField int
|
||||
OptionalPrivate *string
|
||||
}
|
||||
`
|
||||
|
||||
testFile := filepath.Join(tmpDir, "test.go")
|
||||
err := os.WriteFile(testFile, []byte(testCode), 0o644)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Generate lens code
|
||||
outputFile := "gen_lens.go"
|
||||
err = generateLensHelpers(tmpDir, outputFile, false, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify the generated file exists
|
||||
genPath := filepath.Join(tmpDir, outputFile)
|
||||
_, err = os.Stat(genPath)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Read and verify the generated content
|
||||
content, err := os.ReadFile(genPath)
|
||||
require.NoError(t, err)
|
||||
|
||||
contentStr := string(content)
|
||||
|
||||
// Check for expected content
|
||||
assert.Contains(t, contentStr, "package testpkg")
|
||||
assert.Contains(t, contentStr, "MixedStructLenses")
|
||||
assert.Contains(t, contentStr, "MakeMixedStructLenses")
|
||||
|
||||
// Check that lenses are generated for all fields (exported and unexported)
|
||||
assert.Contains(t, contentStr, "PublicField __lens.Lens[MixedStruct, string]")
|
||||
assert.Contains(t, contentStr, "privateField __lens.Lens[MixedStruct, int]")
|
||||
assert.Contains(t, contentStr, "OptionalPrivate __lens.Lens[MixedStruct, *string]")
|
||||
|
||||
// Check lens constructors
|
||||
assert.Contains(t, contentStr, "func(s MixedStruct) string { return s.PublicField }")
|
||||
assert.Contains(t, contentStr, "func(s MixedStruct) int { return s.privateField }")
|
||||
assert.Contains(t, contentStr, "func(s MixedStruct) *string { return s.OptionalPrivate }")
|
||||
|
||||
// Check setters
|
||||
assert.Contains(t, contentStr, "func(s MixedStruct, v string) MixedStruct { s.PublicField = v; return s }")
|
||||
assert.Contains(t, contentStr, "func(s MixedStruct, v int) MixedStruct { s.privateField = v; return s }")
|
||||
assert.Contains(t, contentStr, "func(s MixedStruct, v *string) MixedStruct { s.OptionalPrivate = v; return s }")
|
||||
}
|
||||
|
||||
func TestParseFileWithOnlyUnexportedFields(t *testing.T) {
|
||||
// Create a temporary test file
|
||||
tmpDir := t.TempDir()
|
||||
testFile := filepath.Join(tmpDir, "test.go")
|
||||
|
||||
testCode := `package testpkg
|
||||
|
||||
// fp-go:Lens
|
||||
type PrivateConfig struct {
|
||||
name string
|
||||
value int
|
||||
enabled bool
|
||||
}
|
||||
`
|
||||
|
||||
err := os.WriteFile(testFile, []byte(testCode), 0o644)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Parse the file
|
||||
structs, pkg, err := parseFile(testFile)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify results
|
||||
assert.Equal(t, "testpkg", pkg)
|
||||
assert.Len(t, structs, 1)
|
||||
|
||||
// Check PrivateConfig struct
|
||||
config := structs[0]
|
||||
assert.Equal(t, "PrivateConfig", config.Name)
|
||||
assert.Len(t, config.Fields, 3, "Should include all unexported fields")
|
||||
|
||||
// Check all fields are unexported
|
||||
assert.Equal(t, "name", config.Fields[0].Name)
|
||||
assert.Equal(t, "value", config.Fields[1].Name)
|
||||
assert.Equal(t, "enabled", config.Fields[2].Name)
|
||||
}
|
||||
|
||||
func TestGenerateLensHelpersWithUnexportedEmbeddedFields(t *testing.T) {
|
||||
// Create a temporary directory with test files
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
testCode := `package testpkg
|
||||
|
||||
type BaseConfig struct {
|
||||
publicBase string
|
||||
privateBase int
|
||||
}
|
||||
|
||||
// fp-go:Lens
|
||||
type ExtendedConfig struct {
|
||||
BaseConfig
|
||||
PublicField string
|
||||
privateField bool
|
||||
}
|
||||
`
|
||||
|
||||
testFile := filepath.Join(tmpDir, "test.go")
|
||||
err := os.WriteFile(testFile, []byte(testCode), 0o644)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Generate lens code
|
||||
outputFile := "gen_lens.go"
|
||||
err = generateLensHelpers(tmpDir, outputFile, false, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify the generated file exists
|
||||
genPath := filepath.Join(tmpDir, outputFile)
|
||||
_, err = os.Stat(genPath)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Read and verify the generated content
|
||||
content, err := os.ReadFile(genPath)
|
||||
require.NoError(t, err)
|
||||
|
||||
contentStr := string(content)
|
||||
|
||||
// Check for expected content
|
||||
assert.Contains(t, contentStr, "package testpkg")
|
||||
assert.Contains(t, contentStr, "ExtendedConfigLenses")
|
||||
|
||||
// Check that lenses are generated for embedded unexported fields
|
||||
assert.Contains(t, contentStr, "publicBase __lens.Lens[ExtendedConfig, string]")
|
||||
assert.Contains(t, contentStr, "privateBase __lens.Lens[ExtendedConfig, int]")
|
||||
|
||||
// Check that lenses are generated for direct fields (both exported and unexported)
|
||||
assert.Contains(t, contentStr, "PublicField __lens.Lens[ExtendedConfig, string]")
|
||||
assert.Contains(t, contentStr, "privateField __lens.Lens[ExtendedConfig, bool]")
|
||||
}
|
||||
|
||||
func TestParseFileWithMixedFieldVisibility(t *testing.T) {
|
||||
// Create a temporary test file with various field visibility patterns
|
||||
tmpDir := t.TempDir()
|
||||
testFile := filepath.Join(tmpDir, "test.go")
|
||||
|
||||
testCode := `package testpkg
|
||||
|
||||
// fp-go:Lens
|
||||
type ComplexStruct struct {
|
||||
// Exported fields
|
||||
Name string
|
||||
Age int
|
||||
Email *string
|
||||
|
||||
// Unexported fields
|
||||
password string
|
||||
secretKey []byte
|
||||
internalID *int
|
||||
|
||||
// Mixed with tags
|
||||
PublicWithTag string ` + "`json:\"public,omitempty\"`" + `
|
||||
privateWithTag int ` + "`json:\"private,omitempty\"`" + `
|
||||
}
|
||||
`
|
||||
|
||||
err := os.WriteFile(testFile, []byte(testCode), 0o644)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Parse the file
|
||||
structs, pkg, err := parseFile(testFile)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify results
|
||||
assert.Equal(t, "testpkg", pkg)
|
||||
assert.Len(t, structs, 1)
|
||||
|
||||
// Check ComplexStruct
|
||||
complex := structs[0]
|
||||
assert.Equal(t, "ComplexStruct", complex.Name)
|
||||
assert.Len(t, complex.Fields, 8, "Should include all fields regardless of visibility")
|
||||
|
||||
// Verify field names and types
|
||||
fieldNames := []string{"Name", "Age", "Email", "password", "secretKey", "internalID", "PublicWithTag", "privateWithTag"}
|
||||
for i, expectedName := range fieldNames {
|
||||
assert.Equal(t, expectedName, complex.Fields[i].Name, "Field %d should be %s", i, expectedName)
|
||||
}
|
||||
|
||||
// Check optional fields
|
||||
assert.False(t, complex.Fields[0].IsOptional, "Name should not be optional")
|
||||
assert.True(t, complex.Fields[2].IsOptional, "Email (pointer) should be optional")
|
||||
assert.True(t, complex.Fields[5].IsOptional, "internalID (pointer) should be optional")
|
||||
assert.True(t, complex.Fields[6].IsOptional, "PublicWithTag (with omitempty) should be optional")
|
||||
assert.True(t, complex.Fields[7].IsOptional, "privateWithTag (with omitempty) should be optional")
|
||||
}
|
||||
|
||||
@@ -230,8 +230,16 @@ type Person struct {
|
||||
Email string
|
||||
Phone *string // Optional field
|
||||
}
|
||||
|
||||
// fp-go:Lens
|
||||
type Config struct {
|
||||
PublicField string
|
||||
privateField int // Unexported fields are supported!
|
||||
}
|
||||
```
|
||||
|
||||
**Note:** The generator supports both exported (uppercase) and unexported (lowercase) fields. Generated lenses for unexported fields will have lowercase names and can only be used within the same package as the struct.
|
||||
|
||||
2. **Run `go generate`**:
|
||||
|
||||
```bash
|
||||
@@ -268,6 +276,7 @@ The generator supports:
|
||||
- ✅ Embedded structs (fields are promoted)
|
||||
- ✅ Optional fields (pointers and `omitempty` tags)
|
||||
- ✅ Custom package imports
|
||||
- ✅ **Unexported fields** (lowercase names) - lenses will have lowercase names matching the field names
|
||||
|
||||
See [samples/lens](../samples/lens) for complete examples.
|
||||
|
||||
|
||||
235
v2/samples/builder/README.md
Normal file
235
v2/samples/builder/README.md
Normal file
@@ -0,0 +1,235 @@
|
||||
# 🏗️ Builder Pattern with fp-go
|
||||
|
||||
This package demonstrates a functional builder pattern using fp-go's optics library. It shows how to construct and validate objects using lenses, prisms, and codecs, separating the building phase from validation.
|
||||
|
||||
## 📋 Overview
|
||||
|
||||
The builder pattern here uses two key types:
|
||||
|
||||
- **`PartialPerson`** 🚧: An intermediate type with unvalidated fields (raw `string` and `int`)
|
||||
- **`Person`** ✅: A validated type with refined fields (`NonEmptyString` and `AdultAge`)
|
||||
|
||||
The pattern provides two approaches for validation:
|
||||
|
||||
1. **Prism-based validation** 🔍 (simple, no error messages)
|
||||
2. **Codec-based validation** 📝 (detailed error reporting)
|
||||
|
||||
## 🎯 Core Concepts
|
||||
|
||||
### 1. 🔧 Auto-Generated Lenses
|
||||
|
||||
The `fp-go:Lens` directive in `types.go` generates lens accessors for both types:
|
||||
|
||||
```go
|
||||
// fp-go:Lens
|
||||
type PartialPerson struct {
|
||||
name string
|
||||
age int
|
||||
}
|
||||
|
||||
// fp-go:Lens
|
||||
type Person struct {
|
||||
Name NonEmptyString
|
||||
Age AdultAge
|
||||
}
|
||||
```
|
||||
|
||||
This generates:
|
||||
- `partialPersonLenses` with `.name` and `.age` lenses
|
||||
- `personLenses` with `.Name` and `.Age` lenses
|
||||
|
||||
### 2. 🎁 Exporting Setters as `WithXXX` Methods
|
||||
|
||||
The lens setters are exported as builder methods:
|
||||
|
||||
```go
|
||||
// WithName sets the Name field of a PartialPerson
|
||||
WithName = partialPersonLenses.name.Set
|
||||
|
||||
// WithAge sets the Age field of a PartialPerson
|
||||
WithAge = partialPersonLenses.age.Set
|
||||
```
|
||||
|
||||
These return `Endomorphism[*PartialPerson]` functions that can be composed:
|
||||
|
||||
```go
|
||||
builder := F.Pipe1(
|
||||
A.From(
|
||||
WithName("Alice"),
|
||||
WithAge(25),
|
||||
),
|
||||
allOfPartialPerson,
|
||||
)
|
||||
partial := builder(&PartialPerson{})
|
||||
```
|
||||
|
||||
Or use the convenience function:
|
||||
|
||||
```go
|
||||
builder := MakePerson("Alice", 25)
|
||||
```
|
||||
|
||||
## 🔍 Approach 1: Prism-Based Validation (No Error Messages)
|
||||
|
||||
### Creating Validation Prisms
|
||||
|
||||
Define prisms that validate individual fields:
|
||||
|
||||
> 💡 **Tip**: The `optics/prism` package provides many helpful out-of-the-box prisms for common validations, including:
|
||||
> - `NonEmptyString()` - validates non-empty strings
|
||||
> - `ParseInt()`, `ParseInt64()` - parses integers from strings
|
||||
> - `ParseFloat32()`, `ParseFloat64()` - parses floats from strings
|
||||
> - `ParseBool()` - parses booleans from strings
|
||||
> - `ParseDate(layout)` - parses dates with custom layouts
|
||||
> - `ParseURL()` - parses URLs
|
||||
> - `FromZero()`, `FromNonZero()` - validates zero/non-zero values
|
||||
> - `RegexMatcher()`, `RegexNamedMatcher()` - regex-based validation
|
||||
> - `FromOption()`, `FromEither()`, `FromResult()` - extracts from monadic types
|
||||
> - And many more! Check `optics/prism/prisms.go` for the full list.
|
||||
>
|
||||
> For custom validation logic, create your own prisms:
|
||||
|
||||
```go
|
||||
namePrism = prism.MakePrismWithName(
|
||||
func(s string) Option[NonEmptyString] {
|
||||
if S.IsEmpty(s) {
|
||||
return option.None[NonEmptyString]()
|
||||
}
|
||||
return option.Of(NonEmptyString(s))
|
||||
},
|
||||
func(ns NonEmptyString) string {
|
||||
return string(ns)
|
||||
},
|
||||
"NonEmptyString",
|
||||
)
|
||||
|
||||
agePrism = prism.MakePrismWithName(
|
||||
func(a int) Option[AdultAge] {
|
||||
if a < 18 {
|
||||
return option.None[AdultAge]()
|
||||
}
|
||||
return option.Of(AdultAge(a))
|
||||
},
|
||||
func(aa AdultAge) int {
|
||||
return int(aa)
|
||||
},
|
||||
"AdultAge",
|
||||
)
|
||||
```
|
||||
|
||||
### 🎭 Creating the PersonPrism
|
||||
|
||||
The `PersonPrism` converts between a builder and a validated `Person`:
|
||||
|
||||
```go
|
||||
PersonPrism = prism.MakePrismWithName(
|
||||
buildPerson(), // Forward: builder -> Option[*Person]
|
||||
buildEndomorphism(), // Reverse: *Person -> builder
|
||||
"Person",
|
||||
)
|
||||
```
|
||||
|
||||
**Forward direction** ➡️ (`buildPerson`):
|
||||
1. Applies the builder to an empty `PartialPerson`
|
||||
2. Validates each field using field prisms
|
||||
3. Returns `Some(*Person)` if all validations pass, `None` otherwise
|
||||
|
||||
**Reverse direction** ⬅️ (`buildEndomorphism`):
|
||||
1. Extracts validated fields from `Person`
|
||||
2. Converts them back to raw types
|
||||
3. Returns a builder that reconstructs the `PartialPerson`
|
||||
|
||||
### 💡 Usage Example
|
||||
|
||||
```go
|
||||
// Create a builder
|
||||
builder := MakePerson("Alice", 25)
|
||||
|
||||
// Validate and convert to Person
|
||||
maybePerson := PersonPrism.GetOption(builder)
|
||||
|
||||
// maybePerson is Option[*Person]
|
||||
// - Some(*Person) if validation succeeds ✅
|
||||
// - None if validation fails (no error details) ❌
|
||||
```
|
||||
|
||||
## 📝 Approach 2: Codec-Based Validation (With Error Messages)
|
||||
|
||||
### Creating Field Codecs
|
||||
|
||||
Convert prisms to codecs for detailed validation:
|
||||
|
||||
```go
|
||||
nameCodec = codec.FromRefinement(namePrism)
|
||||
ageCodec = codec.FromRefinement(agePrism)
|
||||
```
|
||||
|
||||
### 🎯 Creating the PersonCodec
|
||||
|
||||
The `PersonCodec` provides bidirectional transformation with validation:
|
||||
|
||||
```go
|
||||
func makePersonCodec() PersonCodec {
|
||||
return codec.MakeType(
|
||||
"Person",
|
||||
codec.Is[*Person](),
|
||||
makePersonValidate(), // Validation with error reporting
|
||||
buildEndomorphism(), // Encoding (same as prism)
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
The `makePersonValidate` function:
|
||||
1. Applies the builder to an empty `PartialPerson`
|
||||
2. Validates each field using field codecs
|
||||
3. Accumulates validation errors using applicative composition 📚
|
||||
4. Returns `Validation[*Person]` (either errors or a valid `Person`)
|
||||
|
||||
### 💡 Usage Example
|
||||
|
||||
```go
|
||||
// Create a builder
|
||||
builder := MakePerson("", 15) // Invalid: empty name, age < 18
|
||||
|
||||
// Validate with detailed errors
|
||||
personCodec := makePersonCodec()
|
||||
validation := personCodec.Validate(builder)
|
||||
|
||||
// validation is Validation[*Person]
|
||||
// - Right(*Person) if validation succeeds ✅
|
||||
// - Left(ValidationErrors) with detailed error messages if validation fails ❌
|
||||
```
|
||||
|
||||
## ⚖️ Key Differences
|
||||
|
||||
| Feature | Prism-Based 🔍 | Codec-Based 📝 |
|
||||
|---------|-------------|-------------|
|
||||
| Error Messages | No (returns `None`) ❌ | Yes (returns detailed errors) ✅ |
|
||||
| Complexity | Simpler 🟢 | More complex 🟡 |
|
||||
| Use Case | Simple validation | Production validation with user feedback |
|
||||
| Return Type | `Option[*Person]` | `Validation[*Person]` |
|
||||
|
||||
## 📝 Pattern Summary
|
||||
|
||||
1. **Define types** 📐: Create `PartialPerson` (unvalidated) and `Person` (validated)
|
||||
2. **Generate lenses** 🔧: Use `fp-go:Lens` directive
|
||||
3. **Export setters** 🎁: Create `WithXXX` methods from lens setters
|
||||
4. **Create validation prisms** 🎭: Define validation rules for each field
|
||||
5. **Choose validation approach** ⚖️:
|
||||
- **Simple** 🔍: Create a `Prism` for quick validation without errors
|
||||
- **Detailed** 📝: Create a `Codec` for validation with error reporting
|
||||
|
||||
## ✨ Benefits
|
||||
|
||||
- **Type Safety** 🛡️: Validated types guarantee business rules at compile time
|
||||
- **Composability** 🧩: Builders can be composed using monoid operations
|
||||
- **Bidirectional** ↔️: Both prisms and codecs support encoding and decoding
|
||||
- **Separation of Concerns** 🎯: Building and validation are separate phases
|
||||
- **Functional** 🔄: Pure functions, no mutation, easy to test
|
||||
|
||||
## 📁 Files
|
||||
|
||||
- `types.go`: Type definitions and lens generation directives
|
||||
- `builder.go`: Prism-based builder implementation
|
||||
- `codec.go`: Codec-based validation implementation
|
||||
- `codec_test.go`: Tests demonstrating usage patterns
|
||||
@@ -90,7 +90,7 @@ var (
|
||||
// Example:
|
||||
// builder := WithName("Alice")
|
||||
// person := builder(&PartialPerson{})
|
||||
WithName = partialPersonLenses.Name.Set
|
||||
WithName = partialPersonLenses.name.Set
|
||||
|
||||
// WithAge is a builder function that sets the Age field of a PartialPerson.
|
||||
// It returns an endomorphism that can be composed with other builder operations.
|
||||
@@ -98,7 +98,7 @@ var (
|
||||
// Example:
|
||||
// builder := WithAge(25)
|
||||
// person := builder(&PartialPerson{})
|
||||
WithAge = partialPersonLenses.Age.Set
|
||||
WithAge = partialPersonLenses.age.Set
|
||||
|
||||
// PersonPrism is a prism that converts between a builder pattern (Endomorphism[*PartialPerson])
|
||||
// and a validated Person in both directions.
|
||||
@@ -160,7 +160,7 @@ func buildPerson() ReaderOption[Endomorphism[*PartialPerson], *Person] {
|
||||
// maybeName extracts the name from PartialPerson, validates it,
|
||||
// and creates a setter for the Person's Name field if valid
|
||||
maybeName := F.Flow3(
|
||||
partialPersonLenses.Name.Get,
|
||||
partialPersonLenses.name.Get,
|
||||
namePrism.GetOption,
|
||||
option.Map(personLenses.Name.Set),
|
||||
)
|
||||
@@ -168,7 +168,7 @@ func buildPerson() ReaderOption[Endomorphism[*PartialPerson], *Person] {
|
||||
// maybeAge extracts the age from PartialPerson, validates it,
|
||||
// and creates a setter for the Person's Age field if valid
|
||||
maybeAge := F.Flow3(
|
||||
partialPersonLenses.Age.Get,
|
||||
partialPersonLenses.age.Get,
|
||||
agePrism.GetOption,
|
||||
option.Map(personLenses.Age.Set),
|
||||
)
|
||||
@@ -200,7 +200,7 @@ func buildEndomorphism() Reader[*Person, Endomorphism[*PartialPerson]] {
|
||||
name := F.Flow3(
|
||||
personLenses.Name.Get,
|
||||
namePrism.ReverseGet,
|
||||
partialPersonLenses.Name.Set,
|
||||
partialPersonLenses.name.Set,
|
||||
)
|
||||
|
||||
// age extracts the validated age, converts it to int,
|
||||
@@ -208,7 +208,7 @@ func buildEndomorphism() Reader[*Person, Endomorphism[*PartialPerson]] {
|
||||
age := F.Flow3(
|
||||
personLenses.Age.Get,
|
||||
agePrism.ReverseGet,
|
||||
partialPersonLenses.Age.Set,
|
||||
partialPersonLenses.age.Set,
|
||||
)
|
||||
|
||||
// Combine the field extractors into a single builder
|
||||
|
||||
@@ -81,7 +81,7 @@ func makePersonValidate() Validate[Endomorphism[*PartialPerson], *Person] {
|
||||
// 2. Validate using nameCodec (ensures non-empty)
|
||||
// 3. Map to a Person name setter if valid
|
||||
valName := F.Flow3(
|
||||
partialPersonLenses.Name.Get,
|
||||
partialPersonLenses.name.Get,
|
||||
nameCodec.Validate,
|
||||
decode.Map[validation.Context](personLenses.Name.Set),
|
||||
)
|
||||
@@ -91,7 +91,7 @@ func makePersonValidate() Validate[Endomorphism[*PartialPerson], *Person] {
|
||||
// 2. Validate using ageCodec (ensures >= 18)
|
||||
// 3. Map to a Person age setter if valid
|
||||
valAge := F.Flow3(
|
||||
partialPersonLenses.Age.Get,
|
||||
partialPersonLenses.age.Get,
|
||||
ageCodec.Validate,
|
||||
decode.Map[validation.Context](personLenses.Age.Set),
|
||||
)
|
||||
|
||||
@@ -151,8 +151,8 @@ func TestMakePersonCodec_Encode(t *testing.T) {
|
||||
partial := builder(emptyPartialPerson)
|
||||
|
||||
// Assert
|
||||
assert.Equal(t, "Eve", partial.Name)
|
||||
assert.Equal(t, 28, partial.Age)
|
||||
assert.Equal(t, "Eve", partial.name)
|
||||
assert.Equal(t, 28, partial.age)
|
||||
}
|
||||
|
||||
// TestMakePersonCodec_RoundTrip tests encoding and decoding round-trip
|
||||
|
||||
@@ -2,7 +2,7 @@ package builder
|
||||
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at
|
||||
// 2026-01-23 12:56:01.1431839 +0100 CET m=+0.004353901
|
||||
// 2026-01-23 16:15:30.703391 +0100 CET m=+0.003782501
|
||||
|
||||
import (
|
||||
__lens "github.com/IBM/fp-go/v2/optics/lens"
|
||||
@@ -15,105 +15,105 @@ import (
|
||||
// PartialPersonLenses provides lenses for accessing fields of PartialPerson
|
||||
type PartialPersonLenses struct {
|
||||
// mandatory fields
|
||||
Name __lens.Lens[PartialPerson, string]
|
||||
Age __lens.Lens[PartialPerson, int]
|
||||
name __lens.Lens[PartialPerson, string]
|
||||
age __lens.Lens[PartialPerson, int]
|
||||
// optional fields
|
||||
NameO __lens_option.LensO[PartialPerson, string]
|
||||
AgeO __lens_option.LensO[PartialPerson, int]
|
||||
nameO __lens_option.LensO[PartialPerson, string]
|
||||
ageO __lens_option.LensO[PartialPerson, int]
|
||||
}
|
||||
|
||||
// PartialPersonRefLenses provides lenses for accessing fields of PartialPerson via a reference to PartialPerson
|
||||
type PartialPersonRefLenses struct {
|
||||
// mandatory fields
|
||||
Name __lens.Lens[*PartialPerson, string]
|
||||
Age __lens.Lens[*PartialPerson, int]
|
||||
name __lens.Lens[*PartialPerson, string]
|
||||
age __lens.Lens[*PartialPerson, int]
|
||||
// optional fields
|
||||
NameO __lens_option.LensO[*PartialPerson, string]
|
||||
AgeO __lens_option.LensO[*PartialPerson, int]
|
||||
nameO __lens_option.LensO[*PartialPerson, string]
|
||||
ageO __lens_option.LensO[*PartialPerson, int]
|
||||
// prisms
|
||||
NameP __prism.Prism[*PartialPerson, string]
|
||||
AgeP __prism.Prism[*PartialPerson, int]
|
||||
nameP __prism.Prism[*PartialPerson, string]
|
||||
ageP __prism.Prism[*PartialPerson, int]
|
||||
}
|
||||
|
||||
// PartialPersonPrisms provides prisms for accessing fields of PartialPerson
|
||||
type PartialPersonPrisms struct {
|
||||
Name __prism.Prism[PartialPerson, string]
|
||||
Age __prism.Prism[PartialPerson, int]
|
||||
name __prism.Prism[PartialPerson, string]
|
||||
age __prism.Prism[PartialPerson, int]
|
||||
}
|
||||
|
||||
// MakePartialPersonLenses creates a new PartialPersonLenses with lenses for all fields
|
||||
func MakePartialPersonLenses() PartialPersonLenses {
|
||||
// mandatory lenses
|
||||
lensName := __lens.MakeLensWithName(
|
||||
func(s PartialPerson) string { return s.Name },
|
||||
func(s PartialPerson, v string) PartialPerson { s.Name = v; return s },
|
||||
"PartialPerson.Name",
|
||||
lensname := __lens.MakeLensWithName(
|
||||
func(s PartialPerson) string { return s.name },
|
||||
func(s PartialPerson, v string) PartialPerson { s.name = v; return s },
|
||||
"PartialPerson.name",
|
||||
)
|
||||
lensAge := __lens.MakeLensWithName(
|
||||
func(s PartialPerson) int { return s.Age },
|
||||
func(s PartialPerson, v int) PartialPerson { s.Age = v; return s },
|
||||
"PartialPerson.Age",
|
||||
lensage := __lens.MakeLensWithName(
|
||||
func(s PartialPerson) int { return s.age },
|
||||
func(s PartialPerson, v int) PartialPerson { s.age = v; return s },
|
||||
"PartialPerson.age",
|
||||
)
|
||||
// optional lenses
|
||||
lensNameO := __lens_option.FromIso[PartialPerson](__iso_option.FromZero[string]())(lensName)
|
||||
lensAgeO := __lens_option.FromIso[PartialPerson](__iso_option.FromZero[int]())(lensAge)
|
||||
lensnameO := __lens_option.FromIso[PartialPerson](__iso_option.FromZero[string]())(lensname)
|
||||
lensageO := __lens_option.FromIso[PartialPerson](__iso_option.FromZero[int]())(lensage)
|
||||
return PartialPersonLenses{
|
||||
// mandatory lenses
|
||||
Name: lensName,
|
||||
Age: lensAge,
|
||||
name: lensname,
|
||||
age: lensage,
|
||||
// optional lenses
|
||||
NameO: lensNameO,
|
||||
AgeO: lensAgeO,
|
||||
nameO: lensnameO,
|
||||
ageO: lensageO,
|
||||
}
|
||||
}
|
||||
|
||||
// MakePartialPersonRefLenses creates a new PartialPersonRefLenses with lenses for all fields
|
||||
func MakePartialPersonRefLenses() PartialPersonRefLenses {
|
||||
// mandatory lenses
|
||||
lensName := __lens.MakeLensStrictWithName(
|
||||
func(s *PartialPerson) string { return s.Name },
|
||||
func(s *PartialPerson, v string) *PartialPerson { s.Name = v; return s },
|
||||
"(*PartialPerson).Name",
|
||||
lensname := __lens.MakeLensStrictWithName(
|
||||
func(s *PartialPerson) string { return s.name },
|
||||
func(s *PartialPerson, v string) *PartialPerson { s.name = v; return s },
|
||||
"(*PartialPerson).name",
|
||||
)
|
||||
lensAge := __lens.MakeLensStrictWithName(
|
||||
func(s *PartialPerson) int { return s.Age },
|
||||
func(s *PartialPerson, v int) *PartialPerson { s.Age = v; return s },
|
||||
"(*PartialPerson).Age",
|
||||
lensage := __lens.MakeLensStrictWithName(
|
||||
func(s *PartialPerson) int { return s.age },
|
||||
func(s *PartialPerson, v int) *PartialPerson { s.age = v; return s },
|
||||
"(*PartialPerson).age",
|
||||
)
|
||||
// optional lenses
|
||||
lensNameO := __lens_option.FromIso[*PartialPerson](__iso_option.FromZero[string]())(lensName)
|
||||
lensAgeO := __lens_option.FromIso[*PartialPerson](__iso_option.FromZero[int]())(lensAge)
|
||||
lensnameO := __lens_option.FromIso[*PartialPerson](__iso_option.FromZero[string]())(lensname)
|
||||
lensageO := __lens_option.FromIso[*PartialPerson](__iso_option.FromZero[int]())(lensage)
|
||||
return PartialPersonRefLenses{
|
||||
// mandatory lenses
|
||||
Name: lensName,
|
||||
Age: lensAge,
|
||||
name: lensname,
|
||||
age: lensage,
|
||||
// optional lenses
|
||||
NameO: lensNameO,
|
||||
AgeO: lensAgeO,
|
||||
nameO: lensnameO,
|
||||
ageO: lensageO,
|
||||
}
|
||||
}
|
||||
|
||||
// MakePartialPersonPrisms creates a new PartialPersonPrisms with prisms for all fields
|
||||
func MakePartialPersonPrisms() PartialPersonPrisms {
|
||||
_fromNonZeroName := __option.FromNonZero[string]()
|
||||
_prismName := __prism.MakePrismWithName(
|
||||
func(s PartialPerson) __option.Option[string] { return _fromNonZeroName(s.Name) },
|
||||
_fromNonZeroname := __option.FromNonZero[string]()
|
||||
_prismname := __prism.MakePrismWithName(
|
||||
func(s PartialPerson) __option.Option[string] { return _fromNonZeroname(s.name) },
|
||||
func(v string) PartialPerson {
|
||||
return PartialPerson{ Name: v }
|
||||
return PartialPerson{ name: v }
|
||||
},
|
||||
"PartialPerson.Name",
|
||||
"PartialPerson.name",
|
||||
)
|
||||
_fromNonZeroAge := __option.FromNonZero[int]()
|
||||
_prismAge := __prism.MakePrismWithName(
|
||||
func(s PartialPerson) __option.Option[int] { return _fromNonZeroAge(s.Age) },
|
||||
_fromNonZeroage := __option.FromNonZero[int]()
|
||||
_prismage := __prism.MakePrismWithName(
|
||||
func(s PartialPerson) __option.Option[int] { return _fromNonZeroage(s.age) },
|
||||
func(v int) PartialPerson {
|
||||
return PartialPerson{ Age: v }
|
||||
return PartialPerson{ age: v }
|
||||
},
|
||||
"PartialPerson.Age",
|
||||
"PartialPerson.age",
|
||||
)
|
||||
return PartialPersonPrisms {
|
||||
Name: _prismName,
|
||||
Age: _prismAge,
|
||||
name: _prismname,
|
||||
age: _prismage,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,13 +38,37 @@ type (
|
||||
// a value of type A. It is an alias for reader.Reader[R, A].
|
||||
Reader[R, A any] = reader.Reader[R, A]
|
||||
|
||||
// Prism represents an optic that focuses on a subset of values of type S that can be
|
||||
// converted to type A. It provides bidirectional transformation with validation.
|
||||
// It is an alias for prism.Prism[S, A].
|
||||
Prism[S, A any] = prism.Prism[S, A]
|
||||
Lens[S, A any] = lens.Lens[S, A]
|
||||
|
||||
Type[A, O, I any] = codec.Type[A, O, I]
|
||||
// Lens represents an optic that focuses on a field of type A within a structure of type S.
|
||||
// It provides getter and setter operations for immutable updates.
|
||||
// It is an alias for lens.Lens[S, A].
|
||||
Lens[S, A any] = lens.Lens[S, A]
|
||||
|
||||
// Type represents a codec that handles bidirectional transformation between types.
|
||||
// A: The validated target type
|
||||
// O: The output encoding type
|
||||
// I: The input decoding type
|
||||
// It is an alias for codec.Type[A, O, I].
|
||||
Type[A, O, I any] = codec.Type[A, O, I]
|
||||
|
||||
// Validate represents a validation function that transforms input I into a validated result A.
|
||||
// It returns a Validation that contains either the validated value or validation errors.
|
||||
// It is an alias for validate.Validate[I, A].
|
||||
Validate[I, A any] = validate.Validate[I, A]
|
||||
Validation[A any] = validation.Validation[A]
|
||||
Encode[A, O any] = codec.Encode[A, O]
|
||||
|
||||
// Validation represents the result of a validation operation.
|
||||
// It contains either a validated value of type A (Right) or validation errors (Left).
|
||||
// It is an alias for validation.Validation[A].
|
||||
Validation[A any] = validation.Validation[A]
|
||||
|
||||
// Encode represents an encoding function that transforms a value of type A into type O.
|
||||
// It is used in codecs for the reverse direction of validation.
|
||||
// It is an alias for codec.Encode[A, O].
|
||||
Encode[A, O any] = codec.Encode[A, O]
|
||||
|
||||
// NonEmptyString is a string type that represents a validated non-empty string.
|
||||
// It is used to ensure that string fields contain meaningful data.
|
||||
@@ -64,11 +88,11 @@ type (
|
||||
//
|
||||
// fp-go:Lens
|
||||
type PartialPerson struct {
|
||||
// Name is the person's name as a raw string, which may be empty or invalid.
|
||||
Name string
|
||||
// name is the person's name as a raw string, which may be empty or invalid.
|
||||
name string
|
||||
|
||||
// Age is the person's age as a raw integer, which may be negative or otherwise invalid.
|
||||
Age int
|
||||
// age is the person's age as a raw integer, which may be negative or otherwise invalid.
|
||||
age int
|
||||
}
|
||||
|
||||
// Person represents a person record with validated fields.
|
||||
|
||||
@@ -107,7 +107,7 @@ func TestHeterogeneousHttpRequests(t *testing.T) {
|
||||
// BenchmarkHeterogeneousHttpRequests shows how to execute multiple HTTP requests in parallel when
|
||||
// the response structure of these requests is different. We use [R.TraverseTuple2] to account for the different types
|
||||
func BenchmarkHeterogeneousHttpRequests(b *testing.B) {
|
||||
for n := 0; n < b.N; n++ {
|
||||
heterogeneousHTTPRequests()(context.Background())()
|
||||
for b.Loop() {
|
||||
heterogeneousHTTPRequests()(b.Context())()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,3 +64,9 @@ type WithGeneric[T any] struct {
|
||||
Name string
|
||||
Value T
|
||||
}
|
||||
|
||||
// fp-go:Lens
|
||||
type DataBuilder struct {
|
||||
name string
|
||||
value string
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
F "github.com/IBM/fp-go/v2/function"
|
||||
L "github.com/IBM/fp-go/v2/optics/lens"
|
||||
O "github.com/IBM/fp-go/v2/option"
|
||||
S "github.com/IBM/fp-go/v2/string"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@@ -341,3 +342,125 @@ func TestCompanyRefLensesOptionalIdempotent(t *testing.T) {
|
||||
assert.Equal(t, &newWebsiteValue, differentWebsite.Website)
|
||||
assert.Equal(t, &websiteValue, company.Website, "Original should be unchanged")
|
||||
}
|
||||
|
||||
func TestDataBuilderLensWithUnexportedFields(t *testing.T) {
|
||||
// Test that lenses can access and modify unexported fields
|
||||
// This demonstrates that the lens generator now supports unexported fields
|
||||
|
||||
// Create a DataBuilder with unexported fields
|
||||
builder := DataBuilder{
|
||||
name: "initial-name",
|
||||
value: "initial-value",
|
||||
}
|
||||
|
||||
// Create lenses
|
||||
lenses := MakeDataBuilderLenses()
|
||||
|
||||
// Test Get on unexported fields
|
||||
assert.Equal(t, "initial-name", lenses.name.Get(builder))
|
||||
assert.Equal(t, "initial-value", lenses.value.Get(builder))
|
||||
|
||||
// Test Set on unexported fields
|
||||
updatedName := lenses.name.Set("updated-name")(builder)
|
||||
assert.Equal(t, "updated-name", updatedName.name)
|
||||
assert.Equal(t, "initial-value", updatedName.value) // Other field unchanged
|
||||
assert.Equal(t, "initial-name", builder.name) // Original unchanged
|
||||
|
||||
updatedValue := lenses.value.Set("updated-value")(builder)
|
||||
assert.Equal(t, "initial-name", updatedValue.name) // Other field unchanged
|
||||
assert.Equal(t, "updated-value", updatedValue.value)
|
||||
assert.Equal(t, "initial-value", builder.value) // Original unchanged
|
||||
|
||||
// Test Modify on unexported fields
|
||||
modifyName := F.Pipe1(
|
||||
lenses.name,
|
||||
L.Modify[DataBuilder](S.Append("-modified")),
|
||||
)
|
||||
modified := modifyName(builder)
|
||||
assert.Equal(t, "initial-name-modified", modified.name)
|
||||
assert.Equal(t, "initial-name", builder.name) // Original unchanged
|
||||
|
||||
// Test composition of modifications
|
||||
updatedBoth := F.Pipe2(
|
||||
builder,
|
||||
lenses.name.Set("new-name"),
|
||||
lenses.value.Set("new-value"),
|
||||
)
|
||||
assert.Equal(t, "new-name", updatedBoth.name)
|
||||
assert.Equal(t, "new-value", updatedBoth.value)
|
||||
assert.Equal(t, "initial-name", builder.name) // Original unchanged
|
||||
assert.Equal(t, "initial-value", builder.value) // Original unchanged
|
||||
}
|
||||
|
||||
func TestDataBuilderRefLensesWithUnexportedFields(t *testing.T) {
|
||||
// Test that ref lenses work with unexported fields and maintain idempotency
|
||||
|
||||
builder := &DataBuilder{
|
||||
name: "test-name",
|
||||
value: "test-value",
|
||||
}
|
||||
|
||||
refLenses := MakeDataBuilderRefLenses()
|
||||
|
||||
// Test Get on unexported fields
|
||||
assert.Equal(t, "test-name", refLenses.name.Get(builder))
|
||||
assert.Equal(t, "test-value", refLenses.value.Get(builder))
|
||||
|
||||
// Test idempotency - setting same value should return same pointer
|
||||
sameName := refLenses.name.Set("test-name")(builder)
|
||||
assert.Same(t, builder, sameName, "Setting name to same value should return identical pointer")
|
||||
|
||||
sameValue := refLenses.value.Set("test-value")(builder)
|
||||
assert.Same(t, builder, sameValue, "Setting value to same value should return identical pointer")
|
||||
|
||||
// Test that setting different value creates new pointer
|
||||
differentName := refLenses.name.Set("different-name")(builder)
|
||||
assert.NotSame(t, builder, differentName, "Setting name to different value should return new pointer")
|
||||
assert.Equal(t, "different-name", differentName.name)
|
||||
assert.Equal(t, "test-name", builder.name, "Original should be unchanged")
|
||||
|
||||
differentValue := refLenses.value.Set("different-value")(builder)
|
||||
assert.NotSame(t, builder, differentValue, "Setting value to different value should return new pointer")
|
||||
assert.Equal(t, "different-value", differentValue.value)
|
||||
assert.Equal(t, "test-value", builder.value, "Original should be unchanged")
|
||||
}
|
||||
|
||||
func TestDataBuilderOptionalLensesWithUnexportedFields(t *testing.T) {
|
||||
// Test optional lenses (LensO) with unexported fields
|
||||
|
||||
builder := DataBuilder{
|
||||
name: "test",
|
||||
value: "data",
|
||||
}
|
||||
|
||||
lenses := MakeDataBuilderLenses()
|
||||
|
||||
// Test getting non-zero values as Some
|
||||
nameOpt := lenses.nameO.Get(builder)
|
||||
assert.True(t, O.IsSome(nameOpt))
|
||||
assert.Equal(t, "test", O.GetOrElse(F.Zero[string])(nameOpt))
|
||||
|
||||
valueOpt := lenses.valueO.Get(builder)
|
||||
assert.True(t, O.IsSome(valueOpt))
|
||||
assert.Equal(t, "data", O.GetOrElse(F.Zero[string])(valueOpt))
|
||||
|
||||
// Test setting to Some
|
||||
updatedName := lenses.nameO.Set(O.Some("new-test"))(builder)
|
||||
assert.Equal(t, "new-test", updatedName.name)
|
||||
|
||||
// Test setting to None (zero value for string is "")
|
||||
clearedName := lenses.nameO.Set(O.None[string]())(builder)
|
||||
assert.Equal(t, "", clearedName.name)
|
||||
|
||||
// Test with zero value
|
||||
emptyBuilder := DataBuilder{
|
||||
name: "",
|
||||
value: "",
|
||||
}
|
||||
|
||||
emptyNameOpt := lenses.nameO.Get(emptyBuilder)
|
||||
assert.True(t, O.IsNone(emptyNameOpt), "Empty string should be None")
|
||||
|
||||
emptyValueOpt := lenses.valueO.Get(emptyBuilder)
|
||||
assert.True(t, O.IsNone(emptyValueOpt), "Empty string should be None")
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package lens
|
||||
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at
|
||||
// 2025-12-16 15:41:28.7198645 +0100 CET m=+0.003889201
|
||||
// 2026-01-23 16:09:35.747264 +0100 CET m=+0.003865601
|
||||
|
||||
import (
|
||||
__lens "github.com/IBM/fp-go/v2/optics/lens"
|
||||
@@ -946,3 +946,108 @@ func MakeWithGenericPrisms[T any]() WithGenericPrisms[T] {
|
||||
Value: _prismValue,
|
||||
}
|
||||
}
|
||||
|
||||
// DataBuilderLenses provides lenses for accessing fields of DataBuilder
|
||||
type DataBuilderLenses struct {
|
||||
// mandatory fields
|
||||
name __lens.Lens[DataBuilder, string]
|
||||
value __lens.Lens[DataBuilder, string]
|
||||
// optional fields
|
||||
nameO __lens_option.LensO[DataBuilder, string]
|
||||
valueO __lens_option.LensO[DataBuilder, string]
|
||||
}
|
||||
|
||||
// DataBuilderRefLenses provides lenses for accessing fields of DataBuilder via a reference to DataBuilder
|
||||
type DataBuilderRefLenses struct {
|
||||
// mandatory fields
|
||||
name __lens.Lens[*DataBuilder, string]
|
||||
value __lens.Lens[*DataBuilder, string]
|
||||
// optional fields
|
||||
nameO __lens_option.LensO[*DataBuilder, string]
|
||||
valueO __lens_option.LensO[*DataBuilder, string]
|
||||
// prisms
|
||||
nameP __prism.Prism[*DataBuilder, string]
|
||||
valueP __prism.Prism[*DataBuilder, string]
|
||||
}
|
||||
|
||||
// DataBuilderPrisms provides prisms for accessing fields of DataBuilder
|
||||
type DataBuilderPrisms struct {
|
||||
name __prism.Prism[DataBuilder, string]
|
||||
value __prism.Prism[DataBuilder, string]
|
||||
}
|
||||
|
||||
// MakeDataBuilderLenses creates a new DataBuilderLenses with lenses for all fields
|
||||
func MakeDataBuilderLenses() DataBuilderLenses {
|
||||
// mandatory lenses
|
||||
lensname := __lens.MakeLensWithName(
|
||||
func(s DataBuilder) string { return s.name },
|
||||
func(s DataBuilder, v string) DataBuilder { s.name = v; return s },
|
||||
"DataBuilder.name",
|
||||
)
|
||||
lensvalue := __lens.MakeLensWithName(
|
||||
func(s DataBuilder) string { return s.value },
|
||||
func(s DataBuilder, v string) DataBuilder { s.value = v; return s },
|
||||
"DataBuilder.value",
|
||||
)
|
||||
// optional lenses
|
||||
lensnameO := __lens_option.FromIso[DataBuilder](__iso_option.FromZero[string]())(lensname)
|
||||
lensvalueO := __lens_option.FromIso[DataBuilder](__iso_option.FromZero[string]())(lensvalue)
|
||||
return DataBuilderLenses{
|
||||
// mandatory lenses
|
||||
name: lensname,
|
||||
value: lensvalue,
|
||||
// optional lenses
|
||||
nameO: lensnameO,
|
||||
valueO: lensvalueO,
|
||||
}
|
||||
}
|
||||
|
||||
// MakeDataBuilderRefLenses creates a new DataBuilderRefLenses with lenses for all fields
|
||||
func MakeDataBuilderRefLenses() DataBuilderRefLenses {
|
||||
// mandatory lenses
|
||||
lensname := __lens.MakeLensStrictWithName(
|
||||
func(s *DataBuilder) string { return s.name },
|
||||
func(s *DataBuilder, v string) *DataBuilder { s.name = v; return s },
|
||||
"(*DataBuilder).name",
|
||||
)
|
||||
lensvalue := __lens.MakeLensStrictWithName(
|
||||
func(s *DataBuilder) string { return s.value },
|
||||
func(s *DataBuilder, v string) *DataBuilder { s.value = v; return s },
|
||||
"(*DataBuilder).value",
|
||||
)
|
||||
// optional lenses
|
||||
lensnameO := __lens_option.FromIso[*DataBuilder](__iso_option.FromZero[string]())(lensname)
|
||||
lensvalueO := __lens_option.FromIso[*DataBuilder](__iso_option.FromZero[string]())(lensvalue)
|
||||
return DataBuilderRefLenses{
|
||||
// mandatory lenses
|
||||
name: lensname,
|
||||
value: lensvalue,
|
||||
// optional lenses
|
||||
nameO: lensnameO,
|
||||
valueO: lensvalueO,
|
||||
}
|
||||
}
|
||||
|
||||
// MakeDataBuilderPrisms creates a new DataBuilderPrisms with prisms for all fields
|
||||
func MakeDataBuilderPrisms() DataBuilderPrisms {
|
||||
_fromNonZeroname := __option.FromNonZero[string]()
|
||||
_prismname := __prism.MakePrismWithName(
|
||||
func(s DataBuilder) __option.Option[string] { return _fromNonZeroname(s.name) },
|
||||
func(v string) DataBuilder {
|
||||
return DataBuilder{ name: v }
|
||||
},
|
||||
"DataBuilder.name",
|
||||
)
|
||||
_fromNonZerovalue := __option.FromNonZero[string]()
|
||||
_prismvalue := __prism.MakePrismWithName(
|
||||
func(s DataBuilder) __option.Option[string] { return _fromNonZerovalue(s.value) },
|
||||
func(v string) DataBuilder {
|
||||
return DataBuilder{ value: v }
|
||||
},
|
||||
"DataBuilder.value",
|
||||
)
|
||||
return DataBuilderPrisms {
|
||||
name: _prismname,
|
||||
value: _prismvalue,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user