Skip to content

Commit

Permalink
always prop
Browse files Browse the repository at this point in the history
  • Loading branch information
Roman Sarvarov committed Jun 12, 2024
1 parent 75bc28d commit 1e13995
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 28 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,14 @@ props := inertia.Props{
i.Render(w, r, "Some/Page", props)
```

Also, Gonertia have support for `always` props ([learn more](https://github.com/inertiajs/inertia-laravel/pull/627)):

```go
props := inertia.Props{
"foo": AlwaysProp(func() any { return "bar" }),
}
```

#### Redirects ([learn more](https://inertiajs.com/redirects))

```go
Expand Down
17 changes: 11 additions & 6 deletions inertia_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,19 +251,21 @@ func TestInertia_Render(t *testing.T) {
asInertiaRequest(r)

err := I().Render(w, r, "Some/Component", Props{
"foo": "bar",
"closure": func() (any, error) { return "prop", nil },
"lazy": LazyProp(func() (any, error) { return "prop", nil }),
"foo": "bar",
"closure": func() any { return "prop" },
"closure_with_err": func() (any, error) { return "prop", nil },
"lazy": LazyProp(func() (any, error) { return "prop", nil }),
})
if err != nil {
t.Fatalf("unexpected error: %#v", err)
}

assertable := AssertFromString(t, w.Body.String())
assertable.AssertProps(Props{
"foo": "bar",
"closure": "prop",
"errors": map[string]any{},
"foo": "bar",
"closure": "prop",
"closure_with_err": "prop",
"errors": map[string]any{},
})
})

Expand All @@ -283,6 +285,7 @@ func TestInertia_Render(t *testing.T) {
"abc": "123",
"closure": func() (any, error) { return "prop", nil },
"lazy": LazyProp(func() (any, error) { return "prop", nil }),
"always": AlwaysProp(func() any { return "prop" }),
})
if err != nil {
t.Fatalf("unexpected error: %#v", err)
Expand All @@ -293,6 +296,8 @@ func TestInertia_Render(t *testing.T) {
"foo": "bar",
"closure": "prop",
"lazy": "prop",
"always": "prop",
"errors": map[string]interface{}{},
})
})

Expand Down
35 changes: 25 additions & 10 deletions props.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ type Props map[string]any
// https://inertiajs.com/partial-reloads
type LazyProp func() (any, error)

// AlwaysProp is a property value that will always evaluated.
//
// https://github.com/inertiajs/inertia-laravel/pull/627
type AlwaysProp func() any

func (i *Inertia) prepareProps(r *http.Request, component string, props Props) (Props, error) {
result := make(Props)

Expand All @@ -22,7 +27,7 @@ func (i *Inertia) prepareProps(r *http.Request, component string, props Props) (
if err != nil {
return nil, fmt.Errorf("getting validation errors from context: %w", err)
}
result["errors"] = ctxValidationErrors
result["errors"] = AlwaysProp(func() any { return ctxValidationErrors })

// Add shared props to the result.
for key, val := range i.sharedProps {
Expand All @@ -49,10 +54,15 @@ func (i *Inertia) prepareProps(r *http.Request, component string, props Props) (

// Filter props.
if len(only) > 0 {
for key := range result {
if _, ok := only[key]; !ok {
delete(result, key)
for key, val := range result {
if _, ok := only[key]; ok {
continue
}
if _, ok := val.(AlwaysProp); ok {
continue
}

delete(result, key)
}
} else {
for key, val := range result {
Expand All @@ -64,7 +74,7 @@ func (i *Inertia) prepareProps(r *http.Request, component string, props Props) (

// Resolve props values.
for key, val := range result {
val, err := resolvePropVal(val)
val, err = resolvePropVal(val)
if err != nil {
return nil, fmt.Errorf("resolve prop value: %w", err)
}
Expand All @@ -79,20 +89,25 @@ func (i *Inertia) propsKeysToReturn(r *http.Request, component string) map[strin
//
// https://inertiajs.com/partial-reloads
if partialComponentFromRequest(r) == component {
return set[string](partialDataFromRequest(r))
return setOf[string](partialDataFromRequest(r))
}

return nil
}

func resolvePropVal(val any) (_ any, err error) {
if closure, ok := val.(func() (any, error)); ok {
val, err = closure()
switch typed := val.(type) {
case func() any:
return typed, nil
case AlwaysProp:
return typed(), nil
case func() (any, error):
val, err = typed()
if err != nil {
return nil, fmt.Errorf("closure prop resolving: %w", err)
}
} else if lazy, ok := val.(LazyProp); ok {
val, err = lazy()
case LazyProp:
val, err = typed()
if err != nil {
return nil, fmt.Errorf("lazy prop resolving: %w", err)
}
Expand Down
2 changes: 1 addition & 1 deletion utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"os"
)

func set[T comparable](data []T) map[T]struct{} {
func setOf[T comparable](data []T) map[T]struct{} {
if len(data) == 0 {
return nil
}
Expand Down
22 changes: 11 additions & 11 deletions utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,69 +5,69 @@ import (
"testing"
)

func Test_set(t *testing.T) {
func Test_setOf(t *testing.T) {
t.Parallel()

t.Run("nil", func(t *testing.T) {
t.Parallel()

got := set[string](nil)
got := setOf[string](nil)
var want map[string]struct{}

if !reflect.DeepEqual(got, want) {
t.Fatalf("set()=%#v, want=%#v", got, want)
t.Fatalf("setOf()=%#v, want=%#v", got, want)
}
})

t.Run("empty", func(t *testing.T) {
t.Parallel()

got := set[string]([]string{})
got := setOf[string]([]string{})
var want map[string]struct{}

if !reflect.DeepEqual(got, want) {
t.Fatalf("set()=%#v, want=%#v", got, want)
t.Fatalf("setOf()=%#v, want=%#v", got, want)
}
})

t.Run("duplicates", func(t *testing.T) {
t.Parallel()

got := set[string]([]string{"foo", "foo"})
got := setOf[string]([]string{"foo", "foo"})
want := map[string]struct{}{
"foo": {},
}

if !reflect.DeepEqual(got, want) {
t.Fatalf("set()=%#v, want=%#v", got, want)
t.Fatalf("setOf()=%#v, want=%#v", got, want)
}
})

t.Run("strings", func(t *testing.T) {
t.Parallel()

got := set[string]([]string{"foo", "bar"})
got := setOf[string]([]string{"foo", "bar"})
want := map[string]struct{}{
"foo": {},
"bar": {},
}

if !reflect.DeepEqual(got, want) {
t.Fatalf("set()=%#v, want=%#v", got, want)
t.Fatalf("setOf()=%#v, want=%#v", got, want)
}
})

t.Run("integers", func(t *testing.T) {
t.Parallel()

got := set[int]([]int{123, 456})
got := setOf[int]([]int{123, 456})
want := map[int]struct{}{
123: {},
456: {},
}

if !reflect.DeepEqual(got, want) {
t.Fatalf("set()=%#v, want=%#v", got, want)
t.Fatalf("setOf()=%#v, want=%#v", got, want)
}
})
}
Expand Down

0 comments on commit 1e13995

Please sign in to comment.