-
-
Notifications
You must be signed in to change notification settings - Fork 172
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
Develop #254 - special benchmark for TypeBox
#255
Conversation
Oops, you revived |
Heya. See below for schema fixes. These should be compatible with both Ajv and TypeBox. Note that Feel free to update the other schemas with Fixes below. TypeBoxObjectUnionImplicit.tsimport { Type } from "@sinclair/typebox";
import { TypeCompiler } from "@sinclair/typebox/compiler";
const Point = Type.Object(
{
x: Type.Number(),
y: Type.Number(),
},
{ additionalProperties: false },
);
const Circle = Type.Object(
{
centroid: Point,
radius: Type.Number(),
},
{ additionalProperties: false },
);
const Line = Type.Object(
{
p1: Point,
p2: Point,
},
{ additionalProperties: false },
);
const Triangle = Type.Object(
{
p1: Point,
p2: Point,
p3: Point,
},
{ additionalProperties: false },
);
const Rectangle = Type.Object(
{
p1: Point,
p2: Point,
p3: Point,
p4: Point,
},
{ additionalProperties: false },
);
const Polyline = Type.Object(
{
points: Type.Array(Point),
},
{ additionalProperties: false },
);
const Polygon = Type.Object(
{
outer: Polyline,
inner: Type.Array(Polyline),
},
{ additionalProperties: false },
);
const Union = Type.Union([
Point,
Line,
Triangle,
Rectangle,
Polyline,
Polygon,
Circle,
]);
export const __TypeBoxObjectUnionImplicit = Type.Array(Union);
export const TypeBoxObjectUnionImplicit = TypeCompiler.Compile(
__TypeBoxObjectUnionImplicit,
); TypeBoxUltimateUnion.tsimport { TSchema, Type } from "@sinclair/typebox";
import { TypeCompiler } from "@sinclair/typebox/compiler";
const Attribute = {
description: Type.Optional(Type.String()),
"x-tson-metaTags": Type.Optional(Type.Array(Type.Any())),
"x-tson-jsDocTags": Type.Optional(Type.Array(Type.Any())),
};
const Unknown = Type.Object({}, { additionalProperties: false });
const NullOnly = Type.Object(
{
type: Type.Literal("null"),
...Attribute,
},
{ additionalProperties: false },
);
const Atomic = (literal: string, type: () => any) => {
return Type.Object(
{
type: Type.Literal(literal),
nullable: Type.Boolean(),
default: Type.Optional(type()),
...Attribute,
},
{ additionalProperties: false },
);
};
const Constant = (literal: string, type: () => any) =>
Type.Intersect(
[
Atomic(literal, type),
Type.Object({
enum: Type.Array(type()),
}),
],
{ additionalProperties: false },
);
const Array = <T extends TSchema>(schema: T) =>
Type.Object(
{
type: Type.Literal("array"),
items: schema,
nullable: Type.Boolean(),
...Attribute,
},
{ additionalProperties: false },
);
const Tuple = <T extends TSchema>(schema: T) =>
Type.Object(
{
type: Type.Literal("array"),
items: Type.Array(schema),
nullable: Type.Boolean(),
...Attribute,
},
{ additionalProperties: false },
);
const Reference = Type.Object(
{
$ref: Type.String(),
...Attribute,
},
{ additionalProperties: false },
);
const RecursiveReference = Type.Object(
{
$recursiveRef: Type.String(),
...Attribute,
},
{ additionalProperties: false },
);
const OneOf = <T extends TSchema>(schema: T) =>
Type.Object(
{
oneOf: Type.Array(schema),
...Attribute,
},
{ additionalProperties: false },
);
const ObjectDef = <T extends TSchema>(schema: T) =>
Type.Object(
{
$id: Type.Optional(Type.String()),
type: Type.Literal("object"),
nullable: Type.Boolean(),
properties: Type.Record(Type.String(), schema),
patternProperties: Type.Optional(
Type.Record(Type.String(), schema),
),
additionalProperties: Type.Optional(schema),
required: Type.Optional(Type.Array(Type.String())),
description: Type.Optional(Type.String()),
"x-tson_jsDocTags": Type.Optional(Type.Array(Type.Any())),
$recursiveAnchor: Type.Optional(Type.Boolean()),
},
{ additionalProperties: false },
);
const Components = <T extends TSchema>(schema: T) =>
Type.Object(
{
schemas: Type.Record(Type.String(), ObjectDef(schema)),
},
{ additionalProperties: false },
);
const Application = <T extends TSchema>(schema: T) =>
Type.Object(
{
schemas: Type.Array(schema),
components: Components(schema),
purpose: Type.Union([Type.Literal("swagger"), Type.Literal("ajv")]),
prefix: Type.String(),
},
{ additionalProperties: false },
);
const Schema = Type.Recursive((schema) =>
Type.Union([
Atomic("boolean", () => Type.Boolean()),
Atomic("integer", () => Type.Number()),
Atomic("bigint", () => Type.Number()),
Atomic("number", () => Type.Number()),
Atomic("string", () => Type.String()),
Constant("boolean", () => Type.Boolean()),
Constant("integer", () => Type.Number()),
Constant("bigint", () => Type.Number()),
Constant("number", () => Type.Number()),
Constant("string", () => Type.String()),
Array(schema),
Tuple(schema),
Reference,
RecursiveReference,
OneOf(schema),
Unknown,
NullOnly,
]),
);
export const __TypeBoxUltimateUnion = Type.Array(Application(Schema));
export const TypeBoxUltimateUnion = TypeCompiler.Compile(
__TypeBoxUltimateUnion,
);
|
You mean that when no dynamic property exists, must assign |
I'll remake benchmark program on Saturday, but it would be measured by another computer (surface pro8) |
@sinclairzx81 Wait, if you utilize |
Yes! there is a performance cost to But just on this (and TSON's default strict excess property checks), have you considered the following as it relates to structural checks in TypeScript? interface Vector3 {
x: number,
y: number,
z: number
}
interface Vector2 {
x: number,
y: number,
}
function add(a: Vector2, b: Vector2): Vector2 {
return { x: a.x + b.x, y: a.y + b.y }
}
// ------------------------------------------------------
// Allowed: Structural / Polymorphic Assignment
// ------------------------------------------------------
const a: Vector3 = { x: 0, y: 0, z: 0 }
const b: Vector3 = { x: 0, y: 0, z: 0 }
add(a, b) // ok !
// ------------------------------------------------------
// Not Allowed: (additionalProperties: false)
// ------------------------------------------------------
add(
{ x: 0, y: 0, z: 0 }, // <-- error !
{ x: 0, y: 0, z: 0 }
) Was wondering if TSON could detect type usage and only apply the union specialization algorithm in cases where direct assignment wasn't possible (inline the TS structural assignment - it has a term, but i forget the name of it). Ill try look it up. Update: I think TS lumps these assignment rules under "Excess Property Checks" Link Here, but I think the general term is "Construction vs Assignment" where Construction + Assignment leads to error. But in the general case, allowing for excess properties can be quite useful in the structural sense (and they're faster to check!!). |
Wow, I found a miracle performance on your How Can you explain me the reason why?
|
Well, I changed data generation function of I didn't understand how Anyway, your
Also, just understand me that I should utilize below graph for advertising. |
@sinclairzx81, this is not related to this benchmark PR. Anyway, when I present this project on a seminar, someone suggested me that shorter name would be much better and recommended me to rename |
@samchon Heya. You might want to fix up that Current Implementation // { prop: undefined | null | number } - expects `prop` to exist
prop: Type.Union([Type.Undefined(), Type.Null(), Type.Number()]) Fixed Implementation // { prop?: null | number } - prop is optional
prop: Type.Optional(Type.Union([Type.Null(), Type.Number()])) The following fixes up the test TypeBoxObjectImplicitUnion.tsimport { Type } from "@sinclair/typebox";
import { TypeCompiler } from "@sinclair/typebox/compiler";
const Point = Type.Object(
{
x: Type.Number(),
y: Type.Number(),
slope: Type.Optional(Type.Union([Type.Null(), Type.Number()])),
},
{ additionalProperties: false },
);
const Line = Type.Object(
{
p1: Point,
p2: Point,
distance: Type.Optional(Type.Union([Type.Null(), Type.Number()])),
},
{ additionalProperties: false },
);
const Triangle = Type.Object(
{
p1: Point,
p2: Point,
p3: Point,
width: Type.Optional(Type.Union([Type.Null(), Type.Number()])),
height: Type.Optional(Type.Union([Type.Null(), Type.Number()])),
area: Type.Optional(Type.Union([Type.Null(), Type.Number()])),
},
{ additionalProperties: false },
);
const Rectangle = Type.Object(
{
p1: Point,
p2: Point,
p3: Point,
p4: Point,
width: Type.Optional(Type.Union([Type.Null(), Type.Number()])),
height: Type.Optional(Type.Union([Type.Null(), Type.Number()])),
area: Type.Optional(Type.Union([Type.Null(), Type.Number()])),
},
{ additionalProperties: false },
);
const Polyline = Type.Object(
{
points: Type.Array(Point),
length: Type.Optional(Type.Union([Type.Null(), Type.Number()])),
},
{ additionalProperties: false },
);
const Polygon = Type.Object(
{
outer: Polyline,
inner: Type.Optional(Type.Array(Polyline)),
area: Type.Optional(Type.Union([Type.Null(), Type.Number()])),
},
{ additionalProperties: false },
);
const Circle = Type.Object(
{
centroid: Type.Optional(Point),
radius: Type.Number(),
area: Type.Optional(Type.Union([Type.Null(), Type.Number()])),
},
{ additionalProperties: false },
);
const Union = Type.Union([
Point,
Line,
Triangle,
Rectangle,
Polyline,
Polygon,
Circle,
]);
export const __TypeBoxObjectUnionImplicit = Type.Array(Union);
export const TypeBoxObjectUnionImplicit = TypeCompiler.Compile(
__TypeBoxObjectUnionImplicit,
); For the purposes of Ajv testing, just note JSON schema doesn't have a specification for Will submit a PR to fix this up. |
Typia sounds like a good name, you should reserve it!
I don't really select libraries based on what they're named (so I'm probably the wrong person to ask). I guess a shorter name can help the success of a library, but I'm mostly looking for functionality, documentation and ease of use first and foremost. |
1st completion for
TypeBox
benchmark.@sinclairzx81 Please check this PR and tell me if something is wrong.