QueueDb.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. /*
  2. Copyright 2021 Google LLC
  3. Use of this source code is governed by an MIT-style
  4. license that can be found in the LICENSE file or at
  5. https://opensource.org/licenses/MIT.
  6. */
  7. import { openDB } from 'idb';
  8. import '../_version.js';
  9. const DB_VERSION = 3;
  10. const DB_NAME = 'workbox-background-sync';
  11. const REQUEST_OBJECT_STORE_NAME = 'requests';
  12. const QUEUE_NAME_INDEX = 'queueName';
  13. /**
  14. * A class to interact directly an IndexedDB created specifically to save and
  15. * retrieve QueueStoreEntries. This class encapsulates all the schema details
  16. * to store the representation of a Queue.
  17. *
  18. * @private
  19. */
  20. export class QueueDb {
  21. constructor() {
  22. this._db = null;
  23. }
  24. /**
  25. * Add QueueStoreEntry to underlying db.
  26. *
  27. * @param {UnidentifiedQueueStoreEntry} entry
  28. */
  29. async addEntry(entry) {
  30. const db = await this.getDb();
  31. const tx = db.transaction(REQUEST_OBJECT_STORE_NAME, 'readwrite', {
  32. durability: 'relaxed',
  33. });
  34. await tx.store.add(entry);
  35. await tx.done;
  36. }
  37. /**
  38. * Returns the first entry id in the ObjectStore.
  39. *
  40. * @return {number | undefined}
  41. */
  42. async getFirstEntryId() {
  43. const db = await this.getDb();
  44. const cursor = await db
  45. .transaction(REQUEST_OBJECT_STORE_NAME)
  46. .store.openCursor();
  47. return cursor === null || cursor === void 0 ? void 0 : cursor.value.id;
  48. }
  49. /**
  50. * Get all the entries filtered by index
  51. *
  52. * @param queueName
  53. * @return {Promise<QueueStoreEntry[]>}
  54. */
  55. async getAllEntriesByQueueName(queueName) {
  56. const db = await this.getDb();
  57. const results = await db.getAllFromIndex(REQUEST_OBJECT_STORE_NAME, QUEUE_NAME_INDEX, IDBKeyRange.only(queueName));
  58. return results ? results : new Array();
  59. }
  60. /**
  61. * Returns the number of entries filtered by index
  62. *
  63. * @param queueName
  64. * @return {Promise<number>}
  65. */
  66. async getEntryCountByQueueName(queueName) {
  67. const db = await this.getDb();
  68. return db.countFromIndex(REQUEST_OBJECT_STORE_NAME, QUEUE_NAME_INDEX, IDBKeyRange.only(queueName));
  69. }
  70. /**
  71. * Deletes a single entry by id.
  72. *
  73. * @param {number} id the id of the entry to be deleted
  74. */
  75. async deleteEntry(id) {
  76. const db = await this.getDb();
  77. await db.delete(REQUEST_OBJECT_STORE_NAME, id);
  78. }
  79. /**
  80. *
  81. * @param queueName
  82. * @returns {Promise<QueueStoreEntry | undefined>}
  83. */
  84. async getFirstEntryByQueueName(queueName) {
  85. return await this.getEndEntryFromIndex(IDBKeyRange.only(queueName), 'next');
  86. }
  87. /**
  88. *
  89. * @param queueName
  90. * @returns {Promise<QueueStoreEntry | undefined>}
  91. */
  92. async getLastEntryByQueueName(queueName) {
  93. return await this.getEndEntryFromIndex(IDBKeyRange.only(queueName), 'prev');
  94. }
  95. /**
  96. * Returns either the first or the last entries, depending on direction.
  97. * Filtered by index.
  98. *
  99. * @param {IDBCursorDirection} direction
  100. * @param {IDBKeyRange} query
  101. * @return {Promise<QueueStoreEntry | undefined>}
  102. * @private
  103. */
  104. async getEndEntryFromIndex(query, direction) {
  105. const db = await this.getDb();
  106. const cursor = await db
  107. .transaction(REQUEST_OBJECT_STORE_NAME)
  108. .store.index(QUEUE_NAME_INDEX)
  109. .openCursor(query, direction);
  110. return cursor === null || cursor === void 0 ? void 0 : cursor.value;
  111. }
  112. /**
  113. * Returns an open connection to the database.
  114. *
  115. * @private
  116. */
  117. async getDb() {
  118. if (!this._db) {
  119. this._db = await openDB(DB_NAME, DB_VERSION, {
  120. upgrade: this._upgradeDb,
  121. });
  122. }
  123. return this._db;
  124. }
  125. /**
  126. * Upgrades QueueDB
  127. *
  128. * @param {IDBPDatabase<QueueDBSchema>} db
  129. * @param {number} oldVersion
  130. * @private
  131. */
  132. _upgradeDb(db, oldVersion) {
  133. if (oldVersion > 0 && oldVersion < DB_VERSION) {
  134. if (db.objectStoreNames.contains(REQUEST_OBJECT_STORE_NAME)) {
  135. db.deleteObjectStore(REQUEST_OBJECT_STORE_NAME);
  136. }
  137. }
  138. const objStore = db.createObjectStore(REQUEST_OBJECT_STORE_NAME, {
  139. autoIncrement: true,
  140. keyPath: 'id',
  141. });
  142. objStore.createIndex(QUEUE_NAME_INDEX, QUEUE_NAME_INDEX, { unique: false });
  143. }
  144. }