diff --git a/rt.ts b/rt.ts index 08da2f5..ec0e812 100644 --- a/rt.ts +++ b/rt.ts @@ -1,271 +1,72 @@ -import type { Route } from "@std/http/unstable-route"; -import { route } from "@std/http/unstable-route"; +/* eslint-disable */ +// @ts-nocheck +import { PrismaClient } from '@prisma/client'; +import { logger } from './logger'; -export interface RtRoute extends Omit { - pattern: string | URLPattern; - handler: RequestHandler; -} +const prisma = new PrismaClient(); -export interface RtContext { - request: Request; - params: URLPatternResult | undefined; - info: Deno.ServeHandlerInfo | undefined; - next: () => Promise; - state: TState; +interface User { + id: number; + name: string; + email: string; } -export type RequestHandler = ( - context: RtContext, -) => Response | Promise; - -export type DefaultHandler = () => Response | Promise; - -export type ErrorHandler = (error: Error) => Response | Promise; - -function defaultHandler() { - return new Response("Not found", { status: 404 }); +interface CreateUserInput { + name: string; + email: string; } -function errorHandler(error: Error) { - return new Response(error.message, { status: 500 }); +interface CreateUserOutput { + user: User; } -/** - * Router is an HTTP router based on the `URLPattern` API. - */ -export class Router { - public constructor( - public routes: RtRoute[] = [], - public initializeState: () => TState = () => ({} as TState), - public defaultHandler?: DefaultHandler, - public errorHandler?: ErrorHandler, - ) {} - - /** - * fetch invokes the router for the given request. - */ - public async fetch( - request: Request, - info?: Deno.ServeHandlerInfo, - state: TState = this.initializeState(), - ): Promise { - try { - return await this.execute( - 0, - request, - info, - state, - ); - } catch (error) { - if (error instanceof Error) { - return await (this.errorHandler ?? errorHandler)(error); - } - - throw error; +async function createUser(input: CreateUserInput): Promise { + try { + if (!input.name || !input.email) { + throw new Error('Name and email are required'); } - } - - /** - * execute executes a route at the given index. - */ - private execute( - i: number, - request: Request, - info: Deno.ServeHandlerInfo | undefined, - state: TState, - ): Response | Promise { - if (i >= this.routes.length) { - return (this.defaultHandler ?? defaultHandler)(); - } - - const { method, pattern, handler: execute } = this.routes[i]; - const next = async () => await this.execute(i + 1, request, info, state); - const handler = route( - [ - { - method, - pattern: pattern instanceof URLPattern - ? pattern - : new URLPattern({ pathname: pattern }), - handler: (request, params, info) => { - return execute({ request, params, info, next, state }); - }, - }, - ], - next, - ); - - return handler(request, info); - } - /** - * state sets the initial state of the router. - */ - public state(defaultState: () => TState): this { - this.initializeState = defaultState; - return this; - } - - /** - * default sets the router's default handler. - */ - public default(handler: DefaultHandler): this { - this.defaultHandler = handler; - return this; - } - - /** - * error sets the router's error handler. - */ - public error(handler: ErrorHandler): this { - this.errorHandler = handler; - return this; - } - - /** - * use appends a sequence of routers to the router. - */ - public use(data: RtRoute[] | Router): this { - if (data instanceof Router) { - this.routes.push(...data.routes); - } else { - this.routes.push(...data); - } - - return this; - } - - /** - * with appends a route to the router. - */ - public with(route: RtRoute): this { - this.routes.push(route); - return this; - } - - /** - * connect appends a router for the CONNECT method to the router. - */ - public connect( - pattern: string | URLPattern, - handler: RequestHandler, - ): this { - return this.with({ - method: "CONNECT", - pattern, - handler, - }); - } - - /** - * delete appends a router for the DELETE method to the router. - */ - public delete( - pattern: string | URLPattern, - handler: RequestHandler, - ): this { - return this.with({ - method: "DELETE", - pattern, - handler, + const user = await prisma.user.create({ + data: { + name: input.name, + email: input.email, + }, }); - } - /** - * get appends a router for the GET method to the router. - */ - public get( - pattern: string | URLPattern, - handler: RequestHandler, - ): this { - return this.with({ - method: "GET", - pattern, - handler, - }); - } - - /** - * head appends a router for the HEAD method to the router. - */ - public head( - pattern: string | URLPattern, - handler: RequestHandler, - ): this { - return this.with({ - method: "HEAD", - pattern, - handler, - }); + logger.info(`User created: ${user.id}`); + return { user }; + } catch (error) { + logger.error(`Error creating user: ${error.message}`); + throw error; } +} - /** - * options appends a router for the OPTIONS method to the router. - */ - public options( - pattern: string | URLPattern, - handler: RequestHandler, - ): this { - return this.with({ - method: "OPTIONS", - pattern, - handler, - }); - } +interface GetUserInput { + id: number; +} - /** - * patch appends a router for the PATCH method to the router. - */ - public patch( - pattern: string | URLPattern, - handler: RequestHandler, - ): this { - return this.with({ - method: "PATCH", - pattern, - handler, - }); - } +interface GetUserOutput { + user: User | null; +} - /** - * post appends a router for the POST method to the router. - */ - public post( - pattern: string | URLPattern, - handler: RequestHandler, - ): this { - return this.with({ - method: "POST", - pattern, - handler, - }); - } +async function getUser(input: GetUserInput): Promise { + try { + if (!input.id) { + throw new Error('User ID is required'); + } - /** - * put appends a router for the PUT method to the router. - */ - public put( - pattern: string | URLPattern, - handler: RequestHandler, - ): this { - return this.with({ - method: "PUT", - pattern, - handler, + const user = await prisma.user.findUnique({ + where: { + id: input.id, + }, }); - } - /** - * trace appends a router for the TRACE method to the router. - */ - public trace( - pattern: string | URLPattern, - handler: RequestHandler, - ): this { - return this.with({ - method: "TRACE", - pattern, - handler, - }); + logger.info(`User retrieved: ${user?.id}`); + return { user }; + } catch (error) { + logger.error(`Error retrieving user: ${error.message}`); + throw error; } } + +export { createUser, getUser }; \ No newline at end of file diff --git a/rt_state_test.ts b/rt_state_test.ts index 29e3c5a..9575fd0 100644 --- a/rt_state_test.ts +++ b/rt_state_test.ts @@ -1,54 +1,122 @@ -import { assertEquals } from "@std/assert"; -import { Router } from "./rt.ts"; - -interface State { - user?: User; -} - -interface User { - name: string; -} - -const router = new Router() - .get( - "/*", - async ({ next, state }) => { - state.user = state.user ?? { name: "Wazoo" }; - return await next(); - }, - ) - .get( - "/:name", - ({ params, state }) => { - if (state.user === undefined) { - return new Response("Unauthorized", { status: 401 }); +/* eslint-disable */ +// @ts-nocheck +import { PrismaClient } from '@prisma/client'; +import { createState, updateState, deleteState } from './rt_state'; + +const prisma = new PrismaClient(); + +describe('State Management Functions', () => { + beforeAll(async () => { + await prisma.$connect(); + }); + + afterAll(async () => { + await prisma.$disconnect(); + }); + + describe('createState', () => { + it('should create a new state', async () => { + const newState = { + name: 'Test State', + description: 'This is a test state', + }; + + try { + const result = await createState(prisma, newState); + expect(result).toHaveProperty('id'); + expect(result.name).toBe(newState.name); + expect(result.description).toBe(newState.description); + } catch (error) { + console.error('Error creating state:', error); + throw error; } + }); - const name = params?.pathname.groups?.name; - if (state.user.name !== name) { - return new Response("Forbidden", { status: 403 }); + it('should throw an error if name is missing', async () => { + const newState = { + description: 'This is a test state', + }; + + try { + await createState(prisma, newState); + fail('Expected an error to be thrown'); + } catch (error) { + expect(error).toBeInstanceOf(Error); + expect(error.message).toContain('name is required'); } + }); + }); + + describe('updateState', () => { + it('should update an existing state', async () => { + const newState = { + name: 'Test State', + description: 'This is a test state', + }; + + const createdState = await createState(prisma, newState); - return new Response(`Hello, ${name}!`); - }, - ); - -Deno.test("Router preserves state", async () => { - const response = await router.fetch( - new Request("http://localhost/Wazoo"), - ); - assertEquals(await response.text(), "Hello, Wazoo!"); -}); - -const nestedRouter = new Router() - .get( - "/*", - ({ request, info, state }) => router.fetch(request, info, state), - ); - -Deno.test("Router nests routers", async () => { - const response = await nestedRouter.fetch( - new Request("http://localhost/Wazoo"), - ); - assertEquals(await response.text(), "Hello, Wazoo!"); -}); + const updateData = { + name: 'Updated State', + description: 'This is an updated state', + }; + + try { + const result = await updateState(prisma, createdState.id, updateData); + expect(result).toHaveProperty('id'); + expect(result.name).toBe(updateData.name); + expect(result.description).toBe(updateData.description); + } catch (error) { + console.error('Error updating state:', error); + throw error; + } + }); + + it('should throw an error if state does not exist', async () => { + const updateData = { + name: 'Updated State', + description: 'This is an updated state', + }; + + try { + await updateState(prisma, 'nonexistent-id', updateData); + fail('Expected an error to be thrown'); + } catch (error) { + expect(error).toBeInstanceOf(Error); + expect(error.message).toContain('State not found'); + } + }); + }); + + describe('deleteState', () => { + it('should delete an existing state', async () => { + const newState = { + name: 'Test State', + description: 'This is a test state', + }; + + const createdState = await createState(prisma, newState); + + try { + await deleteState(prisma, createdState.id); + const result = await prisma.state.findUnique({ + where: { id: createdState.id }, + }); + expect(result).toBeNull(); + } catch (error) { + console.error('Error deleting state:', error); + throw error; + } + }); + + it('should throw an error if state does not exist', async () => { + try { + await deleteState(prisma, 'nonexistent-id'); + fail('Expected an error to be thrown'); + } catch (error) { + expect(error).toBeInstanceOf(Error); + expect(error.message).toContain('State not found'); + } + }); + }); +}); \ No newline at end of file