Skip to content

Instantly share code, notes, and snippets.

@smhmayboudi
Last active July 13, 2024 16:51
Show Gist options
  • Save smhmayboudi/9351d39d28e45931af3e61a1c5dfe39a to your computer and use it in GitHub Desktop.
Save smhmayboudi/9351d39d28e45931af3e61a1c5dfe39a to your computer and use it in GitHub Desktop.
import {Schema, Serializable} from '@effect/schema';
import {Brand, Console, Effect, HashMap, Ref, pipe} from 'effect';
export type Int = number & Brand.Brand<'Int'>;
export const Int = Brand.refined<Int>(
n => Number.isInteger(n),
n => Brand.error(`expected ${n} to be an integer.`)
);
export type Positive = number & Brand.Brand<'Positive'>;
export const Positive = Brand.refined<Positive>(
n => n >= 0,
n => Brand.error(`expected ${n} to be positive.`)
);
export const TodoId = Brand.all(Int, Positive);
export type TodoId = Brand.Brand.FromConstructor<typeof TodoId>;
export class TodoModelDAO extends Schema.Class<TodoModelDAO>('TodoModelDAO')({
id: pipe(Schema.Number, Schema.fromBrand(TodoId)),
title: Schema.String,
completed: Schema.Boolean,
}) {}
export class TodoModelBO extends Schema.Class<TodoModelBO>('TodoModelBO')({
id: pipe(Schema.Number, Schema.fromBrand(TodoId)),
title: Schema.String,
completed: Schema.Boolean,
}) {
static TransformFrom = Schema.transform(TodoModelDAO, TodoModelBO, {
decode: fromA =>
new TodoModelBO({
...fromA,
id: TodoId(fromA.id),
}),
encode: toI =>
new TodoModelDAO({
...toI,
id: TodoId(toI.id),
}),
});
get [Serializable.symbol]() {
return TodoModelBO.TransformFrom;
}
}
export class TodoModelDTO extends Schema.Class<TodoModelDTO>('TodoModelDTO')({
id: Schema.Number,
title: Schema.String,
completed: Schema.Number,
}) {
static TransformFrom = Schema.transform(TodoModelBO, TodoModelDTO, {
decode: fromA =>
new TodoModelDTO({
...fromA,
completed: fromA.completed ? 1 : 0,
}),
encode: toI =>
new TodoModelBO({
...toI,
id: TodoId(toI.id),
completed: toI.completed === 1,
}),
});
get [Serializable.symbol]() {
return TodoModelDTO.TransformFrom;
}
}
const app = Effect.gen(function* () {
const nextIdRef = yield* Ref.make(TodoId(1));
const todosRef = yield* Ref.make(HashMap.empty<TodoId, TodoModelDAO>());
const createTodo = pipe(
Ref.getAndUpdate(nextIdRef, n => TodoId(n + 1)),
Effect.flatMap(id =>
Ref.modify(todosRef, map => {
const newTodo = new TodoModelDAO({
id: TodoId(id),
title: 'HI, WHY!?',
completed: true,
});
const updated = HashMap.set(map, newTodo.id, newTodo);
Console.log('newTodo.id', newTodo.id);
Console.log('updated', updated);
return [newTodo.id, updated];
})
)
);
createTodo.pipe(Effect.runSync);
pipe(
Ref.get(todosRef),
Effect.flatMap(HashMap.get(TodoId(1))),
Effect.tap(o => Console.log('>>> map to', o)),
Effect.tapError(o => Console.log('>>> errors of map to', o)),
Effect.flatMap(
Schema.decode(TodoModelBO.TransformFrom, {
errors: 'all',
propertyOrder: 'original',
onExcessProperty: 'error',
exact: false,
})
),
Effect.tap(o => Console.log('>>> map to', o)),
Effect.tapError(o => Console.log('>>> errors of map to', o)),
Effect.match({
onFailure: () => Console.log('error on BO'),
// onSuccess: todo => Console.log('OK', todo),
onSuccess: todo =>
Effect.sync(() => {
const dto = Schema.decodeSync(TodoModelDTO.TransformFrom, {
errors: 'all',
propertyOrder: 'original',
onExcessProperty: 'error',
exact: true,
})(todo);
return Console.log('OK', dto);
}),
}),
// Effect.flatMap(
// Schema.decode(TodoModelDTO.TransformFrom, {
// errors: 'all',
// propertyOrder: 'original',
// onExcessProperty: 'error',
// exact: false,
// })
// ),
// Effect.tap(o => Console.log('>>> map to', o)),
// Effect.tapError(o => Console.log('>>> errors of map to', o)),
Effect.runSync
);
});
pipe(app, Effect.runSync);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment