Add fetch_cached() client-side ORM cache with SPA auto-reset
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -16,6 +16,10 @@
|
||||
* @Instantiatable
|
||||
*/
|
||||
class Rsx_Js_Model {
|
||||
// Client-side fetch cache: Map<"ModelName:id", Promise<model>>
|
||||
// Reset on SPA navigation, manual reset via orm_cache_reset()
|
||||
static _fetch_cache = new Map();
|
||||
|
||||
/**
|
||||
* Constructor - Initialize model instance with data
|
||||
*
|
||||
@@ -77,7 +81,11 @@ class Rsx_Js_Model {
|
||||
const response = await Orm_Controller.fetch({ model: modelName, id: id });
|
||||
|
||||
// Response is already hydrated by Ajax layer (Ajax.js calls _instantiate_models_recursive)
|
||||
// Just return the response directly
|
||||
|
||||
// Warm fetch cache for subsequent fetch_cached() calls
|
||||
const cache_key = `${modelName}:${id}`;
|
||||
Rsx_Js_Model._fetch_cache.set(cache_key, Promise.resolve(response));
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
@@ -100,9 +108,83 @@ class Rsx_Js_Model {
|
||||
// Pass or_null flag to get null instead of exception
|
||||
const response = await Orm_Controller.fetch({ model: modelName, id: id, or_null: true });
|
||||
|
||||
// Warm fetch cache on successful fetch (don't cache nulls)
|
||||
if (response !== null) {
|
||||
const cache_key = `${modelName}:${id}`;
|
||||
Rsx_Js_Model._fetch_cache.set(cache_key, Promise.resolve(response));
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch record using in-memory cache
|
||||
*
|
||||
* Returns cached result if available, otherwise calls fetch() and caches the result.
|
||||
* Stores promises so concurrent calls for the same model/id share a single backend
|
||||
* request. Cache automatically resets on SPA navigation.
|
||||
*
|
||||
* Intended for non-critical display data (names, labels, log history) where freshness
|
||||
* is not essential. Do NOT use for data that must reflect recent edits.
|
||||
*
|
||||
* @param {number} id - ID to fetch
|
||||
* @returns {Promise} - Model instance (from cache or fresh fetch)
|
||||
* @throws {Error} - If record not found or access denied
|
||||
*/
|
||||
static async fetch_cached(id) {
|
||||
const CurrentClass = this;
|
||||
const modelName = CurrentClass.__MODEL || CurrentClass.name;
|
||||
const cache_key = `${modelName}:${id}`;
|
||||
|
||||
if (Rsx_Js_Model._fetch_cache.has(cache_key)) {
|
||||
return Rsx_Js_Model._fetch_cache.get(cache_key);
|
||||
}
|
||||
|
||||
// Store the promise itself - concurrent calls for same model/id
|
||||
// await the same promise (single backend request)
|
||||
const promise = CurrentClass.fetch(id);
|
||||
Rsx_Js_Model._fetch_cache.set(cache_key, promise);
|
||||
|
||||
try {
|
||||
const result = await promise;
|
||||
return result;
|
||||
} catch (e) {
|
||||
// Failed fetches removed from cache so next attempt retries
|
||||
Rsx_Js_Model._fetch_cache.delete(cache_key);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the ORM fetch cache
|
||||
*
|
||||
* Called automatically on SPA navigation. Can also be called manually
|
||||
* after save operations to ensure subsequent fetch_cached() calls
|
||||
* retrieve fresh data.
|
||||
*
|
||||
* @param {string} [model_name] - Clear specific model only (all IDs)
|
||||
* @param {number} [id] - Clear specific model+id (requires model_name)
|
||||
*/
|
||||
static orm_cache_reset(model_name, id) {
|
||||
if (!model_name) {
|
||||
Rsx_Js_Model._fetch_cache.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
if (id !== undefined) {
|
||||
Rsx_Js_Model._fetch_cache.delete(`${model_name}:${id}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear all entries for specific model
|
||||
const prefix = `${model_name}:`;
|
||||
for (const key of Rsx_Js_Model._fetch_cache.keys()) {
|
||||
if (key.startsWith(prefix)) {
|
||||
Rsx_Js_Model._fetch_cache.delete(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the PHP model class name
|
||||
* Used internally for API calls
|
||||
|
||||
Reference in New Issue
Block a user