You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+23-16
Original file line number
Diff line number
Diff line change
@@ -10,14 +10,14 @@ It can serve as integral part of your application's data layer to provide a
10
10
consistent API over various back-ends and reduce message communication overhead through batching and caching.
11
11
12
12
An important use case for `java-dataloader` is improving the efficiency of GraphQL query execution. Graphql fields
13
-
are resolved in a independent manner and with a true graph of objects, you may be fetching the same object many times.
13
+
are resolved independently and, with a true graph of objects, you may be fetching the same object many times.
14
14
15
15
A naive implementation of graphql data fetchers can easily lead to the dreaded "n+1" fetch problem.
16
16
17
17
Most of the code is ported directly from Facebook's reference implementation, with one IMPORTANT adaptation to make
18
18
it work for Java 8. ([more on this below](#manual-dispatching)).
19
19
20
-
But before reading on, be sure to take a short dive into the
20
+
Before reading on, be sure to take a short dive into the
21
21
[original documentation](https://github.com/facebook/dataloader/blob/master/README.md) provided by Lee Byron (@leebyron)
22
22
and Nicholas Schrock (@schrockn) from [Facebook](https://www.facebook.com/), the creators of the original data loader.
23
23
@@ -51,7 +51,8 @@ and Nicholas Schrock (@schrockn) from [Facebook](https://www.facebook.com/), the
51
51
- Results are ordered according to insertion order of load requests
52
52
- Deals with partial errors when a batch future fails
53
53
- Can disable batching and/or caching in configuration
54
-
- Can supply your own [`CacheMap<K, V>`](https://github.com/graphql-java/java-dataloader/blob/master/src/main/java/io/engagingspaces/vertx/dataloader/CacheMap.java) implementations
54
+
- Can supply your own `CacheMap<K, V>` implementations
55
+
- Can supply your own `ValueCache<K, V>` implementations
55
56
- Has very high test coverage
56
57
57
58
## Examples
@@ -110,7 +111,7 @@ In this version of data loader, this does not happen automatically. More on thi
110
111
111
112
As stated on the original Facebook project :
112
113
113
-
>A naive application may have issued four round-trips to a backend for the required information,
114
+
>A naive application may have issued four round-trips to a backend for the required information,
114
115
but with DataLoader this application will make at most two.
115
116
116
117
> DataLoader allows you to decouple unrelated parts of your application without sacrificing the
@@ -270,9 +271,9 @@ This is not quite as loose in a Java implementation as Java is a type safe langu
270
271
271
272
A batch loader function is defined as `BatchLoader<K, V>` meaning for a key of type `K` it returns a value of type `V`.
272
273
273
-
It cant just return some `Exception` as an object of type `V`. Type safety matters.
274
+
It can't just return some `Exception` as an object of type `V`. Type safety matters.
274
275
275
-
However you can use the `Try` data type which can encapsulate a computation that succeeded or returned an exception.
276
+
However, you can use the `Try` data type which can encapsulate a computation that succeeded or returned an exception.
276
277
277
278
```java
278
279
Try<String> tryS =Try.tryCall(() -> {
@@ -291,7 +292,7 @@ However you can use the `Try` data type which can encapsulate a computation that
291
292
}
292
293
```
293
294
294
-
DataLoader supports this type and you can use this form to create a batch loader that returns a list of `Try` objects, some of which may have succeeded
295
+
DataLoader supports this type, and you can use this form to create a batch loader that returns a list of `Try` objects, some of which may have succeeded,
295
296
and some of which may have failed. From that data loader can infer the right behavior in terms of the `load(x)` promise.
296
297
297
298
```java
@@ -331,7 +332,7 @@ The value cache uses an async API pattern to encapsulate the idea that the value
331
332
The default future cache behind `DataLoader` is an in memory `HashMap`. There is no expiry on this, and it lives for as long as the data loader
332
333
lives.
333
334
334
-
However, you can create your own custom cache and supply it to the data loader on construction via the `org.dataloader.CacheMap` interface.
335
+
However, you can create your own custom future cache and supply it to the data loader on construction via the `org.dataloader.CacheMap` interface.
335
336
336
337
```java
337
338
MyCustomCache customCache =newMyCustomCache();
@@ -342,21 +343,27 @@ However, you can create your own custom cache and supply it to the data loader o
342
343
You could choose to use one of the fancy cache implementations from Guava or Caffeine and wrap it in a `CacheMap` wrapper ready
343
344
for data loader. They can do fancy things like time eviction and efficient LRU caching.
344
345
345
-
As stated above, a custom `org.dataloader.CacheMap` is a local cache of futures with values, not values per se.
346
+
As stated above, a custom `org.dataloader.CacheMap` is a local cache of `CompleteFuture`s to values, not values per se.
347
+
348
+
If you want to externally cache values then you need to use the `org.dataloader.ValueCache` interface.
346
349
347
350
## Custom value caches
348
351
349
-
You will need to create your own implementations of the `org.dataloader.ValueCache` if your want to use an external cache.
352
+
The `org.dataloader.ValueCache` allows you to use an external cache.
353
+
354
+
The API of `ValueCache` has been designed to be asynchronous because it is expected that the value cache could be outside
355
+
your JVM. It uses `CompleteableFuture`s to get and set values into cache, which may involve a network call and hence exceptional failures to get
356
+
or set values.
357
+
358
+
The `ValueCache` API is batch oriented, if you have a backing cache that can do batch cache fetches (such a REDIS) then you can use the `ValueCache.getValues*(`
359
+
call directly. However, if you don't have such a backing cache, then the default implementation will break apart the batch of cache value into individual requests
360
+
to `ValueCache.getValue()` for you.
350
361
351
362
This library does not ship with any implementations of `ValueCache` because it does not want to have
352
363
production dependencies on external cache libraries, but you can easily write your own.
353
364
354
365
The tests have an example based on [Caffeine](https://github.com/ben-manes/caffeine).
355
366
356
-
The API of `ValueCache` has been designed to be asynchronous because it is expected that the value cache could be outside
357
-
your JVM. It uses `CompleteableFuture`s to get and set values into cache, which may involve a network call and hence exceptional failures to get
358
-
or set values.
359
-
360
367
361
368
## Disabling caching
362
369
@@ -369,7 +376,7 @@ In certain uncommon cases, a DataLoader which does not cache may be desirable.
369
376
Calling the above will ensure that every call to `.load()` will produce a new promise, and requested keys will not be saved in memory.
370
377
371
378
However, when the memoization cache is disabled, your batch function will receive an array of keys which may contain duplicates! Each key will
372
-
be associated with each call to `.load()`. Your batch loader should provide a value for each instance of the requested key as per the contract
379
+
be associated with each call to `.load()`. Your batch loader MUST provide a value for each instance of the requested key as per the contract
373
380
374
381
```java
375
382
userDataLoader.load("A");
@@ -445,7 +452,7 @@ then you will not want to cache data meant for user A to then later give it user
445
452
The scope of your `DataLoader` instances is important. You will want to create them per web request to ensure data is only cached within that
446
453
web request and no more.
447
454
448
-
If your data can be shared across web requests then use a custom cache to keep values in a common place.
455
+
If your data can be shared across web requests then use a custom `org.dataloader.ValueCache` to keep values in a common place.
449
456
450
457
Data loaders are stateful components that contain promises (with context) that are likely share the same affinity as the request.
0 commit comments