Source: storage-wallet.js

import DockWallet from './dock-wallet';

/** The Dock Wallet which loads, adds, removes and queries contents in an EDV */
class StorageWallet extends DockWallet {
  constructor(id, storageInterface) {
    super(id);

    this.promises = [];
    this.storageInterface = storageInterface;
  }

  add(content) {
    super.add(content);
    this.promises.push(this.insertToStorage(content));
  }

  remove(contentId) {
    super.remove(contentId);
    this.promises.push(this.removeFromStorage(contentId));
  }

  update(content) {
    super.update(content);
    this.promises.push(this.updateInStorage(content));
  }

  async query(search) {
    // tODO: query the in memory contents first and pass flag to not use it, if empty run storage search
    // Query storage interface and map into wallet contents
    const { documents } = await this.storageInterface.find(search);
    return documents.map((document) => document.content);
  }

  async load() {
    // Find all documents, storage interfaces should return all docs when no params supplied
    const { documents } = await this.storageInterface.find();

    // Format to wallet contents
    if (documents) {
      documents.forEach((document) => super.add(document.content));
    }
    return this.contents;
  }

  async updateInStorage(content) {
    const documentResult = await this.getStorageDocument(content);
    await this.storageInterface.update({
      document: {
        ...documentResult,
        content,
      },
    });
  }

  async insertToStorage(content) {
    // Attempt to insert the document to the storage interface
    // if the promise fails, then the content will be removed and error re-thrown
    try {
      await this.storageInterface.insert({
        document: {
          content,
        },
      });
    } catch (e) {
      super.remove(content.id);
      throw e;
    }
  }

  async removeFromStorage(id) {
    await this.storageInterface.delete({
      document: await this.getStorageDocument({ id }),
    });
  }

  async getStorageDocument({ id }) {
    // Find the storage document by the content ID
    // some interfaces may just return the same document, but some need custom structures
    const { documents } = await this.storageInterface.find({
      equals: {
        'content.id': id,
      },
    });

    // Delete first result from storage
    if (documents.length) {
      return documents[0];
    } else {
      throw new Error(`Unable to find storage document by content.id: ${id}`);
    }
  }

  async sync() {
    // A user will call this method to ensure storage interface requests finish
    // we do this because wallet doesnt always require blocking operations
    // depending on the storage interface used
    const { promises } = this;
    this.promises = [];
    if (promises.length) {
      await Promise.all(promises);
    }
  }
}

export default StorageWallet;