@zenstackhq/orm 3.1.0 → 3.2.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/index.cjs CHANGED
@@ -39,6 +39,7 @@ __export(src_exports, {
39
39
  CRUD_EXT: () => CRUD_EXT,
40
40
  DbNull: () => DbNull,
41
41
  DbNullClass: () => DbNullClass,
42
+ InputValidator: () => InputValidator,
42
43
  JsonNull: () => JsonNull,
43
44
  JsonNullClass: () => JsonNullClass,
44
45
  KyselyUtils: () => kysely_utils_exports,
@@ -653,6 +654,7 @@ var import_ts_pattern5 = require("ts-pattern");
653
654
  var import_common_helpers3 = require("@zenstackhq/common-helpers");
654
655
  var import_decimal = __toESM(require("decimal.js"), 1);
655
656
  var import_kysely3 = require("kysely");
657
+ var import_postgres_array = require("postgres-array");
656
658
  var import_ts_pattern3 = require("ts-pattern");
657
659
  var import_zod = __toESM(require("zod"), 1);
658
660
 
@@ -700,7 +702,7 @@ var BaseCrudDialect = class {
700
702
  transformPrimitive(value, _type, _forArrayField) {
701
703
  return value;
702
704
  }
703
- transformOutput(value, _type) {
705
+ transformOutput(value, _type, _array) {
704
706
  return value;
705
707
  }
706
708
  // #region common query builders
@@ -1557,6 +1559,9 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
1557
1559
  } else if (Array.isArray(value)) {
1558
1560
  if (type === "Json" && !forArrayField) {
1559
1561
  return JSON.stringify(value);
1562
+ }
1563
+ if (isEnum(this.schema, type)) {
1564
+ return this.eb.cast(import_kysely3.sql`ARRAY[${import_kysely3.sql.join(value.map((v) => this.transformPrimitive(v, type, false)), import_kysely3.sql.raw(","))}]`, this.createSchemaQualifiedEnumType(type, true));
1560
1565
  } else {
1561
1566
  return value.map((v) => this.transformPrimitive(v, type, false));
1562
1567
  }
@@ -1570,11 +1575,29 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
1570
1575
  }).otherwise(() => value);
1571
1576
  }
1572
1577
  }
1573
- transformOutput(value, type) {
1578
+ createSchemaQualifiedEnumType(type, array) {
1579
+ let qualified = type;
1580
+ const enumDef = getEnum(this.schema, type);
1581
+ if (enumDef) {
1582
+ const schemaAttr = enumDef.attributes?.find((attr) => attr.name === "@@schema");
1583
+ if (schemaAttr) {
1584
+ const mapArg = schemaAttr.args?.find((arg) => arg.name === "map");
1585
+ if (mapArg && mapArg.value.kind === "literal") {
1586
+ const schemaName = mapArg.value.value;
1587
+ qualified = `"${schemaName}"."${type}"`;
1588
+ }
1589
+ } else {
1590
+ const defaultSchema = this.schema.provider.defaultSchema ?? "public";
1591
+ qualified = `"${defaultSchema}"."${type}"`;
1592
+ }
1593
+ }
1594
+ return array ? import_kysely3.sql.raw(`${qualified}[]`) : import_kysely3.sql.raw(qualified);
1595
+ }
1596
+ transformOutput(value, type, array) {
1574
1597
  if (value === null || value === void 0) {
1575
1598
  return value;
1576
1599
  }
1577
- return (0, import_ts_pattern3.match)(type).with("DateTime", () => this.transformOutputDate(value)).with("Bytes", () => this.transformOutputBytes(value)).with("BigInt", () => this.transformOutputBigInt(value)).with("Decimal", () => this.transformDecimal(value)).otherwise(() => super.transformOutput(value, type));
1600
+ return (0, import_ts_pattern3.match)(type).with("DateTime", () => this.transformOutputDate(value)).with("Bytes", () => this.transformOutputBytes(value)).with("BigInt", () => this.transformOutputBigInt(value)).with("Decimal", () => this.transformDecimal(value)).when((type2) => isEnum(this.schema, type2), () => this.transformOutputEnum(value, array)).otherwise(() => super.transformOutput(value, type, array));
1578
1601
  }
1579
1602
  transformOutputBigInt(value) {
1580
1603
  if (typeof value === "bigint") {
@@ -1607,6 +1630,15 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
1607
1630
  transformOutputBytes(value) {
1608
1631
  return Buffer.isBuffer(value) ? Uint8Array.from(value) : typeof value === "string" && value.startsWith("\\x") ? Uint8Array.from(Buffer.from(value.slice(2), "hex")) : value;
1609
1632
  }
1633
+ transformOutputEnum(value, array) {
1634
+ if (array && typeof value === "string") {
1635
+ try {
1636
+ return (0, import_postgres_array.parse)(value);
1637
+ } catch {
1638
+ }
1639
+ }
1640
+ return value;
1641
+ }
1610
1642
  buildRelationSelection(query, model, relationField, parentAlias, payload) {
1611
1643
  const relationResultName = `${parentAlias}$${relationField}`;
1612
1644
  const joinedQuery = this.buildRelationJSON(model, query, relationField, parentAlias, payload, relationResultName);
@@ -1837,13 +1869,13 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
1837
1869
  return (0, import_ts_pattern4.match)(type).with("Boolean", () => value ? 1 : 0).with("DateTime", () => value instanceof Date ? value.toISOString() : typeof value === "string" ? new Date(value).toISOString() : value).with("Decimal", () => value.toString()).with("Bytes", () => Buffer.from(value)).otherwise(() => value);
1838
1870
  }
1839
1871
  }
1840
- transformOutput(value, type) {
1872
+ transformOutput(value, type, array) {
1841
1873
  if (value === null || value === void 0) {
1842
1874
  return value;
1843
1875
  } else if (this.schema.typeDefs && type in this.schema.typeDefs) {
1844
1876
  return this.transformOutputJson(value);
1845
1877
  } else {
1846
- return (0, import_ts_pattern4.match)(type).with("Boolean", () => this.transformOutputBoolean(value)).with("DateTime", () => this.transformOutputDate(value)).with("Bytes", () => this.transformOutputBytes(value)).with("Decimal", () => this.transformOutputDecimal(value)).with("BigInt", () => this.transformOutputBigInt(value)).with("Json", () => this.transformOutputJson(value)).otherwise(() => super.transformOutput(value, type));
1878
+ return (0, import_ts_pattern4.match)(type).with("Boolean", () => this.transformOutputBoolean(value)).with("DateTime", () => this.transformOutputDate(value)).with("Bytes", () => this.transformOutputBytes(value)).with("Decimal", () => this.transformOutputDecimal(value)).with("BigInt", () => this.transformOutputBigInt(value)).with("Json", () => this.transformOutputJson(value)).otherwise(() => super.transformOutput(value, type, array));
1847
1879
  }
1848
1880
  }
1849
1881
  transformOutputDecimal(value) {
@@ -2123,6 +2155,21 @@ var BaseOperationHandler = class {
2123
2155
  select: this.makeIdSelect(model)
2124
2156
  });
2125
2157
  }
2158
+ async existsNonUnique(kysely, model, filter) {
2159
+ const query = kysely.selectNoFrom((eb) => eb.exists(this.dialect.buildSelectModel(model, model).select(import_kysely5.sql.lit(1).as("$t")).where(() => this.dialect.buildFilter(model, model, filter))).as("exists")).modifyEnd(this.makeContextComment({
2160
+ model,
2161
+ operation: "read"
2162
+ }));
2163
+ let result = [];
2164
+ const compiled = kysely.getExecutor().compileQuery(query.toOperationNode(), (0, import_kysely5.createQueryId)());
2165
+ try {
2166
+ const r = await kysely.getExecutor().executeQuery(compiled);
2167
+ result = r.rows;
2168
+ } catch (err) {
2169
+ throw createDBQueryError(`Failed to execute query: ${err}`, err, compiled.sql, compiled.parameters);
2170
+ }
2171
+ return !!result[0]?.exists;
2172
+ }
2126
2173
  async read(kysely, model, args) {
2127
2174
  let query = this.dialect.buildSelectModel(model, model);
2128
2175
  if (args) {
@@ -2146,7 +2193,7 @@ var BaseOperationHandler = class {
2146
2193
  const r = await kysely.getExecutor().executeQuery(compiled);
2147
2194
  result = r.rows;
2148
2195
  } catch (err) {
2149
- throw createDBQueryError("Failed to execute query", err, compiled.sql, compiled.parameters);
2196
+ throw createDBQueryError(`Failed to execute query: ${err}`, err, compiled.sql, compiled.parameters);
2150
2197
  }
2151
2198
  return result;
2152
2199
  }
@@ -3734,6 +3781,18 @@ var FindOperationHandler = class extends BaseOperationHandler {
3734
3781
  }
3735
3782
  };
3736
3783
 
3784
+ // src/client/crud/operations/exists.ts
3785
+ var ExistsOperationHandler = class extends BaseOperationHandler {
3786
+ static {
3787
+ __name(this, "ExistsOperationHandler");
3788
+ }
3789
+ async handle(_operation, args) {
3790
+ const normalizedArgs = this.normalizeArgs(args);
3791
+ const parsedArgs = this.inputValidator.validateExistsArgs(this.model, normalizedArgs);
3792
+ return await this.existsNonUnique(this.client.$qb, this.model, parsedArgs?.where);
3793
+ }
3794
+ };
3795
+
3737
3796
  // src/client/crud/operations/group-by.ts
3738
3797
  var import_ts_pattern10 = require("ts-pattern");
3739
3798
  var GroupByOperationHandler = class extends BaseOperationHandler {
@@ -4350,9 +4409,96 @@ var InputValidator = class {
4350
4409
  get extraValidationsEnabled() {
4351
4410
  return this.client.$options.validateInput !== false;
4352
4411
  }
4412
+ validateProcedureInput(proc, input) {
4413
+ const procDef = (this.schema.procedures ?? {})[proc];
4414
+ (0, import_common_helpers7.invariant)(procDef, `Procedure "${proc}" not found in schema`);
4415
+ const params = Object.values(procDef.params ?? {});
4416
+ if (typeof input === "undefined") {
4417
+ if (params.length === 0) {
4418
+ return void 0;
4419
+ }
4420
+ if (params.every((p) => p.optional)) {
4421
+ return void 0;
4422
+ }
4423
+ throw createInvalidInputError("Missing procedure arguments", `$procs.${proc}`);
4424
+ }
4425
+ if (typeof input !== "object") {
4426
+ throw createInvalidInputError("Procedure input must be an object", `$procs.${proc}`);
4427
+ }
4428
+ const envelope = input;
4429
+ const argsPayload = Object.prototype.hasOwnProperty.call(envelope, "args") ? envelope.args : void 0;
4430
+ if (params.length === 0) {
4431
+ if (typeof argsPayload === "undefined") {
4432
+ return input;
4433
+ }
4434
+ if (!argsPayload || typeof argsPayload !== "object" || Array.isArray(argsPayload)) {
4435
+ throw createInvalidInputError("Procedure `args` must be an object", `$procs.${proc}`);
4436
+ }
4437
+ if (Object.keys(argsPayload).length === 0) {
4438
+ return input;
4439
+ }
4440
+ throw createInvalidInputError("Procedure does not accept arguments", `$procs.${proc}`);
4441
+ }
4442
+ if (typeof argsPayload === "undefined") {
4443
+ if (params.every((p) => p.optional)) {
4444
+ return input;
4445
+ }
4446
+ throw createInvalidInputError("Missing procedure arguments", `$procs.${proc}`);
4447
+ }
4448
+ if (!argsPayload || typeof argsPayload !== "object" || Array.isArray(argsPayload)) {
4449
+ throw createInvalidInputError("Procedure `args` must be an object", `$procs.${proc}`);
4450
+ }
4451
+ const obj = argsPayload;
4452
+ for (const param of params) {
4453
+ const value = obj[param.name];
4454
+ if (!Object.prototype.hasOwnProperty.call(obj, param.name)) {
4455
+ if (param.optional) {
4456
+ continue;
4457
+ }
4458
+ throw createInvalidInputError(`Missing procedure argument: ${param.name}`, `$procs.${proc}`);
4459
+ }
4460
+ if (typeof value === "undefined") {
4461
+ if (param.optional) {
4462
+ continue;
4463
+ }
4464
+ throw createInvalidInputError(`Invalid procedure argument: ${param.name} is required`, `$procs.${proc}`);
4465
+ }
4466
+ const schema = this.makeProcedureParamSchema(param);
4467
+ const parsed = schema.safeParse(value);
4468
+ if (!parsed.success) {
4469
+ throw createInvalidInputError(`Invalid procedure argument: ${param.name}: ${formatError(parsed.error)}`, `$procs.${proc}`);
4470
+ }
4471
+ }
4472
+ return input;
4473
+ }
4474
+ makeProcedureParamSchema(param) {
4475
+ let schema;
4476
+ if (isTypeDef(this.schema, param.type)) {
4477
+ schema = this.makeTypeDefSchema(param.type);
4478
+ } else if (isEnum(this.schema, param.type)) {
4479
+ schema = this.makeEnumSchema(param.type);
4480
+ } else if (param.type in (this.schema.models ?? {})) {
4481
+ schema = import_zod3.z.record(import_zod3.z.string(), import_zod3.z.unknown());
4482
+ } else {
4483
+ schema = this.makeScalarSchema(param.type);
4484
+ if (schema instanceof import_zod3.z.ZodUnknown) {
4485
+ throw createInternalError(`Unsupported procedure parameter type: ${param.type}`);
4486
+ }
4487
+ }
4488
+ if (param.array) {
4489
+ schema = schema.array();
4490
+ }
4491
+ if (param.optional) {
4492
+ schema = schema.optional();
4493
+ }
4494
+ return schema;
4495
+ }
4353
4496
  validateFindArgs(model, args, options) {
4354
4497
  return this.validate(model, "find", options, (model2, options2) => this.makeFindSchema(model2, options2), args);
4355
4498
  }
4499
+ validateExistsArgs(model, args) {
4500
+ return this.validate(model, "exists", void 0, (model2) => this.makeExistsSchema(model2), args);
4501
+ }
4356
4502
  validateCreateArgs(model, args) {
4357
4503
  return this.validate(model, "create", void 0, (model2) => this.makeCreateSchema(model2), args);
4358
4504
  }
@@ -4457,6 +4603,11 @@ var InputValidator = class {
4457
4603
  }
4458
4604
  return result;
4459
4605
  }
4606
+ makeExistsSchema(model) {
4607
+ return import_zod3.z.strictObject({
4608
+ where: this.makeWhereSchema(model, false).optional()
4609
+ }).optional();
4610
+ }
4460
4611
  makeScalarSchema(type, attributes) {
4461
4612
  if (this.schema.typeDefs && type in this.schema.typeDefs) {
4462
4613
  return this.makeTypeDefSchema(type);
@@ -4518,8 +4669,11 @@ var InputValidator = class {
4518
4669
  fieldSchema
4519
4670
  ];
4520
4671
  })));
4521
- const finalSchema = import_zod3.z.custom((v) => {
4522
- return schema.safeParse(v).success;
4672
+ const finalSchema = import_zod3.z.any().superRefine((value, ctx) => {
4673
+ const parseResult = schema.safeParse(value);
4674
+ if (!parseResult.success) {
4675
+ parseResult.error.issues.forEach((issue) => ctx.addIssue(issue));
4676
+ }
4523
4677
  });
4524
4678
  this.setSchemaCache(key, finalSchema);
4525
4679
  return finalSchema;
@@ -4558,7 +4712,7 @@ var InputValidator = class {
4558
4712
  const enumDef = getEnum(this.schema, fieldDef.type);
4559
4713
  if (enumDef) {
4560
4714
  if (Object.keys(enumDef.values).length > 0) {
4561
- fieldSchema = this.makeEnumFilterSchema(enumDef, !!fieldDef.optional, withAggregations);
4715
+ fieldSchema = this.makeEnumFilterSchema(enumDef, !!fieldDef.optional, withAggregations, !!fieldDef.array);
4562
4716
  }
4563
4717
  } else if (fieldDef.array) {
4564
4718
  fieldSchema = this.makeArrayFilterSchema(fieldDef.type);
@@ -4582,7 +4736,7 @@ var InputValidator = class {
4582
4736
  const enumDef = getEnum(this.schema, def.type);
4583
4737
  if (enumDef) {
4584
4738
  if (Object.keys(enumDef.values).length > 0) {
4585
- fieldSchema = this.makeEnumFilterSchema(enumDef, !!def.optional, false);
4739
+ fieldSchema = this.makeEnumFilterSchema(enumDef, !!def.optional, false, false);
4586
4740
  } else {
4587
4741
  fieldSchema = import_zod3.z.never();
4588
4742
  }
@@ -4597,7 +4751,9 @@ var InputValidator = class {
4597
4751
  }
4598
4752
  }
4599
4753
  }
4600
- fields["$expr"] = import_zod3.z.custom((v) => typeof v === "function").optional();
4754
+ fields["$expr"] = import_zod3.z.custom((v) => typeof v === "function", {
4755
+ error: '"$expr" must be a function'
4756
+ }).optional();
4601
4757
  fields["AND"] = this.orArray(import_zod3.z.lazy(() => this.makeWhereSchema(model, false, withoutRelationFields)), true).optional();
4602
4758
  fields["OR"] = import_zod3.z.lazy(() => this.makeWhereSchema(model, false, withoutRelationFields)).array().optional();
4603
4759
  fields["NOT"] = this.orArray(import_zod3.z.lazy(() => this.makeWhereSchema(model, false, withoutRelationFields)), true).optional();
@@ -4630,15 +4786,13 @@ var InputValidator = class {
4630
4786
  if (this.isTypeDefType(fieldDef.type)) {
4631
4787
  fieldSchemas[fieldName] = this.makeTypedJsonFilterSchema(fieldDef.type, !!fieldDef.optional, !!fieldDef.array).optional();
4632
4788
  } else {
4633
- if (fieldDef.array) {
4789
+ const enumDef = getEnum(this.schema, fieldDef.type);
4790
+ if (enumDef) {
4791
+ fieldSchemas[fieldName] = this.makeEnumFilterSchema(enumDef, !!fieldDef.optional, false, !!fieldDef.array).optional();
4792
+ } else if (fieldDef.array) {
4634
4793
  fieldSchemas[fieldName] = this.makeArrayFilterSchema(fieldDef.type).optional();
4635
4794
  } else {
4636
- const enumDef = getEnum(this.schema, fieldDef.type);
4637
- if (enumDef) {
4638
- fieldSchemas[fieldName] = this.makeEnumFilterSchema(enumDef, !!fieldDef.optional, false).optional();
4639
- } else {
4640
- fieldSchemas[fieldName] = this.makePrimitiveFilterSchema(fieldDef.type, !!fieldDef.optional, false).optional();
4641
- }
4795
+ fieldSchemas[fieldName] = this.makePrimitiveFilterSchema(fieldDef.type, !!fieldDef.optional, false).optional();
4642
4796
  }
4643
4797
  }
4644
4798
  }
@@ -4666,9 +4820,12 @@ var InputValidator = class {
4666
4820
  isTypeDefType(type) {
4667
4821
  return this.schema.typeDefs && type in this.schema.typeDefs;
4668
4822
  }
4669
- makeEnumFilterSchema(enumDef, optional, withAggregations) {
4823
+ makeEnumFilterSchema(enumDef, optional, withAggregations, array) {
4670
4824
  const baseSchema = import_zod3.z.enum(Object.keys(enumDef.values));
4671
- const components = this.makeCommonPrimitiveFilterComponents(baseSchema, optional, () => import_zod3.z.lazy(() => this.makeEnumFilterSchema(enumDef, optional, withAggregations)), [
4825
+ if (array) {
4826
+ return this.internalMakeArrayFilterSchema(baseSchema);
4827
+ }
4828
+ const components = this.makeCommonPrimitiveFilterComponents(baseSchema, optional, () => import_zod3.z.lazy(() => this.makeEnumFilterSchema(enumDef, optional, withAggregations, array)), [
4672
4829
  "equals",
4673
4830
  "in",
4674
4831
  "notIn",
@@ -4684,11 +4841,14 @@ var InputValidator = class {
4684
4841
  ]);
4685
4842
  }
4686
4843
  makeArrayFilterSchema(type) {
4844
+ return this.internalMakeArrayFilterSchema(this.makeScalarSchema(type));
4845
+ }
4846
+ internalMakeArrayFilterSchema(elementSchema) {
4687
4847
  return import_zod3.z.strictObject({
4688
- equals: this.makeScalarSchema(type).array().optional(),
4689
- has: this.makeScalarSchema(type).optional(),
4690
- hasEvery: this.makeScalarSchema(type).array().optional(),
4691
- hasSome: this.makeScalarSchema(type).array().optional(),
4848
+ equals: elementSchema.array().optional(),
4849
+ has: elementSchema.optional(),
4850
+ hasEvery: elementSchema.array().optional(),
4851
+ hasSome: elementSchema.array().optional(),
4692
4852
  isEmpty: import_zod3.z.boolean().optional()
4693
4853
  });
4694
4854
  }
@@ -5748,14 +5908,16 @@ var QueryNameMapper = class extends import_kysely6.OperationNodeTransformer {
5748
5908
  return super.transformSelectQuery(node);
5749
5909
  }
5750
5910
  const processedFroms = node.from.froms.map((from) => this.processSelectTable(from));
5751
- const processedJoins = this.withScopes([
5911
+ const processedJoins = [];
5912
+ const cumulativeScopes = [
5752
5913
  ...processedFroms.map(({ scope }) => scope)
5753
- ], () => (node.joins ?? []).map((join) => this.processSelectTable(join.table)));
5754
- const scopes = [
5755
- ...processedFroms.map(({ scope }) => scope),
5756
- ...processedJoins.map(({ scope }) => scope)
5757
5914
  ];
5758
- return this.withScopes(scopes, () => {
5915
+ for (const join of node.joins ?? []) {
5916
+ const processedJoin = this.withScopes(cumulativeScopes, () => this.processSelectTable(join.table));
5917
+ processedJoins.push(processedJoin);
5918
+ cumulativeScopes.push(processedJoin.scope);
5919
+ }
5920
+ return this.withScopes(cumulativeScopes, () => {
5759
5921
  const joins = node.joins ? node.joins.map((join, i) => ({
5760
5922
  ...join,
5761
5923
  table: processedJoins[i].node,
@@ -6090,9 +6252,9 @@ var QueryNameMapper = class extends import_kysely6.OperationNodeTransformer {
6090
6252
  let schema = this.schema.provider.defaultSchema ?? "public";
6091
6253
  const schemaAttr = this.schema.models[model]?.attributes?.find((attr) => attr.name === "@@schema");
6092
6254
  if (schemaAttr) {
6093
- const nameArg = schemaAttr.args?.find((arg) => arg.name === "map");
6094
- if (nameArg && nameArg.value.kind === "literal") {
6095
- schema = nameArg.value.value;
6255
+ const mapArg = schemaAttr.args?.find((arg) => arg.name === "map");
6256
+ if (mapArg && mapArg.value.kind === "literal") {
6257
+ schema = mapArg.value.value;
6096
6258
  }
6097
6259
  }
6098
6260
  return schema;
@@ -6343,7 +6505,7 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends import_kysely7.
6343
6505
  if (err instanceof ORMError) {
6344
6506
  throw err;
6345
6507
  } else {
6346
- throw createDBQueryError("Failed to execute query", err, compiledQuery.sql, compiledQuery.parameters);
6508
+ throw createDBQueryError(`Failed to execute query: ${err}`, err, compiledQuery.sql, compiledQuery.parameters);
6347
6509
  }
6348
6510
  }
6349
6511
  });
@@ -6583,7 +6745,7 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends import_kysely7.
6583
6745
  try {
6584
6746
  return await connection.executeQuery(compiledQuery);
6585
6747
  } catch (err) {
6586
- throw createDBQueryError("Failed to execute query", err, compiledQuery.sql, compiledQuery.parameters);
6748
+ throw createDBQueryError(`Failed to execute query: ${err}`, err, compiledQuery.sql, compiledQuery.parameters);
6587
6749
  }
6588
6750
  }
6589
6751
  };
@@ -7041,7 +7203,7 @@ var ResultProcessor = class {
7041
7203
  }
7042
7204
  if (key.startsWith(DELEGATE_JOINED_FIELD_PREFIX)) {
7043
7205
  if (value) {
7044
- const subRow = this.dialect.transformOutput(value, "Json");
7206
+ const subRow = this.dialect.transformOutput(value, "Json", false);
7045
7207
  const subModel = key.slice(DELEGATE_JOINED_FIELD_PREFIX.length);
7046
7208
  const idValues = getIdValues(this.schema, subModel, subRow);
7047
7209
  if (Object.values(idValues).some((v) => v === null || v === void 0)) {
@@ -7075,10 +7237,10 @@ var ResultProcessor = class {
7075
7237
  processFieldValue(value, fieldDef) {
7076
7238
  const type = fieldDef.type;
7077
7239
  if (Array.isArray(value)) {
7078
- value.forEach((v, i) => value[i] = this.dialect.transformOutput(v, type));
7240
+ value.forEach((v, i) => value[i] = this.dialect.transformOutput(v, type, false));
7079
7241
  return value;
7080
7242
  } else {
7081
- return this.dialect.transformOutput(value, type);
7243
+ return this.dialect.transformOutput(value, type, !!fieldDef.array);
7082
7244
  }
7083
7245
  }
7084
7246
  processRelation(value, fieldDef) {
@@ -7236,24 +7398,54 @@ var ClientImpl = class _ClientImpl {
7236
7398
  return txBuilder.execute((tx) => execute(tx));
7237
7399
  }
7238
7400
  }
7239
- get $procedures() {
7401
+ get $procs() {
7240
7402
  return Object.keys(this.$schema.procedures ?? {}).reduce((acc, name) => {
7241
- acc[name] = (...args) => this.handleProc(name, args);
7403
+ acc[name] = (input) => this.handleProc(name, input);
7242
7404
  return acc;
7243
7405
  }, {});
7244
7406
  }
7245
- async handleProc(name, args) {
7407
+ async handleProc(name, input) {
7246
7408
  if (!("procedures" in this.$options) || !this.$options || typeof this.$options.procedures !== "object") {
7247
7409
  throw createConfigError("Procedures are not configured for the client.");
7248
7410
  }
7411
+ const procDef = (this.$schema.procedures ?? {})[name];
7412
+ if (!procDef) {
7413
+ throw createConfigError(`Procedure "${name}" is not defined in schema.`);
7414
+ }
7249
7415
  const procOptions = this.$options.procedures;
7250
7416
  if (!procOptions[name] || typeof procOptions[name] !== "function") {
7251
- throw new Error(`Procedure "${name}" does not have a handler configured.`);
7252
- }
7253
- return procOptions[name].apply(this, [
7254
- this,
7255
- ...args
7256
- ]);
7417
+ throw createConfigError(`Procedure "${name}" does not have a handler configured.`);
7418
+ }
7419
+ const inputValidator = new InputValidator(this);
7420
+ const validatedInput = inputValidator.validateProcedureInput(name, input);
7421
+ const handler = procOptions[name];
7422
+ const invokeWithClient = /* @__PURE__ */ __name(async (client, _input) => {
7423
+ let proceed = /* @__PURE__ */ __name(async (nextInput) => {
7424
+ const sanitizedNextInput = nextInput && typeof nextInput === "object" && !Array.isArray(nextInput) ? nextInput : {};
7425
+ return handler({
7426
+ client,
7427
+ ...sanitizedNextInput
7428
+ });
7429
+ }, "proceed");
7430
+ const plugins = [
7431
+ ...client.$options?.plugins ?? []
7432
+ ];
7433
+ for (const plugin of plugins) {
7434
+ const onProcedure = plugin.onProcedure;
7435
+ if (onProcedure) {
7436
+ const _proceed = proceed;
7437
+ proceed = /* @__PURE__ */ __name((nextInput) => onProcedure({
7438
+ client,
7439
+ name,
7440
+ mutation: !!procDef.mutation,
7441
+ input: nextInput,
7442
+ proceed: /* @__PURE__ */ __name((finalInput) => _proceed(finalInput), "proceed")
7443
+ }), "proceed");
7444
+ }
7445
+ }
7446
+ return proceed(_input);
7447
+ }, "invokeWithClient");
7448
+ return invokeWithClient(this, validatedInput);
7257
7449
  }
7258
7450
  async $connect() {
7259
7451
  await this.kysely.connection().execute(async (conn) => {
@@ -7460,7 +7652,10 @@ function createModelCrudHandler(client, model, inputValidator, resultProcessor)
7460
7652
  }, "aggregate"),
7461
7653
  groupBy: /* @__PURE__ */ __name((args) => {
7462
7654
  return createPromise("groupBy", "groupBy", args, new GroupByOperationHandler(client, model, inputValidator), true);
7463
- }, "groupBy")
7655
+ }, "groupBy"),
7656
+ exists: /* @__PURE__ */ __name((args) => {
7657
+ return createPromise("exists", "exists", args, new ExistsOperationHandler(client, model, inputValidator), false);
7658
+ }, "exists")
7464
7659
  };
7465
7660
  }
7466
7661
  __name(createModelCrudHandler, "createModelCrudHandler");
@@ -7892,6 +8087,7 @@ var MatchingExpressionVisitor = class extends ExpressionVisitor {
7892
8087
  CRUD_EXT,
7893
8088
  DbNull,
7894
8089
  DbNullClass,
8090
+ InputValidator,
7895
8091
  JsonNull,
7896
8092
  JsonNullClass,
7897
8093
  KyselyUtils,