1 package org.synchronoss.cpo.core;
2
3 /*-
4 * [[
5 * core
6 * ==
7 * Copyright (C) 2003 - 2026 Exaxis LLC, Synchronoss Technologies Inc
8 * ==
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as
11 * published by the Free Software Foundation, either version 3 of the
12 * License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Lesser Public License for more details.
18 *
19 * You should have received a copy of the GNU General Lesser Public
20 * License along with this program. If not, see
21 * <http://www.gnu.org/licenses/lgpl-3.0.html>.
22 * ]]
23 */
24
25 import java.io.Serializable;
26 import java.util.ArrayList;
27 import java.util.Collection;
28 import java.util.Collections;
29 import java.util.List;
30
31 /**
32 * The clauses of a {@link CpoAdapter} operation: the function group to run plus any run-time where
33 * constraints, orderings, and native expressions. A CpoQuery replaces the telescoping method
34 * overloads that previously carried these as positional parameters.
35 *
36 * <p>Instances are immutable — every accumulator returns a new CpoQuery — so a query may be built
37 * once, held in a constant, and shared freely between threads:
38 *
39 * <pre>{@code
40 * Stream<ValueObject> beans =
41 * adapter.retrieveBeans(CpoQuery.group("byDept").where(w).orderBy(ob), criteria);
42 * }</pre>
43 *
44 * @param groupName The function group name; null selects the default group
45 * @param wheres The run-time where constraints, in the order added
46 * @param orderBys The orderings, in the order added
47 * @param nativeExpressions The native expressions, in the order added
48 * @author david berry
49 */
50 public record CpoQuery(
51 String groupName,
52 List<CpoWhere> wheres,
53 List<CpoOrderBy> orderBys,
54 List<CpoNativeFunction> nativeExpressions)
55 implements Serializable {
56
57 /** Version Id for this class. */
58 private static final long serialVersionUID = 1L;
59
60 private static final CpoQuery DEFAULT_GROUP = new CpoQuery(null, List.of(), List.of(), List.of());
61
62 /**
63 * A query against the named function group.
64 *
65 * @param groupName The function group name; null signifies the default group
66 * @return A CpoQuery with no clauses
67 */
68 public static CpoQuery group(String groupName) {
69 return groupName == null
70 ? DEFAULT_GROUP
71 : new CpoQuery(groupName, List.of(), List.of(), List.of());
72 }
73
74 /**
75 * A query against the default (unnamed) function group.
76 *
77 * @return A CpoQuery with no clauses
78 */
79 public static CpoQuery defaultGroup() {
80 return DEFAULT_GROUP;
81 }
82
83 /**
84 * Adds a where constraint.
85 *
86 * @param where The constraint to add; null is ignored
87 * @return A new CpoQuery with the constraint appended
88 */
89 public CpoQuery where(CpoWhere where) {
90 if (where == null) return this;
91 return new CpoQuery(groupName, append(wheres, where), orderBys, nativeExpressions);
92 }
93
94 /**
95 * Adds a collection of where constraints.
96 *
97 * @param wheres The constraints to add; null or empty is ignored
98 * @return A new CpoQuery with the constraints appended
99 */
100 public CpoQuery wheres(Collection<CpoWhere> wheres) {
101 if (wheres == null || wheres.isEmpty()) return this;
102 return new CpoQuery(groupName, appendAll(this.wheres, wheres), orderBys, nativeExpressions);
103 }
104
105 /**
106 * Adds an ordering.
107 *
108 * @param orderBy The ordering to add; null is ignored
109 * @return A new CpoQuery with the ordering appended
110 */
111 public CpoQuery orderBy(CpoOrderBy orderBy) {
112 if (orderBy == null) return this;
113 return new CpoQuery(groupName, wheres, append(orderBys, orderBy), nativeExpressions);
114 }
115
116 /**
117 * Adds a collection of orderings.
118 *
119 * @param orderBys The orderings to add; null or empty is ignored
120 * @return A new CpoQuery with the orderings appended
121 */
122 public CpoQuery orderBys(Collection<CpoOrderBy> orderBys) {
123 if (orderBys == null || orderBys.isEmpty()) return this;
124 return new CpoQuery(groupName, wheres, appendAll(this.orderBys, orderBys), nativeExpressions);
125 }
126
127 /**
128 * Adds a native expression that augments the expression stored in the metadata.
129 *
130 * @param nativeExpression The native expression to add; null is ignored
131 * @return A new CpoQuery with the native expression appended
132 */
133 public CpoQuery nativeExpression(CpoNativeFunction nativeExpression) {
134 if (nativeExpression == null) return this;
135 return new CpoQuery(groupName, wheres, orderBys, append(nativeExpressions, nativeExpression));
136 }
137
138 /**
139 * Adds a collection of native expressions.
140 *
141 * @param nativeExpressions The native expressions to add; null or empty is ignored
142 * @return A new CpoQuery with the native expressions appended
143 */
144 public CpoQuery nativeExpressions(Collection<CpoNativeFunction> nativeExpressions) {
145 if (nativeExpressions == null || nativeExpressions.isEmpty()) return this;
146 return new CpoQuery(
147 groupName, wheres, orderBys, appendAll(this.nativeExpressions, nativeExpressions));
148 }
149
150 private static <E> List<E> append(List<E> list, E element) {
151 List<E> appended = new ArrayList<>(list);
152 appended.add(element);
153 return Collections.unmodifiableList(appended);
154 }
155
156 private static <E> List<E> appendAll(List<E> list, Collection<E> elements) {
157 List<E> appended = new ArrayList<>(list);
158 appended.addAll(elements);
159 return Collections.unmodifiableList(appended);
160 }
161 }