Ejemplo n.º 1
0
def _merge_items(
    item: qltracer.Source_T,
    parent: qltracer.SourceLike_T,
    *,
    schema: s_schema.Schema,
) -> qltracer.Source_T:

    item_ptrs = dict(item.get_pointers(schema).items(schema))

    for pn, ptr in parent.get_pointers(schema).items(schema):
        if not isinstance(ptr, (qltracer.Pointer, s_sources.Source)):
            continue

        if pn not in item_ptrs:
            ptr_copy = qltracer.Pointer(
                s_name.QualName('__', pn.name),
                source=ptr.get_source(schema),
                target=ptr.get_target(schema),
            )
            ptr_copy.pointers = dict(
                ptr.get_pointers(schema).items(schema))
            item.pointers[pn] = ptr_copy
        else:
            item_ptr = item.getptr(schema, pn)
            assert isinstance(item_ptr, (qltracer.Pointer, s_sources.Source))
            ptr_copy = qltracer.Pointer(
                s_name.QualName('__', pn.name),
                source=item,
                target=item_ptr.get_target(schema),
            )
            ptr_copy.pointers = dict(
                item_ptr.get_pointers(schema).items(schema))
            item.pointers[pn] = _merge_items(ptr_copy, ptr, schema=schema)

    return item
Ejemplo n.º 2
0
def _trace_item_layout(node: qlast.CreateObject,
                       *,
                       obj=None,
                       fq_name=None,
                       ctx: LayoutTraceContext):
    if obj is None:
        fq_name = ctx.get_local_name(node.name)
        obj = ctx.objects[fq_name]

    if hasattr(node, "bases"):
        bases = []
        # construct the parents set, used later in ancestors graph
        parents = set()

        for ref in _get_bases(node, ctx=ctx):
            bases.append(ref)

            # ignore std modules dependencies
            if ref.module not in s_schema.STD_MODULES:
                parents.add(ref)

            if (ref.module not in ctx.local_modules
                    and ref not in ctx.inh_graph):
                base = ctx.schema.get(ref)
                base_obj = type(obj)(name=ref)
                for pn, p in base.get_pointers(ctx.schema).items(ctx.schema):
                    base_obj.pointers[pn] = qltracer.Pointer(
                        pn,
                        source=base,
                        target=p.get_target(ctx.schema),
                    )
                ctx.inh_graph[ref] = {
                    "item": base_obj,
                }

        ctx.parents[fq_name] = parents
        ctx.inh_graph[fq_name] = {
            "item": obj,
            "deps": bases,
            "merge": bases,
        }

    for decl in node.commands:
        if isinstance(decl, qlast.CreateConcretePointer):
            if isinstance(decl.target, qlast.TypeExpr):
                target = _resolve_type_expr(decl.target, ctx=ctx)
            else:
                target = None

            ptr = qltracer.Pointer(decl.name.name, source=obj, target=target)
            obj.pointers[decl.name.name] = ptr
            ptr_name = f'{fq_name}@{decl.name.name}'
            ctx.objects[ptr_name] = ptr
            ctx.defdeps[fq_name].add(ptr_name)

            _trace_item_layout(decl, obj=ptr, fq_name=ptr_name, ctx=ctx)
Ejemplo n.º 3
0
def _merge_items(item, parent):

    for pn, ptr in parent.pointers.items():
        if pn not in item.pointers:
            ptr_copy = qltracer.Pointer(
                pn, source=ptr.source, target=ptr.target)
            ptr_copy.pointers = dict(ptr.pointers)
            item.pointers[pn] = ptr_copy
        else:
            ptr_copy = qltracer.Pointer(
                pn, source=item, target=item.pointers[pn].target)
            ptr_copy.pointers = dict(item.pointers[pn].pointers)
            item.pointers[pn] = _merge_items(ptr_copy, ptr)

    return item
Ejemplo n.º 4
0
def _trace_item_layout(node: qlast.CreateObject,
                       *,
                       obj=None,
                       fq_name=None,
                       ctx: LayoutTraceContext):
    if obj is None:
        fq_name = f'{ctx.module}::{node.name.name}'
        obj = ctx.objects[fq_name]

    if hasattr(node, "bases"):
        bases = []

        for ref in _get_bases(node, ctx=ctx):
            bases.append(ref)

            if (ref.module not in ctx.local_modules
                    and ref not in ctx.inh_graph):
                base = ctx.schema.get(ref)
                base_obj = type(obj)(name=ref)
                for pn, p in base.get_pointers(ctx.schema).items(ctx.schema):
                    base_obj.pointers[pn] = qltracer.Pointer(
                        pn,
                        source=base,
                        target=p.get_target(ctx.schema),
                    )
                ctx.inh_graph[ref] = {
                    "item": base_obj,
                }

        ctx.inh_graph[fq_name] = {
            "item": obj,
            "deps": bases,
            "merge": bases,
        }

    for decl in node.commands:
        if isinstance(decl, qlast.CreateConcretePointer):
            if isinstance(decl.target, qlast.TypeExpr):
                target = _resolve_type_expr(decl.target, ctx=ctx)
            else:
                target = None

            ptr = qltracer.Pointer(decl.name.name, source=obj, target=target)
            obj.pointers[decl.name.name] = ptr
            ptr_name = f'{fq_name}@{decl.name.name}'
            ctx.objects[ptr_name] = ptr

            _trace_item_layout(decl, obj=ptr, fq_name=ptr_name, ctx=ctx)
Ejemplo n.º 5
0
def sdl_to_ddl(schema, documents):
    ddlgraph = {}
    mods = []

    ctx = LayoutTraceContext(
        schema,
        local_modules=frozenset(mod for mod, schema_decl in documents.items()),
    )

    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, qlast.CreateAlias)):
                    ctx.objects[fq_name] = qltracer.ObjectType(fq_name)

                elif isinstance(decl_ast, qlast.CreateScalarType):
                    ctx.objects[fq_name] = qltracer.Type(fq_name)

                elif isinstance(decl_ast,
                                (qlast.CreateLink, qlast.CreateProperty)):
                    ctx.objects[fq_name] = qltracer.Pointer(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)
                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 fq_name in ctx.parents.keys():
        ctx.ancestors[fq_name] = get_ancestors(fq_name, ctx.ancestors,
                                               ctx.parents)

    topological.normalize(ctx.inh_graph, _merge_items)

    ctx = DepTraceContext(schema, ddlgraph, ctx.objects, ctx.parents,
                          ctx.ancestors, ctx.defdeps, ctx.constraints)
    for module_name, declarations in documents.items():
        ctx.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=ctx)

    return mods + list(topological.sort(ddlgraph, allow_unresolved=False))
Ejemplo n.º 6
0
def sdl_to_ddl(schema, declarations):
    ddlgraph = {}
    mods = []

    ctx = LayoutTraceContext(
        schema,
        local_modules=frozenset(mod for mod, schema_decl in declarations),
    )

    for module_name, schema_ast in declarations:
        for decl_ast in schema_ast.declarations:
            if isinstance(decl_ast, qlast.CreateObject):
                fq_name = f'{module_name}::{decl_ast.name.name}'
                if isinstance(decl_ast,
                              (qlast.CreateObjectType, qlast.CreateView)):
                    ctx.objects[fq_name] = qltracer.ObjectType(fq_name)

                elif isinstance(decl_ast, qlast.CreateScalarType):
                    ctx.objects[fq_name] = qltracer.Type(fq_name)

                elif isinstance(decl_ast,
                                (qlast.CreateLink, qlast.CreateProperty)):
                    ctx.objects[fq_name] = qltracer.Pointer(fq_name,
                                                            source=None,
                                                            target=None)

    for module_name, decl_ast in declarations:
        ctx.set_module(module_name)
        trace_layout(decl_ast, ctx=ctx)

    topological.normalize(ctx.inh_graph, _merge_items)

    ctx = DepTraceContext(schema, ddlgraph, ctx.objects)
    for module_name, decl_ast in declarations:
        ctx.set_module(module_name)
        trace_dependencies(decl_ast, ctx=ctx)
        mods.append(qlast.CreateModule(name=qlast.ObjectRef(name=module_name)))

    return mods + list(topological.sort(ddlgraph, allow_unresolved=False))
Ejemplo n.º 7
0
def _trace_item_layout(
    node: qlast.CreateObject,
    *,
    obj: Optional[qltracer.NamedObject] = None,
    fq_name: Optional[s_name.QualName] = None,
    ctx: LayoutTraceContext,
) -> None:
    if obj is None:
        fq_name = ctx.get_local_name(node.name)
        local_obj = ctx.objects[fq_name]
        assert isinstance(local_obj, qltracer.NamedObject)
        obj = local_obj

    assert fq_name is not None

    if isinstance(node, qlast.BasesMixin):
        bases = []
        # construct the parents set, used later in ancestors graph
        parents = set()

        for ref in _get_bases(node, ctx=ctx):
            bases.append(ref)

            # ignore std modules dependencies
            if ref.get_module_name() not in s_schema.STD_MODULES:
                parents.add(ref)

            if (
                ref.module not in ctx.local_modules
                and ref not in ctx.inh_graph
            ):
                base_obj = type(obj)(name=ref)
                ctx.inh_graph[ref] = topological.DepGraphEntry(item=base_obj)

                base = ctx.schema.get(ref)
                if isinstance(base, s_sources.Source):
                    assert isinstance(base_obj, qltracer.Source)
                    base_pointers = base.get_pointers(ctx.schema)
                    for pn, p in base_pointers.items(ctx.schema):
                        base_obj.pointers[pn] = qltracer.Pointer(
                            s_name.QualName('__', pn.name),
                            source=base,
                            target=p.get_target(ctx.schema),
                        )

        ctx.parents[fq_name] = parents
        ctx.inh_graph[fq_name] = topological.DepGraphEntry(
            item=obj,
            deps=set(bases),
            merge=set(bases),
        )

    for decl in node.commands:
        if isinstance(decl, qlast.CreateConcretePointer):
            assert isinstance(obj, qltracer.Source)
            target: Optional[qltracer.TypeLike]
            if isinstance(decl.target, qlast.TypeExpr):
                target = _resolve_type_expr(decl.target, ctx=ctx)
            else:
                target = None

            pn = s_utils.ast_ref_to_unqualname(decl.name)
            ptr = qltracer.Pointer(
                s_name.QualName('__', pn.name),
                source=obj,
                target=target,
            )
            obj.pointers[pn] = ptr
            ptr_name = s_name.QualName(
                module=fq_name.module,
                name=f'{fq_name.name}@{decl.name.name}',
            )
            ctx.objects[ptr_name] = ptr
            ctx.defdeps[fq_name].add(ptr_name)

            _trace_item_layout(
                decl, obj=ptr, fq_name=ptr_name, ctx=ctx)

        elif isinstance(decl, qlast.CreateConcreteConstraint):
            # Validate that the constraint exists at all.
            _validate_schema_ref(decl, ctx=ctx)
            _, con_fq_name = ctx.get_fq_name(decl)

            con_name = s_name.QualName(
                module=fq_name.module,
                name=f'{fq_name.name}@{con_fq_name}',
            )
            ctx.objects[con_name] = qltracer.ConcreteConstraint(con_name)
            ctx.constraints[fq_name].add(con_name)

        elif isinstance(decl, qlast.CreateAnnotationValue):
            # Validate that the constraint exists at all.
            _validate_schema_ref(decl, ctx=ctx)
Ejemplo n.º 8
0
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),
    )

    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,
                                         qlast.CreateAlias)):
                    ctx.objects[fq_name] = qltracer.ObjectType(fq_name)

                elif isinstance(decl_ast, qlast.CreateScalarType):
                    ctx.objects[fq_name] = qltracer.Type(fq_name)

                elif isinstance(decl_ast, (qlast.CreateLink,
                                           qlast.CreateProperty)):
                    ctx.objects[fq_name] = qltracer.Pointer(
                        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)
                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)

    ordered = topological.sort(ddlgraph, allow_unresolved=False)
    return tuple(mods) + tuple(ordered)