Created
June 19, 2018 08:41
-
-
Save mattiamanzati/a4807e19e4455be9630b2dc4835ef9d9 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as t from "io-ts" | |
import {taskEither, TaskEither} from "fp-ts/lib/TaskEither" | |
import {Either, either} from "fp-ts/lib/Either" | |
import { Task } from 'fp-ts/lib/Task'; | |
export type IFieldObserver<T> = (newValue: T) => TaskEither<any, void> | |
export type IFieldInterceptor<T> = (newValue: T) => TaskEither<any, T> | |
export interface IDisposer extends TaskEither<void, void>{} | |
export class Ref<T>{ | |
protected readonly observers: IFieldObserver<T>[] = [] | |
protected readonly interceptors: IFieldInterceptor<T>[] = [] | |
constructor(protected storedValue: T) { | |
} | |
read() { | |
return this.storedValue | |
} | |
write(newValue: T) { | |
return this.observers.reduce( | |
(task, observer) => task.chain((v) => observer(v).map(() => v)), | |
this.interceptors.reduce( | |
(task, interceptor) => task.chain(interceptor), | |
taskEither.of(newValue) | |
).chain((currentValue) => new TaskEither(new Task(() => { | |
this.storedValue = currentValue | |
return Promise.resolve(either.of(currentValue)) | |
})) | |
).map(() => { }) | |
} | |
observe(fn: IFieldObserver<T>) { | |
return new TaskEither(new Task(() => { | |
let isSubscribed = true | |
this.observers.push(fn) | |
return Promise.resolve( | |
either.of(new TaskEither<void, void>(new Task(() => { | |
if (isSubscribed) { | |
this.observers.splice(this.observers.indexOf(fn), 1) | |
isSubscribed = false | |
} | |
return Promise.resolve(either.of(undefined)) | |
}))) | |
) | |
})) | |
} | |
intercept(fn: IFieldInterceptor<T>) { | |
return new TaskEither(new Task(() => { | |
let isSubscribed = true | |
this.interceptors.push(fn) | |
return Promise.resolve( | |
either.of(new TaskEither<void, void>(new Task(() => { | |
if (isSubscribed) { | |
this.interceptors.splice(this.interceptors.indexOf(fn), 1) | |
isSubscribed = false | |
} | |
return Promise.resolve(either.of(undefined)) | |
}))) | |
) | |
})) | |
} | |
} | |
export class RefType<A, O, I> extends t.Type<Ref<A>, O, I>{ | |
constructor( | |
type: t.Type<A, O, I> | |
){ | |
super( | |
`Ref<${type.name}>`, | |
(m): m is Ref<A> => type.is(m), | |
(m, c) => this.is(m) ? type.validate(m, c).map(v => new Ref(v)) : t.failure(m, c), | |
(m) => type.encode(m.read()) | |
) | |
} | |
} | |
function ref<A, O, I>(type: t.Type<A, O, I>){ | |
return new RefType(type) | |
} | |
function entity<P extends t.AnyProps>(props: P) { | |
return t.readonly(t.interface(props)) | |
} | |
export const types = { | |
string: t.string, | |
boolean: t.boolean, | |
number: t.number, | |
Integer: t.Integer, | |
ref, | |
entity | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {types} from "./data" | |
const User = types.entity({ | |
id: types.number, | |
name: types.ref(types.string) | |
}) | |
// vorrei che questo | |
const program = User.decode({ | |
id: 1, | |
name: "World" | |
}).map( | |
john => john.name.write("John Smith") // => TaskEither<WriteError, void> | |
.map((l) => { | |
console.log("New name is", john.name.read()) // => void | |
return l | |
}) | |
) | |
// diventasse questo | |
new Scope() | |
.let("john", () => User.decode({ | |
id: 1, | |
name: "World" | |
})) | |
.do(s => s.john.name.write("John Smith")) | |
.do(s => console.log("New name is", john.name.read())) | |
.return(s => s.john) // TaskEither<ValidationError | WriteError, t.TypeOf<typeof john>> | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment