def test_build_sql_single_insert_w_brackets(tmp_path: pytest.fixture):
    """
    Assert build_sql constructs file given template file referencing a single
    insert, inside brackets.
    """
    inserted_sql_strs = ["SELECT", "  x AS i", "  y AS j", "FROM some_table"]
    inserted_sql_filename = "inserted_sql.sql"
    inserted_sql_filepath = f"{tmp_path}/{inserted_sql_filename}"

    template_sql_strs = [
        f"WITH X AS (@{inserted_sql_filename}@),",
        "SELECT some_stuff FROM somewhere;"
    ]
    template_sql_filename = "template_sql.sql"
    template_sql_filepath = f"{tmp_path}/{template_sql_filename}"

    expected_sql_strs = [
        "WITH X AS (", "  SELECT", "    x AS i", "    y AS j",
        "  FROM some_table", "),", "SELECT some_stuff FROM somewhere;"
    ]

    string_sequence_to_file(inserted_sql_strs, inserted_sql_filepath)
    string_sequence_to_file(template_sql_strs, template_sql_filepath)

    returned_sql_filename = "returned_sql.sql"
    returned_sql_filepath = f"{tmp_path}/{returned_sql_filename}"

    module_under_test.build_sql(template_file=template_sql_filepath,
                                output_file=returned_sql_filepath)

    returned_sql_strs = file_to_string_sequence(returned_sql_filepath)

    assert returned_sql_strs == expected_sql_strs
def test_build_sql_multiple_inserts_cascading(tmp_path: pytest.fixture):
    """
    Assert cascading statements do not break dependencies while inserting minimal code.
    """

    testable_sql_1 = ["SELECT", "  value", "FROM table_1"]
    section_1_filename = "section_1.sql"
    section_1_filepath = f"{tmp_path}/{section_1_filename}"

    # SECTION 2 may depend on section 1
    testable_sql_2 = [
        "WITH section_1 AS @{section_1_filename}@",
        module_under_test.SNIPPET_LINE, "SELECT", "  values", "FROM table_2 ",
        "JOIN section_1 ON some_join"
    ]
    section_2_filename = "section_2.sql"
    section_2_filepath = f"{tmp_path}/{section_2_filename}"

    testable_sql_3 = [
        "WITH section_1 AS @{section_1_filename}@",
        module_under_test.SNIPPET_LINE, "SELECT", "  values", "FROM table_3 ",
        "JOIN section_1 ON some_join"
    ]
    section_3_filename = "section_3.sql"
    section_3_filepath = f"{tmp_path}/{section_3_filename}"

    template_sql_strs = [
        f"WITH section_1 AS (@{section_1_filename}@),",
        f"section_2 AS (@{section_2_filename}@),",
        f"section_3 AS (@{section_3_filename}@),",
        module_under_test.SNIPPET_LINE, "SELECT some_stuff FROM somewhere;"
    ]
    template_sql_filename = "template_sql.sql"
    template_sql_filepath = f"{tmp_path}/{template_sql_filename}"

    expected_sql_strs = [
        "WITH section_1 AS (", "  SELECT", "    value", "  FROM table_1", "),",
        "section_2 AS (", "  SELECT", "    values", "  FROM table_2 ",
        "  JOIN section_1 ON some_join", "),", "section_3 AS (", "  SELECT",
        "    values", "  FROM table_3 ", "  JOIN section_1 ON some_join", "),",
        "SELECT some_stuff FROM somewhere;"
    ]

    string_sequence_to_file(testable_sql_1, section_1_filepath)
    string_sequence_to_file(testable_sql_2, section_2_filepath)
    string_sequence_to_file(testable_sql_3, section_3_filepath)
    string_sequence_to_file(template_sql_strs, template_sql_filepath)

    returned_sql_filename = "returned_sql.sql"
    returned_sql_filepath = f"{tmp_path}/{returned_sql_filename}"

    module_under_test.build_sql(template_file=template_sql_filepath,
                                output_file=returned_sql_filepath)

    returned_sql_strs = file_to_string_sequence(returned_sql_filepath)

    assert returned_sql_strs == expected_sql_strs
def test_build_sql_multiple_inserts(tmp_path: pytest.fixture):
    """
    Assert build_sql constructs file given template file referencing multiple
    inserts.
    """
    inserted_sql_strs_0 = ["SELECT", "  x AS i", "  y AS j", "FROM some_table"]
    inserted_sql_0_filename = "inserted_sql_0.sql"
    inserted_sql_0_filepath = f"{tmp_path}/{inserted_sql_0_filename}"

    inserted_sql_strs_1 = [
        "SELECT", "  this AS that", "  the_other AS the_cats_mother",
        "FROM some_other_table"
    ]
    inserted_sql_1_filename = "inserted_sql_1.sql"
    inserted_sql_1_filepath = f"{tmp_path}/{inserted_sql_1_filename}"

    inserted_sql_strs_2 = [
        "SELECT", "  bill AS ben", "  dick AS harry", "FROM yet_another_table"
    ]
    inserted_sql_2_filename = "inserted_sql_2.sql"
    inserted_sql_2_filepath = f"{tmp_path}/{inserted_sql_2_filename}"

    template_sql_strs = [
        f"WITH X AS @{inserted_sql_0_filename}@,",
        f"WITH Y AS @{inserted_sql_1_filename}@,",
        f"WITH Z AS @{inserted_sql_2_filename}@,",
        "SELECT some_stuff FROM somewhere;"
    ]
    template_sql_filename = "template_sql.sql"
    template_sql_filepath = f"{tmp_path}/{template_sql_filename}"

    expected_sql_strs = [
        "WITH X AS ", "  SELECT", "    x AS i", "    y AS j",
        "  FROM some_table,", "WITH Y AS ", "  SELECT", "    this AS that",
        "    the_other AS the_cats_mother", "  FROM some_other_table,",
        "WITH Z AS ", "  SELECT", "    bill AS ben", "    dick AS harry",
        "  FROM yet_another_table,", "SELECT some_stuff FROM somewhere;"
    ]

    string_sequence_to_file(inserted_sql_strs_0, inserted_sql_0_filepath)
    string_sequence_to_file(inserted_sql_strs_1, inserted_sql_1_filepath)
    string_sequence_to_file(inserted_sql_strs_2, inserted_sql_2_filepath)
    string_sequence_to_file(template_sql_strs, template_sql_filepath)

    returned_sql_filename = "returned_sql.sql"
    returned_sql_filepath = f"{tmp_path}/{returned_sql_filename}"

    module_under_test.build_sql(template_file=template_sql_filepath,
                                output_file=returned_sql_filepath)

    returned_sql_strs = file_to_string_sequence(returned_sql_filepath)

    assert returned_sql_strs == expected_sql_strs
def test_build_sql_relative_path():
    """
    Assert build_sql constructs file given template file with a path relative
    to the project root
    """
    cwd = "test"

    inserted_sql_strs = ["SELECT", "  x AS i", "  y AS j", "FROM some_table"]
    inserted_sql_filename = "inserted_sql.sql"
    inserted_sql_filepath = f"{cwd}/{inserted_sql_filename}"

    template_sql_strs = [
        f"WITH X AS @{inserted_sql_filename}@,",
        "SELECT some_stuff FROM somewhere;"
    ]
    template_sql_filename = "template_sql.sql"
    template_sql_filepath = f"{cwd}/{template_sql_filename}"

    expected_sql_strs = [
        "WITH X AS ", "  SELECT", "    x AS i", "    y AS j",
        "  FROM some_table,", "SELECT some_stuff FROM somewhere;"
    ]

    string_sequence_to_file(inserted_sql_strs, inserted_sql_filepath)
    string_sequence_to_file(template_sql_strs, template_sql_filepath)

    returned_sql_filename = "returned_sql.sql"
    returned_sql_filepath = f"{cwd}/{returned_sql_filename}"

    module_under_test.build_sql(template_file=template_sql_filepath,
                                output_file=returned_sql_filepath)

    returned_sql_strs = file_to_string_sequence(returned_sql_filepath)

    # make sure those files are removed even if the test fails!
    try:

        assert returned_sql_strs == expected_sql_strs

    except AssertionError as e:

        raise e

    finally:

        os.remove(inserted_sql_filepath)
        os.remove(template_sql_filepath)
        os.remove(returned_sql_filepath)
def test_build_sql_raises_when_inserts_not_bookended(tmp_path: pytest.fixture):
    """
    Assert build_sql raises a value error when an insert statment is not
    bookended by insert delimiters, i.e. @this not @this@.
    """

    template_sql_strs = ["WITH X AS @doesnt_matter_what_is_here,"]
    template_sql_filename = "template_sql.sql"
    template_sql_filepath = f"{tmp_path}/{template_sql_filename}"

    string_sequence_to_file(template_sql_strs, template_sql_filepath)

    with pytest.raises(ValueError):

        module_under_test.build_sql(template_file=template_sql_filepath,
                                    output_file="doesnt_matter_what_is_here")
def build_query(tmp_path, template):
    query_file = f"{tmp_path}/built.sql"
    build_sql(template_file=template, output_file=query_file)
    with open(query_file, 'r') as f:
        query = f.read()
    return query