cache.cjs 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. "use strict";
  2. var __defProp = Object.defineProperty;
  3. var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
  4. var __getOwnPropNames = Object.getOwnPropertyNames;
  5. var __hasOwnProp = Object.prototype.hasOwnProperty;
  6. var __export = (target, all) => {
  7. for (var name in all)
  8. __defProp(target, name, { get: all[name], enumerable: true });
  9. };
  10. var __copyProps = (to, from, except, desc) => {
  11. if (from && typeof from === "object" || typeof from === "function") {
  12. for (let key of __getOwnPropNames(from))
  13. if (!__hasOwnProp.call(to, key) && key !== except)
  14. __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  15. }
  16. return to;
  17. };
  18. var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
  19. var cache_exports = {};
  20. __export(cache_exports, {
  21. UpstashCache: () => UpstashCache,
  22. upstashCache: () => upstashCache
  23. });
  24. module.exports = __toCommonJS(cache_exports);
  25. var import_redis = require("@upstash/redis");
  26. var import_core = require("../core/index.cjs");
  27. var import_entity = require("../../entity.cjs");
  28. var import__ = require("../../index.cjs");
  29. const getByTagScript = `
  30. local tagsMapKey = KEYS[1] -- tags map key
  31. local tag = ARGV[1] -- tag
  32. local compositeTableName = redis.call('HGET', tagsMapKey, tag)
  33. if not compositeTableName then
  34. return nil
  35. end
  36. local value = redis.call('HGET', compositeTableName, tag)
  37. return value
  38. `;
  39. const onMutateScript = `
  40. local tagsMapKey = KEYS[1] -- tags map key
  41. local tables = {} -- initialize tables array
  42. local tags = ARGV -- tags array
  43. for i = 2, #KEYS do
  44. tables[#tables + 1] = KEYS[i] -- add all keys except the first one to tables
  45. end
  46. if #tags > 0 then
  47. for _, tag in ipairs(tags) do
  48. if tag ~= nil and tag ~= '' then
  49. local compositeTableName = redis.call('HGET', tagsMapKey, tag)
  50. if compositeTableName then
  51. redis.call('HDEL', compositeTableName, tag)
  52. end
  53. end
  54. end
  55. redis.call('HDEL', tagsMapKey, unpack(tags))
  56. end
  57. local keysToDelete = {}
  58. if #tables > 0 then
  59. local compositeTableNames = redis.call('SUNION', unpack(tables))
  60. for _, compositeTableName in ipairs(compositeTableNames) do
  61. keysToDelete[#keysToDelete + 1] = compositeTableName
  62. end
  63. for _, table in ipairs(tables) do
  64. keysToDelete[#keysToDelete + 1] = table
  65. end
  66. redis.call('DEL', unpack(keysToDelete))
  67. end
  68. `;
  69. class UpstashCache extends import_core.Cache {
  70. constructor(redis, config, useGlobally) {
  71. super();
  72. this.redis = redis;
  73. this.useGlobally = useGlobally;
  74. this.internalConfig = this.toInternalConfig(config);
  75. this.luaScripts = {
  76. getByTagScript: this.redis.createScript(getByTagScript, { readonly: true }),
  77. onMutateScript: this.redis.createScript(onMutateScript)
  78. };
  79. }
  80. static [import_entity.entityKind] = "UpstashCache";
  81. /**
  82. * Prefix for sets which denote the composite table names for each unique table
  83. *
  84. * Example: In the composite table set of "table1", you may find
  85. * `${compositeTablePrefix}table1,table2` and `${compositeTablePrefix}table1,table3`
  86. */
  87. static compositeTableSetPrefix = "__CTS__";
  88. /**
  89. * Prefix for hashes which map hash or tags to cache values
  90. */
  91. static compositeTablePrefix = "__CT__";
  92. /**
  93. * Key which holds the mapping of tags to composite table names
  94. *
  95. * Using this tagsMapKey, you can find the composite table name for a given tag
  96. * and get the cache value for that tag:
  97. *
  98. * ```ts
  99. * const compositeTable = redis.hget(tagsMapKey, 'tag1')
  100. * console.log(compositeTable) // `${compositeTablePrefix}table1,table2`
  101. *
  102. * const cachevalue = redis.hget(compositeTable, 'tag1')
  103. */
  104. static tagsMapKey = "__tagsMap__";
  105. /**
  106. * Queries whose auto invalidation is false aren't stored in their respective
  107. * composite table hashes because those hashes are deleted when a mutation
  108. * occurs on related tables.
  109. *
  110. * Instead, they are stored in a separate hash with the prefix
  111. * `__nonAutoInvalidate__` to prevent them from being deleted when a mutation
  112. */
  113. static nonAutoInvalidateTablePrefix = "__nonAutoInvalidate__";
  114. luaScripts;
  115. internalConfig;
  116. strategy() {
  117. return this.useGlobally ? "all" : "explicit";
  118. }
  119. toInternalConfig(config) {
  120. return config ? {
  121. seconds: config.ex,
  122. hexOptions: config.hexOptions
  123. } : {
  124. seconds: 1
  125. };
  126. }
  127. async get(key, tables, isTag = false, isAutoInvalidate) {
  128. if (!isAutoInvalidate) {
  129. const result2 = await this.redis.hget(UpstashCache.nonAutoInvalidateTablePrefix, key);
  130. return result2 === null ? void 0 : result2;
  131. }
  132. if (isTag) {
  133. const result2 = await this.luaScripts.getByTagScript.exec([UpstashCache.tagsMapKey], [key]);
  134. return result2 === null ? void 0 : result2;
  135. }
  136. const compositeKey = this.getCompositeKey(tables);
  137. const result = (await this.redis.hget(compositeKey, key)) ?? void 0;
  138. return result === null ? void 0 : result;
  139. }
  140. async put(key, response, tables, isTag = false, config) {
  141. const isAutoInvalidate = tables.length !== 0;
  142. const pipeline = this.redis.pipeline();
  143. const ttlSeconds = config && config.ex ? config.ex : this.internalConfig.seconds;
  144. const hexOptions = config && config.hexOptions ? config.hexOptions : this.internalConfig?.hexOptions;
  145. if (!isAutoInvalidate) {
  146. if (isTag) {
  147. pipeline.hset(UpstashCache.tagsMapKey, { [key]: UpstashCache.nonAutoInvalidateTablePrefix });
  148. pipeline.hexpire(UpstashCache.tagsMapKey, key, ttlSeconds, hexOptions);
  149. }
  150. pipeline.hset(UpstashCache.nonAutoInvalidateTablePrefix, { [key]: response });
  151. pipeline.hexpire(UpstashCache.nonAutoInvalidateTablePrefix, key, ttlSeconds, hexOptions);
  152. await pipeline.exec();
  153. return;
  154. }
  155. const compositeKey = this.getCompositeKey(tables);
  156. pipeline.hset(compositeKey, { [key]: response });
  157. pipeline.hexpire(compositeKey, key, ttlSeconds, hexOptions);
  158. if (isTag) {
  159. pipeline.hset(UpstashCache.tagsMapKey, { [key]: compositeKey });
  160. pipeline.hexpire(UpstashCache.tagsMapKey, key, ttlSeconds, hexOptions);
  161. }
  162. for (const table of tables) {
  163. pipeline.sadd(this.addTablePrefix(table), compositeKey);
  164. }
  165. await pipeline.exec();
  166. }
  167. async onMutate(params) {
  168. const tags = Array.isArray(params.tags) ? params.tags : params.tags ? [params.tags] : [];
  169. const tables = Array.isArray(params.tables) ? params.tables : params.tables ? [params.tables] : [];
  170. const tableNames = tables.map((table) => (0, import_entity.is)(table, import__.Table) ? table[import__.OriginalName] : table);
  171. const compositeTableSets = tableNames.map((table) => this.addTablePrefix(table));
  172. await this.luaScripts.onMutateScript.exec([UpstashCache.tagsMapKey, ...compositeTableSets], tags);
  173. }
  174. addTablePrefix = (table) => `${UpstashCache.compositeTableSetPrefix}${table}`;
  175. getCompositeKey = (tables) => `${UpstashCache.compositeTablePrefix}${tables.sort().join(",")}`;
  176. }
  177. function upstashCache({ url, token, config, global = false }) {
  178. const redis = new import_redis.Redis({
  179. url,
  180. token
  181. });
  182. return new UpstashCache(redis, config, global);
  183. }
  184. // Annotate the CommonJS export names for ESM import in node:
  185. 0 && (module.exports = {
  186. UpstashCache,
  187. upstashCache
  188. });
  189. //# sourceMappingURL=cache.cjs.map