openfeign/querydsl

repository·master·Indexed 20 days ago

https://github.com/openfeign/querydsl

A maintained fork of the Querydsl framework under the OpenFeign organization. It provides a type-safe, fluent SQL-like query API for Java backends including JPA, SQL, MongoDB, and Java Collections. The project includes modules for R2DBC (experimental), MongoDB via Morphia, and various reference implementations for integrating with Spring and Google Guice.

Tokens
34.7K
Snippets
111
Records
137
Agent score
70%

What's inside openfeign-querydsl

  1. What is Querydsl?

    master

    Querydsl is a framework for constructing statically typed, SQL-like queries in Java. Instead of using inline strings or XML, you use a fluent API to build queries. This provides several advantages:

    • IDE Code Completion: Discover available columns and operations via your IDE.
    • Compile-time Safety: The compiler catches most query syntax mistakes before runtime.
    • Safe Domain References: Properties are referenced through generated types rather than error-prone strings.
    • Refactoring Support: Renaming a field automatically updates all associated queries.
  2. What is Querydsl and what backends does it support?

    master

    Querydsl is a framework designed to construct queries in a type-safe manner, replacing fragile string-based query construction (like HQL) with generated query types that reflect your domain model. This allows domain changes to be reflected directly in queries and enables IDE auto-complete for faster, safer query construction.

    Querydsl supports the following backends:

    • JPA
    • SQL (JDBC)
    • R2DBC
    • MongoDB
    • Collections
    • Spatial
    • Kotlin
    • Scala
  3. Overview of Querydsl R2DBC for Spring DAO usage

    master

    Querydsl R2DBC provides a typesafe way to interact with databases in Spring projects, offering several advantages over direct JDBC usage:

    • Typesafety: Reduces runtime errors by using typed queries.
    • SQL-like Syntax: The API is designed to be close to standard SQL.
    • Dialect Abstraction: It abstracts over differences between various SQL dialects.

    This specific example project (querydsl-example-r2dbc-sql-codegen) demonstrates a pattern where no generated bean types are used; instead, the queries are used to populate external DTO (Data Transfer Object) types.

  4. Status of R2DBC support

    master

    R2DBC support in Querydsl is currently highly experimental. Users should expect frequent changes and potential instability. The implementation is undergoing a planned refactor to eliminate code and test duplication with querydsl-sql.

    Note that certain functionalities, specifically #addBatch(), may currently be missing or broken due to ongoing development challenges.

  5. Convert Generic Geometry to Specific Types

    master

    If your database schema uses generic geometry types, you can use conversion methods in the Querydsl object model to cast them to more specific types (like Point) to access specialized methods like .x() or .y().

    GeometryPath<Geometry> geometry = shapes.geometry;
    PointPath<Point> point = geometry.asPoint();
    NumberExpression<Double> pointX = point.x();
  6. Use KSP to query Java entities from Kotlin

    master

    A primary advantage of this processor is its ability to handle mixed Java/Kotlin codebases. Unlike querydsl-apt, which may fail to provide Q-classes to Kotlin during the compilation phase, KSP runs as part of kspKotlin. This allows it to see Java sources and emit .kt Q-classes that are immediately available for use in Kotlin code.

    Simply place your @Entity Java classes in src/main/java, and they will be processed automatically.

    // src/main/java/com/example/Person.java
    @Entity
    public class Person {
        @Id private Long id;
        private String name;
        @Embedded private Address address;
        @Transient private String cachedDisplay; // skipped
        public static final String CONSTANT = "x"; // skipped
        // getters/setters...
    }
    
    // src/main/kotlin/com/example/Repository.kt
    val q = QPerson.person
    JPAQueryFactory(em).selectFrom(q).where(q.address.city.eq("London")).fetch()
  7. Initialize deep path properties with @QueryInit

    master

    By default, Querydsl only initializes reference properties up to two levels deep. If you need to access deeper paths (e.g., event.account.customer.address), you must annotate the domain type with com.querydsl.core.annotations.QueryInit to enforce initialization of those paths.

    You can use specific paths or wildcards like "*" or "customer.*".

    This approach allows you to use final entity fields while still enabling deep path navigation in queries.

    @Entity
    class Event {
        @QueryInit("customer.address")
        Account account;
    }
    
    @Entity
    class Account {
        Customer customer;
    }
    
    @Entity
    class Customer {
        String name;
        Address address;
    }
  8. How result customization works in Querydsl

    master

    Querydsl offers two primary mechanisms for customizing query results depending on your goal:

    1. Row-based transformation: Use com.querydsl.core.types.FactoryExpression to transform individual rows into specific objects (like Beans or DTOs). These implementations are accessed via the com.querydsl.core.types.Projections class.
    2. Aggregation: Use com.querydsl.core.ResultTransformer to aggregate multiple rows into a single result structure (like a Map). The primary implementation for this is com.querydsl.core.group.GroupBy.

    Use FactoryExpression when you want to map a row to a single object, and GroupBy when you want to group related rows together (e.g., a parent with a list of children).

  9. Rules and limitations for Alias usage

    master

    When using alias objects within the $(...) (dollar-method) scope, follow these rules to ensure correct path transformation:

    1. Supported Invocations: You may only invoke the following methods on alias types:

      • Getters (standard Java Bean property access)
      • size()
      • contains(Object)
      • get(int)
      • Any other invocation not in this list will throw an exception.
    2. Cascading Paths: Non-primitive and non-final typed properties are themselves aliases. You can cascade method calls (e.g., $(c.getMate().getName()) becomes c.mate.name) until you reach a primitive or final type.

    3. Avoid Non-Tracked Methods: Do not call methods that are not part of the property path construction (like String.toLowerCase()) inside the dollar-method scope, as these transformations are not tracked and will fail to produce the correct path.

  10. Core principles of Querydsl

    master

    Querydsl is built on two primary principles:

    1. Type safety: Queries are constructed using generated query types that mirror your domain properties. All function and method invocations are fully type-safe.
    2. Consistency: Query paths and operations remain consistent across different implementations, and query interfaces share a common base interface.
  11. Handle type casting and supertype references

    master

    Querydsl's generated types use a flattened hierarchy where types are direct subclasses of EntityPathBase or BeanPath. This means you cannot use standard Java casting to access logical supertypes.

    Accessing Supertypes

    If a generated class has a single supertype, you can access it via the _super field provided in the generated Q-type.

    Example: If QBankAccount extends Account, use bankAccount._super to access QAccount members.

    Casting to Subtypes

    To cast a supertype reference to a specific subtype, use the .as(Class<T> type) method on an EntityPathBase instance.

    // Casting supertype to subtype
    QAccount account = new QAccount("account");
    QBankAccount bankAccount = account.as(QBankAccount.class);