diff --git a/README.md b/README.md
index ccd14625..3a06ce6a 100644
--- a/README.md
+++ b/README.md
@@ -14,7 +14,17 @@
## 🚀 Apollo Kotlin Normalized Cache
-This repository hosts [Apollo Kotlin](https://github.com/apollographql/apollo-kotlin)'s new normalized cache, aiming to replace the main repository version.
+This repository hosts [Apollo Kotlin](https://github.com/apollographql/apollo-kotlin)'s new normalized cache, aiming to replace the main repository's version.
+
+Compared to the previous version, this new normalized cache brings:
+
+- [Pagination support](https://apollographql.github.io/apollo-kotlin-normalized-cache/pagination-home.html)
+- [Cache control](https://apollographql.github.io/apollo-kotlin-normalized-cache/cache-control.html) (a.k.a. Time to live or expiration)
+- [Garbage collection](https://apollographql.github.io/apollo-kotlin-normalized-cache/garbage-collection.html), and [trimming](https://apollographql.github.io/apollo-kotlin-normalized-cache/trimming.html)
+- Partial results from the cache
+- API simplifications
+- Key scope support
+- SQL cache improved performance
## 📚 Documentation
diff --git a/Writerside/doc.tree b/Writerside/doc.tree
index b8d91ebf..088a405c 100644
--- a/Writerside/doc.tree
+++ b/Writerside/doc.tree
@@ -18,5 +18,7 @@
+
+
diff --git a/Writerside/topics/cache-control.md b/Writerside/topics/cache-control.md
index d46b9d0e..cfc318ab 100644
--- a/Writerside/topics/cache-control.md
+++ b/Writerside/topics/cache-control.md
@@ -102,20 +102,6 @@ extend type Book @cacheControlField(name: "cachedTitle", maxAge: 30)
extend type Reader @cacheControlField(name: "book", inheritMaxAge: true)
```
-Then configure the Cache compiler plugin in your `build.gradle.kts`:
-
-```kotlin
-apollo {
- service("service") {
- packageName.set(/*...*/)
-
- plugin("com.apollographql.cache:normalized-cache-apollo-compiler-plugin:%latest_version%") {
- argument("packageName", packageName.get())
- }
- }
-}
-```
-
This will generate a map in `yourpackage.cache.Cache.maxAges`, that you can pass to the `SchemaCoordinatesMaxAgeProvider`:
```kotlin
diff --git a/Writerside/topics/compiler-plugin.md b/Writerside/topics/compiler-plugin.md
new file mode 100644
index 00000000..0184c588
--- /dev/null
+++ b/Writerside/topics/compiler-plugin.md
@@ -0,0 +1,241 @@
+# Compiler plugin
+
+When setting up the Normalized Cache in your project, you need to configure the compiler plugin:
+
+```kotlin
+// build.gradle.kts
+apollo {
+ service("service") {
+ // ...
+
+ // Add this
+ plugin("com.apollographql.cache:normalized-cache-apollo-compiler-plugin:%latest_version%") {
+ argument("packageName", packageName.get())
+ }
+ }
+}
+```
+
+This plugin generates some code to support the Normalized Cache features, such as declarative cache IDs, pagination and cache control.
+
+## Declarative cache IDs (`@typePolicy`)
+
+You can refer to the [declarative cache IDs documentation](https://www.apollographql.com/docs/kotlin/caching/declarative-ids)
+for a general overview of this feature.
+
+Here are some additional details of what the compiler plugin does to support it.
+
+Let's consider this schema for example:
+
+```graphql
+# schema.graphqls
+type Query {
+ user(id: ID!): User
+}
+
+type User {
+ id: ID!
+ email: String!
+ name: String!
+}
+```
+
+```graphql
+# extra.graphqls
+extend type User @typePolicy(keyFields: "id")
+```
+
+### Generation of `typePolicies`
+
+A map of type names to `TypePolicy` instances is generated in a `Cache` object.
+
+In the example above, the generated code will look like this:
+
+```kotlin
+object cache {
+ val typePolicies: Map = mapOf(
+ "User" to TypePolicy(keyFields = setOf("id"))
+ )
+}
+
+```
+
+Pass this map to the `TypePolicyCacheKeyGenerator` when configuring the cache:
+
+```kotlin
+val apolloClient = ApolloClient.Builder()
+ // ...
+ .normalizedCache(
+ // ...
+ cacheKeyGenerator = TypePolicyCacheKeyGenerator(Cache.typePolicies)
+ )
+ .build()
+```
+
+### Addition of key fields and `__typename` to selections
+
+The compiler automatically adds the key fields declared with `@typePolicy` to the selections that return that type.
+This is to ensure that a `CacheKey` can be generated for the record.
+
+When you query for `User`, e.g.:
+
+```graphql
+# operations.graphql
+query User {
+ user(id: "1") {
+ email
+ name
+ }
+}
+```
+
+The compiler plugin will automatically add the `id` and `__typename` fields to the selection set, resulting in:
+
+```graphql
+query User {
+ user(id: "1") {
+ __typename # Added by the compiler plugin
+ email
+ name
+ id # Added by the compiler plugin
+ }
+}
+```
+
+Now, [TypePolicyCacheKeyGenerator](https://apollographql.github.io/apollo-kotlin-normalized-cache/kdoc/normalized-cache/com.apollographql.cache.normalized.api/-type-policy-cache-key-generator.html?query=fun%20TypePolicyCacheKeyGenerator(typePolicies:%20Map%3CString,%20TypePolicy%3E,%20keyScope:%20CacheKey.Scope%20=%20CacheKey.Scope.TYPE):%20CacheKeyGenerator)
+can use the value of `__typename` as the type of the returned object, and from that see that there is one key field, `id`, for that type.
+
+From that it can return `User:42` as the cache key for that record.
+
+> If your schema has ids that are unique across the service, you can pass `CacheKey.Scope.SERVICE` to the `TypePolicyCacheKeyGenerator` constructor to save space in the cache.
+>
+> In that example the cache key would be `42` instead of `User:42`.
+
+#### Unions and interfaces
+
+Let's consider this example:
+
+```graphql
+# schema.graphqls
+type Query {
+ search(text: String!): [SearchResult!]!
+}
+
+type Product {
+ shopId: String!
+ productId: String!
+ description: String!
+}
+
+type Book {
+ isbn: ID!
+ title: String!
+}
+
+union SearchResult = User | Post
+```
+
+```graphql
+# extra.graphqls
+extend type Product @typePolicy(keyFields: "shopId productId")
+extend type Book @typePolicy(keyFields: "isbn")
+```
+
+```graphql
+# operations.graphql
+query Search($text: String!) {
+ search(text: $text) {
+ ... on Book {
+ title
+ }
+ }
+}
+```
+
+The plugin needs to add the key fields of all possible types of `SearchResult`, like so:
+
+```graphql
+query Search($text: String!) {
+ search(text: $text) {
+ __typename # Added by the compiler plugin
+ ... on Book {
+ title
+ }
+ # Added by the compiler plugin
+ ... on Book {
+ isbn
+ }
+ ... on Product {
+ shopId
+ productId
+ }
+ }
+}
+```
+
+The principle is the same with interfaces, for instance:
+
+```graphql
+# schema.graphqls
+type Query {
+ search(text: String!): [SearchResult!]!
+}
+
+interface SearchResult {
+ summary: String!
+}
+
+type Product implements SearchResult {
+ summary: String!
+ shopId: String!
+ productId: String!
+}
+
+type Book implements SearchResult {
+ summary: String!
+ isbn: ID!
+ title: String!
+}
+```
+
+The modified query would look the same as above, with the key fields of `Product` and `Book` added to the selection set.
+
+> If key fields are defined on the interface itself, they only need to be added once, instead of once per possible type.
+
+## Resolving to cache keys (`@fieldPolicy`)
+
+When a field returns a type that has key fields, and takes arguments that correspond to these keys, you can use the `@fieldPolicy` directive.
+
+For instance,
+
+```graphql
+# schema.graphqls
+type Query {
+ user(id: ID!): User
+}
+
+type User {
+ id: ID!
+ email: String!
+ name: String!
+}
+```
+
+```graphql
+# extra.graphqls
+extend type User @typePolicy(keyFields: "id")
+
+extend type Query @fieldPolicy(forField: "user", keyArgs: "id")
+```
+
+From this, when selecting e.g. `user(id: 42)` the `FieldPolicyCacheResolver` knows to return `User:42` as a `CacheKey`,
+thus saving a network request if the record is already in the cache.
+
+#### Unions and interfaces {id="field-policy-unions-and-interfaces"}
+
+If a field returns a union or interface it is not possible to know which concrete type will be returned at runtime, and thus prefixing
+the cache key with the correct type name is not possible. Avoiding a network call is not possible here.
+
+However, if your schema has ids that are unique across the service, you can pass `CacheKey.Scope.SERVICE` to the `FieldPolicyCacheResolver` constructor to skip the type name in the cache key.
+Network call avoidance will still work in that case.
+
diff --git a/Writerside/topics/migration-guide.md b/Writerside/topics/migration-guide.md
index f04a9590..697267bb 100644
--- a/Writerside/topics/migration-guide.md
+++ b/Writerside/topics/migration-guide.md
@@ -1,9 +1,11 @@
# Migration guide
-The Apollo Kotlin Normalized Cache used to be part of the [Apollo Kotlin main repository](https://github.com/apollographql/apollo-kotlin).
-It is now hosted in this dedicated repository and published at its own cadence and versioning scheme.
+The Normalized Cache is now hosted in this dedicated repository and published at its own cadence and versioning scheme.
-This guide highlights the main differences between this library and the "classic" version, and how to migrate to it.
+The Normalized Cache in the [Apollo Kotlin main repository](https://github.com/apollographql/apollo-kotlin) will not receive new features - they
+are added here instead. In the future, the main repository Normalized Cache will be deprecated and then removed.
+
+This guide highlights the main differences between this library and the main repository version, and how to migrate from it.
## Artifacts and packages
@@ -38,11 +40,9 @@ import com.apollographql.apollo.cache.normalized.api.MemoryCacheFactory
import com.apollographql.cache.normalized.memory.MemoryCacheFactory
```
-In most cases, this will be enough to migrate your project, but there were a few renames and API breaking changes. Read on for more details.
-
## Compiler plugin
-Configure the compiler plugin in your `build.gradle.kts` file:
+Configure the [compiler plugin](compiler-plugin.md) in your `build.gradle.kts` file:
```kotlin
apollo {
@@ -57,6 +57,9 @@ apollo {
}
```
+In most cases, updating the coordinates/imports and adding the compiler plugin will be enough to migrate your project.
+But there were also a few renames and API breaking changes - read on for more details.
+
## Database schema
The SQLite cache now uses a different schema.
diff --git a/Writerside/topics/trimming.md b/Writerside/topics/trimming.md
new file mode 100644
index 00000000..1c5d4618
--- /dev/null
+++ b/Writerside/topics/trimming.md
@@ -0,0 +1,16 @@
+# Trimming the cache
+
+By default, if you don't use [cache control](cache-control.md) and [garbage collection](garbage-collection.md),
+the cache will grow indefinitely as more data is written to it.
+
+To prevent this, a few APIs are available:
+
+- [`ApolloStore.clearAll()`](https://apollographql.github.io/apollo-kotlin-normalized-cache/kdoc/normalized-cache/com.apollographql.cache.normalized/-apollo-store/index.html#-1013497887%2FFunctions%2F-1172623753):
+ clear the entire cache.
+- [`ApolloStore.remove()`](https://apollographql.github.io/apollo-kotlin-normalized-cache/kdoc/normalized-cache/com.apollographql.cache.normalized/-apollo-store/index.html#-1351099158%2FFunctions%2F-1172623753):
+ remove specific records.
+- [`ApolloStore.removeOperation()`](https://apollographql.github.io/apollo-kotlin-normalized-cache/kdoc/normalized-cache/com.apollographql.cache.normalized/remove-operation.html?query=fun%20%3CD%20:%20Operation.Data%3E%20ApolloStore.removeOperation(operation:%20Operation%3CD%3E,%20data:%20D,%20cacheHeaders:%20CacheHeaders%20=%20CacheHeaders.NONE):%20Set%3CString%3E) and [
+ `ApolloStore.removeFragment()`](https://apollographql.github.io/apollo-kotlin-normalized-cache/kdoc/normalized-cache/com.apollographql.cache.normalized/remove-fragment.html?query=fun%20%3CD%20:%20Fragment.Data%3E%20ApolloStore.removeFragment(fragment:%20Fragment%3CD%3E,%20cacheKey:%20CacheKey,%20data:%20D,%20cacheHeaders:%20CacheHeaders%20=%20CacheHeaders.NONE):%20Set%3CString%3E):
+ remove the records associated to specific operations or fragments.
+- [`ApolloStore.trim()`](https://apollographql.github.io/apollo-kotlin-normalized-cache/kdoc/normalized-cache/com.apollographql.cache.normalized/-cache-manager/trim.html):
+ trim the cache by a specified amount (by default 10%) if it exceeds a certain size. The oldest (according to their updated date) records are removed.
diff --git a/Writerside/topics/welcome.md b/Writerside/topics/welcome.md
index 4f04ac1b..8fa66af5 100644
--- a/Writerside/topics/welcome.md
+++ b/Writerside/topics/welcome.md
@@ -4,8 +4,20 @@ This is [Apollo Kotlin](https://github.com/apollographql/apollo-kotlin)'s Normal
For an introduction please read the Normalized Cache [documentation](https://www.apollographql.com/docs/kotlin/caching/normalized-cache).
-Note: the Normalized Cache used to be part of the [Apollo Kotlin main repository](https://github.com/apollographql/apollo-kotlin).
-It is now hosted in this dedicated repository and published at its own cadence and versioning scheme.
+The Normalized Cache is now hosted in this dedicated repository and published at its own cadence and versioning scheme.
+
+Compared to the previous version, this library brings:
+
+- [Pagination support](pagination-home.md)
+- [](cache-control.md) (a.k.a. Time to live or expiration)
+- [](garbage-collection.md), and [trimming](trimming.md)
+- Partial results from the cache
+- API simplifications
+- Key scope support
+- SQL cache improved performance
+
+The Normalized Cache in the [Apollo Kotlin main repository](https://github.com/apollographql/apollo-kotlin) will not receive new features - they
+are added here instead. In the future, the main repository Normalized Cache will be deprecated and then removed.
## Use in your project
@@ -14,7 +26,7 @@ It is now hosted in this dedicated repository and published at its own cadence a
{style="warning"}
-Add the dependencies to your project.
+1. Add the dependencies to your project
```kotlin
// build.gradle.kts
@@ -27,4 +39,20 @@ dependencies {
}
```
-If you were using the classic Normalized Cache before, please consult the [migration guide](migration-guide.md).
+2. Configure the [compiler plugin](compiler-plugin.md)
+
+```kotlin
+// build.gradle.kts
+apollo {
+ service("service") {
+ // ...
+
+ // Add this
+ plugin("com.apollographql.cache:normalized-cache-apollo-compiler-plugin:%latest_version%") {
+ argument("packageName", packageName.get())
+ }
+ }
+}
+```
+
+If you're already using the main repository Normalized Cache, please consult the [migration guide](migration-guide.md).