@effect/sql-mssql 4.0.0-beta.7 → 4.0.0-beta.71

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,43 @@
1
1
  /**
2
- * @since 1.0.0
2
+ * Microsoft SQL Server client implementation for Effect SQL, backed by the
3
+ * `tedious` driver.
4
+ *
5
+ * This module provides the `MssqlClient` service, constructors, layers, and SQL
6
+ * Server statement compiler. The layers provide both `MssqlClient` and the
7
+ * generic `SqlClient` service, so code written against Effect SQL can run
8
+ * regular queries while SQL Server-specific code can add typed Tedious
9
+ * parameters with `param` and execute stored procedures with `call`.
10
+ *
11
+ * **Mental model**
12
+ *
13
+ * A client owns a scoped pool of Tedious connections and validates startup with
14
+ * `SELECT 1`. Ordinary queries borrow a pooled connection for one operation.
15
+ * Transactions keep one connection for their lifetime, and nested transactions
16
+ * are represented with SQL Server savepoints. Long-running transactions
17
+ * therefore reduce available pool capacity.
18
+ *
19
+ * **Common tasks**
20
+ *
21
+ * Use {@link layer} for a concrete `MssqlClientConfig`, {@link layerConfig} when
22
+ * configuration should come from Effect `Config`, and {@link make} when a scoped
23
+ * client value is needed directly. Use `param` to override the default mapping
24
+ * from Effect SQL primitive values to Tedious `DataType`s, and use the
25
+ * `Procedure` and `Parameter` helpers when a stored procedure needs typed input
26
+ * parameters, output parameters, or result rows.
27
+ *
28
+ * **Gotchas**
29
+ *
30
+ * Tedious permits one active request per connection, and this client does not
31
+ * implement streaming queries. Statements compile to SQL Server-style `@1`
32
+ * parameters and bracket-escaped identifiers. Be explicit about connection pool
33
+ * and timeout settings for workloads with transactions. Review TLS settings:
34
+ * `encrypt` defaults to `false`, and `trustServer` defaults to `true` for the
35
+ * Tedious `trustServerCertificate` option unless overridden.
36
+ *
37
+ * @since 4.0.0
3
38
  */
4
39
  import * as Config from "effect/Config"
40
+ import * as Context from "effect/Context"
5
41
  import * as Duration from "effect/Duration"
6
42
  import * as Effect from "effect/Effect"
7
43
  import { identity } from "effect/Function"
@@ -9,12 +45,23 @@ import * as Layer from "effect/Layer"
9
45
  import * as Pool from "effect/Pool"
10
46
  import * as Redacted from "effect/Redacted"
11
47
  import * as Scope from "effect/Scope"
12
- import * as ServiceMap from "effect/ServiceMap"
13
48
  import * as Stream from "effect/Stream"
14
49
  import * as Reactivity from "effect/unstable/reactivity/Reactivity"
15
50
  import * as Client from "effect/unstable/sql/SqlClient"
16
51
  import type { Connection } from "effect/unstable/sql/SqlConnection"
17
- import { SqlError } from "effect/unstable/sql/SqlError"
52
+ import {
53
+ AuthenticationError,
54
+ AuthorizationError,
55
+ ConnectionError,
56
+ ConstraintError,
57
+ DeadlockError,
58
+ LockTimeoutError,
59
+ SerializationError,
60
+ SqlError,
61
+ SqlSyntaxError,
62
+ UniqueViolation,
63
+ UnknownError
64
+ } from "effect/unstable/sql/SqlError"
18
65
  import * as Statement from "effect/unstable/sql/Statement"
19
66
  import * as Tedious from "tedious"
20
67
  import type { ConnectionOptions } from "tedious/lib/connection.ts"
@@ -28,21 +75,116 @@ const ATTR_DB_NAMESPACE = "db.namespace"
28
75
  const ATTR_SERVER_ADDRESS = "server.address"
29
76
  const ATTR_SERVER_PORT = "server.port"
30
77
 
78
+ const mssqlNumberFromCause = (cause: unknown): number | undefined => {
79
+ if (typeof cause !== "object" || cause === null || !("number" in cause)) {
80
+ return undefined
81
+ }
82
+ const number = cause.number
83
+ return typeof number === "number" ? number : undefined
84
+ }
85
+
86
+ const mssqlConnectionErrorCodes = new Set([233, 10054])
87
+ const mssqlAuthenticationErrorCodes = new Set([4060, 18452, 18456])
88
+ const mssqlAuthorizationErrorCodes = new Set([229, 230, 262, 297, 300])
89
+ const mssqlSyntaxErrorCodes = new Set([102, 207, 208, 2714])
90
+ const mssqlConstraintErrorCodes = new Set([515, 547])
91
+
92
+ const UNKNOWN_CONSTRAINT = "unknown"
93
+
94
+ const normalizeConstraintIdentifier = (identifier: unknown): string => {
95
+ if (typeof identifier !== "string") {
96
+ return UNKNOWN_CONSTRAINT
97
+ }
98
+ const trimmed = identifier.trim()
99
+ return trimmed.length === 0 ? UNKNOWN_CONSTRAINT : trimmed
100
+ }
101
+
102
+ const mssqlCauseProperty = (cause: unknown, property: "constraint" | "message"): unknown => {
103
+ if (typeof cause !== "object" || cause === null || !(property in cause)) {
104
+ return undefined
105
+ }
106
+ return (cause as Record<string, unknown>)[property]
107
+ }
108
+
109
+ const mssqlUniqueViolationConstraintFromMessage = (number: 2601 | 2627, message: unknown): string => {
110
+ if (typeof message !== "string") {
111
+ return UNKNOWN_CONSTRAINT
112
+ }
113
+ const match = number === 2627 ?
114
+ /\bconstraint\s+'([^']*)'/i.exec(message) :
115
+ /\bunique index\s+'([^']*)'/i.exec(message)
116
+ return match === null ? UNKNOWN_CONSTRAINT : normalizeConstraintIdentifier(match[1])
117
+ }
118
+
119
+ const mssqlUniqueViolationConstraintFromCause = (number: 2601 | 2627, cause: unknown): string => {
120
+ const constraint = normalizeConstraintIdentifier(mssqlCauseProperty(cause, "constraint"))
121
+ if (constraint !== UNKNOWN_CONSTRAINT) {
122
+ return constraint
123
+ }
124
+ return mssqlUniqueViolationConstraintFromMessage(number, mssqlCauseProperty(cause, "message"))
125
+ }
126
+
127
+ const classifyError = (
128
+ cause: unknown,
129
+ message: string,
130
+ operation: string,
131
+ fallback: "connection" | "unknown" = "unknown"
132
+ ) => {
133
+ const props = { cause, message, operation }
134
+ const number = mssqlNumberFromCause(cause)
135
+ if (number !== undefined) {
136
+ if (mssqlConnectionErrorCodes.has(number)) {
137
+ return new ConnectionError(props)
138
+ }
139
+ if (mssqlAuthenticationErrorCodes.has(number)) {
140
+ return new AuthenticationError(props)
141
+ }
142
+ if (mssqlAuthorizationErrorCodes.has(number)) {
143
+ return new AuthorizationError(props)
144
+ }
145
+ if (mssqlSyntaxErrorCodes.has(number)) {
146
+ return new SqlSyntaxError(props)
147
+ }
148
+ if (number === 2601 || number === 2627) {
149
+ return new UniqueViolation({ ...props, constraint: mssqlUniqueViolationConstraintFromCause(number, cause) })
150
+ }
151
+ if (mssqlConstraintErrorCodes.has(number)) {
152
+ return new ConstraintError(props)
153
+ }
154
+ if (number === 1205) {
155
+ return new DeadlockError(props)
156
+ }
157
+ if (number === 3960) {
158
+ return new SerializationError(props)
159
+ }
160
+ if (number === 1222) {
161
+ return new LockTimeoutError(props)
162
+ }
163
+ }
164
+ return fallback === "connection" ? new ConnectionError(props) : new UnknownError(props)
165
+ }
166
+
31
167
  /**
32
- * @category type ids
33
- * @since 1.0.0
168
+ * Runtime type identifier used to mark `MssqlClient` values.
169
+ *
170
+ * @category type IDs
171
+ * @since 4.0.0
34
172
  */
35
173
  export const TypeId: unique symbol = Symbol.for("@effect/sql-mssql/MssqlClient")
36
174
 
37
175
  /**
38
- * @category type ids
39
- * @since 1.0.0
176
+ * Type-level identifier used to mark `MssqlClient` values.
177
+ *
178
+ * @category type IDs
179
+ * @since 4.0.0
40
180
  */
41
181
  export type TypeId = typeof TypeId
42
182
 
43
183
  /**
184
+ * Microsoft SQL Server client service, extending `SqlClient` with typed parameter fragments and stored procedure calls.
185
+ *
44
186
  * @category models
45
- * @since 1.0.0
187
+ * @since 4.0.0
46
188
  */
47
189
  export interface MssqlClient extends Client.SqlClient {
48
190
  readonly [TypeId]: TypeId
@@ -65,14 +207,18 @@ export interface MssqlClient extends Client.SqlClient {
65
207
  }
66
208
 
67
209
  /**
210
+ * Context tag used to access the `MssqlClient` service.
211
+ *
68
212
  * @category tags
69
- * @since 1.0.0
213
+ * @since 4.0.0
70
214
  */
71
- export const MssqlClient = ServiceMap.Service<MssqlClient>("@effect/sql-mssql/MssqlClient")
215
+ export const MssqlClient = Context.Service<MssqlClient>("@effect/sql-mssql/MssqlClient")
72
216
 
73
217
  /**
218
+ * Configuration for a Microsoft SQL Server client, including connection, authentication, pool, parameter type, span attribute, and query/result name transform options.
219
+ *
74
220
  * @category models
75
- * @since 1.0.0
221
+ * @since 4.0.0
76
222
  */
77
223
  export interface MssqlClientConfig {
78
224
  readonly domain?: string | undefined
@@ -111,14 +257,18 @@ interface MssqlConnection extends Connection {
111
257
  readonly rollback: (name?: string) => Effect.Effect<void, SqlError>
112
258
  }
113
259
 
114
- const TransactionConnection = Client.TransactionConnection as unknown as ServiceMap.Service<
260
+ const TransactionConnection = Client.TransactionConnection as unknown as (clientId: number) => Context.Service<
115
261
  readonly [conn: MssqlConnection, counter: number],
116
262
  readonly [conn: MssqlConnection, counter: number]
117
263
  >
118
264
 
265
+ let clientIdCounter = 0
266
+
119
267
  /**
268
+ * Creates a scoped Microsoft SQL Server client backed by a connection pool, with transaction and stored procedure support. Streaming queries are not implemented.
269
+ *
120
270
  * @category constructors
121
- * @since 1.0.0
271
+ * @since 4.0.0
122
272
  */
123
273
  export const make = (
124
274
  options: MssqlClientConfig
@@ -174,7 +324,9 @@ export const make = (
174
324
  yield* Effect.callback<void, SqlError>((resume) => {
175
325
  conn.connect((cause) => {
176
326
  if (cause) {
177
- resume(Effect.fail(new SqlError({ cause, message: "Failed to connect" })))
327
+ resume(
328
+ Effect.fail(new SqlError({ reason: classifyError(cause, "Failed to connect", "connect", "connection") }))
329
+ )
178
330
  } else {
179
331
  resume(Effect.void)
180
332
  }
@@ -189,7 +341,9 @@ export const make = (
189
341
  Effect.callback<any, SqlError>((resume) => {
190
342
  const req = new Tedious.Request(sql, (cause, _rowCount, result) => {
191
343
  if (cause) {
192
- resume(Effect.fail(new SqlError({ cause, message: "Failed to execute statement" })))
344
+ resume(
345
+ Effect.fail(new SqlError({ reason: classifyError(cause, "Failed to execute statement", "execute") }))
346
+ )
193
347
  return
194
348
  }
195
349
 
@@ -232,7 +386,9 @@ export const make = (
232
386
  escape(procedure.name),
233
387
  (cause, _, rows) => {
234
388
  if (cause) {
235
- resume(Effect.fail(new SqlError({ cause, message: "Failed to execute statement" })))
389
+ resume(
390
+ Effect.fail(new SqlError({ reason: classifyError(cause, "Failed to execute statement", "execute") }))
391
+ )
236
392
  } else {
237
393
  rows = rowsToObjects(rows)
238
394
  if (transformRows) {
@@ -291,7 +447,13 @@ export const make = (
291
447
  begin: Effect.callback<void, SqlError>((resume) => {
292
448
  conn.beginTransaction((cause) => {
293
449
  if (cause) {
294
- resume(Effect.fail(new SqlError({ cause, message: "Failed to begin transaction" })))
450
+ resume(
451
+ Effect.fail(
452
+ new SqlError({
453
+ reason: classifyError(cause, "Failed to begin transaction", "beginTransaction")
454
+ })
455
+ )
456
+ )
295
457
  } else {
296
458
  resume(Effect.void)
297
459
  }
@@ -300,7 +462,13 @@ export const make = (
300
462
  commit: Effect.callback<void, SqlError>((resume) => {
301
463
  conn.commitTransaction((cause) => {
302
464
  if (cause) {
303
- resume(Effect.fail(new SqlError({ cause, message: "Failed to commit transaction" })))
465
+ resume(
466
+ Effect.fail(
467
+ new SqlError({
468
+ reason: classifyError(cause, "Failed to commit transaction", "commitTransaction")
469
+ })
470
+ )
471
+ )
304
472
  } else {
305
473
  resume(Effect.void)
306
474
  }
@@ -310,7 +478,11 @@ export const make = (
310
478
  Effect.callback<void, SqlError>((resume) => {
311
479
  conn.saveTransaction((cause) => {
312
480
  if (cause) {
313
- resume(Effect.fail(new SqlError({ cause, message: "Failed to create savepoint" })))
481
+ resume(
482
+ Effect.fail(
483
+ new SqlError({ reason: classifyError(cause, "Failed to create savepoint", "createSavepoint") })
484
+ )
485
+ )
314
486
  } else {
315
487
  resume(Effect.void)
316
488
  }
@@ -320,7 +492,13 @@ export const make = (
320
492
  Effect.callback<void, SqlError>((resume) => {
321
493
  conn.rollbackTransaction((cause) => {
322
494
  if (cause) {
323
- resume(Effect.fail(new SqlError({ cause, message: "Failed to rollback transaction" })))
495
+ resume(
496
+ Effect.fail(
497
+ new SqlError({
498
+ reason: classifyError(cause, "Failed to rollback transaction", "rollbackTransaction")
499
+ })
500
+ )
501
+ )
324
502
  } else {
325
503
  resume(Effect.void)
326
504
  }
@@ -349,22 +527,29 @@ export const make = (
349
527
 
350
528
  yield* Pool.get(pool).pipe(
351
529
  Effect.tap((connection) => connection.executeUnprepared("SELECT 1", [], undefined)),
352
- Effect.mapError(({ cause }) => new SqlError({ cause, message: "MssqlClient: Failed to connect" })),
530
+ Effect.mapError((cause) =>
531
+ new SqlError({ reason: classifyError(cause, "MssqlClient: Failed to connect", "connect", "connection") })
532
+ ),
353
533
  Effect.scoped,
354
534
  Effect.timeoutOrElse({
355
535
  duration: options.connectTimeout ?? Duration.seconds(5),
356
- onTimeout: () =>
536
+ orElse: () =>
357
537
  Effect.fail(
358
538
  new SqlError({
359
- message: "MssqlClient: Connection timeout",
360
- cause: new Error("connection timeout")
539
+ reason: new ConnectionError({
540
+ message: "MssqlClient: Connection timeout",
541
+ cause: new Error("connection timeout"),
542
+ operation: "connect"
543
+ })
361
544
  })
362
545
  )
363
546
  })
364
547
  )
365
548
 
549
+ const transactionService = TransactionConnection(clientIdCounter++)
550
+
366
551
  const withTransaction = Client.makeWithTransaction({
367
- transactionService: TransactionConnection,
552
+ transactionService,
368
553
  spanAttributes,
369
554
  acquireConnection: Effect.gen(function*() {
370
555
  const scope = Scope.makeUnsafe()
@@ -382,6 +567,7 @@ export const make = (
382
567
  yield* Client.make({
383
568
  acquirer: Pool.get(pool),
384
569
  compiler,
570
+ transactionService: transactionService as any,
385
571
  spanAttributes,
386
572
  transformRows
387
573
  }),
@@ -426,42 +612,48 @@ export const make = (
426
612
  })
427
613
 
428
614
  /**
615
+ * Creates a layer from a `Config`-wrapped SQL Server client configuration, providing both `MssqlClient` and `SqlClient`.
616
+ *
429
617
  * @category layers
430
- * @since 1.0.0
618
+ * @since 4.0.0
431
619
  */
432
620
  export const layerConfig: (
433
621
  config: Config.Wrap<MssqlClientConfig>
434
622
  ) => Layer.Layer<Client.SqlClient | MssqlClient, Config.ConfigError | SqlError> = (
435
623
  config: Config.Wrap<MssqlClientConfig>
436
624
  ): Layer.Layer<Client.SqlClient | MssqlClient, Config.ConfigError | SqlError> =>
437
- Layer.effectServices(
438
- Config.unwrap(config).asEffect().pipe(
625
+ Layer.effectContext(
626
+ Config.unwrap(config).pipe(
439
627
  Effect.flatMap(make),
440
628
  Effect.map((client) =>
441
- ServiceMap.make(MssqlClient, client).pipe(
442
- ServiceMap.add(Client.SqlClient, client)
629
+ Context.make(MssqlClient, client).pipe(
630
+ Context.add(Client.SqlClient, client)
443
631
  )
444
632
  )
445
633
  )
446
634
  ).pipe(Layer.provide(Reactivity.layer))
447
635
 
448
636
  /**
637
+ * Creates a layer from a concrete SQL Server client configuration, providing both `MssqlClient` and `SqlClient`.
638
+ *
449
639
  * @category layers
450
- * @since 1.0.0
640
+ * @since 4.0.0
451
641
  */
452
642
  export const layer = (
453
643
  config: MssqlClientConfig
454
644
  ): Layer.Layer<Client.SqlClient | MssqlClient, never | SqlError> =>
455
- Layer.effectServices(
645
+ Layer.effectContext(
456
646
  Effect.map(make(config), (client) =>
457
- ServiceMap.make(MssqlClient, client).pipe(
458
- ServiceMap.add(Client.SqlClient, client)
647
+ Context.make(MssqlClient, client).pipe(
648
+ Context.add(Client.SqlClient, client)
459
649
  ))
460
650
  ).pipe(Layer.provide(Reactivity.layer))
461
651
 
462
652
  /**
653
+ * Creates the SQL Server statement compiler, using `@1`-style placeholders, bracket-escaped identifiers, and SQL Server `OUTPUT INSERTED` returning clauses.
654
+ *
463
655
  * @category compiler
464
- * @since 1.0.0
656
+ * @since 4.0.0
465
657
  */
466
658
  export const makeCompiler = (transform?: (_: string) => string) =>
467
659
  Statement.makeCompiler<MssqlCustom>({
@@ -510,7 +702,10 @@ function numberToParamName(n: number) {
510
702
  }
511
703
 
512
704
  /**
513
- * @since 1.0.0
705
+ * Default mapping from Effect SQL primitive value kinds to Tedious SQL Server parameter data types.
706
+ *
707
+ * @category configuration
708
+ * @since 4.0.0
514
709
  */
515
710
  export const defaultParameterTypes: Record<Statement.PrimitiveKind, DataType> = {
516
711
  string: Tedious.TYPES.VarChar,
@@ -1,5 +1,26 @@
1
1
  /**
2
- * @since 1.0.0
2
+ * Utilities for applying Effect SQL migrations to Microsoft SQL Server.
3
+ *
4
+ * This module re-exports the shared `Migrator` loaders and error types, then
5
+ * provides `run` and `layer` helpers for applying ordered migrations through
6
+ * the current SQL Server `SqlClient`. It is typically used at application
7
+ * startup, during deployment, in integration tests that provision temporary SQL
8
+ * Server databases, or in layer graphs that need the database schema to be
9
+ * current before dependent services are acquired.
10
+ *
11
+ * Applied migrations are stored in `effect_sql_migrations` by default and use
12
+ * the shared `<id>_<name>` loader convention. Only migrations with ids greater
13
+ * than the latest recorded id are run, so avoid inserting older migration ids
14
+ * after a later migration has reached production. SQL Server migrations run
15
+ * inside the shared migrator transaction and this adapter does not add a
16
+ * dialect-specific table lock, so coordinate concurrent startup runners and
17
+ * write T-SQL that is valid inside an explicit transaction. Remember that `GO`
18
+ * is a client-side batch separator rather than a T-SQL statement, and split
19
+ * migrations when SQL Server requires an object definition such as `CREATE
20
+ * VIEW`, `CREATE PROCEDURE`, or `CREATE TRIGGER` to start its own batch. This
21
+ * adapter also does not emit SQL Server schema dumps for `schemaDirectory`.
22
+ *
23
+ * @since 4.0.0
3
24
  */
4
25
  import type * as Effect from "effect/Effect"
5
26
  import * as Layer from "effect/Layer"
@@ -8,13 +29,15 @@ import type * as Client from "effect/unstable/sql/SqlClient"
8
29
  import type { SqlError } from "effect/unstable/sql/SqlError"
9
30
 
10
31
  /**
11
- * @since 1.0.0
32
+ * @since 4.0.0
12
33
  */
13
34
  export * from "effect/unstable/sql/Migrator"
14
35
 
15
36
  /**
16
- * @category constructor
17
- * @since 1.0.0
37
+ * Runs SQL migrations using the configured `SqlClient`, returning the migrations that were applied.
38
+ *
39
+ * @category constructors
40
+ * @since 4.0.0
18
41
  */
19
42
  export const run: <R>(
20
43
  options: Migrator.MigratorOptions<R>
@@ -25,8 +48,10 @@ export const run: <R>(
25
48
  > = Migrator.make({})
26
49
 
27
50
  /**
51
+ * Creates a layer that runs the configured SQL migrations during layer construction.
52
+ *
28
53
  * @category layers
29
- * @since 1.0.0
54
+ * @since 4.0.0
30
55
  */
31
56
  export const layer = <R>(
32
57
  options: Migrator.MigratorOptions<R>
package/src/Parameter.ts CHANGED
@@ -1,25 +1,66 @@
1
1
  /**
2
- * @since 1.0.0
2
+ * Typed SQL Server stored procedure parameter metadata.
3
+ *
4
+ * This module builds {@link Parameter} values that pair a stored procedure
5
+ * parameter name with a Tedious `DataType`, Tedious `ParameterOptions`, and a
6
+ * phantom TypeScript value type. `Procedure.param` and
7
+ * `Procedure.outputParam` use this metadata, and `MssqlClient.call` forwards it
8
+ * to Tedious when registering input and output parameters.
9
+ *
10
+ * **Mental model**
11
+ *
12
+ * A `Parameter<A>` describes how Tedious should bind a value; it is not the
13
+ * value itself. The `A` type guides the record accepted by
14
+ * `Procedure.compile`, while Tedious validates and encodes the runtime value
15
+ * when the request is executed.
16
+ *
17
+ * **Common tasks**
18
+ *
19
+ * - Annotate inputs that need explicit SQL Server data types, sizes, precision,
20
+ * scale, or table-valued parameter options.
21
+ * - Define output parameters so `MssqlClient.call` can collect returned values
22
+ * by name.
23
+ * - Reuse the same metadata shape from direct `make` calls and the `Procedure`
24
+ * builders.
25
+ *
26
+ * **Gotchas**
27
+ *
28
+ * Names should match the stored procedure parameter name expected by Tedious,
29
+ * normally without a leading `@`. Table-valued parameter values must use
30
+ * Tedious' table shape with `name`, optional `schema`, `columns`, and `rows`.
31
+ * Output parameters are registered without an initial value, so input-output
32
+ * parameters need explicit modeling instead of assuming compiled input values
33
+ * are reused.
34
+ *
35
+ * @see {@link make} for constructing parameter metadata directly.
36
+ *
37
+ * @since 4.0.0
3
38
  */
4
39
  import { identity } from "effect/Function"
5
40
  import type { DataType } from "tedious/lib/data-type.ts"
6
41
  import type { ParameterOptions } from "tedious/lib/request.ts"
7
42
 
8
43
  /**
44
+ * Runtime type identifier used to mark SQL Server stored procedure parameter metadata.
45
+ *
9
46
  * @category type id
10
- * @since 1.0.0
47
+ * @since 4.0.0
11
48
  */
12
49
  export const TypeId: TypeId = "~@effect/sql-mssql/Parameter"
13
50
 
14
51
  /**
52
+ * Type-level identifier used to mark SQL Server stored procedure parameter metadata.
53
+ *
15
54
  * @category type id
16
- * @since 1.0.0
55
+ * @since 4.0.0
17
56
  */
18
57
  export type TypeId = "~@effect/sql-mssql/Parameter"
19
58
 
20
59
  /**
21
- * @category model
22
- * @since 1.0.0
60
+ * Metadata for a SQL Server stored procedure parameter, including its name, Tedious data type, options, and phantom value type.
61
+ *
62
+ * @category models
63
+ * @since 4.0.0
23
64
  */
24
65
  export interface Parameter<out A> {
25
66
  readonly [TypeId]: (_: never) => A
@@ -30,8 +71,10 @@ export interface Parameter<out A> {
30
71
  }
31
72
 
32
73
  /**
33
- * @category constructor
34
- * @since 1.0.0
74
+ * Creates typed metadata for a SQL Server stored procedure parameter.
75
+ *
76
+ * @category constructors
77
+ * @since 4.0.0
35
78
  */
36
79
  export const make = <A>(
37
80
  name: string,