From 6859e25276797a3ee7d9f7691d04d4ed1b66efc5 Mon Sep 17 00:00:00 2001 From: "xnuinside@gmail.com" Date: Sun, 19 May 2024 00:24:07 +0300 Subject: [PATCH] fix issues with unique indexes with multiple columns (wrong attribute setting) --- CHANGELOG.txt | 8 ++ README.md | 8 ++ docs/README.rst | 15 ++++ pyproject.toml | 2 +- simple_ddl_parser/dialects/sql.py | 9 +- simple_ddl_parser/output/base_data.py | 10 ++- tests/dialects/test_mssql_specific.py | 4 +- tests/test_unique.py | 114 ++++++++++++++++++++++++++ 8 files changed, 160 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index e04eb18..1d421b9 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,3 +1,11 @@ +**v1.5.0** + +### Fixes + +1. Now, `unique` set up to column only if it was only one column in unique constraint/index. Issue - https://github.com/xnuinside/simple-ddl-parser/issues/255 +2. Fixed issue when UNIQUE KEY was identified as primary key - https://github.com/xnuinside/simple-ddl-parser/issues/253 + + **v1.4.0** ### Fixes diff --git a/README.md b/README.md index 4056707..605b5f5 100644 --- a/README.md +++ b/README.md @@ -490,6 +490,14 @@ for help with debugging & testing support for BigQuery dialect DDLs: ## Changelog +**v1.5.0** + +### Fixes + +1. Now, `unique` set up to column only if it was only one column in unique constraint/index. Issue - https://github.com/xnuinside/simple-ddl-parser/issues/255 +2. Fixed issue when UNIQUE KEY was identified as primary key - https://github.com/xnuinside/simple-ddl-parser/issues/253 + + **v1.4.0** ### Fixes diff --git a/docs/README.rst b/docs/README.rst index cb7546a..6e133ae 100644 --- a/docs/README.rst +++ b/docs/README.rst @@ -29,6 +29,12 @@ Yes, library already has about 9000+ downloads per day - https://pypistats.org/ As maintainer, I guarantee that any backward incompatible changes will not be done in patch or minor version. But! Pay attention that sometimes output in keywords can be changed in minor version because of fixing wrong behaviour in past. +Articles with examples +^^^^^^^^^^^^^^^^^^^^^^ + + +#. SQL Diagram (Part 3): SQL-to-ERD with DDL: https://levelup.gitconnected.com/sql-diagram-part-3-sql-to-erd-with-ddl-4c9840ee86c3 + Updates in version 1.x ^^^^^^^^^^^^^^^^^^^^^^ @@ -549,6 +555,15 @@ for help with debugging & testing support for BigQuery dialect DDLs: Changelog --------- +**v1.5.0** + +Fixes +^^^^^ + + +#. Now, ``unique`` set up to column only if it was only one column in unique constraint/index. Issue - https://github.com/xnuinside/simple-ddl-parser/issues/255 +#. Fixed issue when UNIQUE KEY was identified as primary key - https://github.com/xnuinside/simple-ddl-parser/issues/253 + **v1.4.0** Fixes diff --git a/pyproject.toml b/pyproject.toml index 49771e0..ea2f9d1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "simple-ddl-parser" -version = "1.4.0" +version = "1.5.0" description = "Simple DDL Parser to parse SQL & dialects like HQL, TSQL (MSSQL), Oracle, AWS Redshift, Snowflake, MySQL, PostgreSQL, etc ddl files to json/python dict with full information about columns: types, defaults, primary keys, etc.; sequences, alters, custom types & other entities from ddl." authors = ["Iuliia Volkova "] license = "MIT" diff --git a/simple_ddl_parser/dialects/sql.py b/simple_ddl_parser/dialects/sql.py index 38cf73f..4b0b61f 100644 --- a/simple_ddl_parser/dialects/sql.py +++ b/simple_ddl_parser/dialects/sql.py @@ -421,9 +421,12 @@ def get_column_properties(p_list: List) -> Tuple: references = None if isinstance(p_list[-1], str): if p_list[-1].upper() == "KEY": - pk = True - nullable = False - elif p_list[-1].upper() == "UNIQUE": + if p_list[-2].upper() == "UNIQUE": + unique = True + else: + pk = True + nullable = False + if p_list[-1].upper() == "UNIQUE": unique = True elif isinstance(p_list[-1], dict) and "references" in p_list[-1]: p_list[-1]["references"]["column"] = p_list[-1]["references"]["columns"][0] diff --git a/simple_ddl_parser/output/base_data.py b/simple_ddl_parser/output/base_data.py index 875cec4..e53bdf4 100644 --- a/simple_ddl_parser/output/base_data.py +++ b/simple_ddl_parser/output/base_data.py @@ -112,7 +112,7 @@ def set_column_unique_param(self, key: str) -> None: check_in = [] else: check_in = getattr(self, key, {}) - if column["name"] in check_in: + if len(check_in) == 1 and column["name"] in check_in: column["unique"] = True def normalize_ref_columns_in_final_output(self): @@ -285,9 +285,11 @@ def set_default_columns_from_alter(self, statement: Dict) -> None: def set_unique_columns_from_alter(self, statement: Dict) -> None: for column in self.columns: - for column_name in statement["unique"]["columns"]: - if column["name"] == column_name: - column["unique"] = True + if len(statement["unique"]["columns"]) == 1: + # if unique index only on one column + for column_name in statement["unique"]["columns"]: + if column["name"] == column_name: + column["unique"] = True def alter_modify_columns(self, statement) -> None: alter_key = "columns_to_modify" diff --git a/tests/dialects/test_mssql_specific.py b/tests/dialects/test_mssql_specific.py index bba8c64..5130a26 100644 --- a/tests/dialects/test_mssql_specific.py +++ b/tests/dialects/test_mssql_specific.py @@ -1326,7 +1326,7 @@ def test_alter_unique(): "references": None, "size": (38, 20), "type": "DECIMAL", - "unique": True, + "unique": False, }, { "check": None, @@ -1386,7 +1386,7 @@ def test_alter_unique(): "references": None, "size": 7, "type": "DATETIME2", - "unique": True, + "unique": False, }, { "check": None, diff --git a/tests/test_unique.py b/tests/test_unique.py index f1194f6..52af7f8 100644 --- a/tests/test_unique.py +++ b/tests/test_unique.py @@ -259,3 +259,117 @@ def test_unique_key_statement(): } ] assert DDLParser(ddl).run() == expected + + +def test_unique_alter_sql(): + ddl = """ + CREATE TABLE "participations"( + "user_id" BIGINT NOT NULL, + "project_id" BIGINT NOT NULL, + "team_id" BIGINT NOT NULL, + ); + ALTER TABLE + "participations" ADD CONSTRAINT "participations_team_id_user_id_unique" UNIQUE("team_id", "user_id"); + """ + + result = DDLParser(ddl).run() + expected = [ + { + "alter": { + "uniques": [ + { + "columns": ['"team_id"', '"user_id"'], + "constraint_name": '"participations_team_id_user_id_unique"', + } + ] + }, + "checks": [], + "columns": [ + { + "check": None, + "default": None, + "name": '"user_id"', + "nullable": False, + "references": None, + "size": None, + "type": "BIGINT", + "unique": False, + }, + { + "check": None, + "default": None, + "name": '"project_id"', + "nullable": False, + "references": None, + "size": None, + "type": "BIGINT", + "unique": False, + }, + { + "check": None, + "default": None, + "name": '"team_id"', + "nullable": False, + "references": None, + "size": None, + "type": "BIGINT", + "unique": False, + }, + ], + "index": [], + "partitioned_by": [], + "primary_key": [], + "schema": None, + "table_name": '"participations"', + "tablespace": None, + } + ] + assert expected == result + + +def test_unique_key(): + ddl = """ + CREATE TABLE `posts`( + `integer_column__unique` INT NOT NULL AUTO_INCREMENT UNIQUE, + `integer_column__unique_key` INT NOT NULL AUTO_INCREMENT UNIQUE KEY + ); + """ + + result = DDLParser(ddl).run() + expected = [ + { + "alter": {}, + "checks": [], + "columns": [ + { + "autoincrement": True, + "check": None, + "default": None, + "name": "`integer_column__unique`", + "nullable": False, + "references": None, + "size": None, + "type": "INT", + "unique": True, + }, + { + "autoincrement": True, + "check": None, + "default": None, + "name": "`integer_column__unique_key`", + "nullable": False, + "references": None, + "size": None, + "type": "INT", + "unique": True, + }, + ], + "index": [], + "partitioned_by": [], + "primary_key": [], + "schema": None, + "table_name": "`posts`", + "tablespace": None, + } + ] + assert expected == result