Package st.orm

Annotation Interface QueryColumn


@Target(TYPE) @Retention(RUNTIME) @Repeatable(QueryColumns.class) public @interface QueryColumn
Declares a column a query names but the entity or projection does not carry: a query column. It gets a metamodel field, generated as a record component's is, but no component, so it is never selected, inserted or updated. A generated column that stores a derived form of another column, which a search matches and an index is built on, is the typical case: the database computes it, no caller reads it, and a record built by the application has no value to give it.

 @QueryColumn(field = "lastNameFolded", type = String.class, function = "fold_accents")
 record Owner(@PK Integer id, String firstName, String lastName) implements Entity<Integer> {}

 orm.entity(Owner.class).select()
     .where(it -> it.search(input, Owner_.lastNameFolded))
     .getResultList();
 

The search compares LOWER(o.last_name_folded) LIKE LOWER(fold_accents(?)): the column as stored, the input folded by the database through the function() the column names.

The generated Owner_.lastNameFolded is a Metamodel<Owner, String> and goes wherever a column does: where, orderBy, orderFirst, search and suggest, a SqlFunction, a keyset sort and a template placeholder. It is reached through paths like any other field, so a query column of a referenced table is Pet_.owner.lastNameFolded from a query on pets. A record holds no value for it: Metamodel.getValue(Data) throws, and an update cannot set it.

The column follows from the field name through the column name resolver, as a component's does; column() names it where the resolver does not. A column is carried by a field or named by a query column, not both: a declaration whose column a field maps is refused when the model is built, as is one named after a record component. Schema validation checks that the column exists with a compatible type. On an entity every insert leaves it out, so the database must fill it: a NOT NULL query column that is not generated, not an identity column and has no default is reported as an unmapped column is.

Since:
1.16
  • Required Element Summary

    Required Elements
    Modifier and Type
    Required Element
    Description
    The name of the metamodel field, such as lastNameFolded for Owner_.lastNameFolded.
    The type of the column's values, as a record component's type: String.class, Integer.class, LocalDate.class, an enum type.
  • Optional Element Summary

    Optional Elements
    Modifier and Type
    Optional Element
    Description
    The database column name.
    The SQL function whose result the column stores, such as fold_accents for a generated column holding fold_accents(last_name).
    boolean
    Whether the column allows null.
  • Element Details

    • field

      String field
      The name of the metamodel field, such as lastNameFolded for Owner_.lastNameFolded.
    • type

      Class<?> type
      The type of the column's values, as a record component's type: String.class, Integer.class, LocalDate.class, an enum type.
    • column

      String column
      The database column name. By default the column name resolver derives it from the field name, as it does for a record component: lastNameFolded is last_name_folded under the default resolver.
      Default:
      ""
    • nullable

      boolean nullable
      Whether the column allows null. A nullable query column compares as a nullable field does and is refused as a keyset sort field, as a nullable field is.
      Default:
      false
    • function

      String function
      The SQL function whose result the column stores, such as fold_accents for a generated column holding fold_accents(last_name). A value the column is compared with passes through it, on the value side only: last_name_folded = fold_accents(?). The column is read as stored, which is what its index holds, and the database computes the value in the same statement, so a caller passes the input as it is. It applies wherever the column is compared with a value: the comparison operators, IN, BETWEEN, the text operators, search, suggest and orderFirst; a pattern passes through it too, so the function must leave the wildcards and the escape character as they are. A position of a keyset scroll holds the stored value and is compared as it is. A function behind a generated column or an index must be deterministic, giving the same result for the same input. A SQL identifier, optionally qualified by a schema, as SqlFunction takes. Empty for a column compared with a value as it is.
      Default:
      ""