def init_context( *, schema: s_schema.Schema, func_params: typing.Optional[s_func.FuncParameterList]=None, parent_object_type: typing.Optional[s_obj.ObjectMeta]=None, modaliases: typing.Optional[typing.Dict[str, str]]=None, anchors: typing.Optional[typing.Dict[str, s_obj.Object]]=None, singletons: typing.Optional[typing.Iterable[s_types.Type]]=None, security_context: typing.Optional[str]=None, derived_target_module: typing.Optional[str]=None, result_view_name: typing.Optional[str]=None, schema_view_mode: bool=False, disable_constant_folding: bool=False, allow_generic_type_output: bool=False, allow_abstract_operators: bool=False, implicit_id_in_shapes: bool=False, implicit_tid_in_shapes: bool=False, json_parameters: bool=False, session_mode: bool=False) -> \ context.ContextLevel: stack = context.CompilerContext() ctx = stack.current if not schema.get_global(s_mod.Module, '__derived__', None): schema, _ = s_mod.Module.create_in_schema(schema, name='__derived__') ctx.env = context.Environment( schema=schema, path_scope=irast.new_scope_tree(), constant_folding=not disable_constant_folding, func_params=func_params, parent_object_type=parent_object_type, schema_view_mode=schema_view_mode, json_parameters=json_parameters, session_mode=session_mode, allow_abstract_operators=allow_abstract_operators, allow_generic_type_output=allow_generic_type_output) if singletons: # The caller wants us to treat these type references # as singletons for the purposes of the overall expression # cardinality inference, so we set up the scope tree in # the necessary fashion. for singleton in singletons: path_id = pathctx.get_path_id(singleton, ctx=ctx) ctx.env.path_scope.attach_path(path_id) ctx.path_scope = ctx.env.path_scope.attach_fence() if modaliases: ctx.modaliases.update(modaliases) if anchors: with ctx.newscope(fenced=True) as subctx: populate_anchors(anchors, ctx=subctx) ctx.derived_target_module = derived_target_module ctx.toplevel_result_view_name = result_view_name ctx.implicit_id_in_shapes = implicit_id_in_shapes ctx.implicit_tid_in_shapes = implicit_tid_in_shapes return ctx
def _classbases_from_ast( cls, schema: s_schema.Schema, astnode: qlast.ObjectDDL, context: sd.CommandContext, ) -> so.ObjectList[Role]: result = [] for b in getattr(astnode, 'bases', None) or []: result.append(schema.get_global(Role, b.maintype.name)) return so.ObjectList.create(schema, result)
def init_context( *, schema: s_schema.Schema, options: coptions.CompilerOptions, ) -> context.ContextLevel: if not schema.get_global(s_mod.Module, '__derived__', None): schema, _ = s_mod.Module.create_in_schema( schema, name=s_name.UnqualName('__derived__'), ) env = context.Environment( schema=schema, options=options, alias_result_view_name=options.result_view_name, ) ctx = context.ContextLevel(None, context.ContextSwitchMode.NEW, env=env) _ = context.CompilerContext(initial=ctx) if options.singletons: # The caller wants us to treat these type and pointer # references as singletons for the purposes of the overall # expression cardinality inference, so we set up the scope # tree in the necessary fashion. for singleton in options.singletons: path_id = compile_anchor('__', singleton, ctx=ctx).path_id ctx.env.path_scope.attach_path(path_id, context=None) ctx.env.singletons.append(path_id) ctx.modaliases.update(options.modaliases) if options.anchors: with ctx.newscope(fenced=True) as subctx: populate_anchors(options.anchors, ctx=subctx) if options.path_prefix_anchor is not None: path_prefix = options.anchors[options.path_prefix_anchor] ctx.partial_path_prefix = compile_anchor(options.path_prefix_anchor, path_prefix, ctx=ctx) ctx.partial_path_prefix.anchor = options.path_prefix_anchor ctx.partial_path_prefix.show_as_anchor = options.path_prefix_anchor ctx.derived_target_module = options.derived_target_module ctx.toplevel_result_view_name = options.result_view_name ctx.implicit_id_in_shapes = options.implicit_id_in_shapes ctx.implicit_tid_in_shapes = options.implicit_tid_in_shapes ctx.implicit_tname_in_shapes = options.implicit_tname_in_shapes ctx.implicit_limit = options.implicit_limit ctx.expr_exposed = context.Exposure.EXPOSED return ctx
def init_context( *, schema: s_schema.Schema, options: coptions.CompilerOptions, ) -> context.ContextLevel: if not schema.get_global(s_mod.Module, '__derived__', None): schema, _ = s_mod.Module.create_in_schema(schema, name='__derived__') env = context.Environment( schema=schema, path_scope=irast.new_scope_tree(), options=options, ) ctx = context.ContextLevel(None, context.ContextSwitchMode.NEW, env=env) _ = context.CompilerContext(initial=ctx) if options.singletons: # The caller wants us to treat these type references # as singletons for the purposes of the overall expression # cardinality inference, so we set up the scope tree in # the necessary fashion. for singleton in options.singletons: path_id = pathctx.get_path_id(singleton, ctx=ctx) ctx.env.path_scope.attach_path(path_id, context=None) ctx.path_scope = ctx.env.path_scope.attach_fence() ctx.modaliases.update(options.modaliases) if options.anchors: with ctx.newscope(fenced=True) as subctx: populate_anchors(options.anchors, ctx=subctx) if options.path_prefix_anchor is not None: path_prefix = options.anchors[options.path_prefix_anchor] assert isinstance(path_prefix, s_types.Type) ctx.partial_path_prefix = setgen.class_set(path_prefix, ctx=ctx) ctx.partial_path_prefix.anchor = options.path_prefix_anchor ctx.partial_path_prefix.show_as_anchor = options.path_prefix_anchor ctx.derived_target_module = options.derived_target_module ctx.toplevel_result_view_name = options.result_view_name ctx.implicit_id_in_shapes = options.implicit_id_in_shapes ctx.implicit_tid_in_shapes = options.implicit_tid_in_shapes ctx.implicit_limit = options.implicit_limit return ctx
def ptrref_from_ptrcls( *, schema: s_schema.Schema, ptrcls: s_pointers.PointerLike, direction: s_pointers.PointerDirection = ( s_pointers.PointerDirection.Outbound), cache: Optional[Dict[PtrRefCacheKey, irast.BasePointerRef]] = None, typeref_cache: Optional[Dict[TypeRefCacheKey, irast.TypeRef]] = None, include_descendants: bool = False, ) -> irast.BasePointerRef: """Return an IR pointer descriptor for a given schema pointer. An IR PointerRef is an object that fully describes a schema pointer for the purposes of query compilation. Args: schema: A schema instance, in which the type *t* is defined. ptrcls: A :class:`schema.pointers.Pointer` instance for which to return the PointerRef. direction: The direction of the pointer in the path expression. Returns: An instance of a subclass of :class:`ir.ast.BasePointerRef` corresponding to the given schema pointer. """ if cache is not None: cached = cache.get((ptrcls, direction, include_descendants)) if cached is not None: return cached kwargs: Dict[str, Any] = {} ircls: Type[irast.BasePointerRef] source_ref: Optional[irast.TypeRef] target_ref: Optional[irast.TypeRef] out_source: Optional[irast.TypeRef] if isinstance(ptrcls, irast.TupleIndirectionLink): ircls = irast.TupleIndirectionPointerRef elif isinstance(ptrcls, irast.TypeIntersectionLink): ircls = irast.TypeIntersectionPointerRef kwargs['optional'] = ptrcls.is_optional() kwargs['is_empty'] = ptrcls.is_empty() kwargs['is_subtype'] = ptrcls.is_subtype() kwargs['rptr_specialization'] = ptrcls.get_rptr_specialization() elif isinstance(ptrcls, s_pointers.Pointer): ircls = irast.PointerRef kwargs['id'] = ptrcls.id name = ptrcls.get_name(schema) kwargs['module_id'] = schema.get_global( s_mod.Module, name.module).id else: raise AssertionError(f'unexpected pointer class: {ptrcls}') target = ptrcls.get_far_endpoint(schema, direction) if target is not None and not isinstance(target, irast.TypeRef): assert isinstance(target, s_types.Type) target_ref = type_to_typeref(schema, target, cache=typeref_cache) else: target_ref = target source = ptrcls.get_near_endpoint(schema, direction) source_ptr: Optional[irast.BasePointerRef] if (isinstance(ptrcls, s_props.Property) and isinstance(source, s_links.Link)): source_ptr = ptrref_from_ptrcls( ptrcls=source, direction=direction, schema=schema, cache=cache, typeref_cache=typeref_cache, ) source_ref = None else: if source is not None and not isinstance(source, irast.TypeRef): assert isinstance(source, s_types.Type) source_ref = type_to_typeref(schema, source, cache=typeref_cache) else: source_ref = source source_ptr = None if direction is s_pointers.PointerDirection.Inbound: out_source = target_ref out_target = source_ref else: out_source = source_ref out_target = target_ref out_cardinality, dir_cardinality = cardinality_from_ptrcls( schema, ptrcls, direction=direction) material_ptrcls = ptrcls.material_type(schema) material_ptr: Optional[irast.BasePointerRef] if material_ptrcls is not None and material_ptrcls is not ptrcls: material_ptr = ptrref_from_ptrcls( ptrcls=material_ptrcls, direction=direction, schema=schema, cache=cache, typeref_cache=typeref_cache, include_descendants=include_descendants, ) else: material_ptr = None union_components: Set[irast.BasePointerRef] = set() union_of = ptrcls.get_union_of(schema) union_is_concrete = False if union_of: union_ptrs = set() for component in union_of.objects(schema): assert isinstance(component, s_pointers.Pointer) material_comp = component.material_type(schema) union_ptrs.add(material_comp) non_overlapping, union_is_concrete = s_utils.get_non_overlapping_union( schema, union_ptrs, ) union_components = { ptrref_from_ptrcls( ptrcls=p, direction=direction, schema=schema, cache=cache, typeref_cache=typeref_cache, ) for p in non_overlapping } std_parent_name = None for ancestor in ptrcls.get_ancestors(schema).objects(schema): ancestor_name = ancestor.get_name(schema) if ancestor_name.module == 'std' and ancestor.generic(schema): std_parent_name = ancestor_name break is_derived = ptrcls.get_is_derived(schema) base_ptr: Optional[irast.BasePointerRef] if is_derived: base_ptrcls = ptrcls.get_bases(schema).first(schema) top_ptr_name = type(base_ptrcls).get_default_base_name() if base_ptrcls.get_name(schema) != top_ptr_name: base_ptr = ptrref_from_ptrcls( ptrcls=base_ptrcls, direction=direction, schema=schema, cache=cache, typeref_cache=typeref_cache, ) else: base_ptr = None else: base_ptr = None if ( material_ptr is None and include_descendants and isinstance(ptrcls, s_pointers.Pointer) ): descendants = frozenset( ptrref_from_ptrcls( ptrcls=child, direction=direction, schema=schema, cache=cache, typeref_cache=typeref_cache, ) for child in ptrcls.children(schema) if not child.get_is_derived(schema) ) else: descendants = frozenset() kwargs.update(dict( out_source=out_source, out_target=out_target, name=ptrcls.get_name(schema), shortname=ptrcls.get_shortname(schema), path_id_name=ptrcls.get_path_id_name(schema), std_parent_name=std_parent_name, direction=direction, source_ptr=source_ptr, base_ptr=base_ptr, material_ptr=material_ptr, descendants=descendants, is_derived=ptrcls.get_is_derived(schema), is_computable=ptrcls.get_computable(schema), union_components=union_components, union_is_concrete=union_is_concrete, has_properties=ptrcls.has_user_defined_properties(schema), dir_cardinality=dir_cardinality, out_cardinality=out_cardinality, )) ptrref = ircls(**kwargs) if cache is not None: cache[ptrcls, direction, include_descendants] = ptrref return ptrref
def type_to_typeref( schema: s_schema.Schema, t: s_types.Type, *, cache: Optional[Dict[TypeRefCacheKey, irast.TypeRef]] = None, typename: Optional[s_name.Name] = None, include_descendants: bool = False, _name: Optional[str] = None, ) -> irast.TypeRef: """Return an instance of :class:`ir.ast.TypeRef` for a given type. An IR TypeRef is an object that fully describes a schema type for the purposes of query compilation. Args: schema: A schema instance, in which the type *t* is defined. t: A schema type instance. cache: Optional mapping from (type UUID, typename) to cached IR TypeRefs. typename: Optional name hint to use for the type in the returned TypeRef. If ``None``, the type name is used. include_descendants: Whether to include the description of all material type descendants of *t*. _name: Optional subtype element name if this type is a collection within a Tuple, Returns: A ``TypeRef`` instance corresponding to the given schema type. """ result: irast.TypeRef material_type: s_types.Type if cache is not None and typename is None: cached_result = cache.get((t.id, include_descendants)) if cached_result is not None: # If the schema changed due to an ongoing compilation, the name # hint might be outdated. if cached_result.name_hint == t.get_name(schema): return cached_result if t.is_anytuple(schema): result = irast.AnyTupleRef( id=t.id, name_hint=typename or t.get_name(schema), ) elif t.is_any(schema): result = irast.AnyTypeRef( id=t.id, name_hint=typename or t.get_name(schema), ) elif not isinstance(t, s_types.Collection): assert isinstance(t, s_types.InheritingType) union_of = t.get_union_of(schema) if union_of: non_overlapping, union_is_concrete = ( s_utils.get_non_overlapping_union( schema, union_of.objects(schema), ) ) union = frozenset( type_to_typeref(schema, c, cache=cache) for c in non_overlapping ) else: union_is_concrete = False union = frozenset() intersection_of = t.get_intersection_of(schema) if intersection_of: intersection = frozenset( type_to_typeref(schema, c, cache=cache) for c in intersection_of.objects(schema) ) else: intersection = frozenset() schema, material_type = t.material_type(schema) material_typeref: Optional[irast.TypeRef] if material_type is not t: material_typeref = type_to_typeref( schema, material_type, include_descendants=include_descendants, cache=cache, ) else: material_typeref = None if (isinstance(material_type, s_scalars.ScalarType) and not material_type.get_is_abstract(schema)): base_type = material_type.get_topmost_concrete_base(schema) if base_type is material_type: base_typeref = None else: assert isinstance(base_type, s_types.Type) base_typeref = type_to_typeref( schema, base_type, cache=cache ) else: base_typeref = None tname = t.get_name(schema) if typename is not None: name = typename else: name = tname module = schema.get_global(s_mod.Module, tname.module) common_parent_ref: Optional[irast.TypeRef] if union_of: common_parent = s_utils.get_class_nearest_common_ancestor( schema, union_of.objects(schema)) assert isinstance(common_parent, s_types.Type) common_parent_ref = type_to_typeref( schema, common_parent, cache=cache ) else: common_parent_ref = None descendants: Optional[FrozenSet[irast.TypeRef]] if material_typeref is None and include_descendants: descendants = frozenset( type_to_typeref( schema, child, cache=cache, ) for child in t.children(schema) if not child.get_is_derived(schema) ) else: descendants = None result = irast.TypeRef( id=t.id, module_id=module.id, name_hint=name, material_type=material_typeref, base_type=base_typeref, descendants=descendants, union=union, union_is_concrete=union_is_concrete, intersection=intersection, common_parent=common_parent_ref, element_name=_name, is_scalar=t.is_scalar(), is_abstract=t.get_is_abstract(schema), is_view=t.is_view(schema), is_opaque_union=t.get_is_opaque_union(schema), ) elif isinstance(t, s_types.Tuple) and t.is_named(schema): schema, material_type = t.material_type(schema) if material_type is not t: material_typeref = type_to_typeref( schema, material_type, cache=cache ) else: material_typeref = None result = irast.TypeRef( id=t.id, name_hint=typename or t.get_name(schema), material_type=material_typeref, element_name=_name, collection=t.schema_name, in_schema=t.get_is_persistent(schema), subtypes=tuple( type_to_typeref(schema, st, _name=sn) # note: no cache for sn, st in t.iter_subtypes(schema) ) ) else: schema, material_type = t.material_type(schema) if material_type is not t: material_typeref = type_to_typeref( schema, material_type, cache=cache ) else: material_typeref = None result = irast.TypeRef( id=t.id, name_hint=typename or t.get_name(schema), material_type=material_typeref, element_name=_name, collection=t.schema_name, in_schema=t.get_is_persistent(schema), subtypes=tuple( type_to_typeref(schema, st, cache=cache) for st in t.get_subtypes(schema) ) ) if cache is not None and typename is None and _name is None: # Note: there is no cache for `_name` variants since they are only used # for Tuple subtypes and thus they will be cached on the outer level # anyway. # There's also no variant for types with custom typenames since they # proved to have a very low hit rate. # This way we save on the size of the key tuple. cache[t.id, include_descendants] = result return result
def init_context( *, schema: s_schema.Schema, func_params: Optional[s_func.ParameterLikeList]=None, parent_object_type: Optional[s_obj.ObjectMeta]=None, modaliases: Optional[Mapping[Optional[str], str]]=None, anchors: Optional[ Mapping[ Union[str, qlast.SpecialAnchorT], Union[s_obj.Object, irast.Base], ], ]=None, singletons: Optional[Iterable[s_types.Type]]=None, security_context: Optional[str]=None, derived_target_module: Optional[str]=None, result_view_name: Optional[s_name.SchemaName]=None, schema_view_mode: bool=False, disable_constant_folding: bool=False, allow_generic_type_output: bool=False, implicit_limit: int=0, implicit_id_in_shapes: bool=False, implicit_tid_in_shapes: bool=False, json_parameters: bool=False, session_mode: bool=False) -> \ context.ContextLevel: if not schema.get_global(s_mod.Module, '__derived__', None): schema, _ = s_mod.Module.create_in_schema(schema, name='__derived__') env = context.Environment( schema=schema, path_scope=irast.new_scope_tree(), constant_folding=not disable_constant_folding, func_params=func_params, parent_object_type=parent_object_type, schema_view_mode=schema_view_mode, json_parameters=json_parameters, session_mode=session_mode, allow_generic_type_output=allow_generic_type_output) ctx = context.ContextLevel(None, context.ContextSwitchMode.NEW, env=env) _ = context.CompilerContext(initial=ctx) if singletons: # The caller wants us to treat these type references # as singletons for the purposes of the overall expression # cardinality inference, so we set up the scope tree in # the necessary fashion. for singleton in singletons: path_id = pathctx.get_path_id(singleton, ctx=ctx) ctx.env.path_scope.attach_path(path_id) ctx.path_scope = ctx.env.path_scope.attach_fence() if modaliases: ctx.modaliases.update(modaliases) if anchors: with ctx.newscope(fenced=True) as subctx: populate_anchors(anchors, ctx=subctx) ctx.derived_target_module = derived_target_module ctx.toplevel_result_view_name = result_view_name ctx.implicit_id_in_shapes = implicit_id_in_shapes ctx.implicit_tid_in_shapes = implicit_tid_in_shapes ctx.implicit_limit = implicit_limit return ctx
def sdl_to_ddl( schema: s_schema.Schema, documents: Mapping[str, List[qlast.DDL]], ) -> Tuple[qlast.DDLCommand, ...]: ddlgraph: DDLGraph = {} mods: List[qlast.DDLCommand] = [] ctx = LayoutTraceContext( schema, local_modules=frozenset(mod for mod in documents), ) ctx.objects[s_name.QualName('std', 'anytype')] = (schema.get_global( s_pseudo.PseudoType, 'anytype')) ctx.objects[s_name.QualName('std', 'anytuple')] = (schema.get_global( s_pseudo.PseudoType, 'anytuple')) for module_name, declarations in documents.items(): ctx.set_module(module_name) for decl_ast in declarations: if isinstance(decl_ast, qlast.CreateObject): _, fq_name = ctx.get_fq_name(decl_ast) if isinstance(decl_ast, qlast.CreateObjectType): ctx.objects[fq_name] = qltracer.ObjectType(fq_name) elif isinstance(decl_ast, qlast.CreateAlias): ctx.objects[fq_name] = qltracer.Alias(fq_name) elif isinstance(decl_ast, qlast.CreateScalarType): ctx.objects[fq_name] = qltracer.ScalarType(fq_name) elif isinstance(decl_ast, qlast.CreateLink): ctx.objects[fq_name] = qltracer.Link(fq_name, source=None, target=None) elif isinstance(decl_ast, qlast.CreateProperty): ctx.objects[fq_name] = qltracer.Property(fq_name, source=None, target=None) elif isinstance(decl_ast, qlast.CreateFunction): ctx.objects[fq_name] = qltracer.Function(fq_name) elif isinstance(decl_ast, qlast.CreateConstraint): ctx.objects[fq_name] = qltracer.Constraint(fq_name) elif isinstance(decl_ast, qlast.CreateAnnotation): ctx.objects[fq_name] = qltracer.Annotation(fq_name) elif isinstance(decl_ast, qlast.CreateGlobal): ctx.objects[fq_name] = qltracer.Global(fq_name) else: raise AssertionError( f'unexpected SDL declaration: {decl_ast}') for module_name, declarations in documents.items(): ctx.set_module(module_name) for decl_ast in declarations: trace_layout(decl_ast, ctx=ctx) # compute the ancestors graph for obj_name in ctx.parents.keys(): ctx.ancestors[obj_name] = get_ancestors(obj_name, ctx.ancestors, ctx.parents) topological.normalize( ctx.inh_graph, merger=_graph_merge_cb, # type: ignore schema=schema, ) tracectx = DepTraceContext(schema, ddlgraph, ctx.objects, ctx.parents, ctx.ancestors, ctx.defdeps, ctx.constraints) for module_name, declarations in documents.items(): tracectx.set_module(module_name) # module needs to be created regardless of whether its # contents are empty or not mods.append(qlast.CreateModule(name=qlast.ObjectRef(name=module_name))) for decl_ast in declarations: trace_dependencies(decl_ast, ctx=tracectx) # Before sorting normalize all ordering, to make sure that errors # are consistent. for ddlentry in ddlgraph.values(): ddlentry.deps = OrderedSet(sorted(ddlentry.deps)) ddlentry.weak_deps = OrderedSet(sorted(ddlentry.weak_deps)) try: ordered = topological.sort(ddlgraph, allow_unresolved=False) except topological.CycleError as e: assert isinstance(e.item, s_name.QualName) node = tracectx.ddlgraph[e.item].item item_vn = get_verbosename_from_fqname(e.item, tracectx) if e.path is not None and len(e.path): # Recursion involving more than one schema object. rec_vn = get_verbosename_from_fqname(e.path[-1], tracectx) msg = (f'definition dependency cycle between {rec_vn} ' f'and {item_vn}') else: # A single schema object with a recursive definition. msg = f'{item_vn} is defined recursively' raise errors.InvalidDefinitionError(msg, context=node.context) from e return tuple(mods) + tuple(ordered)