Co-authored-by: Julien Valverdé <julien.valverde@mailo.com> Reviewed-on: https://git.jvalver.de/Thilawyn/schemable-class/pulls/1
This commit was merged in pull request #1.
This commit is contained in:
66
src/jsonifiable/JsonifiableSchemableClass.ts
Normal file
66
src/jsonifiable/JsonifiableSchemableClass.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import { Effect } from "effect"
|
||||
import { Class } from "type-fest"
|
||||
import { JsonifiableObject } from "type-fest/source/jsonifiable"
|
||||
import { z } from "zod"
|
||||
import { SchemableClassConstructorParams, SchemableConfig } from ".."
|
||||
|
||||
|
||||
export type JsonifiableSchemableConfig<
|
||||
$SchemableConfig extends SchemableConfig = SchemableConfig,
|
||||
|
||||
JsonifiedValues extends JsonifiableObject = {},
|
||||
|
||||
JsonifySchemaT extends z.ZodRawShape = z.ZodRawShape,
|
||||
JsonifySchemaUnknownKeys extends z.UnknownKeysParam = z.UnknownKeysParam,
|
||||
JsonifySchemaCatchall extends z.ZodTypeAny = z.ZodTypeAny,
|
||||
|
||||
DejsonifySchemaT extends z.ZodRawShape = z.ZodRawShape,
|
||||
DejsonifySchemaUnknownKeys extends z.UnknownKeysParam = z.UnknownKeysParam,
|
||||
DejsonifySchemaCatchall extends z.ZodTypeAny = z.ZodTypeAny,
|
||||
> = {
|
||||
readonly $schemableConfig: $SchemableConfig
|
||||
|
||||
readonly jsonifiedValues: JsonifiedValues
|
||||
|
||||
readonly jsonifySchema: z.ZodObject<
|
||||
JsonifySchemaT,
|
||||
JsonifySchemaUnknownKeys,
|
||||
JsonifySchemaCatchall,
|
||||
JsonifiedValues,
|
||||
$SchemableConfig["values"]
|
||||
>
|
||||
|
||||
readonly dejsonifySchema: z.ZodObject<
|
||||
DejsonifySchemaT,
|
||||
DejsonifySchemaUnknownKeys,
|
||||
DejsonifySchemaCatchall,
|
||||
$SchemableConfig["values"],
|
||||
JsonifiedValues
|
||||
>
|
||||
}
|
||||
|
||||
|
||||
export type JsonifiableSchemableClass<
|
||||
$Config extends JsonifiableSchemableConfig
|
||||
> = (
|
||||
Class<
|
||||
JsonifiableSchemableObject<$Config>,
|
||||
SchemableClassConstructorParams<$Config["$schemableConfig"]>
|
||||
> & {
|
||||
readonly $jsonifiableSchemableConfig: $Config
|
||||
readonly jsonifySchema: $Config["jsonifySchema"]
|
||||
readonly dejsonifySchema: $Config["dejsonifySchema"]
|
||||
}
|
||||
)
|
||||
|
||||
export type JsonifiableSchemableObject<
|
||||
$Config extends JsonifiableSchemableConfig
|
||||
> = {
|
||||
readonly $jsonifiableSchemableConfig: $Config
|
||||
readonly jsonifySchema: $Config["jsonifySchema"]
|
||||
readonly dejsonifySchema: $Config["dejsonifySchema"]
|
||||
|
||||
jsonify(): $Config["jsonifiedValues"]
|
||||
jsonifyPromise(): Promise<$Config["jsonifiedValues"]>
|
||||
jsonifyEffect(): Effect.Effect<never, z.ZodError<$Config["$schemableConfig"]["values"]>, $Config["jsonifiedValues"]>
|
||||
}
|
||||
47
src/jsonifiable/dejsonifySchemable.ts
Normal file
47
src/jsonifiable/dejsonifySchemable.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { Effect, pipe } from "effect"
|
||||
import { z } from "zod"
|
||||
import { JsonifiableSchemableClass, JsonifiableSchemableConfig } from "."
|
||||
import { parseZodTypeEffect } from "../util"
|
||||
|
||||
|
||||
export const dejsonifySchemable = <
|
||||
C extends JsonifiableSchemableClass<$Config>,
|
||||
$Config extends JsonifiableSchemableConfig,
|
||||
>(
|
||||
class_: C | JsonifiableSchemableClass<$Config>,
|
||||
values: $Config["jsonifiedValues"],
|
||||
params?: Partial<z.ParseParams>,
|
||||
) =>
|
||||
new class_(class_.dejsonifySchema.parse(values, params)) as InstanceType<C>
|
||||
|
||||
|
||||
export const dejsonifySchemablePromise = async <
|
||||
C extends JsonifiableSchemableClass<$Config>,
|
||||
$Config extends JsonifiableSchemableConfig,
|
||||
>(
|
||||
class_: C | JsonifiableSchemableClass<$Config>,
|
||||
values: $Config["jsonifiedValues"],
|
||||
params?: Partial<z.ParseParams>,
|
||||
) =>
|
||||
new class_(await class_.dejsonifySchema.parseAsync(values, params)) as InstanceType<C>
|
||||
|
||||
|
||||
export const dejsonifySchemableEffect = <
|
||||
C extends JsonifiableSchemableClass<$Config>,
|
||||
$Config extends JsonifiableSchemableConfig,
|
||||
>(
|
||||
class_: C | JsonifiableSchemableClass<$Config>,
|
||||
values: $Config["jsonifiedValues"],
|
||||
params?: Partial<z.ParseParams>,
|
||||
) => pipe(
|
||||
parseZodTypeEffect<
|
||||
z.output<typeof class_.dejsonifySchema>,
|
||||
z.input<typeof class_.dejsonifySchema>
|
||||
>(
|
||||
class_.dejsonifySchema,
|
||||
values,
|
||||
params,
|
||||
),
|
||||
|
||||
Effect.map(values => new class_(values) as InstanceType<C>),
|
||||
)
|
||||
4
src/jsonifiable/index.ts
Normal file
4
src/jsonifiable/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export * from "./JsonifiableSchemableClass"
|
||||
export * from "./dejsonifySchemable"
|
||||
export * from "./makeJsonifiableSchemableClass"
|
||||
export * from "./schema"
|
||||
98
src/jsonifiable/makeJsonifiableSchemableClass.ts
Normal file
98
src/jsonifiable/makeJsonifiableSchemableClass.ts
Normal file
@@ -0,0 +1,98 @@
|
||||
import { Class } from "type-fest"
|
||||
import { JsonifiableObject } from "type-fest/source/jsonifiable"
|
||||
import { z } from "zod"
|
||||
import { JsonifiableSchemableClass, JsonifiableSchemableConfig, JsonifiableSchemableObject } from "."
|
||||
import { SchemableClass, SchemableConfig } from ".."
|
||||
import { StaticMembers, parseZodTypeEffect } from "../util"
|
||||
|
||||
|
||||
export function makeJsonifiableSchemableClass<
|
||||
C extends SchemableClass<$SchemableConfig>,
|
||||
$SchemableConfig extends SchemableConfig,
|
||||
|
||||
JsonifiedValues extends JsonifiableObject,
|
||||
|
||||
JsonifySchemaT extends z.ZodRawShape,
|
||||
JsonifySchemaUnknownKeys extends z.UnknownKeysParam,
|
||||
JsonifySchemaCatchall extends z.ZodTypeAny,
|
||||
|
||||
DejsonifySchemaT extends z.ZodRawShape,
|
||||
DejsonifySchemaUnknownKeys extends z.UnknownKeysParam,
|
||||
DejsonifySchemaCatchall extends z.ZodTypeAny,
|
||||
>(
|
||||
class_: C | SchemableClass<$SchemableConfig>,
|
||||
|
||||
props: {
|
||||
jsonifySchema: (props: {
|
||||
schema: $SchemableConfig["schema"]
|
||||
s: $SchemableConfig["schema"]["shape"]
|
||||
}) => z.ZodObject<
|
||||
JsonifySchemaT,
|
||||
JsonifySchemaUnknownKeys,
|
||||
JsonifySchemaCatchall,
|
||||
JsonifiedValues,
|
||||
$SchemableConfig["values"]
|
||||
>
|
||||
|
||||
dejsonifySchema: (props: {
|
||||
schema: $SchemableConfig["schema"]
|
||||
s: $SchemableConfig["schema"]["shape"]
|
||||
}) => z.ZodObject<
|
||||
DejsonifySchemaT,
|
||||
DejsonifySchemaUnknownKeys,
|
||||
DejsonifySchemaCatchall,
|
||||
$SchemableConfig["values"],
|
||||
JsonifiedValues
|
||||
>
|
||||
},
|
||||
) {
|
||||
|
||||
const jsonifySchema = props.jsonifySchema({
|
||||
schema: class_.schema,
|
||||
s: class_.schema.shape,
|
||||
})
|
||||
|
||||
const dejsonifySchema = props.dejsonifySchema({
|
||||
schema: class_.schema,
|
||||
s: class_.schema.shape,
|
||||
})
|
||||
|
||||
const $jsonifiableSchemableConfig = {
|
||||
$schemableConfig: class_.$schemableConfig,
|
||||
jsonifiedValues: undefined as unknown as JsonifiedValues,
|
||||
jsonifySchema: undefined as unknown as typeof jsonifySchema,
|
||||
dejsonifySchema: undefined as unknown as typeof dejsonifySchema,
|
||||
} as const satisfies JsonifiableSchemableConfig
|
||||
|
||||
const jsonifiableClass = class JsonifiableSchemableObject extends class_ {
|
||||
static readonly $jsonifiableSchemableConfig = $jsonifiableSchemableConfig
|
||||
static readonly jsonifySchema = jsonifySchema
|
||||
static readonly dejsonifySchema = dejsonifySchema
|
||||
|
||||
readonly $jsonifiableSchemableConfig = $jsonifiableSchemableConfig
|
||||
readonly jsonifySchema = jsonifySchema
|
||||
readonly dejsonifySchema = dejsonifySchema
|
||||
|
||||
jsonify() {
|
||||
return this.jsonifySchema.parse(this)
|
||||
}
|
||||
|
||||
jsonifyPromise() {
|
||||
return this.jsonifySchema.parseAsync(this)
|
||||
}
|
||||
|
||||
jsonifyEffect() {
|
||||
return parseZodTypeEffect(this.jsonifySchema, this)
|
||||
}
|
||||
} satisfies JsonifiableSchemableClass<typeof $jsonifiableSchemableConfig>
|
||||
|
||||
return jsonifiableClass as unknown as (
|
||||
Class<
|
||||
InstanceType<C> & JsonifiableSchemableObject<typeof $jsonifiableSchemableConfig>,
|
||||
ConstructorParameters<C>
|
||||
> &
|
||||
StaticMembers<C> &
|
||||
StaticMembers<JsonifiableSchemableClass<typeof $jsonifiableSchemableConfig>>
|
||||
)
|
||||
|
||||
}
|
||||
18
src/jsonifiable/schema/bigint.ts
Normal file
18
src/jsonifiable/schema/bigint.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { z } from "zod"
|
||||
|
||||
|
||||
export const jsonifyBigIntSchema = <S extends z.ZodBigInt>(schema: S) =>
|
||||
schema.transform(v => v.toString())
|
||||
|
||||
export const dejsonifyBigIntSchema = <S extends z.ZodBigInt>(schema: S) =>
|
||||
z
|
||||
.string()
|
||||
.transform(v => {
|
||||
try {
|
||||
return BigInt(v)
|
||||
}
|
||||
catch (e) {
|
||||
return v
|
||||
}
|
||||
})
|
||||
.pipe(schema)
|
||||
18
src/jsonifiable/schema/date.ts
Normal file
18
src/jsonifiable/schema/date.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { z } from "zod"
|
||||
|
||||
|
||||
export const jsonifyDateSchema = <S extends z.ZodDate>(schema: S) =>
|
||||
schema.transform(v => v.toString())
|
||||
|
||||
export const dejsonifyDateSchema = <S extends z.ZodDate>(schema: S) =>
|
||||
z
|
||||
.string()
|
||||
.transform(v => {
|
||||
try {
|
||||
return new Date(v)
|
||||
}
|
||||
catch (e) {
|
||||
return v
|
||||
}
|
||||
})
|
||||
.pipe(schema)
|
||||
19
src/jsonifiable/schema/decimal.ts
Normal file
19
src/jsonifiable/schema/decimal.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { Decimal } from "decimal.js"
|
||||
import { z } from "zod"
|
||||
|
||||
|
||||
export const jsonifyDecimalSchema = <S extends z.ZodType<Decimal, z.ZodTypeDef, Decimal>>(schema: S) =>
|
||||
schema.transform(v => v.toJSON())
|
||||
|
||||
export const dejsonifyDecimalSchema = <S extends z.ZodType<Decimal, z.ZodTypeDef, Decimal>>(schema: S) =>
|
||||
z
|
||||
.string()
|
||||
.transform(v => {
|
||||
try {
|
||||
return new Decimal(v)
|
||||
}
|
||||
catch (e) {
|
||||
return v
|
||||
}
|
||||
})
|
||||
.pipe(schema)
|
||||
4
src/jsonifiable/schema/index.ts
Normal file
4
src/jsonifiable/schema/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export * from "./bigint"
|
||||
export * from "./date"
|
||||
export * from "./decimal"
|
||||
export * from "./schemable"
|
||||
25
src/jsonifiable/schema/schemable.ts
Normal file
25
src/jsonifiable/schema/schemable.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { z } from "zod"
|
||||
import { JsonifiableSchemableClass, JsonifiableSchemableConfig } from ".."
|
||||
|
||||
|
||||
// TODO: try to find a way to get rid of the 'class_' arg
|
||||
export const jsonifySchemableSchema = <
|
||||
C extends JsonifiableSchemableClass<$Config>,
|
||||
$Config extends JsonifiableSchemableConfig,
|
||||
S extends z.ZodType<InstanceType<C>, z.ZodTypeDef, InstanceType<C>>,
|
||||
>(
|
||||
class_: C | JsonifiableSchemableClass<$Config>,
|
||||
schema: S,
|
||||
) =>
|
||||
schema.pipe(class_.jsonifySchema)
|
||||
|
||||
// TODO: try to find a way to get rid of the 'class_' arg
|
||||
export const dejsonifySchemableSchema = <
|
||||
C extends JsonifiableSchemableClass<$Config>,
|
||||
$Config extends JsonifiableSchemableConfig,
|
||||
S extends z.ZodType<InstanceType<C>, z.ZodTypeDef, InstanceType<C>>,
|
||||
>(
|
||||
class_: C | JsonifiableSchemableClass<$Config>,
|
||||
schema: S,
|
||||
) =>
|
||||
class_.dejsonifySchema.transform(v => new class_(v)).pipe(schema)
|
||||
Reference in New Issue
Block a user