Skip to content

Commit aba9f9a

Browse files
committed
Process FK-referenced tables out of order, use their datatypes for referrer fields
1 parent ffd3b9c commit aba9f9a

File tree

1 file changed

+40
-13
lines changed

1 file changed

+40
-13
lines changed

code/Python/dbd_to_sql.py

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import dbd
44
import os
55
from argparse import ArgumentParser
6+
from collections import defaultdict
67
from glob import glob
78

89
script_dir:str = os.path.dirname(os.path.abspath(__file__));
@@ -67,27 +68,32 @@ def get_sql_type(type:str, int_width:int=0, is_unsigned:bool=False)->str:
6768

6869
return f"{type} DEFAULT {default}";
6970

70-
file:str
71-
for file in dbds:
71+
keys:dict[str, dict[str, str]] = defaultdict(dict);
72+
def process_dbd(file:str)->bool:
7273
parsed:dbd.dbd_file = dbd.parse_dbd_file(file);
7374
if not len(parsed.definitions):
7475
print(f"No definitions found in {file}! Skipping");
75-
continue;
76+
return False;
77+
78+
dirname:str = os.path.dirname(file);
79+
name:str = os.path.splitext(os.path.basename(file))[0];
80+
if keys.get(name, None):
81+
return True; # Already processed
7682

7783
types:dict[str,str] = {};
78-
foreigns:dict[str,str] = {};
84+
foreigns:dict[str,list[str]] = {};
7985
column:dbd.column_definition
8086
for column in parsed.columns:
8187
types[column.name] = column.type;
8288
if column.foreign:
83-
foreigns[column.name] = f"FOREIGN KEY (`{column.name}`) REFERENCES `{column.foreign.table}` (`{column.foreign.column}`) ON DELETE NO ACTION ON UPDATE NO ACTION";
89+
foreigns[column.name] = column.foreign;
8490

8591
definition:dbd.definitions = None;
8692
if args.layout:
8793
definition = next(defn for defn in parsed.definitions if args.layout in defn.layouts);
8894
if not definition:
8995
print(f"No definition found for layout {args.layout}! Skipping");
90-
continue;
96+
return False;
9197
elif args.build:
9298
definition = next(defn for defn in parsed.definitions if args.build in defn.builds);
9399

@@ -96,25 +102,41 @@ def get_sql_type(type:str, int_width:int=0, is_unsigned:bool=False)->str:
96102
lambda defn: max(getattr(build, 'build', getattr(build[-1], 'build', 0)) for build in defn.builds)
97103
);
98104

99-
name:str = os.path.splitext(os.path.basename(file))[0];
100-
101105
# TODO: include comments in sql
102106
columns:list[str] = [];
103107
indices:list[str] = [];
104108
fkeys:list[str] = [];
105109
entry:dbd.definition_entry
106110
for entry in definition.entries:
107-
column = f"`{entry.column}` {get_sql_type(types.get(entry.column), entry.int_width, entry.is_unsigned)}";
111+
sql_type:str = get_sql_type(types.get(entry.column), entry.int_width, entry.is_unsigned);
112+
suffix:str = '';
108113
if 'id' in entry.annotation:
109-
column += ' PRIMARY KEY';
110-
elif entry.column in foreigns.keys():
111-
fkeys.append(foreigns.get(entry.column));
114+
suffix = 'PRIMARY KEY';
115+
keys[name][entry.column] = sql_type;
116+
elif (foreign := foreigns.get(entry.column, None)):
117+
# TODO: unhack!
118+
if not keys.get(foreign.table.string, {}).get(foreign.column.string, None):
119+
foreign_dbd:str = next((f for f in dbds if os.path.basename(f) == f"{foreign.table}.dbd"), None);
120+
if foreign_dbd:
121+
if not process_dbd(foreign_dbd):
122+
print(f"Could not process table {foreign.table} referenced by {name}.{entry.column}");
123+
return False;
124+
if not foreign_dbd:
125+
print(f"FK {name}.{entry.column} references {foreign.column} in {foreign.table} which was not supplied");
126+
127+
sql_type = keys[foreign.table.string].get(foreign.column.string, None) or sql_type;
128+
fkeys.append(
129+
f"FOREIGN KEY (`{entry.column}`) "
130+
f"REFERENCES `{foreign.table}` (`{foreign.column}`) "
131+
'ON DELETE NO ACTION ON UPDATE NO ACTION'
132+
);
112133
elif 'relation' in entry.annotation:
134+
keys[name][entry.column] = sql_type;
113135
indices.append(f"INDEX (`{entry.column}`)");
114136
# TODO: Get self-referencing keys to work
115137
#fkeys.append(f"FOREIGN KEY (`{entry.column}`) REFERENCES `{name}` (`{entry.column}`) ON DELETE NO ACTION ON UPDATE NO ACTION");
116138

117-
columns.append(column);
139+
columns.append(f"`{entry.column}` {sql_type} {suffix}");
118140

119141
fields:list[str] = [','.join(columns)];
120142
if len(indices):
@@ -131,6 +153,11 @@ def get_sql_type(type:str, int_width:int=0, is_unsigned:bool=False)->str:
131153
with open(os.path.join(outdir, f"{name}.sql"), 'w') as file:
132154
file.write(stmt);
133155

156+
return True;
157+
158+
for file in dbds:
159+
process_dbd(file);
160+
134161
if outfile:
135162
with open(outfile, 'a') as file:
136163
file.write("SET SESSION FOREIGN_KEY_CHECKS=1;\n");

0 commit comments

Comments
 (0)