Skip to content

Commit aa10331

Browse files
committed
Enable multiple modules for SQLModel reflection.
1 parent 185dd04 commit aa10331

File tree

5 files changed

+277
-290
lines changed

5 files changed

+277
-290
lines changed

gel/orm/sqlmodel.py

+19-78
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,7 @@ def init_module(self, mod, modules):
107107
try:
108108
self.out = f
109109
self.write(f'{COMMENT}\n')
110-
relimport = '.' * len(dirpath)
111-
self.write(f'from {relimport}._tables import *')
110+
self.write(f'from {self.basemodule}._tables import *')
112111
yield f
113112
finally:
114113
self.out = None
@@ -142,7 +141,7 @@ def spec_to_modules_dict(self, spec):
142141

143142
if len(spec['prop_objects']) > 0:
144143
warnings.warn(
145-
f"Skipping multi properties: SQLAlchemy reflection doesn't "
144+
f"Skipping multi properties: SQLModel reflection doesn't "
146145
f"support multi properties as they produce models without a "
147146
f"clear identity.",
148147
GelORMWarning,
@@ -186,52 +185,34 @@ def render_models(self, spec):
186185
self.write()
187186
self.render_link_table(rec)
188187

189-
if 'default' not in modules or len(modules) > 1:
190-
skipped = ', '.join([repr(m) for m in modules if m != 'default'])
191-
warnings.warn(
192-
f"Skipping modules {skipped}: SQLModel reflection doesn't "
193-
f"support multiple modules or non-default modules.",
194-
GelORMWarning,
195-
)
196-
197-
with self.init_module('default', modules):
198-
maps = modules['default']
188+
for mod, maps in modules.items():
199189
if not maps:
200190
# skip apparently empty modules
201-
return
191+
continue
202192

203-
link_objects = sorted(
204-
maps.get('link_objects', {}).values(),
205-
key=lambda x: x['name']
206-
)
207-
for lobj in link_objects:
208-
self.write()
209-
self.render_link_object(lobj, modules)
193+
with self.init_module(mod, modules):
194+
link_objects = sorted(
195+
maps.get('link_objects', {}).values(),
196+
key=lambda x: x['name']
197+
)
198+
for lobj in link_objects:
199+
self.write()
200+
self.render_link_object(lobj, modules)
210201

211-
objects = sorted(
212-
maps.get('object_types', {}).values(),
213-
key=lambda x: x['name']
214-
)
215-
for rec in maps.get('object_types', {}).values():
216-
self.write()
217-
self.render_type(rec, modules)
202+
objects = sorted(
203+
maps.get('object_types', {}).values(),
204+
key=lambda x: x['name']
205+
)
206+
for rec in maps.get('object_types', {}).values():
207+
self.write()
208+
self.render_type(rec, modules)
218209

219210
def render_link_table(self, spec):
220211
mod, source = get_mod_and_name(spec["source"])
221212
tmod, target = get_mod_and_name(spec["target"])
222213
s_fk = self.get_fk(mod, source, 'default')
223214
t_fk = self.get_fk(tmod, target, 'default')
224215

225-
if mod != 'default' or tmod != 'default':
226-
skipped = ', '.join(
227-
[repr(m) for m in {mod, tmod} if m != 'default'])
228-
warnings.warn(
229-
f"Skipping modules {skipped}: SQLModel reflection doesn't "
230-
f"support multiple modules or non-default modules.",
231-
GelORMWarning,
232-
)
233-
return
234-
235216
self.write()
236217
self.write(f'class {spec["name"]}(sm.SQLModel, table=True):')
237218
self.indent()
@@ -263,14 +244,6 @@ def render_link_object(self, spec, modules):
263244
sql_name = spec['table']
264245
source_name, source_link = sql_name.split('.')
265246

266-
if mod != 'default':
267-
warnings.warn(
268-
f"Skipping module {mod!r}: SQLModel reflection doesn't "
269-
f"support multiple modules or non-default modules.",
270-
GelORMWarning,
271-
)
272-
return
273-
274247
self.write()
275248
self.write(f'class {name}(sm.SQLModel, table=True):')
276249
self.indent()
@@ -292,14 +265,6 @@ def render_link_object(self, spec, modules):
292265
lname = link['name']
293266
tmod, target = get_mod_and_name(link['target']['name'])
294267

295-
if tmod != 'default':
296-
warnings.warn(
297-
f"Skipping module {tmod!r}: SQLModel reflection doesn't "
298-
f"support multiple modules or non-default modules.",
299-
GelORMWarning,
300-
)
301-
return
302-
303268
fk = self.get_fk(tmod, target, mod)
304269
sqlafk = self.get_sqla_fk(tmod, target, mod)
305270
pyname = self.get_py_name(tmod, target, mod)
@@ -341,14 +306,6 @@ def render_type(self, spec, modules):
341306
mod, name = get_mod_and_name(spec['name'])
342307
sql_name = get_sql_name(spec['name'])
343308

344-
if mod != 'default':
345-
warnings.warn(
346-
f"Skipping module {mod!r}: SQLModel reflection doesn't "
347-
f"support multiple modules or non-default modules.",
348-
GelORMWarning,
349-
)
350-
return
351-
352309
self.write()
353310
self.write(f'class {name}(sm.SQLModel, table=True):')
354311
self.indent()
@@ -451,14 +408,6 @@ def render_link(self, spec, mod, parent, modules):
451408
cardinality = spec['cardinality']
452409
bklink = f'_{name}_{parent}'
453410

454-
if tmod != 'default':
455-
warnings.warn(
456-
f"Skipping module {tmod!r}: SQLModel reflection doesn't "
457-
f"support multiple modules or non-default modules.",
458-
GelORMWarning,
459-
)
460-
return
461-
462411
if spec.get('has_link_object'):
463412
# intermediate object will have the actual source and target
464413
# links, so the link here needs to be treated similar to a
@@ -526,14 +475,6 @@ def render_backlink(self, spec, mod, modules):
526475
exclusive = spec['exclusive']
527476
bklink = spec['fwname']
528477

529-
if tmod != 'default':
530-
warnings.warn(
531-
f"Skipping module {tmod!r}: SQLModel reflection doesn't "
532-
f"support multiple modules or non-default modules.",
533-
GelORMWarning,
534-
)
535-
return
536-
537478
if spec.get('has_link_object'):
538479
# intermediate object will have the actual source and target
539480
# links, so the link here needs to refer to the intermediate

tests/dbsetup/sqlmodel.edgeql

-71
This file was deleted.

tests/dbsetup/sqlmodel.esdl

-52
This file was deleted.

tests/test_sqlmodel_basic.py

+2-89
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,10 @@
3434

3535
class TestSQLModelBasic(tb.SQLModelTestCase):
3636
SCHEMA = os.path.join(os.path.dirname(__file__), 'dbsetup',
37-
'sqlmodel.esdl')
37+
'base.esdl')
3838

3939
SETUP = os.path.join(os.path.dirname(__file__), 'dbsetup',
40-
'sqlmodel.edgeql')
40+
'base.edgeql')
4141

4242
MODEL_PACKAGE = 'sqlmbase'
4343

@@ -667,93 +667,6 @@ def test_sqlmodel_update_models_05(self):
667667
dt.datetime.fromisoformat('2025-02-01T20:13:45'),
668668
)
669669

670-
def test_sqlmodel_linkprops_01(self):
671-
val = self.sess.exec(select(self.sm.HasLinkPropsA)).one()
672-
self.assertEqual(val.child.target.num, 0)
673-
self.assertEqual(val.child.a, 'single')
674-
675-
def test_sqlmodel_linkprops_02(self):
676-
val = self.sess.exec(select(self.sm.HasLinkPropsA)).one()
677-
self.assertEqual(val.child.target.num, 0)
678-
self.assertEqual(val.child.a, 'single')
679-
680-
# replace the single child with a different one
681-
ch = self.sess.exec(select(self.sm.Child).filter_by(num=1)).one()
682-
val.child = self.sm.HasLinkPropsA_child_link(a='replaced', target=ch)
683-
self.sess.flush()
684-
685-
val = self.sess.exec(select(self.sm.HasLinkPropsA)).one()
686-
self.assertEqual(val.child.target.num, 1)
687-
self.assertEqual(val.child.a, 'replaced')
688-
689-
# make sure there's only one link object still
690-
vals = self.sess.exec(select(self.sm.HasLinkPropsA_child_link))
691-
self.assertEqual(
692-
[(val.a, val.target.num) for val in vals],
693-
[('replaced', 1)]
694-
)
695-
696-
def test_sqlmodel_linkprops_03(self):
697-
val = self.sess.exec(select(self.sm.HasLinkPropsA)).one()
698-
self.assertEqual(val.child.target.num, 0)
699-
self.assertEqual(val.child.a, 'single')
700-
701-
# delete the child object
702-
val = self.sess.exec(select(self.sm.Child).filter_by(num=0)).one()
703-
self.sess.delete(val)
704-
self.sess.flush()
705-
706-
val = self.sess.exec(select(self.sm.HasLinkPropsA)).one()
707-
self.assertEqual(val.child, None)
708-
709-
# make sure the link object is removed
710-
vals = self.sess.exec(select(self.sm.HasLinkPropsA_child_link))
711-
self.assertEqual(list(vals), [])
712-
713-
def test_sqlmodel_linkprops_04(self):
714-
val = self.sess.exec(select(self.sm.HasLinkPropsB)).one()
715-
self.assertEqual(
716-
{(c.b, c.target.num) for c in val.children},
717-
{('hello', 0), ('world', 1)},
718-
)
719-
720-
def test_sqlmodel_linkprops_05(self):
721-
val = self.sess.exec(select(self.sm.HasLinkPropsB)).one()
722-
self.assertEqual(
723-
{(c.b, c.target.num) for c in val.children},
724-
{('hello', 0), ('world', 1)},
725-
)
726-
727-
# Remove one of the children
728-
for t in list(val.children):
729-
if t.b != 'hello':
730-
val.children.remove(t)
731-
self.sess.flush()
732-
733-
val = self.sess.exec(select(self.sm.HasLinkPropsB)).one()
734-
self.assertEqual(
735-
{(c.b, c.target.num) for c in val.children},
736-
{('hello', 0)},
737-
)
738-
739-
def test_sqlmodel_linkprops_06(self):
740-
val = self.sess.exec(select(self.sm.HasLinkPropsB)).one()
741-
self.assertEqual(
742-
{(c.b, c.target.num) for c in val.children},
743-
{('hello', 0), ('world', 1)},
744-
)
745-
746-
# Remove one of the children
747-
val = self.sess.exec(select(self.sm.Child).filter_by(num=0)).one()
748-
self.sess.delete(val)
749-
self.sess.flush()
750-
751-
val = self.sess.exec(select(self.sm.HasLinkPropsB)).one()
752-
self.assertEqual(
753-
{(c.b, c.target.num) for c in val.children},
754-
{('world', 1)},
755-
)
756-
757670
def test_sqlmodel_sorting(self):
758671
# Test the natural sorting function used for ordering fields, etc.
759672

0 commit comments

Comments
 (0)