Source: databases/documents.js

  1. /**
  2. * @namespace Databases-Documents
  3. * @memberof module:Databases
  4. * @description Documents database.
  5. * @example <caption>Create documents db with custom index</caption>
  6. * import { createHelia } from 'helia'
  7. * import { createOrbitDB, Documents } from 'orbitdb'
  8. *
  9. * const ipfs = createHelia()
  10. * const orbitdb = await createOrbitDB({ ipfs })
  11. * const db = await orbitdb.open('my-docs', { Database: Documents({ indexBy: 'myCustomId'} ) }
  12. *
  13. * @augments module:Databases~Database
  14. */
  15. import Database from '../database.js'
  16. const type = 'documents'
  17. const DefaultOptions = { indexBy: '_id' }
  18. /**
  19. * Defines a Documents database.
  20. * @param {Object} options Various options for configuring the Document store.
  21. * @param {string} [options.indexBy=_id] An index.
  22. * @return {module:Databases.Databases-Documents} A Documents function.
  23. * @memberof module:Databases
  24. */
  25. const Documents = ({ indexBy } = DefaultOptions) => async ({ ipfs, identity, address, name, access, directory, meta, headsStorage, entryStorage, indexStorage, referencesCount, syncAutomatically, onUpdate, encrypt }) => {
  26. const database = await Database({ ipfs, identity, address, name, access, directory, meta, headsStorage, entryStorage, indexStorage, referencesCount, syncAutomatically, encrypt })
  27. const { addOperation, log } = database
  28. /**
  29. * Stores a document to the store.
  30. * @function
  31. * @param {Object} doc An object representing a key/value list of fields.
  32. * @return {string} The hash of the new oplog entry.
  33. * @memberof module:Databases.Databases-Documents
  34. * @instance
  35. */
  36. const put = async (doc) => {
  37. const key = doc[indexBy]
  38. if (!key) { throw new Error(`The provided document doesn't contain field '${indexBy}'`) }
  39. return addOperation({ op: 'PUT', key, value: doc })
  40. }
  41. /**
  42. * Deletes a document from the store.
  43. * @function
  44. * @param {string} key The key of the doc to delete.
  45. * @return {string} The hash of the new oplog entry.
  46. * @memberof module:Databases.Databases-Documents
  47. * @instance
  48. */
  49. const del = async (key) => {
  50. if (!await get(key)) { throw new Error(`No document with key '${key}' in the database`) }
  51. return addOperation({ op: 'DEL', key, value: null })
  52. }
  53. /**
  54. * Gets a document from the store by key.
  55. * @function
  56. * @param {string} key The key of the doc to get.
  57. * @return {Object} The doc corresponding to key or null.
  58. * @memberof module:Databases.Databases-Documents
  59. * @instance
  60. */
  61. const get = async (key) => {
  62. for await (const doc of iterator()) {
  63. if (key === doc.key) {
  64. return doc
  65. }
  66. }
  67. }
  68. /**
  69. * Queries the document store for documents matching mapper filters.
  70. * @function
  71. * @param {function(Object)} findFn A function for querying for specific
  72. * results.
  73. *
  74. * The findFn function's signature takes the form `function(doc)` where doc
  75. * is a document's value property. The function should return true if the
  76. * document should be included in the results, false otherwise.
  77. * @return {Array} Found documents.
  78. * @memberof module:Databases.Databases-Documents
  79. * @instance
  80. */
  81. const query = async (findFn) => {
  82. const results = []
  83. for await (const doc of iterator()) {
  84. if (findFn(doc.value)) {
  85. results.push(doc.value)
  86. }
  87. }
  88. return results
  89. }
  90. /**
  91. * Iterates over documents.
  92. * @function
  93. * @param {Object} [filters={}] Various filters to apply to the iterator.
  94. * @param {string} [filters.amount=-1] The number of results to fetch.
  95. * @yields [string, string, string] The next document as hash/key/value.
  96. * @memberof module:Databases.Databases-Documents
  97. * @instance
  98. */
  99. const iterator = async function * ({ amount } = {}) {
  100. const keys = {}
  101. let count = 0
  102. for await (const entry of log.iterator()) {
  103. const { op, key, value } = entry.payload
  104. if (op === 'PUT' && !keys[key]) {
  105. keys[key] = true
  106. count++
  107. const hash = entry.hash
  108. yield { hash, key, value }
  109. } else if (op === 'DEL' && !keys[key]) {
  110. keys[key] = true
  111. }
  112. if (count >= amount) {
  113. break
  114. }
  115. }
  116. }
  117. /**
  118. * Returns all documents.
  119. * @function
  120. * @return [][string, string, string] An array of documents as hash/key
  121. * value entries.
  122. * @memberof module:Databases.Databases-Documents
  123. * @instance
  124. */
  125. const all = async () => {
  126. const values = []
  127. for await (const entry of iterator()) {
  128. values.unshift(entry)
  129. }
  130. return values
  131. }
  132. return {
  133. ...database,
  134. type,
  135. put,
  136. del,
  137. get,
  138. iterator,
  139. query,
  140. indexBy,
  141. all
  142. }
  143. }
  144. Documents.type = type
  145. export default Documents