redgeoff / delta-pouch

Conflict-free collaborative editing for PouchDB
196 stars 13 forks source link

Override PouchDB.allDocs (issue #175) #176

Open funblaster22 opened 1 year ago

funblaster22 commented 1 year ago

I moved the logic from .all into .mergeAll and made it keep the input shape (i.e. {docs: {}, key: 123, value: {}} stays the same, instead of becoming {...docs}). This is useful because this is the format .allDocs expects I added an override for .allDocs so that 3rd party plugins could take advantage of delta pouch's system without having to know about how the documents are combined together. I also bumped the version to 2.0 since it modifies the prototype of PouchDB, and people might not be expecting that, just to be safe.

Closes #175

funblaster22 commented 1 year ago

Here is some code to test the changes. While waiting for a fix to pouch-db to allow overriding methods, I used pouchdb version 7

<script lang="ts">
  import PouchDB from 'pouchdb-browser';
  import DeltaPouch from 'delta-pouch';
  import PouchFind from "pouchdb-find";
  import PouchFindLive from "pouchdb-live-find";
  import type {Readable, Subscriber, Unsubscriber} from "svelte/store";

  PouchDB.plugin(DeltaPouch);
  PouchDB.plugin(PouchFind);
  PouchDB.plugin(PouchFindLive);
  const upstreamLiveFind = PouchDB.prototype.liveFind;
  PouchDB.plugin(PouchDB => {
    PouchDB.prototype.liveFindStore = function(requestDef: Parameters<typeof upstreamLiveFind>[0]): Readable<{}> {
      console.log(this);
      const liveFeed = upstreamLiveFind.call(this, requestDef);

      return {
        subscribe(run: Subscriber<{}>, invalidate: Invalidator<{}> | undefined): Unsubscriber {
          run([]);
          liveFeed.on('update', (update, aggregate) => run(aggregate));
          return liveFeed.cancel;
        }
      }
    };
  });

  const db = new PouchDB<{}>("test");
  db.deltaInit();

  const liveFeed = db.liveFindStore({
    selector: {},  // {series: 'Mario'}
    sort: [],  // [{series: 'desc'}, {name: 'desc'}]
    aggregate: true
  });

  let newTodo: string;

  function submit(id=undefined, title=undefined) {
      db.save({ $id: id, title: title ?? newTodo }).then(function (doc) {
        console.log(doc);
        // doc.$id is the id of the created doc
      });
  }
</script>

<div>
    <input bind:value={newTodo} /><button on:click={() => submit()}>Submit</button>
    {#each $liveFeed as todo}
        <div>{JSON.stringify(todo)}</div>
        {todo.$id}
        <input value={todo.title} on:change={ev => submit(todo.$id, ev.target.value)} />
        <button on:click={() => db.delete(todo._id).then(console.log)}>❎</button>
    {/each}
</div>