Skip to content

Commit

Permalink
Merge pull request #237 from cfhowes/issue_236_unique
Browse files Browse the repository at this point in the history
Issue #236: Updates to handle stand-alone UNIQUE and UNIQUE KEY statements
  • Loading branch information
xnuinside committed Jan 29, 2024
2 parents f605740 + 4790a6d commit b162a34
Show file tree
Hide file tree
Showing 6 changed files with 7,706 additions and 7,418 deletions.
64 changes: 54 additions & 10 deletions simple_ddl_parser/dialects/sql.py
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,7 @@ def p_column(self, p: List) -> None:
p[0] = {"index_stmt": True, "name": p[2]["type"], "columns": ""}
return
if p[1] and isinstance(p[1], dict) and p[1].get("index_stmt") is True:
# @TODO: if we are normalizing columns, we need to normalize them here too.
p[1]["columns"] = remove_par(list(p))[2]
p[0] = p[1]
return
Expand Down Expand Up @@ -425,6 +426,7 @@ def p_defcolumn(self, p: List) -> None:

p[0]["references"] = p[0].get("references", references)
p[0]["unique"] = unique or p[0].get("unique", unique)
# @TODO: ensure column names are normalized if specified for pk and others.
p[0]["primary_key"] = pk or p[0].get("primary_key", pk)
p[0]["nullable"] = (
nullable if nullable is not True else p[0].get("nullable", nullable)
Expand Down Expand Up @@ -1077,12 +1079,40 @@ def p_expression_table(self, p: List) -> None: # noqa R701

def process_unique_and_primary_constraint(self, data: Dict, p_list: List) -> Dict:
if p_list[-1].get("unique_statement"):
data = self.set_constraint(
data,
"uniques",
{"columns": p_list[-1]["unique_statement"]},
p_list[-2]["constraint"]["name"],
)
unique_statement = p_list[-1]["unique_statement"]
if not isinstance(p_list[-2], dict):
# This is a stand alone unique statement, not a CONSTRAINT with UNIQUE clause.
if (
isinstance(unique_statement["columns"], list)
and len(unique_statement["columns"]) > 1
):
# We have a list of column names, a compound unique index
data = self.set_constraint(
data,
"uniques",
{"columns": unique_statement["columns"]},
unique_statement.get(
"name", "UC_" + "_".join(unique_statement["columns"])
),
)
else:
# We have a single column name.
col_name = (
unique_statement["columns"][0]
if isinstance(unique_statement["columns"], list)
else unique_statement["columns"]
)
for col in data["columns"]:
if col["name"] == col_name:
col["unique"] = True
else:
# We have a constraint specified unique statement.
data = self.set_constraint(
data,
"uniques",
{"columns": p_list[-1]["unique_statement"]["columns"]},
p_list[-2]["constraint"]["name"],
)
else:
data = self.set_constraint(
data,
Expand All @@ -1093,7 +1123,9 @@ def process_unique_and_primary_constraint(self, data: Dict, p_list: List) -> Dic
return data

def process_constraints_and_refs(self, data: Dict, p_list: List) -> Dict:
if "constraint" in p_list[-2]:
if "constraint" in p_list[-2] or (
isinstance(p_list[-1], dict) and p_list[-1].keys() == {"unique_statement"}
):
data = self.process_unique_and_primary_constraint(data, p_list)
elif (
len(p_list) >= 4
Expand Down Expand Up @@ -1606,9 +1638,22 @@ def p_expression_primary_key(self, p):
p[0] = p[1]

def p_uniq(self, p: List) -> None:
"""uniq : UNIQUE LP pid RP"""
"""uniq : UNIQUE LP pid RP
| UNIQUE KEY id LP pid RP
"""
p_list = remove_par(list(p))
p[0] = {"unique_statement": p_list[-1]}
key_name = None
if isinstance(p_list[1], str) and p_list[1].upper() == "UNIQUE":
del p_list[1]
if isinstance(p_list[1], str) and p_list[1].upper() == "KEY":
del p_list[1]
if len(p_list) > 2:
# We have name and columns
key_name = p_list[1]

p[0] = {"unique_statement": {"columns": p_list[-1]}}
if key_name is not None:
p[0]["unique_statement"]["name"] = key_name

def p_statem_by_id(self, p: List) -> None:
"""statem_by_id : id LP pid RP
Expand All @@ -1627,7 +1672,6 @@ def p_pkey(self, p: List) -> None:
| pkey_statement ID LP pid RP
"""
p_list = remove_par(list(p))

columns = []

p[0] = {}
Expand Down
14,601 changes: 7,368 additions & 7,233 deletions simple_ddl_parser/parsetab.py

Large diffs are not rendered by default.

30 changes: 17 additions & 13 deletions tests/dialects/test_mssql_specific.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ def test_constraint_unique():
"references": None,
"size": None,
"type": "BIGINT",
"unique": True,
"unique": False,
},
{
"check": None,
Expand All @@ -236,7 +236,7 @@ def test_constraint_unique():
"references": None,
"size": 8000,
"type": "VARBINARY",
"unique": True,
"unique": False,
},
],
"index": [],
Expand Down Expand Up @@ -412,7 +412,7 @@ def test_two_unique_constructs():
"references": None,
"size": None,
"type": "BIGINT",
"unique": True,
"unique": False,
},
{
"check": None,
Expand Down Expand Up @@ -489,7 +489,7 @@ def test_two_unique_constructs():
"references": None,
"size": 8000,
"type": "VARBINARY",
"unique": True,
"unique": False,
},
{
"check": None,
Expand Down Expand Up @@ -686,7 +686,8 @@ def test_two_unique_constructs():
"checks": [
{
"constraint_name": "CHK_Person_Age_under",
"statement": "days_active<=18 AND " "user_city = 'New York'",
"statement": "days_active<=18 AND "
"user_city = 'New York'",
}
],
"references": [
Expand Down Expand Up @@ -811,7 +812,7 @@ def test_foreign_keys():
"references": None,
"size": None,
"type": "BIGINT",
"unique": True,
"unique": False,
},
{
"check": None,
Expand Down Expand Up @@ -895,7 +896,7 @@ def test_foreign_keys():
"references": None,
"size": 8000,
"type": "VARBINARY",
"unique": True,
"unique": False,
},
{
"check": None,
Expand Down Expand Up @@ -1052,7 +1053,8 @@ def test_foreign_keys():
"checks": [
{
"constraint_name": "CHK_Person_Age_under",
"statement": "days_active<=18 AND " "user_city = 'New York'",
"statement": "days_active<=18 AND "
"user_city = 'New York'",
}
],
"uniques": [
Expand Down Expand Up @@ -1177,7 +1179,7 @@ def test_alter_unique():
"references": None,
"size": None,
"type": "BIGINT",
"unique": True,
"unique": False,
},
{
"check": None,
Expand Down Expand Up @@ -1254,7 +1256,7 @@ def test_alter_unique():
"references": None,
"size": 8000,
"type": "VARBINARY",
"unique": True,
"unique": False,
},
{
"check": None,
Expand Down Expand Up @@ -1451,7 +1453,8 @@ def test_alter_unique():
"checks": [
{
"constraint_name": "CHK_Person_Age_under",
"statement": "days_active<=18 AND " "user_city = 'New York'",
"statement": "days_active<=18 AND "
"user_city = 'New York'",
}
],
"references": [
Expand Down Expand Up @@ -1572,7 +1575,7 @@ def test_defaults_in_alter():
"references": None,
"size": None,
"type": "BIGINT",
"unique": True,
"unique": False,
},
{
"check": None,
Expand Down Expand Up @@ -1696,7 +1699,8 @@ def test_defaults_in_alter():
"checks": [
{
"constraint_name": "CHK_Person_Age_under",
"statement": "days_active<=18 AND " "user_city = 'New York'",
"statement": "days_active<=18 AND "
"user_city = 'New York'",
}
],
"references": [
Expand Down
10 changes: 6 additions & 4 deletions tests/test_indexes.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def test_several_indexes_types():
"references": None,
"size": None,
"type": "BIGINT",
"unique": True,
"unique": False,
},
{
"check": None,
Expand Down Expand Up @@ -262,7 +262,8 @@ def test_several_indexes_types():
"checks": [
{
"constraint_name": "CHK_Person_Age_under",
"statement": "days_active<=18 AND " "user_city = 'New York'",
"statement": "days_active<=18 AND "
"user_city = 'New York'",
}
],
"references": [
Expand Down Expand Up @@ -431,7 +432,7 @@ def test_clustered_index():
"references": None,
"size": None,
"type": "BIGINT",
"unique": True,
"unique": False,
},
{
"check": None,
Expand Down Expand Up @@ -605,7 +606,8 @@ def test_clustered_index():
"checks": [
{
"constraint_name": "CHK_Person_Age_under",
"statement": "days_active<=18 AND " "user_city = 'New York'",
"statement": "days_active<=18 AND "
"user_city = 'New York'",
}
],
"references": [
Expand Down
Loading

0 comments on commit b162a34

Please sign in to comment.