From 52334b5f054388b2c61c5aadc61fbc5b2ddf93c5 Mon Sep 17 00:00:00 2001 From: Guillaume Chau Date: Mon, 2 Sep 2024 15:58:54 +0200 Subject: [PATCH] chore: more jsdoc --- packages/core/src/factory/execute.ts | 2 + packages/core/src/rest/server.ts | 2 +- packages/core/src/types/apiRoute.ts | 47 +++++++++++++++++ packages/core/src/types/factory.ts | 16 ++++++ packages/core/src/types/resolver.ts | 17 ++++++ packages/core/src/types/script.ts | 21 ++++++++ packages/moquerie/src/mocks.ts | 79 ++++++++++++++++++++++++++++ playground/src/schema.mock.ts | 8 ++- 8 files changed, 190 insertions(+), 2 deletions(-) diff --git a/packages/core/src/factory/execute.ts b/packages/core/src/factory/execute.ts index 9475768..2116891 100644 --- a/packages/core/src/factory/execute.ts +++ b/packages/core/src/factory/execute.ts @@ -1,3 +1,4 @@ +import { nanoid } from 'nanoid' import type { ResourceFactory, ResourceFactoryContext, ResourceFactoryFn } from '../types/factory.js' import type { Awaitable } from '../util/types.js' import { createResourceInstanceReference } from '../resource/resourceReference.js' @@ -25,6 +26,7 @@ export async function executeFactory(mq: MoquerieInstance, factory: ResourceFact db: ctx.db, repeat: repeat.bind(null, result) as (fn: (item: any) => any, min: number, max: number) => Promise, pickRandom, + generateId: nanoid, } const rawResult = fn(factoryContext) diff --git a/packages/core/src/rest/server.ts b/packages/core/src/rest/server.ts index 73215ad..9bf62c5 100644 --- a/packages/core/src/rest/server.ts +++ b/packages/core/src/rest/server.ts @@ -59,7 +59,7 @@ export async function setupRestApi(mq: MoquerieInstance, expressApp: Application db: (ctx.db as UntypedQueryManagerProxy), pubsub: ctx.pubSubs, faker: await getFaker(mq), - generateId: () => nanoid(), + generateId: nanoid, generateResource: async (resourceName, factoryId, count = 1) => { const resourceType = ctx.schema.types[resourceName] if (!resourceType) { diff --git a/packages/core/src/types/apiRoute.ts b/packages/core/src/types/apiRoute.ts index 826c567..1813d49 100644 --- a/packages/core/src/types/apiRoute.ts +++ b/packages/core/src/types/apiRoute.ts @@ -19,18 +19,65 @@ export interface ApiRouter { export type DefineApiRouteSetupFn = (router: ApiRouter) => void export interface ApiRouteContext { + /** + * The database query manager. + */ db: QueryManagerProxy + /** + * The pubsub instance to send real-time updates. + */ pubsub: PubSubs + /** + * Generate a random id. + */ generateId: () => string + /** + * Generate one or more resource instances using a factory. + */ generateResource: (resourceName: string, factoryId: string, count?: number) => Promise + /** + * The faker instance. + */ faker: Faker + /** + * Repeat a function multiple times. + */ repeat: (fn: () => T, min: number, max: number) => Promise> + /** + * Pick a random item from a list. + */ pickRandom: (list: T[]) => T | null + /** + * The current request. + */ request: RequestLike + /** + * The path parameters. + * + * Example: + * + * For the route `/users/:id`, if the URL is `/users/123`, then `params` will be `{ id: '123' }`. + */ params: Record + /** + * The query parameters. + * + * Example: + * + * For the URL `/users?name=John`, then `query` will be `{ name: 'John' }`. + */ query: Record + /** + * Read the request body. + */ readBody: () => Promise + /** + * Set the response type. + */ setResponseType: (type: string) => void + /** + * Create an HTTP error. + */ createError: (message: string, data?: any) => Error } diff --git a/packages/core/src/types/factory.ts b/packages/core/src/types/factory.ts index 955dc0a..666adf8 100644 --- a/packages/core/src/types/factory.ts +++ b/packages/core/src/types/factory.ts @@ -149,10 +149,26 @@ export interface ResourceFactory { } export interface ResourceFactoryContext { + /** + * The faker instance. + */ faker: Faker + /** + * The database query manager. + */ db: QueryManagerProxy + /** + * Repeat a function multiple times. + */ repeat: (fn: (context: ResourceFactoryLazyContext) => T, min: number, max: number) => Promise> + /** + * Pick a random item from a list. + */ pickRandom: (list: T[]) => T | null + /** + * Generate a random id. + */ + generateId: () => string } export interface ResourceFactoryLazyContext { diff --git a/packages/core/src/types/resolver.ts b/packages/core/src/types/resolver.ts index a99bc16..3ee1d64 100644 --- a/packages/core/src/types/resolver.ts +++ b/packages/core/src/types/resolver.ts @@ -9,10 +9,27 @@ export interface Resolver { } export interface ResolverContext { + /** + * The parent object. For example, if the resolver is for a field `user` on a `Post` type, then `parent` will be the `Post` object. + */ parent: any + /** + * The input object. This is the object that was passed to the resolver as part of the field parameters. + * + * For example, if the resolver is for a field `user` on a `Post` type, then `input` will be the parameters object that was passed to the `user` field. + */ input: any + /** + * The database query manager. + */ db: QueryManagerProxy + /** + * The pubsub instance to send real-time updates. + */ pubsub: PubSubs + /** + * Generate a random id. + */ generateId: () => string } diff --git a/packages/core/src/types/script.ts b/packages/core/src/types/script.ts index 4032f0f..a72968a 100644 --- a/packages/core/src/types/script.ts +++ b/packages/core/src/types/script.ts @@ -5,12 +5,33 @@ import type { Awaitable } from '../util/types.js' import type { ResourceInstanceReference } from './resource.js' export interface ScriptContext { + /** + * The database query manager. + */ db: QueryManagerProxy + /** + * The pubsub instance to send real-time updates. + */ pubsub: PubSubs + /** + * Generate a random id. + */ generateId: () => string + /** + * Generate one or more resource instances using a factory. + */ generateResource: (resourceName: string, factoryId: string, count?: number) => Promise + /** + * The faker instance. + */ faker: Faker + /** + * Repeat a function multiple times. + */ repeat: (fn: () => T, min: number, max: number) => Promise> + /** + * Pick a random item from a list. + */ pickRandom: (list: T[]) => T | null } diff --git a/packages/moquerie/src/mocks.ts b/packages/moquerie/src/mocks.ts index ccbd7ba..7816b1d 100644 --- a/packages/moquerie/src/mocks.ts +++ b/packages/moquerie/src/mocks.ts @@ -56,6 +56,26 @@ export function defineResolvers(reso } } +/** + * Modify the resource schema, for example to add internal fields that are not exposed in the API. + * @example + * + * ```ts + import { defineSchemaTransforms } from 'moquerie/mocks' + + export default { + // Use a spread operator to be able to use other functions like `defineResolvers` or `defineScripts` + ...defineSchemaTransforms(({ schema, createEnumField }) => { + // Add a new field to the `User` type + schema.types.User.fields.customInternalField = createEnumField('customInternalField', [ + { value: 1, description: 'One' }, + { value: 2, description: 'Two' }, + { value: 3, description: 'Three' }, + ]) + }), + } + ``` + */ export function defineSchemaTransforms(handlers: SchemaTransformAction | Array) { return { __schemaTransforms: handlers, @@ -64,9 +84,44 @@ export function defineSchemaTransforms(handlers: SchemaTransformAction | Array { + // Create message + const [ref] = await generateResource('Message', 'SimpleMessageFactory') + + // Update message with current user + const me = await db.User.findFirstReference((data, { tags }) => tags.includes('me')) + if (!me) { + throw new Error(`User with tag 'me' not found`) + } + await db.Message.updateFirst({ + from: me, + }, (_, instance) => instance.id === ref.__id) + }, + }, + }), + } + ``` + */ export function defineScripts(scripts: Record) { const list: Array> = [] for (const id in scripts) { @@ -79,12 +134,36 @@ export function defineScripts(scripts: Record) { } } +/** + * Define API routes to be used in the dashboard. Use the `router` parameter to add new routes answering different HTTP verbs. Inside the route handler, return the response. + * + * You can define parameters in the route path using the `:name` syntax (see https://www.npmjs.com/package/path-to-regexp). + * + * @example + * + * ```ts + import { defineApiRoutes } from 'moquerie/mocks' + + export default { + // Use a spread operator to be able to use other functions like `defineResolvers` or `defineScripts` + ...defineApiRoutes((router) => { + // Add a new route + router.get('/messages/count', async ({ db }) => { + return (await db.Message.findMany()).length + }) + }), + } + ``` + */ export function defineApiRoutes(fn: DefineApiRouteSetupFn) { return { __apiRouteFn: fn, } } +/** + * Define a factory to generate resources. If you need more complex logic, create factories for the basic generation then use `defineScripts` to create scripts. + */ export function defineFactory, TFn extends ResourceFactoryFn>(info: TInfo, fn: TFn) { return { info, diff --git a/playground/src/schema.mock.ts b/playground/src/schema.mock.ts index ab1e7d8..357ec1f 100644 --- a/playground/src/schema.mock.ts +++ b/playground/src/schema.mock.ts @@ -1,4 +1,4 @@ -import { defineResolvers, defineSchemaTransforms, defineScripts } from 'moquerie/mocks' +import { defineApiRoutes, defineResolvers, defineSchemaTransforms, defineScripts } from 'moquerie/mocks' export default { ...defineResolvers({ @@ -96,4 +96,10 @@ export default { }, }, }), + + ...defineApiRoutes((router) => { + router.get('/hello', async ({ db }) => { + return (await db.Message.findMany()).length + }) + }), }