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

Dynamic procedures #4

Open
hashwarp opened this issue Sep 4, 2024 · 0 comments
Open

Dynamic procedures #4

hashwarp opened this issue Sep 4, 2024 · 0 comments

Comments

@hashwarp
Copy link
Member

hashwarp commented Sep 4, 2024

I tried to get this working but couldn't get it.

import { z as zod, ZodTypeAny, ZodObject, ZodRawShape } from 'zod';
import {
  initTRPC,
  inferRouterInputs,
  inferRouterOutputs,
  procedure as TRPCProcedure,
  ProcedureBuilder,
} from '@trpc/server';
import { customErrorFormatter, hasRole } from '../../util/rpc';
import { dateFromString } from '../../util/zod';
import type { RouterContext } from '../../types';
import { Query, getQueryInput, inferRouterOutputs } from '../../schema';

// Define available entity names (capitalize first letter as used in dynamic names)
type EntityName = keyof typeof Entities;
type CapitalizedEntityName = Capitalize<EntityName>;
// Define possible service method names based on the entity name
type ServiceMethods<N extends string> = `get${N}` | `get${N}s` | `create${N}` | `update${N}`;

// Define the service type
type CoreService = {
  [K in ServiceMethods<CapitalizedEntityName>]: (input: any, ctx: RouterContext) => any;
};

// Utility type for ensuring the return type matches a ProcedureBuilder
type ProcedureType = ProcedureBuilder<RouterContext, object, object, any, any, any, any, boolean>;

// Define a type for entity procedures using template literal types
type EntityProcedures<N extends CapitalizedEntityName> = {
  [K in ServiceMethods<N>]: ProcedureType;
};

// Utility function to create standard procedures for an entity
function createEntityProcedures<N extends CapitalizedEntityName>(
  entity: ZodObject<ZodRawShape>,
  entityName: N
): EntityProcedures<N> {
  return {
    [`get${entityName}`]: procedure
      .use(hasRole('guest', t))
      .use(customErrorFormatter(t))
      .input(getQueryInput(entity))
      .output(entity)
      .query(({ input, ctx }) => (ctx.app.service.Core[`get${entityName}` as keyof CoreService] as any)(input, ctx)),

    [`get${entityName}s`]: procedure
      .use(hasRole('guest', t))
      .use(customErrorFormatter(t))
      .input(getQueryInput(entity))
      .output(entity.array())
      .query(({ input, ctx }) => (ctx.app.service.Core[`get${entityName}s` as keyof CoreService] as any)(input, ctx)),

    [`create${entityName}`]: procedure
      .use(hasRole('admin', t))
      .use(customErrorFormatter(t))
      .input(getQueryInput(entity))
      .output(entity.pick({ id: true }))
      .mutation(({ input, ctx }) =>
        (ctx.app.service.Core[`create${entityName}` as keyof CoreService] as any)(input, ctx)
      ),

    [`update${entityName}`]: procedure
      .use(hasRole('admin', t))
      .use(customErrorFormatter(t))
      .input(getQueryInput(entity))
      .output(entity.pick({ id: true }))
      .mutation(({ input, ctx }) =>
        (ctx.app.service.Core[`update${entityName}` as keyof CoreService] as any)(input, ctx)
      ),
  } as EntityProcedures<N>;
}

// Dynamically create all procedures using the utility function
const entityProcedures = Object.keys(Entities).reduce((acc, entityName) => {
  const entitySchema = Entities[entityName as keyof typeof Entities];
  if (!entitySchema || !(entitySchema instanceof z.ZodObject)) return acc; // Ensure the schema is a ZodObject
  const capitalizedEntityName = (entityName.charAt(0).toUpperCase() + entityName.slice(1)) as CapitalizedEntityName;
  return { ...acc, ...createEntityProcedures(entitySchema, capitalizedEntityName) };
}, {} as Record<string, ProcedureType>);


export const createRouter = () =>
  router({
    ...entityProcedures
  })
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant