Skip to content

Conversation

@dnwpark
Copy link
Contributor

@dnwpark dnwpark commented Oct 29, 2025

Object models now have a __backlinks__ field, which is set to a GelObjectBacklinksModel. This backlinks model contains multi links to std::BaseObject.

These new backlinks models are generated during reflection. At runtime, intersections generate a backlink model alongside the intersection type.

A simple query with backlinks:

default.Inh_A.__backlinks__.l
.is_(default.Link_Inh_A)
.select(n=True, l=True)
WITH baseobject_and_link_inh_a := (
    default::Inh_A.<l [is default::Link_Inh_A]
)
SELECT baseobject_and_link_inh_a {
    n,
    l := baseobject_and_link_inh_a.l { * },
}

A more complex query with backlinks:

default.Link_Inh_AB.l  # Link
.is_(default.Inh_AC)  # Intersection
.__backlinks__.l.is_(default.Link_Inh_A)  #  Backlink
.select(n=True, l=True)
WITH baseobject_and_link_inh_a := (
    (
        default::Link_Inh_AB.l [is default::Inh_AC]
    ).<l [is default::Link_Inh_A]
)
SELECT baseobject_and_link_inh_a {
    n,
    l := baseobject_and_link_inh_a.l { * },
}

Also works inside shapes:

default.Inh_AB.select(
    a=lambda x: x.__backlinks__.l.is_(default.Link_Inh_AB).limit(1).n
)
WITH inh_ab := default::Inh_AB
SELECT inh_ab {
    a := (
        SELECT (inh_ab.<l [is default::Link_Inh_AB]) { * }
        LIMIT 1
    ).n,
}

@dnwpark dnwpark force-pushed the backlinks branch 3 times, most recently from 7afa03c to a6ec0a5 Compare October 30, 2025 16:26
@msullivan
Copy link
Member

This seems basically plausible; could you post some of the generated model code here?

@dnwpark dnwpark force-pushed the backlinks branch 5 times, most recently from 10139fb to a98a638 Compare October 31, 2025 20:31
@dnwpark dnwpark marked this pull request as ready for review October 31, 2025 20:33
@dnwpark dnwpark force-pushed the backlinks branch 2 times, most recently from e4582d6 to 6c2ed38 Compare November 3, 2025 22:59
@dnwpark dnwpark force-pushed the backlinks branch 2 times, most recently from 4a20778 to 3d482e1 Compare November 3, 2025 23:37
@dnwpark
Copy link
Contributor Author

dnwpark commented Nov 4, 2025

In __sharedstd__/__shapes__/std/__init__.py

All other backlinks classes derive from __BaseObject_backlinks__:

class __BaseObject_backlinks__(GelObjectBacklinksModel):
    class __gel_reflection__(GelObjectBacklinksModel.__gel_reflection__):
        name = SchemaPath.from_segments('std', 'BaseObject')
        type_name = SchemaPath.from_segments('std', 'BaseObject')
        @LazyClassProperty["dict[builtins.str, GelPointerReflection]"]
        @classmethod
        def pointers(cls,) -> dict[builtins.str, GelPointerReflection]:
            my_ptrs: dict[builtins.str, GelPointerReflection] = {}
            return my_ptrs

Which is added to BaseObject:

class BaseObject(...):
    ...

    __backlinks__: GelObjectBacklinksModelDescriptor[__BaseObject_backlinks__] = GelObjectBacklinksModelDescriptor[__BaseObject_backlinks__]()

    ...

For user defined types, an object Inh_A with a backlink l:

class __Inh_A_backlinks__(std_shapes.__Object_backlinks__):
    class __gel_reflection__(
        std_shapes.__Object_backlinks__.__gel_reflection__
    ):
        name = SchemaPath.from_segments('default', 'Inh_A')
        type_name = SchemaPath.from_segments('default', 'Inh_A')
        @LazyClassProperty["dict[str, GelPointerReflection]"]
        @classmethod
        def pointers(cls,) -> dict[str, GelPointerReflection]:
            my_ptrs: dict[str, GelPointerReflection] = {
                'l': GelPointerReflection(
                    name='l',
                    type=std_shapes.BaseObject,
                    kind=PointerKind('Link'),
                    cardinality=Cardinality('Many'),
                    computed=True,
                    readonly=True,
                    has_default=False,
                    mutable=False,
                    properties=None,
                ),
            }
            return (
                my_ptrs
                | std_shapes.__Object_backlinks__.__gel_reflection__.pointers
            )

    l: ComputedMultiLink[std_shapes.BaseObject]

...

class Inh_A(...):
    __backlinks__: GelObjectBacklinksModelDescriptor[__Inh_A_backlinks__] = GelObjectBacklinksModelDescriptor[__Inh_A_backlinks__]()

    ...

Copy link
Member

@msullivan msullivan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work!

base_backlinks_reflections: list[str]
base_backlinks_models: list[str]

if objtype.name == "std::BaseObject":
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment on why this is special?


backlinks_model_name = self._mangle_backlinks_model_name(name)

base_object_types = [
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a name change here or a comment, but there is a bunch of code here dealing with both the base types of the current object and also BaseObject, and it's a little confusing

@dnwpark dnwpark merged commit 8a956d6 into master Nov 4, 2025
43 checks passed
@dnwpark dnwpark deleted the backlinks branch November 4, 2025 23:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants