Skip to content

Commit

Permalink
Add custom serialization for scalars.
Browse files Browse the repository at this point in the history
Some scalar types need to be cast into some other SQL type during
serialization. This can be defined as `custom_sql_serialization`
on the scalar types in schema.
  • Loading branch information
vpetrovykh committed Sep 19, 2024
1 parent 97e1a31 commit eaf9a28
Show file tree
Hide file tree
Showing 5 changed files with 16 additions and 21 deletions.
2 changes: 2 additions & 0 deletions edb/ir/ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,8 @@ class TypeRef(ImmutableBase):
needs_custom_json_cast: bool = False
# If this has a schema-configured backend type, what is it
sql_type: typing.Optional[str] = None
# If this has a schema-configured custom sql serialization, what is it
custom_sql_serialization: typing.Optional[str] = None

def __repr__(self) -> str:
return f'<ir.TypeRef \'{self.name_hint}\' at 0x{id(self):x}>'
Expand Down
21 changes: 6 additions & 15 deletions edb/ir/typeutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,25 +196,12 @@ def is_persistent_tuple(typeref: irast.TypeRef) -> bool:
return False


def get_custom_serialization(
typeref: irast.TypeRef,
) -> Optional[str]:
# FIXME: instead of hardcode we need to extract this from the
# schema/extension
if str(typeref.real_base_type.name_hint) in {
'ext::postgis::box2d',
'ext::postgis::box3d',
}:
return 'geometry'

return None


def needs_custom_serialization(typeref: irast.TypeRef) -> bool:
# True if any component needs custom serialization
return contains_predicate(
typeref,
lambda typeref: get_custom_serialization(typeref) is not None
lambda typeref:
typeref.real_base_type.custom_sql_serialization is not None
)


Expand Down Expand Up @@ -427,6 +414,7 @@ def _typeref(

sql_type = None
needs_custom_json_cast = False
custom_sql_serialization = None
if isinstance(t, s_scalars.ScalarType):
sql_type = t.resolve_sql_type(schema)
if material_typeref is None:
Expand All @@ -437,6 +425,8 @@ def _typeref(
if jcast:
needs_custom_json_cast = bool(jcast.get_code(schema))

custom_sql_serialization = t.get_custom_sql_serialization(schema)

result = irast.TypeRef(
id=t.id,
name_hint=name_hint,
Expand All @@ -457,6 +447,7 @@ def _typeref(
is_opaque_union=t.get_is_opaque_union(schema),
needs_custom_json_cast=needs_custom_json_cast,
sql_type=sql_type,
custom_sql_serialization=custom_sql_serialization,
)
elif isinstance(t, s_types.Tuple) and t.is_named(schema):
schema, material_type = t.material_type(schema)
Expand Down
7 changes: 3 additions & 4 deletions edb/pgsql/compiler/expr.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,16 +140,15 @@ def compile_Parameter(

if irtyputils.needs_custom_serialization(expr.typeref):
if irtyputils.is_array(expr.typeref):
el_sql_type = irtyputils.get_custom_serialization(
expr.typeref.subtypes[0])
subt = expr.typeref.subtypes[0]
el_sql_type = subt.real_base_type.custom_sql_serialization
# Arrays of text encoded types need to come in as the custom type
result = pgast.TypeCast(
arg=result,
type_name=pgast.TypeName(name=(f'{el_sql_type}[]',)),
)
else:
el_sql_type = irtyputils.get_custom_serialization(
expr.typeref)
el_sql_type = expr.typeref.real_base_type.custom_sql_serialization
assert el_sql_type is not None
result = pgast.TypeCast(
arg=result,
Expand Down
4 changes: 2 additions & 2 deletions edb/pgsql/compiler/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -640,7 +640,7 @@ def serialize_custom_array(
]
)
else:
el_sql_type = irtyputils.get_custom_serialization(el_type)
el_sql_type = el_type.real_base_type.custom_sql_serialization
return pgast.TypeCast(
arg=expr,
type_name=pgast.TypeName(name=(f'{el_sql_type}[]',)),
Expand Down Expand Up @@ -715,7 +715,7 @@ def output_as_value(
elif irtyputils.is_tuple(ser_typeref):
return serialize_custom_tuple(expr, styperef=ser_typeref, env=env)
else:
el_sql_type = irtyputils.get_custom_serialization(ser_typeref)
el_sql_type = ser_typeref.real_base_type.custom_sql_serialization
assert el_sql_type is not None
val = pgast.TypeCast(
arg=val,
Expand Down
3 changes: 3 additions & 0 deletions edb/schema/scalars.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ class ScalarType(
compcoef=0.0,
)

custom_sql_serialization = so.SchemaField(
str, default=None, inheritable=False, compcoef=0.0)

@classmethod
def get_schema_class_displayname(cls) -> str:
return 'scalar type'
Expand Down

0 comments on commit eaf9a28

Please sign in to comment.