def visit_Set(self, node): if node.expr is not None: result = self.visit(node.expr) else: links = [] while node.rptr and (not node.show_as_anchor or self.context.inline_anchors): rptr = node.rptr ptrcls = rptr.ptrcls pname = ptrcls.shortname if isinstance(rptr.target.scls, s_objtypes.ObjectType): target = rptr.target.scls.shortname target = qlast.TypeName(maintype=qlast.ObjectRef( name=target.name, module=target.module)) else: target = None link = qlast.Ptr( ptr=qlast.ObjectRef(name=pname.name, ), direction=rptr.direction, target=target, ) if isinstance(ptrcls.source, s_links.Link): link.type = 'property' links.append(link) node = node.rptr.source result = qlast.Path() if node.show_as_anchor and not self.context.inline_anchors: if issubclass(node.show_as_anchor, qlast.Expr): step = node.show_as_anchor() else: step = qlast.ObjectRef(name=node.show_as_anchor) else: step = qlast.ObjectRef(name=node.scls.shortname.name, module=node.scls.shortname.module) result.steps.append(step) result.steps.extend(reversed(links)) if node.shape: result = qlast.Shape(expr=result, elements=[]) for el in node.shape: rptr = el.rptr ptrcls = rptr.ptrcls pn = ptrcls.shortname pn = qlast.ShapeElement(expr=qlast.Path(steps=[ qlast.Ptr(ptr=qlast.ObjectRef(name=pn.name), direction=rptr.direction) ])) result.elements.append(pn) return result
def reduce_ShapePath(self, *kids): self.val = qlast.ShapeElement( expr=kids[0].val )
def visit_Field(self, node): if self._is_duplicate_field(node): return is_top, path, prevt, target, steps = \ self._prepare_field(node) json_mode = False is_shadowed = prevt.is_field_shadowed(node.name) # determine if there needs to be extra subqueries if not prevt.dummy and target.dummy: json_mode = True # this is a special introspection type eql, shape, filterable = target.get_template() spec = qlast.ShapeElement( expr=qlast.Path(steps=[ qlast.Ptr(ptr=qlast.ObjectRef( name=node.alias or node.name)) ]), compexpr=eql, ) elif is_shadowed and not node.alias: # shadowed field that doesn't need an alias spec = filterable = shape = qlast.ShapeElement( expr=qlast.Path(steps=steps), ) elif not node.selection_set or is_shadowed and node.alias: # this is either an unshadowed terminal field or an aliased # shadowed field prefix = qlast.Path(steps=self.get_path_prefix(-1)) eql, shape, filterable = prevt.get_field_template( node.name, parent=prefix, has_shape=bool(node.selection_set)) spec = qlast.ShapeElement( expr=qlast.Path(steps=[ qlast.Ptr(ptr=qlast.ObjectRef( # this is already a sub-query name=node.alias or node.name)) ]), compexpr=eql) else: # if the parent is NOT a shadowed type, we need an explicit SELECT eql, shape, filterable = target.get_template() spec = qlast.ShapeElement( expr=qlast.Path(steps=[ qlast.Ptr(ptr=qlast.ObjectRef( # this is already a sub-query name=node.alias or node.name)) ]), compexpr=eql) if node.selection_set is not None: if json_mode: pass else: # a single recursion target, so we can process # selection set now self._context.fields.append({}) vals = self.visit(node.selection_set) self._context.fields.pop() if shape: shape.elements = vals if filterable: where, orderby, offset, limit = \ self._visit_arguments(node.arguments) filterable.where = where filterable.orderby = orderby filterable.offset = offset filterable.limit = limit # just to make sure that limit doesn't change the # serialization from list to a single object, we # need to force multi-cardinality, while being careful # as to not set the cardinality qualifier on a # non-computable shape element. if (limit is not None and (isinstance(filterable, qlast.Statement) or filterable.compexpr is not None)): spec.cardinality = qlast.Cardinality.MANY path.pop() return spec
def visit_Field(self, node): if self._is_duplicate_field(node): return is_top, path, prevt, target, steps = \ self._prepare_field(node) json_mode = False # determine if there needs to be extra subqueries if not prevt.dummy and target.dummy: json_mode = True # this is a special introspection type eql, shape, filterable = target.get_template() spec = qlast.ShapeElement( expr=qlast.Path(steps=[ qlast.Ptr(ptr=qlast.ObjectRef( name=node.alias or node.name)) ]), compexpr=eql, ) elif prevt.is_field_shadowed(node.name): if prevt.has_native_field(node.name) and not node.alias: spec = filterable = shape = qlast.ShapeElement( expr=qlast.Path(steps=steps), ) else: prefix = qlast.Path(steps=self.get_path_prefix(-1)) eql, shape, filterable = prevt.get_field_template( node.name, parent=prefix, has_shape=bool(node.selection_set)) spec = qlast.ShapeElement( expr=qlast.Path(steps=[ qlast.Ptr(ptr=qlast.ObjectRef( # this is already a sub-query name=node.alias or node.name)) ]), compexpr=eql) else: # if the parent is NOT a shadowed type, we need an explicit SELECT eql, shape, filterable = target.get_template() spec = qlast.ShapeElement( expr=qlast.Path(steps=[ qlast.Ptr(ptr=qlast.ObjectRef( # this is already a sub-query name=node.alias or node.name)) ]), compexpr=eql) if node.selection_set is not None: if json_mode: pass else: # a single recursion target, so we can process # selection set now self._context.fields.append({}) vals = self.visit(node.selection_set) self._context.fields.pop() if shape: shape.elements = vals if filterable: where, orderby, offset, limit = \ self._visit_arguments(node.arguments) filterable.where = where filterable.orderby = orderby filterable.offset = offset filterable.limit = limit path.pop() return spec
def _process_view(*, scls: s_nodes.Node, path_id: irast.PathId, elements: typing.List[qlast.ShapeElement], view_rptr: typing.Optional[context.ViewRPtr] = None, view_name: typing.Optional[sn.SchemaName] = None, is_insert: bool = False, is_update: bool = False, ctx: context.CompilerContext) -> s_nodes.Node: view_scls = schemactx.derive_view(scls, is_insert=is_insert, is_update=is_update, derived_name=view_name, ctx=ctx) is_mutation = is_insert or is_update is_defining_shape = ctx.expr_exposed or is_mutation pointers = [] for shape_el in elements: with ctx.newscope(fenced=True) as scopectx: pointers.append( _normalize_view_ptr_expr(shape_el, view_scls, path_id=path_id, is_insert=is_insert, is_update=is_update, view_rptr=view_rptr, ctx=scopectx)) if is_insert: explicit_ptrs = {ptrcls.shortname for ptrcls in pointers} for pn, ptrcls in scls.pointers.items(): if (not ptrcls.default or pn in explicit_ptrs or ptrcls.is_pure_computable()): continue default_ql = qlast.ShapeElement(expr=qlast.Path(steps=[ qlast.Ptr(ptr=qlast.ObjectRef(name=ptrcls.shortname.name, module=ptrcls.shortname.module)) ])) with ctx.newscope(fenced=True) as scopectx: scopectx.singletons = ctx.singletons.copy() scopectx.singletons.add(path_id) pointers.append( _normalize_view_ptr_expr(default_ql, view_scls, path_id=path_id, is_insert=is_insert, is_update=is_update, view_rptr=view_rptr, ctx=scopectx)) # Check if the view shape includes _only_ the link properties. # If so, we do not need to derive a new target view. lprops_only = True for ptrcls in pointers: if not ptrcls.is_link_property(): lprops_only = False break if lprops_only: view_scls = scls for ptrcls in pointers: if ptrcls.is_link_property(): source = view_rptr.derived_ptrcls else: source = view_scls if ptrcls.source is source and isinstance(source, s_sources.Source): # source may be an ScalarType in shapes that reference __type__, # hence the isinstance check. source.add_pointer(ptrcls, replace=True) if is_defining_shape: if source is None: # The nested shape is merely selecting the pointer, # so the link class has not been derived. But for # the purposes of shape tracking, we must derive it # still. source = derive_ptrcls(view_rptr, target_scls=view_scls, ctx=ctx) ctx.class_shapes[source].append(ptrcls) if view_rptr is not None and view_rptr.derived_ptrcls is not None: view_scls.rptr = view_rptr.derived_ptrcls return view_scls
def _process_view( *, stype: s_nodes.Node, path_id: irast.PathId, path_id_namespace: typing.Optional[irast.WeakNamespace]=None, elements: typing.List[qlast.ShapeElement], view_rptr: typing.Optional[context.ViewRPtr]=None, view_name: typing.Optional[sn.SchemaName]=None, is_insert: bool=False, is_update: bool=False, ctx: context.CompilerContext) -> s_nodes.Node: view_scls = schemactx.derive_view( stype, is_insert=is_insert, is_update=is_update, derived_name=view_name, ctx=ctx) is_mutation = is_insert or is_update is_defining_shape = ctx.expr_exposed or is_mutation pointers = [] for shape_el in elements: with ctx.newscope(fenced=True) as scopectx: pointers.append(_normalize_view_ptr_expr( shape_el, view_scls, path_id=path_id, path_id_namespace=path_id_namespace, is_insert=is_insert, is_update=is_update, view_rptr=view_rptr, ctx=scopectx)) if is_insert: explicit_ptrs = {ptrcls.get_shortname(ctx.env.schema).name for ptrcls in pointers} scls_pointers = stype.get_pointers(ctx.env.schema) for pn, ptrcls in scls_pointers.items(ctx.env.schema): if (not ptrcls.get_default(ctx.env.schema) or pn in explicit_ptrs or ptrcls.is_pure_computable(ctx.env.schema)): continue ptrcls_sn = ptrcls.get_shortname(ctx.env.schema) default_ql = qlast.ShapeElement(expr=qlast.Path(steps=[ qlast.Ptr(ptr=qlast.ObjectRef(name=ptrcls_sn.name, module=ptrcls_sn.module)) ])) with ctx.newscope(fenced=True) as scopectx: pointers.append(_normalize_view_ptr_expr( default_ql, view_scls, path_id=path_id, path_id_namespace=path_id_namespace, is_insert=is_insert, is_update=is_update, view_rptr=view_rptr, ctx=scopectx)) # Check if the view shape includes _only_ the link properties. # If so, we do not need to derive a new target view. lprops_only = True for ptrcls in pointers: if not ptrcls.is_link_property(ctx.env.schema): lprops_only = False break if lprops_only: view_scls = stype for ptrcls in pointers: if ptrcls.is_link_property(ctx.env.schema): source = view_rptr.derived_ptrcls else: source = view_scls if (ptrcls.get_source(ctx.env.schema) is source and isinstance(source, s_sources.Source)): # source may be an ScalarType in shapes that reference __type__, # hence the isinstance check. ctx.env.schema = source.add_pointer( ctx.env.schema, ptrcls, replace=True) if is_defining_shape: if source is None: # The nested shape is merely selecting the pointer, # so the link class has not been derived. But for # the purposes of shape tracking, we must derive it # still. The derived pointer must be treated the same # as the original, as this is not a new computable, # and both `Foo.ptr` and `Foo { ptr }` are the same path, # hence the `transparent` modifier. source = derive_ptrcls( view_rptr, target_scls=view_scls, transparent=True, ctx=ctx) ctx.class_shapes[source].append(ptrcls) if (view_rptr is not None and view_rptr.derived_ptrcls is not None and view_scls is not stype): ctx.env.schema = view_scls.set_field_value( ctx.env.schema, 'rptr', view_rptr.derived_ptrcls) return view_scls