Skip to content

Commit

Permalink
chore: more jsdoc
Browse files Browse the repository at this point in the history
  • Loading branch information
Akryum committed Sep 2, 2024
1 parent b75329b commit 52334b5
Show file tree
Hide file tree
Showing 8 changed files with 190 additions and 2 deletions.
2 changes: 2 additions & 0 deletions packages/core/src/factory/execute.ts
Original file line number Diff line number Diff line change
@@ -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'
Expand Down Expand Up @@ -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<any[]>,
pickRandom,
generateId: nanoid,
}

const rawResult = fn(factoryContext)
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/rest/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
47 changes: 47 additions & 0 deletions packages/core/src/types/apiRoute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<ResourceInstanceReference[]>
/**
* The faker instance.
*/
faker: Faker
/**
* Repeat a function multiple times.
*/
repeat: <T = any>(fn: () => T, min: number, max: number) => Promise<Array<T>>
/**
* Pick a random item from a list.
*/
pickRandom: <T extends string | number | boolean = any>(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<string, string>
/**
* The query parameters.
*
* Example:
*
* For the URL `/users?name=John`, then `query` will be `{ name: 'John' }`.
*/
query: Record<string, string>
/**
* Read the request body.
*/
readBody: () => Promise<any>
/**
* Set the response type.
*/
setResponseType: (type: string) => void
/**
* Create an HTTP error.
*/
createError: (message: string, data?: any) => Error
}

Expand Down
16 changes: 16 additions & 0 deletions packages/core/src/types/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: <T = any>(fn: (context: ResourceFactoryLazyContext) => T, min: number, max: number) => Promise<Array<T>>
/**
* Pick a random item from a list.
*/
pickRandom: <T extends string | number | boolean = any>(list: T[]) => T | null
/**
* Generate a random id.
*/
generateId: () => string
}

export interface ResourceFactoryLazyContext<TItem = any> {
Expand Down
17 changes: 17 additions & 0 deletions packages/core/src/types/resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
21 changes: 21 additions & 0 deletions packages/core/src/types/script.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<ResourceInstanceReference[]>
/**
* The faker instance.
*/
faker: Faker
/**
* Repeat a function multiple times.
*/
repeat: <T = any>(fn: () => T, min: number, max: number) => Promise<Array<T>>
/**
* Pick a random item from a list.
*/
pickRandom: <T extends string | number | boolean = any>(list: T[]) => T | null
}

Expand Down
79 changes: 79 additions & 0 deletions packages/moquerie/src/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,26 @@ export function defineResolvers<TResolvers extends ResolverBaseDefinitions>(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<SchemaTransformAction>) {
return {
__schemaTransforms: handlers,
Expand All @@ -64,9 +84,44 @@ export function defineSchemaTransforms(handlers: SchemaTransformAction | Array<S

export type ScriptOption = ScriptFn | {
description?: string
/**
* The script function.
*/
fn: ScriptFn
}

/**
* Add scripts to create more complex scenarios using multiple factories or other actions.
* You can then call these scripts in the dashboard.
*
* @example
*
* ```ts
import { defineScripts } from 'moquerie/mocks'
export default {
// Use a spread operator to be able to use other functions like `defineResolvers` or `defineSchemaTransforms`
...defineScripts({
createSimpleMessage: {
description: `Create a simple message sent by current user`,
fn: async ({ generateResource, db }) => {
// 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<string, ScriptOption>) {
const list: Array<Omit<ScriptItem, 'file'>> = []
for (const id in scripts) {
Expand All @@ -79,12 +134,36 @@ export function defineScripts(scripts: Record<string, ScriptOption>) {
}
}

/**
* 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<TInfo extends Partial<ResourceFactoryInfo>, TFn extends ResourceFactoryFn>(info: TInfo, fn: TFn) {
return {
info,
Expand Down
8 changes: 7 additions & 1 deletion playground/src/schema.mock.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { defineResolvers, defineSchemaTransforms, defineScripts } from 'moquerie/mocks'
import { defineApiRoutes, defineResolvers, defineSchemaTransforms, defineScripts } from 'moquerie/mocks'

export default {
...defineResolvers({
Expand Down Expand Up @@ -96,4 +96,10 @@ export default {
},
},
}),

...defineApiRoutes((router) => {
router.get('/hello', async ({ db }) => {
return (await db.Message.findMany()).length
})
}),
}

0 comments on commit 52334b5

Please sign in to comment.