queriesObserver.esm.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. import { difference, replaceAt } from './utils.esm.js';
  2. import { notifyManager } from './notifyManager.esm.js';
  3. import { QueryObserver } from './queryObserver.esm.js';
  4. import { Subscribable } from './subscribable.esm.js';
  5. class QueriesObserver extends Subscribable {
  6. constructor(client, queries) {
  7. super();
  8. this.client = client;
  9. this.queries = [];
  10. this.result = [];
  11. this.observers = [];
  12. this.observersMap = {};
  13. if (queries) {
  14. this.setQueries(queries);
  15. }
  16. }
  17. onSubscribe() {
  18. if (this.listeners.size === 1) {
  19. this.observers.forEach(observer => {
  20. observer.subscribe(result => {
  21. this.onUpdate(observer, result);
  22. });
  23. });
  24. }
  25. }
  26. onUnsubscribe() {
  27. if (!this.listeners.size) {
  28. this.destroy();
  29. }
  30. }
  31. destroy() {
  32. this.listeners = new Set();
  33. this.observers.forEach(observer => {
  34. observer.destroy();
  35. });
  36. }
  37. setQueries(queries, notifyOptions) {
  38. this.queries = queries;
  39. notifyManager.batch(() => {
  40. const prevObservers = this.observers;
  41. const newObserverMatches = this.findMatchingObservers(this.queries); // set options for the new observers to notify of changes
  42. newObserverMatches.forEach(match => match.observer.setOptions(match.defaultedQueryOptions, notifyOptions));
  43. const newObservers = newObserverMatches.map(match => match.observer);
  44. const newObserversMap = Object.fromEntries(newObservers.map(observer => [observer.options.queryHash, observer]));
  45. const newResult = newObservers.map(observer => observer.getCurrentResult());
  46. const hasIndexChange = newObservers.some((observer, index) => observer !== prevObservers[index]);
  47. if (prevObservers.length === newObservers.length && !hasIndexChange) {
  48. return;
  49. }
  50. this.observers = newObservers;
  51. this.observersMap = newObserversMap;
  52. this.result = newResult;
  53. if (!this.hasListeners()) {
  54. return;
  55. }
  56. difference(prevObservers, newObservers).forEach(observer => {
  57. observer.destroy();
  58. });
  59. difference(newObservers, prevObservers).forEach(observer => {
  60. observer.subscribe(result => {
  61. this.onUpdate(observer, result);
  62. });
  63. });
  64. this.notify();
  65. });
  66. }
  67. getCurrentResult() {
  68. return this.result;
  69. }
  70. getQueries() {
  71. return this.observers.map(observer => observer.getCurrentQuery());
  72. }
  73. getObservers() {
  74. return this.observers;
  75. }
  76. getOptimisticResult(queries) {
  77. return this.findMatchingObservers(queries).map(match => match.observer.getOptimisticResult(match.defaultedQueryOptions));
  78. }
  79. findMatchingObservers(queries) {
  80. const prevObservers = this.observers;
  81. const prevObserversMap = new Map(prevObservers.map(observer => [observer.options.queryHash, observer]));
  82. const defaultedQueryOptions = queries.map(options => this.client.defaultQueryOptions(options));
  83. const matchingObservers = defaultedQueryOptions.flatMap(defaultedOptions => {
  84. const match = prevObserversMap.get(defaultedOptions.queryHash);
  85. if (match != null) {
  86. return [{
  87. defaultedQueryOptions: defaultedOptions,
  88. observer: match
  89. }];
  90. }
  91. return [];
  92. });
  93. const matchedQueryHashes = new Set(matchingObservers.map(match => match.defaultedQueryOptions.queryHash));
  94. const unmatchedQueries = defaultedQueryOptions.filter(defaultedOptions => !matchedQueryHashes.has(defaultedOptions.queryHash));
  95. const matchingObserversSet = new Set(matchingObservers.map(match => match.observer));
  96. const unmatchedObservers = prevObservers.filter(prevObserver => !matchingObserversSet.has(prevObserver));
  97. const getObserver = options => {
  98. const defaultedOptions = this.client.defaultQueryOptions(options);
  99. const currentObserver = this.observersMap[defaultedOptions.queryHash];
  100. return currentObserver != null ? currentObserver : new QueryObserver(this.client, defaultedOptions);
  101. };
  102. const newOrReusedObservers = unmatchedQueries.map((options, index) => {
  103. if (options.keepPreviousData) {
  104. // return previous data from one of the observers that no longer match
  105. const previouslyUsedObserver = unmatchedObservers[index];
  106. if (previouslyUsedObserver !== undefined) {
  107. return {
  108. defaultedQueryOptions: options,
  109. observer: previouslyUsedObserver
  110. };
  111. }
  112. }
  113. return {
  114. defaultedQueryOptions: options,
  115. observer: getObserver(options)
  116. };
  117. });
  118. const sortMatchesByOrderOfQueries = (a, b) => defaultedQueryOptions.indexOf(a.defaultedQueryOptions) - defaultedQueryOptions.indexOf(b.defaultedQueryOptions);
  119. return matchingObservers.concat(newOrReusedObservers).sort(sortMatchesByOrderOfQueries);
  120. }
  121. onUpdate(observer, result) {
  122. const index = this.observers.indexOf(observer);
  123. if (index !== -1) {
  124. this.result = replaceAt(this.result, index, result);
  125. this.notify();
  126. }
  127. }
  128. notify() {
  129. notifyManager.batch(() => {
  130. this.listeners.forEach(({
  131. listener
  132. }) => {
  133. listener(this.result);
  134. });
  135. });
  136. }
  137. }
  138. export { QueriesObserver };
  139. //# sourceMappingURL=queriesObserver.esm.js.map