11import re
2+ from unittest .mock import patch
23
34import pytest
45
89class TestViewsSqlglot :
910 def test_mysql_viewdef_to_sqlite_strips_schema_and_transpiles (self ) -> None :
1011 mysql_select = "SELECT `u`.`id`, `u`.`name` FROM `db`.`users` AS `u` WHERE `u`.`id` > 1"
11- sql = MySQLtoSQLite ._mysql_viewdef_to_sqlite (
12+ # Use an instance to ensure access to _mysql_database for stripping
13+ with patch .object (MySQLtoSQLite , "__init__" , return_value = None ):
14+ inst = MySQLtoSQLite () # type: ignore[call-arg]
15+ inst ._mysql_database = "db" # type: ignore[attr-defined]
16+ sql = inst ._mysql_viewdef_to_sqlite (
1217 view_select_sql = mysql_select ,
1318 view_name = "v_users" ,
14- schema_name = "db" ,
1519 )
1620 assert sql .startswith ('CREATE VIEW IF NOT EXISTS "v_users" AS' )
1721 # Ensure schema qualifier was removed
@@ -26,29 +30,75 @@ def test_mysql_viewdef_to_sqlite_parse_fallback(self, monkeypatch: pytest.Monkey
2630 # Force parse_one to raise so we hit the fallback path
2731 from sqlglot .errors import ParseError
2832
29- def boom (* args , ** kwargs ):
33+ def boom (* _ , ** __ ):
3034 raise ParseError ("boom" )
3135
3236 monkeypatch .setattr ("mysql_to_sqlite3.transporter.parse_one" , boom )
3337
3438 sql_in = "SELECT 1"
35- out = MySQLtoSQLite ._mysql_viewdef_to_sqlite (
39+ with patch .object (MySQLtoSQLite , "__init__" , return_value = None ):
40+ inst = MySQLtoSQLite () # type: ignore[call-arg]
41+ inst ._mysql_database = "db" # type: ignore[attr-defined]
42+ out = inst ._mysql_viewdef_to_sqlite (
3643 view_select_sql = sql_in ,
3744 view_name = "v1" ,
38- schema_name = "db" ,
3945 )
4046 assert out .startswith ('CREATE VIEW IF NOT EXISTS "v1" AS' )
4147 assert "SELECT 1" in out
4248 assert out .strip ().endswith (";" )
4349
44- def test_mysql_viewdef_to_sqlite_keep_schema_true_preserves_qualifiers (self ) -> None :
50+ def test_mysql_viewdef_to_sqlite_parse_fallback_strips_schema (self , monkeypatch : pytest .MonkeyPatch ) -> None :
51+ # Force parse_one to raise so we exercise the fallback path with schema qualifiers
52+ from sqlglot .errors import ParseError
53+
54+ def boom (* _ , ** __ ):
55+ raise ParseError ("boom" )
56+
57+ monkeypatch .setattr ("mysql_to_sqlite3.transporter.parse_one" , boom )
58+
59+ mysql_select = "SELECT `u`.`id` FROM `db`.`users` AS `u` WHERE `u`.`id` > 1"
60+ with patch .object (MySQLtoSQLite , "__init__" , return_value = None ):
61+ inst = MySQLtoSQLite () # type: ignore[call-arg]
62+ inst ._mysql_database = "db" # type: ignore[attr-defined]
63+ out = inst ._mysql_viewdef_to_sqlite (
64+ view_select_sql = mysql_select ,
65+ view_name = "v_users" ,
66+ )
67+ # Should not contain schema qualifier anymore
68+ assert "`db`." not in out and '"db".' not in out and " db." not in out
69+ # Should still reference the table name
70+ assert "FROM `users`" in out or 'FROM "users"' in out or "FROM users" in out
71+ assert out .strip ().endswith (";" )
72+
73+ def test_mysql_viewdef_to_sqlite_strips_schema_from_qualified_columns_nested (self ) -> None :
74+ # Based on the user-reported example with nested subquery and fully-qualified columns
75+ mysql_sql = (
76+ "select `p`.`instrument_id` AS `instrument_id`,`p`.`price_date` AS `price_date`,`p`.`close` AS `close` "
77+ "from (`example`.`prices` `p` join (select `example`.`prices`.`instrument_id` AS `instrument_id`,"
78+ "max(`example`.`prices`.`price_date`) AS `max_date` from `example`.`prices` group by "
79+ "`example`.`prices`.`instrument_id`) `t` on(((`t`.`instrument_id` = `p`.`instrument_id`) and "
80+ "(`t`.`max_date` = `p`.`price_date`))))"
81+ )
82+ with patch .object (MySQLtoSQLite , "__init__" , return_value = None ):
83+ inst = MySQLtoSQLite () # type: ignore[call-arg]
84+ inst ._mysql_database = "example" # type: ignore[attr-defined]
85+ out = inst ._mysql_viewdef_to_sqlite (view_select_sql = mysql_sql , view_name = "v_prices" )
86+ # Ensure all schema qualifiers are removed, including on qualified columns inside subqueries
87+ assert '"example".' not in out and "`example`." not in out and " example." not in out
88+ # Still references the base table name
89+ assert 'FROM "prices"' in out or 'FROM ("prices"' in out or "FROM prices" in out
90+ assert out .strip ().endswith (";" )
91+
92+ def test_mysql_viewdef_to_sqlite_strips_matching_schema_qualifiers (self ) -> None :
4593 mysql_select = "SELECT `u`.`id` FROM `db`.`users` AS `u`"
46- sql = MySQLtoSQLite ._mysql_viewdef_to_sqlite (
94+ # Use instance for consistent attribute access
95+ with patch .object (MySQLtoSQLite , "__init__" , return_value = None ):
96+ inst = MySQLtoSQLite () # type: ignore[call-arg]
97+ inst ._mysql_database = "db" # type: ignore[attr-defined]
98+ # Since keep_schema behavior is no longer parameterized, ensure that if schema matches current db, it is stripped
99+ sql = inst ._mysql_viewdef_to_sqlite (
47100 view_select_sql = mysql_select ,
48101 view_name = "v_users" ,
49- schema_name = "db" ,
50- keep_schema = True ,
51102 )
52- # Should not strip the schema when keep_schema=True
53- assert "`db`." in sql or '"db".' in sql
103+ assert "`db`." not in sql and '"db".' not in sql
54104 assert sql .strip ().endswith (";" )
0 commit comments