1import { assert, describe, it } from "@effect/vitest"
2import * as Cause from "effect/Cause"
3import * as Effect from "effect/Effect"
4import * as Option from "effect/Option"
5import * as Schema from "effect/Schema"
6import * as SqlSchema from "effect/sql/SqlSchema"
7
8describe("SqlSchema", () => {
9 describe("findAll", () => {
10 it.effect("returns decoded results", () =>
11 Effect.gen(function*() {
12 const query = SqlSchema.findAll({
13 Request: Schema.NumberFromString,
14 Result: Schema.Struct({ value: Schema.String }),
15 execute: (request) => Effect.succeed([{ value: `id:${request}` }])
16 })
17
18 const result = yield* query(1)
19 assert.deepStrictEqual(result, [{ value: "id:1" }])
20 }))
21
22 it.effect("returns empty array when no rows", () =>
23 Effect.gen(function*() {
24 const query = SqlSchema.findAll({
25 Request: Schema.String,
26 Result: Schema.String,
27 execute: () => Effect.succeed([])
28 })
29
30 const result = yield* query("test")
31 assert.deepStrictEqual(result, [])
32 }))
33
34 it.effect("fails when a row cannot be decoded", () =>
35 Effect.gen(function*() {
36 const query = SqlSchema.findAll({
37 Request: Schema.String,
38 Result: Schema.Struct({ id: Schema.Number }),
39 execute: () => Effect.succeed([{ id: "not-a-number" }])
40 })
41
42 const error = yield* Effect.flip(query("ignored"))
43 assert.isTrue(Schema.isSchemaError(error))
44 }))
45 })
46
47 describe("findNonEmpty", () => {
48 it.effect("returns non-empty decoded results", () =>
49 Effect.gen(function*() {
50 const query = SqlSchema.findNonEmpty({
51 Request: Schema.NumberFromString,
52 Result: Schema.Struct({ value: Schema.String }),
53 execute: (request) => Effect.succeed([{ value: `id:${request}` }])
54 })
55
56 const result = yield* query(1)
57 assert.deepStrictEqual(result, [{ value: "id:1" }])
58 }))
59
60 it.effect("fails with NoSuchElementError when no rows", () =>
61 Effect.gen(function*() {
62 const query = SqlSchema.findNonEmpty({
63 Request: Schema.String,
64 Result: Schema.String,
65 execute: () => Effect.succeed([])
66 })
67
68 const error = yield* Effect.flip(query("test"))
69 assert.isTrue(Cause.isNoSuchElementError(error))
70 }))
71 })
72
73 describe("void", () => {
74 it.effect("encodes request and discards result", () =>
75 Effect.gen(function*() {
76 let captured: string | undefined
77 const query = SqlSchema.void({
78 Request: Schema.NumberFromString,
79 execute: (request) => {
80 captured = request
81 return Effect.succeed(undefined)
82 }
83 })
84
85 yield* query(42)
86 assert.strictEqual(captured, "42")
87 }))
88 })
89
90 describe("findOne", () => {
91 it.effect("returns the first decoded row", () =>
92 Effect.gen(function*() {
93 const query = SqlSchema.findOne({
94 Request: Schema.String,
95 Result: Schema.NumberFromString,
96 execute: () => Effect.succeed(["1", "2"])
97 })
98
99 const result = yield* query("ignored")
100 assert.strictEqual(result, 1)
101 }))
102
103 it.effect("fails with NoSuchElementError when no rows are returned", () =>
104 Effect.gen(function*() {
105 const query = SqlSchema.findOne({
106 Request: Schema.String,
107 Result: Schema.String,
108 execute: () => Effect.succeed([])
109 })
110
111 const error = yield* Effect.flip(query("ignored"))
112 assert.isTrue(Cause.isNoSuchElementError(error))
113 }))
114
115 it.effect("fails when the first row cannot be decoded", () =>
116 Effect.gen(function*() {
117 const query = SqlSchema.findOne({
118 Request: Schema.String,
119 Result: Schema.Struct({ id: Schema.Number }),
120 execute: () => Effect.succeed([{ id: "not-a-number" }])
121 })
122
123 const error = yield* Effect.flip(query("ignored"))
124 assert.isTrue(Schema.isSchemaError(error))
125 }))
126 })
127
128 describe("findOneOption", () => {
129 it.effect("returns Option.some when a row exists", () =>
130 Effect.gen(function*() {
131 const query = SqlSchema.findOneOption({
132 Request: Schema.NumberFromString,
133 Result: Schema.Struct({ value: Schema.String }),
134 execute: (request) => Effect.succeed([{ value: `id:${request}` }])
135 })
136
137 const result = yield* query(1)
138 assert.isTrue(Option.isSome(result))
139 if (Option.isSome(result)) {
140 assert.deepStrictEqual(result.value, { value: "id:1" })
141 }
142 }))
143
144 it.effect("returns Option.none when no rows are returned", () =>
145 Effect.gen(function*() {
146 const query = SqlSchema.findOneOption({
147 Request: Schema.NumberFromString,
148 Result: Schema.String,
149 execute: () => Effect.succeed([])
150 })
151
152 const result = yield* query(1)
153 assert.isTrue(Option.isNone(result))
154 }))
155
156 it.effect("fails when the first row cannot be decoded", () =>
157 Effect.gen(function*() {
158 const query = SqlSchema.findOneOption({
159 Request: Schema.String,
160 Result: Schema.Struct({ id: Schema.Number }),
161 execute: () => Effect.succeed([{ id: "not-a-number" }])
162 })
163
164 const error = yield* Effect.flip(query("ignored"))
165 assert.isTrue(Schema.isSchemaError(error))
166 }))
167 })
168})