Skip to content

Instantly share code, notes, and snippets.

@AugustoCalaca
Forked from sibelius/createLoader.tsx
Last active April 4, 2020 17:49
Show Gist options
  • Save AugustoCalaca/b3664976537a310f23fa3a8290db1cf5 to your computer and use it in GitHub Desktop.
Save AugustoCalaca/b3664976537a310f23fa3a8290db1cf5 to your computer and use it in GitHub Desktop.
createLoader used on react europe relay workshop
import { mongooseLoader } from '@entria/graphql-mongoose-loader';
import DataLoader from 'dataloader';
import { ConnectionArguments } from 'graphql-relay';
import { Model, Types } from 'mongoose';
import { buildMongoConditionsFromFilters } from '@entria/graphql-mongo-helpers';
import { withConnectionCursor } from './withConnectionCursor';
const defaulViewerCanSee = (context, data) => {
const canSee = {
...data.toObject(),
};
return canSee;
};
type DataLoaderKey = string | Types.ObjectId;
type CreateLoaderArgs<Context> = {
model: Model<any>;
viewerCanSee?: (context: Context, any) => Promise<object>;
loaderName: string;
filterMapping?: object;
};
export const createLoader = <Context extends object>({
model,
viewerCanSee = defaultViewerCanSee,
loaderName,
filterMapping = {},
}: CreateLoaderArgs<Context>) => {
class Loader {
id: string;
constructor(data: any) {
Object.keys(data).map(key => {
this[key] = data[key];
});
this.id = data._id;
}
}
const nameIt = (name, cls) => ({ [name]: class extends cls {} }[name]);
const Wrapper = nameIt(model.collection.name, Loader);
const getLoader = () => new DataLoader(ids => mongooseLoader(model, ids));
const load = async (context: Context, id: DataLoaderKey) => {
if (!id) {
return null;
}
try {
const data = await context.dataloaders[loaderName].load(id.toString());
if (!data) {
return null;
}
const canSee = viewerCanSee(context, data);
if(!canSee) return null;
return new Wrapper(canSee);
} catch (err) {
return null;
}
};
const clearCache = ({ dataloaders }: Context, id: string) => dataloaders[loaderName].clear(id.toString());
const loadAll =
withConnectionCursor(model, load, (context: Context, args: ConnectionArguments) => {
const builtMongoConditions = buildMongoConditionsFromFilters(context, args.filters, filterMapping);
// dont show the user who is in the context on UserLoader.loadAll list
const withoutMe = loaderName === 'UserLoader' && context.user
? {
_id: {
$ne: context.user._id
}
}
: {};
const conditions = {
...builtMongoConditions.conditions,
...withoutMe,
};
const sort = {
createdAt: -1,
};
return {
conditions,
sort,
};
});
return {
Wrapper,
getLoader,
clearCache,
load,
loadAll,
};
};
import { Model } from 'mongoose';
import { ConnectionArguments } from 'graphql-relay';
import { Load, GraphQLContext } from '../interface/RegisterLoader';
import { connectionFromMongoCursor } from '@entria/graphql-mongoose-loader';
type FnOutput = {
conditions: object,
sort: object,
};
export const withConnectionCursor = (model: Model<any>, load: Load, fn: (context: GraphQLContext, args: ConnectionArguments) => FnOutput) => {
return (context: GraphQLContext, args: ConnectionArguments) => {
const { conditions, sort } = fn(context, args);
const documentQuery = model.find(conditions).sort(sort);
return connectionFromMongoCursor({
cursor: documentQuery,
context,
args,
loader: load,
})
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment