This repository has been archived by the owner on Jan 6, 2025. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 37
RenameKeys
Giulio Canti edited this page May 5, 2023
·
3 revisions
Goal: just make it happen.
import * as S from '@effect/schema/Schema'
const From = S.struct({
key_one: S.string,
key_two: S.string
})
const To = S.struct({
keyOne: S.string,
keyTwo: S.string
})
export const schema = S.transform(
From,
To,
(from) => ({ keyOne: from.key_one, keyTwo: from.key_two }),
(to) => ({ key_one: to.keyOne, key_two: to.keyTwo })
)
console.log(S.decode(schema)({ key_one: 'a', key_two: 'b' }))
// { keyOne: 'a', keyTwo: 'b' }
One downside to this method is that it is boilerplate and can become repetitive for larger schemas.
Another downside is that it does not work well with the extend
combinator:
// throws "`extend` can only handle type literals or unions of type literals"
export const schema2 = S.extend(schema, S.struct({ a: S.number }))
Goal: extend
works.
import * as S from '@effect/schema/Schema'
import * as AST from '@effect/schema/AST'
import { identity } from '@effect/data/Function'
const From = S.struct({
key_one: S.string,
key_two: S.string
})
const To = S.struct({
keyOne: S.string,
keyTwo: S.string
})
export const schema: S.Schema<
{
readonly key_one: string
readonly key_two: string
},
{
readonly keyOne: string
readonly keyTwo: string
}
> = S.make(
AST.createTransformByPropertySignatureTransformations(From.ast, To.ast, [
AST.createPropertySignatureTransformation(
'key_one',
'keyOne',
identity,
identity
),
AST.createPropertySignatureTransformation(
'key_two',
'keyTwo',
identity,
identity
)
])
)
console.log(S.decode(schema)({ key_one: 'a', key_two: 'b' }))
// { keyOne: 'a', keyTwo: 'b' }
// ok
export const schema2 = S.extend(schema, S.struct({ a: S.number }))
console.log(S.decode(schema2)({ key_one: 'a', key_two: 'b', a: 1 }))
// { keyOne: 'a', keyTwo: 'b', a: 1 }
Goal: less boilerplate.
import * as S from '@effect/schema/Schema'
import * as AST from '@effect/schema/AST'
import { identity } from '@effect/data/Function'
// from @effect/schema/internal/common.ts
const ownKeys = (o: object): ReadonlyArray<PropertyKey> =>
(Object.keys(o) as ReadonlyArray<PropertyKey>).concat(
Object.getOwnPropertySymbols(o)
)
const rename = <A, Mapping extends Record<keyof A, PropertyKey>>(
schema: S.Schema<A>,
mapping: Mapping
): S.Schema<A, { [K in keyof A as Mapping[K]]: A[K] }> => {
const from = schema.ast
if (AST.isTypeLiteral(from)) {
const to = AST.createTypeLiteral(
from.propertySignatures.map((p) =>
AST.createPropertySignature(
(mapping as any)[p.name],
p.type,
p.isOptional,
p.isReadonly,
p.annotations
)
),
from.indexSignatures
)
return S.make(
AST.createTransformByPropertySignatureTransformations(
from,
to,
ownKeys(mapping).map((from) =>
AST.createPropertySignatureTransformation(
from,
(mapping as any)[from],
identity,
identity
)
)
)
)
}
throw new Error('`rename` can only handle type literals')
}
const From = S.struct({
key_one: S.string,
key_two: S.number
})
const schema = rename(From, { key_one: 'keyOne', key_two: 'keyTwo' } as const)
console.log(S.decode(schema)({ key_one: 'a', key_two: 1 }))
// { keyOne: 'a', keyTwo: 1 }
// ok
export const schema2 = S.extend(schema, S.struct({ a: S.boolean }))
console.log(S.decode(schema2)({ key_one: 'a', key_two: 1, a: true }))
// { a: true, keyOne: 'a', keyTwo: 1 }