@prisma/adapter-mssql 6.17.0-dev.21 → 6.17.0-dev.23
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/README.md +56 -1
- package/dist/index.js +181 -78
- package/dist/index.mjs +181 -78
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ Install the Prisma ORM's driver adapter:
|
|
|
16
16
|
npm install @prisma/adapter-mssql
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
###
|
|
19
|
+
### 2. Instantiate Prisma Client using the driver adapter
|
|
20
20
|
|
|
21
21
|
Finally, when you instantiate Prisma Client, you need to pass an instance of Prisma ORM's driver adapter to the `PrismaClient` constructor:
|
|
22
22
|
|
|
@@ -39,3 +39,58 @@ const config = {
|
|
|
39
39
|
const adapter = new PrismaMssql(config)
|
|
40
40
|
const prisma = new PrismaClient({ adapter })
|
|
41
41
|
```
|
|
42
|
+
|
|
43
|
+
You can also instantiate the adapter with a [JDBC](https://learn.microsoft.com/en-us/sql/connect/jdbc/building-the-connection-url?view=sql-server-ver15) connection string:
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
import { PrismaMssql } from '@prisma/adapter-mssql'
|
|
47
|
+
import { PrismaClient } from '@prisma/client'
|
|
48
|
+
|
|
49
|
+
const adapter = new PrismaMssql('sqlserver://localhost:1433;database=testdb;user=sa;password=mypassword;encrypt=true')
|
|
50
|
+
const prisma = new PrismaClient({ adapter })
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 3. Entra ID Authentication (formerly Azure Active Directory)
|
|
54
|
+
|
|
55
|
+
Entra ID authentication is supported by the mssql driver used by this adapter.
|
|
56
|
+
|
|
57
|
+
For options using the config object, see the options documentation for the [Tedious driver](https://github.com/tediousjs/node-mssql?tab=readme-ov-file#tedious).
|
|
58
|
+
|
|
59
|
+
For example, using the config object to configure [DefaultAzureCredential](https://learn.microsoft.com/en-gb/azure/developer/javascript/sdk/authentication/credential-chains#use-defaultazurecredential-for-flexibility):
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
import { PrismaMssql } from '@prisma/adapter-mssql'
|
|
63
|
+
import { PrismaClient } from '@prisma/client'
|
|
64
|
+
|
|
65
|
+
const config = {
|
|
66
|
+
server: 'localhost',
|
|
67
|
+
port: 1433,
|
|
68
|
+
database: 'mydb',
|
|
69
|
+
authentication: {
|
|
70
|
+
type: 'azure-active-directory-default',
|
|
71
|
+
},
|
|
72
|
+
options: {
|
|
73
|
+
encrypt: true,
|
|
74
|
+
},
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const adapter = new PrismaMssql(config)
|
|
78
|
+
const prisma = new PrismaClient({ adapter })
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Connection string parsing also supports authentication options, as per below:
|
|
82
|
+
|
|
83
|
+
- to use [DefaultAzureCredential](https://learn.microsoft.com/en-gb/azure/developer/javascript/sdk/authentication/credential-chains#use-defaultazurecredential-for-flexibility), set:
|
|
84
|
+
- `authentication=DefaultAzureCredential` in your connection string
|
|
85
|
+
- to use an Entra username/password, set:
|
|
86
|
+
- `authentication=ActiveDirectoryPassword`
|
|
87
|
+
- `userName=<value>`
|
|
88
|
+
- `password=<value>`
|
|
89
|
+
- `clientId=<value>`
|
|
90
|
+
- to use an Entra managed identity, set:
|
|
91
|
+
- `authentication=ActiveDirectoryManagedIdentity`
|
|
92
|
+
- `clientId=<value>` (optional)
|
|
93
|
+
- to use a Service Principal with clientId and secret, set:
|
|
94
|
+
- `authentication=ActiveDirectoryServicePrincipal`
|
|
95
|
+
- `userName=<client id>`
|
|
96
|
+
- `password=<client secret>`
|
package/dist/index.js
CHANGED
|
@@ -91,97 +91,200 @@ function parseConnectionString(connectionString) {
|
|
|
91
91
|
}
|
|
92
92
|
config.port = port;
|
|
93
93
|
}
|
|
94
|
+
const parameters = {};
|
|
94
95
|
for (const part of paramParts) {
|
|
95
96
|
const [key, value] = part.split("=", 2);
|
|
96
97
|
if (!key) continue;
|
|
97
98
|
const trimmedKey = key.trim();
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
99
|
+
if (trimmedKey in parameters) {
|
|
100
|
+
throw new Error(`Duplication configuration parameter: ${trimmedKey}`);
|
|
101
|
+
}
|
|
102
|
+
parameters[trimmedKey] = value.trim();
|
|
103
|
+
if (!handledParameters.includes(trimmedKey)) {
|
|
104
|
+
debug(`Unknown connection string parameter: ${trimmedKey}`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
const database = firstKey(parameters, "database", "initial catalog");
|
|
108
|
+
if (database !== null) {
|
|
109
|
+
config.database = database;
|
|
110
|
+
}
|
|
111
|
+
const user = firstKey(parameters, "user", "username", "uid", "userid");
|
|
112
|
+
if (user !== null) {
|
|
113
|
+
config.user = user;
|
|
114
|
+
}
|
|
115
|
+
const password = firstKey(parameters, "password", "pwd");
|
|
116
|
+
if (password !== null) {
|
|
117
|
+
config.password = password;
|
|
118
|
+
}
|
|
119
|
+
const encrypt = firstKey(parameters, "encrypt");
|
|
120
|
+
if (encrypt !== null) {
|
|
121
|
+
config.options = config.options || {};
|
|
122
|
+
config.options.encrypt = encrypt.toLowerCase() === "true";
|
|
123
|
+
}
|
|
124
|
+
const trustServerCertificate = firstKey(parameters, "trustServerCertificate");
|
|
125
|
+
if (trustServerCertificate !== null) {
|
|
126
|
+
config.options = config.options || {};
|
|
127
|
+
config.options.trustServerCertificate = trustServerCertificate.toLowerCase() === "true";
|
|
128
|
+
}
|
|
129
|
+
const connectionLimit = firstKey(parameters, "connectionLimit");
|
|
130
|
+
if (connectionLimit !== null) {
|
|
131
|
+
config.pool = config.pool || {};
|
|
132
|
+
const limit = parseInt(connectionLimit, 10);
|
|
133
|
+
if (isNaN(limit)) {
|
|
134
|
+
throw new Error(`Invalid connection limit: ${connectionLimit}`);
|
|
135
|
+
}
|
|
136
|
+
config.pool.max = limit;
|
|
137
|
+
}
|
|
138
|
+
const connectionTimeout = firstKey(parameters, "connectionTimeout", "connectTimeout");
|
|
139
|
+
if (connectionTimeout !== null) {
|
|
140
|
+
const timeout = parseInt(connectionTimeout, 10);
|
|
141
|
+
if (isNaN(timeout)) {
|
|
142
|
+
throw new Error(`Invalid connection timeout: ${connectionTimeout}`);
|
|
143
|
+
}
|
|
144
|
+
config.connectionTimeout = timeout;
|
|
145
|
+
}
|
|
146
|
+
const loginTimeout = firstKey(parameters, "loginTimeout");
|
|
147
|
+
if (loginTimeout !== null) {
|
|
148
|
+
const timeout = parseInt(loginTimeout, 10);
|
|
149
|
+
if (isNaN(timeout)) {
|
|
150
|
+
throw new Error(`Invalid login timeout: ${loginTimeout}`);
|
|
151
|
+
}
|
|
152
|
+
config.connectionTimeout = timeout;
|
|
153
|
+
}
|
|
154
|
+
const socketTimeout = firstKey(parameters, "socketTimeout");
|
|
155
|
+
if (socketTimeout !== null) {
|
|
156
|
+
const timeout = parseInt(socketTimeout, 10);
|
|
157
|
+
if (isNaN(timeout)) {
|
|
158
|
+
throw new Error(`Invalid socket timeout: ${socketTimeout}`);
|
|
159
|
+
}
|
|
160
|
+
config.requestTimeout = timeout;
|
|
161
|
+
}
|
|
162
|
+
const poolTimeout = firstKey(parameters, "poolTimeout");
|
|
163
|
+
if (poolTimeout !== null) {
|
|
164
|
+
const timeout = parseInt(poolTimeout, 10);
|
|
165
|
+
if (isNaN(timeout)) {
|
|
166
|
+
throw new Error(`Invalid pool timeout: ${poolTimeout}`);
|
|
167
|
+
}
|
|
168
|
+
config.pool = config.pool || {};
|
|
169
|
+
config.pool.acquireTimeoutMillis = timeout * 1e3;
|
|
170
|
+
}
|
|
171
|
+
const appName = firstKey(parameters, "applicationName", "application name");
|
|
172
|
+
if (appName !== null) {
|
|
173
|
+
config.options = config.options || {};
|
|
174
|
+
config.options.appName = appName;
|
|
175
|
+
}
|
|
176
|
+
const isolationLevel = firstKey(parameters, "isolationLevel");
|
|
177
|
+
if (isolationLevel !== null) {
|
|
178
|
+
config.options = config.options || {};
|
|
179
|
+
config.options.isolationLevel = mapIsolationLevelFromString(isolationLevel);
|
|
180
|
+
}
|
|
181
|
+
const authentication = firstKey(parameters, "authentication");
|
|
182
|
+
if (authentication !== null) {
|
|
183
|
+
config.authentication = parseAuthenticationOptions(parameters, authentication);
|
|
184
|
+
}
|
|
185
|
+
if (!config.server || config.server.trim() === "") {
|
|
186
|
+
throw new Error("Server host is required in connection string");
|
|
187
|
+
}
|
|
188
|
+
return config;
|
|
189
|
+
}
|
|
190
|
+
function parseAuthenticationOptions(parameters, authenticationValue) {
|
|
191
|
+
switch (authenticationValue) {
|
|
192
|
+
/**
|
|
193
|
+
* 'DefaultAzureCredential' is not listed in the JDBC driver spec
|
|
194
|
+
* https://learn.microsoft.com/en-us/sql/connect/jdbc/setting-the-connection-properties?view=sql-server-ver15#properties
|
|
195
|
+
* but is supported by tedious so included here
|
|
196
|
+
*/
|
|
197
|
+
case "DefaultAzureCredential":
|
|
198
|
+
case "ActiveDirectoryIntegrated":
|
|
199
|
+
case "ActiveDirectoryInteractive":
|
|
200
|
+
return { type: "azure-active-directory-default", options: {} };
|
|
201
|
+
case "ActiveDirectoryPassword": {
|
|
202
|
+
const userName = firstKey(parameters, "userName");
|
|
203
|
+
const password = firstKey(parameters, "password");
|
|
204
|
+
const clientId = firstKey(parameters, "clientId");
|
|
205
|
+
const tenantId = firstKey(parameters, "tenantId");
|
|
206
|
+
if (!userName || !password || !clientId) {
|
|
207
|
+
throw new Error(`Invalid authentication, ActiveDirectoryPassword requires userName, password, clientId`);
|
|
147
208
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
209
|
+
return {
|
|
210
|
+
type: "azure-active-directory-password",
|
|
211
|
+
options: {
|
|
212
|
+
userName,
|
|
213
|
+
password,
|
|
214
|
+
clientId,
|
|
215
|
+
tenantId: tenantId || ""
|
|
152
216
|
}
|
|
153
|
-
|
|
154
|
-
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
case "ActiveDirectoryManagedIdentity":
|
|
220
|
+
case "ActiveDirectoryMSI": {
|
|
221
|
+
const clientId = firstKey(parameters, "clientId");
|
|
222
|
+
const msiEndpoint = firstKey(parameters, "msiEndpoint");
|
|
223
|
+
const msiSecret = firstKey(parameters, "msiSecret");
|
|
224
|
+
if (!msiEndpoint || !msiSecret) {
|
|
225
|
+
throw new Error(`Invalid authentication, ActiveDirectoryManagedIdentity requires msiEndpoint, msiSecret`);
|
|
155
226
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
227
|
+
return {
|
|
228
|
+
type: "azure-active-directory-msi-app-service",
|
|
229
|
+
options: {
|
|
230
|
+
clientId: clientId || void 0,
|
|
231
|
+
// @ts-expect-error TODO: tedious typings don't define msiEndpoint and msiSecret -- needs to be fixed upstream
|
|
232
|
+
msiEndpoint,
|
|
233
|
+
msiSecret
|
|
160
234
|
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
case "ActiveDirectoryServicePrincipal": {
|
|
238
|
+
const clientId = firstKey(parameters, "userName");
|
|
239
|
+
const clientSecret = firstKey(parameters, "password");
|
|
240
|
+
const tenantId = firstKey(parameters, "tenantId");
|
|
241
|
+
if (clientId && clientSecret) {
|
|
242
|
+
return {
|
|
243
|
+
type: "azure-active-directory-service-principal-secret",
|
|
244
|
+
options: {
|
|
245
|
+
clientId,
|
|
246
|
+
clientSecret,
|
|
247
|
+
tenantId: tenantId || ""
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
} else {
|
|
251
|
+
throw new Error(
|
|
252
|
+
`Invalid authentication, ActiveDirectoryServicePrincipal requires userName (clientId), password (clientSecret)`
|
|
253
|
+
);
|
|
164
254
|
}
|
|
165
|
-
case "applicationName":
|
|
166
|
-
case "application name":
|
|
167
|
-
config.options = config.options || {};
|
|
168
|
-
config.options.appName = trimmedValue;
|
|
169
|
-
break;
|
|
170
|
-
case "isolationLevel":
|
|
171
|
-
config.options = config.options || {};
|
|
172
|
-
config.options.isolationLevel = mapIsolationLevelFromString(trimmedValue);
|
|
173
|
-
break;
|
|
174
|
-
case "schema":
|
|
175
|
-
break;
|
|
176
|
-
default:
|
|
177
|
-
debug(`Unknown connection string parameter: ${trimmedKey}`);
|
|
178
255
|
}
|
|
179
256
|
}
|
|
180
|
-
|
|
181
|
-
|
|
257
|
+
return void 0;
|
|
258
|
+
}
|
|
259
|
+
function firstKey(parameters, ...keys) {
|
|
260
|
+
for (const key of keys) {
|
|
261
|
+
if (key in parameters) {
|
|
262
|
+
return parameters[key];
|
|
263
|
+
}
|
|
182
264
|
}
|
|
183
|
-
return
|
|
265
|
+
return null;
|
|
184
266
|
}
|
|
267
|
+
var handledParameters = [
|
|
268
|
+
"application name",
|
|
269
|
+
"applicationName",
|
|
270
|
+
"connectTimeout",
|
|
271
|
+
"connectionLimit",
|
|
272
|
+
"connectionTimeout",
|
|
273
|
+
"database",
|
|
274
|
+
"encrypt",
|
|
275
|
+
"initial catalog",
|
|
276
|
+
"isolationLevel",
|
|
277
|
+
"loginTimeout",
|
|
278
|
+
"password",
|
|
279
|
+
"poolTimeout",
|
|
280
|
+
"pwd",
|
|
281
|
+
"socketTimeout",
|
|
282
|
+
"trustServerCertificate",
|
|
283
|
+
"uid",
|
|
284
|
+
"user",
|
|
285
|
+
"userid",
|
|
286
|
+
"username"
|
|
287
|
+
];
|
|
185
288
|
|
|
186
289
|
// src/conversion.ts
|
|
187
290
|
var import_driver_adapter_utils2 = require("@prisma/driver-adapter-utils");
|
package/dist/index.mjs
CHANGED
|
@@ -58,97 +58,200 @@ function parseConnectionString(connectionString) {
|
|
|
58
58
|
}
|
|
59
59
|
config.port = port;
|
|
60
60
|
}
|
|
61
|
+
const parameters = {};
|
|
61
62
|
for (const part of paramParts) {
|
|
62
63
|
const [key, value] = part.split("=", 2);
|
|
63
64
|
if (!key) continue;
|
|
64
65
|
const trimmedKey = key.trim();
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
66
|
+
if (trimmedKey in parameters) {
|
|
67
|
+
throw new Error(`Duplication configuration parameter: ${trimmedKey}`);
|
|
68
|
+
}
|
|
69
|
+
parameters[trimmedKey] = value.trim();
|
|
70
|
+
if (!handledParameters.includes(trimmedKey)) {
|
|
71
|
+
debug(`Unknown connection string parameter: ${trimmedKey}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
const database = firstKey(parameters, "database", "initial catalog");
|
|
75
|
+
if (database !== null) {
|
|
76
|
+
config.database = database;
|
|
77
|
+
}
|
|
78
|
+
const user = firstKey(parameters, "user", "username", "uid", "userid");
|
|
79
|
+
if (user !== null) {
|
|
80
|
+
config.user = user;
|
|
81
|
+
}
|
|
82
|
+
const password = firstKey(parameters, "password", "pwd");
|
|
83
|
+
if (password !== null) {
|
|
84
|
+
config.password = password;
|
|
85
|
+
}
|
|
86
|
+
const encrypt = firstKey(parameters, "encrypt");
|
|
87
|
+
if (encrypt !== null) {
|
|
88
|
+
config.options = config.options || {};
|
|
89
|
+
config.options.encrypt = encrypt.toLowerCase() === "true";
|
|
90
|
+
}
|
|
91
|
+
const trustServerCertificate = firstKey(parameters, "trustServerCertificate");
|
|
92
|
+
if (trustServerCertificate !== null) {
|
|
93
|
+
config.options = config.options || {};
|
|
94
|
+
config.options.trustServerCertificate = trustServerCertificate.toLowerCase() === "true";
|
|
95
|
+
}
|
|
96
|
+
const connectionLimit = firstKey(parameters, "connectionLimit");
|
|
97
|
+
if (connectionLimit !== null) {
|
|
98
|
+
config.pool = config.pool || {};
|
|
99
|
+
const limit = parseInt(connectionLimit, 10);
|
|
100
|
+
if (isNaN(limit)) {
|
|
101
|
+
throw new Error(`Invalid connection limit: ${connectionLimit}`);
|
|
102
|
+
}
|
|
103
|
+
config.pool.max = limit;
|
|
104
|
+
}
|
|
105
|
+
const connectionTimeout = firstKey(parameters, "connectionTimeout", "connectTimeout");
|
|
106
|
+
if (connectionTimeout !== null) {
|
|
107
|
+
const timeout = parseInt(connectionTimeout, 10);
|
|
108
|
+
if (isNaN(timeout)) {
|
|
109
|
+
throw new Error(`Invalid connection timeout: ${connectionTimeout}`);
|
|
110
|
+
}
|
|
111
|
+
config.connectionTimeout = timeout;
|
|
112
|
+
}
|
|
113
|
+
const loginTimeout = firstKey(parameters, "loginTimeout");
|
|
114
|
+
if (loginTimeout !== null) {
|
|
115
|
+
const timeout = parseInt(loginTimeout, 10);
|
|
116
|
+
if (isNaN(timeout)) {
|
|
117
|
+
throw new Error(`Invalid login timeout: ${loginTimeout}`);
|
|
118
|
+
}
|
|
119
|
+
config.connectionTimeout = timeout;
|
|
120
|
+
}
|
|
121
|
+
const socketTimeout = firstKey(parameters, "socketTimeout");
|
|
122
|
+
if (socketTimeout !== null) {
|
|
123
|
+
const timeout = parseInt(socketTimeout, 10);
|
|
124
|
+
if (isNaN(timeout)) {
|
|
125
|
+
throw new Error(`Invalid socket timeout: ${socketTimeout}`);
|
|
126
|
+
}
|
|
127
|
+
config.requestTimeout = timeout;
|
|
128
|
+
}
|
|
129
|
+
const poolTimeout = firstKey(parameters, "poolTimeout");
|
|
130
|
+
if (poolTimeout !== null) {
|
|
131
|
+
const timeout = parseInt(poolTimeout, 10);
|
|
132
|
+
if (isNaN(timeout)) {
|
|
133
|
+
throw new Error(`Invalid pool timeout: ${poolTimeout}`);
|
|
134
|
+
}
|
|
135
|
+
config.pool = config.pool || {};
|
|
136
|
+
config.pool.acquireTimeoutMillis = timeout * 1e3;
|
|
137
|
+
}
|
|
138
|
+
const appName = firstKey(parameters, "applicationName", "application name");
|
|
139
|
+
if (appName !== null) {
|
|
140
|
+
config.options = config.options || {};
|
|
141
|
+
config.options.appName = appName;
|
|
142
|
+
}
|
|
143
|
+
const isolationLevel = firstKey(parameters, "isolationLevel");
|
|
144
|
+
if (isolationLevel !== null) {
|
|
145
|
+
config.options = config.options || {};
|
|
146
|
+
config.options.isolationLevel = mapIsolationLevelFromString(isolationLevel);
|
|
147
|
+
}
|
|
148
|
+
const authentication = firstKey(parameters, "authentication");
|
|
149
|
+
if (authentication !== null) {
|
|
150
|
+
config.authentication = parseAuthenticationOptions(parameters, authentication);
|
|
151
|
+
}
|
|
152
|
+
if (!config.server || config.server.trim() === "") {
|
|
153
|
+
throw new Error("Server host is required in connection string");
|
|
154
|
+
}
|
|
155
|
+
return config;
|
|
156
|
+
}
|
|
157
|
+
function parseAuthenticationOptions(parameters, authenticationValue) {
|
|
158
|
+
switch (authenticationValue) {
|
|
159
|
+
/**
|
|
160
|
+
* 'DefaultAzureCredential' is not listed in the JDBC driver spec
|
|
161
|
+
* https://learn.microsoft.com/en-us/sql/connect/jdbc/setting-the-connection-properties?view=sql-server-ver15#properties
|
|
162
|
+
* but is supported by tedious so included here
|
|
163
|
+
*/
|
|
164
|
+
case "DefaultAzureCredential":
|
|
165
|
+
case "ActiveDirectoryIntegrated":
|
|
166
|
+
case "ActiveDirectoryInteractive":
|
|
167
|
+
return { type: "azure-active-directory-default", options: {} };
|
|
168
|
+
case "ActiveDirectoryPassword": {
|
|
169
|
+
const userName = firstKey(parameters, "userName");
|
|
170
|
+
const password = firstKey(parameters, "password");
|
|
171
|
+
const clientId = firstKey(parameters, "clientId");
|
|
172
|
+
const tenantId = firstKey(parameters, "tenantId");
|
|
173
|
+
if (!userName || !password || !clientId) {
|
|
174
|
+
throw new Error(`Invalid authentication, ActiveDirectoryPassword requires userName, password, clientId`);
|
|
114
175
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
176
|
+
return {
|
|
177
|
+
type: "azure-active-directory-password",
|
|
178
|
+
options: {
|
|
179
|
+
userName,
|
|
180
|
+
password,
|
|
181
|
+
clientId,
|
|
182
|
+
tenantId: tenantId || ""
|
|
119
183
|
}
|
|
120
|
-
|
|
121
|
-
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
case "ActiveDirectoryManagedIdentity":
|
|
187
|
+
case "ActiveDirectoryMSI": {
|
|
188
|
+
const clientId = firstKey(parameters, "clientId");
|
|
189
|
+
const msiEndpoint = firstKey(parameters, "msiEndpoint");
|
|
190
|
+
const msiSecret = firstKey(parameters, "msiSecret");
|
|
191
|
+
if (!msiEndpoint || !msiSecret) {
|
|
192
|
+
throw new Error(`Invalid authentication, ActiveDirectoryManagedIdentity requires msiEndpoint, msiSecret`);
|
|
122
193
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
194
|
+
return {
|
|
195
|
+
type: "azure-active-directory-msi-app-service",
|
|
196
|
+
options: {
|
|
197
|
+
clientId: clientId || void 0,
|
|
198
|
+
// @ts-expect-error TODO: tedious typings don't define msiEndpoint and msiSecret -- needs to be fixed upstream
|
|
199
|
+
msiEndpoint,
|
|
200
|
+
msiSecret
|
|
127
201
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
case "ActiveDirectoryServicePrincipal": {
|
|
205
|
+
const clientId = firstKey(parameters, "userName");
|
|
206
|
+
const clientSecret = firstKey(parameters, "password");
|
|
207
|
+
const tenantId = firstKey(parameters, "tenantId");
|
|
208
|
+
if (clientId && clientSecret) {
|
|
209
|
+
return {
|
|
210
|
+
type: "azure-active-directory-service-principal-secret",
|
|
211
|
+
options: {
|
|
212
|
+
clientId,
|
|
213
|
+
clientSecret,
|
|
214
|
+
tenantId: tenantId || ""
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
} else {
|
|
218
|
+
throw new Error(
|
|
219
|
+
`Invalid authentication, ActiveDirectoryServicePrincipal requires userName (clientId), password (clientSecret)`
|
|
220
|
+
);
|
|
131
221
|
}
|
|
132
|
-
case "applicationName":
|
|
133
|
-
case "application name":
|
|
134
|
-
config.options = config.options || {};
|
|
135
|
-
config.options.appName = trimmedValue;
|
|
136
|
-
break;
|
|
137
|
-
case "isolationLevel":
|
|
138
|
-
config.options = config.options || {};
|
|
139
|
-
config.options.isolationLevel = mapIsolationLevelFromString(trimmedValue);
|
|
140
|
-
break;
|
|
141
|
-
case "schema":
|
|
142
|
-
break;
|
|
143
|
-
default:
|
|
144
|
-
debug(`Unknown connection string parameter: ${trimmedKey}`);
|
|
145
222
|
}
|
|
146
223
|
}
|
|
147
|
-
|
|
148
|
-
|
|
224
|
+
return void 0;
|
|
225
|
+
}
|
|
226
|
+
function firstKey(parameters, ...keys) {
|
|
227
|
+
for (const key of keys) {
|
|
228
|
+
if (key in parameters) {
|
|
229
|
+
return parameters[key];
|
|
230
|
+
}
|
|
149
231
|
}
|
|
150
|
-
return
|
|
232
|
+
return null;
|
|
151
233
|
}
|
|
234
|
+
var handledParameters = [
|
|
235
|
+
"application name",
|
|
236
|
+
"applicationName",
|
|
237
|
+
"connectTimeout",
|
|
238
|
+
"connectionLimit",
|
|
239
|
+
"connectionTimeout",
|
|
240
|
+
"database",
|
|
241
|
+
"encrypt",
|
|
242
|
+
"initial catalog",
|
|
243
|
+
"isolationLevel",
|
|
244
|
+
"loginTimeout",
|
|
245
|
+
"password",
|
|
246
|
+
"poolTimeout",
|
|
247
|
+
"pwd",
|
|
248
|
+
"socketTimeout",
|
|
249
|
+
"trustServerCertificate",
|
|
250
|
+
"uid",
|
|
251
|
+
"user",
|
|
252
|
+
"userid",
|
|
253
|
+
"username"
|
|
254
|
+
];
|
|
152
255
|
|
|
153
256
|
// src/conversion.ts
|
|
154
257
|
import {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma/adapter-mssql",
|
|
3
|
-
"version": "6.17.0-dev.
|
|
3
|
+
"version": "6.17.0-dev.23",
|
|
4
4
|
"description": "Prisma's driver adapter for \"mssql\"",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -33,10 +33,10 @@
|
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"mssql": "^11.0.1",
|
|
35
35
|
"async-mutex": "0.5.0",
|
|
36
|
-
"@prisma/driver-adapter-utils": "6.17.0-dev.
|
|
36
|
+
"@prisma/driver-adapter-utils": "6.17.0-dev.23"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"@types/mssql": "9.1.
|
|
39
|
+
"@types/mssql": "9.1.8"
|
|
40
40
|
},
|
|
41
41
|
"scripts": {
|
|
42
42
|
"dev": "DEV=true tsx helpers/build.ts",
|