def declare_view_from_schema( viewcls: s_obj.Object, *, ctx: context.ContextLevel) -> irast.Set: vc = ctx.env.schema_view_cache.get(viewcls) if vc is not None: return vc with ctx.detached() as subctx: subctx.expr_exposed = False view_expr = qlparser.parse(viewcls.get_expr(ctx.env.schema).text) viewcls_name = viewcls.get_name(ctx.env.schema) view_set = declare_view(view_expr, alias=viewcls_name, fully_detached=True, ctx=subctx) # The view path id _itself_ should not be in the nested namespace. view_set.path_id = view_set.path_id.replace_namespace( ctx.path_id_namespace) vc = subctx.aliased_views[viewcls_name] ctx.env.schema_view_cache[viewcls] = vc ctx.source_map.update(subctx.source_map) ctx.aliased_views[viewcls_name] = subctx.aliased_views[viewcls_name] ctx.view_nodes[vc.get_name(ctx.env.schema)] = vc ctx.view_sets[vc] = subctx.view_sets[vc] return vc
def type_to_ql_typeref(t: s_obj.Object, *, _name=None, ctx: context.ContextLevel) -> qlast.TypeName: if not isinstance(t, s_abc.Collection): result = qlast.TypeName(name=_name, maintype=qlast.ObjectRef( module=t.get_name(ctx.env.schema).module, name=t.get_name(ctx.env.schema).name)) elif isinstance(t, s_abc.Tuple) and t.named: result = qlast.TypeName( name=_name, maintype=qlast.ObjectRef(name=t.schema_name), subtypes=[ type_to_ql_typeref(st, _name=sn, ctx=ctx) for sn, st in t.iter_subtypes(ctx.env.schema) ]) else: result = qlast.TypeName(name=_name, maintype=qlast.ObjectRef(name=t.schema_name), subtypes=[ type_to_ql_typeref(st, ctx=ctx) for st in t.get_subtypes(ctx.env.schema) ]) return result
def pg_type_from_object(schema: s_schema.Schema, obj: s_obj.Object, persistent_tuples: bool = False) -> Tuple[str, ...]: if isinstance(obj, s_scalars.ScalarType): return pg_type_from_scalar(schema, obj) elif obj.is_type() and obj.is_anytuple(schema): return ('record', ) elif isinstance(obj, s_abc.Tuple): if persistent_tuples: return common.get_tuple_backend_name(obj.id, catenate=False) else: return ('record', ) elif isinstance(obj, s_abc.Array): if obj.is_polymorphic(schema): return ('anyarray', ) else: tp = pg_type_from_object(schema, obj.get_subtypes(schema)[0], persistent_tuples=persistent_tuples) return pg_type_array(tp) elif isinstance(obj, s_objtypes.ObjectType): return ('uuid', ) elif obj.is_type() and obj.is_any(schema): return ('anyelement', ) else: raise ValueError(f'could not determine PG type for {obj!r}')
def derive_view_name( stype: s_obj.Object, derived_name_quals: typing.Optional[typing.Sequence[str]]=(), derived_name_base: typing.Optional[str]=None, *, ctx: context.ContextLevel) -> sn.Name: if not derived_name_quals: derived_name_quals = (ctx.aliases.get('view'),) if not derived_name_base: derived_name_base = stype.get_shortname(ctx.env.schema) if ctx.derived_target_module: derived_name_module = ctx.derived_target_module else: derived_name_module = '__derived__' derived_sname = sn.get_specialized_name( derived_name_base, *derived_name_quals) return sn.SchemaName(module=derived_name_module, name=derived_sname)
def type_to_ql_typeref(t: s_obj.Object, *, _name=None, schema: s_schema.Schema) -> qlast.TypeName: if t.is_any(): result = qlast.TypeName(name=_name, maintype=qlast.AnyType()) elif t.is_anytuple(): result = qlast.TypeName(name=_name, maintype=qlast.AnyTuple()) elif not isinstance(t, s_abc.Collection): result = qlast.TypeName( name=_name, maintype=qlast.ObjectRef( module=t.get_name(schema).module, name=t.get_name(schema).name ) ) elif isinstance(t, s_abc.Tuple) and t.named: result = qlast.TypeName( name=_name, maintype=qlast.ObjectRef( name=t.schema_name ), subtypes=[ type_to_ql_typeref(st, _name=sn, schema=schema) for sn, st in t.iter_subtypes(schema) ] ) else: result = qlast.TypeName( name=_name, maintype=qlast.ObjectRef( name=t.schema_name ), subtypes=[ type_to_ql_typeref(st, schema=schema) for st in t.get_subtypes(schema) ] ) return result
def resolve_ptr( near_endpoint: s_obj.Object, pointer_name: str, *, upcoming_intersections: Sequence[s_types.Type] = (), far_endpoints: Iterable[s_obj.Object] = (), direction: s_pointers.PointerDirection = ( s_pointers.PointerDirection.Outbound), source_context: Optional[parsing.ParserContext] = None, track_ref: Optional[Union[qlast.Base, Literal[False]]], ctx: context.ContextLevel, ) -> s_pointers.Pointer: if not isinstance(near_endpoint, s_sources.Source): # Reference to a property on non-object msg = 'invalid property reference on a primitive type expression' raise errors.InvalidReferenceError(msg, context=source_context) ptr: Optional[s_pointers.Pointer] = None if direction is s_pointers.PointerDirection.Outbound: ptr = near_endpoint.maybe_get_ptr( ctx.env.schema, s_name.UnqualName(pointer_name), ) if ptr is not None: ref = ptr.get_nearest_non_derived_parent(ctx.env.schema) if track_ref is not False: ctx.env.add_schema_ref(ref, track_ref) else: ptrs = near_endpoint.getrptrs(ctx.env.schema, pointer_name, sources=far_endpoints) if ptrs: if track_ref is not False: # If this reverse pointer access is followed by # intersections, we filter out any pointers that # couldn't be picked up by the intersections. This avoids # creating spurious dependencies when reverse # links are used in schemas. dep_ptrs = { ptr for ptr in ptrs if (src := ptr.get_source(ctx.env.schema)) and all( src.issubclass(ctx.env.schema, typ) or any( dsrc.issubclass(ctx.env.schema, typ) for dsrc in src.descendants(ctx.env.schema)) for typ in upcoming_intersections) } for p in dep_ptrs: ctx.env.add_schema_ref( p.get_nearest_non_derived_parent(ctx.env.schema), track_ref) opaque = not far_endpoints ctx.env.schema, ptr = s_pointers.get_or_create_union_pointer( ctx.env.schema, ptrname=s_name.UnqualName(pointer_name), source=near_endpoint, direction=direction, components=ptrs, opaque=opaque, modname=ctx.derived_target_module, ) if ptr is not None: return ptr if isinstance(near_endpoint, s_links.Link): vname = near_endpoint.get_verbosename(ctx.env.schema, with_parent=True) msg = f'{vname} has no property {pointer_name!r}' elif direction == s_pointers.PointerDirection.Outbound: msg = (f'{near_endpoint.get_verbosename(ctx.env.schema)} ' f'has no link or property {pointer_name!r}') else: nep_name = near_endpoint.get_displayname(ctx.env.schema) path = f'{nep_name}.{direction}{pointer_name}' msg = f'{path!r} does not resolve to any known path' err = errors.InvalidReferenceError(msg, context=source_context) if direction is s_pointers.PointerDirection.Outbound: near_enpoint_pointers = near_endpoint.get_pointers(ctx.env.schema) s_utils.enrich_schema_lookup_error( err, s_name.UnqualName(pointer_name), modaliases=ctx.modaliases, item_type=s_pointers.Pointer, collection=near_enpoint_pointers.objects(ctx.env.schema), schema=ctx.env.schema, ) raise err
def resolve_ptr( near_endpoint: s_obj.Object, pointer_name: str, *, far_endpoints: Iterable[s_obj.Object] = (), direction: s_pointers.PointerDirection = ( s_pointers.PointerDirection.Outbound ), source_context: Optional[parsing.ParserContext] = None, track_ref: Optional[Union[qlast.Base, Literal[False]]], ctx: context.ContextLevel, ) -> s_pointers.Pointer: if not isinstance(near_endpoint, s_sources.Source): # Reference to a property on non-object msg = 'invalid property reference on a primitive type expression' raise errors.InvalidReferenceError(msg, context=source_context) ptr: Optional[s_pointers.Pointer] = None if direction is s_pointers.PointerDirection.Outbound: ptr = near_endpoint.maybe_get_ptr( ctx.env.schema, s_name.UnqualName(pointer_name), ) if ptr is not None: ref = ptr.get_nearest_non_derived_parent(ctx.env.schema) if track_ref is not False: ctx.env.add_schema_ref(ref, track_ref) else: ptrs = near_endpoint.getrptrs(ctx.env.schema, pointer_name, sources=far_endpoints) if ptrs: if track_ref is not False: for p in ptrs: ctx.env.add_schema_ref( p.get_nearest_non_derived_parent(ctx.env.schema), track_ref) opaque = not far_endpoints ctx.env.schema, ptr = s_pointers.get_or_create_union_pointer( ctx.env.schema, ptrname=s_name.UnqualName(pointer_name), source=near_endpoint, direction=direction, components=ptrs, opaque=opaque, modname=ctx.derived_target_module, ) if ptr is not None: return ptr if isinstance(near_endpoint, s_links.Link): vname = near_endpoint.get_verbosename(ctx.env.schema, with_parent=True) msg = f'{vname} has no property {pointer_name!r}' elif direction == s_pointers.PointerDirection.Outbound: msg = (f'{near_endpoint.get_verbosename(ctx.env.schema)} ' f'has no link or property {pointer_name!r}') else: nep_name = near_endpoint.get_displayname(ctx.env.schema) path = f'{nep_name}.{direction}{pointer_name}' msg = f'{path!r} does not resolve to any known path' err = errors.InvalidReferenceError(msg, context=source_context) if direction is s_pointers.PointerDirection.Outbound: near_enpoint_pointers = near_endpoint.get_pointers(ctx.env.schema) s_utils.enrich_schema_lookup_error( err, s_name.UnqualName(pointer_name), modaliases=ctx.modaliases, item_type=s_pointers.Pointer, collection=near_enpoint_pointers.objects(ctx.env.schema), schema=ctx.env.schema, ) raise err
def derive_view(stype: s_obj.Object, source: typing.Optional[s_nodes.Node] = None, target: typing.Optional[s_nodes.Node] = None, *qualifiers, derived_name: typing.Optional[sn.SchemaName] = None, derived_name_quals: typing.Optional[typing.Sequence[str]] = (), derived_name_base: typing.Optional[str] = None, merge_bases=None, preserve_shape: bool = False, is_insert: bool = False, is_update: bool = False, attrs: typing.Optional[dict] = None, ctx: context.ContextLevel) -> s_obj.Object: if source is None: source = stype if derived_name is None and (ctx.derived_target_module or source is stype): derived_name = derive_view_name(stype=stype, derived_name_quals=derived_name_quals, derived_name_base=derived_name_base, ctx=ctx) if isinstance(stype, s_abc.Type): if is_insert: vtype = s_types.ViewType.Insert elif is_update: vtype = s_types.ViewType.Update else: vtype = s_types.ViewType.Select if attrs is None: attrs = {} else: attrs = dict(attrs) attrs['view_type'] = vtype if isinstance(stype, s_abc.Collection): ctx.env.schema, derived = stype.derive_subtype(ctx.env.schema, name=derived_name) else: if stype.get_name(ctx.env.schema) == derived_name: qualifiers = list(qualifiers) qualifiers.append(ctx.aliases.get('d')) ctx.env.schema, derived = stype.derive(ctx.env.schema, source, target, *qualifiers, merge_bases=merge_bases, name=derived_name, mark_derived=True, attrs=attrs) if not stype.generic(ctx.env.schema): if isinstance(derived, s_sources.Source): scls_pointers = stype.get_pointers(ctx.env.schema) derived_own_pointers = derived.get_own_pointers(ctx.env.schema) for pn, ptr in derived_own_pointers.items(ctx.env.schema): # This is a view of a view. Make sure query-level # computable expressions for pointers are carried over. src_ptr = scls_pointers.get(ctx.env.schema, pn) computable_data = ctx.source_map.get(src_ptr) if computable_data is not None: ctx.source_map[ptr] = computable_data if isinstance(derived, s_abc.Type): ctx.view_nodes[derived.get_name(ctx.env.schema)] = derived if preserve_shape and stype in ctx.env.view_shapes: ctx.env.view_shapes[derived] = ctx.env.view_shapes[stype] return derived