jakartaee / data

Data-API
Apache License 2.0
93 stars 26 forks source link

Query on Field Type Limitations within jakarta.data.metamodel Package and Its Impact on Extensibility[clarification]: #560

Open otaviojava opened 6 months ago

otaviojava commented 6 months ago

Specification

https://github.com/jakartaee/data/blob/main/spec/src/main/asciidoc/repository.asciidoc#type-safe-access-to-entity-attributes

I need clarification on ...

Hello,

I'm reaching out to discuss and understand the specific rationale behind the field type restrictions outlined in the documentation/specification, which states:

The metamodel class can contain one or more fields of type java.lang.String or jakarta.data.metamodel.Attribute (or Attribute subclasses from the jakarta.data.metamodel package) the field type must be java.lang.String, jakarta.data.model.Attribute, or an Attribute subclass from the jakarta.data.metamodel package.

This constraint limits the model's extensibility, especially when attempting to develop specializations that accommodate various criteria conditions, such as those applicable to NoSQL databases.

For context, I want to create specialized attributes that could directly handle more granular query logic within the type system. An example of such a specialization might be:

public interface BooleanAttribute<T> extends SortableAttribute<T> {
    CriteriaCondition isTrue();
    CriteriaCondition isFalse();
}

And applying this to an entity like this:

@Entity
public class Person {
    @Id
    private String id;
    @Column
    private String name;
    @Column
    private Boolean active; // Intended to utilize BooleanAttribute for advanced querying
}

My goal is to enable more expressive queries directly through the metamodel, such as:

_Person.active.isFalse();

However, the restriction above prevents the implementation of such extensions, potentially limiting the framework's utility for complex or specialized use cases.

Additional information

No response

gavinking commented 6 months ago

I think it's at least a little bit hard to have this discussion without getting into the specifics of how we plan to use the metamodel to express restrictions. That's something we're not addressing that in JD 1.0, and so we have done something very minimal with the metamodel.

But there are at least two approaches, I guess:

  1. like in JPA, you can express restrictions via some sort of "builder", e.g. builder.isFalse(_Person.active) and this is completely typesafe, though a bit verbose, or
  2. as you suggest, you can have lots of little subtypes like BooleanAttribute extends SortableAttribute<Boolean>, and there is even an open proposal against JPA to introduce this there. This reduces verbosity, but at the cost of quite a lot of complexity, and it can only really cover the basic types built in to the spec.

The passage you indicate leaves us free to take route 2 in the future, without breaking client code. And providers which wish to provide this functionality today, as an extension, can do it via approach 1, which is more general, if also more verbose.

On the other hand, if we open the door too wide to providers introducing their own extensions like BooleanAttribute, we will have to break existing programs if we ever introduce our own standard version of these types.

So I would say this is OK for now. It's something we know we're going to come back to after 1.0.

otaviojava commented 6 months ago

The challenge here is that we are talking about cross-databases. Thus, some queries make sense on one side but not on the other.

For example, only Graph databases have direction in their relationship, and given a provider that uses Apache Tinkerpop, it might introduce this:

_person.outE("knows").("how", "social-media");

It only makes sense to an Apache Tinkerpop Graph database provider, and it won´t make sense to become a standard; this is super specific.

I am not talking about introducing it now but allowing vendors to explore this extensibility, even if the spec does not guarantee the behavior or compatibility among vendors.

gavinking commented 6 months ago

So then that would seem to argue in favor of a builder-style approach, no? That way, each data store type has its own dedicated builder with the operations it supports.

gavinking commented 6 months ago

Wait, wait, what I said here is wrong:

you can express restrictions via some sort of "builder", e.g. builder.isFalse(_Person.active) and this is completely typesafe

In fact, that's not true today, because Attribute<T> doesn't encode the type of the attribute.

So to make code like the above typesafe, we do need to introduce either:

Fortunately, we just don't have many types, due to the inherent limitations on what Jakarta Data is trying to achieve.

Scanning the sort of operations we have in JDQL today, it looks to me like only NumericAttribute is missing in order to express everything you can express in JDQL. Even the need for BooleanAttribute is unclear, since _Person.active.isTrue() is a synonym for _Person.active.equalTo(true).

But of course if we wish to accommodate vendor extensions, as you suggest, and assuming we didn't introduce TypedAttribute<T,X>, then we would want to have BooleanAttribute and TemporalAttribute.

But anyway this really starts to get into the weeds of stuff we're not doing in 1.0.

I think it's best that we leave this alone for now, so that we can introduce such subtypes in Jakarta Data 1.1.

otaviojava commented 6 months ago

Yeap, I will put the the Jakarta Data Future label.