apollo-kotlin icon indicating copy to clipboard operation
apollo-kotlin copied to clipboard

Normalized cache: handle dangling references

Open piotr-pawlowski opened this issue 4 years ago • 3 comments

ApolloStore: does remove(key: CacheKey) method remove ApolloCacheReference field in related records? I mean a mechanism like "ON DELETE CASCADE SET NULL" in RDBMS.

piotr-pawlowski avatar Aug 06 '20 20:08 piotr-pawlowski

This method with flag cascade = true looks for children and deletes them with root record (cacheKey).

From SqlNormalizedCache:

 override fun remove(cacheKey: CacheKey, cascade: Boolean): Boolean {
    val result: Boolean = nextCache?.remove(cacheKey, cascade) ?: false
    if (result) {
      return true
    }
    return if (cascade) {
      selectRecordForKey(cacheKey.key)
          ?.referencedFields()
          ?.all { remove(CacheKey(it.key), cascade = true) }
          ?: false
    } else {
      deleteRecord(cacheKey.key)
    }
  }

From cache.sq:

recordForKey:
SELECT key, record FROM records WHERE key=?;

So this method loads the record from database, retrieves referencedFields (children for that loaded record) and deletes them all with given record.

But what about referencing field? There should be a solution to remove references from parent records to provide consistency of database.

For example:

SELECT key, record FROM records WHERE record LIKE '%ApolloCacheReference{<cache key>}%'

And then clear that referencing field from the record by merge method or somehow. Without that solution there is no way to fetch parent data from cache, because there occurs MISS field error (there is still ApolloCacheReference field to a child record that doesn't exists in database).

piotr-pawlowski avatar Aug 13 '20 15:08 piotr-pawlowski

Hoping to dig into this soon. I'm realizing just now that cascade wasn't a great naming choice as it's about deleting children, not parents like SQL is doing.

apollo-client refers to this as dangling references and handles them with readFunctions.

I think something similar would work. Compared to cascade delete, that'd keep the dangling reference around in case it becomes valid again. I think that could be handy?

I tweaked the name of this issue a bit so that it's more clear in https://github.com/apollographql/apollo-kotlin/issues/2331

martinbonnin avatar Apr 06 '22 10:04 martinbonnin