11"""Parser for Drizzle ORM TypeScript schemas into SchemaForge IR."""
2+
23from __future__ import annotations
34
45import re
@@ -66,16 +67,16 @@ def parse(self, text: str) -> Schema:
6667
6768 # Find all table definitions: pgTable('name', { ... }) or mysqlTable etc.
6869 table_pattern = re .compile (
69- r' (?:export\s+)?(?:const\s+)?(\w+)\s*=\s*'
70- r' (pgTable|mysqlTable|sqliteTable)\s*\(\s*'
70+ r" (?:export\s+)?(?:const\s+)?(\w+)\s*=\s*"
71+ r" (pgTable|mysqlTable|sqliteTable)\s*\(\s*"
7172 r"['\"](\w+)['\"]\s*,\s*\{" ,
7273 re .MULTILINE ,
7374 )
7475
7576 # Also find pgEnum declarations
7677 enum_pattern = re .compile (
77- r' (?:export\s+)?(?:const\s+)?(\w+)\s*=\s*'
78- r' pgEnum\s*\(\s*'
78+ r" (?:export\s+)?(?:const\s+)?(\w+)\s*=\s*"
79+ r" pgEnum\s*\(\s*"
7980 r"['\"](\w+)['\"]\s*,\s*\[([^\]]*)\]" ,
8081 re .MULTILINE ,
8182 )
@@ -84,7 +85,9 @@ def parse(self, text: str) -> Schema:
8485 m .group (1 )
8586 enum_name = m .group (2 )
8687 values_str = m .group (3 )
87- values = [v .strip ().strip ("'\" " ) for v in values_str .split ("," ) if v .strip ()]
88+ values = [
89+ v .strip ().strip ("'\" " ) for v in values_str .split ("," ) if v .strip ()
90+ ]
8891 schema .enums .append (EnumType (name = enum_name , values = values ))
8992
9093 for m in table_pattern .finditer (text ):
@@ -121,24 +124,24 @@ def _extract_columns_block(self, text: str, start_pos: int) -> str | None:
121124
122125 while i < len (text ) and depth > 0 :
123126 ch = text [i ]
124- if ch == '{' :
127+ if ch == "{" :
125128 depth += 1
126- elif ch == '}' :
129+ elif ch == "}" :
127130 depth -= 1
128- elif ch in ("'" , '"' , '`' ):
131+ elif ch in ("'" , '"' , "`" ):
129132 # Skip string literals
130133 quote = ch
131134 i += 1
132135 while i < len (text ) and text [i ] != quote :
133- if text [i ] == ' \\ ' :
136+ if text [i ] == " \\ " :
134137 i += 1
135138 i += 1
136139 i += 1
137140
138141 if depth != 0 :
139142 return None
140143
141- return text [block_start : i - 1 ]
144+ return text [block_start : i - 1 ]
142145
143146 def _parse_columns (self , columns_text : str , factory : str ) -> list [Column ]:
144147 """Parse column definitions from the columns block."""
@@ -149,7 +152,7 @@ def _parse_columns(self, columns_text: str, factory: str) -> list[Column]:
149152
150153 for col_def in col_defs :
151154 col_def = col_def .strip ()
152- if not col_def or col_def .startswith ('//' ) or col_def .startswith ('/*' ):
155+ if not col_def or col_def .startswith ("//" ) or col_def .startswith ("/*" ):
153156 continue
154157 col = self ._parse_single_column (col_def , factory )
155158 if col :
@@ -170,19 +173,19 @@ def _split_column_defs(self, text: str) -> list[str]:
170173 ch = text [i ]
171174 if in_string :
172175 current += ch
173- if ch == string_char and (i == 0 or text [i - 1 ] != ' \\ ' ):
176+ if ch == string_char and (i == 0 or text [i - 1 ] != " \\ " ):
174177 in_string = False
175- elif ch in ("'" , '"' , '`' ):
178+ elif ch in ("'" , '"' , "`" ):
176179 in_string = True
177180 string_char = ch
178181 current += ch
179- elif ch == '(' :
182+ elif ch == "(" :
180183 depth += 1
181184 current += ch
182- elif ch == ')' :
185+ elif ch == ")" :
183186 depth -= 1
184187 current += ch
185- elif ch == ',' and depth == 0 :
188+ elif ch == "," and depth == 0 :
186189 defs .append (current .strip ())
187190 current = ""
188191 else :
@@ -215,19 +218,19 @@ def _parse_single_column(self, col_def: str, factory: str) -> Column | None:
215218 col_type = _DRIZZLE_TYPE_MAP .get (type_func , ColumnType .CUSTOM )
216219
217220 # Parse type args from the rest of the definition
218- rest = col_def [m .end ():]
221+ rest = col_def [m .end () :]
219222 type_args : dict [str , Any ] = {}
220223
221224 # Extract { length: N }
222- length_m = re .search (r' length\s*:\s*(\d+)' , rest )
225+ length_m = re .search (r" length\s*:\s*(\d+)" , rest )
223226 if length_m :
224227 type_args ["length" ] = int (length_m .group (1 ))
225228
226229 # Extract { precision: N, scale: N }
227- precision_m = re .search (r' precision\s*:\s*(\d+)' , rest )
230+ precision_m = re .search (r" precision\s*:\s*(\d+)" , rest )
228231 if precision_m :
229232 type_args ["precision" ] = int (precision_m .group (1 ))
230- scale_m = re .search (r' scale\s*:\s*(\d+)' , rest )
233+ scale_m = re .search (r" scale\s*:\s*(\d+)" , rest )
231234 if scale_m :
232235 type_args ["scale" ] = int (scale_m .group (1 ))
233236
@@ -238,7 +241,7 @@ def _parse_single_column(self, col_def: str, factory: str) -> Column | None:
238241
239242 # Parse default value
240243 default = None
241- default_m = re .search (r' \.default\(([^)]+)\)' , rest )
244+ default_m = re .search (r" \.default\(([^)]+)\)" , rest )
242245 if default_m :
243246 default_val = default_m .group (1 ).strip ()
244247 if default_val .lower () == "null" :
0 commit comments