Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feature] Custom async fields that work with RxDB exec() and subscribe() #386

Closed
natew opened this issue Dec 1, 2017 · 2 comments
Closed

Comments

@natew
Copy link
Contributor

natew commented Dec 1, 2017

We have a body field that contains a huge amount of text that slows down pouch very quickly. So we've moved that into it's own simple IndexDB.

But we also really love using RxDB syntax for subscribe as well as exec (both are used extensively). And since we previously had all that field it would be really nice to be able to not have to rewrite a bunch of views to add in custom logic to get that. Especially in this case since we both subscribe in certain places, and use promises in others.

For now I've come up with this extraordinarily hacky solution, that fails on the .exec() case, but at least lets us continue developing:

const resolvedBodies = {}
const db = new IndexDB()

// methods defined on collection
export const methods = {
  // hacky way to have async resolving of bodies for now
  get body() {
    if (this.bodyTEMP) {
      ;(async () => {
        const res = await db.get(this.id)
        if (resolvedBodies[this.id] !== res.body) {
          resolvedBodies[this.id] = res.body
          // hacky, triggers update
          this.bodyTEMP = `${Math.random()}`
          this.save()
        }
      })()
      return resolvedBodies[this.id] || ''
    }
    return ''
  },
}

export const preInsert = doc => {
      if (typeof doc.body !== 'undefined') {
        db.put({ id: doc.id, body: doc.body })
        doc.bodyTEMP = `${Math.random()}`
        delete doc.body
      }
}

I know, it's horrible. Anyway, I brought it up in chat but figure issues are best left for the issue tracker.

To me the simplest solution would be to support async methods:

const heroes = await myDatabase.collection({
  name: 'heroes',
  schema: mySchema,
  customAsyncMethods: {
    description: function(){
        return new Promise.resolve('hello mate')
    }
  }
});
await heroes.insert({
  name: 'Skeletor'
});

const doc = await heroes.findOne().exec();
console.log(doc.description);
// logs out "hello mate"
// customAsyncMethods are resolved onto docs before returning

But I believe you answer was that async postCreate is not possible, due to newDocument().

@pubkey
Copy link
Owner

pubkey commented Dec 3, 2017

I still think this is an edge-case. You should generate the description where you need it, not at document-creation.

I now added option-parameters and a new plugin-hook postCreateRxDocument.
With both of them you can do the following solution:

// create a rxdb-plugin that uses the hook and options
const myPlugin = {
    rxdb: true,
    hooks: {
        postCreateRxDocument: async (doc) => {
            // get the options from the collection-options
            const asyncMethods = doc.collection.options.customAsyncMethods;

            if (asyncMethods) {
                // resolve all async-methods
                await Promise.all(
                    Object.keys(asyncMethods).map(async (key) => {
                        const fun = asyncMethods[key];
                        const value = await fun();
                        doc.key = value;
                    })
                );
            }
        }
    }
};

// add the plugin to rxdb
RxDB.plugin(myPlugin);

// now you can create collections with the options
myDatabase.collection({
    name: 'foobar',
    schema: mySchema,
    options: {
        customAsyncMethods: {
            description: () => new Promise.resolve('hello mate')
        }
    }
});

// and later access description of document
myDocument.description; // 'hello mate'

@natew
Copy link
Contributor Author

natew commented Dec 5, 2017

This is perfect, and I really appreciate the help here. In a perfect world pouch would be a bit better with large docs, but this really helps until then!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants