15
15
*/
16
16
package org .springframework .data .neo4j .core ;
17
17
18
+ import java .util .List ;
18
19
import java .util .function .Consumer ;
19
20
import java .util .function .Predicate ;
20
21
import java .util .regex .Pattern ;
23
24
24
25
import org .apache .commons .logging .LogFactory ;
25
26
import org .jspecify .annotations .Nullable ;
26
- import org .neo4j .driver .NotificationCategory ;
27
+ import org .neo4j .driver .NotificationClassification ;
27
28
import org .neo4j .driver .NotificationSeverity ;
28
- import org .neo4j .driver .summary .InputPosition ;
29
- import org .neo4j .driver .summary .Notification ;
29
+ import org .neo4j .driver .summary .GqlNotification ;
30
30
import org .neo4j .driver .summary .Plan ;
31
31
import org .neo4j .driver .summary .ResultSummary ;
32
32
@@ -66,8 +66,15 @@ final class ResultSummaries {
66
66
private static final LogAccessor cypherTopologyNotificationLog = new LogAccessor (
67
67
LogFactory .getLog ("org.springframework.data.neo4j.cypher.topology" ));
68
68
69
- private static final Pattern DEPRECATED_ID_PATTERN = Pattern
70
- .compile ("(?im)The query used a deprecated function[.:] \\ (?[`']id.+" );
69
+ private static final LogAccessor cypherSchemaNotificationLog = new LogAccessor (
70
+ LogFactory .getLog ("org.springframework.data.neo4j.cypher.schema" ));
71
+
72
+ private static final List <Pattern > STUFF_THAT_MIGHT_INFORM_THAT_THE_ID_FUNCTION_IS_PROBLEMATIC = Stream .of (
73
+ "(?im)The query used a deprecated function[.:] \\ (?[`']id.+" ,
74
+ "(?im).*id is deprecated and will be removed without a replacement\\ ." ,
75
+ "(?im).*feature deprecated with replacement\\ . id is deprecated\\ . It is replaced by elementId or consider using an application-generated id\\ ." )
76
+ .map (Pattern ::compile )
77
+ .toList ();
71
78
72
79
private ResultSummaries () {
73
80
}
@@ -86,29 +93,33 @@ static ResultSummary process(ResultSummary resultSummary) {
86
93
87
94
private static void logNotifications (ResultSummary resultSummary ) {
88
95
89
- if (resultSummary .notifications ().isEmpty () || !Neo4jClient .cypherLog .isWarnEnabled ()) {
96
+ if (resultSummary .gqlStatusObjects ().isEmpty () || !Neo4jClient .cypherLog .isWarnEnabled ()) {
90
97
return ;
91
98
}
92
99
93
100
boolean supressIdDeprecations = Neo4jClient .SUPPRESS_ID_DEPRECATIONS .getAcquire ();
94
- Predicate <Notification > isDeprecationWarningForId ;
101
+ Predicate <GqlNotification > isDeprecationWarningForId ;
95
102
try {
96
103
isDeprecationWarningForId = notification -> supressIdDeprecations
97
- && notification .category ()
98
- .orElse (NotificationCategory .UNRECOGNIZED )
99
- .equals (NotificationCategory .DEPRECATION )
100
- && DEPRECATED_ID_PATTERN .matcher (notification .description ()).matches ();
104
+ && notification .classification ()
105
+ .filter (cat -> cat == NotificationClassification .UNRECOGNIZED
106
+ || cat == NotificationClassification .DEPRECATION )
107
+ .isPresent ()
108
+ && STUFF_THAT_MIGHT_INFORM_THAT_THE_ID_FUNCTION_IS_PROBLEMATIC .stream ()
109
+ .anyMatch (p -> p .matcher (notification .statusDescription ()).matches ());
101
110
}
102
111
finally {
103
112
Neo4jClient .SUPPRESS_ID_DEPRECATIONS .setRelease (supressIdDeprecations );
104
113
}
105
114
106
115
String query = resultSummary .query ().text ();
107
- resultSummary .notifications ()
116
+ resultSummary .gqlStatusObjects ()
108
117
.stream ()
118
+ .filter (GqlNotification .class ::isInstance )
119
+ .map (GqlNotification .class ::cast )
109
120
.filter (Predicate .not (isDeprecationWarningForId ))
110
- .forEach (notification -> notification .severityLevel ().ifPresent (severityLevel -> {
111
- var category = notification .category ().orElse (null );
121
+ .forEach (notification -> notification .severity ().ifPresent (severityLevel -> {
122
+ var category = notification .classification ().orElse (null );
112
123
113
124
var logger = getLogAccessor (category );
114
125
Consumer <String > logFunction ;
@@ -130,35 +141,22 @@ else if (severityLevel == NotificationSeverity.OFF) {
130
141
}));
131
142
}
132
143
133
- private static LogAccessor getLogAccessor (@ Nullable NotificationCategory category ) {
134
- if (category == null ) {
144
+ private static LogAccessor getLogAccessor (@ Nullable NotificationClassification classification ) {
145
+ if (classification == null ) {
135
146
return Neo4jClient .cypherLog ;
136
147
}
137
- if (category .equals (NotificationCategory .HINT )) {
138
- return cypherHintNotificationLog ;
139
- }
140
- else if (category .equals (NotificationCategory .DEPRECATION )) {
141
- return cypherDeprecationNotificationLog ;
142
- }
143
- else if (category .equals (NotificationCategory .PERFORMANCE )) {
144
- return cypherPerformanceNotificationLog ;
145
- }
146
- else if (category .equals (NotificationCategory .GENERIC )) {
147
- return cypherGenericNotificationLog ;
148
- }
149
- else if (category .equals (NotificationCategory .UNSUPPORTED )) {
150
- return cypherUnsupportedNotificationLog ;
151
- }
152
- else if (category .equals (NotificationCategory .UNRECOGNIZED )) {
153
- return cypherUnrecognizedNotificationLog ;
154
- }
155
- else if (category .equals (NotificationCategory .SECURITY )) {
156
- return cypherSecurityNotificationLog ;
157
- }
158
- else if (category .equals (NotificationCategory .TOPOLOGY )) {
159
- return cypherTopologyNotificationLog ;
160
- }
161
- return Neo4jClient .cypherLog ;
148
+
149
+ return switch (classification ) {
150
+ case HINT -> cypherHintNotificationLog ;
151
+ case UNRECOGNIZED -> cypherUnrecognizedNotificationLog ;
152
+ case UNSUPPORTED -> cypherUnsupportedNotificationLog ;
153
+ case PERFORMANCE -> cypherPerformanceNotificationLog ;
154
+ case DEPRECATION -> cypherDeprecationNotificationLog ;
155
+ case SECURITY -> cypherSecurityNotificationLog ;
156
+ case TOPOLOGY -> cypherTopologyNotificationLog ;
157
+ case GENERIC -> cypherGenericNotificationLog ;
158
+ case SCHEMA -> cypherSchemaNotificationLog ;
159
+ };
162
160
}
163
161
164
162
/**
@@ -167,25 +165,23 @@ else if (category.equals(NotificationCategory.TOPOLOGY)) {
167
165
* @param forQuery the query that caused the notification
168
166
* @return a formatted string
169
167
*/
170
- static String format (Notification notification , String forQuery ) {
168
+ static String format (GqlNotification notification , String forQuery ) {
171
169
172
- InputPosition position = notification .position ();
173
- boolean hasPosition = position != null ;
170
+ var position = notification .position ().orElse (null );
174
171
175
172
StringBuilder queryHint = new StringBuilder ();
176
173
String [] lines = forQuery .split ("(\r \n |\n )" );
177
174
for (int i = 0 ; i < lines .length ; i ++) {
178
175
String line = lines [i ];
179
176
queryHint .append ("\t " ).append (line ).append (LINE_SEPARATOR );
180
- if (hasPosition && i + 1 == position .line ()) {
177
+ if (position != null && i + 1 == position .line ()) {
181
178
queryHint .append ("\t " )
182
179
.append (Stream .generate (() -> " " ).limit (position .column () - 1 ).collect (Collectors .joining ()))
183
180
.append ("^" )
184
181
.append (System .lineSeparator ());
185
182
}
186
183
}
187
- return String .format ("%s: %s%n%s%s" , notification .code (), notification .title (), queryHint ,
188
- notification .description ());
184
+ return String .format ("%s (%s):%n%s" , notification .statusDescription (), notification .gqlStatus (), queryHint );
189
185
}
190
186
191
187
/**
0 commit comments