smallorange-data-loaderdeprecated

This package create cached queries to avoid make duplicate requests to the backend.

Usage no npm install needed!

<script type="module">
  import smallorangeDataLoader from 'https://cdn.skypack.dev/smallorange-data-loader';
</script>

README

CircleCI

Small Orange Data Loader

This package create cached queries to avoid make duplicate requests to the backend. The sample below is self explanatory (we reduce 121 queries to just 4 using this package):

Usage with GraphQL

    const users = [{
        id: 0,
        name: 'Philip'
    }, {
        id: 1,
        name: 'David'
    }, {
        id: 2,
        name: 'John'
    }, {
        id: 3,
        name: 'George'
    }];

    const friendsOf = [
        [1, 2, 3],
        [0, 2, 3],
        [0, 1, 3],
        [0, 1, 2]
    ];

    const getUser = sinon.spy(id => Observable.create(subscriber => {
        if (!users[id]) {
            subscriber.error(new Error('no user id'));
        }

        subscriber.next(users[id]);
        subscriber.complete();
    }).share());

    const User = new GraphQLObjectType({
        name: 'User',
        fields: () => ({
            name: {
                type: GraphQLString
            },
            friends: {
                type: new GraphQLList(User),
                resolve: ({
                    id
                }, args, context) => {
                    const {
                        userLoader
                    } = context;

                    return Observable.from(friendsOf[id])
                        .mergeMap(id => userLoader ? userLoader.get(id) : getUser(id))
                        .toArray()
                        .toPromise();
                }
            }
        })
    });

    const schema = new GraphQLSchema({
        query: new GraphQLObjectType({
            name: 'Query',
            fields: {
                user: {
                    type: User,
                    args: {
                        id: {
                            type: new GraphQLNonNull(GraphQLInt)
                        },
                        useLoader: {
                            type: GraphQLBoolean
                        }
                    },
                    resolve: (root, {
                        id,
                        useLoader
                    }, context, info) => {
                        if (useLoader) {
                            const userLoader = context.userLoader = new DataLoader(getUser);

                            return userLoader.get(id)
                                .toPromise();
                        }

                        return getUser(id)
                            .toPromise();
                    }
                }
            }
        })
    });

    const asyncGraph = requestString => Observable.fromPromise(graphql(schema, requestString, {}, {}))
        .do(response => {
            if (response.errors) {
                throw new Error(response.errors.join());
            }
        });

    const query = (id, useLoader = false) => `{
        user(id: ${id}, useLoader: ${useLoader}) {
            name
            friends {
                name
                friends {
                    name
                    friends {
                        name
                        friends {
                            name
                        }
                    }
                }
            }
        }
    }`;

    asyncGraph(query(0))
            .subscribe(null, null, () => {
                // getUser will be called 121 times
            });

    asyncGraph(query(0, true))
            .subscribe(null, null, () => {
                // getUser will be called 4 times, once per user ;)
            });