Skip to content

Commit

Permalink
🧹 chore: merge mani
Browse files Browse the repository at this point in the history
  • Loading branch information
SaltyAom committed Dec 23, 2024
2 parents 0d2e399 + 4ed9465 commit 9c6571e
Show file tree
Hide file tree
Showing 9 changed files with 252 additions and 16 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# 1.1.27 - 23 Dec 2024
Bug fix:
- [#963](https://github.com/elysiajs/elysia/pull/963) array parser on query string when AOT is off
- [#961](https://github.com/elysiajs/elysia/pull/961) literal handler when AOT is off

# 1.1.26 - 4 Dev 2024
Bug fix:
- [#907](https://github.com/elysiajs/elysia/issues/907), [#872](https://github.com/elysiajs/elysia/issues/872), [#926](https://github.com/elysiajs/elysia/issues/926) BooleanString is not behave correctly if property is not provided
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "elysia",
"description": "Ergonomic Framework for Human",
"version": "1.2.0-exp.52",
"version": "1.2.0-rc.0",
"author": {
"name": "saltyAom",
"url": "https://github.com/SaltyAom",
Expand Down
10 changes: 6 additions & 4 deletions src/dynamic-handle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {

import type { Context } from './context'

import { parseQuery, parseQueryFromURL } from './fast-querystring'
import { parseQuery } from './fast-querystring'

import { redirect, signCookie, StatusMap } from './utils'
import { parseCookie } from './cookies'
Expand All @@ -19,7 +19,7 @@ import { TransformDecodeError } from '@sinclair/typebox/value'

// JIT Handler
export type DynamicHandler = {
handle: Handler<any, any>
handle: unknown | Handler<any, any>
content?: string
hooks: LifeCycleStore
validator?: SchemaValidator
Expand Down Expand Up @@ -175,8 +175,10 @@ export const createDynamicHandler = (app: AnyElysia) => {

context.body = body
context.params = handler?.params || undefined

// @ts-ignore
context.query =
qi === -1 ? {} : parseQueryFromURL(url.substring(qi + 1))
qi === -1 ? {} : parseQuery(url.substring(qi + 1))

context.headers = {}
for (const [key, value] of request.headers.entries())
Expand Down Expand Up @@ -332,7 +334,7 @@ export const createDynamicHandler = (app: AnyElysia) => {
}
}

let response = handle(context)
let response = typeof handle === 'function' ? handle(context) : handle
if (response instanceof Promise) response = await response

if (!hooks.afterHandle.length) {
Expand Down
42 changes: 39 additions & 3 deletions src/type-system.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import {
TArray,
TDate,
TUnsafe,
TypeRegistry
TypeRegistry,
TInteger,
IntegerOptions
} from '@sinclair/typebox'
import { TypeSystem } from '@sinclair/typebox/system'
import {
Expand Down Expand Up @@ -261,6 +263,12 @@ const Files: ElysiaFiles =
if (!FormatRegistry.Has('numeric'))
FormatRegistry.Set('numeric', (value) => !!value && !isNaN(+value))

if (!FormatRegistry.Has('integer'))
FormatRegistry.Set(
'integer',
(value) => !!value && Number.isInteger(+value)
)

if (!FormatRegistry.Has('boolean'))
FormatRegistry.Set(
'boolean',
Expand Down Expand Up @@ -354,6 +362,32 @@ export const ElysiaType = {
})
.Encode((value) => value) as any as TNumber
},
Integer: (property?: IntegerOptions): TInteger => {
const schema = Type.Integer(property)

return t
.Transform(
t.Union(
[
t.String({
format: 'integer',
default: 0
}),
t.Number(property)
],
property
)
)
.Decode((value) => {
const number = +value

if (!Value.Check(schema, number))
throw new ValidationError('property', schema, number)

return number
})
.Encode((value) => value) as any as TInteger
},
Date: (property?: DateOptions) => {
const schema = Type.Date(property)

Expand Down Expand Up @@ -637,6 +671,7 @@ declare module '@sinclair/typebox' {
ObjectString: typeof ElysiaType.ObjectString
ArrayString: typeof ElysiaType.ArrayString
Numeric: typeof ElysiaType.Numeric
Integer: typeof ElysiaType.Integer
File: typeof ElysiaType.File
Files: typeof ElysiaType.Files
Nullable: typeof ElysiaType.Nullable
Expand All @@ -663,7 +698,7 @@ declare module '@sinclair/typebox' {
/**
* A Boolean string
*
* Will be parse to Boolean
* Will be parsed to a Boolean
*/
t.BooleanString = ElysiaType.BooleanString
t.ObjectString = ElysiaType.ObjectString
Expand All @@ -672,9 +707,10 @@ t.ArrayString = ElysiaType.ArrayString
/**
* A Numeric string
*
* Will be parse to Number
* Will be parsed to a Number
*/
t.Numeric = ElysiaType.Numeric
t.Integer = ElysiaType.Integer

t.File = (arg = {}) =>
ElysiaType.File({
Expand Down
20 changes: 14 additions & 6 deletions test/core/dynamic.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ describe('Dynamic Mode', () => {
expect(res).toBe('Hi')
})

it('handle literal', async () => {
const app = new Elysia({ aot: false }).get('/', 'Hi');

const response = await app.handle(req('/')).then((x) => x.text());

expect(response).toBe('Hi');
})

it('handle body', async () => {
const app = new Elysia({
aot: false
Expand Down Expand Up @@ -144,15 +152,14 @@ describe('Dynamic Mode', () => {
})

it('validate', async () => {
const app = new Elysia({
// aot: false
}).post('/', ({ query: { id } }) => id.toString(), {
const app = new Elysia({ aot: false }).post('/', ({ query: { id, arr } }) => `${id} - ${arr}`, {
body: t.Object({
username: t.String(),
password: t.String()
}),
query: t.Object({
id: t.String()
id: t.String(),
arr: t.Array(t.String()),
}),
response: {
200: t.String()
Expand All @@ -161,13 +168,14 @@ describe('Dynamic Mode', () => {

const res = await app
.handle(
post('/?id=me', {
post('/?id=me&arr=v1&arr=v2', {
username: 'username',
password: 'password'
})
)
.then((x) => x.text())
expect(res).toBe('me')

expect(res).toBe('me - v1,v2')
})

it('handle non query fallback', async () => {
Expand Down
58 changes: 56 additions & 2 deletions test/validator/body.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,60 @@ describe('Body Validator', () => {
expect(res.status).toBe(200)
})

it('parse single integer', async () => {
const app = new Elysia().post('/', ({ body }) => body, {
body: t.Object({
name: t.String(),
job: t.String(),
trait: t.Optional(t.String()),
age: t.Integer()
})
})
const res = await app.handle(
post('/', {
name: 'sucrose',
job: 'alchemist',
age: '16'
})
)

expect(await res.json()).toEqual({
name: 'sucrose',
job: 'alchemist',
age: 16
})

expect(res.status).toBe(200)
})

it('parse multiple integers', async () => {
const app = new Elysia().post('/', ({ body }) => body, {
body: t.Object({
name: t.String(),
job: t.String(),
trait: t.Optional(t.String()),
age: t.Integer(),
rank: t.Integer()
})
})
const res = await app.handle(
post('/', {
name: 'sucrose',
job: 'alchemist',
age: '16',
rank: '4'
})
)

expect(await res.json()).toEqual({
name: 'sucrose',
job: 'alchemist',
age: 16,
rank: 4
})
expect(res.status).toBe(200)
})

it('validate empty body', async () => {
const app = new Elysia().post('/', ({ body }) => body, {
body: t.Union([
Expand Down Expand Up @@ -416,7 +470,7 @@ describe('Body Validator', () => {
expect(value).toBe('number')
})

it("coerce number to numeric", async () => {
it('coerce number to numeric', async () => {
const app = new Elysia().post('/', ({ body }) => typeof body, {
body: t.Number()
})
Expand Down Expand Up @@ -450,7 +504,7 @@ describe('Body Validator', () => {
expect(response.status).toBe(422)
})

it("coerce string to boolean", async () => {
it('coerce string to boolean', async () => {
const app = new Elysia().post('/', ({ body }) => typeof body, {
body: t.Boolean()
})
Expand Down
43 changes: 43 additions & 0 deletions test/validator/header.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,49 @@ describe('Header Validator', () => {
expect(res.status).toBe(200)
})

it('parse single integer', async () => {
const app = new Elysia().get('/', ({ headers }) => headers, {
headers: t.Object({
limit: t.Integer()
})
})
const res = await app.handle(
req('/', {
headers: {
limit: '16'
}
})
)

expect(await res.json()).toEqual({
limit: 16
})
expect(res.status).toBe(200)
})

it('parse multiple integers', async () => {
const app = new Elysia().get('/', ({ headers }) => headers, {
headers: t.Object({
limit: t.Integer(),
offset: t.Integer()
})
})
const res = await app.handle(
req('/', {
headers: {
limit: '16',
offset: '4'
}
})
)

expect(await res.json()).toEqual({
limit: 16,
offset: 4
})
expect(res.status).toBe(200)
})

it('validate partial', async () => {
const app = new Elysia().get('/', ({ headers }) => headers, {
headers: t.Partial(
Expand Down
65 changes: 65 additions & 0 deletions test/validator/params.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,71 @@ describe('Params Validator', () => {
expect(res.status).toBe(200)
})

it('parse single integer', async () => {
const app = new Elysia().get('/id/:id', ({ params }) => params, {
params: t.Object({
id: t.Integer()
})
})
const res = await app.handle(req('/id/617'))
expect(await res.json()).toEqual({
id: 617
})
expect(res.status).toBe(200)
})

it('parse malformed integer', async () => {
const app = new Elysia().get('/id/:id', ({ params }) => params, {
params: t.Object({
id: t.Integer()
})
})

const res = await app.handle(req('/id/617.1234'))
expect(await res.json()).toEqual({
errors: [
{
errors: [],
message: 'Expected integer',
path: '',
schema: {
type: 'integer'
},
summary: 'Expected integer',
type: 27,
value: 617.1234
}
],
expected: 0,
found: 617.1234,
message: 'Expected integer',
on: 'property',
property: 'root',
summary: 'Expected integer',
type: 'validation'
})
expect(res.status).toBe(422)
})

it('parse multiple integer', async () => {
const app = new Elysia().get(
'/id/:id/chapter/:chapterId',
({ params }) => params,
{
params: t.Object({
id: t.Integer(),
chapterId: t.Integer()
})
}
)
const res = await app.handle(req('/id/617/chapter/12'))
expect(await res.json()).toEqual({
id: 617,
chapterId: 12
})
expect(res.status).toBe(200)
})

it('create default string params', async () => {
const app = new Elysia().get('/:name', ({ params }) => params, {
params: t.Object({
Expand Down
Loading

0 comments on commit 9c6571e

Please sign in to comment.