# ujo-core

> Core type-safe Key pattern, domain metamodel, and WHERE criterion DSL for Ujorm3.
> Provides the foundation for compile-time-safe property access and SQL condition building.

## Maven

```xml
<dependency>
    <groupId>org.ujorm</groupId>
    <artifactId>ujo-core</artifactId>
    <version>3.0.4</version>
</dependency>
```

## Key Concept: Key<DOMAIN, VALUE>

`org.ujorm.core.Key<D, V>` is a type-safe property descriptor — a singleton per field.
It carries no data; it describes a property of class `D` with value type `V`.

```java
Key<Employee, String> nameKey = MetaEmployee.name;  // generated by APT

// Type-safe get/set
String name = nameKey.getValue(employee);
nameKey.setValue(employee, "Alice");

// Metadata
String colName = nameKey.name();             // "name"
String fullName = nameKey.fullName();        // "Employee.name"
Class<String> type = nameKey.type();         // String.class
Class<Employee> domain = nameKey.domainClass();
boolean isPk = nameKey.info().primaryKey();
```

`Key` implements `CharSequence`, so it can be used where a `String` column name is expected.

## DomainHandler<D> — Metamodel Descriptor

`org.ujorm.core.DomainHandler<D>` describes a domain class at runtime:

```java
DomainHandler<Employee> handler = DomainHandlerProvider.getHandler(Employee.class);

List<Key<Employee, ?>> keys = handler.getKeyList();
Key<Employee, Long> pk = handler.findPrimaryKey(true);
Key<Employee, String> k = handler.getKey("name", String.class);
Key<Employee, String> k2 = handler.getKeyByColumn("emp_name", true, String.class);
String table = handler.getDatabaseTable();
Employee empty = handler.newDomain();
```

## Criterion — Type-Safe WHERE Conditions

`org.ujorm.core.criterion.Criterion<D>` is an immutable, composable WHERE predicate.
Build from `Key` factory methods; combine with `.and()`, `.or()`, `.not()`:

```java
Criterion<Employee> byName = MetaEmployee.name.whereEq("Alice");
Criterion<Employee> byId   = MetaEmployee.id.whereGe(1L);
Criterion<Employee> active = MetaEmployee.active.whereEq(true);

Criterion<Employee> combined = byName.and(byId).or(active);
Criterion<Employee> negated  = byName.not();
```

### Available factory methods on Key (via CriterionProvider)

| Method | SQL equivalent |
|--------|----------------|
| `whereEq(value)` | `col = ?` |
| `whereNeq(value)` | `col <> ?` |
| `whereGt(value)` | `col > ?` |
| `whereGe(value)` | `col >= ?` |
| `whereLt(value)` | `col < ?` |
| `whereLe(value)` | `col <= ?` |
| `whereNull()` | `col IS NULL` |
| `whereNotNull()` | `col IS NOT NULL` |
| `whereIn(v1, v2, ...)` | `col IN (?,?,...)` |
| `whereNotIn(collection)` | `col NOT IN (...)` |
| `whereSql(template, value)` | custom SQL; `{0}` = column, `{1}` = value |

### Operator enum

`org.ujorm.core.criterion.Operator`: `EQ`, `NOT_EQ`, `GT`, `GE`, `LT`, `LE`, `IN`, `NOT_IN`,
`REGEXP`, `NOT_REGEXP`, `STARTS`, `ENDS`, `CONTAINS`, `CUSTOM_SQL`, `ALWAYS_TRUE`, `ALWAYS_FALSE`.

## @Domain Annotation

`org.ujorm.annotation.@Domain` marks non-JPA POJOs or Records for APT metamodel generation
(alternative to `@Entity`/`@Table` when JPA is not desired):

```java
@Domain
public record Point(int x, int y) {}
// APT generates MetaPoint with Key<Point, Integer> x and y
```

## Notes

- Keys are singletons — compare with `==`, not `.equals()`.
- `Key` implements `Comparable` and can be sorted/used in sets.
- `Criterion` is purely a data structure; it is evaluated by `SelectQuery` or `SqlQuery`, not in-memory.
- This module is a transitive dependency of `ujo-orm`; usually declared indirectly.
