@effect/sql-mssql 4.0.0-beta.9 → 4.0.0-beta.90
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.
- package/dist/MssqlClient.d.ts +57 -16
- package/dist/MssqlClient.d.ts.map +1 -1
- package/dist/MssqlClient.js +154 -39
- package/dist/MssqlClient.js.map +1 -1
- package/dist/MssqlMigrator.d.ts +17 -5
- package/dist/MssqlMigrator.d.ts.map +1 -1
- package/dist/MssqlMigrator.js +8 -4
- package/dist/MssqlMigrator.js.map +1 -1
- package/dist/Parameter.d.ts +16 -8
- package/dist/Parameter.d.ts.map +1 -1
- package/dist/Parameter.js +19 -5
- package/dist/Parameter.js.map +1 -1
- package/dist/Procedure.d.ts +47 -22
- package/dist/Procedure.d.ts.map +1 -1
- package/dist/Procedure.js +33 -13
- package/dist/Procedure.js.map +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.js +6 -6
- package/package.json +4 -4
- package/src/MssqlClient.ts +229 -38
- package/src/MssqlMigrator.ts +17 -5
- package/src/Parameter.ts +27 -9
- package/src/Procedure.ts +57 -24
- package/src/index.ts +6 -6
package/src/MssqlClient.ts
CHANGED
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
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. `make` creates a pooled Tedious client, checks the
|
|
7
|
+
* connection with `SELECT 1`, maps SQL Server failures to `SqlError`, and
|
|
8
|
+
* supports transactions with savepoints. The SQL Server-specific service adds
|
|
9
|
+
* typed Tedious parameters with `param`, stored procedure calls with `call`,
|
|
10
|
+
* direct or config-backed layers, and default parameter type mappings.
|
|
11
|
+
* Streaming queries are not implemented by this driver.
|
|
12
|
+
*
|
|
13
|
+
* @since 4.0.0
|
|
3
14
|
*/
|
|
4
15
|
import * as Config from "effect/Config"
|
|
16
|
+
import * as Context from "effect/Context"
|
|
5
17
|
import * as Duration from "effect/Duration"
|
|
6
18
|
import * as Effect from "effect/Effect"
|
|
7
19
|
import { identity } from "effect/Function"
|
|
@@ -9,12 +21,23 @@ import * as Layer from "effect/Layer"
|
|
|
9
21
|
import * as Pool from "effect/Pool"
|
|
10
22
|
import * as Redacted from "effect/Redacted"
|
|
11
23
|
import * as Scope from "effect/Scope"
|
|
12
|
-
import * as ServiceMap from "effect/ServiceMap"
|
|
13
24
|
import * as Stream from "effect/Stream"
|
|
14
25
|
import * as Reactivity from "effect/unstable/reactivity/Reactivity"
|
|
15
26
|
import * as Client from "effect/unstable/sql/SqlClient"
|
|
16
27
|
import type { Connection } from "effect/unstable/sql/SqlConnection"
|
|
17
|
-
import {
|
|
28
|
+
import {
|
|
29
|
+
AuthenticationError,
|
|
30
|
+
AuthorizationError,
|
|
31
|
+
ConnectionError,
|
|
32
|
+
ConstraintError,
|
|
33
|
+
DeadlockError,
|
|
34
|
+
LockTimeoutError,
|
|
35
|
+
SerializationError,
|
|
36
|
+
SqlError,
|
|
37
|
+
SqlSyntaxError,
|
|
38
|
+
UniqueViolation,
|
|
39
|
+
UnknownError
|
|
40
|
+
} from "effect/unstable/sql/SqlError"
|
|
18
41
|
import * as Statement from "effect/unstable/sql/Statement"
|
|
19
42
|
import * as Tedious from "tedious"
|
|
20
43
|
import type { ConnectionOptions } from "tedious/lib/connection.ts"
|
|
@@ -28,21 +51,116 @@ const ATTR_DB_NAMESPACE = "db.namespace"
|
|
|
28
51
|
const ATTR_SERVER_ADDRESS = "server.address"
|
|
29
52
|
const ATTR_SERVER_PORT = "server.port"
|
|
30
53
|
|
|
54
|
+
const mssqlNumberFromCause = (cause: unknown): number | undefined => {
|
|
55
|
+
if (typeof cause !== "object" || cause === null || !("number" in cause)) {
|
|
56
|
+
return undefined
|
|
57
|
+
}
|
|
58
|
+
const number = cause.number
|
|
59
|
+
return typeof number === "number" ? number : undefined
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const mssqlConnectionErrorCodes = new Set([233, 10054])
|
|
63
|
+
const mssqlAuthenticationErrorCodes = new Set([4060, 18452, 18456])
|
|
64
|
+
const mssqlAuthorizationErrorCodes = new Set([229, 230, 262, 297, 300])
|
|
65
|
+
const mssqlSyntaxErrorCodes = new Set([102, 207, 208, 2714])
|
|
66
|
+
const mssqlConstraintErrorCodes = new Set([515, 547])
|
|
67
|
+
|
|
68
|
+
const UNKNOWN_CONSTRAINT = "unknown"
|
|
69
|
+
|
|
70
|
+
const normalizeConstraintIdentifier = (identifier: unknown): string => {
|
|
71
|
+
if (typeof identifier !== "string") {
|
|
72
|
+
return UNKNOWN_CONSTRAINT
|
|
73
|
+
}
|
|
74
|
+
const trimmed = identifier.trim()
|
|
75
|
+
return trimmed.length === 0 ? UNKNOWN_CONSTRAINT : trimmed
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const mssqlCauseProperty = (cause: unknown, property: "constraint" | "message"): unknown => {
|
|
79
|
+
if (typeof cause !== "object" || cause === null || !(property in cause)) {
|
|
80
|
+
return undefined
|
|
81
|
+
}
|
|
82
|
+
return (cause as Record<string, unknown>)[property]
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const mssqlUniqueViolationConstraintFromMessage = (number: 2601 | 2627, message: unknown): string => {
|
|
86
|
+
if (typeof message !== "string") {
|
|
87
|
+
return UNKNOWN_CONSTRAINT
|
|
88
|
+
}
|
|
89
|
+
const match = number === 2627 ?
|
|
90
|
+
/\bconstraint\s+'([^']*)'/i.exec(message) :
|
|
91
|
+
/\bunique index\s+'([^']*)'/i.exec(message)
|
|
92
|
+
return match === null ? UNKNOWN_CONSTRAINT : normalizeConstraintIdentifier(match[1])
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const mssqlUniqueViolationConstraintFromCause = (number: 2601 | 2627, cause: unknown): string => {
|
|
96
|
+
const constraint = normalizeConstraintIdentifier(mssqlCauseProperty(cause, "constraint"))
|
|
97
|
+
if (constraint !== UNKNOWN_CONSTRAINT) {
|
|
98
|
+
return constraint
|
|
99
|
+
}
|
|
100
|
+
return mssqlUniqueViolationConstraintFromMessage(number, mssqlCauseProperty(cause, "message"))
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const classifyError = (
|
|
104
|
+
cause: unknown,
|
|
105
|
+
message: string,
|
|
106
|
+
operation: string,
|
|
107
|
+
fallback: "connection" | "unknown" = "unknown"
|
|
108
|
+
) => {
|
|
109
|
+
const props = { cause, message, operation }
|
|
110
|
+
const number = mssqlNumberFromCause(cause)
|
|
111
|
+
if (number !== undefined) {
|
|
112
|
+
if (mssqlConnectionErrorCodes.has(number)) {
|
|
113
|
+
return new ConnectionError(props)
|
|
114
|
+
}
|
|
115
|
+
if (mssqlAuthenticationErrorCodes.has(number)) {
|
|
116
|
+
return new AuthenticationError(props)
|
|
117
|
+
}
|
|
118
|
+
if (mssqlAuthorizationErrorCodes.has(number)) {
|
|
119
|
+
return new AuthorizationError(props)
|
|
120
|
+
}
|
|
121
|
+
if (mssqlSyntaxErrorCodes.has(number)) {
|
|
122
|
+
return new SqlSyntaxError(props)
|
|
123
|
+
}
|
|
124
|
+
if (number === 2601 || number === 2627) {
|
|
125
|
+
return new UniqueViolation({ ...props, constraint: mssqlUniqueViolationConstraintFromCause(number, cause) })
|
|
126
|
+
}
|
|
127
|
+
if (mssqlConstraintErrorCodes.has(number)) {
|
|
128
|
+
return new ConstraintError(props)
|
|
129
|
+
}
|
|
130
|
+
if (number === 1205) {
|
|
131
|
+
return new DeadlockError(props)
|
|
132
|
+
}
|
|
133
|
+
if (number === 3960) {
|
|
134
|
+
return new SerializationError(props)
|
|
135
|
+
}
|
|
136
|
+
if (number === 1222) {
|
|
137
|
+
return new LockTimeoutError(props)
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return fallback === "connection" ? new ConnectionError(props) : new UnknownError(props)
|
|
141
|
+
}
|
|
142
|
+
|
|
31
143
|
/**
|
|
32
|
-
*
|
|
33
|
-
*
|
|
144
|
+
* Runtime type identifier used to mark `MssqlClient` values.
|
|
145
|
+
*
|
|
146
|
+
* @category type IDs
|
|
147
|
+
* @since 4.0.0
|
|
34
148
|
*/
|
|
35
149
|
export const TypeId: unique symbol = Symbol.for("@effect/sql-mssql/MssqlClient")
|
|
36
150
|
|
|
37
151
|
/**
|
|
38
|
-
*
|
|
39
|
-
*
|
|
152
|
+
* Type-level identifier used to mark `MssqlClient` values.
|
|
153
|
+
*
|
|
154
|
+
* @category type IDs
|
|
155
|
+
* @since 4.0.0
|
|
40
156
|
*/
|
|
41
157
|
export type TypeId = typeof TypeId
|
|
42
158
|
|
|
43
159
|
/**
|
|
160
|
+
* Microsoft SQL Server client service, extending `SqlClient` with typed parameter fragments and stored procedure calls.
|
|
161
|
+
*
|
|
44
162
|
* @category models
|
|
45
|
-
* @since
|
|
163
|
+
* @since 4.0.0
|
|
46
164
|
*/
|
|
47
165
|
export interface MssqlClient extends Client.SqlClient {
|
|
48
166
|
readonly [TypeId]: TypeId
|
|
@@ -65,14 +183,23 @@ export interface MssqlClient extends Client.SqlClient {
|
|
|
65
183
|
}
|
|
66
184
|
|
|
67
185
|
/**
|
|
68
|
-
*
|
|
69
|
-
*
|
|
186
|
+
* Service tag for the Microsoft SQL Server client service.
|
|
187
|
+
*
|
|
188
|
+
* **When to use**
|
|
189
|
+
*
|
|
190
|
+
* Use to access or provide a Microsoft SQL Server client through the Effect
|
|
191
|
+
* context.
|
|
192
|
+
*
|
|
193
|
+
* @category services
|
|
194
|
+
* @since 4.0.0
|
|
70
195
|
*/
|
|
71
|
-
export const MssqlClient =
|
|
196
|
+
export const MssqlClient = Context.Service<MssqlClient>("@effect/sql-mssql/MssqlClient")
|
|
72
197
|
|
|
73
198
|
/**
|
|
199
|
+
* Configuration for a Microsoft SQL Server client, including connection, authentication, pool, parameter type, span attribute, and query/result name transform options.
|
|
200
|
+
*
|
|
74
201
|
* @category models
|
|
75
|
-
* @since
|
|
202
|
+
* @since 4.0.0
|
|
76
203
|
*/
|
|
77
204
|
export interface MssqlClientConfig {
|
|
78
205
|
readonly domain?: string | undefined
|
|
@@ -86,6 +213,10 @@ export interface MssqlClientConfig {
|
|
|
86
213
|
readonly username?: string | undefined
|
|
87
214
|
readonly password?: Redacted.Redacted | undefined
|
|
88
215
|
readonly connectTimeout?: Duration.Input | undefined
|
|
216
|
+
readonly cancelTimeout?: Duration.Input | undefined
|
|
217
|
+
readonly connectionRetryInterval?: Duration.Input | undefined
|
|
218
|
+
readonly multiSubnetFailover?: boolean | undefined
|
|
219
|
+
readonly maxRetriesOnTransientErrors?: number | undefined
|
|
89
220
|
|
|
90
221
|
readonly minConnections?: number | undefined
|
|
91
222
|
readonly maxConnections?: number | undefined
|
|
@@ -111,14 +242,18 @@ interface MssqlConnection extends Connection {
|
|
|
111
242
|
readonly rollback: (name?: string) => Effect.Effect<void, SqlError>
|
|
112
243
|
}
|
|
113
244
|
|
|
114
|
-
const TransactionConnection = Client.TransactionConnection as unknown as
|
|
245
|
+
const TransactionConnection = Client.TransactionConnection as unknown as (clientId: number) => Context.Service<
|
|
115
246
|
readonly [conn: MssqlConnection, counter: number],
|
|
116
247
|
readonly [conn: MssqlConnection, counter: number]
|
|
117
248
|
>
|
|
118
249
|
|
|
250
|
+
let clientIdCounter = 0
|
|
251
|
+
|
|
119
252
|
/**
|
|
253
|
+
* Creates a scoped Microsoft SQL Server client backed by a connection pool, with transaction and stored procedure support. Streaming queries are not implemented.
|
|
254
|
+
*
|
|
120
255
|
* @category constructors
|
|
121
|
-
* @since
|
|
256
|
+
* @since 4.0.0
|
|
122
257
|
*/
|
|
123
258
|
export const make = (
|
|
124
259
|
options: MssqlClientConfig
|
|
@@ -149,13 +284,21 @@ export const make = (
|
|
|
149
284
|
port: options.port,
|
|
150
285
|
database: options.database,
|
|
151
286
|
trustServerCertificate: options.trustServer ?? true,
|
|
287
|
+
multiSubnetFailover: options.multiSubnetFailover,
|
|
152
288
|
connectTimeout: options.connectTimeout
|
|
153
289
|
? Duration.toMillis(Duration.fromInputUnsafe(options.connectTimeout))
|
|
154
290
|
: undefined,
|
|
155
291
|
rowCollectionOnRequestCompletion: true,
|
|
156
292
|
useColumnNames: false,
|
|
157
293
|
instanceName: options.instanceName,
|
|
158
|
-
encrypt: options.encrypt ?? false
|
|
294
|
+
encrypt: options.encrypt ?? false,
|
|
295
|
+
cancelTimeout: options.cancelTimeout
|
|
296
|
+
? Duration.toMillis(Duration.fromInputUnsafe(options.cancelTimeout))
|
|
297
|
+
: undefined,
|
|
298
|
+
connectionRetryInterval: options.connectionRetryInterval
|
|
299
|
+
? Duration.toMillis(Duration.fromInputUnsafe(options.connectionRetryInterval))
|
|
300
|
+
: undefined,
|
|
301
|
+
maxRetriesOnTransientErrors: options.maxRetriesOnTransientErrors
|
|
159
302
|
} as ConnectionOptions,
|
|
160
303
|
server: options.server,
|
|
161
304
|
authentication: {
|
|
@@ -174,7 +317,9 @@ export const make = (
|
|
|
174
317
|
yield* Effect.callback<void, SqlError>((resume) => {
|
|
175
318
|
conn.connect((cause) => {
|
|
176
319
|
if (cause) {
|
|
177
|
-
resume(
|
|
320
|
+
resume(
|
|
321
|
+
Effect.fail(new SqlError({ reason: classifyError(cause, "Failed to connect", "connect", "connection") }))
|
|
322
|
+
)
|
|
178
323
|
} else {
|
|
179
324
|
resume(Effect.void)
|
|
180
325
|
}
|
|
@@ -189,7 +334,9 @@ export const make = (
|
|
|
189
334
|
Effect.callback<any, SqlError>((resume) => {
|
|
190
335
|
const req = new Tedious.Request(sql, (cause, _rowCount, result) => {
|
|
191
336
|
if (cause) {
|
|
192
|
-
resume(
|
|
337
|
+
resume(
|
|
338
|
+
Effect.fail(new SqlError({ reason: classifyError(cause, "Failed to execute statement", "execute") }))
|
|
339
|
+
)
|
|
193
340
|
return
|
|
194
341
|
}
|
|
195
342
|
|
|
@@ -232,7 +379,9 @@ export const make = (
|
|
|
232
379
|
escape(procedure.name),
|
|
233
380
|
(cause, _, rows) => {
|
|
234
381
|
if (cause) {
|
|
235
|
-
resume(
|
|
382
|
+
resume(
|
|
383
|
+
Effect.fail(new SqlError({ reason: classifyError(cause, "Failed to execute statement", "execute") }))
|
|
384
|
+
)
|
|
236
385
|
} else {
|
|
237
386
|
rows = rowsToObjects(rows)
|
|
238
387
|
if (transformRows) {
|
|
@@ -279,6 +428,9 @@ export const make = (
|
|
|
279
428
|
executeValues(sql, params) {
|
|
280
429
|
return run(sql, params, true)
|
|
281
430
|
},
|
|
431
|
+
executeValuesUnprepared(sql, params) {
|
|
432
|
+
return run(sql, params, true)
|
|
433
|
+
},
|
|
282
434
|
executeUnprepared(sql, params, transformRows) {
|
|
283
435
|
return this.execute(sql, params, transformRows)
|
|
284
436
|
},
|
|
@@ -291,7 +443,13 @@ export const make = (
|
|
|
291
443
|
begin: Effect.callback<void, SqlError>((resume) => {
|
|
292
444
|
conn.beginTransaction((cause) => {
|
|
293
445
|
if (cause) {
|
|
294
|
-
resume(
|
|
446
|
+
resume(
|
|
447
|
+
Effect.fail(
|
|
448
|
+
new SqlError({
|
|
449
|
+
reason: classifyError(cause, "Failed to begin transaction", "beginTransaction")
|
|
450
|
+
})
|
|
451
|
+
)
|
|
452
|
+
)
|
|
295
453
|
} else {
|
|
296
454
|
resume(Effect.void)
|
|
297
455
|
}
|
|
@@ -300,7 +458,13 @@ export const make = (
|
|
|
300
458
|
commit: Effect.callback<void, SqlError>((resume) => {
|
|
301
459
|
conn.commitTransaction((cause) => {
|
|
302
460
|
if (cause) {
|
|
303
|
-
resume(
|
|
461
|
+
resume(
|
|
462
|
+
Effect.fail(
|
|
463
|
+
new SqlError({
|
|
464
|
+
reason: classifyError(cause, "Failed to commit transaction", "commitTransaction")
|
|
465
|
+
})
|
|
466
|
+
)
|
|
467
|
+
)
|
|
304
468
|
} else {
|
|
305
469
|
resume(Effect.void)
|
|
306
470
|
}
|
|
@@ -310,7 +474,11 @@ export const make = (
|
|
|
310
474
|
Effect.callback<void, SqlError>((resume) => {
|
|
311
475
|
conn.saveTransaction((cause) => {
|
|
312
476
|
if (cause) {
|
|
313
|
-
resume(
|
|
477
|
+
resume(
|
|
478
|
+
Effect.fail(
|
|
479
|
+
new SqlError({ reason: classifyError(cause, "Failed to create savepoint", "createSavepoint") })
|
|
480
|
+
)
|
|
481
|
+
)
|
|
314
482
|
} else {
|
|
315
483
|
resume(Effect.void)
|
|
316
484
|
}
|
|
@@ -320,7 +488,13 @@ export const make = (
|
|
|
320
488
|
Effect.callback<void, SqlError>((resume) => {
|
|
321
489
|
conn.rollbackTransaction((cause) => {
|
|
322
490
|
if (cause) {
|
|
323
|
-
resume(
|
|
491
|
+
resume(
|
|
492
|
+
Effect.fail(
|
|
493
|
+
new SqlError({
|
|
494
|
+
reason: classifyError(cause, "Failed to rollback transaction", "rollbackTransaction")
|
|
495
|
+
})
|
|
496
|
+
)
|
|
497
|
+
)
|
|
324
498
|
} else {
|
|
325
499
|
resume(Effect.void)
|
|
326
500
|
}
|
|
@@ -349,22 +523,29 @@ export const make = (
|
|
|
349
523
|
|
|
350
524
|
yield* Pool.get(pool).pipe(
|
|
351
525
|
Effect.tap((connection) => connection.executeUnprepared("SELECT 1", [], undefined)),
|
|
352
|
-
Effect.mapError((
|
|
526
|
+
Effect.mapError((cause) =>
|
|
527
|
+
new SqlError({ reason: classifyError(cause, "MssqlClient: Failed to connect", "connect", "connection") })
|
|
528
|
+
),
|
|
353
529
|
Effect.scoped,
|
|
354
530
|
Effect.timeoutOrElse({
|
|
355
531
|
duration: options.connectTimeout ?? Duration.seconds(5),
|
|
356
|
-
|
|
532
|
+
orElse: () =>
|
|
357
533
|
Effect.fail(
|
|
358
534
|
new SqlError({
|
|
359
|
-
|
|
360
|
-
|
|
535
|
+
reason: new ConnectionError({
|
|
536
|
+
message: "MssqlClient: Connection timeout",
|
|
537
|
+
cause: new Error("connection timeout"),
|
|
538
|
+
operation: "connect"
|
|
539
|
+
})
|
|
361
540
|
})
|
|
362
541
|
)
|
|
363
542
|
})
|
|
364
543
|
)
|
|
365
544
|
|
|
545
|
+
const transactionService = TransactionConnection(clientIdCounter++)
|
|
546
|
+
|
|
366
547
|
const withTransaction = Client.makeWithTransaction({
|
|
367
|
-
transactionService
|
|
548
|
+
transactionService,
|
|
368
549
|
spanAttributes,
|
|
369
550
|
acquireConnection: Effect.gen(function*() {
|
|
370
551
|
const scope = Scope.makeUnsafe()
|
|
@@ -382,6 +563,7 @@ export const make = (
|
|
|
382
563
|
yield* Client.make({
|
|
383
564
|
acquirer: Pool.get(pool),
|
|
384
565
|
compiler,
|
|
566
|
+
transactionService: transactionService as any,
|
|
385
567
|
spanAttributes,
|
|
386
568
|
transformRows
|
|
387
569
|
}),
|
|
@@ -426,42 +608,48 @@ export const make = (
|
|
|
426
608
|
})
|
|
427
609
|
|
|
428
610
|
/**
|
|
611
|
+
* Creates a layer from a `Config`-wrapped SQL Server client configuration, providing both `MssqlClient` and `SqlClient`.
|
|
612
|
+
*
|
|
429
613
|
* @category layers
|
|
430
|
-
* @since
|
|
614
|
+
* @since 4.0.0
|
|
431
615
|
*/
|
|
432
616
|
export const layerConfig: (
|
|
433
617
|
config: Config.Wrap<MssqlClientConfig>
|
|
434
618
|
) => Layer.Layer<Client.SqlClient | MssqlClient, Config.ConfigError | SqlError> = (
|
|
435
619
|
config: Config.Wrap<MssqlClientConfig>
|
|
436
620
|
): Layer.Layer<Client.SqlClient | MssqlClient, Config.ConfigError | SqlError> =>
|
|
437
|
-
Layer.
|
|
438
|
-
Config.unwrap(config).
|
|
621
|
+
Layer.effectContext(
|
|
622
|
+
Config.unwrap(config).pipe(
|
|
439
623
|
Effect.flatMap(make),
|
|
440
624
|
Effect.map((client) =>
|
|
441
|
-
|
|
442
|
-
|
|
625
|
+
Context.make(MssqlClient, client).pipe(
|
|
626
|
+
Context.add(Client.SqlClient, client)
|
|
443
627
|
)
|
|
444
628
|
)
|
|
445
629
|
)
|
|
446
630
|
).pipe(Layer.provide(Reactivity.layer))
|
|
447
631
|
|
|
448
632
|
/**
|
|
633
|
+
* Creates a layer from a concrete SQL Server client configuration, providing both `MssqlClient` and `SqlClient`.
|
|
634
|
+
*
|
|
449
635
|
* @category layers
|
|
450
|
-
* @since
|
|
636
|
+
* @since 4.0.0
|
|
451
637
|
*/
|
|
452
638
|
export const layer = (
|
|
453
639
|
config: MssqlClientConfig
|
|
454
640
|
): Layer.Layer<Client.SqlClient | MssqlClient, never | SqlError> =>
|
|
455
|
-
Layer.
|
|
641
|
+
Layer.effectContext(
|
|
456
642
|
Effect.map(make(config), (client) =>
|
|
457
|
-
|
|
458
|
-
|
|
643
|
+
Context.make(MssqlClient, client).pipe(
|
|
644
|
+
Context.add(Client.SqlClient, client)
|
|
459
645
|
))
|
|
460
646
|
).pipe(Layer.provide(Reactivity.layer))
|
|
461
647
|
|
|
462
648
|
/**
|
|
649
|
+
* Creates the SQL Server statement compiler, using `@1`-style placeholders, bracket-escaped identifiers, and SQL Server `OUTPUT INSERTED` returning clauses.
|
|
650
|
+
*
|
|
463
651
|
* @category compiler
|
|
464
|
-
* @since
|
|
652
|
+
* @since 4.0.0
|
|
465
653
|
*/
|
|
466
654
|
export const makeCompiler = (transform?: (_: string) => string) =>
|
|
467
655
|
Statement.makeCompiler<MssqlCustom>({
|
|
@@ -510,7 +698,10 @@ function numberToParamName(n: number) {
|
|
|
510
698
|
}
|
|
511
699
|
|
|
512
700
|
/**
|
|
513
|
-
*
|
|
701
|
+
* Default mapping from Effect SQL primitive value kinds to Tedious SQL Server parameter data types.
|
|
702
|
+
*
|
|
703
|
+
* @category configuration
|
|
704
|
+
* @since 4.0.0
|
|
514
705
|
*/
|
|
515
706
|
export const defaultParameterTypes: Record<Statement.PrimitiveKind, DataType> = {
|
|
516
707
|
string: Tedious.TYPES.VarChar,
|
package/src/MssqlMigrator.ts
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
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`. `run` returns the applied migration IDs
|
|
7
|
+
* and names, while `layer` runs migrations during layer construction and
|
|
8
|
+
* provides no services.
|
|
9
|
+
*
|
|
10
|
+
* @since 4.0.0
|
|
3
11
|
*/
|
|
4
12
|
import type * as Effect from "effect/Effect"
|
|
5
13
|
import * as Layer from "effect/Layer"
|
|
@@ -8,13 +16,15 @@ import type * as Client from "effect/unstable/sql/SqlClient"
|
|
|
8
16
|
import type { SqlError } from "effect/unstable/sql/SqlError"
|
|
9
17
|
|
|
10
18
|
/**
|
|
11
|
-
* @since
|
|
19
|
+
* @since 4.0.0
|
|
12
20
|
*/
|
|
13
21
|
export * from "effect/unstable/sql/Migrator"
|
|
14
22
|
|
|
15
23
|
/**
|
|
16
|
-
*
|
|
17
|
-
*
|
|
24
|
+
* Runs SQL migrations using the configured `SqlClient`, returning the migrations that were applied.
|
|
25
|
+
*
|
|
26
|
+
* @category constructors
|
|
27
|
+
* @since 4.0.0
|
|
18
28
|
*/
|
|
19
29
|
export const run: <R>(
|
|
20
30
|
options: Migrator.MigratorOptions<R>
|
|
@@ -25,8 +35,10 @@ export const run: <R>(
|
|
|
25
35
|
> = Migrator.make({})
|
|
26
36
|
|
|
27
37
|
/**
|
|
38
|
+
* Creates a layer that runs the configured SQL migrations during layer construction.
|
|
39
|
+
*
|
|
28
40
|
* @category layers
|
|
29
|
-
* @since
|
|
41
|
+
* @since 4.0.0
|
|
30
42
|
*/
|
|
31
43
|
export const layer = <R>(
|
|
32
44
|
options: Migrator.MigratorOptions<R>
|
package/src/Parameter.ts
CHANGED
|
@@ -1,25 +1,41 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
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
|
+
* @see {@link make} for constructing parameter metadata directly.
|
|
11
|
+
*
|
|
12
|
+
* @since 4.0.0
|
|
3
13
|
*/
|
|
4
14
|
import { identity } from "effect/Function"
|
|
5
15
|
import type { DataType } from "tedious/lib/data-type.ts"
|
|
6
16
|
import type { ParameterOptions } from "tedious/lib/request.ts"
|
|
7
17
|
|
|
8
18
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
19
|
+
* Runtime type identifier used to mark SQL Server stored procedure parameter metadata.
|
|
20
|
+
*
|
|
21
|
+
* @category type IDs
|
|
22
|
+
* @since 4.0.0
|
|
11
23
|
*/
|
|
12
24
|
export const TypeId: TypeId = "~@effect/sql-mssql/Parameter"
|
|
13
25
|
|
|
14
26
|
/**
|
|
15
|
-
*
|
|
16
|
-
*
|
|
27
|
+
* Type-level identifier used to mark SQL Server stored procedure parameter metadata.
|
|
28
|
+
*
|
|
29
|
+
* @category type IDs
|
|
30
|
+
* @since 4.0.0
|
|
17
31
|
*/
|
|
18
32
|
export type TypeId = "~@effect/sql-mssql/Parameter"
|
|
19
33
|
|
|
20
34
|
/**
|
|
21
|
-
*
|
|
22
|
-
*
|
|
35
|
+
* Metadata for a SQL Server stored procedure parameter, including its name, Tedious data type, options, and phantom value type.
|
|
36
|
+
*
|
|
37
|
+
* @category models
|
|
38
|
+
* @since 4.0.0
|
|
23
39
|
*/
|
|
24
40
|
export interface Parameter<out A> {
|
|
25
41
|
readonly [TypeId]: (_: never) => A
|
|
@@ -30,8 +46,10 @@ export interface Parameter<out A> {
|
|
|
30
46
|
}
|
|
31
47
|
|
|
32
48
|
/**
|
|
33
|
-
*
|
|
34
|
-
*
|
|
49
|
+
* Creates typed metadata for a SQL Server stored procedure parameter.
|
|
50
|
+
*
|
|
51
|
+
* @category constructors
|
|
52
|
+
* @since 4.0.0
|
|
35
53
|
*/
|
|
36
54
|
export const make = <A>(
|
|
37
55
|
name: string,
|