Skip to content

Commit

Permalink
🎉 feat: reference model
Browse files Browse the repository at this point in the history
  • Loading branch information
SaltyAom committed Jan 23, 2023
1 parent 77e89f7 commit 9605f4e
Show file tree
Hide file tree
Showing 11 changed files with 610 additions and 138 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
@@ -1,3 +1,8 @@
# 0.2.0-rc.0 - 23 Jan 2023
Feature:
- Add support for reference model via `.setModel`
- Add support for OpenAPI's `definitions` field

# 0.2.0-beta.2 - 22 Jan 2023
Feature:
- Add support for custom openapi field using `schema.detail`
Expand Down
Binary file modified bun.lockb
Binary file not shown.
32 changes: 20 additions & 12 deletions example/schema.ts
@@ -1,25 +1,30 @@
import { Elysia, t, SCHEMA } from '../src'
import { Elysia, t, SCHEMA, DEFS } from '../src'

const app = new Elysia()
// Strictly validate response
.get('/', () => 'hi', {
schema: {
.setModel(
'a',
t.Object({
response: t.String()
}
})
})
)
.setModel(
'b',
t.Object({
response: t.Number()
})
)
// Strictly validate response
.get('/', () => 'hi')
// Strictly validate body and response
.post('/', ({ body }) => body.id, {
.post('/', ({ body, query }) => body.id, {
schema: {
body: t.Object({
id: t.Number(),
username: t.String(),
profile: t.Object({
name: t.String()
})
}),
response: {
200: t.Number()
}
})
}
})
// Strictly validate query, params, and body
Expand Down Expand Up @@ -71,4 +76,7 @@ const app = new Elysia()
)
.listen(8080)

type A = typeof app['store'][typeof SCHEMA]['/query/:id']['GET']['query']
type A = typeof app['store'][typeof SCHEMA]['/']['POST']['query']
type B = typeof app['store'][typeof DEFS]

// const a = app.getModel('b')
2 changes: 1 addition & 1 deletion package.json
@@ -1,7 +1,7 @@
{
"name": "elysia",
"description": "Fast, and friendly Bun web framework",
"version": "0.2.0-beta.2",
"version": "0.2.0-rc.0",
"author": {
"name": "saltyAom",
"url": "https://github.com/SaltyAom",
Expand Down
10 changes: 6 additions & 4 deletions src/context.ts
@@ -1,16 +1,18 @@
import { Elysia } from '.'
import type { TypedRoute } from './types'

type UnwrapFn<T> = T extends (...params: any) => any ? ReturnType<T> : T

export interface Context<
Route extends TypedRoute = TypedRoute,
Store extends Elysia['store'] = Elysia['store']
> {
request: Request
query: Route['query'] extends undefined
query: UnwrapFn<Route['query']> extends undefined
? Record<string, unknown>
: Route['query']
params: Route['params']
body: Route['body']
: UnwrapFn<Route['query']>
params: UnwrapFn<Route['params']>
body: UnwrapFn<Route['body']>
store: Store

set: {
Expand Down
87 changes: 58 additions & 29 deletions src/index.ts
Expand Up @@ -8,8 +8,10 @@ import {
mergeHook,
mergeDeep,
createValidationError,
getSchemaValidator,
SCHEMA,
getSchemaValidator
DEFS,
getResponseSchemaValidator
} from './utils'
import { registerSchemaPath } from './schema'
import { mapErrorCode, mapErrorStatus } from './error'
Expand Down Expand Up @@ -44,8 +46,10 @@ import type {
NoReturnHandler,
ElysiaRoute,
MaybePromise,
IsNever
IsNever,
InferSchema
} from './types'
import { type TSchema } from '@sinclair/typebox'

/**
* ### Elysia Server
Expand All @@ -65,7 +69,8 @@ export default class Elysia<Instance extends ElysiaInstance = ElysiaInstance> {
config: ElysiaConfig

store: Instance['store'] = {
[SCHEMA]: {}
[SCHEMA]: {},
[DEFS]: {}
}
// Will be applied to Context
protected decorators: Record<string, unknown> | null = null
Expand Down Expand Up @@ -99,7 +104,7 @@ export default class Elysia<Instance extends ElysiaInstance = ElysiaInstance> {
}

private _addHandler<
Schema extends TypedSchema = TypedSchema,
Schema extends TypedSchema,
Path extends string = string
>(
method: HTTPMethod,
Expand All @@ -116,28 +121,36 @@ export default class Elysia<Instance extends ElysiaInstance = ElysiaInstance> {
hooks: mergeHook(clone(this.event), hook as RegisteredHook)
})

const defs = this.store[DEFS]

const body = getSchemaValidator(
hook?.schema?.body ?? this.$schema?.body
hook?.schema?.body ?? this.$schema?.body,
defs
)
const header = getSchemaValidator(
hook?.schema?.headers ?? this.$schema?.headers,
defs,
true
)
const params = getSchemaValidator(
hook?.schema?.params ?? this.$schema?.params
hook?.schema?.params ?? this.$schema?.params,
defs
)
const query = getSchemaValidator(
hook?.schema?.query ?? this.$schema?.query
hook?.schema?.query ?? this.$schema?.query,
defs
)
const response = getSchemaValidator(
hook?.schema?.response ?? this.$schema?.response
const response = getResponseSchemaValidator(
hook?.schema?.response ?? this.$schema?.response,
defs
)

registerSchemaPath({
schema: this.store[SCHEMA],
hook,
method,
path
path,
models: this.store[DEFS]
})

const validator =
Expand Down Expand Up @@ -639,7 +652,7 @@ export default class Elysia<Instance extends ElysiaInstance = ElysiaInstance> {
* ```
*/
get<
Schema extends TypedSchema = TypedSchema,
Schema extends InferSchema<Instance> = InferSchema<Instance>,
Path extends string = string,
Response = unknown
>(
Expand Down Expand Up @@ -671,7 +684,7 @@ export default class Elysia<Instance extends ElysiaInstance = ElysiaInstance> {
* ```
*/
post<
Schema extends TypedSchema = {},
Schema extends InferSchema<Instance> = InferSchema<Instance>,
Path extends string = string,
Response = unknown
>(
Expand Down Expand Up @@ -703,7 +716,7 @@ export default class Elysia<Instance extends ElysiaInstance = ElysiaInstance> {
* ```
*/
put<
Schema extends TypedSchema = {},
Schema extends InferSchema<Instance> = InferSchema<Instance>,
Path extends string = string,
Response = unknown
>(
Expand Down Expand Up @@ -735,7 +748,7 @@ export default class Elysia<Instance extends ElysiaInstance = ElysiaInstance> {
* ```
*/
patch<
Schema extends TypedSchema = {},
Schema extends InferSchema<Instance> = InferSchema<Instance>,
Path extends string = string,
Response = unknown
>(
Expand Down Expand Up @@ -767,7 +780,7 @@ export default class Elysia<Instance extends ElysiaInstance = ElysiaInstance> {
* ```
*/
delete<
Schema extends TypedSchema = {},
Schema extends InferSchema<Instance> = InferSchema<Instance>,
Path extends string = string,
Response = unknown
>(
Expand Down Expand Up @@ -799,7 +812,7 @@ export default class Elysia<Instance extends ElysiaInstance = ElysiaInstance> {
* ```
*/
options<
Schema extends TypedSchema = {},
Schema extends InferSchema<Instance> = InferSchema<Instance>,
Path extends string = string,
Response = unknown
>(
Expand All @@ -826,7 +839,7 @@ export default class Elysia<Instance extends ElysiaInstance = ElysiaInstance> {
* ```
*/
all<
Schema extends TypedSchema = {},
Schema extends InferSchema<Instance> = InferSchema<Instance>,
Path extends string = string,
Response = unknown
>(
Expand Down Expand Up @@ -858,7 +871,7 @@ export default class Elysia<Instance extends ElysiaInstance = ElysiaInstance> {
* ```
*/
head<
Schema extends TypedSchema = {},
Schema extends InferSchema<Instance> = InferSchema<Instance>,
Path extends string = string,
Response = unknown
>(
Expand Down Expand Up @@ -890,7 +903,7 @@ export default class Elysia<Instance extends ElysiaInstance = ElysiaInstance> {
* ```
*/
trace<
Schema extends TypedSchema = {},
Schema extends InferSchema<Instance> = InferSchema<Instance>,
Path extends string = string,
Response = unknown
>(
Expand Down Expand Up @@ -922,7 +935,7 @@ export default class Elysia<Instance extends ElysiaInstance = ElysiaInstance> {
* ```
*/
connect<
Schema extends TypedSchema = {},
Schema extends InferSchema<Instance> = InferSchema<Instance>,
Path extends string = string,
Response = unknown
>(
Expand Down Expand Up @@ -955,7 +968,7 @@ export default class Elysia<Instance extends ElysiaInstance = ElysiaInstance> {
*/
route<
Method extends HTTPMethod = HTTPMethod,
Schema extends TypedSchema = {},
Schema extends InferSchema<Instance> = InferSchema<Instance>,
Path extends string = string,
Response = unknown
>(
Expand Down Expand Up @@ -1104,21 +1117,22 @@ export default class Elysia<Instance extends ElysiaInstance = ElysiaInstance> {
* ```
*/
schema<
Schema extends TypedSchema = TypedSchema,
Schema extends InferSchema<Instance> = InferSchema<Instance>,
NewInstance = Elysia<{
request: Instance['request']
store: Instance['store']
schema: MergeSchema<Schema, Instance['schema']>
}>
>(schema: Schema): NewInstance {
const defs = this.store[DEFS]

this.$schema = {
body: getSchemaValidator(schema?.body),
headers: getSchemaValidator(schema?.headers),
params: getSchemaValidator(schema?.params),
query: getSchemaValidator(schema?.query),
response: getSchemaValidator(
schema?.response?.['200'] ?? schema.response
)
body: getSchemaValidator(schema.body, defs),
headers: getSchemaValidator(schema?.headers, defs, true),
params: getSchemaValidator(schema?.params, defs),
query: getSchemaValidator(schema?.query, defs),
// @ts-ignore
response: getSchemaValidator(schema?.response, defs)
}

return this as unknown as NewInstance
Expand Down Expand Up @@ -1421,13 +1435,28 @@ export default class Elysia<Instance extends ElysiaInstance = ElysiaInstance> {
get modules() {
return Promise.all(this.lazyLoadModules)
}

setModel<Recorder extends Record<string, TSchema>>(
record: Recorder
): Elysia<{
store: Instance['store'] & {
[Defs in typeof DEFS]: Recorder
}
request: Instance['request']
schema: Instance['schema']
}> {
Object.assign(this.store[DEFS], record)

return this as unknown as any
}
}

export { Elysia, Router }
export { Type as t } from '@sinclair/typebox'

export {
SCHEMA,
DEFS,
getPath,
createValidationError,
getSchemaValidator
Expand Down

0 comments on commit 9605f4e

Please sign in to comment.