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

Enable configuration #121

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 52 additions & 6 deletions src/app/routes.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,39 @@
import os
import base64
import gzip

from configparser import MissingSectionHeaderError
from datetime import datetime
from flask import Blueprint, redirect, render_template, request, url_for
from sqlfluff.api import fix, lint

bp = Blueprint("routes", __name__)

config_directory = ".temp"
config_file_name = ".sqlfluff"

def sql_encode(data: str) -> str:

def parameter_encode(data: str) -> str:
"""Gzip and base-64 encode a string."""
return base64.urlsafe_b64encode(gzip.compress(data.encode())).decode()


def sql_decode(data: str) -> str:
def parameter_decode(data: str) -> str:
"""Gzip and base-64 decode a string."""
return gzip.decompress(base64.urlsafe_b64decode(data.encode())).decode()


def write_config_file(config: str) -> str:
file_name = f"{config_directory}/{config_file_name}-{datetime.now()}"
if not os.path.exists(config_directory):
os.mkdir(config_directory)

f = open(file_name, "w")
f.write(config)
f.close()
return file_name


@bp.route("/", methods=["GET", "POST"])
def home():
"""Render the main page."""
Expand All @@ -30,8 +47,14 @@ def home():
# long SQL string that breaks something in HTTP get.
sql = request.form["sql"]
dialect = request.form["dialect"]
sqlfluff_config = request.form["sqlfluff_config"]
return redirect(
url_for("routes.fluff_results", sql=sql_encode(sql), dialect=dialect)
url_for(
"routes.fluff_results",
sql=parameter_encode(sql),
dialect=dialect,
sqlfluff_config=parameter_encode(sqlfluff_config),
)
)


Expand All @@ -40,17 +63,40 @@ def fluff_results():
"""Serve the results page."""
# we get carriage returns from the form somehow. so split on them and join via
# regular newline. add a newline to avoid the annoying newline-at-end-of-file error.
sql = sql_decode(request.args["sql"]).strip()
sql = parameter_decode(request.args["sql"]).strip()
sql = "\n".join(sql.splitlines()) + "\n"

dialect = request.args["dialect"]
linted = lint(sql, dialect=dialect)
fixed_sql = fix(sql, dialect=dialect)

sqlfluff_config = (
"\n".join(
parameter_decode(request.args["sqlfluff_config"]).strip().splitlines()
)
+ "\n"
)

temp_config_file_path = write_config_file(sqlfluff_config)

try:
linted = lint(sql, dialect=dialect, config_path=temp_config_file_path)
fixed_sql = fix(sql, dialect=dialect, config_path=temp_config_file_path)
except MissingSectionHeaderError:
linted = [
{
"code": "config",
"description": "Failed to parse the config as it is missing a section header",
}
]
fixed_sql = ""

os.remove(temp_config_file_path)

return render_template(
"index.html",
results=True,
sql=sql,
dialect=dialect,
sqlfluff_config=sqlfluff_config,
lint_errors=linted,
fixed_sql=fixed_sql,
)
4 changes: 4 additions & 0 deletions src/app/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ <h2>Your Terrible SQL</h2>
</option>
{% endfor %}
</select>

<label for="sqlfluff_config">Config</label>
<textarea class="form-control text-monospace" name='sqlfluff_config' id="sqlfluff_config"
rows="8">{{sqlfluff_config}}</textarea>
</div>

<button type="submit" class="btn btn-primary mb-2 btn-block" id="submitButton">Help me.</button>
Expand Down
36 changes: 26 additions & 10 deletions test/test_app.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Tests for the application."""
import app
import pytest
from app.routes import sql_encode
from app.routes import parameter_encode
from bs4 import BeautifulSoup


Expand All @@ -27,7 +27,7 @@ def test_post_redirect(client):
"""Test the redirect works."""
rv = client.post(
"/",
data=dict(sql="1234", dialect="ansi"),
data=dict(sql="1234", dialect="ansi", sqlfluff_config="5678"),
follow_redirects=False,
headers={"Content-Type": "application/x-www-form-urlencoded"},
)
Expand All @@ -36,8 +36,12 @@ def test_post_redirect(client):

def test_results_no_errors(client):
"""Test that the results is good to go when there is no error."""
sql_encoded = sql_encode("select * from table")
rv = client.get("/fluffed", query_string=f"""dialect=ansi&sql={sql_encoded}""")
sql_encoded = parameter_encode("select * from table")
sqlfluff_config_encoded = parameter_encode("[sqlfluff]\n")
rv = client.get(
"/fluffed",
query_string=f"""dialect=ansi&sql={sql_encoded}&sqlfluff_config={sqlfluff_config_encoded}""",
)
html = rv.data.decode().lower()
assert "sqlfluff online" in html
assert "fixed sql" in html
Expand All @@ -46,8 +50,12 @@ def test_results_no_errors(client):

def test_results_some_errors(client):
"""Test that the results is good to go with one obvious error."""
sql_encoded = sql_encode("select * FROM table")
rv = client.get("/fluffed", query_string=f"""dialect=ansi&sql={sql_encoded}""")
sql_encoded = parameter_encode("select * FROM table")
sqlfluff_config_encoded = parameter_encode("[sqlfluff]\n")
rv = client.get(
"/fluffed",
query_string=f"""dialect=ansi&sql={sql_encoded}&sqlfluff_config={sqlfluff_config_encoded}""",
)
html = rv.data.decode().lower()
assert "sqlfluff online" in html
assert "fixed sql" in html
Expand All @@ -61,8 +69,12 @@ def test_carriage_return_sql(client):

If it doesn't work, we should have one extra fixed character per carriage return.
"""
sql_encoded = sql_encode("select col \r\n \r\n \r\n from xyz")
rv = client.get("/fluffed", query_string=f"""dialect=ansi&sql={sql_encoded}""")
sql_encoded = parameter_encode("select col \r\n \r\n \r\n from xyz")
sqlfluff_config_encoded = parameter_encode("[sqlfluff]\n")
rv = client.get(
"/fluffed",
query_string=f"""dialect=ansi&sql={sql_encoded}&sqlfluff_config={sqlfluff_config_encoded}""",
)

html = rv.data.decode().lower()
soup = BeautifulSoup(html, "html.parser")
Expand All @@ -79,8 +91,12 @@ def test_carriage_return_sql(client):

def test_newlines_in_error(client):
"""Test newlines in error messages get correctly displayed"""
sql_encoded = sql_encode("select 1 from t group by 1\n\nAAAAAA")
rv = client.get("/fluffed", query_string=f"""dialect=ansi&sql={sql_encoded}""")
sql_encoded = parameter_encode("select 1 from t group by 1\n\nAAAAAA")
sqlfluff_config_encoded = parameter_encode("[sqlfluff]\n")
rv = client.get(
"/fluffed",
query_string=f"""dialect=ansi&sql={sql_encoded}&sqlfluff_config={sqlfluff_config_encoded}""",
)

html = rv.data.decode().lower()
soup = BeautifulSoup(html, "html.parser")
Expand Down