Skip to content

Commit

Permalink
Refactor KeystoneContext definition for docs (#4942)
Browse files Browse the repository at this point in the history
  • Loading branch information
timleslie authored Feb 25, 2021
1 parent e6844dd commit 6c949db
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 110 deletions.
5 changes: 5 additions & 0 deletions .changeset/perfect-pillows-prove.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@keystone-next/types': patch
---

Refactored `KeystoneContext` definition to make documentation easier. No functional changes.
2 changes: 1 addition & 1 deletion packages-next/types/src/base.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { KeystoneContext } from './core';
import type { KeystoneContext } from './context';
import type { BaseGeneratedListTypes, GqlNames } from './utils';

// TODO: This is only a partial typing of the core Keystone class.
Expand Down
117 changes: 117 additions & 0 deletions packages-next/types/src/context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import { IncomingMessage } from 'http';
import { GraphQLSchema, ExecutionResult, DocumentNode } from 'graphql';
import { BaseKeystone } from './base';
import type { BaseGeneratedListTypes } from './utils';

export type KeystoneContext = {
req?: IncomingMessage;
lists: KeystoneListsAPI<any>;
graphql: KeystoneGraphQLAPI<any>;
sudo: () => KeystoneContext;
exitSudo: () => KeystoneContext;
withSession: (session: any) => KeystoneContext;
totalResults: number;
maxTotalResults: number;
schemaName: 'public';
/** @deprecated */
gqlNames: (listKey: string) => Record<string, string>; // TODO: actual keys
/** @deprecated */
executeGraphQL: any; // TODO: type this
keystone: BaseKeystone;
} & AccessControlContext &
Partial<SessionContext<any>> &
DatabaseAPIs;

// List item API

export type KeystoneListsAPI<
KeystoneListsTypeInfo extends Record<string, BaseGeneratedListTypes>
> = {
[Key in keyof KeystoneListsTypeInfo]: {
findMany(
args: KeystoneListsTypeInfo[Key]['args']['listQuery'] & ResolveFields
): Promise<readonly KeystoneListsTypeInfo[Key]['backing'][]>;
findOne(
args: { readonly where: { readonly id: string } } & ResolveFields
): Promise<KeystoneListsTypeInfo[Key]['backing'] | null>;
count(args: KeystoneListsTypeInfo[Key]['args']['listQuery']): Promise<number>;
updateOne(
args: {
readonly id: string;
readonly data: KeystoneListsTypeInfo[Key]['inputs']['update'];
} & ResolveFields
): Promise<KeystoneListsTypeInfo[Key]['backing'] | null>;
updateMany(
args: {
readonly data: readonly {
readonly id: string;
readonly data: KeystoneListsTypeInfo[Key]['inputs']['update'];
}[];
} & ResolveFields
): Promise<(KeystoneListsTypeInfo[Key]['backing'] | null)[] | null>;
createOne(
args: { readonly data: KeystoneListsTypeInfo[Key]['inputs']['create'] } & ResolveFields
): Promise<KeystoneListsTypeInfo[Key]['backing'] | null>;
createMany(
args: {
readonly data: readonly { readonly data: KeystoneListsTypeInfo[Key]['inputs']['update'] }[];
} & ResolveFields
): Promise<(KeystoneListsTypeInfo[Key]['backing'] | null)[] | null>;
deleteOne(
args: { readonly id: string } & ResolveFields
): Promise<KeystoneListsTypeInfo[Key]['backing'] | null>;
deleteMany(
args: { readonly ids: readonly string[] } & ResolveFields
): Promise<(KeystoneListsTypeInfo[Key]['backing'] | null)[] | null>;
};
};

type ResolveFields = { readonly resolveFields?: false | string };

// GraphQL API

export type KeystoneGraphQLAPI<
// this is here because it will be used soon
// eslint-disable-next-line @typescript-eslint/no-unused-vars
KeystoneListsTypeInfo extends Record<string, BaseGeneratedListTypes>
> = {
schema: GraphQLSchema;
run: (args: GraphQLExecutionArguments) => Promise<Record<string, any>>;
raw: (args: GraphQLExecutionArguments) => Promise<ExecutionResult>;
};

type GraphQLExecutionArguments = {
context?: any;
query: string | DocumentNode;
variables: Record<string, any>;
};

// Access control API

export type AccessControlContext = {
getListAccessControlForUser: any; // TODO
getFieldAccessControlForUser: any; // TODO
};

// Session API

export type SessionContext<T> = {
// Note: session is typed like this to acknowledge the default session shape
// if you're using keystone's built-in session implementation, but we don't
// actually know what it will look like.
session?: { itemId: string; listKey: string; data?: Record<string, any> } | any;
startSession(data: T): Promise<string>;
endSession(): Promise<void>;
};

// DatabaseAPIs is used to provide access to the underlying database abstraction through
// context and other developer-facing APIs in Keystone, so they can be used easily.

// The implementation is very basic, and assumes there's a single adapter keyed by the constructor
// name. Since there's no option _not_ to do that using the new config, we probably don't need
// anything more sophisticated than this.
export type DatabaseAPIs = {
knex?: any;
mongoose?: any;
prisma?: any;
};
111 changes: 2 additions & 109 deletions packages-next/types/src/core.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,6 @@
import { IncomingMessage, ServerResponse } from 'http';
import { GraphQLSchema, ExecutionResult, DocumentNode } from 'graphql';

import type { BaseGeneratedListTypes, GqlNames, MaybePromise } from './utils';
import { BaseKeystone } from './base';

// DatabaseAPIs is used to provide access to the underlying database abstraction through
// context and other developer-facing APIs in Keystone, so they can be used easily.

// The implementation is very basic, and assumes there's a single adapter keyed by the constructor
// name. Since there's no option _not_ to do that using the new config, we probably don't need
// anything more sophisticated than this.
export type DatabaseAPIs = {
knex?: any;
mongoose?: any;
prisma?: any;
};
import type { GqlNames, MaybePromise } from './utils';
import type { KeystoneContext, SessionContext } from './context';

/* TODO: Review these types */
type FieldDefaultValueArgs<T> = { context: KeystoneContext; originalInput?: T };
Expand All @@ -37,106 +23,13 @@ export type SessionImplementation = {
): Promise<SessionContext<any>>;
};

export type AccessControlContext = {
getListAccessControlForUser: any; // TODO
getFieldAccessControlForUser: any; // TODO
};

export type SessionContext<T> = {
// Note: session is typed like this to acknowledge the default session shape
// if you're using keystone's built-in session implementation, but we don't
// actually know what it will look like.
session?: { itemId: string; listKey: string; data?: Record<string, any> } | any;
startSession(data: T): Promise<string>;
endSession(): Promise<void>;
};

export type KeystoneContext = {
schemaName: 'public';
lists: KeystoneListsAPI<any>;
totalResults: number;
keystone: BaseKeystone;
graphql: KeystoneGraphQLAPI<any>;
/** @deprecated */
executeGraphQL: any; // TODO: type this
/** @deprecated */
gqlNames: (listKey: string) => Record<string, string>; // TODO: actual keys
maxTotalResults: number;
sudo: () => KeystoneContext;
exitSudo: () => KeystoneContext;
withSession: (session: any) => KeystoneContext;
req?: IncomingMessage;
} & AccessControlContext &
Partial<SessionContext<any>> &
DatabaseAPIs;

export type GraphQLResolver = (root: any, args: any, context: KeystoneContext) => any;

export type GraphQLSchemaExtension = {
typeDefs: string;
resolvers: Record<string, Record<string, GraphQLResolver>>;
};

type GraphQLExecutionArguments = {
context?: any;
query: string | DocumentNode;
variables: Record<string, any>;
};
export type KeystoneGraphQLAPI<
// this is here because it will be used soon
// eslint-disable-next-line @typescript-eslint/no-unused-vars
KeystoneListsTypeInfo extends Record<string, BaseGeneratedListTypes>
> = {
schema: GraphQLSchema;

run: (args: GraphQLExecutionArguments) => Promise<Record<string, any>>;
raw: (args: GraphQLExecutionArguments) => Promise<ExecutionResult>;
};

type ResolveFields = { readonly resolveFields?: false | string };

export type KeystoneListsAPI<
KeystoneListsTypeInfo extends Record<string, BaseGeneratedListTypes>
> = {
[Key in keyof KeystoneListsTypeInfo]: {
findMany(
args: KeystoneListsTypeInfo[Key]['args']['listQuery'] & ResolveFields
): Promise<readonly KeystoneListsTypeInfo[Key]['backing'][]>;
findOne(
args: { readonly where: { readonly id: string } } & ResolveFields
): Promise<KeystoneListsTypeInfo[Key]['backing'] | null>;
count(args: KeystoneListsTypeInfo[Key]['args']['listQuery']): Promise<number>;
updateOne(
args: {
readonly id: string;
readonly data: KeystoneListsTypeInfo[Key]['inputs']['update'];
} & ResolveFields
): Promise<KeystoneListsTypeInfo[Key]['backing'] | null>;
updateMany(
args: {
readonly data: readonly {
readonly id: string;
readonly data: KeystoneListsTypeInfo[Key]['inputs']['update'];
}[];
} & ResolveFields
): Promise<(KeystoneListsTypeInfo[Key]['backing'] | null)[] | null>;
createOne(
args: { readonly data: KeystoneListsTypeInfo[Key]['inputs']['create'] } & ResolveFields
): Promise<KeystoneListsTypeInfo[Key]['backing'] | null>;
createMany(
args: {
readonly data: readonly { readonly data: KeystoneListsTypeInfo[Key]['inputs']['update'] }[];
} & ResolveFields
): Promise<(KeystoneListsTypeInfo[Key]['backing'] | null)[] | null>;
deleteOne(
args: { readonly id: string } & ResolveFields
): Promise<KeystoneListsTypeInfo[Key]['backing'] | null>;
deleteMany(
args: { readonly ids: readonly string[] } & ResolveFields
): Promise<(KeystoneListsTypeInfo[Key]['backing'] | null)[] | null>;
};
};

const preventInvalidUnderscorePrefix = (str: string) => str.replace(/^__/, '_');

// TODO: don't duplicate this between here and packages/keystone/ListTypes/list.js
Expand Down
1 change: 1 addition & 0 deletions packages-next/types/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export * from './utils';
export * from './session';
export * from './admin-meta';
export * from './base';
export * from './context';

1 comment on commit 6c949db

@vercel
Copy link

@vercel vercel bot commented on 6c949db Feb 25, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.