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(hogvm): json parsing #22705

Merged
merged 5 commits into from
Jun 6, 2024
Merged

feat(hogvm): json parsing #22705

merged 5 commits into from
Jun 6, 2024

Conversation

mariusandra
Copy link
Collaborator

@mariusandra mariusandra commented Jun 5, 2024

Problem

Websites like JSON, so we should support it in Hog.

Changes

Adds two functions: jsonParse(string) and jsonStringify(any, indent=0) that do just that.

Naming things

I'm very open to good name suggestions. I took inspiration from JavaScript due to its familiarity. parse is a commonly used term, but stringify is JS-only. We're definitely not going for Python's json.💩s approach. toJSON and fromJSON are confusing because you never know what is from and what is to. I thought toString could also stand in for stringifyJSON, but while it would work with objects, you don't expect extra quotes wen you call it on toString('a normal string').

Here are what other languages do:

JavaScript

  • Convert to JSON: JSON.stringify(object)
  • Parse from JSON: JSON.parse(jsonString)

Python

  • Convert to JSON: json.dumps(object)
  • Parse from JSON: json.loads(jsonString)

Java

  • Convert to JSON: new Gson().toJson(object) (using Gson library)
  • Parse from JSON: new Gson().fromJson(jsonString, Class<T>) (using Gson library)

C#

  • Convert to JSON: JsonConvert.SerializeObject(object) (using Newtonsoft.Json)
  • Parse from JSON: JsonConvert.DeserializeObject<T>(jsonString) (using Newtonsoft.Json)

Ruby

  • Convert to JSON: object.to_json
  • Parse from JSON: JSON.parse(jsonString)

PHP

  • Convert to JSON: json_encode(object)
  • Parse from JSON: json_decode(jsonString, true)

Go

  • Convert to JSON: json.Marshal(object)
  • Parse from JSON: json.Unmarshal(jsonString, &object)

Swift

  • Convert to JSON: try JSONEncoder().encode(object)
  • Parse from JSON: try JSONDecoder().decode(Type.self, from: jsonString)

Kotlin

  • Convert to JSON: Gson().toJson(object) (using Gson library)
  • Parse from JSON: Gson().fromJson(jsonString, Type::class.java) (using Gson library)

Rust

  • Convert to JSON: serde_json::to_string(&object).unwrap()
  • Parse from JSON: serde_json::from_str(jsonString).unwrap()

so... dunno.

  • jsonParse(string) and jsonStringify(object, indent=0) <-- we have this now
  • parseJSON(string) and stringifyJSON(object, indent=0) <-- alternative, but writing capital JSON every time already became annoying, plus it's easier for muscle memory if the words are in the same order as javascript
  • toJson vs toJSON vs toJsonString vs toJSONString don't appeal to me.
  • Python's dumping and loading never made sense to me
  • We can also introduce namespaces like json::parse() or json.parse, but I'm not sure these add much at this point.

The meta problem here is that we'd like Hog functions to have as similar names to ClickHouse (& HogQL) functions as possible. CH doesn't have such JSON parsing functions, and we don't know if they'll ever add anything with these names. If they do, it'll be prototype.js all over again. It's probably fine though.

How did you test this code?

Added tests

Copy link
Contributor

github-actions bot commented Jun 5, 2024

Size Change: +198 B (+0.02%)

Total Size: 1.06 MB

ℹ️ View Unchanged
Filename Size Change
frontend/dist/toolbar.js 1.06 MB +198 B (+0.02%)

compressed-size-action

Copy link
Contributor

@benjackwhite benjackwhite left a comment

Choose a reason for hiding this comment

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

This PR description will be referenced in university lectures one day ;)

},
jsonStringify: (args) => {
// Recursively convert maps to objects
function convert(x: any): any {
Copy link
Contributor

Choose a reason for hiding this comment

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

Intrigued to know the perf of this. At some point we probably do want some sort of tests measuring that kind of thing

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This might have some performance drawbacks, and I hope we get everything else right and can look at benchmarking these things.

Some thoughts regarding performance for now:

  • We might rewrite everything in a compiled language anyway, so a boost here might be 🤷
  • new Map([[key1, value1], [key2, value2]]) and vice versa might be a lot faster?
  • Making our own JSONify function (a loop that concatenates strings) may be even faster?

We can also switch HogVM to use objects natively instead of maps. I went with objects initially, but swapped to maps because 1) simple add/remove operations are 10x faster on maps vs objects, 2) objects in JS only support string keys, maps support anything as keys... just like python's dicts. So moving from objects to maps internally made the entire thing faster and more compatible with the Python version. However yes, I didn't think of a potential performance drawback with json.stringify. Let's see how far we can get with this? 🤷

@mariusandra mariusandra enabled auto-merge (squash) June 6, 2024 09:01
@mariusandra mariusandra disabled auto-merge June 6, 2024 09:06
@mariusandra mariusandra merged commit e021cef into master Jun 6, 2024
77 of 78 checks passed
@mariusandra mariusandra deleted the hogvm-json-parsing branch June 6, 2024 09:06
thmsobrmlr pushed a commit that referenced this pull request Jun 6, 2024
@mariusandra mariusandra mentioned this pull request Jun 6, 2024
51 tasks
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