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

Fix behavior of Leaf context encoding and improve Leaf errors #212

Merged
merged 6 commits into from
Aug 17, 2022

Conversation

gwynne
Copy link
Member

@gwynne gwynne commented Aug 13, 2022

Types which use superEncoder(forKey:) in their Codable conformance (such as Fluent models) can now safely be provided to Leaf views as context objects. In general, handling of context encoding is significantly improved.

LeafError now conforms to AbortError and DebuggableError for improved error UI/UX.

gwynne added 2 commits August 13, 2022 12:50
…to Codable requirements, and actually support superEncoder(). Add a bunch of missing test coverage.
@gwynne gwynne added bug Something isn't working semver-patch Internal changes only labels Aug 13, 2022
@gwynne gwynne requested a review from 0xTim August 13, 2022 17:53
@gwynne gwynne self-assigned this Aug 13, 2022
… remove unnecessary usage of _openExistential(), remove some unneeded throws and optionals
Copy link
Member

@0xTim 0xTim left a comment

Choose a reason for hiding this comment

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

LGTM

@dev-xdyang
Copy link

dev-xdyang commented Aug 15, 2022

this pull request is great, but I found a bug.

1: add a route like this, and pass empty list to todoList parameter

func routes(_ app: Application) throws {
    app.get { req async throws -> View in
        let context = DemoModel(title: "Demo", todoList: [])
        return try await req.view.render("demo", context)
    }
}

struct DemoModel: Encodable {
    let title: String
    let todoList: [String]
}

2: in leaf template file, use #count() tag to check the todoList count

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">

  <title>#(title)</title>
</head>

<body>
    #if(count(todoList) > 0):
          <h1>#(title)</h1>
    #else:
          <h1>#(title)</h1>
    #endif
</body>
</html>

when visit this page on browser will encounter error:

{
  "error": true,
  "reason": "Unable to convert count parameter to LeafData collection"
}

and I tested leaf 4.2.0, it work right!

@0xTim
Copy link
Member

0xTim commented Aug 15, 2022

cc @gwynne looks like some behaviour has changed here

Copy link
Member

@0xTim 0xTim left a comment

Choose a reason for hiding this comment

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

Need to fix the count regression (yay for missing test coverage)

@gwynne
Copy link
Member Author

gwynne commented Aug 15, 2022

Yeah, to say the least... I'll add some more tests to cover whatever this turns out to be.

let encoder: EncoderImpl
var data: [LeafEncodingResolvable] = []
var nextCodingKey: CodingKey { GenericCodingKey(intValue: self.count) }
var resolvedData: LeafData? { let compact = data.compactMap(\.resolvedData); return compact.isEmpty ? nil : .array(compact) }

Choose a reason for hiding this comment

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

Was this intentional? It now means that in templates I need to do:

#if(myArray):
  #if(count(myArray) > 0):
    …
  #endif
#endif

Which seems to be a regression of how templates are written.

private final class EncoderKeyedContainerImpl<Key>: KeyedEncodingContainerProtocol, LeafEncodingResolvable where Key: CodingKey {
let encoder: EncoderImpl
var data: [String: LeafEncodingResolvable] = [:]
var resolvedData: LeafData? { let compact = self.data.compactMapValues { $0.resolvedData }; return compact.isEmpty ? nil : .dictionary(compact) }

Choose a reason for hiding this comment

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

Same issue here as with arrays below.

An empty array or dictionary is an intentional choice, and I don't think Leaf should be eliding it, given that it requires double checks.

We also can't do something like this:

#if(myArray && count(myArray) > 0):
 …
#endif

Because of vapor/leaf-kit#85

@gwynne
Copy link
Member Author

gwynne commented Aug 17, 2022

Nope, this is a bug. I'll be pushing a fix for it shortly.

gwynne added 2 commits August 16, 2022 22:49
…ields+Codable conformance with regards to empty containers: They must be explicitly preserved.
…ing, don't use a separate class for single value containers (should make encoding of complex contexts a little faster), simplify some names, remove unnecessary use of _openExistential() from the tests
@gwynne
Copy link
Member Author

gwynne commented Aug 17, 2022

That should do it 🤞

@gwynne gwynne requested review from 0xTim and tonyarnold August 17, 2022 04:19
Copy link
Member

@0xTim 0xTim left a comment

Choose a reason for hiding this comment

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

🎉 🙌

Copy link

@tonyarnold tonyarnold left a comment

Choose a reason for hiding this comment

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

This is working well with the latest changes - thanks, @gwynne! ❤️

@gwynne gwynne merged commit 04f262e into main Aug 17, 2022
@gwynne gwynne deleted the fix-leaf-encoding-and-errors branch August 17, 2022 06:32
@VaporBot
Copy link

These changes are now available in 4.2.1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working semver-patch Internal changes only
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants