@zenstackhq/orm 3.4.6 → 3.5.0-beta.1

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.js CHANGED
@@ -20,6 +20,14 @@ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "defau
20
20
  // src/client/client-impl.ts
21
21
  import { invariant as invariant14, lowerCaseFirst as lowerCaseFirst3 } from "@zenstackhq/common-helpers";
22
22
  import { CompiledQuery, DefaultConnectionProvider, DefaultQueryExecutor as DefaultQueryExecutor2, Kysely, Log, sql as sql8, Transaction } from "kysely";
23
+ import z2 from "zod";
24
+
25
+ // src/utils/zod-utils.ts
26
+ import { fromError } from "zod-validation-error/v4";
27
+ function formatError(error) {
28
+ return fromError(error).toString();
29
+ }
30
+ __name(formatError, "formatError");
23
31
 
24
32
  // src/client/crud/operations/aggregate.ts
25
33
  import { match as match8 } from "ts-pattern";
@@ -4627,13 +4635,6 @@ var UpdateOperationHandler = class extends BaseOperationHandler {
4627
4635
  import { invariant as invariant9 } from "@zenstackhq/common-helpers";
4628
4636
  import { match as match14 } from "ts-pattern";
4629
4637
 
4630
- // src/utils/zod-utils.ts
4631
- import { fromError } from "zod-validation-error/v4";
4632
- function formatError(error) {
4633
- return fromError(error).toString();
4634
- }
4635
- __name(formatError, "formatError");
4636
-
4637
4638
  // src/client/zod/factory.ts
4638
4639
  import { enumerate as enumerate3, invariant as invariant8, lowerCaseFirst } from "@zenstackhq/common-helpers";
4639
4640
  import { ZodUtils } from "@zenstackhq/zod";
@@ -4685,6 +4686,15 @@ function _ts_metadata(k, v) {
4685
4686
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
4686
4687
  }
4687
4688
  __name(_ts_metadata, "_ts_metadata");
4689
+ function toFieldInfo(def) {
4690
+ return {
4691
+ name: def.name,
4692
+ type: def.type,
4693
+ optional: def.optional,
4694
+ array: def.array
4695
+ };
4696
+ }
4697
+ __name(toFieldInfo, "toFieldInfo");
4688
4698
  function createQuerySchemaFactory(clientOrSchema, options) {
4689
4699
  return new ZodSchemaFactory(clientOrSchema, options);
4690
4700
  }
@@ -4699,6 +4709,7 @@ var ZodSchemaFactory = class {
4699
4709
  ];
4700
4710
  schema;
4701
4711
  options;
4712
+ extraValidationsEnabled = true;
4702
4713
  constructor(clientOrSchema, options) {
4703
4714
  if ("$schema" in clientOrSchema) {
4704
4715
  this.schema = clientOrSchema.$schema;
@@ -4711,9 +4722,6 @@ var ZodSchemaFactory = class {
4711
4722
  get plugins() {
4712
4723
  return this.options.plugins ?? [];
4713
4724
  }
4714
- get extraValidationsEnabled() {
4715
- return this.options.validateInput !== false;
4716
- }
4717
4725
  shouldIncludeRelations(options) {
4718
4726
  return options?.relationDepth === void 0 || options.relationDepth > 0;
4719
4727
  }
@@ -4734,14 +4742,13 @@ var ZodSchemaFactory = class {
4734
4742
  setCache(cacheKey, schema) {
4735
4743
  return this.schemaCache.set(cacheKey, schema);
4736
4744
  }
4737
- // @ts-ignore
4738
- printCacheStats(detailed = false) {
4739
- console.log("Schema cache size:", this.schemaCache.size);
4740
- if (detailed) {
4741
- for (const key of this.schemaCache.keys()) {
4742
- console.log(` ${key}`);
4743
- }
4744
- }
4745
+ get cacheStats() {
4746
+ return {
4747
+ size: this.schemaCache.size,
4748
+ keys: [
4749
+ ...this.schemaCache.keys()
4750
+ ]
4751
+ };
4745
4752
  }
4746
4753
  // #endregion
4747
4754
  // #region Find
@@ -4889,14 +4896,14 @@ var ZodSchemaFactory = class {
4889
4896
  const enumDef = getEnum(this.schema, fieldDef.type);
4890
4897
  if (enumDef) {
4891
4898
  if (Object.keys(enumDef.values).length > 0) {
4892
- fieldSchema = this.makeEnumFilterSchema(model, fieldDef, withAggregations, ignoreSlicing);
4899
+ fieldSchema = this.makeEnumFilterSchema(model, toFieldInfo(fieldDef), withAggregations, ignoreSlicing);
4893
4900
  }
4894
4901
  } else if (fieldDef.array) {
4895
- fieldSchema = this.makeArrayFilterSchema(model, fieldDef);
4902
+ fieldSchema = this.makeArrayFilterSchema(model, toFieldInfo(fieldDef));
4896
4903
  } else if (this.isTypeDefType(fieldDef.type)) {
4897
- fieldSchema = this.makeTypedJsonFilterSchema(model, fieldDef);
4904
+ fieldSchema = this.makeTypedJsonFilterSchema(model, toFieldInfo(fieldDef));
4898
4905
  } else {
4899
- fieldSchema = this.makePrimitiveFilterSchema(model, fieldDef, withAggregations, ignoreSlicing);
4906
+ fieldSchema = this.makePrimitiveFilterSchema(model, toFieldInfo(fieldDef), withAggregations, ignoreSlicing);
4900
4907
  }
4901
4908
  }
4902
4909
  if (fieldSchema) {
@@ -4913,12 +4920,12 @@ var ZodSchemaFactory = class {
4913
4920
  const enumDef = getEnum(this.schema, def.type);
4914
4921
  if (enumDef) {
4915
4922
  if (Object.keys(enumDef.values).length > 0) {
4916
- fieldSchema = this.makeEnumFilterSchema(model, def, false, true);
4923
+ fieldSchema = this.makeEnumFilterSchema(model, toFieldInfo(def), false, true);
4917
4924
  } else {
4918
4925
  fieldSchema = z.never();
4919
4926
  }
4920
4927
  } else {
4921
- fieldSchema = this.makePrimitiveFilterSchema(model, def, false, true);
4928
+ fieldSchema = this.makePrimitiveFilterSchema(model, toFieldInfo(def), false, true);
4922
4929
  }
4923
4930
  return [
4924
4931
  key,
@@ -4965,15 +4972,15 @@ var ZodSchemaFactory = class {
4965
4972
  const fieldSchemas = {};
4966
4973
  for (const [fieldName, fieldDef] of Object.entries(typeDef.fields)) {
4967
4974
  if (this.isTypeDefType(fieldDef.type)) {
4968
- fieldSchemas[fieldName] = this.makeTypedJsonFilterSchema(contextModel, fieldDef).optional();
4975
+ fieldSchemas[fieldName] = this.makeTypedJsonFilterSchema(contextModel, toFieldInfo(fieldDef)).optional();
4969
4976
  } else {
4970
4977
  const enumDef = getEnum(this.schema, fieldDef.type);
4971
4978
  if (enumDef) {
4972
- fieldSchemas[fieldName] = this.makeEnumFilterSchema(contextModel, fieldDef, false).optional();
4979
+ fieldSchemas[fieldName] = this.makeEnumFilterSchema(contextModel, toFieldInfo(fieldDef), false).optional();
4973
4980
  } else if (fieldDef.array) {
4974
- fieldSchemas[fieldName] = this.makeArrayFilterSchema(contextModel, fieldDef).optional();
4981
+ fieldSchemas[fieldName] = this.makeArrayFilterSchema(contextModel, toFieldInfo(fieldDef)).optional();
4975
4982
  } else {
4976
- fieldSchemas[fieldName] = this.makePrimitiveFilterSchema(contextModel, fieldDef, false).optional();
4983
+ fieldSchemas[fieldName] = this.makePrimitiveFilterSchema(contextModel, toFieldInfo(fieldDef), false).optional();
4977
4984
  }
4978
4985
  }
4979
4986
  }
@@ -6557,9 +6564,11 @@ var InputValidator = class {
6557
6564
  }
6558
6565
  client;
6559
6566
  zodFactory;
6560
- constructor(client) {
6567
+ enabled;
6568
+ constructor(client, options) {
6561
6569
  this.client = client;
6562
6570
  this.zodFactory = new ZodSchemaFactory(client);
6571
+ this.enabled = options?.enabled !== false;
6563
6572
  }
6564
6573
  // #region Entry points
6565
6574
  validateFindArgs(model, args, operation) {
@@ -6606,6 +6615,9 @@ var InputValidator = class {
6606
6615
  }
6607
6616
  // TODO: turn it into a Zod schema and cache
6608
6617
  validateProcedureInput(proc, input) {
6618
+ if (!this.enabled) {
6619
+ return input;
6620
+ }
6609
6621
  const procDef = (this.client.$schema.procedures ?? {})[proc];
6610
6622
  invariant9(procDef, `Procedure "${proc}" not found in schema`);
6611
6623
  const params = Object.values(procDef.params ?? {});
@@ -6670,6 +6682,9 @@ var InputValidator = class {
6670
6682
  // #endregion
6671
6683
  // #region Validation helpers
6672
6684
  validate(model, operation, getSchema, args) {
6685
+ if (!this.enabled) {
6686
+ return args;
6687
+ }
6673
6688
  const schema = getSchema(model);
6674
6689
  const { error, data } = schema.safeParse(args);
6675
6690
  if (error) {
@@ -7504,6 +7519,7 @@ var TempAliasTransformer = class extends OperationNodeTransformer2 {
7504
7519
  };
7505
7520
 
7506
7521
  // src/client/executor/zenstack-query-executor.ts
7522
+ var DEFAULT_MAX_SLOW_RECORDS = 100;
7507
7523
  var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExecutor {
7508
7524
  static {
7509
7525
  __name(this, "ZenStackQueryExecutor");
@@ -7920,13 +7936,49 @@ In such cases, ZenStack cannot reliably determine the IDs of the mutated entitie
7920
7936
  parameters
7921
7937
  };
7922
7938
  }
7939
+ const trackSlowQuery = this.options.diagnostics !== void 0;
7940
+ const startTimestamp = trackSlowQuery ? performance.now() : void 0;
7941
+ const startedAt = trackSlowQuery ? /* @__PURE__ */ new Date() : void 0;
7923
7942
  try {
7924
7943
  const result = await connection.executeQuery(compiledQuery);
7944
+ if (startTimestamp !== void 0) {
7945
+ this.trackSlowQuery(compiledQuery, startTimestamp, startedAt);
7946
+ }
7925
7947
  return this.ensureProperQueryResult(compiledQuery.query, result);
7926
7948
  } catch (err) {
7927
7949
  throw createDBQueryError(`Failed to execute query: ${err}`, err, compiledQuery.sql, compiledQuery.parameters);
7928
7950
  }
7929
7951
  }
7952
+ trackSlowQuery(compiledQuery, startTimestamp, startedAt) {
7953
+ const durationMs = performance.now() - startTimestamp;
7954
+ const thresholdMs = this.options.diagnostics?.slowQueryThresholdMs;
7955
+ if (thresholdMs === void 0 || durationMs < thresholdMs) {
7956
+ return;
7957
+ }
7958
+ const slowQueries = this.client.slowQueries;
7959
+ const maxRecords = this.options.diagnostics?.slowQueryMaxRecords ?? DEFAULT_MAX_SLOW_RECORDS;
7960
+ if (maxRecords <= 0) {
7961
+ return;
7962
+ }
7963
+ const queryInfo = {
7964
+ startedAt,
7965
+ durationMs,
7966
+ sql: compiledQuery.sql
7967
+ };
7968
+ if (slowQueries.length >= maxRecords) {
7969
+ let minIndex = 0;
7970
+ for (let i = 1; i < slowQueries.length; i++) {
7971
+ if (slowQueries[i].durationMs < slowQueries[minIndex].durationMs) {
7972
+ minIndex = i;
7973
+ }
7974
+ }
7975
+ if (durationMs > slowQueries[minIndex].durationMs) {
7976
+ slowQueries[minIndex] = queryInfo;
7977
+ }
7978
+ } else {
7979
+ slowQueries.push(queryInfo);
7980
+ }
7981
+ }
7930
7982
  ensureProperQueryResult(query, result) {
7931
7983
  let finalResult = result;
7932
7984
  if (this.isMutationNode(query)) {
@@ -8598,6 +8650,7 @@ var ClientImpl = class _ClientImpl {
8598
8650
  kyselyProps;
8599
8651
  auth;
8600
8652
  inputValidator;
8653
+ slowQueries = [];
8601
8654
  constructor(schema, options, baseClient, executor) {
8602
8655
  this.schema = schema;
8603
8656
  this.options = options;
@@ -8607,9 +8660,7 @@ var ClientImpl = class _ClientImpl {
8607
8660
  ...functions_exports,
8608
8661
  ...this.$options.functions
8609
8662
  };
8610
- if (!baseClient && !options.skipValidationForComputedFields) {
8611
- this.validateComputedFieldsConfig();
8612
- }
8663
+ this.validateOptions(baseClient, options);
8613
8664
  if (baseClient) {
8614
8665
  this.kyselyProps = {
8615
8666
  ...baseClient.kyselyProps,
@@ -8617,6 +8668,7 @@ var ClientImpl = class _ClientImpl {
8617
8668
  };
8618
8669
  this.kyselyRaw = baseClient.kyselyRaw;
8619
8670
  this.auth = baseClient.auth;
8671
+ this.slowQueries = baseClient.slowQueries;
8620
8672
  } else {
8621
8673
  const driver = new ZenStackDriver(options.dialect.createDriver(), new Log(this.$options.log ?? []));
8622
8674
  const compiler = options.dialect.createQueryCompiler();
@@ -8637,32 +8689,31 @@ var ClientImpl = class _ClientImpl {
8637
8689
  });
8638
8690
  }
8639
8691
  this.kysely = new Kysely(this.kyselyProps);
8640
- this.inputValidator = baseClient?.inputValidator ?? new InputValidator(this);
8692
+ this.inputValidator = baseClient?.inputValidator ?? new InputValidator(this, {
8693
+ enabled: this.$options.validateInput !== false
8694
+ });
8641
8695
  return createClientProxy(this);
8642
8696
  }
8643
- get $qb() {
8644
- return this.kysely;
8645
- }
8646
- get $qbRaw() {
8647
- return this.kyselyRaw;
8648
- }
8649
- get $zod() {
8650
- return this.inputValidator.zodFactory;
8651
- }
8652
- get isTransaction() {
8653
- return this.kysely.isTransaction;
8654
- }
8655
- /**
8656
- * Create a new client with a new query executor.
8657
- */
8658
- withExecutor(executor) {
8659
- return new _ClientImpl(this.schema, this.$options, this, executor);
8697
+ validateOptions(baseClient, options) {
8698
+ if (!baseClient && !options.skipValidationForComputedFields) {
8699
+ this.validateComputedFieldsConfig(options);
8700
+ }
8701
+ if (options.diagnostics) {
8702
+ const diagnosticsSchema = z2.object({
8703
+ slowQueryThresholdMs: z2.number().nonnegative().optional(),
8704
+ slowQueryMaxRecords: z2.int().nonnegative().or(z2.literal(Infinity)).optional()
8705
+ });
8706
+ const parseResult = diagnosticsSchema.safeParse(options.diagnostics);
8707
+ if (!parseResult.success) {
8708
+ throw createConfigError(`Invalid diagnostics configuration: ${formatError(parseResult.error)}`);
8709
+ }
8710
+ }
8660
8711
  }
8661
8712
  /**
8662
8713
  * Validates that all computed fields in the schema have corresponding configurations.
8663
8714
  */
8664
- validateComputedFieldsConfig() {
8665
- const computedFieldsConfig = "computedFields" in this.$options ? this.$options.computedFields : void 0;
8715
+ validateComputedFieldsConfig(options) {
8716
+ const computedFieldsConfig = "computedFields" in options ? options.computedFields : void 0;
8666
8717
  for (const [modelName, modelDef] of Object.entries(this.$schema.models)) {
8667
8718
  if (modelDef.computedFields) {
8668
8719
  for (const fieldName of Object.keys(modelDef.computedFields)) {
@@ -8678,6 +8729,24 @@ var ClientImpl = class _ClientImpl {
8678
8729
  }
8679
8730
  }
8680
8731
  }
8732
+ get $qb() {
8733
+ return this.kysely;
8734
+ }
8735
+ get $qbRaw() {
8736
+ return this.kyselyRaw;
8737
+ }
8738
+ get $zod() {
8739
+ return this.inputValidator.zodFactory;
8740
+ }
8741
+ get isTransaction() {
8742
+ return this.kysely.isTransaction;
8743
+ }
8744
+ /**
8745
+ * Create a new client with a new query executor.
8746
+ */
8747
+ withExecutor(executor) {
8748
+ return new _ClientImpl(this.schema, this.$options, this, executor);
8749
+ }
8681
8750
  // implementation
8682
8751
  async $transaction(input, options) {
8683
8752
  invariant14(typeof input === "function" || Array.isArray(input) && input.every((p) => p.then && p.cb), "Invalid transaction input, expected a function or an array of ZenStackPromise");
@@ -8799,7 +8868,9 @@ var ClientImpl = class _ClientImpl {
8799
8868
  plugins: newPlugins
8800
8869
  };
8801
8870
  const newClient = new _ClientImpl(this.schema, newOptions, this);
8802
- newClient.inputValidator = new InputValidator(newClient);
8871
+ newClient.inputValidator = new InputValidator(newClient, {
8872
+ enabled: newOptions.validateInput !== false
8873
+ });
8803
8874
  return newClient;
8804
8875
  }
8805
8876
  $unuse(pluginId) {
@@ -8814,7 +8885,9 @@ var ClientImpl = class _ClientImpl {
8814
8885
  plugins: newPlugins
8815
8886
  };
8816
8887
  const newClient = new _ClientImpl(this.schema, newOptions, this);
8817
- newClient.inputValidator = new InputValidator(newClient);
8888
+ newClient.inputValidator = new InputValidator(newClient, {
8889
+ enabled: newClient.$options.validateInput !== false
8890
+ });
8818
8891
  return newClient;
8819
8892
  }
8820
8893
  $unuseAll() {
@@ -8823,7 +8896,9 @@ var ClientImpl = class _ClientImpl {
8823
8896
  plugins: []
8824
8897
  };
8825
8898
  const newClient = new _ClientImpl(this.schema, newOptions, this);
8826
- newClient.inputValidator = new InputValidator(newClient);
8899
+ newClient.inputValidator = new InputValidator(newClient, {
8900
+ enabled: newOptions.validateInput !== false
8901
+ });
8827
8902
  return newClient;
8828
8903
  }
8829
8904
  $setAuth(auth) {
@@ -8839,7 +8914,9 @@ var ClientImpl = class _ClientImpl {
8839
8914
  }
8840
8915
  $setOptions(options) {
8841
8916
  const newClient = new _ClientImpl(this.schema, options, this);
8842
- newClient.inputValidator = new InputValidator(newClient);
8917
+ newClient.inputValidator = new InputValidator(newClient, {
8918
+ enabled: newClient.$options.validateInput !== false
8919
+ });
8843
8920
  return newClient;
8844
8921
  }
8845
8922
  $setInputValidation(enable) {
@@ -8849,6 +8926,14 @@ var ClientImpl = class _ClientImpl {
8849
8926
  };
8850
8927
  return this.$setOptions(newOptions);
8851
8928
  }
8929
+ async $diagnostics() {
8930
+ return {
8931
+ zodCache: this.inputValidator.zodFactory.cacheStats,
8932
+ slowQueries: this.slowQueries.map((q) => ({
8933
+ ...q
8934
+ }))
8935
+ };
8936
+ }
8852
8937
  $executeRaw(query, ...values) {
8853
8938
  return createZenStackPromise(async () => {
8854
8939
  const result = await sql8(query, ...values).execute(this.kysely);