Package is.codion.framework.domain.entity.condition


@NullMarked package is.codion.framework.domain.entity.condition
Provides a type-safe condition API for building SQL WHERE clauses programmatically.

Overview

The condition framework enables type-safe query construction through a fluent API that mirrors SQL operators while leveraging Java's type system for compile-time safety. Conditions are the primary mechanism for filtering data when querying entities.

Core Concepts

Condition Types

  • ColumnCondition - Conditions based on column values (equality, comparison, patterns, nullity)
  • ForeignKeyCondition - Conditions based on foreign key relationships
  • CustomCondition - Complex conditions that cannot be expressed with standard operators
  • Combination Conditions - AND/OR combinations of other conditions
  • All Condition - Represents no filtering (SELECT all rows)

Basic Usage

Note: Column and ForeignKey implement their respective condition factory interfaces, allowing you to create conditions directly from attributes.

// Column conditions - created directly from Column attributes
Condition nameStartsWithA = Customer.NAME.like("A%");
Condition ageOver18 = Customer.AGE.greaterThan(18);
Condition hasEmail = Customer.EMAIL.isNotNull();

// Foreign key conditions
Entity usa = connection.selectSingle(Country.CODE.equalTo("US"));
Condition fromUSA = Customer.COUNTRY_FK.equalTo(usa);

// Combining conditions
Condition complexCondition = and(
    nameStartsWithA,
    ageOver18,
    hasEmail,
    fromUSA
);

// Using conditions in queries
List<Entity> customers = connection.select(complexCondition);

Column Condition Examples

// Equality
Track.NAME.equalTo("Yesterday")
Track.RATING.equalTo(5)

// Comparison
Track.DURATION.greaterThan(180)
Invoice.TOTAL.between(10.0, 100.0)

// Pattern matching
Artist.NAME.like("The %")
Artist.NAME.likeIgnoreCase("%beatles%")

// Nullity
Customer.PHONE.isNull()
Customer.EMAIL.isNotNull()

// Multiple values
Track.GENRE_ID.in(1, 2, 3)
Album.YEAR.notIn(1990, 1991, 1992)

Foreign Key Condition Examples

// Single entity reference
Entity metalGenre = connection.selectSingle(Genre.NAME.equalTo("Metal"));
Condition metalTracks = Track.GENRE_FK.equalTo(metalGenre);

// Multiple entity references
List<Entity> selectedArtists = connection.select(Artist.NAME.like("A%"));
Condition bySelectedArtists = Album.ARTIST_FK.in(selectedArtists);

// Null foreign key (orphaned records)
Condition noAlbum = Track.ALBUM_FK.isNull();

Custom Conditions

For complex queries that cannot be expressed with standard operators, use ConditionType to define custom SQL conditions:

// Define in entity interface
ConditionType NOT_IN_PLAYLIST = TYPE.conditionType("not_in_playlist");

// Implement in entity definition
.condition(Track.NOT_IN_PLAYLIST, (columns, values) ->
    "track.id NOT IN (SELECT track_id FROM playlist_track WHERE playlist_id = ?)")

// Use in queries
List<Entity> tracks = connection.select(
    Track.NOT_IN_PLAYLIST.get(Playlist.ID, playlistId));

Condition Combinations

// AND combination
Condition activeCustomers = and(
    Customer.ACTIVE.equalTo(true),
    Customer.LAST_ORDER_DATE.greaterThan(oneYearAgo)
);

// OR combination
Condition importantCustomers = or(
    Customer.TOTAL_PURCHASES.greaterThan(10000),
    Customer.VIP.equalTo(true)
);

// Complex nesting
Condition targetCustomers = and(
    activeCustomers,
    importantCustomers,
    Customer.EMAIL.isNotNull()
);

Advanced Features

Case Sensitivity

// Case-insensitive operations
Artist.NAME.equalToIgnoreCase("the beatles")
Album.TITLE.likeIgnoreCase("%love%")

All Condition

// Select all rows (no WHERE clause)
List<Entity> allCustomers = connection.select(all(Customer.TYPE));

// Useful for conditional filtering
Condition filter = searchTerm.isEmpty() ?
    all(Product.TYPE) :
    Product.NAME.like("%" + searchTerm + "%");

Best Practices

  • Use column-specific methods for type safety (equalTo, greaterThan, etc.)
  • Prefer foreign key conditions over joining on ID columns
  • Use custom conditions for complex SQL that doesn't fit the standard API
  • Combine conditions logically to build readable queries
  • Leverage case-insensitive operations when appropriate
See Also: