def coll_as_json_object(expr, *, styperef, env): if irtyputils.is_tuple(styperef): return tuple_as_json_object(expr, styperef=styperef, env=env) elif irtyputils.is_array(styperef): return array_as_json_object(expr, styperef=styperef, env=env) else: raise RuntimeError(f'{styperef!r} is not a collection')
def pg_type_from_ir_typeref( ir_typeref: irast.TypeRef, *, serialized: bool = False, persistent_tuples: bool = False) -> Tuple[str, ...]: if irtyputils.is_array(ir_typeref): if (irtyputils.is_generic(ir_typeref) or (irtyputils.is_abstract(ir_typeref.subtypes[0]) and irtyputils.is_scalar(ir_typeref.subtypes[0]))): return ('anyarray', ) else: tp = pg_type_from_ir_typeref(ir_typeref.subtypes[0], serialized=serialized, persistent_tuples=persistent_tuples) if len(tp) == 1: return (tp[0] + '[]', ) else: return (tp[0], tp[1] + '[]') elif irtyputils.is_anytuple(ir_typeref): return ('record', ) elif irtyputils.is_tuple(ir_typeref): if ir_typeref.material_type: material = ir_typeref.material_type else: material = ir_typeref if persistent_tuples or material.in_schema: return common.get_tuple_backend_name(material.id, catenate=False) else: return ('record', ) elif irtyputils.is_any(ir_typeref): return ('anyelement', ) else: if ir_typeref.material_type: material = ir_typeref.material_type else: material = ir_typeref if irtyputils.is_object(material): if serialized: return ('record', ) else: return ('uuid', ) elif irtyputils.is_abstract(material): return ('anynonarray', ) else: pg_type = base_type_name_map.get(material.id) if pg_type is None: # User-defined scalar type pg_type = common.get_scalar_backend_name( material.id, material.name_hint.module, catenate=False) return pg_type
def coll_as_json_object( expr: pgast.BaseExpr, *, styperef: irast.TypeRef, env: context.Environment, ) -> pgast.BaseExpr: if irtyputils.is_tuple(styperef): return tuple_as_json_object(expr, styperef=styperef, env=env) elif irtyputils.is_array(styperef): return array_as_json_object(expr, styperef=styperef, env=env) else: raise RuntimeError(f'{styperef!r} is not a collection')
def __infer_type_introspection(ir, env): if irtyputils.is_scalar(ir.typeref): return env.schema.get('schema::ScalarType') elif irtyputils.is_object(ir.typeref): return env.schema.get('schema::ObjectType') elif irtyputils.is_array(ir.typeref): return env.schema.get('schema::Array') elif irtyputils.is_tuple(ir.typeref): return env.schema.get('schema::Tuple') else: raise errors.QueryError('unexpected type in INTROSPECT', context=ir.context)
def __infer_type_introspection( ir: irast.TypeIntrospection, env: context.Environment, ) -> s_types.Type: if irtyputils.is_scalar(ir.typeref): return cast(s_objtypes.ObjectType, env.schema.get('schema::ScalarType')) elif irtyputils.is_object(ir.typeref): return cast(s_objtypes.ObjectType, env.schema.get('schema::ObjectType')) elif irtyputils.is_array(ir.typeref): return cast(s_objtypes.ObjectType, env.schema.get('schema::Array')) elif irtyputils.is_tuple(ir.typeref): return cast(s_objtypes.ObjectType, env.schema.get('schema::Tuple')) else: raise errors.QueryError('unexpected type in INTROSPECT', context=ir.context)
def compile_TypeCast(expr: qlast.TypeCast, *, ctx: context.ContextLevel) -> irast.Set: target_typeref = typegen.ql_typeexpr_to_ir_typeref(expr.type, ctx=ctx) ir_expr: irast.Base if (isinstance(expr.expr, qlast.Array) and not expr.expr.elements and irtyputils.is_array(target_typeref)): ir_expr = irast.Array() elif isinstance(expr.expr, qlast.Parameter): pt = typegen.ql_typeexpr_to_type(expr.type, ctx=ctx) if ((pt.is_tuple(ctx.env.schema) or pt.is_anytuple(ctx.env.schema)) and not ctx.env.options.func_params): raise errors.QueryError( 'cannot pass tuples as query parameters', context=expr.expr.context, ) if (isinstance(pt, s_types.Collection) and pt.contains_array_of_tuples(ctx.env.schema) and not ctx.env.options.func_params): raise errors.QueryError( 'cannot pass collections with tuple elements' ' as query parameters', context=expr.expr.context, ) param_name = expr.expr.name if expr.cardinality_mod: if expr.cardinality_mod == qlast.CardinalityModifier.Optional: required = False elif expr.cardinality_mod == qlast.CardinalityModifier.Required: required = True else: raise NotImplementedError( f"cardinality modifier {expr.cardinality_mod}") else: required = True if ctx.env.options.json_parameters: if param_name.isdecimal(): raise errors.QueryError( 'queries compiled to accept JSON parameters do not ' 'accept positional parameters', context=expr.expr.context) typeref = typegen.type_to_typeref( ctx.env.get_track_schema_type('std::json'), env=ctx.env, ) param = casts.compile_cast( irast.Parameter( typeref=typeref, name=param_name, required=required, context=expr.expr.context, ), pt, srcctx=expr.expr.context, ctx=ctx, ) else: typeref = typegen.type_to_typeref(pt, env=ctx.env) param = setgen.ensure_set( irast.Parameter( typeref=typeref, name=param_name, required=required, context=expr.expr.context, ), ctx=ctx, ) if param_name not in ctx.env.query_parameters: if ctx.env.query_parameters: first_key: str = next(iter(ctx.env.query_parameters)) if first_key.isdecimal(): if not param_name.isdecimal(): raise errors.QueryError( f'cannot combine positional and named parameters ' f'in the same query', context=expr.expr.context) else: if param_name.isdecimal(): raise errors.QueryError(f'expected a named argument', context=expr.expr.context) ctx.env.query_parameters[param_name] = irast.Param( name=param_name, required=required, schema_type=pt, ir_type=typeref, ) else: param_first_type = ctx.env.query_parameters[param_name].schema_type if not param_first_type.explicitly_castable_to(pt, ctx.env.schema): raise errors.QueryError( f'cannot cast ' f'{param_first_type.get_displayname(ctx.env.schema)} to ' f'{pt.get_displayname(ctx.env.schema)}', context=expr.expr.context) return param else: with ctx.new() as subctx: # We use "exposed" mode in case this is a type of a cast # that wants view shapes, e.g. a std::json cast. We do # this wholesale to support tuple and array casts without # having to analyze the target type (which is cumbersome # in QL AST). subctx.expr_exposed = True ir_expr = dispatch.compile(expr.expr, ctx=subctx) new_stype = typegen.ql_typeexpr_to_type(expr.type, ctx=ctx) return casts.compile_cast(ir_expr, new_stype, cardinality_mod=expr.cardinality_mod, ctx=ctx, srcctx=expr.expr.context)
def compile_TypeCast(expr: qlast.TypeCast, *, ctx: context.ContextLevel) -> irast.Set: target_stype = typegen.ql_typeexpr_to_type(expr.type, ctx=ctx) target_typeref = typegen.type_to_typeref(target_stype, env=ctx.env) ir_expr: Union[irast.Set, irast.Expr] if (isinstance(expr.expr, qlast.Array) and not expr.expr.elements and irtyputils.is_array(target_typeref)): ir_expr = irast.Array(elements=[], typeref=target_typeref) elif isinstance(expr.expr, qlast.Parameter): pt = typegen.ql_typeexpr_to_type(expr.type, ctx=ctx) if ((pt.is_tuple(ctx.env.schema) or pt.is_anytuple(ctx.env.schema)) and not ctx.env.options.func_params): raise errors.QueryError( 'cannot pass tuples as query parameters', context=expr.expr.context, ) if (isinstance(pt, s_types.Collection) and pt.contains_array_of_tuples(ctx.env.schema) and not ctx.env.options.func_params): raise errors.QueryError( 'cannot pass collections with tuple elements' ' as query parameters', context=expr.expr.context, ) param_name = expr.expr.name if expr.cardinality_mod: if expr.cardinality_mod == qlast.CardinalityModifier.Optional: required = False elif expr.cardinality_mod == qlast.CardinalityModifier.Required: required = True else: raise NotImplementedError( f"cardinality modifier {expr.cardinality_mod}") else: required = True if ctx.env.options.json_parameters: if param_name.isdecimal(): raise errors.QueryError( 'queries compiled to accept JSON parameters do not ' 'accept positional parameters', context=expr.expr.context) typeref = typegen.type_to_typeref( ctx.env.get_track_schema_type(sn.QualName('std', 'json')), env=ctx.env, ) param = casts.compile_cast( irast.Parameter( typeref=typeref, name=param_name, required=required, context=expr.expr.context, ), pt, srcctx=expr.expr.context, ctx=ctx, ) else: typeref = typegen.type_to_typeref(pt, env=ctx.env) param = setgen.ensure_set( irast.Parameter( typeref=typeref, name=param_name, required=required, context=expr.expr.context, ), ctx=ctx, ) if param_name not in ctx.env.query_parameters: if ctx.env.query_parameters: first_key: str = next(iter(ctx.env.query_parameters)) if first_key.isdecimal(): if not param_name.isdecimal(): raise errors.QueryError( f'cannot combine positional and named parameters ' f'in the same query', context=expr.expr.context) else: if param_name.isdecimal(): raise errors.QueryError(f'expected a named argument', context=expr.expr.context) ctx.env.query_parameters[param_name] = irast.Param( name=param_name, required=required, schema_type=pt, ir_type=typeref, ) else: param_first_type = ctx.env.query_parameters[param_name].schema_type if not param_first_type.castable_to(pt, ctx.env.schema): raise errors.QueryError( f'cannot cast ' f'{param_first_type.get_displayname(ctx.env.schema)} to ' f'{pt.get_displayname(ctx.env.schema)}', context=expr.expr.context) return param else: with ctx.new() as subctx: if target_stype.contains_json(subctx.env.schema): # JSON wants type shapes and acts as an output sink. subctx.expr_exposed = True subctx.inhibit_implicit_limit = True subctx.implicit_id_in_shapes = False subctx.implicit_tid_in_shapes = False subctx.implicit_tname_in_shapes = False ir_expr = dispatch.compile(expr.expr, ctx=subctx) return casts.compile_cast(ir_expr, target_stype, cardinality_mod=expr.cardinality_mod, ctx=ctx, srcctx=expr.expr.context)
def compile_TypeCast(expr: qlast.TypeCast, *, ctx: context.ContextLevel) -> irast.Set: target_typeref = typegen.ql_typeexpr_to_ir_typeref(expr.type, ctx=ctx) ir_expr: irast.Base if (isinstance(expr.expr, qlast.Array) and not expr.expr.elements and irtyputils.is_array(target_typeref)): ir_expr = irast.Array() elif isinstance(expr.expr, qlast.Parameter): pt = typegen.ql_typeexpr_to_type(expr.type, ctx=ctx) param_name = expr.expr.name if param_name not in ctx.env.query_parameters: if ctx.env.query_parameters: first_key: str = next(iter(ctx.env.query_parameters)) if first_key.isdecimal(): if not param_name.isdecimal(): raise errors.QueryError( f'cannot combine positional and named parameters ' f'in the same query', context=expr.expr.context) else: if param_name.isdecimal(): raise errors.QueryError(f'expected a named argument', context=expr.expr.context) ctx.env.query_parameters[param_name] = pt else: param_first_type = ctx.env.query_parameters[param_name] if not param_first_type.explicitly_castable_to(pt, ctx.env.schema): raise errors.QueryError( f'cannot cast ' f'{param_first_type.get_displayname(ctx.env.schema)} to ' f'{pt.get_displayname(ctx.env.schema)}', context=expr.expr.context) if ctx.env.json_parameters: if param_name.isdecimal(): raise errors.QueryError( 'queries compiled to accept JSON parameters do not ' 'accept positional parameters', context=expr.expr.context) json_typeref = irtyputils.type_to_typeref( ctx.env.schema, ctx.env.get_track_schema_type('std::json')) param = cast.compile_cast( irast.Parameter( typeref=json_typeref, name=param_name, context=expr.expr.context, ), pt, srcctx=expr.expr.context, ctx=ctx, ) else: param = setgen.ensure_set( irast.Parameter( typeref=irtyputils.type_to_typeref(ctx.env.schema, pt), name=param_name, context=expr.expr.context, ), ctx=ctx, ) return param else: with ctx.new() as subctx: # We use "exposed" mode in case this is a type of a cast # that wants view shapes, e.g. a std::json cast. We do # this wholesale to support tuple and array casts without # having to analyze the target type (which is cumbersome # in QL AST). subctx.expr_exposed = True ir_expr = dispatch.compile(expr.expr, ctx=subctx) new_stype = typegen.ql_typeexpr_to_type(expr.type, ctx=ctx) return cast.compile_cast(ir_expr, new_stype, ctx=ctx, srcctx=expr.expr.context)