Effect-tsのLSPプラグインがあるみたいなので、それを試してみる
参考
Layerからグラフの生成
依存関係なし
domain_liveのような変数にカーソルを合わせると
グラフを表示できる機能が追加されるようだ
※Vueなどのプロジェクトでは競合する何かがあるのか、うまく動かなかった
ソースコード
import { Duration, Effect, Layer } from "effect"
type type_employee_id = string
type type_department_id = string
// ---- employee ----
interface interface_employee {
employee_id: type_employee_id
employee_name: string
department_id: type_department_id
}
class database_employee_service extends Effect.Service<database_employee_service>()("database_employee_service", {
succeed: ({
get_one_employee: (employee_id: type_employee_id) =>
Effect.gen(function*() {
console.log("get_one_employee start")
yield* Effect.sleep(Duration.seconds(5))
const data: interface_employee = {
employee_id,
employee_name: "test employee",
department_id: test_department_id
}
console.log("get_one_employee end")
return data
})
})
}) {}
// ---- department ----
interface interface_department {
department_id: type_department_id
department_name: string
}
class database_department_service extends Effect.Service<database_department_service>()("database_department_service", {
succeed: ({
get_one_department: (department_id: type_department_id) =>
Effect.gen(function*() {
console.log("get_one_department start")
yield* Effect.sleep(Duration.seconds(3))
const data: interface_department = {
department_id,
department_name: "test department"
}
console.log("get_one_department end")
return data
})
})
}) {}
// ---- test data ----
const test_employee_id: type_employee_id = "e_00_test"
const test_department_id: type_department_id = "d_00_test"
// ---- service ----------------
const get_data_from_2db = Effect.gen(function*() {
const DatabaseEmployee = yield* database_employee_service
const result_employee = yield* DatabaseEmployee.get_one_employee(test_employee_id)
console.log(result_employee)
const DatabaseDepartment = yield* database_department_service
const result_department = yield* DatabaseDepartment.get_one_department(result_employee.department_id)
console.log(result_department)
})
const service_live = Layer.mergeAll(database_employee_service.Default, database_department_service.Default)
const program_2db = get_data_from_2db.pipe(
Effect.provide(service_live)
)
// ---- layer -----------------
interface employee_data {
employee: interface_employee
department: interface_department
}
class domain_employee_service extends Effect.Service<domain_employee_service>()("domain_employee_service", {
effect: Effect.gen(function*() {
const DatabaseEmployee = yield* database_employee_service
const DatabaseDepartment = yield* database_department_service
return {
get_one_employee_data: (
employee_id: type_employee_id
) =>
Effect.gen(function*() {
const employee = yield* DatabaseEmployee.get_one_employee(employee_id)
const department = yield* DatabaseDepartment.get_one_department(employee.department_id)
const result: employee_data = {
employee,
department
}
return result
})
}
}),
dependencies: [service_live]
}) {}
const get_data_from_domain = Effect.gen(function*() {
const DomainEmployee = yield* domain_employee_service
const result_employee = yield* DomainEmployee.get_one_employee_data(test_employee_id)
console.log(result_employee)
})
const domain_live = Layer.mergeAll(
domain_employee_service.Default
)
const program_domain = Effect.provide(get_data_from_domain, domain_live)
// ---- Entry Point ----
Effect.runPromise(program_domain)
動作結果
get_one_employee start
get_one_employee end
get_one_department start
get_one_department end
{
employee: {
employee_id: 'e_00_test',
employee_name: 'test employee',
department_id: 'd_00_test'
},
department: { department_id: 'd_00_test', department_name: 'test department' }
}
依存関係が存在あり
Layerの作り方が不十分だと以下のように下位のLayerが表示されてしまう
import { Context, Duration, Effect, Layer } from "effect"
type type_employee_id = string
type type_department_id = string
// ---- employee ----
interface interface_employee {
employee_id: type_employee_id
employee_name: string
department_id: type_department_id
}
class database_employee extends Context.Tag("database_employee")<
database_employee,
{
readonly get_one_employee: (
employee_id: type_employee_id
) => Effect.Effect<interface_employee>
}
>() {}
const DatabaseServiceEmployee = database_employee.of({
get_one_employee: (employee_id) =>
Effect.gen(function*() {
console.log("get_one_employee start")
yield* Effect.sleep(Duration.seconds(5))
const data: interface_employee = {
employee_id,
employee_name: "test employee",
department_id: test_department_id
}
console.log("get_one_employee end")
return data
})
})
const DatabaseLayerEmployee = Layer.succeed(
database_employee,
{
get_one_employee: (employee_id) =>
Effect.gen(function*() {
console.log("get_one_employee start")
yield* Effect.sleep(Duration.seconds(5))
const data: interface_employee = {
employee_id,
employee_name: "test employee",
department_id: test_department_id
}
console.log("get_one_employee end")
return data
})
}
)
// ---- department ----
interface interface_department {
department_id: type_department_id
department_name: string
}
class database_department extends Context.Tag("database_department")<
database_department,
{
readonly get_one_department: (
department_id: type_department_id
) => Effect.Effect<interface_department>
}
>() {}
const DatabaseServiceDepartment = database_department.of({
get_one_department: (department_id) =>
Effect.gen(function*() {
console.log("get_one_department start")
yield* Effect.sleep(Duration.seconds(3))
const data: interface_department = {
department_id,
department_name: "test department"
}
console.log("get_one_department end")
return data
})
})
const DatabaseLayerDepartment = Layer.succeed(
database_department,
{
get_one_department: (department_id) =>
Effect.gen(function*() {
console.log("get_one_department start")
yield* Effect.sleep(Duration.seconds(3))
const data: interface_department = {
department_id,
department_name: "test department"
}
console.log("get_one_department end")
return data
})
}
)
// ---- test data ----
const test_employee_id: type_employee_id = "e_00_test"
const test_department_id: type_department_id = "d_00_test"
// ---- service ----------------
const get_data_from_2db = Effect.gen(function*() {
const DatabaseEmployee = yield* database_employee
const result_employee = yield* DatabaseEmployee.get_one_employee(test_employee_id)
console.log(result_employee)
const DatabaseDepartment = yield* database_department
const result_department = yield* DatabaseDepartment.get_one_department(result_employee.department_id)
console.log(result_department)
})
const program_2db = get_data_from_2db.pipe(
Effect.provideService(database_employee, DatabaseServiceEmployee),
Effect.provideService(database_department, DatabaseServiceDepartment)
)
// ---- layer -----------------
interface employee_data {
employee: interface_employee
department: interface_department
}
class domain_employee extends Context.Tag("domain_employee")<
domain_employee,
{
readonly get_one_employee_data: (
employee_id: type_employee_id
) => Effect.Effect<employee_data>
}
>() {}
const DomainLayerEmployee = Layer.effect(
domain_employee,
Effect.gen(function*() {
const DatabaseEmployee = yield* database_employee
const DatabaseDepartment = yield* database_department
return {
get_one_employee_data: (
employee_id: type_employee_id
) =>
Effect.gen(function*() {
const employee = yield* DatabaseEmployee.get_one_employee(employee_id)
const department = yield* DatabaseDepartment.get_one_department(employee.department_id)
const result: employee_data = {
employee,
department
}
return result
})
}
})
)
const get_data_from_domain = Effect.gen(function*() {
const DomainEmployee = yield* domain_employee
const result_employee = yield* DomainEmployee.get_one_employee_data(test_employee_id)
console.log(result_employee)
})
const DomainLive = DomainLayerEmployee.pipe(
Layer.provide(DatabaseLayerEmployee),
Layer.provide(DatabaseLayerDepartment)
)
const program_domain = Effect.provide(get_data_from_domain, DomainLive)
// ---- Entry Point ----
Effect.runPromise(program_domain)
Layerの変換
Layerの変換を2ステップで実行できる
ステップ1 Layerを配列で並べて変換
以下のようにLayerを配列で並べる
const test = [
database_employee_service.Default,
database_department_service.Default
]
Prepare layers for automatic compositionを選択
以下のように変換される
const test =[database_employee_service.Default,
database_department_service.Default] as any as Layer.Layer<database_department_service | database_employee_service>
ステップ2 再度変換
Compose layers automatically with target output servicesを選択
以下のように変換される
const test =database_department_service.Default.pipe(Layer.merge(database_employee_service.Default))