suspensive icon indicating copy to clipboard operation
suspensive copied to clipboard

[Feature]: createCache

Open SEOKKAMONI opened this issue 1 year ago • 2 comments

Package Scope

@suspensive/cache

Description

add createCache

Possible Solution

No response

etc.

No response

SEOKKAMONI avatar Aug 04 '24 05:08 SEOKKAMONI

const queryCache = createCache({
    invalidateInterval: 2000,
  })

queryCache.options()

queryCache.options()

const textQueryCache = () => queryCache.options({ cacheKey: [111,], cacheFn: () => Promise.resolve({ text: 5 }) })

return (
  <queryCache.Provider>
     <Cache {...textQueryCache()}>
       {(cached) => cached.data}
     </Cache>
  </queryCache.Provider>
)

const Example = () => {
  const queryCache = queryCache.use()
  const { data: text } = queryCache.use(textQueryCache())


 queryCache.invalidate()

  queryCache.reset()
}

manudeli avatar Aug 04 '24 06:08 manudeli

const unreachableUnique = symbol()

const createCache = ({ defaultOptions, options }) => {
  const cacheUnique = symbol()
  const context = createContext(defaultOptions)
  return {
    [unreachableUnique]: { cacheUnique, context }, // To make userCache["user" | "users"], not userCache.options["user" | "users"]
    ...combine(cacheUnique, unreachableUnique).with(options),
  }
}

const Cache = Object.assign(({ children, ...options }) => children(useCache(options)), {
  Provider: ({ cache }) => cache[unreachableUnique].context.Provider
})

const useCache = (options) => {
  const cacheControl = useCacheControl(options[unreachableUnique].cache)

  return useSyncExternalStore(
    (sync) => cacheControl.subscribe(options, sync),
    () => cacheControl.read(options),
    () => cacheControl.read(options)
  )
}

const queryCache = createCache({
  user: {
    fn: (userId: number) => api.user(userId), 
    invalidateInterval: 3000,
  },
  users: {
    fn: () => api.users()
  }
},
{
  invalidateInterval: 2000,
})

return (
  <Cache.Provider cache={queryCache}>
    <Suspense>
      <Cache {...queryCache.user(1)}>
        {(cached) => cached.data}
      </Cache>
    </Suspense>
  </Cache.Provider>
)

const Example = () => {
  const queryCacheControl = useCacheControl(queryCache)
  const cachedUser = useCache(queryCache.user(1))

  queryCacheControl.invalidate(queryCache.user(1))
  queryCacheControl.reset(queryCache.user(1))
}

manudeli avatar Aug 04 '24 07:08 manudeli

const unreachableUnique = symbol()

const createCache = ({ defaultOptions, options }) => {
  const cacheUnique = symbol()
  const context = createContext(defaultOptions)
  return {
    [unreachableUnique]: { cacheUnique, context }, // To make userCache["user" | "users"], not userCache.options["user" | "users"]
    ...combine(cacheUnique, unreachableUnique).with(options),
  }
}

const Cache = Object.assign(({ children, ...options }) => children(useCache(options)), {
  Provider: ({ cache }) => cache[unreachableUnique].context.Provider
})

const useRead = (options) => {
  const cache = useCache(options[unreachableUnique].cache)

  return useSyncExternalStore(
    (sync) => cache.subscribe(options, sync),
    () => cache.read(options),
    () => cache.read(options)
  )
}

const queryCache = createCache({
  user: {
    fn: (userId: number) => api.user(userId), 
    invalidateInterval: 3000,
  },
  users: {
    fn: () => api.users()
  }
},
{
  invalidateInterval: 2000,
})

return (
  <Cache.Provider cache={queryCache}>
    <Suspense>
      <Cache {...queryCache.user(1)}>
        {(cached) => cached.data}
      </Cache>
    </Suspense>
  </Cache.Provider>
)

const Example = () => {
  const queryCacheStore = useCacheStore(queryCache)
  const cachedUser = useRead(queryCache.user(1))

  queryCacheStore.invalidate(queryCache.user(1))
  queryCacheStore.reset(queryCache.user(1))
}

There is a Cache under the CacheStore, and a Cacheable exists under the Cache. The following example code applies the hierarchy I mentioned.

@manudeli if there are any parts that are not properly synced, please share them with me!

SEOKKAMONI avatar Aug 18 '24 15:08 SEOKKAMONI

People can be co-author:

Candidate Reasons Count Add this as commit message
@SEOKKAMONI https://github.com/toss/suspensive/issues/1191#issuecomment-2295304331 https://github.com/toss/suspensive/issues/1191#issuecomment-2298662236 https://github.com/toss/suspensive/issues/1191 3 Co-authored-by: SEOKKAMONI <[email protected]>
@manudeli https://github.com/toss/suspensive/issues/1191#issuecomment-2267358179 https://github.com/toss/suspensive/issues/1191#issuecomment-2267411286 https://github.com/toss/suspensive/issues/1191#issuecomment-2295595481 3 Co-authored-by: manudeli <[email protected]>

coauthors[bot] avatar Aug 18 '24 15:08 coauthors[bot]

I thought there is no name cachestore like below

const unreachableUnique = symbol()

const createCache = ({ defaultOptions, options }) => {
  const cacheUnique = symbol()
  const context = createContext(defaultOptions)
  return {
    [unreachableUnique]: { cacheUnique, context }, // To make userCache["user" | "users"], not userCache.options["user" | "users"]
    ...combine(cacheUnique, unreachableUnique).with(options),
  }
}

const useRead = (options) => {
  const cache = useCache(options[unreachableUnique].cache)

  return useSyncExternalStore(
    cache.subscribe,
    () => cache.read(options),
    () => cache.read(options)
  )
}

const query = createCache({
  user: {
    fn: (userId: number) => api.user(userId), 
    invalidateInterval: 3000,
  },
  users: {
    fn: () => api.users()
  }
})

return (
  <CacheProvider cache=[query]>
    <Suspense>
      <Read {...query.user(1)}>
        {({ data: user }) => user.name}
      </Read>
    </Suspense>
  </CacheProvider>
)

const Example = () => {
  const queryCache = useCache(query)
  const { data: user } = useRead(query.user(1))

  user

  queryCache.invalidate(query.user(1))
  queryCache.reset(query.user(1))
}

manudeli avatar Aug 19 '24 03:08 manudeli

Oh, I was mistaken. Controlling Cacheable through the Cache is indeed correct. Looking back at the interface I proposed, it was actually controlling Cacheable through CacheStore. Thank you for pointing out my mistake! So, is CacheStore not an interface that users actually interact with, but rather something that exists theoretically to represent a hierarchy?

SEOKKAMONI avatar Aug 20 '24 11:08 SEOKKAMONI