Skip to content

Commit 6402540

Browse files
authored
Add ParametricTypeName to support names of types like arrays and tuples. (#940)
Adds to `_schemapath` - `ParametricTypeName` which represents a type with parameters such as `array<int64>`. - `TypeName` which is an alias for `SchemaPath | ParametricTypeName` Then uses these: - Change query builder expressions to use `TypeName` instead of `SchemaPath` for types. - Add `type_name` to `GelTypeMetadata.__gel_reflection__`
1 parent b2c9224 commit 6402540

File tree

18 files changed

+528
-195
lines changed

18 files changed

+528
-195
lines changed

gel/_internal/_codegen/_models/_pydantic.py

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1131,7 +1131,8 @@ def write_schema_reflection(
11311131
base_types: Iterable[str] = (),
11321132
base_metadata_class: str = "GelSchemaMetadata",
11331133
) -> None:
1134-
schemapath = self.import_name(BASE_IMPL, "SchemaPath")
1134+
sp_clsname = self.import_name(BASE_IMPL, "SchemaPath")
1135+
ptn_clsname = self.import_name(BASE_IMPL, "ParametricTypeName")
11351136
base_types = list(base_types)
11361137
if not base_types:
11371138
if isinstance(sobj, reflection.InheritingType):
@@ -1148,14 +1149,21 @@ def write_schema_reflection(
11481149
base_types,
11491150
),
11501151
):
1151-
self.write(f"name = {sobj.schemapath.as_code(schemapath)}")
1152+
obj_name = sobj.schemapath.as_python_code(sp_clsname, ptn_clsname)
1153+
self.write(f"name = {obj_name}")
1154+
if isinstance(sobj, reflection.Type):
1155+
type_name = sobj.get_type_name(self._types).as_python_code(
1156+
sp_clsname, ptn_clsname
1157+
)
1158+
self.write(f"type_name = {type_name}")
11521159

11531160
def write_object_type_reflection(
11541161
self,
11551162
objtype: reflection.ObjectType,
11561163
base_types: list[str],
11571164
) -> None:
1158-
sp = self.import_name(BASE_IMPL, "SchemaPath")
1165+
sp_clsname = self.import_name(BASE_IMPL, "SchemaPath")
1166+
ptn_clsname = self.import_name(BASE_IMPL, "ParametricTypeName")
11591167
lazyclassproperty = self.import_name(BASE_IMPL, "LazyClassProperty")
11601168
objecttype_t = self.get_type(
11611169
self._schema_object_type,
@@ -1186,7 +1194,14 @@ def write_object_type_reflection(
11861194
"__gel_reflection__",
11871195
_map_name(lambda s: f"{s}.__gel_reflection__", class_bases),
11881196
):
1189-
self.write(f"name = {objtype.schemapath.as_code(sp)}")
1197+
obj_name = objtype.schemapath.as_python_code(
1198+
sp_clsname, ptn_clsname
1199+
)
1200+
type_name = objtype.get_type_name(self._types).as_python_code(
1201+
sp_clsname, ptn_clsname
1202+
)
1203+
self.write(f"name = {obj_name}")
1204+
self.write(f"type_name = {type_name}")
11901205
# Need a cheap at runtime way to check if the type is abstract
11911206
# in GelModel.__new__
11921207
self.write(f"abstract = {objtype.abstract!r}")
@@ -1263,6 +1278,9 @@ def _write_pointers_reflection(
12631278
self.write(f"my_ptrs: {ptr_ref_t} = {{")
12641279
classes = {
12651280
"SchemaPath": self.import_name(BASE_IMPL, "SchemaPath"),
1281+
"ParametricTypeName": self.import_name(
1282+
BASE_IMPL, "ParametricTypeName"
1283+
),
12661284
"GelPointerReflection": gel_ptr_ref,
12671285
"Cardinality": self.import_name(BASE_IMPL, "Cardinality"),
12681286
"PointerKind": self.import_name(BASE_IMPL, "PointerKind"),
@@ -1301,8 +1319,9 @@ def _reflect_pointer(
13011319
target_type = self._types[ptr.target_id]
13021320
kwargs: dict[str, str] = {
13031321
"name": repr(ptr.name),
1304-
"type": target_type.schemapath.as_code(classes["SchemaPath"]),
1305-
"typexpr": repr(target_type.edgeql),
1322+
"type": target_type.get_type_name(self._types).as_python_code(
1323+
classes["SchemaPath"], classes["ParametricTypeName"]
1324+
),
13061325
"kind": f"{classes['PointerKind']}({str(ptr.kind)!r})",
13071326
"cardinality": f"{classes['Cardinality']}({str(ptr.card)!r})",
13081327
"computed": str(ptr.is_computed),
@@ -2797,7 +2816,7 @@ def _write_prefix_op_method_node_ctor(
27972816
args = [
27982817
"expr=self", # The operand is always 'self' for method calls
27992818
f'op="{op_name}"', # Gel operator name (e.g., "-", "+")
2800-
"type_=__rtype__.__gel_reflection__.name", # Result type info
2819+
"type_=__rtype__.__gel_reflection__.type_name", # Result type info
28012820
]
28022821

28032822
self.write(self.format_list(f"{node_cls}({{list}}),", args))
@@ -2863,7 +2882,7 @@ def _write_prefix_op_func_node_ctor(
28632882
args = [
28642883
f"expr={other}",
28652884
f'op="{op_name}"', # Gel operator name (e.g., "-", "+")
2866-
"type_=__rtype__.__gel_reflection__.name", # Result type info
2885+
"type_=__rtype__.__gel_reflection__.type_name", # Result type info
28672886
]
28682887

28692888
self.write(self.format_list(f"{node_cls}({{list}}),", args))
@@ -2925,7 +2944,7 @@ def _write_infix_op_func_node_ctor(
29252944
self.write(f"{op_chain}(")
29262945
self.write(f' "{op_name}",')
29272946
self.write(" __args__,")
2928-
self.write(" __rtype__.__gel_reflection__.name,")
2947+
self.write(" __rtype__.__gel_reflection__.type_name,")
29292948
self.write(")")
29302949
return
29312950

@@ -2948,7 +2967,7 @@ def _write_infix_op_func_node_ctor(
29482967
f"lexpr={this}",
29492968
f'op="{op_name}"',
29502969
f"rexpr={other}",
2951-
"type_=__rtype__.__gel_reflection__.name",
2970+
"type_=__rtype__.__gel_reflection__.type_name",
29522971
]
29532972

29542973
self.write(self.format_list(f"{node_cls}({{list}}),", args))
@@ -3024,7 +3043,7 @@ def _write_infix_op_method_node_ctor(
30243043

30253044
args = [
30263045
f'op="{op_name}"', # Gel operator name (e.g., "+", "[]")
3027-
"type_=__rtype__.__gel_reflection__.name", # Result type info
3046+
"type_=__rtype__.__gel_reflection__.type_name", # Result type info
30283047
]
30293048

30303049
if swapped:
@@ -5161,7 +5180,7 @@ def _write_func_node_ctor(
51615180
self.write("args=__args__,")
51625181
if bool(sig.kwargs):
51635182
self.write("kwargs=__kwargs__,")
5164-
self.write("type_=__rtype__.__gel_reflection__.name,")
5183+
self.write("type_=__rtype__.__gel_reflection__.type_name,")
51655184
self.write(")")
51665185

51675186
def _write_function_overload(
@@ -5482,7 +5501,7 @@ def write_cast_match(
54825501
with self.if_(f"{type_var} is None"):
54835502
self.write(
54845503
f"{type_var} = "
5485-
f"{cast_t}.__gel_reflection__.name"
5504+
f"{cast_t}.__gel_reflection__.type_name"
54865505
)
54875506
if type_var is not None:
54885507
anytype = self.get_type(self._types_by_name["anytype"])
@@ -5491,7 +5510,7 @@ def write_cast_match(
54915510
with self.if_(f"{type_var} is None"):
54925511
self.write(
54935512
f"{type_var} = "
5494-
f"{var}.__gel_reflection__.name"
5513+
f"{var}.__gel_reflection__.type_name"
54955514
)
54965515

54975516
# Build a `match` block for Python-to-Gel coercion of values.
@@ -5605,7 +5624,7 @@ def write_cast_match(
56055624
self.write(
56065625
f"{new_pident} = {set_lit}("
56075626
f"items=(*{pident},), "
5608-
f"type_={canon_type}.__gel_reflection__.name)"
5627+
f"type_={canon_type}.__gel_reflection__.type_name)"
56095628
)
56105629

56115630
rt_generics = generic_param_map.get("__return__")

gel/_internal/_edgeql/_schema.py

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,13 @@
55

66
from __future__ import annotations
77

8-
from typing import TYPE_CHECKING, final
8+
from typing import final
99

1010
import re
1111
import uuid
1212

1313
from gel._internal._polyfills._strenum import StrEnum
14-
15-
if TYPE_CHECKING:
16-
from collections.abc import Iterable
14+
from gel._internal._schemapath import ParametricTypeName, SchemaPath, TypeName
1715

1816

1917
@final
@@ -73,46 +71,56 @@ def _get_type_id(name: str, cls: str) -> uuid.UUID:
7371

7472

7573
def get_array_type_id_and_name(
76-
element: str,
77-
) -> tuple[uuid.UUID, str]:
78-
type_id = _get_type_id(f"array<{_mangle_name(element)}>", "Array")
79-
type_name = f"array<{element}>"
74+
element: TypeName,
75+
) -> tuple[uuid.UUID, TypeName]:
76+
type_id = _get_type_id(
77+
f"array<{_mangle_name(element.as_schema_name())}>", "Array"
78+
)
79+
type_name = ParametricTypeName(SchemaPath("std", "array"), [element])
8080
return type_id, type_name
8181

8282

8383
def get_range_type_id_and_name(
84-
element: str,
85-
) -> tuple[uuid.UUID, str]:
86-
type_id = _get_type_id(f"range<{_mangle_name(element)}>", "Range")
87-
type_name = f"range<{element}>"
84+
element: TypeName,
85+
) -> tuple[uuid.UUID, TypeName]:
86+
type_id = _get_type_id(
87+
f"range<{_mangle_name(element.as_schema_name())}>", "Range"
88+
)
89+
type_name = ParametricTypeName(
90+
SchemaPath("std", "range"),
91+
[element],
92+
)
8893
return type_id, type_name
8994

9095

9196
def get_multirange_type_id_and_name(
92-
element: str,
93-
) -> tuple[uuid.UUID, str]:
97+
element: TypeName,
98+
) -> tuple[uuid.UUID, TypeName]:
9499
type_id = _get_type_id(
95-
f"multirange<{_mangle_name(element)}>", "MultiRange"
100+
f"multirange<{_mangle_name(element.as_schema_name())}>", "MultiRange"
101+
)
102+
type_name = ParametricTypeName(
103+
SchemaPath("std", "range"),
104+
[element],
96105
)
97-
type_name = f"multirange<{element}>"
98106
return type_id, type_name
99107

100108

101109
def get_tuple_type_id_and_name(
102-
elements: Iterable[str],
103-
) -> tuple[uuid.UUID, str]:
104-
body = ", ".join(elements)
110+
elements: list[TypeName],
111+
) -> tuple[uuid.UUID, TypeName]:
112+
body = ", ".join(element.as_schema_name() for element in elements)
105113
type_id = _get_type_id(f"tuple<{_mangle_name(body)}>", "Tuple")
106-
type_name = f"tuple<{body}>"
114+
type_name = ParametricTypeName(SchemaPath("std", "tuple"), elements)
107115
return type_id, type_name
108116

109117

110118
def get_named_tuple_type_id_and_name(
111-
elements: dict[str, str],
112-
) -> tuple[uuid.UUID, str]:
113-
body = ", ".join(f"{n}:{t}" for n, t in elements.items())
119+
elements: dict[str, TypeName],
120+
) -> tuple[uuid.UUID, TypeName]:
121+
body = ", ".join(f"{n}:{t.as_schema_name()}" for n, t in elements.items())
114122
type_id = _get_type_id(f"tuple<{_mangle_name(body)}>", "Tuple")
115-
type_name = f"tuple<{body}>"
123+
type_name = ParametricTypeName(SchemaPath("std", "tuple"), elements)
116124
return type_id, type_name
117125

118126

gel/_internal/_qb/_abstract.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
if TYPE_CHECKING:
2121
from collections.abc import Iterable, Iterator, Mapping
22-
from gel._internal._schemapath import SchemaPath
22+
from gel._internal._schemapath import TypeName
2323

2424

2525
@dataclass(kw_only=True, frozen=True)
@@ -89,7 +89,7 @@ class Expr(Node):
8989
def precedence(self) -> _edgeql.Precedence: ...
9090

9191
@abc.abstractproperty
92-
def type(self) -> SchemaPath: ...
92+
def type(self) -> TypeName: ...
9393

9494
@abc.abstractmethod
9595
def __edgeql_expr__(self, *, ctx: ScopeContext) -> str: ...
@@ -100,10 +100,10 @@ def __edgeql_qb_expr__(self) -> Self:
100100

101101
@dataclass(kw_only=True, frozen=True)
102102
class TypedExpr(Expr):
103-
type_: SchemaPath
103+
type_: TypeName
104104

105105
@property
106-
def type(self) -> SchemaPath:
106+
def type(self) -> TypeName:
107107
return self.type_
108108

109109

@@ -499,7 +499,7 @@ class ImplicitIteratorStmt(IteratorExpr, Stmt):
499499
"""Base class for statements that are implicit iterators"""
500500

501501
@property
502-
def type(self) -> SchemaPath:
502+
def type(self) -> TypeName:
503503
return self.iter_expr.type
504504

505505
@property

0 commit comments

Comments
 (0)