Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

always prop #1

Merged
merged 1 commit into from
Jun 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading