def _compile_shape(ir_set: irast.Set, shape: typing.List[irast.Set], *, ctx: context.CompilerContextLevel) -> pgast.TupleVar: result = shapecomp.compile_shape(ir_set, shape, ctx=ctx) for element in result.elements: # The ref might have already been added by the nested shape # processing, so add it conditionally. pathctx.put_path_serialized_var_if_not_exists(ctx.rel, element.path_id, element.val, env=ctx.env) ser_elements = [] for el in result.elements: ser_val = pathctx.get_path_serialized_or_value_var(ctx.rel, el.path_id, env=ctx.env) ser_elements.append( pgast.TupleElement(path_id=el.path_id, name=el.name, val=ser_val)) ser_result = pgast.TupleVar(elements=ser_elements, named=True) sval = output.serialize_expr(ser_result, path_id=ir_set.path_id, env=ctx.env) pathctx.put_path_serialized_var(ctx.rel, ir_set.path_id, sval, force=True, env=ctx.env) return result
def strip_output_var( var: pgast.OutputVar, *, optional: typing.Optional[bool] = None, nullable: typing.Optional[bool] = None) -> pgast.OutputVar: if isinstance(var, pgast.TupleVarBase): elements = [] for el in var.elements: if isinstance(el.name, str): val = pgast.ColumnRef(name=[el.name]) else: val = strip_output_var(el.name) elements.append( pgast.TupleElement(path_id=el.path_id, name=el.name, val=val)) result = pgast.TupleVar(elements, named=var.named) else: result = pgast.ColumnRef( name=[var.name[-1]], optional=optional if optional is not None else var.optional, nullable=nullable if nullable is not None else var.nullable, ) return result
def get_rvar_var( rvar: pgast.BaseRangeVar, var: pgast.OutputVar) -> pgast.OutputVar: fieldref: pgast.OutputVar if isinstance(var, pgast.TupleVarBase): elements = [] for el in var.elements: assert isinstance(el.name, pgast.OutputVar) val = get_rvar_var(rvar, el.name) elements.append( pgast.TupleElement( path_id=el.path_id, name=el.name, val=val)) fieldref = pgast.TupleVar(elements, named=var.named) elif isinstance(var, pgast.ColumnRef): fieldref = get_column(rvar, var) else: raise AssertionError(f'unexpected OutputVar subclass: {var!r}') return fieldref
def fix_tuple( rel: pgast.Query, ref: pgast.BaseExpr, *, aspect: str, env: context.Environment) -> pgast.BaseExpr: if ( isinstance(ref, pgast.TupleVarBase) and not isinstance(ref, pgast.TupleVar) ): elements = [] for el in ref.elements: assert el.path_id is not None val = get_path_var_and_fix_tuple( rel, el.path_id, aspect=aspect, env=env) elements.append( pgast.TupleElement( path_id=el.path_id, name=el.name, val=val)) ref = pgast.TupleVar( elements, named=ref.named, typeref=ref.typeref, ) return ref
def tuple_element_for_shape_el( shape_el: irast.Set, value: Optional[pgast.BaseExpr] = None, *, ctx: context.CompilerContextLevel) -> pgast.TupleElementBase: if shape_el.path_id.is_type_intersection_path(): assert shape_el.rptr is not None rptr = shape_el.rptr.source.rptr else: rptr = shape_el.rptr assert rptr is not None ptrref = rptr.ptrref ptrname = ptrref.shortname if value is not None: return pgast.TupleElement( path_id=shape_el.path_id, name=ptrname.name, val=value, ) else: return pgast.TupleElementBase( path_id=shape_el.path_id, name=ptrname.name, )
def tuple_element_for_shape_el(shape_el, value, *, ctx): if shape_el.path_id.is_type_indirection_path(): rptr = shape_el.rptr.source.rptr else: rptr = shape_el.rptr ptrref = rptr.ptrref ptrname = ptrref.shortname return pgast.TupleElement( path_id=shape_el.path_id, name=ptrname, val=value, )
def get_path_serialized_output( rel: pgast.Query, path_id: irast.PathId, *, env: context.Environment) -> pgast.OutputVar: # Serialized output is a special case, we don't # want this behaviour to be recursive, so it # must be kept outside of get_path_output() generic. aspect = 'serialized' path_id = map_path_id(path_id, rel.view_path_id_map) result = rel.path_outputs.get((path_id, aspect)) if result is not None: return result ref = get_path_serialized_or_value_var(rel, path_id, env=env) if ( isinstance(ref, pgast.TupleVarBase) and not isinstance(ref, pgast.TupleVar) ): elements = [] for el in ref.elements: assert el.path_id is not None val = get_path_serialized_or_value_var(rel, el.path_id, env=env) elements.append( pgast.TupleElement( path_id=el.path_id, name=el.name, val=val)) ref = pgast.TupleVar( elements, named=ref.named, typeref=ref.typeref, ) refexpr = output.serialize_expr(ref, path_id=path_id, env=env) alias = get_path_output_alias(path_id, aspect, env=env) restarget = pgast.ResTarget(name=alias, val=refexpr, ser_safe=True) rel.target_list.append(restarget) result = pgast.ColumnRef( name=[alias], nullable=refexpr.nullable, ser_safe=True) _put_path_output_var(rel, path_id, aspect, result, env=env) return result
def get_rvar_var(rvar: pgast.BaseRangeVar, var: pgast.OutputVar) -> pgast.OutputVar: assert isinstance(var, pgast.OutputVar) if isinstance(var, pgast.TupleVarBase): elements = [] for el in var.elements: val = get_rvar_var(rvar, el.name) elements.append( pgast.TupleElement(path_id=el.path_id, name=el.name, val=val)) fieldref = pgast.TupleVar(elements, named=var.named) else: fieldref = get_column(rvar, var) return fieldref
def _compile_shape(ir_set: irast.Set, shape: Sequence[Tuple[irast.Set, qlast.ShapeOp]], *, ctx: context.CompilerContextLevel) -> pgast.TupleVar: result = shapecomp.compile_shape(ir_set, shape, ctx=ctx) for element in result.elements: # We want to force, because the path id might already exist # serialized with a different shape, and we need ours to be # visible. (Anything needing the old one needs to have pulled # it already: see the "unfortunate hack" in # process_set_as_tuple.) pathctx.put_path_serialized_var(ctx.rel, element.path_id, element.val, force=True, env=ctx.env) # When we compile a shape during materialization, stash the # set away so we can consume it in unpack_rvar. if (ctx.materializing and ir_set.typeref.id not in ctx.env.materialized_views): ctx.env.materialized_views[ir_set.typeref.id] = ir_set ser_elements = [] for el in result.elements: ser_val = pathctx.get_path_serialized_or_value_var(ctx.rel, el.path_id, env=ctx.env) ser_elements.append( pgast.TupleElement(path_id=el.path_id, name=el.name, val=ser_val)) ser_result = pgast.TupleVar(elements=ser_elements, named=True) sval = output.serialize_expr(ser_result, path_id=ir_set.path_id, env=ctx.env) pathctx.put_path_serialized_var(ctx.rel, ir_set.path_id, sval, force=True, env=ctx.env) return result
def strip_output_var(var: pgast.OutputVar, *, optional: Optional[bool] = None, nullable: Optional[bool] = None) -> pgast.OutputVar: result: pgast.OutputVar if isinstance(var, pgast.TupleVarBase): elements = [] for el in var.elements: val: pgast.OutputVar el_name = el.name if isinstance(el_name, str): val = pgast.ColumnRef(name=[el_name]) elif isinstance(el_name, pgast.OutputVar): val = strip_output_var(el_name) else: raise AssertionError( f'unexpected tuple element class: {el_name!r}') elements.append( pgast.TupleElement(path_id=el.path_id, name=el_name, val=val)) result = pgast.TupleVar( elements, named=var.named, typeref=var.typeref, ) elif isinstance(var, pgast.ColumnRef): result = pgast.ColumnRef( name=[var.name[-1]], optional=optional if optional is not None else var.optional, nullable=nullable if nullable is not None else var.nullable, ) else: raise AssertionError(f'unexpected OutputVar subclass: {var!r}') return result
def compile_Tuple(expr: irast.Tuple, *, ctx: context.CompilerContextLevel) -> pgast.BaseExpr: ttype = expr.typeref ttypes = {} for i, st in enumerate(ttype.subtypes): if st.element_name: ttypes[st.element_name] = st else: ttypes[str(i)] = st telems = list(ttypes) elements = [] for i, e in enumerate(expr.elements): telem = telems[i] ttype = ttypes[telem] val = dispatch.compile(e.val, ctx=ctx) elements.append(pgast.TupleElement(path_id=e.path_id, val=val)) result = pgast.TupleVar(elements=elements) return output.output_as_value(result, env=ctx.env)
def _compile_shape(ir_set: irast.Set, shape: List[Tuple[irast.Set, qlast.ShapeOp]], *, ctx: context.CompilerContextLevel) -> pgast.TupleVar: result = shapecomp.compile_shape(ir_set, shape, ctx=ctx) for element in result.elements: # We want to force, because the path id might already exist # serialized with a different shape, and we need ours to be # visible. (Anything needing the old one needs to have pulled # it already: see the "unfortunate hack" in # process_set_as_tuple.) pathctx.put_path_serialized_var(ctx.rel, element.path_id, element.val, force=True, env=ctx.env) ser_elements = [] for el in result.elements: ser_val = pathctx.get_path_serialized_or_value_var(ctx.rel, el.path_id, env=ctx.env) ser_elements.append( pgast.TupleElement(path_id=el.path_id, name=el.name, val=ser_val)) ser_result = pgast.TupleVar(elements=ser_elements, named=True) sval = output.serialize_expr(ser_result, path_id=ir_set.path_id, env=ctx.env) pathctx.put_path_serialized_var(ctx.rel, ir_set.path_id, sval, force=True, env=ctx.env) return result
def _get_path_output(rel: pgast.BaseRelation, path_id: irast.PathId, *, aspect: str, allow_nullable: bool = True, ptr_info: typing.Optional[ pg_types.PointerStorageInfo] = None, env: context.Environment) -> pgast.OutputVar: result = rel.path_outputs.get((path_id, aspect)) if result is not None: return result alias = None rptr = path_id.rptr() if rptr is not None and irtyputils.is_id_ptrref(rptr): # A value reference to Object.id is the same as a value # reference to the Object itself. src_path_id = path_id.src_path() id_output = rel.path_outputs.get((src_path_id, 'value')) if id_output is not None: _put_path_output_var(rel, path_id, aspect, id_output, env=env) return id_output if is_terminal_relation(rel): return _get_rel_path_output(rel, path_id, aspect=aspect, ptr_info=ptr_info, env=env) elif is_values_relation(rel): # The VALUES() construct seems to always expose its # value as "column1". alias = 'column1' ref = pgast.ColumnRef(name=[alias]) else: ref = get_path_var(rel, path_id, aspect=aspect, env=env) other_output = find_path_output(rel, path_id, ref, env=env) if other_output is not None: _put_path_output_var(rel, path_id, aspect, other_output, env=env) return other_output if isinstance(ref, pgast.TupleVar): elements = [] for el in ref.elements: el_path_id = reverse_map_path_id(el.path_id, rel.view_path_id_map) try: # Similarly to get_path_var(), check for outer path_id # first for tuple serialized var disambiguation. element = _get_path_output(rel, el_path_id, aspect=aspect, allow_nullable=False, env=env) except LookupError: element = get_path_output(rel, el_path_id, aspect=aspect, allow_nullable=False, env=env) elements.append( pgast.TupleElement(path_id=el_path_id, name=element)) result = pgast.TupleVar(elements=elements, named=ref.named) else: if astutils.is_set_op_query(rel): result = dbobj.strip_output_var(ref) else: if alias is None: alias = get_path_output_alias(path_id, aspect, env=env) restarget = pgast.ResTarget(name=alias, val=ref, ser_safe=getattr( ref, 'ser_safe', False)) if hasattr(rel, 'returning_list'): rel.returning_list.append(restarget) else: rel.target_list.append(restarget) nullable = is_nullable(ref, env=env) if isinstance(ref, pgast.ColumnRef): optional = ref.optional else: optional = None if nullable and not allow_nullable: var = get_path_var(rel, path_id, aspect=aspect, env=env) rel.where_clause = astutils.extend_binop( rel.where_clause, pgast.NullTest(arg=var, negated=True)) nullable = False result = pgast.ColumnRef(name=[alias], nullable=nullable, optional=optional) _put_path_output_var(rel, path_id, aspect, result, env=env) if (aspect == 'identity' and path_id.is_objtype_path() and (path_id, 'value') not in rel.path_outputs): _put_path_output_var(rel, path_id, 'value', result, env=env) return result