queriesObserver.js 5.3 KB

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