def init_stmt( irstmt: irast.Stmt, qlstmt: qlast.Statement, *, ctx: context.ContextLevel, parent_ctx: context.ContextLevel) -> None: ctx.stmt = irstmt if ctx.toplevel_stmt is None: parent_ctx.toplevel_stmt = ctx.toplevel_stmt = irstmt parent_ctx.path_scope = ctx.path_scope = irast.new_scope_tree() else: ctx.path_scope = parent_ctx.path_scope.attach_fence() pending_own_ns = parent_ctx.pending_stmt_own_path_id_namespace if pending_own_ns: ctx.path_scope.namespaces.add(pending_own_ns) pending_full_ns = parent_ctx.pending_stmt_full_path_id_namespace if pending_full_ns: ctx.path_id_namespace += tuple(pending_full_ns) metadata = ctx.stmt_metadata.get(qlstmt) if metadata is not None and metadata.is_unnest_fence: ctx.path_scope.unnest_fence = True irstmt.parent_stmt = parent_ctx.stmt process_with_block(qlstmt, ctx=ctx, parent_ctx=parent_ctx)
def init_context( *, schema: s_schema.Schema, func: typing.Optional[s_func.Function]=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, implicit_id_in_shapes: bool=False) -> \ context.ContextLevel: stack = context.CompilerContext() ctx = stack.current if not schema.get('__derived__', None): schema, _ = s_mod.Module.create_in_schema(schema, name='__derived__') ctx.env = context.Environment(schema=schema, path_scope=irast.new_scope_tree(), schema_view_mode=schema_view_mode) 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.func = func ctx.derived_target_module = derived_target_module ctx.toplevel_result_view_name = result_view_name ctx.implicit_id_in_shapes = implicit_id_in_shapes return ctx
def fuse_scope_branch(ir_set: irast.Set, parent: irast.ScopeTreeNode, branch: irast.ScopeTreeNode, *, ctx: context.ContextLevel) -> None: if parent.path_id is None: parent.attach_subtree(branch) else: if branch.path_id is None and len(branch.children) == 1: target_branch = next(iter(branch.children)) else: target_branch = branch if parent.path_id == target_branch.path_id: new_root = irast.new_scope_tree() for child in tuple(target_branch.children): new_root.attach_child(child) parent.attach_subtree(new_root) else: parent.attach_subtree(branch)
def __init__(self, prevlevel, mode): self.mode = mode if prevlevel is None: self.schema = None self.derived_target_module = None self.aliases = compiler.AliasGenerator() self.anchors = {} self.modaliases = {} self.arguments = {} self.all_sets = [] self.stmt_metadata = {} self.completion_work = [] self.pending_cardinality = set() self.pointer_derivation_map = collections.defaultdict(list) self.source_map = {} self.view_nodes = {} self.view_sets = {} self.aliased_views = collections.ChainMap() self.schema_view_cache = {} self.expr_view_cache = {} self.shape_type_cache = {} self.class_view_overrides = {} self.clause = None self.toplevel_clause = None self.toplevel_stmt = None self.stmt = None self.path_id_namespace = tuple() self.pending_stmt_own_path_id_namespace = None self.pending_stmt_full_path_id_namespace = None self.view_map = collections.ChainMap() self.class_shapes = collections.defaultdict(list) self.path_scope = None self.path_scope_is_temp = False self.path_scope_map = {} self.scope_id_ctr = compiler.Counter() self.in_aggregate = False self.view_scls = None self.expr_exposed = False self.partial_path_prefix = None self.view_rptr = None self.toplevel_result_view_name = None self.implicit_id_in_shapes = False self.empty_result_type_hint = None else: self.schema = prevlevel.schema self.derived_target_module = prevlevel.derived_target_module self.aliases = prevlevel.aliases self.arguments = prevlevel.arguments self.all_sets = prevlevel.all_sets self.stmt_metadata = prevlevel.stmt_metadata self.completion_work = prevlevel.completion_work self.pending_cardinality = prevlevel.pending_cardinality self.pointer_derivation_map = prevlevel.pointer_derivation_map self.source_map = prevlevel.source_map self.view_nodes = prevlevel.view_nodes self.view_sets = prevlevel.view_sets self.schema_view_cache = prevlevel.schema_view_cache self.expr_view_cache = prevlevel.expr_view_cache self.shape_type_cache = prevlevel.shape_type_cache self.path_id_namespace = prevlevel.path_id_namespace self.pending_stmt_own_path_id_namespace = \ prevlevel.pending_stmt_own_path_id_namespace self.pending_stmt_full_path_id_namespace = \ prevlevel.pending_stmt_full_path_id_namespace self.view_map = prevlevel.view_map self.class_shapes = prevlevel.class_shapes self.path_scope = prevlevel.path_scope self.path_scope_is_temp = prevlevel.path_scope_is_temp self.path_scope_map = prevlevel.path_scope_map self.scope_id_ctr = prevlevel.scope_id_ctr self.view_scls = prevlevel.view_scls self.expr_exposed = prevlevel.expr_exposed self.toplevel_clause = prevlevel.toplevel_clause self.toplevel_stmt = prevlevel.toplevel_stmt self.implicit_id_in_shapes = prevlevel.implicit_id_in_shapes self.empty_result_type_hint = prevlevel.empty_result_type_hint if mode == ContextSwitchMode.SUBQUERY: self.anchors = prevlevel.anchors.copy() self.modaliases = prevlevel.modaliases.copy() self.aliased_views = prevlevel.aliased_views.new_child() self.class_view_overrides = \ prevlevel.class_view_overrides.copy() self.pending_stmt_own_path_id_namespace = None self.pending_stmt_full_path_id_namespace = None self.view_rptr = None self.view_scls = None self.clause = None self.stmt = None self.in_aggregate = False self.partial_path_prefix = None self.view_rptr = None self.toplevel_result_view_name = None elif mode == ContextSwitchMode.DETACHED: self.anchors = prevlevel.anchors.copy() self.modaliases = prevlevel.modaliases.copy() self.aliased_views = collections.ChainMap() self.class_view_overrides = {} self.expr_exposed = False self.source_map = {} self.view_nodes = {} self.view_sets = {} self.path_id_namespace = (self.aliases.get('ns'), ) self.pending_stmt_own_path_id_namespace = None self.pending_stmt_full_path_id_namespace = None self.view_rptr = None self.view_scls = None self.clause = None self.stmt = None self.in_aggregate = False self.partial_path_prefix = None self.view_rptr = None self.toplevel_result_view_name = None else: self.anchors = prevlevel.anchors self.modaliases = prevlevel.modaliases self.aliased_views = prevlevel.aliased_views self.class_view_overrides = prevlevel.class_view_overrides self.clause = prevlevel.clause self.stmt = prevlevel.stmt self.in_aggregate = prevlevel.in_aggregate self.partial_path_prefix = prevlevel.partial_path_prefix self.view_rptr = prevlevel.view_rptr self.toplevel_result_view_name = \ prevlevel.toplevel_result_view_name if mode in { ContextSwitchMode.NEWFENCE_TEMP, ContextSwitchMode.NEWSCOPE_TEMP }: if prevlevel.path_scope is None: prevlevel.path_scope = irast.new_scope_tree() self.path_scope = prevlevel.path_scope.copy() self.path_scope_is_temp = True if mode in { ContextSwitchMode.NEWFENCE, ContextSwitchMode.NEWFENCE_TEMP }: if prevlevel.path_scope is None: prevlevel.path_scope = irast.new_scope_tree() self.path_scope = prevlevel.path_scope.attach_fence() if mode in { ContextSwitchMode.NEWSCOPE, ContextSwitchMode.NEWSCOPE_TEMP }: if prevlevel.path_scope is None: prevlevel.path_scope = irast.new_scope_tree() self.path_scope = prevlevel.path_scope.attach_branch()
def _normalize_ptr_default(self, expr, source, ptr, ptrdecl): module_aliases = {None: source.name.module} ir, _, expr_text = edgeql.utils.normalize_tree( expr, self._schema, modaliases=module_aliases, anchors={qlast.Source: source}) self_set = ast.find_children( ir, lambda n: getattr(n, 'anchor', None) == qlast.Source, terminate_early=True) try: expr_type = ir_utils.infer_type(ir, self._schema) except edgeql.EdgeQLError as e: raise s_err.SchemaError( 'could not determine the result type of the default ' 'expression on {!s}.{!s}'.format(source.name, ptr.shortname), context=expr.context) from e ptr.default = expr_text ptr.normalize_defaults() if ptr.is_pure_computable(): # Pure computable without explicit target. # Fixup pointer target and target property. ptr.target = expr_type if isinstance(ptr, s_links.Link): if not isinstance(expr_type, s_objtypes.ObjectType): raise s_err.SchemaDefinitionError( f'invalid link target, expected object type, got ' f'{expr_type.__class__.__name__}', context=ptrdecl.expr.context) else: if not isinstance(expr_type, (s_scalars.ScalarType, s_types.Collection)): raise s_err.SchemaDefinitionError( f'invalid property target, expected primitive type, ' f'got {expr_type.__class__.__name__}', context=ptrdecl.expr.context) if isinstance(ptr, s_links.Link): pname = s_name.Name('std::target') tgt_prop = ptr.pointers[pname] tgt_prop.target = expr_type cardinality = self._get_literal_attribute(ptrdecl, 'cardinality') if cardinality is not None: raise s_err.SchemaError( 'computable links must not define explicit cardinality', context=expr.context) scope_tree_root = ir_ast.new_scope_tree() if self_set is not None: scope_tree_root.attach_path(self_set.path_id) scope_tree = scope_tree_root.attach_fence() else: scope_tree = scope_tree_root cardinality = \ ir_inference.infer_cardinality(ir, scope_tree, self._schema) if cardinality == qlast.Cardinality.MANY: ptr.cardinality = s_pointers.PointerCardinality.ManyToMany else: ptr.cardinality = s_pointers.PointerCardinality.ManyToOne if (not isinstance(expr_type, s_types.Type) or (ptr.target is not None and not expr_type.issubclass(ptr.target))): raise s_err.SchemaError( 'default value query must yield a single result of ' 'type {!r}'.format(ptr.target.name), context=expr.context) if not isinstance(ptr.target, s_scalars.ScalarType): many_mapping = (s_pointers.PointerCardinality.ManyToOne, s_pointers.PointerCardinality.ManyToMany) if ptr.cardinality not in many_mapping: raise s_err.SchemaError( 'type links with query defaults ' 'must have either a "*1" or "**" cardinality', context=expr.context)
def _cmd_tree_from_ast(cls, astnode, context, schema): from edb.lang.edgeql import utils as ql_utils from edb.lang.ir import ast as irast from edb.lang.ir import inference as ir_inference from edb.lang.ir import utils as ir_utils from . import objtypes as s_objtypes cmd = super()._cmd_tree_from_ast(astnode, context, schema) if isinstance(astnode, qlast.CreateConcreteLink): cmd.add( sd.AlterObjectProperty(property='required', new_value=astnode.is_required)) # "source" attribute is set automatically as a refdict back-attr parent_ctx = context.get(LinkSourceCommandContext) source_name = parent_ctx.op.classname target_type = None if len(astnode.targets) > 1: cmd.add( sd.AlterObjectProperty( property='spectargets', new_value=so.ObjectList([ utils.ast_to_typeref(t, modaliases=context.modaliases, schema=schema) for t in astnode.targets ]))) target_name = sources.Source.gen_virt_parent_name( (sn.Name(module=t.maintype.module, name=t.maintype.name) for t in astnode.targets), module=source_name.module) target = so.ObjectRef(classname=target_name) create_virt_parent = s_objtypes.CreateObjectType( classname=target_name, metaclass=s_objtypes.ObjectType) create_virt_parent.update( (sd.AlterObjectProperty( property='bases', new_value=so.ObjectList([ so.ObjectRef( classname=sn.Name(module='std', name='Object')) ])), sd.AlterObjectProperty(property='name', new_value=target_name), sd.AlterObjectProperty(property='is_virtual', new_value=True))) alter_db_ctx = context.get(s_db.DatabaseCommandContext) for cc in alter_db_ctx.op.get_subcommands( type=s_objtypes.CreateObjectType): if cc.classname == create_virt_parent.classname: break else: alter_db_ctx.op.add(create_virt_parent) else: target_expr = astnode.targets[0] if isinstance(target_expr, qlast.TypeName): target = utils.ast_to_typeref( target_expr, modaliases=context.modaliases, schema=schema) else: # computable source = schema.get(source_name, default=None) if source is None: raise s_err.SchemaDefinitionError( f'cannot define link computables in CREATE TYPE', hint='Perform a CREATE TYPE without the link ' 'followed by ALTER TYPE defining the ' 'computable', context=target_expr.context) ir, _, target_expr = ql_utils.normalize_tree( target_expr, schema, anchors={qlast.Source: source}) try: target_type = ir_utils.infer_type(ir, schema) except edgeql.EdgeQLError as e: raise s_err.SchemaDefinitionError( 'could not determine the result type of ' 'computable expression', context=target_expr.context) from e target = utils.reduce_to_typeref(target_type) cmd.add( sd.AlterObjectProperty(property='default', new_value=target_expr)) cmd.add( sd.AlterObjectProperty(property='computable', new_value=True)) scope_tree = irast.new_scope_tree() scope_tree.attach_path(irast.PathId(source)) cardinality = ir_inference.infer_cardinality( ir, scope_tree.attach_fence(), schema) if cardinality == qlast.Cardinality.ONE: link_card = pointers.PointerCardinality.ManyToOne else: link_card = pointers.PointerCardinality.ManyToMany cmd.add( sd.AlterObjectProperty(property='cardinality', new_value=link_card)) if (isinstance(target, so.ObjectRef) and target.classname == source_name): # Special case for loop links. Since the target # is the same as the source, we know it's a proper # type. pass else: if target_type is None: target_type = utils.resolve_typeref(target, schema=schema) if not isinstance(target_type, s_objtypes.ObjectType): raise s_err.SchemaDefinitionError( f'invalid link target, expected object type, got ' f'{target_type.__class__.__name__}', context=astnode.targets[0].context) cmd.add(sd.AlterObjectProperty(property='target', new_value=target)) base_prop_name = sn.Name('std::source') s_name = lproperties.Property.get_specialized_name( base_prop_name, cmd.classname) src_prop_name = sn.Name(name=s_name, module=cmd.classname.module) src_prop = lproperties.CreateProperty( classname=src_prop_name, metaclass=lproperties.Property) src_prop.update(( sd.AlterObjectProperty(property='name', new_value=src_prop_name), sd.AlterObjectProperty( property='bases', new_value=[so.ObjectRef(classname=base_prop_name)]), sd.AlterObjectProperty( property='source', new_value=so.ObjectRef(classname=cmd.classname)), sd.AlterObjectProperty( property='target', new_value=so.ObjectRef(classname=source_name)), sd.AlterObjectProperty(property='required', new_value=True), sd.AlterObjectProperty(property='readonly', new_value=True), )) cmd.add(src_prop) base_prop_name = sn.Name('std::target') s_name = lproperties.Property.get_specialized_name( base_prop_name, cmd.classname) tgt_prop_name = sn.Name(name=s_name, module=cmd.classname.module) tgt_prop = lproperties.CreateProperty( classname=tgt_prop_name, metaclass=lproperties.Property) tgt_prop.update(( sd.AlterObjectProperty(property='name', new_value=tgt_prop_name), sd.AlterObjectProperty( property='bases', new_value=[so.ObjectRef(classname=base_prop_name)]), sd.AlterObjectProperty( property='source', new_value=so.ObjectRef(classname=cmd.classname)), sd.AlterObjectProperty(property='target', new_value=target), sd.AlterObjectProperty(property='required', new_value=False), sd.AlterObjectProperty(property='readonly', new_value=True), )) cmd.add(tgt_prop) cls._parse_default(cmd) return cmd