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

feat(evaluator): simplified synchronous evaluator #273

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

ricokahler
Copy link

@ricokahler ricokahler commented Feb 20, 2025

⚠️ This is a proposal! ⚠️

This is still a work in progress (and is fairly adventurous) but I wanted to share this direction for feedback before I continue down this path.

  • The async evaluator was complete gutted for a simplified synchronous evaluator. Switching to completely synchronous control flow allowed for a lot of simplification and enabled some usage of native JS functions via arrays and sets.
  • I noticed that the Value wrappers didn't seem to be necessary in this model so I tried removing it. It seems to be pretty doable but handling dates requires checking a string to see if it's a date first and that may be problematic. At the current state of this PR, the date handling is close but still wrong.
  • I brought in @portabletext/toolkit to get the portable text text value. I haven't checked if the output is the same but this approach is super appealing if there isn't a difference in output.
  • I tried simplifying Scope to an array of values which somewhat works but doesn't have a concept of root and dataset

How does this look so far? This PR isn't ready for an in-depth review but I'd love thoughts on this direction. It's a large change but the resulting code is greatly simplified. Is it worth it?

Let me know what you think. Is this a good candidate for a groq-js v2? Or should this be just tacked on to the existing code? Or do we want to support both async and sync evaluation with an approach similar to #272 ?

Copy link

socket-security bot commented Feb 20, 2025

New dependencies detected. Learn more about Socket for GitHub ↗︎

Package New capabilities Transitives Size Publisher
npm/@portabletext/[email protected] None +1 170 kB sanity-io

View full report↗︎

}
Object.defineProperty(acc, attribute.name, {
enumerable: true,
get: () => evaluate({...context, node: attribute.value}),
Copy link
Author

Choose a reason for hiding this comment

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

lazy evaluation based on property access. what a great idea @judofyr

Copy link
Collaborator

Choose a reason for hiding this comment

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

Nice! I like this!

Comment on lines +11 to +13
interface EvaluateOpCallOptions extends Context {
node: OpCallNode
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't quite see the need for this. Why not use multiple parameters? Isn't the current restructuring just adding lots of unnecessary allocations anyway?

@judofyr
Copy link
Collaborator

judofyr commented Feb 21, 2025

I tried simplifying Scope to an array of values which somewhat works but doesn't have a concept of root and dataset

The main reason here was to be as close to the spec as possible (e.g. https://spec.groq.dev/draft/#sec-Scope) which has some educational value, but it's not a very big deal.

@judofyr
Copy link
Collaborator

judofyr commented Feb 21, 2025

I think this makes a lot of sense for a groq-js v2. We can still in a minor release introduce an evaluateAsync later on.

It seems to be pretty doable but handling dates requires checking a string to see if it's a date first and that may be problematic. At the current state of this PR, the date handling is close but still wrong.

I think we might need to keep our own Date wrapper, but there's a few things we can do:

  1. We can introduce an evaluation option called normalize (which defaults to true) which at the end traverses the object deeply and gets of rid any GROQ-specific types.
  2. We can implement toJSON() on our Date wrapper so that it's possible to run JSON.stringify(…) on it directly.

Let's also be way more precise (both in the API and preferably in the types) around what types we actually handle in the evaluator. We shouldn't need to use any / unknown anywhere.

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