1/**
2 * Typed metadata builders for Microsoft SQL Server stored procedure calls.
3 *
4 * This module defines the `Procedure` values consumed by `MssqlClient.call`.
5 * `make` starts a procedure definition, `param` and `outputParam` add typed
6 * Tedious parameter metadata, `withRows` sets the expected row type, and
7 * `compile` binds input values before execution. The module also defines the
8 * typed result shape for output parameters and returned rows.
9 *
10 * @stability unstable
11 * @since 4.0.0
12 */
13import { identity } from "effect/Function"
14import type { Pipeable } from "effect/Pipeable"
15import { pipeArguments } from "effect/Pipeable"
16import type { Row } from "effect/sql/SqlConnection"
17import type { Covariant } from "effect/Types"
18import type { DataType } from "tedious/lib/data-type.ts"
19import type { ParameterOptions } from "tedious/lib/request.ts"
20import * as Parameter from "./Parameter.ts"
21
22/**
23 * Runtime type identifier used to mark SQL Server stored procedure definitions.
24 *
25 * @stability unstable
26 * @category type IDs
27 * @since 4.0.0
28 */
29export const TypeId: TypeId = "~@effect/sql-mssql/Procedure"
30
31/**
32 * Type-level identifier used to mark SQL Server stored procedure definitions.
33 *
34 * @stability unstable
35 * @category type IDs
36 * @since 4.0.0
37 */
38export type TypeId = "~@effect/sql-mssql/Procedure"
39
40/**
41 * Pipeable definition of a SQL Server stored procedure, tracking its input parameters, output parameters, and result row type.
42 *
43 * @stability unstable
44 * @category models
45 * @since 4.0.0
46 */
47export interface Procedure<
48 I extends Record<string, Parameter.Parameter<any>>,
49 O extends Record<string, Parameter.Parameter<any>>,
50 A = never
51> extends Pipeable {
52 readonly [TypeId]: {
53 readonly _A: Covariant<A>
54 }
55 readonly _tag: "Procedure"
56 readonly name: string
57 readonly params: I
58 readonly outputParams: O
59}
60
61/**
62 * Stored procedure definition with concrete input values bound for execution.
63 *
64 * @stability unstable
65 * @category models
66 * @since 4.0.0
67 */
68export interface ProcedureWithValues<
69 I extends Record<string, Parameter.Parameter<any>>,
70 O extends Record<string, Parameter.Parameter<any>>,
71 A
72> extends Procedure<I, O, A> {
73 readonly values: Procedure.ParametersRecord<I>
74}
75
76/**
77 * Namespace containing type helpers and result types for SQL Server stored procedures.
78 *
79 * @stability unstable
80 * @since 4.0.0
81 */
82export declare namespace Procedure {
83 /**
84 * Maps a record of `Parameter` metadata to the corresponding record of parameter value types.
85 *
86 * @stability unstable
87 * @category utility types
88 * @since 4.0.0
89 */
90 export type ParametersRecord<
91 A extends Record<string, Parameter.Parameter<any>>
92 > =
93 & {
94 readonly [K in keyof A]: A[K] extends Parameter.Parameter<infer T> ? T
95 : never
96 }
97 & {}
98
99 /**
100 * Result of a SQL Server stored procedure call, containing typed output parameter values and returned rows.
101 *
102 * @stability unstable
103 * @category models
104 * @since 4.0.0
105 */
106 export interface Result<
107 O extends Record<string, Parameter.Parameter<any>>,
108 A
109 > {
110 readonly output: ParametersRecord<O>
111 readonly rows: ReadonlyArray<A>
112 }
113}
114
115type Simplify<A> = { [K in keyof A]: A[K] } & {}
116
117const procedureProto = {
118 [TypeId]: {
119 _A: identity
120 },
121 _tag: "Procedure",
122 pipe() {
123 return pipeArguments(this, arguments)
124 }
125}
126
127/**
128 * Creates an empty SQL Server stored procedure definition for the given procedure name.
129 *
130 * @stability unstable
131 * @category constructors
132 * @since 4.0.0
133 */
134export const make = (name: string): Procedure<{}, {}> => {
135 const procedure = Object.create(procedureProto)
136 procedure.name = name
137 procedure.params = {}
138 procedure.outputParams = {}
139 return procedure
140}
141
142/**
143 * Adds a typed input parameter to a SQL Server stored procedure definition.
144 *
145 * @stability unstable
146 * @category combinators
147 * @since 4.0.0
148 */
149export const param = <A>() =>
150<N extends string, T extends DataType>(
151 name: N,
152 type: T,
153 options?: ParameterOptions
154) =>
155<
156 I extends Record<string, Parameter.Parameter<any>>,
157 O extends Record<string, Parameter.Parameter<any>>
158>(
159 self: Procedure<I, O>
160): Procedure<Simplify<I & { [K in N]: Parameter.Parameter<A> }>, O> => ({
161 ...self,
162 params: {
163 ...self.params,
164 [name]: Parameter.make(name, type, options)
165 }
166})
167
168/**
169 * Adds a typed output parameter to a SQL Server stored procedure definition.
170 *
171 * @stability unstable
172 * @category combinators
173 * @since 4.0.0
174 */
175export const outputParam = <A>() =>
176<N extends string, T extends DataType>(
177 name: N,
178 type: T,
179 options?: ParameterOptions
180) =>
181<
182 I extends Record<string, Parameter.Parameter<any>>,
183 O extends Record<string, Parameter.Parameter<any>>
184>(
185 self: Procedure<I, O>
186): Procedure<I, Simplify<O & { [K in N]: Parameter.Parameter<A> }>> => ({
187 ...self,
188 outputParams: {
189 ...self.outputParams,
190 [name]: Parameter.make(name, type, options)
191 }
192})
193
194/**
195 * Sets the expected row type for a SQL Server stored procedure definition.
196 *
197 * @stability unstable
198 * @category combinators
199 * @since 4.0.0
200 */
201export const withRows = <A extends object = Row>() =>
202<
203 I extends Record<string, Parameter.Parameter<any>>,
204 O extends Record<string, Parameter.Parameter<any>>
205>(
206 self: Procedure<I, O>
207): Procedure<I, O, A> => self as any
208
209/**
210 * Binds input values to a SQL Server stored procedure definition, producing a value that can be executed with `MssqlClient.call`.
211 *
212 * @stability unstable
213 * @category combinators
214 * @since 4.0.0
215 */
216export const compile = <
217 I extends Record<string, Parameter.Parameter<any>>,
218 O extends Record<string, Parameter.Parameter<any>>,
219 A
220>(
221 self: Procedure<I, O, A>
222) =>
223(input: Procedure.ParametersRecord<I>): ProcedureWithValues<I, O, A> => ({
224 ...self,
225 values: input
226})