Skip to content

Commit 3618c3d

Browse files
authored
Update README.md
1 parent 47e6ae3 commit 3618c3d

File tree

1 file changed

+173
-1
lines changed

1 file changed

+173
-1
lines changed

README.md

Lines changed: 173 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,173 @@
1-
# SwiftDataLoader
1+
# SwiftDataLoader
2+
SwiftDataLoader is a generic utility to be used as part of your application's data fetching layer to provide a simplified and consistent API over various remote data sources such as databases or web services via batching and caching.
3+
4+
This is a Swift version of the Facebook [DataLoader](https://github.com/facebook/dataloader).
5+
6+
[![CircleCI](https://circleci.com/gh/kimdv/SwiftDataLoader.svg?style=svg)](https://circleci.com/gh/kimdv/SwiftDataLoader)
7+
[![codecov](https://codecov.io/gh/kimdv/SwiftDataLoader/branch/master/graph/badge.svg)](https://codecov.io/gh/kimdv/SwiftDataLoader)
8+
9+
## Installation 💻
10+
11+
Update your `Package.swift` file.
12+
13+
```swift
14+
.Package(url: "https://github.com/kimdv/SwiftDataLoader.git", majorVersion: 1)
15+
```
16+
17+
## Gettings started 🚀
18+
### Batching
19+
Batching is not an advanced feature, it's DataLoader's primary feature.
20+
21+
Create a DataLoader by providing a batch loading function
22+
```swift
23+
let userLoader = Dataloader<Int, User>(batchLoadFunction: { keys in
24+
try User.query(on: req).filter(\User.id ~~ keys).all().map { users in
25+
return users.map { DataLoaderFutureValue.success($0) }
26+
}
27+
})
28+
```
29+
#### Load single key
30+
```
31+
let future1 = try userLoader.load(key: 1, on: req)
32+
let future2 = try userLoader.load(key: 2, on: req)
33+
let future3 = try userLoader.load(key: 1, on: req)
34+
```
35+
36+
Now there is only one thing left and that is to dispathc it `try userLoader.dispatchQueue(on: req.eventLoop)`
37+
38+
The example above will only fetch users twice because `future1 == future3`
39+
40+
#### Load multiple keys
41+
There is also an API to load multiple keys at once
42+
```
43+
try userLoader.loadMany(keys: [1, 2, 3], on: req.eventLoop)
44+
```
45+
46+
### Disable batching
47+
It is also possible to disable batching `DataLoaderOptions(batchingEnabled: false)`
48+
It will invoke `batchLoadFunction` with a single key
49+
50+
### Chaching
51+
52+
DataLoader provides a memoization cache for all loads which occur in a single
53+
request to your application. After `.load()` is called once with a given key,
54+
the resulting value is cached to eliminate redundant loads.
55+
56+
In addition to relieving pressure on your data storage, caching results per-request
57+
also creates fewer objects which may relieve memory pressure on your application:
58+
59+
```swift
60+
let userLoader = DataLoader<Int, Int>(...)
61+
let future1 = userLoader.load(1)
62+
let future2 = userLoader.load(1)
63+
assert(future1 === future2)
64+
```
65+
66+
#### Caching per-Request
67+
68+
DataLoader caching *does not* replace Redis, Memcache, or any other shared
69+
application-level cache. DataLoader is first and foremost a data loading mechanism,
70+
and its cache only serves the purpose of not repeatedly loading the same data in
71+
the context of a single request to your Application. To do this, it maintains a
72+
simple in-memory memoization cache (more accurately: `.load()` is a memoized function).
73+
74+
Avoid multiple requests from different users using the DataLoader instance, which
75+
could result in cached data incorrectly appearing in each request. Typically,
76+
DataLoader instances are created when a Request begins, and are not used once the
77+
Request ends.
78+
79+
#### Clearing Cache
80+
81+
In certain uncommon cases, clearing the request cache may be necessary.
82+
83+
The most common example when clearing the loader's cache is necessary is after
84+
a mutation or update within the same request, when a cached value could be out of
85+
date and future loads should not use any possibly cached value.
86+
87+
Here's a simple example using SQL UPDATE to illustrate.
88+
89+
```swift
90+
// Request begins...
91+
let userLoader = DataLoader<Int, Int>(...)
92+
93+
// And a value happens to be loaded (and cached).
94+
userLoader.load(4)
95+
96+
// A mutation occurs, invalidating what might be in cache.
97+
sqlRun('UPDATE users WHERE id=4 SET username="zuck"').then { userLoader.clear(4) }
98+
99+
// Later the value load is loaded again so the mutated data appears.
100+
userLoader.load(4)
101+
102+
// Request completes.
103+
```
104+
105+
#### Caching Errors
106+
107+
If a batch load fails (that is, a batch function throws or returns a DataLoaderFutureValue.failure(Error)),
108+
then the requested values will not be cached. However if a batch
109+
function returns an `Error` instance for an individual value, that `Error` will
110+
be cached to avoid frequently loading the same `Error`.
111+
112+
In some circumstances you may wish to clear the cache for these individual Errors:
113+
114+
```swift
115+
userLoader.load(1).catch { error in {
116+
if (/* determine if should clear error */) {
117+
userLoader.clear(1);
118+
}
119+
throw error
120+
}
121+
```
122+
123+
#### Disabling Cache
124+
125+
In certain uncommon cases, a DataLoader which *does not* cache may be desirable.
126+
Calling `DataLoader(options: DataLoaderOptions(cachingEnabled: false), batchLoadFunction: batchLoadFunction)` will ensure that every
127+
call to `.load()` will produce a *new* Future, and requested keys will not be
128+
saved in memory.
129+
130+
However, when the memoization cache is disabled, your batch function will
131+
receive an array of keys which may contain duplicates! Each key will be
132+
associated with each call to `.load()`. Your batch loader should provide a value
133+
for each instance of the requested key.
134+
135+
For example:
136+
137+
```swift
138+
let myLoader = DataLoader<String, String>(options: DataLoaderOptions(cachingEnabled: false), batchLoadFunction: { keys in
139+
self.someBatchLoader(keys: keys).map { DataLoaderFutureValue.success($0) }
140+
})
141+
142+
myLoader.load("A")
143+
myLoader.load("B")
144+
myLoader.load("A")
145+
146+
// > [ "A", "B", "A" ]
147+
```
148+
149+
More complex cache behavior can be achieved by calling `.clear()` or `.clearAll()`
150+
rather than disabling the cache completely. For example, this DataLoader will
151+
provide unique keys to a batch function due to the memoization cache being
152+
enabled, but will immediately clear its cache when the batch function is called
153+
so later requests will load new values.
154+
155+
```swift
156+
let myLoader = DataLoader<String, String>(batchLoadFunction: { keys in
157+
identityLoader.clearAll()
158+
return someBatchLoad(keys: keys)
159+
})
160+
```
161+
162+
## Contributing 🤘
163+
164+
All your feedback and help to improve this project is very welcome. Please create issues for your bugs, ideas and enhancement requests, or better yet, contribute directly by creating a PR. 😎
165+
166+
When reporting an issue, please add a detailed instruction, and if possible a code snippet or test that can be used as a reproducer of your problem. 💥
167+
168+
When creating a pull request, please adhere to the current coding style where possible, and create tests with your code so it keeps providing an awesome test coverage level 💪
169+
170+
## Acknowledgements 👏
171+
172+
This library is entirely a Swift version of Facebooks [DataLoader](https://github.com/facebook/dataloader). Developed by [Lee Byron](https://github.com/leebyron) and
173+
[Nicholas Schrock](https://github.com/schrockn) from [Facebook](https://www.facebook.com/).

0 commit comments

Comments
 (0)