pubkey / rxdb

A fast, local first, reactive Database for JavaScript Applications https://rxdb.info/
https://rxdb.info/
Apache License 2.0
21.68k stars 1.07k forks source link

adding method to a RxCollection in plugin #1536

Closed yanshiyason closed 5 years ago

yanshiyason commented 5 years ago

I want to add a method to a RxCollection in my plugin and this line is throwing a COL17:RxCollection.ORM: statics-name not allowed error.

https://github.com/pubkey/rxdb/blob/ac9fc95b0eda276110f371afca985f949275c3f1/src/rx-collection.ts#L849

Here is my plugin code:

import { RxCollection, RxError, RxPlugin } from 'rxdb';

type DocTypeKeys<T> = keyof (T);
type ValidationErrors<T> = Record<DocTypeKeys<T>, string[]>;
type ValidInsert<T> = [true, T];
type InvalidInsert<T> = [false, ValidationErrors<T>];
type ValidatedInsert<T> = ValidInsert<T> | InvalidInsert<T>;

export interface IValidatedInsertCollection {
    validatedInsert<T>(doc: T): Promise<ValidatedInsert<T>>;
}

export const validatedInsertPlugin: RxPlugin = {
    rxdb: true,
    prototypes: {
        RxCollection(proto: any) {
            Object.assign(proto, {
                async validatedInsert<T>(doc: T): Promise<ValidatedInsert<T>> {
                    try {
                        const product = await proto.insert(doc);
                        return [true, product as T];
                    } catch (e) {
                        const error = e as RxError;
                        const validationErrors = error.parameters.errors.reduce(
                            (acc, e) => {
                                ...
                            },
                            {} as ValidationErrors<T>
                        );

                        return [false, validationErrors!];
                    }
                },
            });
        },
    },
    overwritable: {},
    hooks: {},
};

This is the API I want to achieve:

const db = await createDatabase();
const [ok, docOrError] = await db.products.validatedInsert<BlogDocType>({...});
expect(ok).toEqual(false);
expect(docOrError).toEqual({
    description: ['has less length than allowed'],
    title: ['has less length than allowed'],
    authors: ['has less items than allowed'],
});

const [ok, docOrError] = await db.products.validatedInsert<BlogDocType>({...});
expect(ok).toEqual(true);
// => docOrError is RxDocument<BlogDocType>

The code worked when implemented in the application, but I am trying to move it to a library.

Thank you for any advice.

yanshiyason commented 5 years ago

By the way, here are the properties contained in the object when it raises:

my method validatedInsert is on line 64. But I kind of expect it to be there because I want to extend the RxCollection prototype?

0: "_isInMemory"
1: "destroyed"
2: "_atomicUpsertQueues"
3: "synced"
4: "hooks"
5: "_subs"
6: "_repStates"
7: "pouch"
8: "_docCache"
9: "_queryCache"
10: "_dataMigrator"
11: "_crypter"
12: "_changeEventBuffer"
13: "database"
14: "name"
15: "schema"
16: "pouchSettings"
17: "migrationStrategies"
18: "methods"
19: "attachments"
20: "options"
21: "statics"
22: "constructor"
23: "prepare"
24: "getDocumentPrototype"
25: "getDocumentConstructor"
26: "migrationNeeded"
27: "migrate"
28: "migratePromise"
29: "_handleToPouch"
30: "_handleFromPouch"
31: "_pouchPut"
32: "_pouchGet"
33: "_pouchFind"
34: "_createDocument"
35: "_createDocuments"
36: "$emit"
37: "insert"
38: "upsert"
39: "atomicUpsert"
40: "find"
41: "findOne"
42: "dump"
43: "importDump"
44: "watchForChanges"
45: "sync"
46: "syncGraphQL"
47: "inMemory"
48: "addHook"
49: "getHooks"
50: "_runHooks"
51: "_runHooksSync"
52: "newDocument"
53: "destroy"
54: "remove"
55: "$"
56: "insert$"
57: "update$"
58: "remove$"
59: "docChanges$"
60: "onDestroy"
61: "insertLocal"
62: "upsertLocal"
63: "getLocal"
64: "validatedInsert"
65: "preInsert"
66: "postInsert"
67: "preSave"
68: "postSave"
69: "preRemove"
70: "postRemove"
71: "preCreate"
72: "postCreate"
yanshiyason commented 5 years ago

https://github.com/rafamel/rxdb-utils/blob/243acf196339958fceadb515d61084441b0e8993/src/collections.js#L7

By looking at this code it gave me another idea.. maybe I can define the method here in a hook?

pubkey commented 5 years ago

RxDB will check if a method-name is already used internally by RxCollection and then it will not allow you to overwrite this with the statics. Can it be that you still set validatedInsert as ORM-function in your code?

yanshiyason commented 5 years ago

Ahh, you are right. I forgot to remove my own definition in another file. Sorry about that.