Skip to content

Commit

Permalink
Update gel-orm generators.
Browse files Browse the repository at this point in the history
Make generated models sorted by name so that the output is stable and
does not change when the schema does not change.
Expose arrays as valid scalars for SQLAlchemy and Django.
Don't attempt to reflect computeds because we don't have then in SQL.
Reformat to avoid long lines.
  • Loading branch information
vpetrovykh committed Feb 3, 2025
1 parent a61960f commit c4020ef
Show file tree
Hide file tree
Showing 11 changed files with 541 additions and 163 deletions.
45 changes: 35 additions & 10 deletions gel/orm/django/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@
# values are controlled in Django via settings (USE_TZ) and are mutually
# exclusive in the same app under default circumstances.
'std::datetime': 'DateTimeField',
'cal::local_date': 'DateField',
'cal::local_datetime': 'DateTimeField',
'cal::local_time': 'TimeField',
'std::cal::local_date': 'DateField',
'std::cal::local_datetime': 'DateTimeField',
'std::cal::local_time': 'TimeField',
# all kinds of durations are not supported due to this error:
# iso_8601 intervalstyle currently not supported
}
Expand All @@ -38,6 +38,8 @@
#
from django.db import models
from django.contrib.postgres import fields as pgf
class GelUUIDField(models.UUIDField):
# This field must be treated as a auto-generated UUID.
Expand All @@ -55,6 +57,17 @@ class GelPGMeta:
'''

CLOSEPAR_RE = re.compile(r'\)(?=\s+#|$)')
ARRAY_RE = re.compile(r'^array<(?P<el>.+)>$')
NAME_RE = re.compile(r'^(?P<alpha>\w+?)(?P<num>\d*)$')


def field_name_sort(item):
key, val = item

match = NAME_RE.fullmatch(key)
res = (match.group('alpha'), int(match.group('num') or -1))

return res


class ModelClass(object):
Expand Down Expand Up @@ -166,11 +179,11 @@ def build_models(self, maps):

mod.links['source'] = (
f"LTForeignKey({source!r}, models.DO_NOTHING, "
f"db_column='source', primary_key=True)"
f"db_column='source')"
)
mod.links['target'] = (
f"LTForeignKey({target!r}, models.DO_NOTHING, "
f"db_column='target')"
f"db_column='target', primary_key=True)"
)

# Update the source model with the corresponding
Expand All @@ -197,6 +210,12 @@ def render_prop(self, prop):
req = 'blank=True, null=True'

target = prop['target']['name']
is_array = False
match = ARRAY_RE.fullmatch(target)
if match:
is_array = True
target = match.group('el')

try:
ftype = GEL_SCALAR_MAP[target]
except KeyError:
Expand All @@ -206,7 +225,10 @@ def render_prop(self, prop):
)
return ''

return f'models.{ftype}({req})'
if is_array:
return f'pgf.ArrayField(models.{ftype}({req}))'
else:
return f'models.{ftype}({req})'

def render_link(self, link, bklink=None):
if link['required']:
Expand Down Expand Up @@ -267,7 +289,7 @@ def render_models(self, spec):
self.out = f
self.write(BASE_STUB)

for mod in modmap.values():
for mod in sorted(modmap.values(), key=lambda x: x.name):
self.write()
self.write()
self.render_model_class(mod)
Expand All @@ -284,19 +306,22 @@ def render_model_class(self, mod):
if mod.props:
self.write()
self.write(f'# properties as Fields')
for name, val in mod.props.items():
props = sorted(mod.props.items(), key=field_name_sort)
for name, val in props:
self.write(f'{name} = {val}')

if mod.links:
self.write()
self.write(f'# links as ForeignKeys')
for name, val in mod.links.items():
links = sorted(mod.links.items(), key=field_name_sort)
for name, val in links:
self.write(f'{name} = {val}')

if mod.mlinks:
self.write()
self.write(f'# multi links as ManyToManyFields')
for name, val in mod.mlinks.items():
mlinks = sorted(mod.mlinks.items(), key=field_name_sort)
for name, val in mlinks:
self.write(f'{name} = {val}')

if '.' not in mod.table:
Expand Down
4 changes: 2 additions & 2 deletions gel/orm/introspection.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
),
target: {name},
},
} filter .name != '__type__',
} filter .name != '__type__' and not exists .expr,
properties: {
name,
readonly,
Expand All @@ -42,7 +42,7 @@
filter .name = 'std::exclusive'
),
target: {name},
},
} filter not exists .expr,
backlinks := <array<str>>[],
}
filter
Expand Down
Loading

0 comments on commit c4020ef

Please sign in to comment.