@@ -634,6 +634,45 @@ def alter(definition: str, old_definition: str, context: dict, adapter) -> tuple
634634 return sql , [e for e in external_stores if e not in external_stores_ ]
635635
636636
637+ def _parse_index_args (args : str ) -> list [str ]:
638+ """
639+ Parse comma-separated index arguments, handling nested parentheses.
640+
641+ Parameters
642+ ----------
643+ args : str
644+ The arguments string from an index declaration (e.g., ``"a, b, (func(x, y))"``)
645+
646+ Returns
647+ -------
648+ list[str]
649+ List of individual arguments with surrounding whitespace stripped.
650+
651+ Notes
652+ -----
653+ This parser correctly handles nested parentheses in expressions like
654+ ``(json_value(`col`, '$.path' returning char(20)))``.
655+ """
656+ result = []
657+ current = []
658+ depth = 0
659+ for char in args :
660+ if char == "(" :
661+ depth += 1
662+ current .append (char )
663+ elif char == ")" :
664+ depth -= 1
665+ current .append (char )
666+ elif char == "," and depth == 0 :
667+ result .append ("" .join (current ).strip ())
668+ current = []
669+ else :
670+ current .append (char )
671+ if current :
672+ result .append ("" .join (current ).strip ())
673+ return [arg for arg in result if arg ] # Filter empty strings
674+
675+
637676def compile_index (line : str , index_sql : list [str ], adapter ) -> None :
638677 """
639678 Parse an index declaration and append SQL to index_sql.
@@ -667,7 +706,7 @@ def format_attribute(attr):
667706 raise DataJointError (f'Table definition syntax error in line "{ line } "' )
668707 match = match .groupdict ()
669708
670- attr_list = re . findall ( r"(?:[^,(]|\([^)]*\))+" , match ["args" ])
709+ attr_list = _parse_index_args ( match ["args" ])
671710 index_sql .append (
672711 "{unique}index ({attrs})" .format (
673712 unique = "unique " if match ["unique" ] else "" ,
0 commit comments