Beispiel #1
0
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
Beispiel #3
0
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}')
Beispiel #4
0
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)
Beispiel #5
0
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
Beispiel #6
0
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
Beispiel #7
0
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
Beispiel #8
0
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