prisma-sql 1.71.0 → 1.73.0

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/generator.js CHANGED
@@ -2312,7 +2312,7 @@ var require_package = __commonJS({
2312
2312
  "package.json"(exports$1, module) {
2313
2313
  module.exports = {
2314
2314
  name: "prisma-sql",
2315
- version: "1.71.0",
2315
+ version: "1.73.0",
2316
2316
  description: "Convert Prisma queries to optimized SQL with type safety. 2-7x faster than Prisma Client.",
2317
2317
  main: "dist/index.cjs",
2318
2318
  module: "dist/index.js",
@@ -2378,13 +2378,13 @@ var require_package = __commonJS({
2378
2378
  license: "MIT",
2379
2379
  dependencies: {
2380
2380
  "@dee-wan/schema-parser": "1.4.0",
2381
- "@prisma/generator-helper": "^6.19.2",
2382
- "@prisma/internals": "^6.19.2"
2381
+ "@prisma/generator-helper": "^7.4.0",
2382
+ "@prisma/internals": "^7.4.0"
2383
2383
  },
2384
2384
  devDependencies: {
2385
2385
  "@faker-js/faker": "^10.2.0",
2386
- "@prisma/adapter-better-sqlite3": "^6.19.2",
2387
- "@prisma/adapter-pg": "^6.19.2",
2386
+ "@prisma/adapter-better-sqlite3": "^7.4.0",
2387
+ "@prisma/adapter-pg": "^7.4.0",
2388
2388
  "@semantic-release/changelog": "^6.0.3",
2389
2389
  "@semantic-release/git": "^10.0.1",
2390
2390
  "@types/better-sqlite3": "^7.6.13",
@@ -2398,8 +2398,8 @@ var require_package = __commonJS({
2398
2398
  tsx: "^4.21.0",
2399
2399
  typescript: "^5.9.3",
2400
2400
  vitest: "^4.0.18",
2401
- "@prisma/client": "6.19.2",
2402
- prisma: "6.19.2"
2401
+ "@prisma/client": "7.4.0",
2402
+ prisma: "7.4.0"
2403
2403
  },
2404
2404
  engines: {
2405
2405
  node: ">=16.0.0"
@@ -2407,6 +2407,241 @@ var require_package = __commonJS({
2407
2407
  };
2408
2408
  }
2409
2409
  });
2410
+ var MAX_DEPTH = 20;
2411
+ function normalizeValue(value, seen = /* @__PURE__ */ new WeakSet(), depth = 0) {
2412
+ if (depth > MAX_DEPTH) {
2413
+ throw new Error(`Max normalization depth exceeded (${MAX_DEPTH} levels)`);
2414
+ }
2415
+ if (value instanceof Date) {
2416
+ return normalizeDateValue(value);
2417
+ }
2418
+ if (typeof value === "bigint") {
2419
+ return value.toString();
2420
+ }
2421
+ if (Array.isArray(value)) {
2422
+ return normalizeArrayValue(value, seen, depth);
2423
+ }
2424
+ if (value && typeof value === "object") {
2425
+ return normalizeObjectValue(value, seen, depth);
2426
+ }
2427
+ return value;
2428
+ }
2429
+ function normalizeDateValue(date) {
2430
+ const t = date.getTime();
2431
+ if (!Number.isFinite(t)) {
2432
+ throw new Error("Invalid Date value in SQL params");
2433
+ }
2434
+ return date.toISOString();
2435
+ }
2436
+ function normalizeArrayValue(value, seen, depth) {
2437
+ const arrRef = value;
2438
+ if (seen.has(arrRef)) {
2439
+ throw new Error("Circular reference in SQL params");
2440
+ }
2441
+ seen.add(arrRef);
2442
+ const out = value.map((v) => normalizeValue(v, seen, depth + 1));
2443
+ seen.delete(arrRef);
2444
+ return out;
2445
+ }
2446
+ function normalizeObjectValue(value, seen, depth) {
2447
+ if (value instanceof Uint8Array) return value;
2448
+ if (typeof Buffer !== "undefined" && Buffer.isBuffer(value)) return value;
2449
+ const proto = Object.getPrototypeOf(value);
2450
+ const isPlain = proto === Object.prototype || proto === null;
2451
+ if (!isPlain) return value;
2452
+ const obj = value;
2453
+ if (seen.has(obj)) {
2454
+ throw new Error("Circular reference in SQL params");
2455
+ }
2456
+ seen.add(obj);
2457
+ const out = {};
2458
+ for (const [k, v] of Object.entries(obj)) {
2459
+ out[k] = normalizeValue(v, seen, depth + 1);
2460
+ }
2461
+ seen.delete(obj);
2462
+ return out;
2463
+ }
2464
+
2465
+ // src/sql-builder-dialect.ts
2466
+ var globalDialect = "postgres";
2467
+ function setGlobalDialect(dialect) {
2468
+ if (dialect !== "postgres" && dialect !== "sqlite") {
2469
+ throw new Error(
2470
+ `Invalid dialect: ${dialect}. Must be 'postgres' or 'sqlite'`
2471
+ );
2472
+ }
2473
+ globalDialect = dialect;
2474
+ }
2475
+ function getGlobalDialect() {
2476
+ return globalDialect;
2477
+ }
2478
+ function assertNonEmpty(value, name) {
2479
+ if (!value || value.trim().length === 0) {
2480
+ throw new Error(`${name} is required and cannot be empty`);
2481
+ }
2482
+ }
2483
+ function arrayContains(column, value, arrayType, dialect) {
2484
+ assertNonEmpty(column, "arrayContains column");
2485
+ assertNonEmpty(value, "arrayContains value");
2486
+ if (dialect === "postgres") {
2487
+ return `${column} @> ARRAY[${value}]::${arrayType}`;
2488
+ }
2489
+ return `EXISTS (SELECT 1 FROM json_each(${column}) WHERE value = ${value})`;
2490
+ }
2491
+ function arrayOverlaps(column, value, arrayType, dialect) {
2492
+ assertNonEmpty(column, "arrayOverlaps column");
2493
+ assertNonEmpty(value, "arrayOverlaps value");
2494
+ if (dialect === "postgres") {
2495
+ return `${column} && ${value}::${arrayType}`;
2496
+ }
2497
+ return `EXISTS (
2498
+ SELECT 1 FROM json_each(${column}) AS col
2499
+ JOIN json_each(${value}) AS val
2500
+ WHERE col.value = val.value
2501
+ )`;
2502
+ }
2503
+ function arrayContainsAll(column, value, arrayType, dialect) {
2504
+ assertNonEmpty(column, "arrayContainsAll column");
2505
+ assertNonEmpty(value, "arrayContainsAll value");
2506
+ if (dialect === "postgres") {
2507
+ return `${column} @> ${value}::${arrayType}`;
2508
+ }
2509
+ return `NOT EXISTS (
2510
+ SELECT 1 FROM json_each(${value}) AS val
2511
+ WHERE NOT EXISTS (
2512
+ SELECT 1 FROM json_each(${column}) AS col
2513
+ WHERE col.value = val.value
2514
+ )
2515
+ )`;
2516
+ }
2517
+ function arrayIsEmpty(column, dialect) {
2518
+ assertNonEmpty(column, "arrayIsEmpty column");
2519
+ if (dialect === "postgres") {
2520
+ return `(${column} IS NULL OR array_length(${column}, 1) IS NULL)`;
2521
+ }
2522
+ return `(${column} IS NULL OR json_array_length(${column}) = 0)`;
2523
+ }
2524
+ function arrayIsNotEmpty(column, dialect) {
2525
+ assertNonEmpty(column, "arrayIsNotEmpty column");
2526
+ if (dialect === "postgres") {
2527
+ return `(${column} IS NOT NULL AND array_length(${column}, 1) IS NOT NULL)`;
2528
+ }
2529
+ return `(${column} IS NOT NULL AND json_array_length(${column}) > 0)`;
2530
+ }
2531
+ function arrayEquals(column, value, arrayType, dialect) {
2532
+ assertNonEmpty(column, "arrayEquals column");
2533
+ assertNonEmpty(value, "arrayEquals value");
2534
+ if (dialect === "postgres") {
2535
+ return `${column} = ${value}::${arrayType}`;
2536
+ }
2537
+ return `json(${column}) = json(${value})`;
2538
+ }
2539
+ function caseInsensitiveLike(column, pattern, dialect) {
2540
+ assertNonEmpty(column, "caseInsensitiveLike column");
2541
+ assertNonEmpty(pattern, "caseInsensitiveLike pattern");
2542
+ if (dialect === "postgres") {
2543
+ return `${column} ILIKE ${pattern}`;
2544
+ }
2545
+ return `LOWER(${column}) LIKE LOWER(${pattern})`;
2546
+ }
2547
+ function caseInsensitiveEquals(column, value, dialect) {
2548
+ assertNonEmpty(column, "caseInsensitiveEquals column");
2549
+ assertNonEmpty(value, "caseInsensitiveEquals value");
2550
+ return `LOWER(${column}) = LOWER(${value})`;
2551
+ }
2552
+ function jsonExtractText(column, path, dialect) {
2553
+ assertNonEmpty(column, "jsonExtractText column");
2554
+ assertNonEmpty(path, "jsonExtractText path");
2555
+ if (dialect === "postgres") {
2556
+ const p = String(path).trim();
2557
+ const pathExpr = /^\$\d+$/.test(p) ? `${p}::text[]` : p;
2558
+ return `${column}#>>${pathExpr}`;
2559
+ }
2560
+ return `json_extract(${column}, ${path})`;
2561
+ }
2562
+ function jsonExtractNumeric(column, path, dialect) {
2563
+ assertNonEmpty(column, "jsonExtractNumeric column");
2564
+ assertNonEmpty(path, "jsonExtractNumeric path");
2565
+ if (dialect === "postgres") {
2566
+ const p = String(path).trim();
2567
+ const pathExpr = /^\$\d+$/.test(p) ? `${p}::text[]` : p;
2568
+ return `(${column}#>>${pathExpr})::numeric`;
2569
+ }
2570
+ return `CAST(json_extract(${column}, ${path}) AS REAL)`;
2571
+ }
2572
+ function jsonToText(column, dialect) {
2573
+ assertNonEmpty(column, "jsonToText column");
2574
+ if (dialect === "postgres") {
2575
+ return `${column}::text`;
2576
+ }
2577
+ return column;
2578
+ }
2579
+ function inArray(column, value, dialect) {
2580
+ assertNonEmpty(column, "inArray column");
2581
+ assertNonEmpty(value, "inArray value");
2582
+ if (dialect === "postgres") {
2583
+ return `${column} = ANY(${value})`;
2584
+ }
2585
+ return `${column} IN (SELECT value FROM json_each(${value}))`;
2586
+ }
2587
+ function notInArray(column, value, dialect) {
2588
+ assertNonEmpty(column, "notInArray column");
2589
+ assertNonEmpty(value, "notInArray value");
2590
+ if (dialect === "postgres") {
2591
+ return `${column} != ALL(${value})`;
2592
+ }
2593
+ return `${column} NOT IN (SELECT value FROM json_each(${value}))`;
2594
+ }
2595
+ function getArrayType(prismaType, dialect) {
2596
+ if (!prismaType || prismaType.length === 0) {
2597
+ return dialect === "sqlite" ? "TEXT" : "text[]";
2598
+ }
2599
+ if (dialect === "sqlite") {
2600
+ return "TEXT";
2601
+ }
2602
+ const baseType = prismaType.replace(/\[\]|\?/g, "");
2603
+ switch (baseType) {
2604
+ case "String":
2605
+ return "text[]";
2606
+ case "Int":
2607
+ return "integer[]";
2608
+ case "Float":
2609
+ return "double precision[]";
2610
+ case "Decimal":
2611
+ return "numeric[]";
2612
+ case "Boolean":
2613
+ return "boolean[]";
2614
+ case "BigInt":
2615
+ return "bigint[]";
2616
+ case "DateTime":
2617
+ return "timestamptz[]";
2618
+ default:
2619
+ return `"${baseType}"[]`;
2620
+ }
2621
+ }
2622
+ function jsonAgg(content, dialect) {
2623
+ assertNonEmpty(content, "jsonAgg content");
2624
+ if (dialect === "postgres") {
2625
+ return `json_agg(${content})`;
2626
+ }
2627
+ return `json_group_array(${content})`;
2628
+ }
2629
+ function jsonBuildObject(pairs, dialect) {
2630
+ const safePairs = (pairs != null ? pairs : "").trim();
2631
+ if (dialect === "postgres") {
2632
+ return safePairs.length > 0 ? `json_build_object(${safePairs})` : `json_build_object()`;
2633
+ }
2634
+ return safePairs.length > 0 ? `json_object(${safePairs})` : `json_object()`;
2635
+ }
2636
+ function prepareArrayParam(value, dialect) {
2637
+ if (!Array.isArray(value)) {
2638
+ throw new Error("prepareArrayParam requires array value");
2639
+ }
2640
+ if (dialect === "postgres") {
2641
+ return value.map((v) => normalizeValue(v));
2642
+ }
2643
+ return JSON.stringify(value.map((v) => normalizeValue(v)));
2644
+ }
2410
2645
 
2411
2646
  // src/builder/shared/constants.ts
2412
2647
  var IS_PRODUCTION = process.env.NODE_ENV === "production";
@@ -3232,241 +3467,6 @@ function joinCondition(field, parentModel, childModel, parentAlias, childAlias)
3232
3467
  function getModelByName(schemas, name) {
3233
3468
  return schemas.find((m) => m.name === name);
3234
3469
  }
3235
- var MAX_DEPTH = 20;
3236
- function normalizeValue(value, seen = /* @__PURE__ */ new WeakSet(), depth = 0) {
3237
- if (depth > MAX_DEPTH) {
3238
- throw new Error(`Max normalization depth exceeded (${MAX_DEPTH} levels)`);
3239
- }
3240
- if (value instanceof Date) {
3241
- return normalizeDateValue(value);
3242
- }
3243
- if (typeof value === "bigint") {
3244
- return value.toString();
3245
- }
3246
- if (Array.isArray(value)) {
3247
- return normalizeArrayValue(value, seen, depth);
3248
- }
3249
- if (value && typeof value === "object") {
3250
- return normalizeObjectValue(value, seen, depth);
3251
- }
3252
- return value;
3253
- }
3254
- function normalizeDateValue(date) {
3255
- const t = date.getTime();
3256
- if (!Number.isFinite(t)) {
3257
- throw new Error("Invalid Date value in SQL params");
3258
- }
3259
- return date.toISOString();
3260
- }
3261
- function normalizeArrayValue(value, seen, depth) {
3262
- const arrRef = value;
3263
- if (seen.has(arrRef)) {
3264
- throw new Error("Circular reference in SQL params");
3265
- }
3266
- seen.add(arrRef);
3267
- const out = value.map((v) => normalizeValue(v, seen, depth + 1));
3268
- seen.delete(arrRef);
3269
- return out;
3270
- }
3271
- function normalizeObjectValue(value, seen, depth) {
3272
- if (value instanceof Uint8Array) return value;
3273
- if (typeof Buffer !== "undefined" && Buffer.isBuffer(value)) return value;
3274
- const proto = Object.getPrototypeOf(value);
3275
- const isPlain = proto === Object.prototype || proto === null;
3276
- if (!isPlain) return value;
3277
- const obj = value;
3278
- if (seen.has(obj)) {
3279
- throw new Error("Circular reference in SQL params");
3280
- }
3281
- seen.add(obj);
3282
- const out = {};
3283
- for (const [k, v] of Object.entries(obj)) {
3284
- out[k] = normalizeValue(v, seen, depth + 1);
3285
- }
3286
- seen.delete(obj);
3287
- return out;
3288
- }
3289
-
3290
- // src/sql-builder-dialect.ts
3291
- var globalDialect = "postgres";
3292
- function setGlobalDialect(dialect) {
3293
- if (dialect !== "postgres" && dialect !== "sqlite") {
3294
- throw new Error(
3295
- `Invalid dialect: ${dialect}. Must be 'postgres' or 'sqlite'`
3296
- );
3297
- }
3298
- globalDialect = dialect;
3299
- }
3300
- function getGlobalDialect() {
3301
- return globalDialect;
3302
- }
3303
- function assertNonEmpty(value, name) {
3304
- if (!value || value.trim().length === 0) {
3305
- throw new Error(`${name} is required and cannot be empty`);
3306
- }
3307
- }
3308
- function arrayContains(column, value, arrayType, dialect) {
3309
- assertNonEmpty(column, "arrayContains column");
3310
- assertNonEmpty(value, "arrayContains value");
3311
- if (dialect === "postgres") {
3312
- return `${column} @> ARRAY[${value}]::${arrayType}`;
3313
- }
3314
- return `EXISTS (SELECT 1 FROM json_each(${column}) WHERE value = ${value})`;
3315
- }
3316
- function arrayOverlaps(column, value, arrayType, dialect) {
3317
- assertNonEmpty(column, "arrayOverlaps column");
3318
- assertNonEmpty(value, "arrayOverlaps value");
3319
- if (dialect === "postgres") {
3320
- return `${column} && ${value}::${arrayType}`;
3321
- }
3322
- return `EXISTS (
3323
- SELECT 1 FROM json_each(${column}) AS col
3324
- JOIN json_each(${value}) AS val
3325
- WHERE col.value = val.value
3326
- )`;
3327
- }
3328
- function arrayContainsAll(column, value, arrayType, dialect) {
3329
- assertNonEmpty(column, "arrayContainsAll column");
3330
- assertNonEmpty(value, "arrayContainsAll value");
3331
- if (dialect === "postgres") {
3332
- return `${column} @> ${value}::${arrayType}`;
3333
- }
3334
- return `NOT EXISTS (
3335
- SELECT 1 FROM json_each(${value}) AS val
3336
- WHERE NOT EXISTS (
3337
- SELECT 1 FROM json_each(${column}) AS col
3338
- WHERE col.value = val.value
3339
- )
3340
- )`;
3341
- }
3342
- function arrayIsEmpty(column, dialect) {
3343
- assertNonEmpty(column, "arrayIsEmpty column");
3344
- if (dialect === "postgres") {
3345
- return `(${column} IS NULL OR array_length(${column}, 1) IS NULL)`;
3346
- }
3347
- return `(${column} IS NULL OR json_array_length(${column}) = 0)`;
3348
- }
3349
- function arrayIsNotEmpty(column, dialect) {
3350
- assertNonEmpty(column, "arrayIsNotEmpty column");
3351
- if (dialect === "postgres") {
3352
- return `(${column} IS NOT NULL AND array_length(${column}, 1) IS NOT NULL)`;
3353
- }
3354
- return `(${column} IS NOT NULL AND json_array_length(${column}) > 0)`;
3355
- }
3356
- function arrayEquals(column, value, arrayType, dialect) {
3357
- assertNonEmpty(column, "arrayEquals column");
3358
- assertNonEmpty(value, "arrayEquals value");
3359
- if (dialect === "postgres") {
3360
- return `${column} = ${value}::${arrayType}`;
3361
- }
3362
- return `json(${column}) = json(${value})`;
3363
- }
3364
- function caseInsensitiveLike(column, pattern, dialect) {
3365
- assertNonEmpty(column, "caseInsensitiveLike column");
3366
- assertNonEmpty(pattern, "caseInsensitiveLike pattern");
3367
- if (dialect === "postgres") {
3368
- return `${column} ILIKE ${pattern}`;
3369
- }
3370
- return `LOWER(${column}) LIKE LOWER(${pattern})`;
3371
- }
3372
- function caseInsensitiveEquals(column, value, dialect) {
3373
- assertNonEmpty(column, "caseInsensitiveEquals column");
3374
- assertNonEmpty(value, "caseInsensitiveEquals value");
3375
- return `LOWER(${column}) = LOWER(${value})`;
3376
- }
3377
- function jsonExtractText(column, path, dialect) {
3378
- assertNonEmpty(column, "jsonExtractText column");
3379
- assertNonEmpty(path, "jsonExtractText path");
3380
- if (dialect === "postgres") {
3381
- const p = String(path).trim();
3382
- const pathExpr = /^\$\d+$/.test(p) ? `${p}::text[]` : p;
3383
- return `${column}#>>${pathExpr}`;
3384
- }
3385
- return `json_extract(${column}, ${path})`;
3386
- }
3387
- function jsonExtractNumeric(column, path, dialect) {
3388
- assertNonEmpty(column, "jsonExtractNumeric column");
3389
- assertNonEmpty(path, "jsonExtractNumeric path");
3390
- if (dialect === "postgres") {
3391
- const p = String(path).trim();
3392
- const pathExpr = /^\$\d+$/.test(p) ? `${p}::text[]` : p;
3393
- return `(${column}#>>${pathExpr})::numeric`;
3394
- }
3395
- return `CAST(json_extract(${column}, ${path}) AS REAL)`;
3396
- }
3397
- function jsonToText(column, dialect) {
3398
- assertNonEmpty(column, "jsonToText column");
3399
- if (dialect === "postgres") {
3400
- return `${column}::text`;
3401
- }
3402
- return column;
3403
- }
3404
- function inArray(column, value, dialect) {
3405
- assertNonEmpty(column, "inArray column");
3406
- assertNonEmpty(value, "inArray value");
3407
- if (dialect === "postgres") {
3408
- return `${column} = ANY(${value})`;
3409
- }
3410
- return `${column} IN (SELECT value FROM json_each(${value}))`;
3411
- }
3412
- function notInArray(column, value, dialect) {
3413
- assertNonEmpty(column, "notInArray column");
3414
- assertNonEmpty(value, "notInArray value");
3415
- if (dialect === "postgres") {
3416
- return `${column} != ALL(${value})`;
3417
- }
3418
- return `${column} NOT IN (SELECT value FROM json_each(${value}))`;
3419
- }
3420
- function getArrayType(prismaType, dialect) {
3421
- if (!prismaType || prismaType.length === 0) {
3422
- return dialect === "sqlite" ? "TEXT" : "text[]";
3423
- }
3424
- if (dialect === "sqlite") {
3425
- return "TEXT";
3426
- }
3427
- const baseType = prismaType.replace(/\[\]|\?/g, "");
3428
- switch (baseType) {
3429
- case "String":
3430
- return "text[]";
3431
- case "Int":
3432
- return "integer[]";
3433
- case "Float":
3434
- return "double precision[]";
3435
- case "Decimal":
3436
- return "numeric[]";
3437
- case "Boolean":
3438
- return "boolean[]";
3439
- case "BigInt":
3440
- return "bigint[]";
3441
- case "DateTime":
3442
- return "timestamptz[]";
3443
- default:
3444
- return `"${baseType}"[]`;
3445
- }
3446
- }
3447
- function jsonAgg(content, dialect) {
3448
- assertNonEmpty(content, "jsonAgg content");
3449
- if (dialect === "postgres") {
3450
- return `json_agg(${content})`;
3451
- }
3452
- return `json_group_array(${content})`;
3453
- }
3454
- function jsonBuildObject(pairs, dialect) {
3455
- const safePairs = (pairs != null ? pairs : "").trim();
3456
- if (dialect === "postgres") {
3457
- return safePairs.length > 0 ? `json_build_object(${safePairs})` : `json_build_object()`;
3458
- }
3459
- return safePairs.length > 0 ? `json_object(${safePairs})` : `json_object()`;
3460
- }
3461
- function prepareArrayParam(value, dialect) {
3462
- if (!Array.isArray(value)) {
3463
- throw new Error("prepareArrayParam requires array value");
3464
- }
3465
- if (dialect === "postgres") {
3466
- return value.map((v) => normalizeValue(v));
3467
- }
3468
- return JSON.stringify(value.map((v) => normalizeValue(v)));
3469
- }
3470
3470
  function normalizeIntLike(name, v, opts = {}) {
3471
3471
  var _a3, _b;
3472
3472
  if (!isNotNullish(v)) return void 0;
@@ -7153,7 +7153,6 @@ var DEFAULT_SELECT_CACHE = /* @__PURE__ */ new WeakMap();
7153
7153
  function toSelectEntries(select2) {
7154
7154
  const out = [];
7155
7155
  for (const [k, v] of Object.entries(select2)) {
7156
- if (k === "_count") continue;
7157
7156
  if (v !== false && v !== void 0) out.push([k, v]);
7158
7157
  }
7159
7158
  return out;
@@ -7246,7 +7245,9 @@ function validateFieldKeys(entries, scalarSet, relationSet, allowCount = false)
7246
7245
  if (!scalarSet.has(k) && !relationSet.has(k)) unknown.push(k);
7247
7246
  }
7248
7247
  if (unknown.length > 0) {
7249
- throw new Error(`Select contains unknown fields: ${unknown.join(", ")}`);
7248
+ throw new Error(
7249
+ `Unknown field '${unknown.join("', '")}' does not exist on this model`
7250
+ );
7250
7251
  }
7251
7252
  }
7252
7253
  function buildSelectedScalarParts(entries, scalarNames, alias, model) {
@@ -7427,23 +7428,56 @@ function buildNestedToOneJoins(relations, baseAlias, baseModel, aliasGen, dialec
7427
7428
  }
7428
7429
  return { joins, aliasMap };
7429
7430
  }
7430
- function buildNestedToOneSelects(relations, aliasMap) {
7431
+ function buildNestedToOneSelects(relations, aliasMap, dialect) {
7431
7432
  const selects = [];
7432
7433
  for (const rel of relations) {
7433
7434
  const relAlias = aliasMap.get(rel.name);
7434
7435
  if (!relAlias) continue;
7435
7436
  const relSelect = buildRelationSelect(rel.args, rel.model, relAlias);
7436
7437
  if (!relSelect || relSelect.trim().length === 0) continue;
7437
- selects.push(`${sqlStringLiteral(rel.name)}, ${relSelect}`);
7438
+ const jsonExpr = jsonBuildObject(relSelect, dialect);
7439
+ const pkField = getPrimaryKeyField(rel.model);
7440
+ const pkCol = `${relAlias}.${quoteColumn(rel.model, pkField)}`;
7441
+ const nullSafeExpr = `CASE WHEN ${pkCol} IS NOT NULL THEN ${jsonExpr} ELSE NULL END`;
7442
+ selects.push(`${sqlStringLiteral(rel.name)}, ${nullSafeExpr}`);
7438
7443
  }
7439
7444
  return selects;
7440
7445
  }
7446
+ function extractCountSelectFromRelArgs(relArgs) {
7447
+ if (!isPlainObject(relArgs)) return null;
7448
+ const obj = relArgs;
7449
+ if (!isPlainObject(obj.select)) return null;
7450
+ const sel = obj.select;
7451
+ const countRaw = sel["_count"];
7452
+ if (!countRaw) return null;
7453
+ if (isPlainObject(countRaw) && "select" in countRaw) {
7454
+ return countRaw.select;
7455
+ }
7456
+ return null;
7457
+ }
7441
7458
  function buildSelectWithNestedIncludes(relArgs, relModel, relAlias, ctx) {
7442
7459
  const nestedToOnes = extractNestedToOneRelations(
7443
7460
  relArgs,
7444
7461
  relModel,
7445
7462
  ctx.schemaByName
7446
7463
  );
7464
+ const countSelect = extractCountSelectFromRelArgs(relArgs);
7465
+ const countJoins = [];
7466
+ function appendCountToSelect(baseSelect2) {
7467
+ if (!countSelect || Object.keys(countSelect).length === 0) return baseSelect2;
7468
+ const countBuild = buildRelationCountSql(
7469
+ countSelect,
7470
+ relModel,
7471
+ ctx.schemas,
7472
+ relAlias,
7473
+ ctx.params,
7474
+ ctx.dialect
7475
+ );
7476
+ if (!countBuild.jsonPairs) return baseSelect2;
7477
+ countJoins.push(...countBuild.joins);
7478
+ const countExpr = `'_count', ${jsonBuildObject(countBuild.jsonPairs, ctx.dialect)}`;
7479
+ return baseSelect2 ? `${baseSelect2}${SQL_SEPARATORS.FIELD_LIST}${countExpr}` : countExpr;
7480
+ }
7447
7481
  if (nestedToOnes.length === 0) {
7448
7482
  let relSelect = buildRelationSelect(relArgs, relModel, relAlias);
7449
7483
  let nestedIncludes = [];
@@ -7472,7 +7506,8 @@ function buildSelectWithNestedIncludes(relArgs, relModel, relAlias, ctx) {
7472
7506
  ).join(SQL_SEPARATORS.FIELD_LIST);
7473
7507
  relSelect = isNotNullish(relSelect) && relSelect.trim().length > 0 ? `${relSelect}${SQL_SEPARATORS.FIELD_LIST}${nestedSelects2}` : nestedSelects2;
7474
7508
  }
7475
- return { select: relSelect, nestedJoins: [] };
7509
+ relSelect = appendCountToSelect(relSelect);
7510
+ return { select: relSelect, nestedJoins: countJoins };
7476
7511
  }
7477
7512
  const { joins, aliasMap } = buildNestedToOneJoins(
7478
7513
  nestedToOnes,
@@ -7482,7 +7517,11 @@ function buildSelectWithNestedIncludes(relArgs, relModel, relAlias, ctx) {
7482
7517
  ctx.dialect
7483
7518
  );
7484
7519
  const baseSelect = buildRelationSelect(relArgs, relModel, relAlias);
7485
- const nestedSelects = buildNestedToOneSelects(nestedToOnes, aliasMap);
7520
+ const nestedSelects = buildNestedToOneSelects(
7521
+ nestedToOnes,
7522
+ aliasMap,
7523
+ ctx.dialect
7524
+ );
7486
7525
  const allParts = [];
7487
7526
  if (baseSelect && baseSelect.trim().length > 0) {
7488
7527
  allParts.push(baseSelect);
@@ -7490,9 +7529,11 @@ function buildSelectWithNestedIncludes(relArgs, relModel, relAlias, ctx) {
7490
7529
  for (const ns of nestedSelects) {
7491
7530
  allParts.push(ns);
7492
7531
  }
7532
+ let finalSelect = allParts.join(SQL_SEPARATORS.FIELD_LIST);
7533
+ finalSelect = appendCountToSelect(finalSelect);
7493
7534
  return {
7494
- select: allParts.join(SQL_SEPARATORS.FIELD_LIST),
7495
- nestedJoins: joins
7535
+ select: finalSelect,
7536
+ nestedJoins: [...joins, ...countJoins]
7496
7537
  };
7497
7538
  }
7498
7539
  function buildWhereParts(whereInput, relModel, relAlias, ctx) {
@@ -7874,7 +7915,7 @@ function validateDistinct(model, distinct) {
7874
7915
  const relationSet = getRelationFieldSet(model);
7875
7916
  if (relationSet.has(f)) {
7876
7917
  throw new Error(
7877
- `distinct field '${f}' is a relation. Only scalar fields are allowed.
7918
+ `distinct field '${f}' is a relation field. Only scalar fields are allowed.
7878
7919
  Available scalar fields: ${[...scalarSet].join(", ")}`
7879
7920
  );
7880
7921
  }
@@ -7912,7 +7953,7 @@ function validateOrderBy(model, orderBy) {
7912
7953
  if (!scalarSet.has(f)) {
7913
7954
  if (relationSet.has(f)) {
7914
7955
  throw new Error(
7915
- `orderBy field '${f}' is a relation. Only scalar fields are allowed.
7956
+ `orderBy field '${f}' is a relation field. Only scalar fields are allowed.
7916
7957
  Available scalar fields: ${[...scalarSet].join(", ")}`
7917
7958
  );
7918
7959
  }