cacheService.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. import { api } from "src/boot/axios";
  2. const createDbConnection = (dbName = "apiCache", version = 1) => {
  3. let db = null;
  4. const ready = new Promise((resolve, reject) => {
  5. const request = indexedDB.open(dbName, version);
  6. request.onerror = () => reject(request.error);
  7. request.onsuccess = () => {
  8. db = request.result;
  9. resolve(db);
  10. };
  11. request.onupgradeneeded = (event) => {
  12. const db = event.target.result;
  13. if (!db.objectStoreNames.contains("apiCache")) {
  14. db.createObjectStore("apiCache", { keyPath: "key" });
  15. }
  16. };
  17. });
  18. return {
  19. getDb: () => ready,
  20. };
  21. };
  22. const { getDb } = createDbConnection();
  23. const getFromCache = async (key) => {
  24. const db = await getDb();
  25. return new Promise((resolve) => {
  26. const transaction = db.transaction(["apiCache"], "readonly");
  27. const store = transaction.objectStore("apiCache");
  28. const request = store.get(key);
  29. request.onsuccess = () => {
  30. const entry = request.result;
  31. if (entry?.timestamp + entry?.ttl > Date.now()) {
  32. resolve(entry.data);
  33. } else {
  34. resolve(null);
  35. }
  36. };
  37. });
  38. };
  39. const setInCache = async (key, data, ttl) => {
  40. const db = await getDb();
  41. const entry = {
  42. key,
  43. data,
  44. timestamp: Date.now(),
  45. ttl: ttl * 1000,
  46. };
  47. return new Promise((resolve) => {
  48. const transaction = db.transaction(["apiCache"], "readwrite");
  49. const store = transaction.objectStore("apiCache");
  50. store.put(entry);
  51. transaction.oncomplete = () => resolve();
  52. });
  53. };
  54. const clearCache = async (cacheKey) => {
  55. const db = await getDb();
  56. const transaction = db.transaction(["apiCache"], "readwrite");
  57. const store = transaction.objectStore("apiCache");
  58. return new Promise((resolve) => {
  59. if (!cacheKey) {
  60. store.clear();
  61. transaction.oncomplete = () => resolve();
  62. return;
  63. }
  64. const request = store.getAllKeys();
  65. request.onsuccess = () => {
  66. const deletePromises = request.result
  67. .filter((key) => key.includes(cacheKey))
  68. .map(
  69. (key) =>
  70. new Promise((resolve) => {
  71. const deleteRequest = store.delete(key);
  72. deleteRequest.onsuccess = () => resolve();
  73. }),
  74. );
  75. Promise.all(deletePromises).then(() => resolve());
  76. };
  77. });
  78. };
  79. export const createCachedApi = (namespace, ttl = 3600) => {
  80. const getCacheKey = (path) => `${namespace}:${path}`;
  81. const getResourcePaths = (path) => {
  82. const segments = path.split("/").filter(Boolean);
  83. const paths = [];
  84. for (let i = 0; i <= segments.length; i++) {
  85. const currentPath = "/" + segments.slice(0, i).join("/");
  86. paths.push(currentPath);
  87. }
  88. return paths;
  89. };
  90. const invalidateAll = async (path) => {
  91. const paths = getResourcePaths(path);
  92. await Promise.all(paths.map((path) => clearCache(getCacheKey(path))));
  93. };
  94. const get = async (path, options = {}) => {
  95. const key = getCacheKey(path);
  96. const cached = await getFromCache(key);
  97. if (cached) return cached;
  98. const { data } = await api.get(path);
  99. await setInCache(key, { data }, options.ttl ?? ttl);
  100. return { data };
  101. };
  102. const post = async (path, payload) => {
  103. const { data } = await api.post(path, payload);
  104. await invalidateAll(path);
  105. return { data };
  106. };
  107. const put = async (path, payload) => {
  108. const { data } = await api.put(path, payload);
  109. await invalidateAll(path);
  110. return { data };
  111. };
  112. const del = async (path) => {
  113. const { data } = await api.delete(path);
  114. await invalidateAll(path);
  115. return { data };
  116. };
  117. return { get, post, put, del, invalidateAll };
  118. };