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(hogql): stringOr ^^ #25638

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open

feat(hogql): stringOr ^^ #25638

wants to merge 1 commit into from

Conversation

mariusandra
Copy link
Collaborator

@mariusandra mariusandra commented Oct 16, 2024

Problem

We want to easily get the first not empty string in Hog/QL:

In JavaScript:

const a = null
const b = ''
const c = 'banana'
const d = 'dingo'

console.log(a || b || c || d) // 'banana' -- this is what we want
console.log(a ?? b ?? c ?? d) // ''

In Hog:

let a := null
let b := ''
let c := 'banana'
let d := 'dingo'

print(a || b || c || d) // 'bananadingo' -- double pipe is string concatenation
print(a ?? b ?? c ?? d) // ''
print(a or b or c or d) // true

In HogQL

select null || '' || 'banana' || 'dingo' // 'bananadingo' -- double pipe is string concatenation
select null ?? '' ?? 'banana' ?? 'dingo' // ''
select null or '' or 'banana' or 'dingo' // errors
select coalesce(null, '', 'banana', 'dingo') // ''

The only real way to get banana is:

let a := null
let b := ''
let c := 'banana'
let d := 'dingo'

print(notEmpty(a) ? a : notEmpty(b) ? b : notEmpty(c) ? c : d) // 'banana'

... but we could do better.

Changes

Introducing stringOr(null, '', 'banana', 'dingo') and its shorthand ^^

image

Why ^^?

Looking at my keyboard, I found these underutilised symbols in our language: ! $ % ^ & _ ~. I excluded symbols that are common bitwise operators or used elsewhere in Hog, and added a bunch of doubles.

The question became: which of these is the most natural/obvious?

print(null ! '' ! 'banana' ! 'dingo')    // feels like "not"
print(null @ '' @ 'banana' @ 'dingo')    // banana at dingo? doesn't read right
print(null $ '' $ 'banana' $ 'dingo')    // somehow this makes me think of joining strings
print(null _ '' _ 'banana' _ 'dingo')    // this too
print(null !! '' !! 'banana' !! 'dingo') // this is "truthiness" in a lot of places
print(null $$ '' $$ 'banana' $$ 'dingo') // feels heavy, and also like concat
print(null %% '' %% 'banana' %% 'dingo') // feels like weird string formatting
print(null ^^ '' ^^ 'banana' ^^ 'dingo') // ^ is XOR, so it is a funky "or" and I can kind of feel it
print(null && '' && 'banana' && 'dingo') // we don't use it, but that's definitely not an "or"
print(null ~~ '' ~~ 'banana' ~~ 'dingo') // it looks like joining with a rope
print(null __ '' __ 'banana' __ 'dingo') // feels like joining/underscoring strings

... and that's how I settled on ^^

How did you test this code?

I didn't yet. This is a WIP in the spirit of "the fastest way to get the right answer is to post the wrong answer on the internet".

To test locally, run pip install ./hogql_parser. If you change the ^^ in HogQLLexer.g4 and want to play around, run pnpm run grammar:build followed by pip install ./hogql_parser.

Alternatives

We claim back ||, however it is a standard SQL concatenation operator. We have advertised it and people are using it in queries, so it'll be a hard fight.

@mariusandra mariusandra requested a review from a team October 16, 2024 19:48
@posthog-bot
Copy link
Contributor

It looks like the code of hogql-parser has changed since last push, but its version stayed the same at 1.0.45. 👀
Make sure to resolve this in hogql_parser/setup.py before merging!

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