Skip to content

Commit 035fffd

Browse files
Add suggestions from the code review
1 parent 9a250ad commit 035fffd

7 files changed

+67
-54
lines changed

ballerina/annotation_processor.bal

+2-2
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ isolated function getInterceptorConfig(readonly & Interceptor interceptor) retur
127127
return classType.@InterceptorConfig;
128128
}
129129

130-
isolated function getCacheConfig(GraphqlServiceConfig? serviceConfig) returns ServerCacheConfig? {
130+
isolated function getCacheConfig(GraphqlServiceConfig? serviceConfig) returns readonly & ServerCacheConfig? {
131131
if serviceConfig is GraphqlServiceConfig {
132132
if serviceConfig.cacheConfig is ServerCacheConfig {
133133
return serviceConfig.cacheConfig;
@@ -136,7 +136,7 @@ isolated function getCacheConfig(GraphqlServiceConfig? serviceConfig) returns Se
136136
return;
137137
}
138138

139-
isolated function getFieldCacheConfigFromServiceConfig(GraphqlServiceConfig? serviceConfig) returns ServerCacheConfig? {
139+
isolated function getFieldCacheConfigFromServiceConfig(GraphqlServiceConfig? serviceConfig) returns readonly & ServerCacheConfig? {
140140
if serviceConfig is GraphqlServiceConfig {
141141
return serviceConfig.fieldCacheConfig;
142142
}

ballerina/engine.bal

+5-3
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ isolated class Engine {
3131

3232
isolated function init(string schemaString, int? maxQueryDepth, Service s,
3333
readonly & (readonly & Interceptor)[] interceptors, boolean introspection,
34-
boolean validation, ServerCacheConfig? cacheConfig = (), ServerCacheConfig? fieldCacheConfig = ())
34+
boolean validation, ServerCacheConfig? cacheConfig = (),
35+
ServerCacheConfig? fieldCacheConfig = ())
3536
returns Error? {
3637
if maxQueryDepth is int && maxQueryDepth < 1 {
3738
return error Error("Max query depth value must be a positive integer");
@@ -41,7 +42,7 @@ isolated class Engine {
4142
self.interceptors = interceptors;
4243
self.introspection = introspection;
4344
self.validation = validation;
44-
self.cacheConfig = cacheConfig.cloneReadOnly();
45+
self.cacheConfig = cacheConfig;
4546
self.cache = initCacheTable(cacheConfig, fieldCacheConfig);
4647
self.addService(s);
4748
}
@@ -284,7 +285,8 @@ isolated class Engine {
284285

285286
(readonly & Interceptor)? interceptor = context.getNextInterceptor('field);
286287
__Type fieldType = 'field.getFieldType();
287-
ResponseGenerator responseGenerator = new (self, context, fieldType, 'field.getPath().clone(), 'field.getCacheConfig().clone(), 'field.getParentArgHashes().clone());
288+
ResponseGenerator responseGenerator = new (self, context, fieldType, 'field.getPath().clone(),
289+
'field.getCacheConfig(), 'field.getParentArgHashes());
288290
do {
289291
if interceptor is readonly & Interceptor {
290292
any|error result = self.executeInterceptor(interceptor, 'field, context);

ballerina/field.bal

+18-13
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,14 @@ public class Field {
2727
private string[] resourcePath;
2828
private readonly & Interceptor[] fieldInterceptors;
2929
private final ServerCacheConfig? cacheConfig;
30-
private final string[] parentArgHashes;
30+
private final readonly & string[] parentArgHashes;
31+
private final boolean cacheEnabled;
32+
private final decimal cacheMaxAge;
3133

3234
isolated function init(parser:FieldNode internalNode, __Type fieldType, service object {}? serviceObject = (),
3335
(string|int)[] path = [], parser:RootOperationType operationType = parser:OPERATION_QUERY,
3436
string[] resourcePath = [], any|error fieldValue = (), ServerCacheConfig? cacheConfig = (),
35-
string[] parentArgHashes = []) {
37+
readonly & string[] parentArgHashes = []) {
3638
self.internalNode = internalNode;
3739
self.serviceObject = serviceObject;
3840
self.fieldType = fieldType;
@@ -45,8 +47,16 @@ public class Field {
4547
getFieldInterceptors(serviceObject, operationType, internalNode.getName(), self.resourcePath) : [];
4648
ServerCacheConfig? fieldCache = serviceObject is service object {} ?
4749
getFieldCacheConfig(serviceObject, operationType, internalNode.getName(), self.resourcePath) : ();
48-
self.cacheConfig = fieldCache is ServerCacheConfig ? fieldCache : cacheConfig;
50+
ServerCacheConfig? updatedCacheConfig = fieldCache is ServerCacheConfig ? fieldCache : cacheConfig;
51+
self.cacheConfig = updatedCacheConfig;
4952
self.parentArgHashes = parentArgHashes;
53+
if updatedCacheConfig is ServerCacheConfig {
54+
self.cacheEnabled = updatedCacheConfig.enabled;
55+
self.cacheMaxAge = updatedCacheConfig.maxAge;
56+
} else {
57+
self.cacheEnabled = false;
58+
self.cacheMaxAge = 0d;
59+
}
5060
}
5161

5262
# Returns the name of the field.
@@ -136,8 +146,8 @@ public class Field {
136146
foreach __Field 'field in typeFields {
137147
if 'field.name == selection.getName() {
138148
result.push(new Field(selection, 'field.'type, (),[...currentPath, ...unwrappedPath, 'field.name],
139-
self.operationType.clone(), self.resourcePath.clone(), cacheConfig = self.cacheConfig.clone(),
140-
parentArgHashes = self.parentArgHashes.clone()));
149+
self.operationType.clone(), self.resourcePath.clone(), cacheConfig = self.cacheConfig,
150+
parentArgHashes = self.parentArgHashes));
141151
break;
142152
}
143153
}
@@ -170,8 +180,7 @@ public class Field {
170180
}
171181

172182
isolated function isCacheEnabled() returns boolean {
173-
ServerCacheConfig? cacheConfig = self.getCacheConfig();
174-
return cacheConfig is ServerCacheConfig && cacheConfig.enabled;
183+
return self.cacheEnabled;
175184
}
176185

177186
isolated function getCacheConfig() returns ServerCacheConfig? {
@@ -183,14 +192,10 @@ public class Field {
183192
}
184193

185194
isolated function getCacheMaxAge() returns decimal {
186-
ServerCacheConfig? cacheConfig = self.getCacheConfig();
187-
if cacheConfig is ServerCacheConfig {
188-
return cacheConfig.maxAge;
189-
}
190-
return 0d;
195+
return self.cacheMaxAge;
191196
}
192197

193-
isolated function getParentArgHashes() returns string[] {
198+
isolated function getParentArgHashes() returns readonly & string[] {
194199
return self.parentArgHashes;
195200
}
196201

ballerina/listener.bal

+4-2
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ public class Listener {
7777
if self.graphiql.enabled {
7878
check validateGraphiqlPath(self.graphiql.path);
7979
string gqlServiceBasePath = name is () ? "" : getBasePath(name);
80-
engine = check new (schemaString, maxQueryDepth, s, interceptors, introspection, validation, operationCacheConfig, fieldCacheConfig);
80+
engine = check new (schemaString, maxQueryDepth, s, interceptors, introspection, validation,
81+
operationCacheConfig, fieldCacheConfig);
8182
__Schema & readonly schema = engine.getSchema();
8283
__Type? subscriptionType = schema.subscriptionType;
8384
string graphqlUrl = string `${self.httpEndpoint}/${gqlServiceBasePath}`;
@@ -91,7 +92,8 @@ public class Listener {
9192
return error Error("Error occurred while attaching the GraphiQL endpoint", result);
9293
}
9394
} else {
94-
engine = check new (schemaString, maxQueryDepth, s, interceptors, introspection, validation, operationCacheConfig, fieldCacheConfig);
95+
engine = check new (schemaString, maxQueryDepth, s, interceptors, introspection, validation,
96+
operationCacheConfig, fieldCacheConfig);
9597
}
9698

9799
HttpService httpService = getHttpService(engine, serviceConfig);

ballerina/response_generator.bal

+4-3
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,13 @@ class ResponseGenerator {
2323
private final Context context;
2424
private (string|int)[] path;
2525
private final __Type fieldType;
26-
private final ServerCacheConfig? cacheConfig;
27-
private final string[] parentArgHashes;
26+
private final readonly & ServerCacheConfig? cacheConfig;
27+
private final readonly & string[] parentArgHashes;
2828

2929
private final string functionNameGetFragmentFromService = "";
3030

31-
isolated function init(Engine engine, Context context, __Type fieldType, (string|int)[] path = [], ServerCacheConfig? cacheConfig = (), string[] parentArgHashes = []) {
31+
isolated function init(Engine engine, Context context, __Type fieldType, (string|int)[] path = [],
32+
ServerCacheConfig? cacheConfig = (), readonly & string[] parentArgHashes = []) {
3233
self.engine = engine;
3334
self.context = context;
3435
self.path = path;

ballerina/types.bal

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public type Graphiql record {|
7070
# + enabled - State of the caching
7171
# + maxAge - TTL of the cache in seconds
7272
# + maxSize - Maximum number of cache entries
73-
public type ServerCacheConfig record {|
73+
public type ServerCacheConfig readonly & record{|
7474
boolean enabled = true;
7575
decimal maxAge = 60;
7676
int maxSize = 120;

docs/spec/spec.md

+33-30
Original file line numberDiff line numberDiff line change
@@ -104,14 +104,14 @@ The conforming implementation of the specification is released and included in t
104104
* 7.1.6 [Service Interceptors](#716-service-interceptors)
105105
* 7.1.7 [Introspection Configurations](#717-introspection-configurations)
106106
* 7.1.8 [Constraint Configurations](#718-constraint-configurations)
107-
* 7.1.9 [Operation Cache Configurations](#719-operation-cache-configurations)
107+
* 7.1.9 [Operation-level Cache Configurations](#719-operation-level-cache-configurations)
108108
* 7.1.9.1 [The `enabled` Field](#7191-the-enabled-field)
109109
* 7.1.9.2 [The `maxAge` Field](#7192-the-maxage-field)
110110
* 7.1.9.3 [The `maxSize` Field](#7193-the-maxsize-field)
111111
* 7.2 [Resource Configuration](#72-resource-configuration)
112112
* 7.2.1 [Field Interceptors](#721-field-interceptors)
113113
* 7.2.2 [Prefetch Method Name Configuration](#722-prefetch-method-name-configuration)
114-
* 7.2.3 [Field Cache Configurations](#723-field-cache-configuration)
114+
* 7.2.3 [Field-level Cache Configurations](#723-field-level-cache-configuration)
115115
* 7.3 [Interceptor Configuration](#73-interceptor-configuration)
116116
* 7.3.1 [Scope Configuration](#731-scope-configuration)
117117
* 7.4 [ID Annotation](#74-id-annotation)
@@ -202,8 +202,8 @@ The conforming implementation of the specification is released and included in t
202202
* 10.6.3.3 [Define the Corresponding `prefetch` Method](#10633-define-the-corresponding-prefetch-method)
203203
* 10.7 [Caching](#107-caching)
204204
* 10.7.1 [Server-side Caching](#1071-server-side-caching)
205-
* 10.7.1.1 [Operation Caching](#10711-operation-caching)
206-
* 10.7.1.2 [Field Caching](#10712-field-caching)
205+
* 10.7.1.1 [Operation-level Caching](#10711-operation-level-caching)
206+
* 10.7.1.2 [Field-level Caching](#10712-field-level-caching)
207207
* 10.7.1.3 [Cache Eviction](#10713-cache-eviction)
208208
* 10.7.1.3.1 [The `invalidate` Method](#107131-the-invalidate-method)
209209
* 10.7.1.3.2 [The `invalidateAll` Method](#107132-the-invalidateall-method)
@@ -1774,43 +1774,46 @@ service on new graphql:Listener(9090) {
17741774
}
17751775
```
17761776

1777-
#### 7.1.9 Operation Cache Configurations
1777+
#### 7.1.9 Operation-level Cache Configurations
17781778

1779-
The `cacheConfig` field is used to provide the GraphQL operation cache configuration to enable the caching for `query` operations.
1779+
The `cacheConfig` field is used to provide the GraphQL operation-level cache configuration to enable the caching for `query` operations.
17801780

1781-
###### Example: Operation Cache Configurations
1781+
###### Example: Enable Operation-level Cache with Default Values
17821782

17831783
```ballerina
17841784
@graphql:ServiceConfig {
1785-
cacheConfig: {
1786-
enabled: true,
1787-
maxAge: 60,
1788-
maxSize: 120
1789-
}
1785+
cacheConfig: {}
17901786
}
17911787
service on new graphql:Listener(9090) {
17921788
// ...
17931789
}
17941790
```
17951791

1796-
###### Example: Enable Operation Cache with Default Values
1792+
###### Example: Operation-level Cache Configurations
17971793

17981794
```ballerina
17991795
@graphql:ServiceConfig {
1800-
cacheConfig: {}
1796+
cacheConfig: {
1797+
enabled: false
1798+
maxAge: 100,
1799+
maxSize: 150
1800+
}
18011801
}
18021802
service on new graphql:Listener(9090) {
18031803
// ...
18041804
}
18051805
```
18061806

18071807
##### 7.1.9.1 The `enabled` Field
1808+
18081809
The optinal field `enabled` accepts a `boolean` that denotes whether the server-side operation cache is enabled or not. By default, it has been set to `true`.
18091810

18101811
##### 7.1.9.2 The `maxAge` Field
1811-
The optional field `maxAge` accepts a valid `decimal` value which considers as the TTL(Time To Live) in seconds. The default maxAge is `60` seconds.
1812+
1813+
The optional field `maxAge` accepts a valid `decimal` value which is considerd as the TTL(Time To Live) in seconds. The default maxAge is `60` seconds.
18121814

18131815
##### 7.1.9.3 The `maxSize` Field
1816+
18141817
The optional field `maxSize` accepts an int that denotes the maximum number of cache entries in the cache table. By default, it has been set to `120`.
18151818

18161819
### 7.2 Resource Configuration
@@ -1873,20 +1876,20 @@ service on new graphql:Listener(9090) {
18731876
}
18741877
```
18751878

1876-
#### 7.2.3 Field Cache Configuration
1879+
#### 7.2.3 Field-level Cache Configuration
18771880

1878-
The `cacheConfig` field is used to provide the field cache configs. The fields are as same as the operation cache configs. The field configurations override the operation configurations.
1881+
The `cacheConfig` field is used to provide the field-level cache configs. The fields are as same as the operation cache configs. The field configurations override the operation configurations.
18791882

1880-
###### Example: Field Cache Configs
1883+
###### Example: Field-level Cache Configs
18811884

18821885
```ballerina
18831886
service on new graphql:Listener(9090) {
18841887
18851888
@graphql:ResourceConfig {
18861889
cacheConfig: {
18871890
enabled: true,
1888-
maxAge: 60,
1889-
maxSize: 120
1891+
maxAge: 90,
1892+
maxSize: 80
18901893
}
18911894
}
18921895
resource function get name(int id) returns string {
@@ -3595,7 +3598,7 @@ distinct service class Author {
35953598
}
35963599
```
35973600

3598-
###### Example: Overriding the Defalut `prefetch` Method Name
3601+
###### Example: Overriding the Default `prefetch` Method Name
35993602

36003603
```ballerina
36013604
distinct service class Author {
@@ -3612,7 +3615,7 @@ distinct service class Author {
36123615
}
36133616
```
36143617

3615-
Bringing everything together, the subsequent examples demonstrates how to engage a DataLoader with a GraphQL service.
3618+
Bringing everything together, the subsequent examples demonstrate how to engage a DataLoader with a GraphQL service.
36163619

36173620
###### Example: Utilizing a DataLoader in a GraphQL Service
36183621

@@ -3753,15 +3756,15 @@ This section describes the caching mechanisms in the Ballerina GraphQL module.
37533756

37543757
#### 10.7.1 Server-side Caching
37553758

3756-
The Ballerina GraphQL module offers built-in server-side caching for GraphQL `query` operations. The caching operates as in-memory caching, implemented using the Ballerina cache module. The GraphQL module generates cache keys based on the arguments and the path. In server-side caching, the `errors` and `null` values are skipped when caching. There are two different ways called `operation caching` and `field caching` to enable server-side caching.
3759+
The Ballerina GraphQL module offers built-in server-side caching for GraphQL `query` operations. The caching operates as in-memory caching, implemented using the Ballerina cache module. The GraphQL module generates cache keys based on the arguments and the path. In server-side caching, the `errors` and `null` values are skipped when caching. There are two different ways called `operation-level caching` and `field-level caching` to enable server-side caching.
37573760

3758-
##### 10.7.1.1 Operation Caching
3761+
##### 10.7.1.1 Operation-level Caching
37593762

3760-
Operation caching can be used to cache the entire operation, and this can be enabled by providing the [operation cache configurations](#719-operation-cache-configurations). Once enabled, the GraphQL server initiates caching for all subfields of `query` operations. The fields requested through query operations will be cached based on the specified cache configurations
3763+
Operation-level caching can be used to cache the entire operation, and this can be enabled by providing the [operation cache configurations](#719-operation-level-cache-configurations). Once enabled, the GraphQL server initiates caching for all subfields of `query` operations. The fields requested through query operations will be cached based on the specified cache configurations
37613764

3762-
##### 10.7.1.2 Field Caching
3765+
##### 10.7.1.2 Field-level Caching
37633766

3764-
The GraphQL field caching can be enabled only for a specific field. This can be done by providing the [field cache configurations](#723-field-cache-configuration). Once the field caching is enabled for a field, it will be applied to the sub-fields of that field.
3767+
The GraphQL field-level caching can be enabled only for a specific field. This can be done by providing the [field cache configurations](#723-field-level-cache-configuration). Once the field-level caching is enabled for a field, it will be applied to the sub-fields of that field.
37653768

37663769
#### 10.7.1.3 Cache Eviction
37673770

@@ -3783,7 +3786,7 @@ The `invalidateAll` method can be used to clear the entire cache table. This met
37833786
public isolated function invalidateAll() returns error? {}
37843787
```
37853788

3786-
###### Example: Operation Cache Enabling and Eviction
3789+
###### Example: Operation-level Cache Enabling and Eviction
37873790

37883791
```ballerina
37893792
import ballerina/graphql;
@@ -3816,7 +3819,7 @@ service /graphql on new graphql:Listener(9090) {
38163819

38173820
In this example, caching is enabled at the operation level. Therefore, the field `name` and `type` will be cached. When updating the name with a mutation, the cached values become invalid. Hence, the `invalidate` function can be used to evict the existing cache values.
38183821

3819-
###### Example: Field Cache Enabling and Eviction
3822+
###### Example: Field-level Cache Enabling and Eviction
38203823

38213824
```ballerina
38223825
import ballerina/graphql;
@@ -3883,4 +3886,4 @@ public isolated distinct service class Person {
38833886
}
38843887
```
38853888

3886-
In this example, GraphQL field caching is enabled for the `age` field via the resource configurations. When the age is changed using the `updateAge` operation, the `invalidate` method is used to remove the existing cache entries related to the age field.
3889+
In this example, GraphQL field-level caching is enabled for the `age` field via the resource configurations. When the age is changed using the `updateAge` operation, the `invalidate` method is used to remove the existing cache entries related to the age field.

0 commit comments

Comments
 (0)