Skip to content

[ES|QL] Precise validation and autocomplete for CASE#244280

Merged
bartoval merged 7 commits intoelastic:mainfrom
bartoval:show_function_signature_while_typing
Dec 9, 2025
Merged

[ES|QL] Precise validation and autocomplete for CASE#244280
bartoval merged 7 commits intoelastic:mainfrom
bartoval:show_function_signature_while_typing

Conversation

@bartoval
Copy link
Contributor

@bartoval bartoval commented Nov 26, 2025

Summary

#177118

This enhances the existing logic, which already handles operators, commas, and field filtering based on their position within the CASE function.

case.mp4
  • Added semantic validation to better assess the consistency and structure of the CASE command.
  • Added an “add value…” snippet to the suggestions for both even-numbered positions and potential default values (effectively for all positions starting from the second).
  • Strengthen the existing logic for handling fields, operators, and commas
@bartoval bartoval self-assigned this Nov 26, 2025
@bartoval bartoval requested a review from a team as a code owner November 26, 2025 07:08
@bartoval bartoval added backport:skip This PR does not require backporting Feature:ES|QL ES|QL related features in Kibana Team:ESQL ES|QL related features in Kibana t// v9.3.0 labels Nov 26, 2025
@elasticmachine
Copy link
Contributor

Pinging @elastic/kibana-esql (Team:ESQL)

type: 'any',
},
],
repeatingParams: [
Copy link
Contributor Author

Choose a reason for hiding this comment

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

this might be the thing that we don't like

Copy link
Contributor

Choose a reason for hiding this comment

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

I dont like it 😄 The signature is this

 signatures: [
    {
      params: [
        {
          name: 'condition',
          type: 'boolean',
        },
        {
          name: 'value',
          type: 'any',
        },
      ],
      minParams: 2,
      returnType: 'unknown',
    },
  ],

The repeating params seems as a repetition to me. Why don'y you just add a flag: signatureIsRepeating? (the name can change ofc)

About the trailingParam what does the any means here? Don't we want this to be a constant?

@bartoval bartoval changed the title precise validation and autocomplete for CASE Nov 26, 2025
@stratoula
Copy link
Contributor

I find the demonstration video confusing. What exactly are we suggesting here?

case(bytes < bytes, agent, agent)

This is a confusing suggestion. The signatures are:

  • condition
  • value

and this is repetitive

So in my head at least, when you have condition then you can suggest an expression but when is a value we should suggest a constant to help the users to fill it in correctly and so on.

@elastic-vault-github-plugin-prod elastic-vault-github-plugin-prod bot requested a review from a team as a code owner November 26, 2025 07:31
@bartoval
Copy link
Contributor Author

I find the demonstration video confusing. What exactly are we suggesting here?

case(bytes < bytes, agent, agent)

This is a confusing suggestion. The signatures are:

  • condition
  • value

and this is repetitive

So in my head at least, when you have condition then you can suggest an expression but when is a value we should suggest a constant to help the users to fill it in correctly and so on.

why constant? Types are boolean or any for odd positions and are any for others (including default)

@stratoula
Copy link
Contributor

stratoula commented Nov 26, 2025

The point is to help them create easily queries like:

| EVAL
      status =
        CASE(
          TO_INTEGER(response.keyword) >= 200 AND
            TO_INTEGER(response.keyword) < 400,
          "HTTP 2xx and 3xx",
          TO_INTEGER(response.keyword) >= 400 AND
            TO_INTEGER(response.keyword) < 500,
          "HTTP 4xx",
          "HTTP 5xx")

We can suggest everything else too but the point is to help them to easily write the most common cases which are usually things like the above.

The task needs investigation and brainstorming. So I am expecting to have some ideas in order to discuss and take a decision together. I dont know which is the correct solution, I said that yesterday too, I just know that the case suggestions are a bit confusing

@bartoval
Copy link
Contributor Author

The point is to help them create easily queries like:

| EVAL
      status =
        CASE(
          TO_INTEGER(response.keyword) >= 200 AND
            TO_INTEGER(response.keyword) < 400,
          "HTTP 2xx and 3xx",
          TO_INTEGER(response.keyword) >= 400 AND
            TO_INTEGER(response.keyword) < 500,
          "HTTP 4xx",
          "HTTP 5xx")

We can suggest everything else too but the point is to help them to easily write the most common cases which are usually things like the above.

The task needs investigation and brainstorming. So I am expecting to have some ideas in order to discuss and take a decision together. I dont know which is the correct solution, I said that yesterday too, I just know that the case suggestions are a bit confusing

ok, understood

@bartoval
Copy link
Contributor Author

bartoval commented Nov 27, 2025

The point is to help them create easily queries like:

| EVAL
      status =
        CASE(
          TO_INTEGER(response.keyword) >= 200 AND
            TO_INTEGER(response.keyword) < 400,
          "HTTP 2xx and 3xx",
          TO_INTEGER(response.keyword) >= 400 AND
            TO_INTEGER(response.keyword) < 500,
          "HTTP 4xx",
          "HTTP 5xx")

We can suggest everything else too but the point is to help them to easily write the most common cases which are usually things like the above.

The task needs investigation and brainstorming. So I am expecting to have some ideas in order to discuss and take a decision together. I dont know which is the correct solution, I said that yesterday too, I just know that the case suggestions are a bit confusing

@stratoula
I have this kind of idea, I don't know if I can do it, I haven't done any critical thinking about it, but I like it.

extend suggestions building a map based on the previous context that we can customize time by time with column -> array of values otherwise keep standard behaviour. Here some exapmple

export const FUNCTION_SUGGESTION_HINTS = {
  case: {
    // Position 0, 2, 4... (condition)
    0: {
      prioritizeFieldTypes: ['boolean'],
    },
    // Position 1, 3, 5... (value)
    1: {
      
      // Level 2: generic defaults
      defaultLiterals: {
        integer: ['0'],
        double: ['0.0'],
        boolean: ['true', 'false'],
        ip: ['"0.0.0.0"'],
        geo_point: ['TO_GEOPOINT("POINT (0,0)")']
        ...
      },
      
      // Level 3: domain-specific values (HIGHEST PRIORITY)
      domainValues: { // here a column name previosly present in the previous condition
        'agent': ['"Mozilla"', '"Chrome"', '"Safari"', '"Edge"', '"Firefox"'],
        'response': ['"200"', '"301"', '"400"', '"404"', '"500"'],
      },
    },
  },
};
Example 1: CASE(agent == "Mozilla", /
Field: agent (keyword)
Suggestions:
━━━━━━━━━━━━━━━━━━━━━━━
Domain values for "agent":        ← FIRST (Level 3)
  "Mozilla"
  "Chrome"
  "Safari"
  "Edge"
  "Firefox"

Default:                          ← SECOND (Level 2)
  .....
  
Keyword fields:                   ← THIRD (Level 1)
  agent
 ....the rest

Do you like the direction? too complicated? Is what you are thinking ? (obviously it's just a draft)

@bartoval bartoval marked this pull request as draft November 27, 2025 15:58
@stratoula
Copy link
Contributor

I will check it tmr morning Val and I will let you know!

@stratoula
Copy link
Contributor

I like the idea of having something like this prioritizeFieldTypes . The defaultLiterals I don't think we need this and the domainValues I don't understand it tbh. Is this hardcoded?

I want to show the pairs (condition, value):

1st arg ---> condition. Let' say that the user types languages <= 1.
2nd arg --> value (the first suggestion here could be a Add a value for the previous condition. The user selects it and this adds an example string or an empty string
3nd arg --> condition or <default_value> (If the number of arguments is odd, the last argument is the default value which is returned when no condition matches.). So here the user can continue other giving another pair condition value or give a default value. So we want to prioritize other boolean (expression) or a suggestion to add the default value (When no conditions met)

I want to investigate if the above is possible with a clean and easy way. If it is not possible let's close this issue. (After some consideration I don't think it is tbh)

@bartoval
Copy link
Contributor Author

bartoval commented Nov 28, 2025

I like the idea of having something like this prioritizeFieldTypes . The defaultLiterals I don't think we need this and the domainValues I don't understand it tbh. Is this hardcoded?

I want to show the pairs (condition, value):

1st arg ---> condition. Let' say that the user types languages <= 1. 2nd arg --> value (the first suggestion here could be a Add a value for the previous condition. The user selects it and this adds an example string or an empty string 3nd arg --> condition or <default_value> (If the number of arguments is odd, the last argument is the default value which is returned when no condition matches.). So here the user can continue other giving another pair condition value or give a default value. So we want to prioritize other boolean (expression) or a suggestion to add the default value (When no conditions met)

I want to investigate if the above is possible with a clean and easy way. If it is not possible let's close this issue. (After some consideration I don't think it is tbh)

2nd arg: (my focus now)
Yes the values in domainValues are hardcoded but configurable by us, using predictable suggestions (i was thinking about LIMIT that suggest 1,10,100). This is the same principle. where the values ​​are references. For example, client IP suggests 0.0.0.0, agent suggests Chrome, Mozilla...they are quite predictable. Something like:
1

3nd arg:
This is a little trickier, because you don't know what the user wants to do. They might want to add a default or create a continuation expression.

I already do mini-checks for this. The third value never displays the continuation comma, and you can only add valid operators or operators to create a Boolean expression. As soon as a Boolean expression is completed, the continuation comma is added to the suggestions. We already do this in main; here I added some validations for incompelte situations.

Why close it? We can keep it open over time without priority. I've never seen a good idea on the first or second try. First ideas are always bad, then maybe you connect the dots after 20 attempts. ..who know

@stratoula
Copy link
Contributor

Ok I like the first and third argument ideas ++ I dont like the 2nd argument though. No need to go crazy there I think. At least for case I think you just want the user to understand that this is the value applicable for the first solution. I dont thinkt the hardcoded values is the solution here tbh

@bartoval bartoval force-pushed the show_function_signature_while_typing branch 3 times, most recently from bfebe16 to cca12c3 Compare December 3, 2025 20:54
@bartoval bartoval force-pushed the show_function_signature_while_typing branch 7 times, most recently from 0a524ce to 1bccb7d Compare December 4, 2025 13:01
@bartoval bartoval force-pushed the show_function_signature_while_typing branch from 1bccb7d to 0c48605 Compare December 4, 2025 13:13
@bartoval bartoval marked this pull request as ready for review December 4, 2025 13:20
@bartoval
Copy link
Contributor Author

bartoval commented Dec 4, 2025

"I'll reopen it and update the description. Let’s see if I opened the fortune cookies.

Copy link
Contributor

@stratoula stratoula left a comment

Choose a reason for hiding this comment

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

Looks very nice! Some comments to make it even more easier


export const valuePlaceholderConstant: ISuggestionItem = withAutoSuggest({
label: i18n.translate('kbn-esql-ast.esql.autocomplete.valuePlaceholderLabel', {
defaultMessage: 'Add a value and let autocomplete "value"',
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
defaultMessage: 'Add a value and let autocomplete "value"',
defaultMessage: 'Insert value placeholder',
asSnippet: true,
kind: 'Constant',
detail: i18n.translate('kbn-esql-ast.esql.autocomplete.valuePlaceholderDetail', {
defaultMessage: 'Insert a value placeholder',
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
defaultMessage: 'Insert a value placeholder',
defaultMessage: 'Describe the CASE condition',
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we distinguish the default value from the value you use to describe the condition?

So here, have another completion item, Default value or Fallback Value

image
Copy link
Contributor Author

Choose a reason for hiding this comment

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

default
Copy link
Contributor

@stratoula stratoula left a comment

Choose a reason for hiding this comment

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

I really love it! Thanx Val, looks great

@elasticmachine
Copy link
Contributor

💚 Build Succeeded

Metrics [docs]

Public APIs missing comments

Total count of every public API that lacks a comment. Target amount is 0. Run node scripts/build_api_docs --plugin [yourplugin] --stats comments for more detailed information.

id before after diff
@kbn/esql-ast 627 630 +3

Page load bundle

Size of the bundles that are downloaded on every page load. Target size is below 100kb

id before after diff
kbnUiSharedDeps-srcJs 4.1MB 4.1MB +2.3KB
Unknown metric groups

API count

id before after diff
@kbn/esql-ast 819 822 +3

cc @bartoval

@bartoval bartoval merged commit 623f7a3 into elastic:main Dec 9, 2025
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport:skip This PR does not require backporting Feature:ES|QL ES|QL related features in Kibana release_note:enhancement Team:ESQL ES|QL related features in Kibana t// v9.3.0

4 participants