diff --git a/storm-core/src/main/java/st/orm/core/spi/DefaultSqlDialect.java b/storm-core/src/main/java/st/orm/core/spi/DefaultSqlDialect.java index 2c40b8ee9..6124263c4 100644 --- a/storm-core/src/main/java/st/orm/core/spi/DefaultSqlDialect.java +++ b/storm-core/src/main/java/st/orm/core/spi/DefaultSqlDialect.java @@ -134,7 +134,7 @@ public Pattern getValidIdentifierPattern() { "TABLESAMPLE", "THEN", "TIME", "TIMESTAMP", "TIMEZONE_HOUR", "TIMEZONE_MINUTE", "TO", "TRAILING", "TRANSLATE", "TRANSLATION", "TREAT", "TRIGGER", "TRIM", "TRUE", "UESCAPE", "UNDER", "UNION", "UNIQUE", "UNKNOWN", - "UNNEST", "UPDATE", "UPPER", "USER", "USING", "VALUE", "VALUES", "VAR_POP", + "UNNEST", "UPDATE", "UPPER", "USE", "USER", "USING", "VALUE", "VALUES", "VAR_POP", "VAR_SAMP", "VARBINARY", "VARCHAR", "VARYING", "VERSIONING", "WHEN", "WHENEVER", "WHERE", "WIDTH_BUCKET", "WINDOW", "WITH", "WITHIN", "WITHOUT", "YEAR" diff --git a/storm-core/src/main/java/st/orm/core/template/ORMTemplate.java b/storm-core/src/main/java/st/orm/core/template/ORMTemplate.java index 39ea6bd7d..bbb2a22ab 100644 --- a/storm-core/src/main/java/st/orm/core/template/ORMTemplate.java +++ b/storm-core/src/main/java/st/orm/core/template/ORMTemplate.java @@ -18,6 +18,7 @@ import jakarta.annotation.Nonnull; import java.sql.Connection; import java.util.List; +import java.util.function.Predicate; import java.util.function.UnaryOperator; import javax.sql.DataSource; import st.orm.Data; @@ -104,6 +105,28 @@ default List validateSchema() { throw new PersistenceException("Schema validation is not supported by this template."); } + /** + * Validates discovered types matching the filter against the database schema. + * + *

Discovers all entity and projection types via the classpath index, applies the given filter, and validates + * the matching types. This is useful when a single application connects to multiple datasources and only a + * subset of types is reachable from each connection.

+ * + *

Logs each validation error and returns the list of error messages. On success, logs a + * confirmation message and returns an empty list.

+ * + *

This method requires a DataSource-backed template. Templates created from a raw + * {@link Connection} or {@code EntityManager} do not support schema validation.

+ * + * @param filter predicate to select which discovered types to validate. + * @return the list of validation error messages (empty on success). + * @throws PersistenceException if the template does not support schema validation. + * @since 1.11 + */ + default List validateSchema(@Nonnull Predicate> filter) { + throw new PersistenceException("Schema validation is not supported by this template."); + } + /** * Validates the specified types against the database schema. * @@ -135,6 +158,24 @@ default void validateSchemaOrThrow() { throw new PersistenceException("Schema validation is not supported by this template."); } + /** + * Validates discovered types matching the filter and throws if any errors are found. + * + *

Discovers all entity and projection types via the classpath index, applies the given filter, and validates + * the matching types. This is useful when a single application connects to multiple datasources and only a + * subset of types is reachable from each connection.

+ * + *

This method requires a DataSource-backed template. Templates created from a raw + * {@link Connection} or {@code EntityManager} do not support schema validation.

+ * + * @param filter predicate to select which discovered types to validate. + * @throws PersistenceException if validation fails or the template does not support schema validation. + * @since 1.11 + */ + default void validateSchemaOrThrow(@Nonnull Predicate> filter) { + throw new PersistenceException("Schema validation is not supported by this template."); + } + /** * Validates the specified types and throws if any errors are found. * diff --git a/storm-core/src/main/java/st/orm/core/template/impl/ORMTemplateImpl.java b/storm-core/src/main/java/st/orm/core/template/impl/ORMTemplateImpl.java index caf95ba45..f6a6362bf 100644 --- a/storm-core/src/main/java/st/orm/core/template/impl/ORMTemplateImpl.java +++ b/storm-core/src/main/java/st/orm/core/template/impl/ORMTemplateImpl.java @@ -111,6 +111,11 @@ public List validateSchema() { return createSchemaValidator().validateAndReport(isStrictSchemaValidation()); } + @Override + public List validateSchema(@Nonnull Predicate> filter) { + return createSchemaValidator().validateAndReport(filter, isStrictSchemaValidation()); + } + @Override public List validateSchema(@Nonnull Iterable> types) { return createSchemaValidator().validateAndReport(types, isStrictSchemaValidation()); @@ -121,6 +126,11 @@ public void validateSchemaOrThrow() { createSchemaValidator().validateReportAndThrow(isStrictSchemaValidation()); } + @Override + public void validateSchemaOrThrow(@Nonnull Predicate> filter) { + createSchemaValidator().validateReportAndThrow(filter, isStrictSchemaValidation()); + } + @Override public void validateSchemaOrThrow(@Nonnull Iterable> types) { List errors = createSchemaValidator().validateAndReport(types, isStrictSchemaValidation()); diff --git a/storm-core/src/main/java/st/orm/core/template/impl/SchemaValidator.java b/storm-core/src/main/java/st/orm/core/template/impl/SchemaValidator.java index 836d346ef..497768d99 100644 --- a/storm-core/src/main/java/st/orm/core/template/impl/SchemaValidator.java +++ b/storm-core/src/main/java/st/orm/core/template/impl/SchemaValidator.java @@ -34,6 +34,7 @@ import java.util.SortedSet; import java.util.TreeMap; import java.util.TreeSet; +import java.util.function.Predicate; import java.util.stream.Collectors; import javax.sql.DataSource; import org.slf4j.Logger; @@ -202,6 +203,28 @@ public List validateAndReport(boolean strict) { return reportErrors(validate(types), strict, types.size()); } + /** + * Validates discovered types matching the filter, logs each finding, and returns the error messages. + * + *

Discovers all entity and projection types via the classpath index, applies the given filter, and validates + * the matching types.

+ * + *

In strict mode, all findings (including warnings like type narrowing and nullability mismatches) are treated + * as errors. In non-strict mode, warnings are logged at WARN level but excluded from the returned error list.

+ * + * @param filter predicate to select which discovered types to validate. + * @param strict whether to treat warnings as errors. + * @return the list of error messages (empty on success). + * @since 1.11 + */ + public List validateAndReport(@Nonnull Predicate> filter, boolean strict) { + LOGGER.info("Validating Data types for schema compatibility."); + List> types = TypeDiscovery.getDataTypes().stream() + .filter(filter) + .toList(); + return reportErrors(validate(types), strict, types.size()); + } + /** * Validates the specified types, logs each finding, and returns the error messages. * @@ -241,6 +264,21 @@ public void validateReportAndThrow(boolean strict) { } } + /** + * Validates discovered types matching the filter, reports errors with logging, and throws if any errors remain. + * + * @param filter predicate to select which discovered types to validate. + * @param strict whether to treat warnings as errors. + * @throws st.orm.PersistenceException if one or more validation errors are detected after reporting. + * @since 1.11 + */ + public void validateReportAndThrow(@Nonnull Predicate> filter, boolean strict) { + List errors = validateAndReport(filter, strict); + if (!errors.isEmpty()) { + throw new st.orm.PersistenceException(formatErrors(errors)); + } + } + private static List reportErrors( @Nonnull List validationErrors, boolean strict, diff --git a/storm-java21/src/main/java/st/orm/template/ORMTemplate.java b/storm-java21/src/main/java/st/orm/template/ORMTemplate.java index 92572bf5d..a19617999 100644 --- a/storm-java21/src/main/java/st/orm/template/ORMTemplate.java +++ b/storm-java21/src/main/java/st/orm/template/ORMTemplate.java @@ -18,6 +18,7 @@ import jakarta.annotation.Nonnull; import java.sql.Connection; import java.util.List; +import java.util.function.Predicate; import java.util.function.UnaryOperator; import javax.sql.DataSource; import st.orm.Data; @@ -105,6 +106,26 @@ public interface ORMTemplate extends QueryTemplate, RepositoryLookup { */ List validateSchema(); + /** + * Validates discovered types matching the filter against the database schema. + * + *

Discovers all entity and projection types via the classpath index, applies the given filter, and validates + * the matching types. This is useful when a single application connects to multiple datasources and only a + * subset of types is reachable from each connection.

+ * + *

Logs each validation error and returns the list of error messages. On success, logs a + * confirmation message and returns an empty list.

+ * + *

This method requires a DataSource-backed template. Templates created from a raw + * {@link Connection} or {@code EntityManager} do not support schema validation.

+ * + * @param filter predicate to select which discovered types to validate. + * @return the list of validation error messages (empty on success). + * @throws st.orm.PersistenceException if the template does not support schema validation. + * @since 1.11 + */ + List validateSchema(@Nonnull Predicate> filter); + /** * Validates the specified types against the database schema. * @@ -132,6 +153,22 @@ public interface ORMTemplate extends QueryTemplate, RepositoryLookup { */ void validateSchemaOrThrow(); + /** + * Validates discovered types matching the filter and throws if any errors are found. + * + *

Discovers all entity and projection types via the classpath index, applies the given filter, and validates + * the matching types. This is useful when a single application connects to multiple datasources and only a + * subset of types is reachable from each connection.

+ * + *

This method requires a DataSource-backed template. Templates created from a raw + * {@link Connection} or {@code EntityManager} do not support schema validation.

+ * + * @param filter predicate to select which discovered types to validate. + * @throws st.orm.PersistenceException if validation fails or the template does not support schema validation. + * @since 1.11 + */ + void validateSchemaOrThrow(@Nonnull Predicate> filter); + /** * Validates the specified types and throws if any errors are found. * diff --git a/storm-java21/src/main/java/st/orm/template/impl/ORMTemplateImpl.java b/storm-java21/src/main/java/st/orm/template/impl/ORMTemplateImpl.java index 4be42f1a3..6f77ace02 100644 --- a/storm-java21/src/main/java/st/orm/template/impl/ORMTemplateImpl.java +++ b/storm-java21/src/main/java/st/orm/template/impl/ORMTemplateImpl.java @@ -26,6 +26,7 @@ import java.lang.reflect.Type; import java.util.List; import java.util.Optional; +import java.util.function.Predicate; import st.orm.Data; import st.orm.Entity; import st.orm.EntityCallback; @@ -64,6 +65,11 @@ public List validateSchema() { return core.validateSchema(); } + @Override + public List validateSchema(@Nonnull Predicate> filter) { + return core.validateSchema(filter); + } + @Override public List validateSchema(@Nonnull Iterable> types) { return core.validateSchema(types); @@ -74,6 +80,11 @@ public void validateSchemaOrThrow() { core.validateSchemaOrThrow(); } + @Override + public void validateSchemaOrThrow(@Nonnull Predicate> filter) { + core.validateSchemaOrThrow(filter); + } + @Override public void validateSchemaOrThrow(@Nonnull Iterable> types) { core.validateSchemaOrThrow(types); diff --git a/storm-kotlin/src/main/kotlin/st/orm/template/ORMTemplate.kt b/storm-kotlin/src/main/kotlin/st/orm/template/ORMTemplate.kt index 6a72e11f4..cb1fc1242 100644 --- a/storm-kotlin/src/main/kotlin/st/orm/template/ORMTemplate.kt +++ b/storm-kotlin/src/main/kotlin/st/orm/template/ORMTemplate.kt @@ -99,6 +99,26 @@ interface ORMTemplate : */ fun validateSchema(): List + /** + * Validates discovered types matching the filter against the database schema. + * + * Discovers all entity and projection types via the classpath index, applies the given filter, and validates + * the matching types. This is useful when a single application connects to multiple datasources and only a + * subset of types is reachable from each connection. + * + * Logs each validation error and returns the list of error messages. On success, logs a + * confirmation message and returns an empty list. + * + * This method requires a DataSource-backed template. Templates created from a raw + * [java.sql.Connection] or `EntityManager` do not support schema validation. + * + * @param filter predicate to select which discovered types to validate. + * @return the list of validation error messages (empty on success). + * @throws st.orm.PersistenceException if the template does not support schema validation. + * @since 1.11 + */ + fun validateSchema(filter: (KClass) -> Boolean): List + /** * Validates the specified types against the database schema. * @@ -126,6 +146,22 @@ interface ORMTemplate : */ fun validateSchemaOrThrow() + /** + * Validates discovered types matching the filter and throws if any errors are found. + * + * Discovers all entity and projection types via the classpath index, applies the given filter, and validates + * the matching types. This is useful when a single application connects to multiple datasources and only a + * subset of types is reachable from each connection. + * + * This method requires a DataSource-backed template. Templates created from a raw + * [java.sql.Connection] or `EntityManager` do not support schema validation. + * + * @param filter predicate to select which discovered types to validate. + * @throws st.orm.PersistenceException if validation fails or the template does not support schema validation. + * @since 1.11 + */ + fun validateSchemaOrThrow(filter: (KClass) -> Boolean) + /** * Validates the specified types and throws if any errors are found. * diff --git a/storm-kotlin/src/main/kotlin/st/orm/template/impl/ORMTemplateImpl.kt b/storm-kotlin/src/main/kotlin/st/orm/template/impl/ORMTemplateImpl.kt index 5350e3feb..8b3edfa37 100644 --- a/storm-kotlin/src/main/kotlin/st/orm/template/impl/ORMTemplateImpl.kt +++ b/storm-kotlin/src/main/kotlin/st/orm/template/impl/ORMTemplateImpl.kt @@ -88,10 +88,14 @@ class ORMTemplateImpl(private val core: st.orm.core.template.ORMTemplate) : override fun validateSchema(): List = core.validateSchema() + override fun validateSchema(filter: (KClass) -> Boolean): List = core.validateSchema { filter(it.kotlin) } + override fun validateSchema(vararg types: KClass): List = core.validateSchema(types.map { it.java }) override fun validateSchemaOrThrow() = core.validateSchemaOrThrow() + override fun validateSchemaOrThrow(filter: (KClass) -> Boolean) = core.validateSchemaOrThrow { filter(it.kotlin) } + override fun validateSchemaOrThrow(vararg types: KClass) = core.validateSchemaOrThrow(types.map { it.java }) /**