可用版本: Dev (3.21) | 最新 (3.20) | 3.19 | 3.18 | 3.17 | 3.16

这是一个实验性功能,因此可能会发生变化。使用风险自负!

遍历

适用于 ❌ 开源版   ✅ Express 版   ✅ 专业版   ✅ 企业版

虽然来自模型 API 的 访问器方法允许手动遍历表达式树,但遍历表达式树的更通用方法是使用 org.jooq.Traverser API,它可以以类似于 java.util.stream.Collector 迭代 java.util.stream.Stream 的方式遍历 org.jooq.QueryPart,收集和聚合有关表达式树的数据。一个 Traverser 包含此 API

public interface Traverser<A, R> {

    /**
     * A supplier for a temporary data structure to accumulate {@link QueryPart}
     * objects into during traversal.
     */
    Supplier<A> supplier();

    /**
     * An optional traversal abort condition to short circuit traversal e.g.
     * when the searched object has been found.
     */
    Predicate<A> abort();

    /**
     * An optional recursion condition to prevent entering a specific
     * {@link QueryPart}, e.g. when it is undesired to enter any subqueries.
     */
    Predicate<QueryPart> recurse();

    /**
     * An optional recursion condition to prevent entering a specific
     * {@link QueryPart}'s children, e.g. when it is desired to traverse only
     * into certain operators.
     */
    Predicate<QueryPart> recurseChildren();

    /**
     * A callback that is invoked before recursing into a subtree.
     */
    BiFunction<A, QueryPart, A> before();

    /**
     * A callback that is invoked after recursing into a subtree.
     */
    BiFunction<A, QueryPart, A> after();

    /**
     * An optional transformation function to turn the temporary data structure
     * supplied by {@link #supplier()} into the final data structure.
     */
    Function<A, R> finisher();
}

一些元素类似于 java.util.stream.Collector,其他元素特定于树遍历。

一个简单的例子展示了可以做什么

// Any ordinary QueryPart:
Condition condition = BOOK.ID.eq(1);
int count = condition.$traverse(

    // Supplier of the initial data structure: an int
    () -> 0,

    // Print all traversed QueryParts and increment the counter
    (r, q) -> {
        System.out.println("Part " + r + ": " + q);
        return r + 1;
    }
);
System.out.println("Count : " + count);

以上代码将打印

Part 0: "BOOK"."ID" = 1
Part 1: "BOOK"."ID"
Part 2: 1
Count : 3

在稍微复杂的 QueryPart 上使用相同的 traverser

Condition condition = BOOK.ID.eq(1).or(BOOK.ID.eq(2));
// ...
Part 0: ("BOOK"."ID" = 1 or "BOOK"."ID" = 2)
Part 1: "BOOK"."ID" = 1
Part 2: "BOOK"."ID"
Part 3: 1
Part 4: "BOOK"."ID" = 2
Part 5: "BOOK"."ID"
Part 6: 2
Count : 7

重用你的 JDK collectors

任何 Collector 都可以使用 Traversers.collecting(Collector) 转换为 Traverser。例如,如果你想计算表达式中所有 QueryPart 项的数量,而不是上面手写的 traverser,只需使用 JDK Collectors.counting()

// Contains 3 query parts
long count1 = BOOK.ID.eq(1)
    .$traverse(Traversers.collecting(Collectors.counting());

// Contains 7 query parts
long count2 = BOOK.ID.eq(1).or(BOOK.ID.eq(2))
    .$traverse(Traversers.collecting(Collectors.counting());

限制

就像 模型 API 替换一样,traversers 不能遍历到“opaque” org.jooq.QueryPart 实例,包括 自定义 QueryPartsplain SQL 模板。另请参阅 需要代码生成的功能 以获取更多详细信息。

反馈

您对此页面有任何反馈吗? 我们很乐意听取您的意见!

The jOOQ Logo