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

Support format preserving SQL transformations #10

Merged
merged 1 commit into from
Feb 28, 2024

Conversation

crisptrutski
Copy link
Collaborator

This mechanism seems to have some legs, but could breakdown if we do structural transformations.

The implementation can definitely be optimized and very likely simplified as well.

/**
* Walk the given `expression`, invoking the callbacks for side effects as appropriate.
*/
public Expression walk(Expression expression) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We don't strictly need this overloading, as we will still have this expression in scope in our calling Clojure, but this allows us to hide the implementation detail that the AST is mutable - potentially future proofing against a functional implementation.

I also think it's nice to semantically differentiate the cases and avoid leaking the null sentinel value.

(defn walk-query
"Walk over the query's AST, using the callbacks for their side-effects, for example to mutate the AST itself."
[parsed-query callbacks]
(.walk (AstWalker. (update-vals callbacks preserve) ::ignored) parsed-query))
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Using this sentinel based on a recent reading of the "nil should be the absence of only a few values" tip from the Naming section of Elements of Clojure. Not sure if the advice really applies here. The value should never leak in any case, and we're unlikely to break that.

Comment on lines +44 to +49
"select *, boink
, yoink as oink
from /* /* lore */
core_user,
bore_user, /* more */ snore_user ;"
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It's not fun writing or reading these multi-line strings here, it could be nice to break this corpus out into text and/or EDN test resource files.

@@ -1,6 +1,6 @@
(ns macaw.core-test
(:require
[clojure.test :refer :all]
[clojure.test :refer [deftest testing is]]
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Leaking some Cursive linting

(defn replace-names
"Given a SQL query, apply the given table and column renames."
[sql renames]
(rewrite/replace-names sql (parsed-query sql) renames))
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I fumbled a bit with how to structure the namespaces, and this smells quite a bit. If we adopt a Potemkin style facade-only namespace that would solve the circular dependency we're using this proxy to solve. I was a bit loathe to just add the (controversial to some) dependency yet though.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Another alternative is to stick with a mono namespace for now.

Table)
(net.sf.jsqlparser.statement
Statement)))
(net.sf.jsqlparser.parser CCJSqlParserUtil)
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Whitespace wars, I find this a easier to scan personally unless the class list gets very long.

Copy link
Contributor

Choose a reason for hiding this comment

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

If it passes Kondo I don't care :)

(defn- update-query
"Emit a SQL string for an updated AST, preserving the comments and whitespace from the original SQL."
[updated-ast sql]
;; work around ast visitor processing (inexplicably and incorrectly) duplicating expressions visits
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Wanted to check if you know what's going on here before I file a bug. I hope it's not something grandfathered in through the TableNamesFinder.

@crisptrutski crisptrutski force-pushed the whitespace-preserving branch 2 times, most recently from 8e1194b to 8ed40e1 Compare February 28, 2024 10:15
@tsmacdonald tsmacdonald force-pushed the whitespace-preserving branch from 8ed40e1 to ad7f7d7 Compare February 28, 2024 17:03
@tsmacdonald tsmacdonald force-pushed the whitespace-preserving branch from ad7f7d7 to dc933b0 Compare February 28, 2024 19:20
Base automatically changed from enum-map to master February 28, 2024 19:22
Copy link
Contributor

@tsmacdonald tsmacdonald left a comment

Choose a reason for hiding this comment

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

Nice! 🔥 🔥 🔥

@tsmacdonald tsmacdonald merged commit 77f002e into master Feb 28, 2024
4 checks passed
@tsmacdonald tsmacdonald deleted the whitespace-preserving branch February 28, 2024 20:04
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