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

feat(createLoader): param to getLoader #247

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 23 additions & 20 deletions src/createLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,32 @@ import { validateContextUser } from './validateContextUser';
import { withConnectionAggregate } from './withConnectionAggregate';
import { withConnectionCursor } from './withConnectionCursor';

const defaultViewerCanSee = <Value extends Document>(_context: BaseContext<string, Value>, data: Value): Value => data;

export interface BaseContext<LoaderName extends string, Value extends Document> {
dataloaders: Record<LoaderName, DataLoader<string, Value>>;
}

type filtersConditionsOrSortFn<Context> = (context: Context, args: FilteredConnectionArguments) => object;

export type CreateLoaderArgs<
Context extends BaseContext<LoaderName, Value>,
export type GetLoaderFunction<Context, Value extends Document> = (ctx: Context) => DataLoader<string, Value>;

export const defaultGetLoader = <
LoaderName extends string,
Value extends Document
> = {
Value extends Document,
Context extends BaseContext<LoaderName, Value>,
>(
name: LoaderName,
) => {
return (ctx: Context) => ctx.dataloaders[name];
};

export type ViewerCanSeeFn<Context, Value extends Document> = (context: Context, data: Value) => Value | Promise<Value>;

export type CreateLoaderArgs<Context, Value extends Document> = {
model: Model<Value>;
viewerCanSee?: (context: Context, data: Value) => Value | Promise<Value>;
loaderName: LoaderName;
viewerCanSee?: ViewerCanSeeFn<Context, Value>;
filterMapping?: object;
isAggregate?: boolean;
getLoaderByCtx: GetLoaderFunction<Context, Value>;
shouldValidateContextUser?: boolean;
defaultFilters?: object | filtersConditionsOrSortFn<Context>;
defaultConditions?: object | filtersConditionsOrSortFn<Context>;
Expand All @@ -38,21 +46,17 @@ export interface FilteredConnectionArguments extends ConnectionArguments {
filters: GraphQLFilter | null;
}

export const createLoader = <
Context extends BaseContext<LoaderName, Value>,
LoaderName extends string,
Value extends Document
>({
export const createLoader = <Context, Value extends Document>({
model,
viewerCanSee = defaultViewerCanSee,
loaderName,
viewerCanSee = (_ctx, data) => data,
filterMapping = {},
isAggregate = false,
shouldValidateContextUser = false,
defaultFilters = {},
defaultConditions = {},
defaultSort = { createdAt: -1 },
}: CreateLoaderArgs<Context, LoaderName, Value>) => {
getLoaderByCtx,
}: CreateLoaderArgs<Context, Value>) => {
class Loader {
[key: string]: any;
constructor(data: Value) {
Expand All @@ -77,7 +81,7 @@ export const createLoader = <
}

try {
const data = await context.dataloaders[loaderName].load(id.toString());
const data = await getLoaderByCtx(context).load(id.toString());

if (!data) {
return null;
Expand All @@ -91,10 +95,9 @@ export const createLoader = <
}
};

const clearCache = ({ dataloaders }: Context, id: string) => dataloaders[loaderName].clear(id.toString());
const clearCache = (ctx: Context, id: string) => getLoaderByCtx(ctx).clear(id.toString());

const primeCache = ({ dataloaders }: Context, id: string, data: Value) =>
dataloaders[loaderName].prime(id.toString(), data);
const primeCache = (ctx: Context, id: string, data: Value) => getLoaderByCtx(ctx).prime(id.toString(), data);

const clearAndPrimeCache = (context: Context, id: string, data: Value) =>
clearCache(context, id) && primeCache(context, id, data);
Expand Down
2 changes: 1 addition & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,4 @@ export interface GraphqlSortArg<SortFieldT extends string> {
direction: SortDirection;
}

export type LoaderFn<Context extends object> = (ctx: Context, id: DataLoaderKey) => any;
export type LoaderFn<Context> = (ctx: Context, id: DataLoaderKey) => any;
38 changes: 18 additions & 20 deletions src/withConnectionAggregate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,21 @@ import { buildAggregatePipeline } from './buildAggregatePipeline';

type WithConnectionAggregateConditions = { defaultConditions?: object; builtMongoConditions: BuiltConditionSet };

export const withConnectionAggregate = <Context extends object>(
model: Model<any>,
loader: LoaderFn<Context>,
condFn: (...p: any[]) => WithConnectionAggregateConditions,
) => (...params: any[]) => {
const { defaultConditions = {}, builtMongoConditions } = condFn(...params);

const [context, args] = params;

const aggregatePipeline = buildAggregatePipeline({ defaultConditions, builtMongoConditions });

const aggregate = model.aggregate(aggregatePipeline);

return connectionFromMongoAggregate({
aggregate,
context,
args,
loader: loader as any,
});
};
export const withConnectionAggregate =
<Context>(model: Model<any>, loader: LoaderFn<Context>, condFn: (...p: any[]) => WithConnectionAggregateConditions) =>
(...params: any[]) => {
const { defaultConditions = {}, builtMongoConditions } = condFn(...params);

const [context, args] = params;

const aggregatePipeline = buildAggregatePipeline({ defaultConditions, builtMongoConditions });

const aggregate = model.aggregate(aggregatePipeline);

return connectionFromMongoAggregate({
aggregate,
context,
args,
loader: loader as any,
});
};
32 changes: 17 additions & 15 deletions src/withConnectionCursor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,23 @@ import { Model } from 'mongoose';

import { LoaderFn } from './types';

export const withConnectionCursor = <Context extends object>(
model: Model<any>,
loader: LoaderFn<Context>,
condFn: (...p: any[]) => { conditions?: object; sort?: object },
) => (...params: any[]) => {
const { conditions = {}, sort = {} } = condFn(...params);
export const withConnectionCursor =
<Context>(
model: Model<any>,
loader: LoaderFn<Context>,
condFn: (...p: any[]) => { conditions?: object; sort?: object },
) =>
(...params: any[]) => {
const { conditions = {}, sort = {} } = condFn(...params);

const [context, args] = params;
const [context, args] = params;

const cursor = model.find(conditions).sort(sort);
const cursor = model.find(conditions).sort(sort);

return connectionFromMongoCursor({
cursor,
context,
args,
loader: loader as any,
});
};
return connectionFromMongoCursor({
cursor,
context,
args,
loader: loader as any,
});
};