1import { assert, describe, it } from "@effect/vitest"
2import { Effect, Exit } from "effect"
3import * as Schema from "effect/Schema"
4import { SqlResolver } from "effect/sql"
5
6describe("SqlResolver", () => {
7 describe("grouped", () => {
8 it.effect("does not execute a batch when every request fails encoding", () =>
9 Effect.gen(function*() {
10 let executions = 0
11 const resolver = SqlResolver.grouped({
12 Request: Schema.Number.check(Schema.isGreaterThan(0)),
13 RequestGroupKey: (request) => request,
14 Result: Schema.Number,
15 ResultGroupKey: (result) => result,
16 execute: (inputs) => {
17 executions++
18 return Effect.succeed(inputs)
19 }
20 })
21
22 const error = yield* Effect.flip(SqlResolver.request(-1, resolver))
23
24 assert.strictEqual(error._tag, "SchemaError")
25 assert.strictEqual(executions, 0)
26 }))
27 })
28
29 describe("findById", () => {
30 it.effect("does not execute a batch when every request fails encoding", () =>
31 Effect.gen(function*() {
32 let executions = 0
33 const resolver = SqlResolver.findById({
34 Id: Schema.Number.check(Schema.isGreaterThan(0)),
35 Result: Schema.Struct({ id: Schema.Number }),
36 ResultId: (result) => result.id,
37 execute: (inputs) => {
38 executions++
39 return Effect.succeed(inputs.map((id) => ({ id })))
40 }
41 })
42
43 const error = yield* Effect.flip(SqlResolver.request(-1, resolver))
44
45 assert.strictEqual(error._tag, "SchemaError")
46 assert.strictEqual(executions, 0)
47 }))
48
49 it.effect("completes duplicate requests when id encoding fails", () =>
50 Effect.gen(function*() {
51 const resolver = SqlResolver.findById({
52 Id: Schema.Number.check(Schema.isGreaterThan(0)),
53 Result: Schema.Struct({ id: Schema.Number }),
54 ResultId: (result) => result.id,
55 execute: (inputs) => Effect.succeed(inputs.map((id) => ({ id })))
56 })
57 const execute = SqlResolver.request(resolver)
58
59 const errors = yield* Effect.all([
60 Effect.flip(execute(-1)),
61 Effect.flip(execute(-1))
62 ], { concurrency: "unbounded" })
63
64 assert.deepStrictEqual(errors.map((error) => error._tag), ["SchemaError", "SchemaError"])
65 }))
66
67 it.effect("deduplicates requests by id", () =>
68 Effect.gen(function*() {
69 const batches: Array<Array<number>> = []
70 const FindById = SqlResolver.findById({
71 Id: Schema.Number,
72 Result: Schema.Struct({ id: Schema.Number, name: Schema.String }),
73 ResultId: (result) => result.id,
74 execute: (ids) => {
75 batches.push([...ids])
76 return Effect.succeed(ids.map((id) => ({ id, name: `name${id}` })))
77 }
78 })
79 const execute = SqlResolver.request(FindById)
80
81 assert.deepStrictEqual(
82 yield* Effect.all({
83 one: execute(1),
84 oneAgain: execute(1),
85 two: execute(2)
86 }, { concurrency: "unbounded" }),
87 {
88 one: { id: 1, name: "name1" },
89 oneAgain: { id: 1, name: "name1" },
90 two: { id: 2, name: "name2" }
91 }
92 )
93 assert.deepStrictEqual(batches, [[1, 2]])
94 }))
95 })
96
97 describe("ordered", () => {
98 it.effect("does not execute a batch when every request fails encoding", () =>
99 Effect.gen(function*() {
100 let executions = 0
101 const resolver = SqlResolver.ordered({
102 Request: Schema.Number.check(Schema.isGreaterThan(0)),
103 Result: Schema.String,
104 execute: (inputs) => {
105 executions++
106 return Effect.succeed(inputs.map(String))
107 }
108 })
109
110 const error = yield* Effect.flip(SqlResolver.request(-1, resolver))
111
112 assert.strictEqual(error._tag, "SchemaError")
113 assert.strictEqual(executions, 0)
114 }))
115
116 it.effect("keeps valid results aligned when another request fails encoding", () =>
117 Effect.gen(function*() {
118 const resolver = SqlResolver.ordered({
119 Request: Schema.Number.check(Schema.isGreaterThan(0)),
120 Result: Schema.String,
121 execute: (inputs) => Effect.succeed(inputs.map((input) => `value-${input}`))
122 })
123 const execute = SqlResolver.request(resolver)
124 const [invalid, valid] = yield* Effect.all([
125 Effect.exit(execute(-1)),
126 Effect.exit(execute(2))
127 ], { concurrency: "unbounded" })
128
129 assert(Exit.isFailure(invalid))
130 assert(Exit.isSuccess(valid))
131 assert.strictEqual(valid.value, "value-2")
132 }))
133 })
134
135 describe("void", () => {
136 it.effect("does not execute a batch when every request fails encoding", () =>
137 Effect.gen(function*() {
138 let executions = 0
139 const resolver = SqlResolver.void({
140 Request: Schema.Number.check(Schema.isGreaterThan(0)),
141 execute: (inputs) => {
142 executions++
143 return Effect.succeed(inputs)
144 }
145 })
146
147 const error = yield* Effect.flip(SqlResolver.request(-1, resolver))
148
149 assert.strictEqual(error._tag, "SchemaError")
150 assert.strictEqual(executions, 0)
151 }))
152 })
153})