SerializerMiddleware.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. */
  4. "use strict";
  5. const memoize = require("../util/memoize");
  6. const LAZY_TARGET = Symbol("lazy serialization target");
  7. const LAZY_SERIALIZED_VALUE = Symbol("lazy serialization data");
  8. /**
  9. * @template DeserializedType
  10. * @template SerializedType
  11. */
  12. class SerializerMiddleware {
  13. /* istanbul ignore next */
  14. /**
  15. * @abstract
  16. * @param {DeserializedType} data data
  17. * @param {object} context context object
  18. * @returns {SerializedType|Promise<SerializedType>} serialized data
  19. */
  20. serialize(data, context) {
  21. const AbstractMethodError = require("../AbstractMethodError");
  22. throw new AbstractMethodError();
  23. }
  24. /* istanbul ignore next */
  25. /**
  26. * @abstract
  27. * @param {SerializedType} data data
  28. * @param {object} context context object
  29. * @returns {DeserializedType|Promise<DeserializedType>} deserialized data
  30. */
  31. deserialize(data, context) {
  32. const AbstractMethodError = require("../AbstractMethodError");
  33. throw new AbstractMethodError();
  34. }
  35. /**
  36. * @param {any | function(): Promise<any> | any} value contained value or function to value
  37. * @param {SerializerMiddleware<any, any>} target target middleware
  38. * @param {object=} options lazy options
  39. * @param {any=} serializedValue serialized value
  40. * @returns {function(): Promise<any> | any} lazy function
  41. */
  42. static createLazy(value, target, options = {}, serializedValue) {
  43. if (SerializerMiddleware.isLazy(value, target)) return value;
  44. const fn = typeof value === "function" ? value : () => value;
  45. fn[LAZY_TARGET] = target;
  46. /** @type {any} */ (fn).options = options;
  47. fn[LAZY_SERIALIZED_VALUE] = serializedValue;
  48. return fn;
  49. }
  50. /**
  51. * @param {function(): Promise<any> | any} fn lazy function
  52. * @param {SerializerMiddleware<any, any>=} target target middleware
  53. * @returns {boolean} true, when fn is a lazy function (optionally of that target)
  54. */
  55. static isLazy(fn, target) {
  56. if (typeof fn !== "function") return false;
  57. const t = fn[LAZY_TARGET];
  58. return target ? t === target : !!t;
  59. }
  60. /**
  61. * @param {function(): Promise<any> | any} fn lazy function
  62. * @returns {object} options
  63. */
  64. static getLazyOptions(fn) {
  65. if (typeof fn !== "function") return undefined;
  66. return /** @type {any} */ (fn).options;
  67. }
  68. /**
  69. * @param {function(): Promise<any> | any} fn lazy function
  70. * @returns {any} serialized value
  71. */
  72. static getLazySerializedValue(fn) {
  73. if (typeof fn !== "function") return undefined;
  74. return fn[LAZY_SERIALIZED_VALUE];
  75. }
  76. /**
  77. * @param {function(): Promise<any> | any} fn lazy function
  78. * @param {any} value serialized value
  79. * @returns {void}
  80. */
  81. static setLazySerializedValue(fn, value) {
  82. fn[LAZY_SERIALIZED_VALUE] = value;
  83. }
  84. /**
  85. * @param {function(): Promise<any> | any} lazy lazy function
  86. * @param {function(any): Promise<any> | any} serialize serialize function
  87. * @returns {function(): Promise<any> | any} new lazy
  88. */
  89. static serializeLazy(lazy, serialize) {
  90. const fn = memoize(() => {
  91. const r = lazy();
  92. if (r && typeof r.then === "function") {
  93. return r.then(data => data && serialize(data));
  94. }
  95. return serialize(r);
  96. });
  97. fn[LAZY_TARGET] = lazy[LAZY_TARGET];
  98. /** @type {any} */ (fn).options = /** @type {any} */ (lazy).options;
  99. lazy[LAZY_SERIALIZED_VALUE] = fn;
  100. return fn;
  101. }
  102. /**
  103. * @param {function(): Promise<any> | any} lazy lazy function
  104. * @param {function(any): Promise<any> | any} deserialize deserialize function
  105. * @returns {function(): Promise<any> | any} new lazy
  106. */
  107. static deserializeLazy(lazy, deserialize) {
  108. const fn = memoize(() => {
  109. const r = lazy();
  110. if (r && typeof r.then === "function") {
  111. return r.then(data => deserialize(data));
  112. }
  113. return deserialize(r);
  114. });
  115. fn[LAZY_TARGET] = lazy[LAZY_TARGET];
  116. /** @type {any} */ (fn).options = /** @type {any} */ (lazy).options;
  117. fn[LAZY_SERIALIZED_VALUE] = lazy;
  118. return fn;
  119. }
  120. /**
  121. * @param {function(): Promise<any> | any} lazy lazy function
  122. * @returns {function(): Promise<any> | any} new lazy
  123. */
  124. static unMemoizeLazy(lazy) {
  125. if (!SerializerMiddleware.isLazy(lazy)) return lazy;
  126. const fn = () => {
  127. throw new Error(
  128. "A lazy value that has been unmemorized can't be called again"
  129. );
  130. };
  131. fn[LAZY_SERIALIZED_VALUE] = SerializerMiddleware.unMemoizeLazy(
  132. lazy[LAZY_SERIALIZED_VALUE]
  133. );
  134. fn[LAZY_TARGET] = lazy[LAZY_TARGET];
  135. fn.options = /** @type {any} */ (lazy).options;
  136. return fn;
  137. }
  138. }
  139. module.exports = SerializerMiddleware;