@effect/sql-mssql 4.0.0-beta.7 → 4.0.0-beta.70
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 +62 -15
- package/dist/MssqlClient.d.ts.map +1 -1
- package/dist/MssqlClient.js +155 -37
- package/dist/MssqlClient.js.map +1 -1
- package/dist/MssqlMigrator.d.ts +30 -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 +14 -6
- package/dist/Parameter.d.ts.map +1 -1
- package/dist/Parameter.js +28 -4
- package/dist/Parameter.js.map +1 -1
- package/dist/Procedure.d.ts +41 -16
- package/dist/Procedure.d.ts.map +1 -1
- package/dist/Procedure.js +37 -8
- package/dist/Procedure.js.map +1 -1
- package/dist/index.d.ts +90 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +90 -6
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
- package/src/MssqlClient.ts +222 -36
- package/src/MssqlMigrator.ts +30 -5
- package/src/Parameter.ts +35 -7
- package/src/Procedure.ts +60 -18
- package/src/index.ts +90 -6
package/src/MssqlClient.ts
CHANGED
|
@@ -1,7 +1,34 @@
|
|
|
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 and layers that also satisfy
|
|
6
|
+
* the generic `SqlClient` service. It is intended for server applications,
|
|
7
|
+
* background workers, migrations, and tests that need SQL Server query
|
|
8
|
+
* compilation, Tedious parameter typing, scoped connection management,
|
|
9
|
+
* transactions, and typed stored procedure calls.
|
|
10
|
+
*
|
|
11
|
+
* Clients own a scoped pool of Tedious connections and validate startup with
|
|
12
|
+
* `SELECT 1`. Regular queries borrow a pooled connection per operation, while
|
|
13
|
+
* transactions keep one pooled connection for their lifetime and use SQL Server
|
|
14
|
+
* savepoints for nested transactions. Long-running transactions therefore
|
|
15
|
+
* reduce available pool capacity; size `maxConnections`, `connectionTTL`, and
|
|
16
|
+
* `connectTimeout` accordingly.
|
|
17
|
+
*
|
|
18
|
+
* Tedious permits one active request per connection. This client compiles
|
|
19
|
+
* statements with named `@1`-style parameters, maps Effect SQL primitive values
|
|
20
|
+
* to Tedious `DataType`s unless `param` is used, and does not implement
|
|
21
|
+
* streaming queries. Be deliberate about TLS options: `encrypt` defaults to
|
|
22
|
+
* `false` and `trustServerCertificate` defaults to `true` unless overridden.
|
|
23
|
+
* Stored procedure calls go through `callProcedure`; define input and output
|
|
24
|
+
* parameters with the `Procedure` and `Parameter` helpers so Tedious receives
|
|
25
|
+
* the correct data types and output values can be collected from `returnValue`
|
|
26
|
+
* events.
|
|
27
|
+
*
|
|
28
|
+
* @since 4.0.0
|
|
3
29
|
*/
|
|
4
30
|
import * as Config from "effect/Config"
|
|
31
|
+
import * as Context from "effect/Context"
|
|
5
32
|
import * as Duration from "effect/Duration"
|
|
6
33
|
import * as Effect from "effect/Effect"
|
|
7
34
|
import { identity } from "effect/Function"
|
|
@@ -9,12 +36,23 @@ import * as Layer from "effect/Layer"
|
|
|
9
36
|
import * as Pool from "effect/Pool"
|
|
10
37
|
import * as Redacted from "effect/Redacted"
|
|
11
38
|
import * as Scope from "effect/Scope"
|
|
12
|
-
import * as ServiceMap from "effect/ServiceMap"
|
|
13
39
|
import * as Stream from "effect/Stream"
|
|
14
40
|
import * as Reactivity from "effect/unstable/reactivity/Reactivity"
|
|
15
41
|
import * as Client from "effect/unstable/sql/SqlClient"
|
|
16
42
|
import type { Connection } from "effect/unstable/sql/SqlConnection"
|
|
17
|
-
import {
|
|
43
|
+
import {
|
|
44
|
+
AuthenticationError,
|
|
45
|
+
AuthorizationError,
|
|
46
|
+
ConnectionError,
|
|
47
|
+
ConstraintError,
|
|
48
|
+
DeadlockError,
|
|
49
|
+
LockTimeoutError,
|
|
50
|
+
SerializationError,
|
|
51
|
+
SqlError,
|
|
52
|
+
SqlSyntaxError,
|
|
53
|
+
UniqueViolation,
|
|
54
|
+
UnknownError
|
|
55
|
+
} from "effect/unstable/sql/SqlError"
|
|
18
56
|
import * as Statement from "effect/unstable/sql/Statement"
|
|
19
57
|
import * as Tedious from "tedious"
|
|
20
58
|
import type { ConnectionOptions } from "tedious/lib/connection.ts"
|
|
@@ -28,21 +66,116 @@ const ATTR_DB_NAMESPACE = "db.namespace"
|
|
|
28
66
|
const ATTR_SERVER_ADDRESS = "server.address"
|
|
29
67
|
const ATTR_SERVER_PORT = "server.port"
|
|
30
68
|
|
|
69
|
+
const mssqlNumberFromCause = (cause: unknown): number | undefined => {
|
|
70
|
+
if (typeof cause !== "object" || cause === null || !("number" in cause)) {
|
|
71
|
+
return undefined
|
|
72
|
+
}
|
|
73
|
+
const number = cause.number
|
|
74
|
+
return typeof number === "number" ? number : undefined
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const mssqlConnectionErrorCodes = new Set([233, 10054])
|
|
78
|
+
const mssqlAuthenticationErrorCodes = new Set([4060, 18452, 18456])
|
|
79
|
+
const mssqlAuthorizationErrorCodes = new Set([229, 230, 262, 297, 300])
|
|
80
|
+
const mssqlSyntaxErrorCodes = new Set([102, 207, 208, 2714])
|
|
81
|
+
const mssqlConstraintErrorCodes = new Set([515, 547])
|
|
82
|
+
|
|
83
|
+
const UNKNOWN_CONSTRAINT = "unknown"
|
|
84
|
+
|
|
85
|
+
const normalizeConstraintIdentifier = (identifier: unknown): string => {
|
|
86
|
+
if (typeof identifier !== "string") {
|
|
87
|
+
return UNKNOWN_CONSTRAINT
|
|
88
|
+
}
|
|
89
|
+
const trimmed = identifier.trim()
|
|
90
|
+
return trimmed.length === 0 ? UNKNOWN_CONSTRAINT : trimmed
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const mssqlCauseProperty = (cause: unknown, property: "constraint" | "message"): unknown => {
|
|
94
|
+
if (typeof cause !== "object" || cause === null || !(property in cause)) {
|
|
95
|
+
return undefined
|
|
96
|
+
}
|
|
97
|
+
return (cause as Record<string, unknown>)[property]
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const mssqlUniqueViolationConstraintFromMessage = (number: 2601 | 2627, message: unknown): string => {
|
|
101
|
+
if (typeof message !== "string") {
|
|
102
|
+
return UNKNOWN_CONSTRAINT
|
|
103
|
+
}
|
|
104
|
+
const match = number === 2627 ?
|
|
105
|
+
/\bconstraint\s+'([^']*)'/i.exec(message) :
|
|
106
|
+
/\bunique index\s+'([^']*)'/i.exec(message)
|
|
107
|
+
return match === null ? UNKNOWN_CONSTRAINT : normalizeConstraintIdentifier(match[1])
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const mssqlUniqueViolationConstraintFromCause = (number: 2601 | 2627, cause: unknown): string => {
|
|
111
|
+
const constraint = normalizeConstraintIdentifier(mssqlCauseProperty(cause, "constraint"))
|
|
112
|
+
if (constraint !== UNKNOWN_CONSTRAINT) {
|
|
113
|
+
return constraint
|
|
114
|
+
}
|
|
115
|
+
return mssqlUniqueViolationConstraintFromMessage(number, mssqlCauseProperty(cause, "message"))
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const classifyError = (
|
|
119
|
+
cause: unknown,
|
|
120
|
+
message: string,
|
|
121
|
+
operation: string,
|
|
122
|
+
fallback: "connection" | "unknown" = "unknown"
|
|
123
|
+
) => {
|
|
124
|
+
const props = { cause, message, operation }
|
|
125
|
+
const number = mssqlNumberFromCause(cause)
|
|
126
|
+
if (number !== undefined) {
|
|
127
|
+
if (mssqlConnectionErrorCodes.has(number)) {
|
|
128
|
+
return new ConnectionError(props)
|
|
129
|
+
}
|
|
130
|
+
if (mssqlAuthenticationErrorCodes.has(number)) {
|
|
131
|
+
return new AuthenticationError(props)
|
|
132
|
+
}
|
|
133
|
+
if (mssqlAuthorizationErrorCodes.has(number)) {
|
|
134
|
+
return new AuthorizationError(props)
|
|
135
|
+
}
|
|
136
|
+
if (mssqlSyntaxErrorCodes.has(number)) {
|
|
137
|
+
return new SqlSyntaxError(props)
|
|
138
|
+
}
|
|
139
|
+
if (number === 2601 || number === 2627) {
|
|
140
|
+
return new UniqueViolation({ ...props, constraint: mssqlUniqueViolationConstraintFromCause(number, cause) })
|
|
141
|
+
}
|
|
142
|
+
if (mssqlConstraintErrorCodes.has(number)) {
|
|
143
|
+
return new ConstraintError(props)
|
|
144
|
+
}
|
|
145
|
+
if (number === 1205) {
|
|
146
|
+
return new DeadlockError(props)
|
|
147
|
+
}
|
|
148
|
+
if (number === 3960) {
|
|
149
|
+
return new SerializationError(props)
|
|
150
|
+
}
|
|
151
|
+
if (number === 1222) {
|
|
152
|
+
return new LockTimeoutError(props)
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return fallback === "connection" ? new ConnectionError(props) : new UnknownError(props)
|
|
156
|
+
}
|
|
157
|
+
|
|
31
158
|
/**
|
|
32
|
-
*
|
|
33
|
-
*
|
|
159
|
+
* Runtime type identifier used to mark `MssqlClient` values.
|
|
160
|
+
*
|
|
161
|
+
* @category type IDs
|
|
162
|
+
* @since 4.0.0
|
|
34
163
|
*/
|
|
35
164
|
export const TypeId: unique symbol = Symbol.for("@effect/sql-mssql/MssqlClient")
|
|
36
165
|
|
|
37
166
|
/**
|
|
38
|
-
*
|
|
39
|
-
*
|
|
167
|
+
* Type-level identifier used to mark `MssqlClient` values.
|
|
168
|
+
*
|
|
169
|
+
* @category type IDs
|
|
170
|
+
* @since 4.0.0
|
|
40
171
|
*/
|
|
41
172
|
export type TypeId = typeof TypeId
|
|
42
173
|
|
|
43
174
|
/**
|
|
175
|
+
* Microsoft SQL Server client service, extending `SqlClient` with typed parameter fragments and stored procedure calls.
|
|
176
|
+
*
|
|
44
177
|
* @category models
|
|
45
|
-
* @since
|
|
178
|
+
* @since 4.0.0
|
|
46
179
|
*/
|
|
47
180
|
export interface MssqlClient extends Client.SqlClient {
|
|
48
181
|
readonly [TypeId]: TypeId
|
|
@@ -65,14 +198,18 @@ export interface MssqlClient extends Client.SqlClient {
|
|
|
65
198
|
}
|
|
66
199
|
|
|
67
200
|
/**
|
|
201
|
+
* Context tag used to access the `MssqlClient` service.
|
|
202
|
+
*
|
|
68
203
|
* @category tags
|
|
69
|
-
* @since
|
|
204
|
+
* @since 4.0.0
|
|
70
205
|
*/
|
|
71
|
-
export const MssqlClient =
|
|
206
|
+
export const MssqlClient = Context.Service<MssqlClient>("@effect/sql-mssql/MssqlClient")
|
|
72
207
|
|
|
73
208
|
/**
|
|
209
|
+
* Configuration for a Microsoft SQL Server client, including connection, authentication, pool, parameter type, span attribute, and query/result name transform options.
|
|
210
|
+
*
|
|
74
211
|
* @category models
|
|
75
|
-
* @since
|
|
212
|
+
* @since 4.0.0
|
|
76
213
|
*/
|
|
77
214
|
export interface MssqlClientConfig {
|
|
78
215
|
readonly domain?: string | undefined
|
|
@@ -111,14 +248,18 @@ interface MssqlConnection extends Connection {
|
|
|
111
248
|
readonly rollback: (name?: string) => Effect.Effect<void, SqlError>
|
|
112
249
|
}
|
|
113
250
|
|
|
114
|
-
const TransactionConnection = Client.TransactionConnection as unknown as
|
|
251
|
+
const TransactionConnection = Client.TransactionConnection as unknown as (clientId: number) => Context.Service<
|
|
115
252
|
readonly [conn: MssqlConnection, counter: number],
|
|
116
253
|
readonly [conn: MssqlConnection, counter: number]
|
|
117
254
|
>
|
|
118
255
|
|
|
256
|
+
let clientIdCounter = 0
|
|
257
|
+
|
|
119
258
|
/**
|
|
259
|
+
* Creates a scoped Microsoft SQL Server client backed by a connection pool, with transaction and stored procedure support. Streaming queries are not implemented.
|
|
260
|
+
*
|
|
120
261
|
* @category constructors
|
|
121
|
-
* @since
|
|
262
|
+
* @since 4.0.0
|
|
122
263
|
*/
|
|
123
264
|
export const make = (
|
|
124
265
|
options: MssqlClientConfig
|
|
@@ -174,7 +315,9 @@ export const make = (
|
|
|
174
315
|
yield* Effect.callback<void, SqlError>((resume) => {
|
|
175
316
|
conn.connect((cause) => {
|
|
176
317
|
if (cause) {
|
|
177
|
-
resume(
|
|
318
|
+
resume(
|
|
319
|
+
Effect.fail(new SqlError({ reason: classifyError(cause, "Failed to connect", "connect", "connection") }))
|
|
320
|
+
)
|
|
178
321
|
} else {
|
|
179
322
|
resume(Effect.void)
|
|
180
323
|
}
|
|
@@ -189,7 +332,9 @@ export const make = (
|
|
|
189
332
|
Effect.callback<any, SqlError>((resume) => {
|
|
190
333
|
const req = new Tedious.Request(sql, (cause, _rowCount, result) => {
|
|
191
334
|
if (cause) {
|
|
192
|
-
resume(
|
|
335
|
+
resume(
|
|
336
|
+
Effect.fail(new SqlError({ reason: classifyError(cause, "Failed to execute statement", "execute") }))
|
|
337
|
+
)
|
|
193
338
|
return
|
|
194
339
|
}
|
|
195
340
|
|
|
@@ -232,7 +377,9 @@ export const make = (
|
|
|
232
377
|
escape(procedure.name),
|
|
233
378
|
(cause, _, rows) => {
|
|
234
379
|
if (cause) {
|
|
235
|
-
resume(
|
|
380
|
+
resume(
|
|
381
|
+
Effect.fail(new SqlError({ reason: classifyError(cause, "Failed to execute statement", "execute") }))
|
|
382
|
+
)
|
|
236
383
|
} else {
|
|
237
384
|
rows = rowsToObjects(rows)
|
|
238
385
|
if (transformRows) {
|
|
@@ -291,7 +438,13 @@ export const make = (
|
|
|
291
438
|
begin: Effect.callback<void, SqlError>((resume) => {
|
|
292
439
|
conn.beginTransaction((cause) => {
|
|
293
440
|
if (cause) {
|
|
294
|
-
resume(
|
|
441
|
+
resume(
|
|
442
|
+
Effect.fail(
|
|
443
|
+
new SqlError({
|
|
444
|
+
reason: classifyError(cause, "Failed to begin transaction", "beginTransaction")
|
|
445
|
+
})
|
|
446
|
+
)
|
|
447
|
+
)
|
|
295
448
|
} else {
|
|
296
449
|
resume(Effect.void)
|
|
297
450
|
}
|
|
@@ -300,7 +453,13 @@ export const make = (
|
|
|
300
453
|
commit: Effect.callback<void, SqlError>((resume) => {
|
|
301
454
|
conn.commitTransaction((cause) => {
|
|
302
455
|
if (cause) {
|
|
303
|
-
resume(
|
|
456
|
+
resume(
|
|
457
|
+
Effect.fail(
|
|
458
|
+
new SqlError({
|
|
459
|
+
reason: classifyError(cause, "Failed to commit transaction", "commitTransaction")
|
|
460
|
+
})
|
|
461
|
+
)
|
|
462
|
+
)
|
|
304
463
|
} else {
|
|
305
464
|
resume(Effect.void)
|
|
306
465
|
}
|
|
@@ -310,7 +469,11 @@ export const make = (
|
|
|
310
469
|
Effect.callback<void, SqlError>((resume) => {
|
|
311
470
|
conn.saveTransaction((cause) => {
|
|
312
471
|
if (cause) {
|
|
313
|
-
resume(
|
|
472
|
+
resume(
|
|
473
|
+
Effect.fail(
|
|
474
|
+
new SqlError({ reason: classifyError(cause, "Failed to create savepoint", "createSavepoint") })
|
|
475
|
+
)
|
|
476
|
+
)
|
|
314
477
|
} else {
|
|
315
478
|
resume(Effect.void)
|
|
316
479
|
}
|
|
@@ -320,7 +483,13 @@ export const make = (
|
|
|
320
483
|
Effect.callback<void, SqlError>((resume) => {
|
|
321
484
|
conn.rollbackTransaction((cause) => {
|
|
322
485
|
if (cause) {
|
|
323
|
-
resume(
|
|
486
|
+
resume(
|
|
487
|
+
Effect.fail(
|
|
488
|
+
new SqlError({
|
|
489
|
+
reason: classifyError(cause, "Failed to rollback transaction", "rollbackTransaction")
|
|
490
|
+
})
|
|
491
|
+
)
|
|
492
|
+
)
|
|
324
493
|
} else {
|
|
325
494
|
resume(Effect.void)
|
|
326
495
|
}
|
|
@@ -349,22 +518,29 @@ export const make = (
|
|
|
349
518
|
|
|
350
519
|
yield* Pool.get(pool).pipe(
|
|
351
520
|
Effect.tap((connection) => connection.executeUnprepared("SELECT 1", [], undefined)),
|
|
352
|
-
Effect.mapError((
|
|
521
|
+
Effect.mapError((cause) =>
|
|
522
|
+
new SqlError({ reason: classifyError(cause, "MssqlClient: Failed to connect", "connect", "connection") })
|
|
523
|
+
),
|
|
353
524
|
Effect.scoped,
|
|
354
525
|
Effect.timeoutOrElse({
|
|
355
526
|
duration: options.connectTimeout ?? Duration.seconds(5),
|
|
356
|
-
|
|
527
|
+
orElse: () =>
|
|
357
528
|
Effect.fail(
|
|
358
529
|
new SqlError({
|
|
359
|
-
|
|
360
|
-
|
|
530
|
+
reason: new ConnectionError({
|
|
531
|
+
message: "MssqlClient: Connection timeout",
|
|
532
|
+
cause: new Error("connection timeout"),
|
|
533
|
+
operation: "connect"
|
|
534
|
+
})
|
|
361
535
|
})
|
|
362
536
|
)
|
|
363
537
|
})
|
|
364
538
|
)
|
|
365
539
|
|
|
540
|
+
const transactionService = TransactionConnection(clientIdCounter++)
|
|
541
|
+
|
|
366
542
|
const withTransaction = Client.makeWithTransaction({
|
|
367
|
-
transactionService
|
|
543
|
+
transactionService,
|
|
368
544
|
spanAttributes,
|
|
369
545
|
acquireConnection: Effect.gen(function*() {
|
|
370
546
|
const scope = Scope.makeUnsafe()
|
|
@@ -382,6 +558,7 @@ export const make = (
|
|
|
382
558
|
yield* Client.make({
|
|
383
559
|
acquirer: Pool.get(pool),
|
|
384
560
|
compiler,
|
|
561
|
+
transactionService: transactionService as any,
|
|
385
562
|
spanAttributes,
|
|
386
563
|
transformRows
|
|
387
564
|
}),
|
|
@@ -426,42 +603,48 @@ export const make = (
|
|
|
426
603
|
})
|
|
427
604
|
|
|
428
605
|
/**
|
|
606
|
+
* Creates a layer from a `Config`-wrapped SQL Server client configuration, providing both `MssqlClient` and `SqlClient`.
|
|
607
|
+
*
|
|
429
608
|
* @category layers
|
|
430
|
-
* @since
|
|
609
|
+
* @since 4.0.0
|
|
431
610
|
*/
|
|
432
611
|
export const layerConfig: (
|
|
433
612
|
config: Config.Wrap<MssqlClientConfig>
|
|
434
613
|
) => Layer.Layer<Client.SqlClient | MssqlClient, Config.ConfigError | SqlError> = (
|
|
435
614
|
config: Config.Wrap<MssqlClientConfig>
|
|
436
615
|
): Layer.Layer<Client.SqlClient | MssqlClient, Config.ConfigError | SqlError> =>
|
|
437
|
-
Layer.
|
|
438
|
-
Config.unwrap(config).
|
|
616
|
+
Layer.effectContext(
|
|
617
|
+
Config.unwrap(config).pipe(
|
|
439
618
|
Effect.flatMap(make),
|
|
440
619
|
Effect.map((client) =>
|
|
441
|
-
|
|
442
|
-
|
|
620
|
+
Context.make(MssqlClient, client).pipe(
|
|
621
|
+
Context.add(Client.SqlClient, client)
|
|
443
622
|
)
|
|
444
623
|
)
|
|
445
624
|
)
|
|
446
625
|
).pipe(Layer.provide(Reactivity.layer))
|
|
447
626
|
|
|
448
627
|
/**
|
|
628
|
+
* Creates a layer from a concrete SQL Server client configuration, providing both `MssqlClient` and `SqlClient`.
|
|
629
|
+
*
|
|
449
630
|
* @category layers
|
|
450
|
-
* @since
|
|
631
|
+
* @since 4.0.0
|
|
451
632
|
*/
|
|
452
633
|
export const layer = (
|
|
453
634
|
config: MssqlClientConfig
|
|
454
635
|
): Layer.Layer<Client.SqlClient | MssqlClient, never | SqlError> =>
|
|
455
|
-
Layer.
|
|
636
|
+
Layer.effectContext(
|
|
456
637
|
Effect.map(make(config), (client) =>
|
|
457
|
-
|
|
458
|
-
|
|
638
|
+
Context.make(MssqlClient, client).pipe(
|
|
639
|
+
Context.add(Client.SqlClient, client)
|
|
459
640
|
))
|
|
460
641
|
).pipe(Layer.provide(Reactivity.layer))
|
|
461
642
|
|
|
462
643
|
/**
|
|
644
|
+
* Creates the SQL Server statement compiler, using `@1`-style placeholders, bracket-escaped identifiers, and SQL Server `OUTPUT INSERTED` returning clauses.
|
|
645
|
+
*
|
|
463
646
|
* @category compiler
|
|
464
|
-
* @since
|
|
647
|
+
* @since 4.0.0
|
|
465
648
|
*/
|
|
466
649
|
export const makeCompiler = (transform?: (_: string) => string) =>
|
|
467
650
|
Statement.makeCompiler<MssqlCustom>({
|
|
@@ -510,7 +693,10 @@ function numberToParamName(n: number) {
|
|
|
510
693
|
}
|
|
511
694
|
|
|
512
695
|
/**
|
|
513
|
-
*
|
|
696
|
+
* Default mapping from Effect SQL primitive value kinds to Tedious SQL Server parameter data types.
|
|
697
|
+
*
|
|
698
|
+
* @category configuration
|
|
699
|
+
* @since 4.0.0
|
|
514
700
|
*/
|
|
515
701
|
export const defaultParameterTypes: Record<Statement.PrimitiveKind, DataType> = {
|
|
516
702
|
string: Tedious.TYPES.VarChar,
|
package/src/MssqlMigrator.ts
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
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`. 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
|
|
32
|
+
* @since 4.0.0
|
|
12
33
|
*/
|
|
13
34
|
export * from "effect/unstable/sql/Migrator"
|
|
14
35
|
|
|
15
36
|
/**
|
|
16
|
-
*
|
|
17
|
-
*
|
|
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
|
|
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,51 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Typed metadata for SQL Server stored procedure parameters.
|
|
3
|
+
*
|
|
4
|
+
* This module records the bare parameter name, Tedious `DataType`, Tedious
|
|
5
|
+
* `ParameterOptions`, and phantom TypeScript value type used by
|
|
6
|
+
* `Procedure.param` and `Procedure.outputParam`. `MssqlClient.call` later
|
|
7
|
+
* forwards input parameters to Tedious with `Request.addParameter` and output
|
|
8
|
+
* parameters with `Request.addOutputParameter`, so names should match the
|
|
9
|
+
* stored procedure parameter name without a leading `@`.
|
|
10
|
+
*
|
|
11
|
+
* Use these values when defining stored procedures that need explicit SQL
|
|
12
|
+
* Server parameter metadata, such as sized strings or binary values, decimal
|
|
13
|
+
* precision/scale, table-valued parameters, and output parameters. The generic
|
|
14
|
+
* type parameter is only a compile-time guide for the value record accepted by
|
|
15
|
+
* `Procedure.compile`; Tedious still validates and encodes the runtime value.
|
|
16
|
+
* In particular, TVP values must use Tedious' table shape with `name`,
|
|
17
|
+
* optional `schema`, `columns`, and `rows`, and output parameters are registered
|
|
18
|
+
* with no initial value, so SQL Server input-output parameters need separate
|
|
19
|
+
* care rather than assuming an output parameter is populated from compiled
|
|
20
|
+
* input values.
|
|
21
|
+
*
|
|
22
|
+
* @since 4.0.0
|
|
3
23
|
*/
|
|
4
24
|
import { identity } from "effect/Function"
|
|
5
25
|
import type { DataType } from "tedious/lib/data-type.ts"
|
|
6
26
|
import type { ParameterOptions } from "tedious/lib/request.ts"
|
|
7
27
|
|
|
8
28
|
/**
|
|
29
|
+
* Runtime type identifier used to mark SQL Server stored procedure parameter metadata.
|
|
30
|
+
*
|
|
9
31
|
* @category type id
|
|
10
|
-
* @since
|
|
32
|
+
* @since 4.0.0
|
|
11
33
|
*/
|
|
12
34
|
export const TypeId: TypeId = "~@effect/sql-mssql/Parameter"
|
|
13
35
|
|
|
14
36
|
/**
|
|
37
|
+
* Type-level identifier used to mark SQL Server stored procedure parameter metadata.
|
|
38
|
+
*
|
|
15
39
|
* @category type id
|
|
16
|
-
* @since
|
|
40
|
+
* @since 4.0.0
|
|
17
41
|
*/
|
|
18
42
|
export type TypeId = "~@effect/sql-mssql/Parameter"
|
|
19
43
|
|
|
20
44
|
/**
|
|
21
|
-
*
|
|
22
|
-
*
|
|
45
|
+
* Metadata for a SQL Server stored procedure parameter, including its name, Tedious data type, options, and phantom value type.
|
|
46
|
+
*
|
|
47
|
+
* @category models
|
|
48
|
+
* @since 4.0.0
|
|
23
49
|
*/
|
|
24
50
|
export interface Parameter<out A> {
|
|
25
51
|
readonly [TypeId]: (_: never) => A
|
|
@@ -30,8 +56,10 @@ export interface Parameter<out A> {
|
|
|
30
56
|
}
|
|
31
57
|
|
|
32
58
|
/**
|
|
33
|
-
*
|
|
34
|
-
*
|
|
59
|
+
* Creates typed metadata for a SQL Server stored procedure parameter.
|
|
60
|
+
*
|
|
61
|
+
* @category constructors
|
|
62
|
+
* @since 4.0.0
|
|
35
63
|
*/
|
|
36
64
|
export const make = <A>(
|
|
37
65
|
name: string,
|