diff --git a/api/src/main/java/jakarta/data/BasicRestriction.java b/api/src/main/java/jakarta/data/BasicRestriction.java
new file mode 100644
index 000000000..a59ab7426
--- /dev/null
+++ b/api/src/main/java/jakarta/data/BasicRestriction.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2024 Contributors to the Eclipse Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+package jakarta.data;
+
+/**
+ * A basic restriction applies to a single field, representing conditions such as equality,
+ * comparisons, range checks, and pattern matches.
+ *
+ * <p>The {@code BasicRestriction} interface provides methods for defining simple, singular restrictions
+ * based on a specific field, an operator, and an optional comparison value. This interface supports
+ * common operators (e.g., EQUAL, GREATER_THAN) and serves as a foundation for filtering
+ * logic on individual fields.</p>
+ *
+ * @param <T> the type of the entity on which the restriction is applied.
+ */
+public interface BasicRestriction<T> extends Restriction<T> {
+
+    /**
+     * The name of the field on which this restriction is applied.
+     *
+     * @return the field name as a String.
+     */
+    String field();
+
+    /**
+     * The operator defining the type of comparison or condition for this restriction.
+     *
+     * @return the operator representing the restriction type (e.g., EQUAL, LIKE, BETWEEN).
+     */
+    Operator operator();
+
+    /**
+     * The value used for comparison in this restriction, if applicable.
+     *
+     * @return the comparison value, or {@code null} if the restriction does not use a value (e.g., IS_NULL).
+     */
+    Object value();
+}
diff --git a/api/src/main/java/jakarta/data/CompositeRestriction.java b/api/src/main/java/jakarta/data/CompositeRestriction.java
new file mode 100644
index 000000000..d829b62f2
--- /dev/null
+++ b/api/src/main/java/jakarta/data/CompositeRestriction.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2024 Contributors to the Eclipse Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+package jakarta.data;
+
+import java.util.List;
+
+/**
+ * A composite restriction that combines multiple {@link Restriction} instances using logical operators.
+ *
+ * <p>The {@code MultipleRestriction} interface allows for combining multiple restrictions, enabling complex
+ * filtering scenarios where multiple conditions must be satisfied. Each contained {@link Restriction}
+ * can be evaluated based on the logical operator specified by the {@link CompositeRestrictionType} type.</p>
+ *
+ * <p>This interface is useful for defining AND/OR conditions where multiple fields and restrictions
+ * are evaluated together in a repository query.</p>
+ *
+ * @param <T> the type of the entity on which the restriction is applied.
+ */
+public interface CompositeRestriction<T> extends Restriction<T> {
+
+    /**
+     * The list of restrictions that are combined in this composite restriction.
+     *
+     * @return a list of individual restrictions.
+     */
+    List<Restriction<? extends T>> restrictions();
+
+    /**
+     * The logical operator used to combine the contained restrictions, such as AND or OR.
+     *
+     * @return the logical combination type for this composite restriction.
+     */
+    CompositeRestrictionType type();
+}
diff --git a/api/src/main/java/jakarta/data/CompositeRestrictionRecord.java b/api/src/main/java/jakarta/data/CompositeRestrictionRecord.java
new file mode 100644
index 000000000..2cb9a7452
--- /dev/null
+++ b/api/src/main/java/jakarta/data/CompositeRestrictionRecord.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2024 Contributors to the Eclipse Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+package jakarta.data;
+
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * A composite restriction representing a collection of individual {@link Restriction}
+ * and {@link CompositeRestrictionType} instances, combined under a single logical operation.
+ *
+ * <p>This record allows multiple restrictions to be treated as a single entity, making
+ * it easy to pass complex conditions to repository methods.</p>
+ *
+ * @param <T> the entity type that the restrictions apply to.
+ */
+record CompositeRestrictionRecord<T>(CompositeRestrictionType type, List<Restriction<? extends T>> restrictions)
+        implements Iterable<Restriction<? extends T>>, CompositeRestriction<T> {
+
+    /**
+     * Constructs a composite restriction with the specified operator and list of restrictions.
+     *
+     * @param restrictions the list of restrictions to combine.
+     */
+    public CompositeRestrictionRecord {
+        restrictions = List.copyOf(restrictions); // Ensure immutability of the list
+    }
+
+    @Override
+    public Iterator<Restriction<? extends T>> iterator() {
+        return restrictions.iterator();
+    }
+
+    /**
+     * Creates a composite restriction where all specified restrictions must be true (AND logic).
+     *
+     * @param restrictions the individual restrictions to combine.
+     * @param <T>          the entity type that the restrictions apply to.
+     * @return a CompositeRestriction representing the AND combination of the provided restrictions.
+     */
+    @SafeVarargs
+    public static <T> CompositeRestrictionRecord<T> all(Restriction<T>... restrictions) {
+        return new CompositeRestrictionRecord<>(CompositeRestrictionType.ALL, List.of(restrictions));
+    }
+
+    /**
+     * Creates a composite restriction where any of the specified restrictions may be true (OR logic).
+     *
+     * @param restrictions the individual restrictions to combine.
+     * @param <T>          the entity type that the restrictions apply to.
+     * @return a CompositeRestriction representing the OR combination of the provided restrictions.
+     */
+    @SafeVarargs
+    public static <T> CompositeRestrictionRecord<T> any(Restriction<T>... restrictions) {
+        return new CompositeRestrictionRecord<>(CompositeRestrictionType.ANY, List.of(restrictions));
+    }
+
+}
diff --git a/api/src/main/java/jakarta/data/CompositeRestrictionType.java b/api/src/main/java/jakarta/data/CompositeRestrictionType.java
new file mode 100644
index 000000000..e96b2ded4
--- /dev/null
+++ b/api/src/main/java/jakarta/data/CompositeRestrictionType.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2024 Contributors to the Eclipse Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+package jakarta.data;
+
+
+/**
+ * Represents the logical operators used to combine multiple restrictions in a query.
+ *
+ * <p>The `Restrict` enum defines two types of logical combinations:</p>
+ * <ul>
+ *   <li><b>ALL</b> - Requires that all contained restrictions are satisfied (logical AND).</li>
+ *   <li><b>ANY</b> - Requires that at least one of the contained restrictions is satisfied (logical OR).</li>
+ * </ul>
+ *
+ * <p>This enum is typically used in {@link CompositeRestriction} to specify how its list of
+ * restrictions should be combined, allowing for flexible and complex query conditions.</p>
+ */
+public enum CompositeRestrictionType {
+    /**
+     * Requires that all contained restrictions must be satisfied (logical AND).
+     */
+    ALL,
+
+    /**
+     * Requires that at least one of the contained restrictions must be satisfied (logical OR).
+     */
+    ANY
+}
diff --git a/api/src/main/java/jakarta/data/Operator.java b/api/src/main/java/jakarta/data/Operator.java
new file mode 100644
index 000000000..8a184ba8d
--- /dev/null
+++ b/api/src/main/java/jakarta/data/Operator.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2024 Contributors to the Eclipse Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ */
+package jakarta.data;
+
+
+/**
+ * Enum representing common operators used to define query conditions in Jakarta Data queries.
+ * The {@code Operator} enum provides a set of operations to specify how values should be compared,
+ * matched, or restricted when filtering data, supporting flexible and expressive querying across
+ * different contexts.
+ */
+public enum Operator {
+
+    /**
+     * Matches records where the field value is exactly equal to the specified value.
+     * Typically used for exact matching on unique identifiers, names, or other exact-value fields.
+     */
+    EQUAL,
+
+    /**
+     * Matches records where the field value is greater than the specified value.
+     * Often applied to numerical fields (e.g., dates, prices) for retrieving values above a given threshold.
+     */
+    GREATER_THAN,
+
+    /**
+     * Matches records where the field value is greater than or equal to the specified value.
+     * Useful for inclusive range queries, where the specified boundary is included in the results.
+     */
+    GREATER_THAN_EQUAL,
+
+    /**
+     * Matches records where the field value is contained within a specified collection of values.
+     * Commonly used to match against multiple possible values, such as category or status lists.
+     */
+    IN,
+
+    /**
+     * Matches records where the field value is less than the specified value.
+     * Frequently used in numerical comparisons to retrieve values below a certain threshold.
+     */
+    LESS_THAN,
+
+    /**
+     * Matches records where the field value is less than or equal to the specified value.
+     * Suitable for inclusive range queries that include the specified boundary in the results.
+     */
+    LESS_THAN_EQUAL,
+
+    /**
+     * Matches records where the field value conforms to a specified pattern, often with wildcards.
+     * Commonly applied to string fields for partial matches (e.g., names containing a substring).
+     */
+    LIKE,
+
+    /**
+     * Matches records where the field value falls within a specified range.
+     * Typically used for range-based comparisons, such as finding dates between a start and end date.
+     */
+    BETWEEN
+}
+
+
+
diff --git a/api/src/main/java/jakarta/data/Order.java b/api/src/main/java/jakarta/data/Order.java
index 3cc99a502..02b7d4a69 100644
--- a/api/src/main/java/jakarta/data/Order.java
+++ b/api/src/main/java/jakarta/data/Order.java
@@ -17,12 +17,12 @@
  */
 package jakarta.data;
 
-import java.util.Iterator;
-import java.util.List;
-
 import jakarta.data.metamodel.StaticMetamodel;
 import jakarta.data.repository.OrderBy;
 
+import java.util.Iterator;
+import java.util.List;
+
 /**
  * <p>Requests sorting on various entity attributes.</p>
  *
@@ -169,4 +169,4 @@ public Iterator<Sort<? super T>> iterator() {
     public String toString() {
         return sorts.toString();
     }
-}
\ No newline at end of file
+}
diff --git a/api/src/main/java/jakarta/data/Pattern.java b/api/src/main/java/jakarta/data/Pattern.java
new file mode 100644
index 000000000..71487feb7
--- /dev/null
+++ b/api/src/main/java/jakarta/data/Pattern.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2024 Contributors to the Eclipse Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+package jakarta.data;
+
+
+/**
+ * Represents a pattern for use in string matching conditions. This class supports options
+ * such as exact match, prefix, suffix, and substring matching. It is intended to be used
+ * with attributes that apply the pattern to create a {@link Restriction}.
+ *
+ * <p>Example usage:</p>
+ * <pre>
+ * // Pattern for a case-sensitive prefix match for values starting with "Guide"
+ * Pattern prefixMatch = Pattern.startsWith("Guide");
+ *
+ * // Pattern for matching values containing "Java"
+ * Pattern containsMatch = Pattern.contains("Java");
+ * </pre>
+ */
+public record Pattern(String value, boolean caseSensitive) {
+
+    /**
+     * Creates a pattern for an exact match with the specified literal.
+     *
+     * <p>Example usage:</p>
+     * <pre>
+     * Pattern exactMatch = Pattern.is("Java Guide");
+     * </pre>
+     *
+     * @param literal the exact text to match.
+     * @return a {@code Pattern} instance for an exact match.
+     */
+    public static Pattern is(String literal) {
+        return new Pattern(escape(literal), true);
+    }
+
+    /**
+     * Creates a pattern for a custom match.
+     *
+     * <p>Example usage:</p>
+     * <pre>
+     * Pattern customPatternMatch = Pattern.matches("Ja%_a");
+     * </pre>
+     *
+     * @param pattern the pattern to match.
+     * @return a {@code Pattern} instance for a custom match.
+     */
+    public static Pattern matches(String pattern) {
+        return new Pattern(pattern, true);
+    }
+
+    /**
+     * Creates a pattern using custom single and multi-character wildcards.
+     *
+     * <p>Example usage:</p>
+     * <pre>
+     * Pattern wildcardMatch = Pattern.matches("Ja?a%", '?', '*');
+     * </pre>
+     *
+     * @param pattern           the custom pattern to match.
+     * @param characterWildcard the character to use as a single-character wildcard.
+     * @param stringWildcard    the character to use as a multi-character wildcard.
+     * @return a {@code Pattern} instance for a custom match with specified wildcards.
+     */
+    public static Pattern matches(String pattern, char characterWildcard, char stringWildcard) {
+        final String standardized = escape(pattern)
+                .replace(characterWildcard, '_')
+                .replace(stringWildcard, '%');
+        return new Pattern(standardized, true);
+    }
+
+    /**
+     * Creates a pattern for a match where values start with the specified prefix.
+     *
+     * <p>Example usage:</p>
+     * <pre>
+     * Pattern prefixMatch = Pattern.startsWith("Hibernate");
+     * </pre>
+     *
+     * @param prefix the prefix to match at the beginning of the value.
+     * @return a {@code Pattern} instance for a prefix match.
+     */
+    public static Pattern startsWith(String prefix) {
+        return new Pattern(escape(prefix) + '%', true);
+    }
+
+    /**
+     * Creates a pattern for a match where values end with the specified suffix.
+     *
+     * <p>Example usage:</p>
+     * <pre>
+     * Pattern suffixMatch = Pattern.endsWith("Guide");
+     * </pre>
+     *
+     * @param suffix the suffix to match at the end of the value.
+     * @return a {@code Pattern} instance for a suffix match.
+     */
+    public static Pattern endsWith(String suffix) {
+        return new Pattern('%' + escape(suffix), true);
+    }
+
+    /**
+     * Creates a pattern for a match where values contain the specified substring.
+     *
+     * <p>Example usage:</p>
+     * <pre>
+     * Pattern substringMatch = Pattern.contains("Java");
+     * </pre>
+     *
+     * @param substring the substring to match within the value.
+     * @return a {@code Pattern} instance for a substring match.
+     */
+    public static Pattern contains(String substring) {
+        return new Pattern('%' + escape(substring) + '%', true);
+    }
+
+    /**
+     * Escapes special characters in the pattern, such as underscores and percent signs,
+     * to ensure literal matches for these characters.
+     *
+     * @param literal the text to escape.
+     * @return the escaped text with special characters handled.
+     */
+    private static String escape(String literal) {
+        return literal.replace("_", "\\_").replace("%", "\\%");
+    }
+}
+
+
diff --git a/api/src/main/java/jakarta/data/Restrict.java b/api/src/main/java/jakarta/data/Restrict.java
new file mode 100644
index 000000000..217fb50f4
--- /dev/null
+++ b/api/src/main/java/jakarta/data/Restrict.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2024 Contributors to the Eclipse Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+package jakarta.data;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Utility class for constructing complex restrictions in repository queries.
+ * The `Restrict` class provides static methods for creating basic and composite
+ * restrictions, supporting conditions like equality, comparisons, and logical
+ * combinations (`ALL` and `ANY`).
+ *
+ * <p>Example usage:</p>
+ * <pre>
+ * // Create a single equality restriction
+ * Restriction<Book> titleRestriction = Restrict.equalTo("Java Guide", "title");
+ *
+ * // Create a composite restriction using AND logic
+ * Restriction<Book> compositeRestriction = Restrict.all(
+ *     Restrict.equalTo("Java Guide", "title"),
+ *     Restrict.greaterThan(2020, "publicationYear")
+ * );
+ * </pre>
+ */
+public final class Restrict {
+
+    private Restrict() {
+    }
+
+    /**
+     * Creates a composite restriction that requires all specified restrictions to be met.
+     *
+     * @param restrictions the list of restrictions to combine with AND logic.
+     * @param <T> the entity type.
+     * @return a composite restriction using AND logic.
+     */
+    @SafeVarargs
+    public static <T> Restriction<T> all(Restriction<T>... restrictions) {
+        return new CompositeRestrictionRecord<>(CompositeRestrictionType.ALL, List.of(restrictions));
+    }
+
+    /**
+     * Creates a composite restriction that requires at least one of the specified restrictions to be met.
+     *
+     * @param restrictions the list of restrictions to combine with OR logic.
+     * @param <T> the entity type.
+     * @return a composite restriction using OR logic.
+     */
+    @SafeVarargs
+    public static <T> Restriction<T> any(Restriction<T>... restrictions) {
+        return new CompositeRestrictionRecord<>(CompositeRestrictionType.ANY, List.of(restrictions));
+    }
+
+    /**
+     * Creates an equality restriction for the specified field and value.
+     *
+     * @param value the value to match exactly.
+     * @param field the name of the field to apply the restriction on.
+     * @param <T> the entity type.
+     * @return an equality restriction for the specified field.
+     */
+    public static <T> Restriction<T> equalTo(Object value, String field) {
+        return new RestrictionRecord<>(field, Operator.EQUAL, value);
+    }
+
+    /**
+     * Creates a "less than" restriction for the specified field and value.
+     *
+     * @param value the upper bound (exclusive) for the field.
+     * @param field the name of the field to apply the restriction on.
+     * @param <T> the entity type.
+     * @return a "less than" restriction for the specified field.
+     */
+    public static <T> Restriction<T> lessThan(Object value, String field) {
+        return new RestrictionRecord<>(field, Operator.LESS_THAN, value);
+    }
+
+    /**
+     * Creates a "greater than or equal to" restriction for the specified field and value.
+     *
+     * @param value the lower bound (inclusive) for the field.
+     * @param field the name of the field to apply the restriction on.
+     * @param <T> the entity type.
+     * @return a "greater than or equal to" restriction for the specified field.
+     */
+    public static <T> Restriction<T> greaterThanEqual(Object value, String field) {
+        return new RestrictionRecord<>(field, Operator.GREATER_THAN_EQUAL, value);
+    }
+
+    /**
+     * Creates a "less than or equal to" restriction for the specified field and value.
+     *
+     * @param value the upper bound (inclusive) for the field.
+     * @param field the name of the field to apply the restriction on.
+     * @param <T> the entity type.
+     * @return a "less than or equal to" restriction for the specified field.
+     */
+    public static <T> Restriction<T> lessThanEqual(Object value, String field) {
+        return new RestrictionRecord<>(field, Operator.LESS_THAN_EQUAL, value);
+    }
+
+    /**
+     * Creates a "greater than" restriction for the specified field and value.
+     *
+     * @param value the lower bound (exclusive) for the field.
+     * @param field the name of the field to apply the restriction on.
+     * @param <T> the entity type.
+     * @return a "greater than" restriction for the specified field.
+     */
+    public static <T> Restriction<T> greaterThan(Object value, String field) {
+        return new RestrictionRecord<>(field, Operator.GREATER_THAN, value);
+    }
+
+    /**
+     * Creates an "in" restriction, restricting the field to match any value in the specified set.
+     *
+     * @param values the set of allowed values for the field.
+     * @param field the name of the field to apply the restriction on.
+     * @param <T> the entity type.
+     * @return an "in" restriction for the specified field.
+     */
+    public static <T> Restriction<T> in(Set<Object> values, String field) {
+        return new RestrictionRecord<>(field, Operator.IN, values);
+    }
+
+    /**
+     * Creates a restriction that matches field values containing the specified substring.
+     *
+     * <p>Example usage:</p>
+     * <pre>
+     * Restriction<Book> containsMatch = Restrict.contains("Java", "title");
+     * </pre>
+     *
+     * @param value the substring to search for within the field's value.
+     * @param field the name of the field to apply the restriction on.
+     * @param <T> the entity type.
+     * @return a restriction that matches values containing the specified substring.
+     */
+    public static <T> Restriction<T> contains(String value, String field) {
+        var contains = Pattern.contains(value);
+        return new RestrictionRecord<>(field, Operator.LIKE, contains.value());
+    }
+
+    /**
+     * Creates a restriction that matches field values starting with the specified prefix.
+     *
+     * <p>Example usage:</p>
+     * <pre>
+     * Restriction<Book> startsWithMatch = Restrict.startsWith("Guide", "title");
+     * </pre>
+     *
+     * @param value the prefix to match at the beginning of the field's value.
+     * @param field the name of the field to apply the restriction on.
+     * @param <T> the entity type.
+     * @return a restriction that matches values starting with the specified prefix.
+     */
+    public static <T> Restriction<T> startsWith(String value, String field) {
+        var contains = Pattern.startsWith(value);
+        return new RestrictionRecord<>(field, Operator.LIKE, contains.value());
+    }
+
+    /**
+     * Creates a restriction that matches field values ending with the specified suffix.
+     *
+     * <p>Example usage:</p>
+     * <pre>
+     * Restriction<Book> endsWithMatch = Restrict.endsWith("Guide", "title");
+     * </pre>
+     *
+     * @param value the suffix to match at the end of the field's value.
+     * @param field the name of the field to apply the restriction on.
+     * @param <T> the entity type.
+     * @return a restriction that matches values ending with the specified suffix.
+     */
+    public static <T> Restriction<T> endsWith(String value, String field) {
+        var contains = Pattern.endsWith(value);
+        return new RestrictionRecord<>(field, Operator.LIKE, contains.value());
+    }
+
+    /**
+     * Creates a restriction that matches field values ending with the specified pattern.
+     *
+     * <p>Example usage:</p>
+     * <pre>
+     * Pattern pattern = Pattern.endsWith("Guide");
+     * Restriction<Book> endsWithPatternMatch = Restrict.endsWith(pattern, "title");
+     * </pre>
+     *
+     * @param pattern the pattern to match at the end of the field's value.
+     * @param field the name of the field to apply the restriction on.
+     * @param <T> the entity type.
+     * @return a restriction that matches values ending with the specified pattern.
+     */
+    public static <T> Restriction<T> endsWith(Pattern pattern, String field) {
+        return new RestrictionRecord<>(field, Operator.LIKE, pattern.value());
+    }
+}
diff --git a/api/src/main/java/jakarta/data/Restriction.java b/api/src/main/java/jakarta/data/Restriction.java
new file mode 100644
index 000000000..cdb962178
--- /dev/null
+++ b/api/src/main/java/jakarta/data/Restriction.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2024 Contributors to the Eclipse Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+package jakarta.data;
+
+
+/**
+ * Represents a condition used to filter values in repository queries.
+ *
+ * <p>The `Restriction` interface serves as a general contract for defining filter conditions,
+ * supporting various operations such as equality, comparisons, range, null checks,
+ * and pattern matching. Implementations of `Restriction` can be used to construct
+ * flexible and type-safe filtering logic in repository queries.</p>
+ *
+ * <p>Subtypes include {@link BasicRestriction}, which handles single-field conditions,
+ * and {@link CompositeRestriction}, which combines multiple restrictions
+ * using logical operators.</p>
+ *
+ * @param <T> the type of the entity on which the restriction is applied.
+ */
+public interface Restriction<T> {
+
+
+}
diff --git a/api/src/main/java/jakarta/data/RestrictionRecord.java b/api/src/main/java/jakarta/data/RestrictionRecord.java
new file mode 100644
index 000000000..be1a1335e
--- /dev/null
+++ b/api/src/main/java/jakarta/data/RestrictionRecord.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2024 Contributors to the Eclipse Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+package jakarta.data;
+
+/**
+ * A basic implementation of the `Restriction` interface, representing various conditions
+ * used in repository queries, including equality, comparison, and range checks.
+ *
+ * @param <T> the type of the entity on which the restriction is applied.
+ */
+record RestrictionRecord<T>(String field, Operator operator, Object value) implements BasicRestriction<T> {
+
+    /**
+     * Constructs a `BasicRestriction` with the specified field, operator, and value.
+     *
+     * @param field    the name of the field to apply the restriction to.
+     * @param operator the operator defining the comparison or condition.
+     * @param value    the value to compare the field against (optional for null checks).
+     */
+    public RestrictionRecord {
+        if (field == null || operator == null) {
+            throw new IllegalArgumentException("Field and operator must not be null.");
+        }
+    }
+}
diff --git a/api/src/main/java/jakarta/data/metamodel/Attribute.java b/api/src/main/java/jakarta/data/metamodel/Attribute.java
index 2906554d6..6cb3efd9a 100644
--- a/api/src/main/java/jakarta/data/metamodel/Attribute.java
+++ b/api/src/main/java/jakarta/data/metamodel/Attribute.java
@@ -17,6 +17,8 @@
  */
 package jakarta.data.metamodel;
 
+import jakarta.data.Restrict;
+import jakarta.data.Restriction;
 import jakarta.data.Sort;
 
 /**
@@ -32,4 +34,23 @@ public interface Attribute<T> {
      * @return the entity attribute name.
      */
     String name();
+
+    /**
+     * Creates an equality restriction for the attribute.
+     *
+     * @param value the value to match exactly.
+     * @return a Restriction representing an equality condition.
+     */
+    default Restriction<T> equal(Object value) {
+      return Restrict.equalTo(value, name());
+    }
+
+    /**
+     * Creates a restriction for checking if the attribute is null.
+     *
+     * @return a Restriction representing the condition where the attribute is null.
+     */
+    default Restriction<T> isNull(){
+        return Restrict.equalTo(null, name());
+    }
 }
diff --git a/api/src/main/java/jakarta/data/metamodel/Range.java b/api/src/main/java/jakarta/data/metamodel/Range.java
new file mode 100644
index 000000000..a7577c4f1
--- /dev/null
+++ b/api/src/main/java/jakarta/data/metamodel/Range.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2024 Contributors to the Eclipse Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+package jakarta.data.metamodel;
+
+import jakarta.data.BasicRestriction;
+import jakarta.data.Operator;
+import jakarta.data.Restriction;
+
+import java.util.List;
+
+/**
+ * Represents a range-based restriction for repository queries, allowing comparisons within
+ * a specified range or boundary on a particular entity attribute.
+ *
+ * <p>This class implements {@link Restriction <T>} and provides flexible factory methods
+ * to create range-based conditions, supporting inclusive and exclusive bounds.</p>
+ *
+ * <p>Usage examples:</p>
+ * <pre>
+ * // A range between two dates (inclusive)
+ * Restriction<Book> publicationDateRange = Range.between(_Book.publicationDate, pastDate, LocalDate.now());
+ *
+ * // An exclusive range above a certain rating
+ * Restriction<Book> ratingAbove = Range.above(_Book.rating, 4.5);
+ *
+ * // An inclusive range up to a certain price
+ * Restriction<Book> priceTo = Range.to(_Book.price, 100);
+ * </pre>
+ *
+ * <p>The `operator()` method dynamically determines the appropriate operator based on the range type:</p>
+ * <ul>
+ *     <li>If both bounds are specified, {@code Operator.BETWEEN} is used.</li>
+ *     <li>If only the lower bound is specified and the range is exclusive, {@code Operator.GREATER_THAN} is used.</li>
+ *     <li>If only the lower bound is specified and the range is inclusive, {@code Operator.GREATER_THAN_EQUAL} is used.</li>
+ *     <li>If only the upper bound is specified and the range is exclusive, {@code Operator.LESS_THAN} is used.</li>
+ *     <li>If only the upper bound is specified and the range is inclusive, {@code Operator.LESS_THAN_EQUAL} is used.</li>
+ * </ul>
+ *
+ * @param <T> the type of the entity's attribute on which the range is applied.
+ */
+public record Range<T>(String field, T lowerBound, T upperBound, boolean open) implements BasicRestriction<T> {
+
+    @Override
+    public String field() {
+        return field;
+    }
+
+    @Override
+    public Operator operator() {
+        if (lowerBound != null && upperBound != null) {
+            return Operator.BETWEEN;
+        } else if (lowerBound != null && open) {
+            return Operator.GREATER_THAN;
+        } else if (lowerBound != null) {
+            return Operator.GREATER_THAN_EQUAL;
+        } else if (upperBound != null && open) {
+            return Operator.LESS_THAN;
+        } else {
+            return Operator.LESS_THAN_EQUAL;
+        }
+    }
+
+    @Override
+    public Object value() {
+        if (lowerBound != null && upperBound != null) {
+            return List.of(lowerBound, upperBound);
+        }
+        return lowerBound != null ? lowerBound : upperBound;
+    }
+
+    public static <T> Range<T> between(String field, T lowerBound, T upperBound) {
+        return new Range<>(field, lowerBound, upperBound, false);
+    }
+
+    public static <T> Range<T> from(String field, T lowerBound) {
+        return new Range<>(field, lowerBound, null, false);
+    }
+
+    public static <T> Range<T> to(String field, T upperBound) {
+        return new Range<>(field, null, upperBound, false);
+    }
+
+    public static <T> Range<T> above(String field, T lowerBound) {
+        return new Range<>(field, lowerBound, null, true);
+    }
+
+    public static <T> Range<T> below(String field, T upperBound) {
+        return new Range<>(field, null, upperBound, true);
+    }
+}
diff --git a/api/src/main/java/jakarta/data/metamodel/SortableAttribute.java b/api/src/main/java/jakarta/data/metamodel/SortableAttribute.java
index 559960a41..bd1a64ed0 100644
--- a/api/src/main/java/jakarta/data/metamodel/SortableAttribute.java
+++ b/api/src/main/java/jakarta/data/metamodel/SortableAttribute.java
@@ -17,6 +17,8 @@
  */
 package jakarta.data.metamodel;
 
+import jakarta.data.Restrict;
+import jakarta.data.Restriction;
 import jakarta.data.Sort;
 
 /**
@@ -49,4 +51,95 @@ public interface SortableAttribute<T> extends Attribute<T> {
      */
     Sort<T> desc();
 
+    /**
+     * Creates a restriction for values greater than the specified value.
+     *
+     * @param value the lower bound (exclusive) for the attribute.
+     * @return a Restriction representing a greater-than condition.
+     */
+    default Restriction<T> greaterThan(Object value) {
+        return  Restrict.greaterThan(value, name());
+    }
+
+    /**
+     * Creates a restriction for values greater than or equal to the specified value.
+     *
+     * @param value the lower bound (inclusive) for the attribute.
+     * @return a Restriction representing a greater-than-or-equal condition.
+     */
+    default Restriction<T> greaterThanEqual(Object value) {
+        return  Restrict.greaterThanEqual(value, name());
+    }
+
+    /**
+     * Creates a restriction for values less than the specified value.
+     *
+     * @param value the upper bound (exclusive) for the attribute.
+     * @return a Restriction representing a less-than condition.
+     */
+    default Restriction<T> lessThan(Object value) {
+        return  Restrict.lessThan(value, name());
+    }
+
+    /**
+     * Creates a restriction for values less than or equal to the specified value.
+     *
+     * @param value the upper bound (inclusive) for the attribute.
+     * @return a Restriction representing a less-than-or-equal condition.
+     */
+    default Restriction<T> lessThanOrEqual(Object value) {
+        return  Restrict.lessThanEqual(value, name());
+    }
+
+    /**
+     * Creates a restriction for values within the specified range, inclusive of both bounds.
+     *
+     * @param lowerBound the lower bound (inclusive).
+     * @param upperBound the upper bound (inclusive).
+     * @return a Restriction representing a range condition.
+     */
+    default Range<T> between(T lowerBound, T upperBound) {
+        return Range.between(name(), lowerBound, upperBound);
+    }
+
+    /**
+     * Creates a restriction for values greater than or equal to the specified lower bound.
+     *
+     * @param lowerBound the lower bound (inclusive).
+     * @return a Restriction representing a "greater than or equal" condition.
+     */
+    default Range<T> from(T lowerBound) {
+        return Range.from(name(), lowerBound);
+    }
+
+    /**
+     * Creates a restriction for values less than or equal to the specified upper bound.
+     *
+     * @param upperBound the upper bound (inclusive).
+     * @return a Restriction representing a "less than or equal" condition.
+     */
+    default Range<T> to(T upperBound) {
+        return Range.to(name(), upperBound);
+    }
+
+    /**
+     * Creates a restriction for values greater than the specified lower bound (exclusive).
+     *
+     * @param lowerBound the lower bound (exclusive).
+     * @return a Restriction representing a "greater than" condition.
+     */
+    default Range<T> above(T lowerBound) {
+        return Range.above(name(), lowerBound);
+    }
+
+    /**
+     * Creates a restriction for values less than the specified upper bound (exclusive).
+     *
+     * @param upperBound the upper bound (exclusive).
+     * @return a Restriction representing a "less than" condition.
+     */
+    default Range<T> below(T upperBound) {
+        return Range.below(name(), upperBound);
+    }
+
 }
diff --git a/api/src/main/java/jakarta/data/metamodel/StaticMetamodel.java b/api/src/main/java/jakarta/data/metamodel/StaticMetamodel.java
index b0a4f47a5..1e644833f 100644
--- a/api/src/main/java/jakarta/data/metamodel/StaticMetamodel.java
+++ b/api/src/main/java/jakarta/data/metamodel/StaticMetamodel.java
@@ -17,14 +17,14 @@
  */
 package jakarta.data.metamodel;
 
+import jakarta.data.Sort;
+
 import java.lang.annotation.Documented;
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
-import jakarta.data.Sort;
-
 /**
  * <p>Annotates a class which serves as a static metamodel for an entity, enabling
  * type-safe access to entity attribute names and related objects such as instances
diff --git a/api/src/main/java/jakarta/data/metamodel/TextAttribute.java b/api/src/main/java/jakarta/data/metamodel/TextAttribute.java
index c00390f09..351ab5ccd 100644
--- a/api/src/main/java/jakarta/data/metamodel/TextAttribute.java
+++ b/api/src/main/java/jakarta/data/metamodel/TextAttribute.java
@@ -17,10 +17,16 @@
  */
 package jakarta.data.metamodel;
 
+import jakarta.data.Operator;
+import jakarta.data.Pattern;
+import jakarta.data.Restrict;
+import jakarta.data.Restriction;
 import jakarta.data.Sort;
+import jakarta.data.metamodel.impl.BasicRestrictionRecord;
+
 
 /**
- * Represents an textual entity attribute in the {@link StaticMetamodel}.
+ * Represents a textual entity attribute in the {@link StaticMetamodel}.
  *
  * @param <T> entity class of the static metamodel.
  */
@@ -40,4 +46,55 @@ public interface TextAttribute<T> extends SortableAttribute<T> {
      */
     Sort<T> descIgnoreCase();
 
+    /**
+     * Creates a `LIKE` restriction for a match on the specified text.
+     *
+     * @param text the text to match.
+     * @return a Restriction representing a `LIKE` condition.
+     */
+    default Restriction<T> like(String text) {
+        return new BasicRestrictionRecord<>(name(), Operator.LIKE, text);
+    }
+
+    /**
+     * Creates a `LIKE` restriction for a match on the specified pattern.
+     *
+     * @param pattern the `Pattern` instance to match.
+     * @return a Restriction representing a `LIKE` condition.
+     */
+    default Restriction<T> like(Pattern pattern) {
+        return new BasicRestrictionRecord<>(name(), Operator.LIKE, pattern.value());
+    }
+
+    /**
+     * Creates a `LIKE` restriction for values that start with the specified text.
+     *
+     * @param text the text prefix to match.
+     * @return a Restriction representing a prefix `LIKE` condition.
+     */
+    default Restriction<T> startsWith(String text) {
+        return Restrict.startsWith(text, name());
+    }
+
+    /**
+     * Creates a `LIKE` restriction for values that contain the specified substring.
+     *
+     * @param text the substring to match.
+     * @return a Restriction representing a substring `LIKE` condition.
+     */
+    default Restriction<T> contains(String text) {
+        return Restrict.contains(text, name());
+    }
+
+
+    /**
+     * Creates a `LIKE` restriction for values that end with the specified text.
+     *
+     * @param text the text suffix to match.
+     * @return a Restriction representing a suffix `LIKE` condition.
+     */
+    default Restriction<T> endsWith(String text) {
+        return Restrict.endsWith(text, name());
+    }
+
 }
diff --git a/api/src/main/java/jakarta/data/metamodel/impl/AttributeRecord.java b/api/src/main/java/jakarta/data/metamodel/impl/AttributeRecord.java
index 31d329af7..48fc78bde 100644
--- a/api/src/main/java/jakarta/data/metamodel/impl/AttributeRecord.java
+++ b/api/src/main/java/jakarta/data/metamodel/impl/AttributeRecord.java
@@ -28,5 +28,6 @@
  */
 public record AttributeRecord<T>(String name)
         implements Attribute<T> {
+
 }
 
diff --git a/api/src/main/java/jakarta/data/metamodel/impl/BasicRestrictionRecord.java b/api/src/main/java/jakarta/data/metamodel/impl/BasicRestrictionRecord.java
new file mode 100644
index 000000000..810d80343
--- /dev/null
+++ b/api/src/main/java/jakarta/data/metamodel/impl/BasicRestrictionRecord.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2024 Contributors to the Eclipse Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+package jakarta.data.metamodel.impl;
+
+import jakarta.data.Operator;
+import jakarta.data.BasicRestriction;
+
+public record BasicRestrictionRecord<T>(String field, Operator operator, Object value) implements BasicRestriction<T> {
+
+}
diff --git a/api/src/main/java/jakarta/data/metamodel/impl/SortableAttributeRecord.java b/api/src/main/java/jakarta/data/metamodel/impl/SortableAttributeRecord.java
index 73f1df791..ed8c15211 100644
--- a/api/src/main/java/jakarta/data/metamodel/impl/SortableAttributeRecord.java
+++ b/api/src/main/java/jakarta/data/metamodel/impl/SortableAttributeRecord.java
@@ -37,5 +37,6 @@ public Sort<T> asc() {
     public Sort<T> desc() {
         return Sort.desc(name);
     }
+
 }
 
diff --git a/api/src/main/java/jakarta/data/metamodel/impl/TextAttributeRecord.java b/api/src/main/java/jakarta/data/metamodel/impl/TextAttributeRecord.java
index 4fe325751..720df286d 100644
--- a/api/src/main/java/jakarta/data/metamodel/impl/TextAttributeRecord.java
+++ b/api/src/main/java/jakarta/data/metamodel/impl/TextAttributeRecord.java
@@ -47,4 +47,5 @@ public Sort<T> ascIgnoreCase() {
     public Sort<T> descIgnoreCase() {
         return Sort.descIgnoreCase(name);
     }
+
 }
diff --git a/api/src/main/java/jakarta/data/page/CursoredPage.java b/api/src/main/java/jakarta/data/page/CursoredPage.java
index 272409bb8..d8b7a51c0 100644
--- a/api/src/main/java/jakarta/data/page/CursoredPage.java
+++ b/api/src/main/java/jakarta/data/page/CursoredPage.java
@@ -17,9 +17,10 @@
  */
 package jakarta.data.page;
 
-import jakarta.data.repository.OrderBy;
 import jakarta.data.Order;
 import jakarta.data.Sort;
+import jakarta.data.repository.OrderBy;
+
 import java.util.NoSuchElementException;
 
 /**
@@ -208,4 +209,4 @@ public interface CursoredPage<T> extends Page<T> {
      */
     @Override
     PageRequest previousPageRequest();
-}
\ No newline at end of file
+}
diff --git a/api/src/main/java/jakarta/data/repository/OrderBy.java b/api/src/main/java/jakarta/data/repository/OrderBy.java
index cd8db4988..9b2044799 100644
--- a/api/src/main/java/jakarta/data/repository/OrderBy.java
+++ b/api/src/main/java/jakarta/data/repository/OrderBy.java
@@ -19,6 +19,7 @@
 
 import jakarta.data.Order;
 import jakarta.data.Sort;
+
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Repeatable;
 import java.lang.annotation.Retention;
diff --git a/api/src/main/java/module-info.java b/api/src/main/java/module-info.java
index f52e8862f..eec8ab95a 100644
--- a/api/src/main/java/module-info.java
+++ b/api/src/main/java/module-info.java
@@ -1066,6 +1066,7 @@
  * of the repository operation.</p>
  */
 module jakarta.data {
+    requires java.management;
     exports jakarta.data;
     exports jakarta.data.metamodel;
     exports jakarta.data.metamodel.impl;
@@ -1075,4 +1076,7 @@
     exports jakarta.data.exceptions;
     opens jakarta.data.repository;
     exports jakarta.data.spi;
-}
\ No newline at end of file
+    opens jakarta.data.metamodel;
+    opens jakarta.data;
+    opens jakarta.data.metamodel.impl;
+}
diff --git a/api/src/test/java/jakarta/data/CompositeRestrictionRecordTest.java b/api/src/test/java/jakarta/data/CompositeRestrictionRecordTest.java
new file mode 100644
index 000000000..55b020e69
--- /dev/null
+++ b/api/src/test/java/jakarta/data/CompositeRestrictionRecordTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2024 Contributors to the Eclipse Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+package jakarta.data;
+
+
+import org.assertj.core.api.SoftAssertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.Set;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
+
+
+class CompositeRestrictionRecordTest {
+
+    @Test
+    void shouldCreateAllCompositeRestriction() {
+        Restriction<String> restriction1 = Restrict.equalTo("value1", "field1");
+        Restriction<String> restriction2 = Restrict.lessThan(10, "field2");
+
+        CompositeRestrictionRecord<String> composite = CompositeRestrictionRecord.all(restriction1, restriction2);
+
+        SoftAssertions.assertSoftly(soft -> {
+            soft.assertThat(composite.type()).isEqualTo(CompositeRestrictionType.ALL);
+            soft.assertThat(composite.restrictions()).containsExactly(restriction1, restriction2);
+        });
+    }
+
+    @Test
+    void shouldCreateAnyCompositeRestriction() {
+        Restriction<String> restriction1 = Restrict.greaterThan(5, "field1");
+        Restriction<String> restriction2 = Restrict.in(Set.of(1, 2, 3), "field2");
+
+        CompositeRestrictionRecord<String> composite = CompositeRestrictionRecord.any(restriction1, restriction2);
+
+        SoftAssertions.assertSoftly(soft -> {
+            soft.assertThat(composite.type()).isEqualTo(CompositeRestrictionType.ANY);
+            soft.assertThat(composite.restrictions()).containsExactly(restriction1, restriction2);
+        });
+    }
+
+    @Test
+    void shouldBeIterable() {
+        Restriction<String> restriction1 = Restrict.equalTo("value1", "field1");
+        Restriction<String> restriction2 = Restrict.lessThan(10, "field2");
+
+        CompositeRestrictionRecord<String> composite = CompositeRestrictionRecord.all(restriction1, restriction2);
+
+        assertThat(composite).containsExactly(restriction1, restriction2);
+    }
+
+    @Test
+    void shouldReturnImmutableRestrictionsList() {
+        Restriction<String> restriction1 = Restrict.equalTo("value1", "field1");
+        Restriction<String> restriction2 = Restrict.lessThan(10, "field2");
+
+        CompositeRestrictionRecord<String> composite = CompositeRestrictionRecord.all(restriction1, restriction2);
+
+        assertThatThrownBy(() -> composite.restrictions().add(Restrict.greaterThan(15, "field3")))
+                .isInstanceOf(UnsupportedOperationException.class);
+    }
+
+    @Test
+    void shouldSupportEmptyRestrictions() {
+        CompositeRestrictionRecord<String> composite = CompositeRestrictionRecord.all();
+
+        SoftAssertions.assertSoftly(soft -> {
+            soft.assertThat(composite.type()).isEqualTo(CompositeRestrictionType.ALL);
+            soft.assertThat(composite.restrictions()).isEmpty();
+        });
+    }
+
+    @Test
+    void shouldCombineDifferentRestrictionTypes() {
+        Restriction<String> restriction1 = Restrict.contains("text", "field1");
+        Restriction<String> restriction2 = Restrict.startsWith("prefix", "field2");
+        Restriction<String> restriction3 = Restrict.endsWith("suffix", "field3");
+
+        CompositeRestrictionRecord<String> composite = CompositeRestrictionRecord.all(restriction1, restriction2, restriction3);
+
+        SoftAssertions.assertSoftly(soft -> {
+            soft.assertThat(composite.type()).isEqualTo(CompositeRestrictionType.ALL);
+            soft.assertThat(composite.restrictions()).containsExactly(restriction1, restriction2, restriction3);
+        });
+    }
+}
diff --git a/api/src/test/java/jakarta/data/PatternTest.java b/api/src/test/java/jakarta/data/PatternTest.java
new file mode 100644
index 000000000..1eba8222e
--- /dev/null
+++ b/api/src/test/java/jakarta/data/PatternTest.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2024 Contributors to the Eclipse Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+package jakarta.data;
+
+import org.assertj.core.api.SoftAssertions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+
+import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
+
+class PatternTest {
+
+    @Test
+    void shouldCreateExactMatchPattern() {
+        Pattern pattern = Pattern.is("Java Guide");
+        assertThat(pattern.value()).isEqualTo("Java Guide");
+        assertThat(pattern.caseSensitive()).isTrue();
+    }
+
+    @Test
+    void shouldCreateCustomMatchPattern() {
+        Pattern pattern = Pattern.matches("Ja%_a");
+        assertThat(pattern.value()).isEqualTo("Ja%_a");
+        assertThat(pattern.caseSensitive()).isTrue();
+    }
+
+    @Test
+    void shouldCreateCustomWildcardPattern() {
+        Pattern pattern = Pattern.matches("Ja?a*", '?', '*');
+        SoftAssertions.assertSoftly(soft -> {
+            soft.assertThat(pattern.value()).isEqualTo("Ja_a%");
+            soft.assertThat(pattern.caseSensitive()).isTrue();
+        });
+    }
+
+    @Test
+    void shouldCreatePrefixMatchPattern() {
+        Pattern pattern = Pattern.startsWith("Hibernate");
+        SoftAssertions.assertSoftly(soft -> {
+            soft.assertThat(pattern.value()).isEqualTo("Hibernate%");
+            soft.assertThat(pattern.caseSensitive()).isTrue();
+        });
+    }
+
+    @Test
+    void shouldCreateSuffixMatchPattern() {
+        Pattern pattern = Pattern.endsWith("Guide");
+        SoftAssertions.assertSoftly(soft -> {
+            soft.assertThat(pattern.value()).isEqualTo("%Guide");
+            soft.assertThat(pattern.caseSensitive()).isTrue();
+        });
+    }
+
+    @Test
+    void shouldCreateSubstringMatchPattern() {
+        Pattern pattern = Pattern.contains("Java");
+        SoftAssertions.assertSoftly(soft -> {
+            soft.assertThat(pattern.value()).isEqualTo("%Java%");
+            soft.assertThat(pattern.caseSensitive()).isTrue();
+        });
+    }
+
+    @ParameterizedTest
+    @CsvSource({
+            "Jav_%,Jav\\_\\%",
+            "Hello%World,Hello\\%World",
+            "Special_Chars,Special\\_Chars"
+    })
+    void shouldEscapeSpecialCharacters(String input, String expected) {
+        Pattern pattern = Pattern.is(input);
+        SoftAssertions.assertSoftly(soft -> {
+            soft.assertThat(pattern.value()).isEqualTo(expected);
+            soft.assertThat(pattern.caseSensitive()).isTrue();
+        });
+    }
+}
diff --git a/api/src/test/java/jakarta/data/RestrictTest.java b/api/src/test/java/jakarta/data/RestrictTest.java
new file mode 100644
index 000000000..0d02a13aa
--- /dev/null
+++ b/api/src/test/java/jakarta/data/RestrictTest.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2024 Contributors to the Eclipse Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+package jakarta.data;
+
+import org.assertj.core.api.SoftAssertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+import java.util.Set;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class RestrictTest {
+
+    @Test
+    void shouldCreateBasicEqualityRestriction() {
+        Restriction<String> restriction = Restrict.equalTo("Java Guide", "title");
+
+        assertThat(restriction).isInstanceOf(BasicRestriction.class);
+        BasicRestriction<String> basic = (BasicRestriction<String>) restriction;
+
+        SoftAssertions.assertSoftly(soft -> {
+            soft.assertThat(basic.field()).isEqualTo("title");
+            soft.assertThat(basic.operator()).isEqualTo(Operator.EQUAL);
+            soft.assertThat(basic.value()).isEqualTo("Java Guide");
+        });
+    }
+
+    @Test
+    void shouldCreateLessThanRestriction() {
+        Restriction<String> restriction = Restrict.lessThan(100, "price");
+
+        assertThat(restriction).isInstanceOf(BasicRestriction.class);
+        BasicRestriction<String> basic = (BasicRestriction<String>) restriction;
+
+        SoftAssertions.assertSoftly(soft -> {
+            soft.assertThat(basic.field()).isEqualTo("price");
+            soft.assertThat(basic.operator()).isEqualTo(Operator.LESS_THAN);
+            soft.assertThat(basic.value()).isEqualTo(100);
+        });
+    }
+
+    @Test
+    void shouldCreateGreaterThanRestriction() {
+        Restriction<String> restriction = Restrict.greaterThan(2020, "year");
+
+        assertThat(restriction).isInstanceOf(BasicRestriction.class);
+        BasicRestriction<String> basic = (BasicRestriction<String>) restriction;
+
+        SoftAssertions.assertSoftly(soft -> {
+            soft.assertThat(basic.field()).isEqualTo("year");
+            soft.assertThat(basic.operator()).isEqualTo(Operator.GREATER_THAN);
+            soft.assertThat(basic.value()).isEqualTo(2020);
+        });
+    }
+
+    @Test
+    void shouldCreateInRestriction() {
+        Restriction<String> restriction = Restrict.in(Set.of("Java", "Spring"), "title");
+
+        assertThat(restriction).isInstanceOf(BasicRestriction.class);
+        BasicRestriction<String> basic = (BasicRestriction<String>) restriction;
+
+        SoftAssertions.assertSoftly(soft -> {
+            soft.assertThat(basic.field()).isEqualTo("title");
+            soft.assertThat(basic.operator()).isEqualTo(Operator.IN);
+            soft.assertThat(basic.value()).isInstanceOf(Set.class);
+            Set<String> values = (Set<String>) basic.value();
+            soft.assertThat(values).containsExactlyInAnyOrder("Java", "Spring");
+        });
+    }
+
+    @Test
+    void shouldCreateContainsRestriction() {
+        Restriction<String> restriction = Restrict.contains("Hibernate", "title");
+
+        assertThat(restriction).isInstanceOf(BasicRestriction.class);
+        BasicRestriction<String> basic = (BasicRestriction<String>) restriction;
+
+        SoftAssertions.assertSoftly(soft -> {
+            soft.assertThat(basic.field()).isEqualTo("title");
+            soft.assertThat(basic.operator()).isEqualTo(Operator.LIKE);
+            soft.assertThat(basic.value()).isEqualTo("%Hibernate%");
+        });
+    }
+
+    @Test
+    void shouldCreateStartsWithRestriction() {
+        Restriction<String> restriction = Restrict.startsWith("Hibernate", "title");
+
+        assertThat(restriction).isInstanceOf(BasicRestriction.class);
+        BasicRestriction<String> basic = (BasicRestriction<String>) restriction;
+
+        SoftAssertions.assertSoftly(soft -> {
+            soft.assertThat(basic.field()).isEqualTo("title");
+            soft.assertThat(basic.operator()).isEqualTo(Operator.LIKE);
+            soft.assertThat(basic.value()).isEqualTo("Hibernate%");
+        });
+    }
+
+    @Test
+    void shouldCreateEndsWithRestriction() {
+        Restriction<String> restriction = Restrict.endsWith("Guide", "title");
+
+        assertThat(restriction).isInstanceOf(BasicRestriction.class);
+        BasicRestriction<String> basic = (BasicRestriction<String>) restriction;
+
+        SoftAssertions.assertSoftly(soft -> {
+            soft.assertThat(basic.field()).isEqualTo("title");
+            soft.assertThat(basic.operator()).isEqualTo(Operator.LIKE);
+            soft.assertThat(basic.value()).isEqualTo("%Guide");
+        });
+    }
+
+    @Test
+    void shouldCreateCompositeAllRestriction() {
+        Restriction<String> restriction = Restrict.all(
+                Restrict.equalTo("Java Guide", "title"),
+                Restrict.greaterThan(2020, "publicationYear")
+        );
+
+        assertThat(restriction).isInstanceOf(CompositeRestriction.class);
+        CompositeRestriction<String> composite = (CompositeRestriction<String>) restriction;
+
+        SoftAssertions.assertSoftly(soft -> {
+            soft.assertThat(composite.type()).isEqualTo(CompositeRestrictionType.ALL);
+            soft.assertThat(composite.restrictions()).hasSize(2);
+            soft.assertThat(composite.restrictions().get(0)).isInstanceOf(BasicRestriction.class);
+            soft.assertThat(composite.restrictions().get(1)).isInstanceOf(BasicRestriction.class);
+        });
+    }
+
+    @Test
+    void shouldCreateCompositeAnyRestriction() {
+        Restriction<String> restriction = Restrict.any(
+                Restrict.contains("Java", "title"),
+                Restrict.lessThan(500, "pages")
+        );
+
+        assertThat(restriction).isInstanceOf(CompositeRestriction.class);
+        CompositeRestriction<String> composite = (CompositeRestriction<String>) restriction;
+
+        SoftAssertions.assertSoftly(soft -> {
+            soft.assertThat(composite.type()).isEqualTo(CompositeRestrictionType.ANY);
+            soft.assertThat(composite.restrictions()).hasSize(2);
+            soft.assertThat(composite.restrictions().get(0)).isInstanceOf(BasicRestriction.class);
+            soft.assertThat(composite.restrictions().get(1)).isInstanceOf(BasicRestriction.class);
+        });
+    }
+}
diff --git a/api/src/test/java/jakarta/data/metamodel/RangeTest.java b/api/src/test/java/jakarta/data/metamodel/RangeTest.java
new file mode 100644
index 000000000..8de44cc8f
--- /dev/null
+++ b/api/src/test/java/jakarta/data/metamodel/RangeTest.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2024 Contributors to the Eclipse Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+package jakarta.data.metamodel;
+
+import jakarta.data.Operator;
+import org.assertj.core.api.SoftAssertions;
+import org.junit.jupiter.api.Test;
+
+import java.time.LocalDate;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class RangeTest {
+
+
+    @Test
+    void shouldCreateInclusiveBetweenRange() {
+        Range<LocalDate> range = Range.between("publicationDate", LocalDate.of(2020, 1, 1), LocalDate.of(2023, 1, 1));
+
+        SoftAssertions.assertSoftly(soft -> {
+            soft.assertThat(range.field()).isEqualTo("publicationDate");
+            soft.assertThat(range.operator()).isEqualTo(Operator.BETWEEN);
+            soft.assertThat(range.value()).isEqualTo(List.of(LocalDate.of(2020, 1, 1), LocalDate.of(2023, 1, 1)));
+        });
+    }
+
+    @Test
+    void shouldCreateInclusiveFromRange() {
+        Range<Double> range = Range.from("rating", 4.0);
+
+        SoftAssertions.assertSoftly(soft -> {
+            soft.assertThat(range.field()).isEqualTo("rating");
+            soft.assertThat(range.operator()).isEqualTo(Operator.GREATER_THAN_EQUAL);
+            soft.assertThat(range.value()).isEqualTo(4.0);
+        });
+    }
+
+    @Test
+    void shouldCreateInclusiveToRange() {
+        Range<Integer> range = Range.to("price", 100);
+
+        SoftAssertions.assertSoftly(soft -> {
+            soft.assertThat(range.field()).isEqualTo("price");
+            soft.assertThat(range.operator()).isEqualTo(Operator.LESS_THAN_EQUAL);
+            soft.assertThat(range.value()).isEqualTo(100);
+        });
+    }
+
+    @Test
+    void shouldCreateExclusiveAboveRange() {
+        Range<Double> range = Range.above("rating", 4.0);
+
+        SoftAssertions.assertSoftly(soft -> {
+            soft.assertThat(range.field()).isEqualTo("rating");
+            soft.assertThat(range.operator()).isEqualTo(Operator.GREATER_THAN);
+            soft.assertThat(range.value()).isEqualTo(4.0);
+        });
+    }
+
+    @Test
+    void shouldCreateExclusiveBelowRange() {
+        Range<Double> range = Range.below("price", 200.0);
+
+        SoftAssertions.assertSoftly(soft -> {
+            soft.assertThat(range.field()).isEqualTo("price");
+            soft.assertThat(range.operator()).isEqualTo(Operator.LESS_THAN);
+            soft.assertThat(range.value()).isEqualTo(200.0);
+        });
+    }
+
+    @Test
+    void shouldHandleNullLowerBoundForToRange() {
+        Range<Double> range = Range.to("price", 200.0);
+
+        SoftAssertions.assertSoftly(soft -> {
+            soft.assertThat(range.field()).isEqualTo("price");
+            soft.assertThat(range.operator()).isEqualTo(Operator.LESS_THAN_EQUAL);
+            soft.assertThat(range.lowerBound()).isNull();
+            soft.assertThat(range.upperBound()).isEqualTo(200.0);
+        });
+    }
+
+    @Test
+    void shouldHandleNullUpperBoundForFromRange() {
+        Range<Double> range = Range.from("price", 50.0);
+
+        SoftAssertions.assertSoftly(soft -> {
+            soft.assertThat(range.field()).isEqualTo("price");
+            soft.assertThat(range.operator()).isEqualTo(Operator.GREATER_THAN_EQUAL);
+            soft.assertThat(range.lowerBound()).isEqualTo(50.0);
+            soft.assertThat(range.upperBound()).isNull();
+        });
+    }
+
+    @Test
+    void shouldHandleBothBoundsForBetweenRange() {
+        Range<Double> range = Range.between("price", 50.0, 200.0);
+
+        SoftAssertions.assertSoftly(soft -> {
+            soft.assertThat(range.field()).isEqualTo("price");
+            soft.assertThat(range.operator()).isEqualTo(Operator.BETWEEN);
+            soft.assertThat(range.lowerBound()).isEqualTo(50.0);
+            soft.assertThat(range.upperBound()).isEqualTo(200.0);
+        });
+    }
+
+    @Test
+    void shouldHandleOpenRangeForAbove() {
+        Range<Integer> range = Range.above("age", 18);
+
+        SoftAssertions.assertSoftly(soft -> {
+            soft.assertThat(range.field()).isEqualTo("age");
+            soft.assertThat(range.operator()).isEqualTo(Operator.GREATER_THAN);
+            soft.assertThat(range.lowerBound()).isEqualTo(18);
+            soft.assertThat(range.upperBound()).isNull();
+            soft.assertThat(range.open()).isTrue();
+        });
+    }
+
+    @Test
+    void shouldHandleOpenRangeForBelow() {
+        Range<Integer> range = Range.below("age", 65);
+
+        SoftAssertions.assertSoftly(soft -> {
+            soft.assertThat(range.field()).isEqualTo("age");
+            soft.assertThat(range.operator()).isEqualTo(Operator.LESS_THAN);
+            soft.assertThat(range.lowerBound()).isNull();
+            soft.assertThat(range.upperBound()).isEqualTo(65);
+            soft.assertThat(range.open()).isTrue();
+        });
+    }
+}
diff --git a/api/src/test/java/jakarta/data/metamodel/impl/BasicRestrictionRecordTest.java b/api/src/test/java/jakarta/data/metamodel/impl/BasicRestrictionRecordTest.java
new file mode 100644
index 000000000..b151341f4
--- /dev/null
+++ b/api/src/test/java/jakarta/data/metamodel/impl/BasicRestrictionRecordTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2024 Contributors to the Eclipse Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+package jakarta.data.metamodel.impl;
+
+import jakarta.data.Operator;
+import org.assertj.core.api.SoftAssertions;
+import org.junit.jupiter.api.Test;
+
+
+class BasicRestrictionRecordTest {
+    @Test
+    void shouldCreateBasicEqualityRestriction() {
+        BasicRestrictionRecord<String> restriction = new BasicRestrictionRecord<>("title", Operator.EQUAL, "Java Guide");
+
+        SoftAssertions.assertSoftly(soft -> {
+            soft.assertThat(restriction.field()).isEqualTo("title");
+            soft.assertThat(restriction.operator()).isEqualTo(Operator.EQUAL);
+            soft.assertThat(restriction.value()).isEqualTo("Java Guide");
+        });
+    }
+
+    @Test
+    void shouldCreateGreaterThanRestriction() {
+        BasicRestrictionRecord<String> restriction = new BasicRestrictionRecord<>("price", Operator.GREATER_THAN, 100);
+
+        SoftAssertions.assertSoftly(soft -> {
+            soft.assertThat(restriction.field()).isEqualTo("price");
+            soft.assertThat(restriction.operator()).isEqualTo(Operator.GREATER_THAN);
+            soft.assertThat(restriction.value()).isEqualTo(100);
+        });
+    }
+
+    @Test
+    void shouldCreateLessThanRestriction() {
+        BasicRestrictionRecord<String> restriction = new BasicRestrictionRecord<>("quantity", Operator.LESS_THAN, 50);
+
+        SoftAssertions.assertSoftly(soft -> {
+            soft.assertThat(restriction.field()).isEqualTo("quantity");
+            soft.assertThat(restriction.operator()).isEqualTo(Operator.LESS_THAN);
+            soft.assertThat(restriction.value()).isEqualTo(50);
+        });
+    }
+
+}