Skip to content

Commit

Permalink
docs: update entity at jnosql
Browse files Browse the repository at this point in the history
Signed-off-by: Otavio Santana <[email protected]>
  • Loading branch information
otaviojava committed Feb 12, 2024
1 parent 7e9ec0b commit 4c17d76
Showing 1 changed file with 16 additions and 123 deletions.
139 changes: 16 additions & 123 deletions spec/src/main/asciidoc/chapters/api/entity.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ NOTE: When there's no risk of confusion, we often use the word “entity” to m

Data represented by an entity is persistent, that is, the data itself outlives any Java process which makes use of it. Thus, it is necessary to maintain an association between instances of Java entity classes and state held in a data store.

- Each persistent instantiation of the schema is distinguishable by a unique _identifier_. For example, a row of a relational database table is identifiable by the value of its primary key.
- Each persistent instantiation of the schema is distinguishable by a unique _identifier_.
- Any persistent instantiation of the schema is representable by an instance of the entity class. In a given Java program, multiple entity class instances might represent the same persistent instance of the schema.
In Jakarta NoSQL, the concrete definition of an entity may be understood to encompass the following aspects:
Expand All @@ -24,7 +24,7 @@ In Jakarta NoSQL, the concrete definition of an entity may be understood to enco

A _programming model for entity classes_ specifies:

- a set of restrictions on the implementation of a Java class which allows it to be used as an entity class with a given Jakarta Data provider, and
- a set of restrictions on the implementation of a Java class which allows it to be used as an entity class with a given Jakarta NoSQL provider, and
- a set of annotations allowing the identification of a Java class as an entity class, and further specification of the schema of the entity.

Jakarta NosQL does not define its own programming model for entities, but instead:
Expand All @@ -33,13 +33,12 @@ Jakarta NosQL does not define its own programming model for entities, but instea

This section lays out the core requirements that an entity programming model must satisfy in order to be compatible with Jakarta Data, and for the defining provider to be considered a fully-compliant implementation of this specification.

Every entity programming model specifies an _entity-defining annotation_. For Jakarta Persistence, this is `jakarta.persistence.Entity`. For Jakarta NoSQL, it is `jakarta.nosql.Entity`. A Jakarta Data provider must provide repository implementations for entity classes bearing the entity-defining annotations it supports, and must ignore entity classes with entity-defining annotations it does not support.
Every entity programming model specifies an _entity-defining annotation_, that is `jakarta.nosql.Entity`. A Jakarta NoSQL provider must provide repository implementations for entity classes bearing the entity-defining annotations it supports, and must ignore entity classes with entity-defining annotations it does not support.

NOTE: To maintain clarity and to disambiguate the desired Jakarta Data provider, a single entity class should not mix entity-defining annotations from different providers. For example, an entity class should not be annotated both `jakarta.persistence.Entity` and `jakarta.nosql.Entity`. This practice allows the entity-defining annotation to indicate the desired provider in programs where multiple Jakarta Data providers are available.

Furthermore, an entity programming model must define an annotation which identifies the field or property holding the unique identifier of an entity. For Jakarta Persistence, it is `jakarta.persistence.Id` or `jakarta.persistence.EmbeddedId`. For Jakarta NoSQL, it is `jakarta.nosql.Id`. Alternatively, an entity programming model might allow the identifier field or property to be identified via some convention.
Furthermore, an entity programming model must define an annotation which identifies the field or property holding the unique identifier of an entity, the `jakarta.nosql.Id`.

Typically, an entity programming model specifies additional annotations which are used to make the schema of the entity explicit, for example, `jakarta.persistence.Id` and `jakarta.persistence.Column`, or `jakarta.nosql.Id` and `jakarta.nosql.Column`. The nature of such annotations is beyond the scope of this specification.
Typically, an entity programming model specifies additional annotations which are used to make the schema of the entity explicit, for example, `jakarta.nosql.Id` and `jakarta.nosql.Column`. The nature of such annotations is beyond the scope of this specification.

In a given entity programming model, entity classes might always be mutable, or might always be immutable, or, alternatively, the model might support a mix of mutable and immutable entity classes.

Expand All @@ -53,32 +52,22 @@ An entity programming model might support inheritance between entities, and migh
==== Persistent Fields

A field of an entity class may or may not represent state which is persistent in the datastore.
A _persistent field_ has some corresponding representation in the data schema of the entity, for example, it might map to a column or columns in a relational database table.
Any programming model for entity classes must provide well-defined rules for distinguishing fields which are persistent in the datastore from which fields are _transient_, having no persistent representation in the datastore.
Furthermore, the programming model must specify how the Jakarta Data provider accesses the persistent fields of an entity to read and write their values.
A _persistent field_ has some corresponding representation in the data schema of the entity.


Every programming model for entity classes must support _direct field access_, that is, access to the persistent fields of an entity class without triggering any intermediating user-written code such as JavaBeans-style property accessors.
When direct field access is used, every Java field marked with the Java language `transient` modifier must be treated as transient.
A programming model might place constraints on the visibility of persistent fields.
For example, Jakarta Persistence disallows `public` persistent fields.
Every programming model must permit `private` persistent fields.

A programming model for entity classes might also support _property-based access_, that is, access to persistent fields via JavaBeans-style property accessors, or, especially for Java `record` types, via accessor methods combined with constructor-based initialization.
Such programming models should provide an annotation or other convention to distinguish transient properties.
For example, Jakarta Persistence provides `jakarta.persistence.Transient`.
When property-based access is supported, a programming model might place constraints on the visibility of property accessors.
For example, Jakarta Persistence requires that property accessors be `public` or `protected`.
Support for property-based access is not required by this specification.
A programming model might place constraints on the visibility of persistent fields.

Jakarta Data distinguishes three kinds of persistent field within entity classes.
Jakarta NoSQL distinguishes three kinds of persistent field within entity classes.

- A _basic field_ holds a value belonging to some fundamental data type supported natively by the Jakarta Data Provider. Support for the set of basic types enumerated in the next section below is mandatory for all Jakarta Data providers.
- An _embedded field_ allows the inclusion of the state of a finer-grained Java class within the state of an entity. The type of an embedded field is often a user-written Java class. Support for embedded fields varies depending on the Jakarta Data provider and the database type.
- An _association field_ implements an association between entity types. Support for association fields varies depending on the Jakarta Data provider and the database type.
- A _basic field_ holds a value belonging to some fundamental data type supported natively by the Jakarta NoSQL Provider. Support for the set of basic types enumerated in the next section below is mandatory for all Jakarta NoSQL providers.
- An _embedded field_ allows the inclusion of the state of a finer-grained Java class within the state of an entity. The type of an embedded field is often a user-written Java class. Support for embedded fields varies depending on the Jakarta NoSQL provider and the database type.
- An _association field_ implements an association between entity types. Support for association fields varies depending on the Jakarta NoSQL provider and the database type.

==== Basic Types

Every Jakarta Data provider must support the following basic types within its programming model:
Every Jakarta NoSQL provider must support the following basic types within its programming model:

|===
| Basic Data Type | Description
Expand Down Expand Up @@ -120,9 +109,9 @@ public class Person {
}
----

In addition to the types listed above, an entity programming model might support additional domain-specific basic types. This extended set of basic types might include types with a nontrivial internal structure. An entity programming model might even provide mechanisms to convert between user-written types and natively-supported basic types. For example, Jakarta Persistence defines the `AttributeConverter` interface.
In addition to the types listed above, an entity programming model might support additional domain-specific basic types. This extended set of basic types might include types with a nontrivial internal structure. An entity programming model might even provide mechanisms to convert between user-written types and natively-supported basic types, defined at the `AttributeConverter` interface.

NOTE: Many key-value, wide-column, document, and relational databases feature native support for arrays or even associative arrays of these basic types. Unfortunately, the semantics of such types--along with their performance characteristics--are extremely nonuniform, and so support for such types is left undefined by the Jakarta Data specification.
NOTE: Many key-value, wide-column, document, and relational databases feature native support for arrays or even associative arrays of these basic types. Unfortunately, the semantics of such types--along with their performance characteristics--are extremely nonuniform, and so support for such types is left undefined by the Jakarta NoSQL specification.

==== Embedded Fields and Embeddable Classes

Expand Down Expand Up @@ -180,18 +169,6 @@ In a document, wide-column, or graph database, the JSON representation of an ins
}
----

Or, in a relational database, the DDL for the `Person` table might look like this:

[source,sql]
----
create table Person (
id bigint primary key,
name varchar,
street varchar,
city varchar,
postalCode varchar
)
----

In a structured representation, the fields of the embeddable class are somehow grouped together in the data schema.

Expand All @@ -211,25 +188,8 @@ For example, the JSON representation of `Person` might be:
}
----

Or the SQL DDL could be:

[source,sql]
----
create type Address as (
street varchar,
city varchar,
postalCode varchar
)
create table Person (
id bigint primary key,
name varchar,
address Address
)
----

NOTE: Support for embeddable classes and embedded fields is not required by this specification.
However, every Jakarta Data provider is strongly encouraged to provide support for embeddable classes within its entity programming model.
However, every Jakarta NoSQL provider is strongly encouraged to provide support for embeddable classes within its entity programming model.

==== Entity Associations

Expand Down Expand Up @@ -258,76 +218,9 @@ public class Book {
}
----

In a relational database, these entities might map to the following data schema:

[source,sql]
----
create table Author (
uuid id primary key,
name varchar,
)
create table BookAuthor(
book bigint,
author uuid,
primary key (book, author),
foreign key (author) references Author,
foreign key (book) references Book
)
create table Book (
id bigint primary key,
title varchar,
category varchar
)
----

NOTE: Support for entity associations is not required by this specification.

==== Entity Property Names

Within an entity, property names must be unique ignoring case. For simple entity properties, the field or accessor method name serves as the entity property name. In the case of embedded classes, entity property names are computed by concatenating the field or accessor method names at each level, optionally joined by a delimiter.

Locations where entity property names can be used, along with delimiters, are shown in the table. The examples in the table assume an `Order` entity has an `address` of type `MailingAddress` with a `zipCode` of type `int`.

.Locations of Entity Properties and Delimiters Table:
[cols="3, 1, 6"]
|===
|Entity Property Location |Delimiter |Example

|`@Query` annotation
|`.`
|`@Query("SELECT o FROM Order o WHERE o.address.zipCode=?1")`

|_Query by Method Name_ method name
|`_`
|`List<Order> findByAddress_zipCode(int zip);`

|_Parameter-based Conditions_ parameter name
|`_`
|`@Find List<Order> find(int address_zipCode);`

|`Sort` property value
|`.` or `_`
|`Sort.asc("address_zipCode")`

|`@By` or `@OrderBy` annotation value
|`.` or `_`
|`@Find List<Order> find(@By("address.zipCode") int zip);`
|===

For a given entity property name, delimiter usage must be consistent. Either the delimiter must always be used within the entity property name to delimit subcomponents or the delimiter must never be used within the entity property name. Except in the case of `@Query` where the delimiter is required by the query language, delimiters can be omitted entirely from an entity property name when it is unnecessary to disambiguate the entity property to which the name refers.

The resolution of properties involves the following steps:

1. *Property Extraction*: The framework obtains entity property names from the locations in the above table, applying the BNF grammar in the case of _Query by Method Name_ to extract entity property names from the method name. For example, for the query method `findByAddressZipCode`, the property name extracted is `AddressZipCode`.

2. *Property Lookup on Entity*: The framework compares the extracted name, ignoring case, against the field names of the respective entity class.

3. *Property Lookup in Hierarchy*: If no match was found among the entity field names, the framework compares the extracted name, ignoring case, against the combination of the field names of the respective entity and the fields of the entity's hierarchy of relations and embedded classes, concatenated as outlined in this section above, both with and without the optional delimiter.

4. *Resolution Outcome*: If the framework successfully identifies a property in the domain class or along the specified traversal path that matches the extracted property name, it uses that property.

When `@Query` is used, the Jakarta Data specification defers to the rules of the query language on whether the delimiter is required and whether the case must match.

Users are encouraged to follow Java's camel case naming standards for fields of entities, relations, and embedded classes, avoiding underscores in field names. The resolution algorithm for property identification relies on traversal with underscores. Adhering to camel case for property names ensures consistency and eliminates ambiguity, enabling effective data filtering and retrieval from domain classes.

0 comments on commit 4c17d76

Please sign in to comment.