sql-formatter icon indicating copy to clipboard operation
sql-formatter copied to clipboard

Feature Request: Format "ON" to separate line

Open rigogsilva opened this issue 2 years ago • 13 comments

Describe the Feature Is there a region so not add OR to the logicalOperatorNewline? Or maybe is there a different way to control that?

Why do you want this feature? Normally in sql the ON is not on the same line as the join itself. For example:

SELECT
  *
FROM
  foo
  JOIN foo 
    ON foo.account_id = bar.account_id
    AND foo.something = bar.something
  AND a = b

This looks a bit weird:

SELECT
  *
FROM
  foo
  JOIN foo ON foo.account_id = bar.account_id
    AND foo.something = bar.something
  AND a = b

And it is nice to look at the ON and AND clause without having to move your eye to the right. Helps readability.

rigogsilva avatar Jun 23 '22 20:06 rigogsilva

With the latest version (7.0.2) I actually get this result:

SELECT
  *
FROM
  foo
  JOIN foo ON foo.account_id = bar.account_id
  AND foo.something = bar.something
  AND a = b

But I agree that the current formatting of ON expression leaves it looking quite confusing. Ideally both of these AND-operator lines should be indented. I would consider both of these to be acceptable:

FROM
  foo
  JOIN foo ON foo.account_id = bar.account_id
    AND foo.something = bar.something
    AND a = b
-- or
FROM
  foo
  JOIN foo ON
    foo.account_id = bar.account_id
    AND foo.something = bar.something
    AND a = b

Though in my experience joining over multiple fields is not something you do often. You can get a much better result from the formatter if you use parenthesis:

SELECT
  *
FROM
  foo
  JOIN foo ON (
    foo.account_id = bar.account_id
    AND foo.something = bar.something
    AND a = b
  )

With the current architecture this is pretty difficult to fix. More likely after a larger rewrite of the parser that's currently in progress.

nene avatar Jun 24 '22 12:06 nene

Yeah I was thinking something like this also:

FROM
  foo
  JOIN foo 
    ON foo.account_id = bar.account_id
    AND foo.something = bar.something
    AND a = b

Which is closer to what I have seen in sql formatting.

Not a problem. Thanks for considering. I was able to handle it with post processing witch is not ideal but works:

  const onFormattedQuery = (
    sqlFormatterQuery.toString().split("\n")
    .map((line: string) => {
      if (line.includes(" ON ")) {
        const beginSpacesCount = line.search(/\S/);
        const newOnLone = `\n${"".padStart(2 + beginSpacesCount, " ")}ON `;
        return line.replace(" ON ", newOnLone);
      } else {
        return line;
      }
    })
)

rigogsilva avatar Jun 24 '22 15:06 rigogsilva

Glad you found a solution :)

nene avatar Jun 24 '22 17:06 nene

Relates to #267

nene avatar Jul 01 '22 07:07 nene

I was able to handle it with post processing witch is not ideal but works

@rigogsilva, would you be able to explain how you did the post processing you mentioned here? The onFormattedQuery snippet you posted makes sense, but then I'm not sure exactly where this should go and how to call it in accordance with sql-formatter. Any input you could provide would also be much appreciated, @nene 😊

andrewtavis avatar Sep 30 '22 10:09 andrewtavis

That snippet is supposed to simply be applied to sql-formatter output, like so:

import {format} from "sql-formatter";

const result = postProcessOnKeywords(format("SELECT *"));

function postProcessOnKeywords(sql) {
  return (
    sql.toString().split("\n")
    .map((line: string) => {
      if (line.includes(" ON ")) {
        const beginSpacesCount = line.search(/\S/);
        const newOnLone = `\n${"".padStart(2 + beginSpacesCount, " ")}ON `;
        return line.replace(" ON ", newOnLone);
      } else {
        return line;
      }
    })
  );
}

nene avatar Sep 30 '22 15:09 nene

Thanks for your reply, @nene!

And is there a way to then get this into a VS Code task or something that could be triggered automatically on save via scripts/settings? Asking as sql-formatter is very close to what my team and I need, but getting ON on the next line and adding some spacing that we can write our own scripts for would be needed for a rollout. Just have never written something that would automate some code changes, so am a bit a loss :)

andrewtavis avatar Sep 30 '22 16:09 andrewtavis

I guess the simplest way to integrate it into VSCode is to fork the VSCode extension and add this code.

Though, given the repeated interest here, I might also finally implement an option for this formatting style in sql-formatter.

nene avatar Oct 01 '22 07:10 nene

Thanks for a further reply! It'd be great if this were an option in here. As stated, the big thing on my end for potentially adopting sql-formatter team wide is ON on the next line and a line space before statements.

My TypeScript is a bit novice, but I'd be happy to give this a shot if you'd be willing to provide some directions on this 😊

andrewtavis avatar Oct 03 '22 13:10 andrewtavis

Thanks for interest in helping. Though there might be some quick'n'dirty fixes (like the one above) to patch this up, I want to do this properly, which means properly parsing a FROM-clause with all the joins. This is to ensure we only format the ON keyword inside join syntax and nowhere else (like in ON DELETE CASCADE, which will trip up the above hack).

However, I'm not yet fully sure how I would go about implementing it, so I can't really provide any real guidance.

I am actively considering it though. So hopefully it'll happen rather sooner than later.

nene avatar Oct 05 '22 16:10 nene

Thanks for your interest in implementing! I'll go ahead and read up a bit on the project further and we can discuss/ideate this going forward :) At the very least I can be here to cheer you on when the work begins 😅😊

andrewtavis avatar Oct 05 '22 17:10 andrewtavis

Look forward to hearing if this feature will be added - it's the only thing holding our team back from using the vscode extension which otherwise is great - much faster and easier to integrate that the alternative we are considering (sqlfluff) despite that library being more configurable 👍

StephenDriffill avatar Oct 31 '22 11:10 StephenDriffill

This feature will likely never be implemented in SQL Formatter because there are fundamental problems with the architecture of this library.

I can instead suggest using prettier-plugin-sql-cst which already does format the code in the style you're suggesting.

nene avatar Jan 22 '24 12:01 nene