| """Π’Π΅ΡΡΡ Π½Π° ΠΏΠΎΡΡΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΡ SQL ΠΈ ΡΠ²ΡΠ·Π°Π½Π½ΡΠ΅ ΡΡΠ½ΠΊΡΠΈΠΈ. |
| |
| ΠΠΎΠΊΡΡΠ²Π°Π΅Ρ ΡΠ°Π·Π΄Π΅Π» 2.5 ΠΏΠΎΡΡΠ½ΠΈΡΠ΅Π»ΡΠ½ΠΎΠΉ Π·Π°ΠΏΠΈΡΠΊΠΈ: ΡΠΈΡΡΠΊΡ Π°ΡΡΠ΅ΡΠ°ΠΊΡΠΎΠ², |
| Π²Π°Π»ΠΈΠ΄Π°ΡΠΈΡ ΡΠ΅ΡΠ΅Π· sqlglot, Π½ΠΎΡΠΌΠ°Π»ΠΈΠ·Π°ΡΠΈΡ Π΄Π»Ρ Exact Match ΠΈ AST-ΡΡΠΎΠ²Π½Π΅Π²ΡΠΉ |
| Π³Π²Π°ΡΠ΄Π΅ΠΉΠ» is_select_only. |
| """ |
|
|
| from src.models.postprocess import ( |
| is_select_only, |
| is_valid_sql, |
| normalize_sql, |
| postprocess, |
| strip_model_artifacts, |
| ) |
|
|
|
|
| |
| |
| |
|
|
| def test_strip_markdown_block_with_lang(): |
| raw = "```sql\nSELECT * FROM users;\n```" |
| assert strip_model_artifacts(raw).upper().startswith("SELECT") |
|
|
|
|
| def test_strip_markdown_block_without_lang(): |
| raw = "```\nSELECT id FROM t;\n```" |
| assert strip_model_artifacts(raw).upper().startswith("SELECT") |
|
|
|
|
| def test_strip_sql_prefix(): |
| raw = "SQL: SELECT 1;" |
| assert strip_model_artifacts(raw).upper().startswith("SELECT") |
|
|
|
|
| def test_strip_russian_prefix(): |
| raw = "ΠΡΠ²Π΅Ρ: SELECT name FROM students;" |
| assert strip_model_artifacts(raw).upper().startswith("SELECT") |
|
|
|
|
| def test_strip_natural_language_before_select(): |
| raw = "ΠΠΎΡ SQL, ΠΊΠΎΡΠΎΡΡΠΉ ΠΎΡΠ²Π΅ΡΠ°Π΅Ρ Π½Π° Π²ΠΎΠΏΡΠΎΡ: SELECT * FROM t WHERE id = 1;" |
| out = strip_model_artifacts(raw) |
| assert out.upper().startswith("SELECT") |
| assert "ΠΠΎΡ" not in out |
|
|
|
|
| def test_keeps_first_statement_of_two(): |
| raw = "SELECT 1; SELECT 2;" |
| out = strip_model_artifacts(raw) |
| assert "SELECT 1" in out |
| assert "SELECT 2" not in out |
|
|
|
|
| def test_with_cte_is_preserved(): |
| raw = "WITH agg AS (SELECT id FROM t) SELECT * FROM agg" |
| out = strip_model_artifacts(raw) |
| assert out.upper().startswith("WITH") |
|
|
|
|
| def test_strip_returns_empty_on_garbage(): |
| |
| |
| |
| raw = "ΠΏΡΠΎΡΡΠΎ ΡΠ΅ΠΊΡΡ Π±Π΅Π· Π·Π°ΠΏΡΠΎΡΠ°" |
| assert strip_model_artifacts(raw) == "ΠΏΡΠΎΡΡΠΎ ΡΠ΅ΠΊΡΡ Π±Π΅Π· Π·Π°ΠΏΡΠΎΡΠ°" |
|
|
|
|
| |
| |
| |
|
|
| def test_valid_select(): |
| assert is_valid_sql("SELECT * FROM students WHERE id = 1") |
|
|
|
|
| def test_valid_with_cte(): |
| assert is_valid_sql("WITH x AS (SELECT id FROM t) SELECT * FROM x") |
|
|
|
|
| def test_invalid_garbage(): |
| assert not is_valid_sql("SELEC * FRM where") |
|
|
|
|
| def test_invalid_empty(): |
| assert not is_valid_sql("") |
| assert not is_valid_sql(" ") |
|
|
|
|
| |
| |
| |
|
|
| def test_select_passes_guardrail(): |
| assert is_select_only("SELECT id FROM t") |
|
|
|
|
| def test_with_cte_passes_guardrail(): |
| assert is_select_only("WITH x AS (SELECT id FROM t) SELECT * FROM x") |
|
|
|
|
| def test_drop_table_blocked(): |
| assert not is_select_only("DROP TABLE users") |
|
|
|
|
| def test_delete_blocked(): |
| assert not is_select_only("DELETE FROM users WHERE id = 1") |
|
|
|
|
| def test_update_blocked(): |
| assert not is_select_only("UPDATE users SET name = 'a' WHERE id = 1") |
|
|
|
|
| def test_insert_blocked(): |
| assert not is_select_only("INSERT INTO users (id, name) VALUES (1, 'a')") |
|
|
|
|
| def test_empty_blocked(): |
| assert not is_select_only("") |
| assert not is_select_only(" ") |
|
|
|
|
| def test_invalid_sql_blocked_by_guardrail(): |
| |
| |
| assert not is_select_only("not a sql at all") |
|
|
|
|
| |
| |
| |
|
|
| def test_normalize_collapses_whitespace(): |
| a = "SELECT * FROM Users" |
| b = "select * from users" |
| assert normalize_sql(a) == normalize_sql(b) |
|
|
|
|
| def test_normalize_idempotent(): |
| sql = "SELECT id FROM t WHERE x = 1" |
| assert normalize_sql(normalize_sql(sql)) == normalize_sql(sql) |
|
|
|
|
| def test_normalize_fallback_on_invalid(): |
| |
| out = normalize_sql("not really sql") |
| assert isinstance(out, str) |
| assert out.upper() == out |
|
|
|
|
| |
| |
| |
|
|
| def test_postprocess_extracts_from_markdown(): |
| raw = "```sql\nSELECT name FROM students WHERE group_id = 1;\nSELECT 2;\n```" |
| out = postprocess(raw) |
| assert out.upper().startswith("SELECT NAME") or out.startswith("SELECT name") |
| assert "SELECT 2" not in out |
|
|
|
|
| def test_postprocess_returns_empty_on_invalid(): |
| |
| |
| raw = "Π― Π½Π΅ ΠΌΠΎΠ³Ρ ΡΠ³Π΅Π½Π΅ΡΠΈΡΠΎΠ²Π°ΡΡ SQL Π΄Π»Ρ ΡΡΠΎΠ³ΠΎ Π²ΠΎΠΏΡΠΎΡΠ°." |
| assert postprocess(raw) == "" |
|
|
|
|
| def test_postprocess_returns_empty_on_truncated(): |
| |
| raw = "SELECT * FROM users WHERE" |
| assert postprocess(raw) == "" |
|
|
|
|
| def test_postprocess_keeps_valid_with_cte(): |
| raw = "WITH agg AS (SELECT id FROM t) SELECT * FROM agg" |
| out = postprocess(raw) |
| assert out.upper().startswith("WITH") |
|
|