Skip to content

Commit

Permalink
feat: BigInt support
Browse files Browse the repository at this point in the history
  • Loading branch information
Julien-R44 committed Jan 28, 2024
1 parent aaeb7ff commit 81aa868
Show file tree
Hide file tree
Showing 7 changed files with 358 additions and 0 deletions.
24 changes: 24 additions & 0 deletions src/schema/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
StringType,
ObjectType,
NumberType,
BigIntType,
EnumSetType,
BooleanType,
TypedSchema,
Expand Down Expand Up @@ -284,6 +285,28 @@ oneOf.nullableAndOptional = function nullableAndOptionalEnum(enumOptions: any[],
>
}

/**
* BigInt schema type
*/
function bigint(rules?: Rule[]) {
return getLiteralType('bigint', false, false, undefined, rules || []) as ReturnType<BigIntType>
}
bigint.optional = function optionalBigInt(rules?: Rule[]) {
return getLiteralType('bigint', true, false, undefined, rules || []) as ReturnType<
BigIntType['optional']
>
}
bigint.nullable = function nullableBigInt(rules?: Rule[]) {
return getLiteralType('bigint', false, true, undefined, rules || []) as ReturnType<
BigIntType['nullable']
>
}
bigint.nullableAndOptional = function nullableAndOptionalBigInt(rules?: Rule[]) {
return getLiteralType('bigint', true, true, undefined, rules || []) as ReturnType<
BigIntType['nullableAndOptional']
>
}

/**
* Enum set schema type
*/
Expand Down Expand Up @@ -365,6 +388,7 @@ export const schema: Schema = {
date,
object,
array,
bigint,
enum: oneOf as unknown as EnumType,
enumSet: enumSet as unknown as EnumSetType,
file,
Expand Down
23 changes: 23 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,28 @@ export type EnumSetReturnValue<Options extends AllowedEnumOptions> =
? Options[number][]
: never

/**
* BigInt schema types
*/
export interface BigIntType {
(rules?: Rule[]): {
t: bigint
getTree(): SchemaLiteral
}
optional(rules?: Rule[]): {
t?: bigint
getTree(): SchemaLiteral
}
nullable(rules?: Rule[]): {
t: bigint | null
getTree(): SchemaLiteral
}
nullableAndOptional(rules?: Rule[]): {
t?: bigint | null
getTree(): SchemaLiteral
}
}

/**
* Signature to define an enum type. We accept a static list of enum
* values or a ref that is resolved lazily.
Expand Down Expand Up @@ -644,6 +666,7 @@ export interface Schema {
boolean: BooleanType
number: NumberType
date: DateType
bigint: BigIntType
enum: EnumType
enumSet: EnumSetType
object: ObjectType
Expand Down
2 changes: 2 additions & 0 deletions src/validations/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import { file } from './primitives/file.js'
import { number } from './primitives/number.js'
import { object } from './primitives/object.js'
import { string } from './primitives/string.js'
import { bigint } from './primitives/bigint.js'

import { alpha } from './string/alpha.js'
import { alphaNum } from './string/alpha_num.js'
Expand Down Expand Up @@ -70,6 +71,7 @@ const validations = {
beforeOrEqual,
beforeField,
beforeOrEqualToField,
bigint,
confirmed,
required,
nullable,
Expand Down
50 changes: 50 additions & 0 deletions src/validations/primitives/bigint.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* @adonisjs/validator
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

import { SyncValidation } from '../../types.js'
import { wrapCompile } from '../../validator/helpers.js'

const DEFAULT_MESSAGE = 'bigint validation failed'
const RULE_NAME = 'bigint'

/**
* Ensure the value is a valid bigint. Numeric string will be casted
* to valid bigint
*/
export const bigint: SyncValidation = {
compile: wrapCompile(RULE_NAME),
validate(value, _, { mutate, errorReporter, pointer, arrayExpressionPointer }) {
if (typeof value === 'bigint') {
return
}

/**
* Report error when value is not a bigint and neither a string or a number
*/
if (typeof value !== 'string' && typeof value !== 'number') {
errorReporter.report(pointer, RULE_NAME, DEFAULT_MESSAGE, arrayExpressionPointer)
return
}

/**
* Attempt to cast string or number to a bigint. In case of
* failure report the validation error
*/
try {
const castedValue = BigInt(value)

/**
* Mutate the value
*/
mutate(castedValue)
} catch (e) {
errorReporter.report(pointer, RULE_NAME, DEFAULT_MESSAGE, arrayExpressionPointer)
}
},
}
5 changes: 5 additions & 0 deletions src/validations/primitives/number.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ export const number: SyncValidation = {
return
}

if (castedValue === Number.POSITIVE_INFINITY || castedValue === Number.NEGATIVE_INFINITY) {
errorReporter.report(pointer, RULE_NAME, DEFAULT_MESSAGE, arrayExpressionPointer)
return
}

/**
* Mutate the value
*/
Expand Down
110 changes: 110 additions & 0 deletions tests/schema.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,116 @@ test.group('Schema | Date', () => {
})
})

test.group('Schema | BigInt', () => {
test('define schema with bigint rule', ({ assert }) => {
assert.deepEqual(
schema.create({
username: schema.bigint(),
}).tree,
{
username: {
type: 'literal',
subtype: 'bigint',
optional: false,
nullable: false,
rules: [
{
name: 'required',
allowUndefineds: true,
async: false,
compiledOptions: [],
},
{
name: 'bigint',
allowUndefineds: false,
async: false,
compiledOptions: [],
},
],
},
}
)
})

test('define schema with optional bigint rule', ({ assert }) => {
assert.deepEqual(
schema.create({
username: schema.bigint.optional(),
}).tree,
{
username: {
type: 'literal',
subtype: 'bigint',
optional: true,
nullable: false,
rules: [
{
name: 'bigint',
allowUndefineds: false,
async: false,
compiledOptions: [],
},
],
},
}
)
})

test('define schema with nullable bigint rule', ({ assert }) => {
assert.deepEqual(
schema.create({
username: schema.bigint.nullable(),
}).tree,
{
username: {
type: 'literal',
subtype: 'bigint',
optional: false,
nullable: true,
rules: [
{
name: 'nullable',
allowUndefineds: true,
async: false,
compiledOptions: [],
},
{
name: 'bigint',
allowUndefineds: false,
async: false,
compiledOptions: [],
},
],
},
}
)
})

test('define schema with both optional and nullable bigint rule', ({ assert }) => {
assert.deepEqual(
schema.create({
username: schema.bigint.nullableAndOptional(),
}).tree,
{
username: {
type: 'literal',
subtype: 'bigint',
optional: true,
nullable: true,
rules: [
{
name: 'bigint',
allowUndefineds: false,
async: false,
compiledOptions: [],
},
],
},
}
)
})
})

test.group('Schema | Enum', () => {
test('define schema with enum rule', ({ assert }) => {
assert.deepEqual(
Expand Down
Loading

0 comments on commit 81aa868

Please sign in to comment.