15
15
*/
16
16
package org .springframework .data .jdbc .repository .query ;
17
17
18
- import java .util .ArrayList ;
19
- import java .util .Collection ;
18
+ import java .util .Collections ;
19
+ import java .util .List ;
20
20
21
21
import org .springframework .data .domain .Pageable ;
22
22
import org .springframework .data .domain .Sort ;
23
23
import org .springframework .data .jdbc .core .convert .JdbcConverter ;
24
+ import org .springframework .data .mapping .PersistentPropertyPath ;
24
25
import org .springframework .data .mapping .context .MappingContext ;
25
26
import org .springframework .data .relational .core .dialect .Dialect ;
26
27
import org .springframework .data .relational .core .dialect .RenderContextFactory ;
28
+ import org .springframework .data .relational .core .mapping .PersistentPropertyPathExtension ;
27
29
import org .springframework .data .relational .core .mapping .RelationalPersistentEntity ;
28
30
import org .springframework .data .relational .core .mapping .RelationalPersistentProperty ;
29
31
import org .springframework .data .relational .core .query .Criteria ;
32
+ import org .springframework .data .relational .core .sql .Expression ;
30
33
import org .springframework .data .relational .core .sql .Select ;
31
34
import org .springframework .data .relational .core .sql .SelectBuilder ;
32
35
import org .springframework .data .relational .core .sql .SqlIdentifier ;
35
38
import org .springframework .data .relational .repository .query .RelationalEntityMetadata ;
36
39
import org .springframework .data .relational .repository .query .RelationalParameterAccessor ;
37
40
import org .springframework .data .relational .repository .query .RelationalQueryCreator ;
41
+ import org .springframework .data .repository .query .Parameters ;
42
+ import org .springframework .data .repository .query .parser .Part ;
38
43
import org .springframework .data .repository .query .parser .PartTree ;
39
44
import org .springframework .jdbc .core .namedparam .MapSqlParameterSource ;
40
45
import org .springframework .util .Assert ;
@@ -50,8 +55,6 @@ class JdbcQueryCreator extends RelationalQueryCreator<ParametrizedQuery> {
50
55
private final PartTree tree ;
51
56
private final RelationalParameterAccessor accessor ;
52
57
private final QueryMapper queryMapper ;
53
-
54
- private final MappingContext <RelationalPersistentEntity <?>, RelationalPersistentProperty > mappingContext ;
55
58
private final RelationalEntityMetadata <?> entityMetadata ;
56
59
private final RenderContextFactory renderContextFactory ;
57
60
@@ -65,8 +68,8 @@ class JdbcQueryCreator extends RelationalQueryCreator<ParametrizedQuery> {
65
68
* @param entityMetadata relational entity metadata, must not be {@literal null}.
66
69
* @param accessor parameter metadata provider, must not be {@literal null}.
67
70
*/
68
- JdbcQueryCreator (PartTree tree , JdbcConverter converter , Dialect dialect ,
69
- RelationalEntityMetadata <?> entityMetadata , RelationalParameterAccessor accessor ) {
71
+ JdbcQueryCreator (PartTree tree , JdbcConverter converter , Dialect dialect , RelationalEntityMetadata <?> entityMetadata ,
72
+ RelationalParameterAccessor accessor ) {
70
73
super (tree , accessor );
71
74
72
75
Assert .notNull (converter , "JdbcConverter must not be null" );
@@ -76,12 +79,60 @@ class JdbcQueryCreator extends RelationalQueryCreator<ParametrizedQuery> {
76
79
this .tree = tree ;
77
80
this .accessor = accessor ;
78
81
79
- this .mappingContext = (MappingContext ) converter .getMappingContext ();
80
82
this .entityMetadata = entityMetadata ;
81
83
this .queryMapper = new QueryMapper (dialect , converter );
82
84
this .renderContextFactory = new RenderContextFactory (dialect );
83
85
}
84
86
87
+ /**
88
+ * Validate parameters for the derived query. Specifically checking that the query method defines scalar parameters
89
+ * and collection parameters where required and that invalid parameter declarations are rejected.
90
+ *
91
+ * @param tree
92
+ * @param parameters
93
+ */
94
+ public static void validate (PartTree tree , Parameters <?, ?> parameters ,
95
+ MappingContext <? extends RelationalPersistentEntity <?>, ? extends RelationalPersistentProperty > context ) {
96
+
97
+ RelationalQueryCreator .validate (tree , parameters );
98
+
99
+ for (PartTree .OrPart parts : tree ) {
100
+ for (Part part : parts ) {
101
+
102
+ PersistentPropertyPath <? extends RelationalPersistentProperty > propertyPath = context
103
+ .getPersistentPropertyPath (part .getProperty ());
104
+ PersistentPropertyPathExtension path = new PersistentPropertyPathExtension (context , propertyPath );
105
+
106
+ for (PersistentPropertyPathExtension pathToValidate = path ; path .getLength () > 0 ; path = path .getParentPath ()) {
107
+ validateProperty (pathToValidate );
108
+ }
109
+ }
110
+ }
111
+ }
112
+
113
+ private static void validateProperty (PersistentPropertyPathExtension path ) {
114
+
115
+ if (!path .getParentPath ().isEmbedded () && path .getLength () > 1 ) {
116
+ throw new IllegalArgumentException (
117
+ String .format ("Cannot query by nested property: %s" , path .getRequiredPersistentPropertyPath ().toDotPath ()));
118
+ }
119
+
120
+ if (path .isMultiValued () || path .isMap ()) {
121
+ throw new IllegalArgumentException (String .format ("Cannot query by multi-valued property: %s" ,
122
+ path .getRequiredPersistentPropertyPath ().getLeafProperty ().getName ()));
123
+ }
124
+
125
+ if (!path .isEmbedded () && path .isEntity ()) {
126
+ throw new IllegalArgumentException (
127
+ String .format ("Cannot query by nested entity: %s" , path .getRequiredPersistentPropertyPath ().toDotPath ()));
128
+ }
129
+
130
+ if (path .getRequiredPersistentPropertyPath ().getLeafProperty ().isReference ()) {
131
+ throw new IllegalArgumentException (
132
+ String .format ("Cannot query by reference: %s" , path .getRequiredPersistentPropertyPath ().toDotPath ()));
133
+ }
134
+ }
135
+
85
136
/**
86
137
* Creates {@link ParametrizedQuery} applying the given {@link Criteria} and {@link Sort} definition.
87
138
*
@@ -96,7 +147,12 @@ protected ParametrizedQuery complete(Criteria criteria, Sort sort) {
96
147
Table table = Table .create (entityMetadata .getTableName ());
97
148
MapSqlParameterSource parameterSource = new MapSqlParameterSource ();
98
149
99
- SelectBuilder .SelectFromAndJoin builder = Select .builder ().select (table .columns (getSelectProjection ())).from (table );
150
+ List <? extends Expression > columns = table .columns (getSelectProjection ());
151
+ if (columns .isEmpty ()) {
152
+ columns = Collections .singletonList (table .asterisk ());
153
+ }
154
+
155
+ SelectBuilder .SelectFromAndJoin builder = Select .builder ().select (columns ).from (table );
100
156
101
157
if (tree .isExistsProjection ()) {
102
158
builder = builder .limit (1 );
@@ -132,27 +188,6 @@ private SqlIdentifier[] getSelectProjection() {
132
188
return new SqlIdentifier [] { tableEntity .getIdColumn () };
133
189
}
134
190
135
- Collection <SqlIdentifier > columnNames = unwrapColumnNames ("" , tableEntity );
136
-
137
- return columnNames .toArray (new SqlIdentifier [0 ]);
138
- }
139
-
140
- private Collection <SqlIdentifier > unwrapColumnNames (String prefix , RelationalPersistentEntity <?> persistentEntity ) {
141
-
142
- Collection <SqlIdentifier > columnNames = new ArrayList <>();
143
-
144
- for (RelationalPersistentProperty property : persistentEntity ) {
145
-
146
- if (property .isEmbedded ()) {
147
- columnNames .addAll (
148
- unwrapColumnNames (prefix + property .getEmbeddedPrefix (), mappingContext .getPersistentEntity (property )));
149
- }
150
-
151
- else {
152
- columnNames .add (property .getColumnName ().transform (prefix ::concat ));
153
- }
154
- }
155
-
156
- return columnNames ;
191
+ return new SqlIdentifier [0 ];
157
192
}
158
193
}
0 commit comments