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

Draft: Make Context a user-implementable Trait #829

Open
wants to merge 9 commits into
base: master
Choose a base branch
from

Conversation

fabianfreyer
Copy link

@fabianfreyer fabianfreyer commented May 12, 2023

This adds a ContextProvider Trait that replaces the UserContext and implements all methods that Tera uses to interface with the Context. A straightforward pass-through implementation for Context is also provided.

Technically, this is a breaking change, since function signatures change, but existing code should work as-is and be specialized down to the same implementation.

@Keats
Copy link
Owner

Keats commented May 13, 2023

I'm not going to make a big change to v1 like that. What's the usecase?

@fabianfreyer
Copy link
Author

fabianfreyer commented May 13, 2023

That's fair, it's a pretty big user-facing change. Could this make it into v2? I'd be happy to maintain this patchset on top of v1 in a fork for my specific usecase, until v2 comes out, but it seems like something that could be useful for others too, and having it upstreamed at some point would be very helpful.

My use case is I want to proxy the variable lookups to something like config-rs or figment, which provide layered lookups. In my specific usage scenario, I need to e.g. have a JSON/TOML/etc. file that provides user context for a template, but can have environment variables that either supplement additional variables or override values, while dynamically resolving paths; e.g.:

{
   "foo": {
       "bar": "baz"
   }
}

In this case, a template of {{ foo.bar }} would render qux if there is a FOO_BAR=qux environment variable set, but also be able to e.g. access {{ FOO_BAR }}. That would require some form of dynamic lookups to determine which "layer" matches a key, and pretty much precludes pre-filling a context with all possible variations.

This allows implementors to return owned values.
@fabianfreyer
Copy link
Author

@Keats I've added an example to showcase how this might be helpful. I'm a bit unsure what the into_json is really used for, and whether that would need to be a part of the context.

@Keats
Copy link
Owner

Keats commented May 23, 2023

Thanks for the example. I'm not entirely sure whether this is worth adding though, you could just feed the whole env/whatever source you're getting it from to the context before rendering the template and you would have something that works just as well and that is probably faster.

@fabianfreyer
Copy link
Author

Not entirely; this would require being able to iterate over / know in advance the keys. Layered configuration crates like Figment or Config-rs don't usually give you that API, they only provide a "get" method, and for good measure. If you look at my use case above, overriding configuration with environment variables, one would have to determine all possible override variations a priori and fill them into a Context, which is difficult, kills performance, and uses a ton of resources (e.g. finding all possible upper/lowercase combinations, replacing each _ with a . or creating a sub-object for it, etc...). The context would probably need to look like the following to get the same functionality, and this would explode very quickly for larger contexts:

{
   "foo": { "bar": "qux" },
   "foo_bar": "qux",
   "FOO_BAR": "qux",
   "FOO": {"BAR": "qux"},
   "FOO": {"bar": "qux"},
   "foo": {"BAR": "qux"},
   // all the other possible combinations
}

OTOH, being able to check whether there's a matching combination when Tera encounters a variable is trivial.

FWIW, liquid does have a trait for this, but it requires iterating over keys as well.

@Keats
Copy link
Owner

Keats commented May 24, 2023

OTOH, being able to check whether there's a matching combination when Tera encounters a variable is trivial.

In practice though in Tera v2, you're not going to get the json dot anymore you're going to get a bunch of ident split (eg instead of getting foo.bar, you're going to get foo and then bar) so it's not going to be trivial. Especially since the Context won't have access to the stack of the VM and will be used only as the input data - it could just be a Value.

It seems easier to have a template function to grab from Figment/config-rs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants