Skip to content

Commit 6f6996b

Browse files
committed
fix: various mssql compat fixes
1 parent ab8c8f5 commit 6f6996b

48 files changed

Lines changed: 421 additions & 455 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/test-query-compiler.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,12 @@ jobs:
5656
relation_load_strategy: '["query"]'
5757
test_threads: 1
5858

59+
- name: mssql
60+
setup_task: dev-mssql-qc
61+
ignored_tests_list: query-compiler/query-engine-tests-todo/mssql/skip
62+
should_fail_tests_list: query-compiler/query-engine-tests-todo/mssql/fail
63+
relation_load_strategy: '["query"]'
64+
5965
name: ${{ matrix.adapter.name }}
6066

6167
uses: ./.github/workflows/test-query-compiler-template.yml

Makefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,11 @@ start-mssql_edge:
376376
dev-mssql_edge: start-mssql_edge
377377
cp $(CONFIG_PATH)/sqlserver2019 $(CONFIG_FILE)
378378

379+
dev-mssql-qc: start-mssql_2022 build-qc-wasm build-driver-adapters-kit-qc
380+
cp $(CONFIG_PATH)/sqlserver-qc $(CONFIG_FILE)
381+
382+
test-mssql-qc: dev-mssql-qc test-qe
383+
379384
start-mssql_2017:
380385
docker compose -f docker-compose.yml up --wait -d --remove-orphans mssql-2017
381386

libs/driver-adapters/executor/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"@prisma/adapter-better-sqlite3": "workspace:*",
2828
"@prisma/adapter-d1": "workspace:*",
2929
"@prisma/adapter-libsql": "workspace:*",
30+
"@prisma/adapter-mssql": "workspace:*",
3031
"@prisma/adapter-neon": "workspace:*",
3132
"@prisma/adapter-pg": "workspace:*",
3233
"@prisma/adapter-planetscale": "workspace:*",
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { PrismaMssql } from '@prisma/adapter-mssql'
2+
import type {
3+
SqlDriverAdapter,
4+
SqlDriverAdapterFactory,
5+
} from '@prisma/driver-adapter-utils'
6+
import type { DriverAdaptersManager, SetupDriverAdaptersInput } from './index'
7+
import type { DriverAdapterTag, EnvForAdapter } from '../types'
8+
9+
const TAG = 'mssql' as const satisfies DriverAdapterTag
10+
type TAG = typeof TAG
11+
12+
export class MssqlManager implements DriverAdaptersManager {
13+
#factory: SqlDriverAdapterFactory
14+
#adapter?: SqlDriverAdapter
15+
16+
private constructor(
17+
private env: EnvForAdapter<TAG>,
18+
{ url }: SetupDriverAdaptersInput,
19+
) {
20+
const config = mssqlOptions(url)
21+
this.#factory = new PrismaMssql(config, { schema: config.schema })
22+
}
23+
24+
static async setup(env: EnvForAdapter<TAG>, input: SetupDriverAdaptersInput) {
25+
return new MssqlManager(env, input)
26+
}
27+
28+
factory() {
29+
return this.#factory
30+
}
31+
32+
async connect() {
33+
this.#adapter = await this.#factory.connect()
34+
return this.#adapter
35+
}
36+
37+
async teardown() {
38+
await this.#adapter?.dispose()
39+
}
40+
}
41+
42+
function mssqlOptions(url: string) {
43+
const [, server, port, database, schema, user, password] =
44+
url.match(
45+
/^sqlserver:\/\/([^:;]+):(\d+);database=([^;]+);schema=([^;]+);user=([^;]+);password=([^;]+);/,
46+
) || []
47+
48+
return {
49+
user,
50+
password,
51+
database,
52+
schema,
53+
server,
54+
port: Number(port),
55+
options: {
56+
trustServerCertificate: true,
57+
},
58+
}
59+
}

libs/driver-adapters/executor/src/qc-test-worker/worker-query.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,7 @@ import {
1010
type TransactionManager,
1111
UserFacingError,
1212
} from '@prisma/client-engine-runtime'
13-
import {
14-
ColumnType,
15-
ColumnTypeEnum,
16-
IsolationLevel,
17-
SqlQueryable,
18-
SqlResultSet,
19-
} from '@prisma/driver-adapter-utils'
13+
import { IsolationLevel, SqlQueryable } from '@prisma/driver-adapter-utils'
2014
import Decimal from 'decimal.js'
2115

2216
import { JsonOutputTaggedValue } from '../engines/JsonProtocol'

libs/driver-adapters/executor/src/setup.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { LibSQLManager } from './driver-adapters-manager/libsql'
1010
import { PlanetScaleManager } from './driver-adapters-manager/planetscale'
1111
import { D1Manager } from './driver-adapters-manager/d1'
1212
import { BetterSQLite3Manager } from './driver-adapters-manager/better-sqlite3'
13+
import { MssqlManager } from './driver-adapters-manager/mssql'
1314

1415
export async function setupDriverAdaptersManager(
1516
env: Env,
@@ -40,5 +41,9 @@ export async function setupDriverAdaptersManager(
4041
{ DRIVER_ADAPTER: 'better-sqlite3' },
4142
async (env) => await BetterSQLite3Manager.setup(env, input),
4243
)
44+
.with(
45+
{ DRIVER_ADAPTER: 'mssql' },
46+
async (env) => await MssqlManager.setup(env, input),
47+
)
4348
.exhaustive()
4449
}

libs/driver-adapters/executor/src/types/env.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,13 @@ export const Env = S.extend(
4747
EnvPlanetScale,
4848
EnvNeonWS,
4949
S.struct({
50-
DRIVER_ADAPTER: S.literal('pg', 'libsql', 'd1', 'better-sqlite3'),
50+
DRIVER_ADAPTER: S.literal(
51+
'pg',
52+
'libsql',
53+
'd1',
54+
'better-sqlite3',
55+
'mssql',
56+
),
5157
}),
5258
),
5359
S.union(

libs/driver-adapters/pnpm-workspace.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ packages:
22
- '../../../prisma/packages/adapter-d1'
33
- '../../../prisma/packages/adapter-better-sqlite3'
44
- '../../../prisma/packages/adapter-libsql'
5+
- '../../../prisma/packages/adapter-mssql'
56
- '../../../prisma/packages/adapter-neon'
67
- '../../../prisma/packages/adapter-pg'
78
- '../../../prisma/packages/adapter-planetscale'

query-compiler/query-compiler/src/translate.rs

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -293,15 +293,28 @@ impl<'a, 'b> NodeTranslator<'a, 'b> {
293293
let fields = self.process_edge_selections(edge, &node, selection);
294294

295295
match sink {
296-
RowSink::AllRows(field) | RowSink::SingleRowArray(field) => {
296+
RowSink::All(field) | RowSink::ExactlyOne(field) | RowSink::AtMostOne(field) => {
297297
*field.node_input_field(&mut node) = vec![SelectionResult::new(fields)];
298298
}
299-
RowSink::SingleRow(field) => {
299+
RowSink::Single(field) => {
300300
*field.node_input_field(&mut node) = SelectionResult::new(fields);
301301
}
302-
RowSink::SingleRowFilter(field) => {
302+
RowSink::ExactlyOneFilter(field) => {
303303
*field.node_input_field(&mut node) = SelectionResult::new(fields).filter();
304304
}
305+
RowSink::ExactlyOneWriteArgs(selection, field) => {
306+
let result = SelectionResult::new(fields);
307+
let model = node.as_query().map(Query::model);
308+
let args = field.node_input_field(&mut node);
309+
for arg in args {
310+
arg.inject(selection.assimilate(result.clone()).map_err(|err| {
311+
TranslateError::GraphBuildError(QueryGraphBuilderError::DomainError(err))
312+
})?);
313+
if let Some(model) = &model {
314+
arg.update_datetimes(model);
315+
}
316+
}
317+
}
305318
RowSink::Discard => {}
306319
}
307320
}
@@ -432,11 +445,8 @@ impl<'a, 'b> NodeTranslator<'a, 'b> {
432445

433446
let requires_unique = matches!(
434447
edge_content,
435-
Some(QueryGraphDependency::ProjectedDataSinkDependency(
436-
_,
437-
RowSink::SingleRow(_) | RowSink::SingleRowArray(_) | RowSink::SingleRowFilter(_),
438-
_
439-
))
448+
Some(QueryGraphDependency::ProjectedDataSinkDependency(_, sink, _))
449+
if sink.is_unique()
440450
);
441451

442452
let source = self.graph.edge_source(&edge);

query-compiler/query-compiler/src/translate/query/read.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ pub(crate) fn translate_read_query(query: ReadQuery, builder: &dyn QueryBuilder)
4444
}
4545

4646
ReadQuery::ManyRecordsQuery(mut mrq) => {
47+
// Skip the query entirely if the take is 0.
48+
if mrq.args.take == Take::Some(0) {
49+
return Ok(Expression::Concat(vec![]));
50+
}
51+
4752
let selected_fields = match mrq.relation_load_strategy {
4853
RelationLoadStrategy::Join => mrq.selected_fields.into_virtuals_last(),
4954
RelationLoadStrategy::Query => mrq.selected_fields.without_relations().into_virtuals_last(),
@@ -220,6 +225,11 @@ fn build_read_related_records(
220225
links: Vec<ConditionalLink>,
221226
builder: &dyn QueryBuilder,
222227
) -> TranslateResult<(Expression, JoinMetadata)> {
228+
// Skip the query entirely if the take is 0.
229+
if rrq.args.take == Take::Some(0) {
230+
return Ok((Expression::Concat(vec![]), JoinMetadata::default()));
231+
}
232+
223233
let mut linkage = RelationLinkage::new(rrq.parent_field.clone(), links);
224234

225235
if let Some(results) = rrq.parent_results {
@@ -386,7 +396,7 @@ fn extract_distinct_by(args: &mut QueryArguments) -> Vec<String> {
386396
distinct.db_names().collect_vec()
387397
}
388398

389-
#[derive(Debug, Clone)]
399+
#[derive(Debug, Default, Clone)]
390400
struct JoinMetadata {
391401
fields: Vec<String>,
392402
is_relation_unique: bool,

0 commit comments

Comments
 (0)