@zenstackhq/orm 3.4.6 → 3.5.0-beta.2

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
@@ -67,6 +67,14 @@ module.exports = __toCommonJS(src_exports);
67
67
  // src/client/client-impl.ts
68
68
  var import_common_helpers14 = require("@zenstackhq/common-helpers");
69
69
  var import_kysely12 = require("kysely");
70
+ var import_zod3 = __toESM(require("zod"), 1);
71
+
72
+ // src/utils/zod-utils.ts
73
+ var import_v4 = require("zod-validation-error/v4");
74
+ function formatError(error) {
75
+ return (0, import_v4.fromError)(error).toString();
76
+ }
77
+ __name(formatError, "formatError");
70
78
 
71
79
  // src/client/crud/operations/aggregate.ts
72
80
  var import_ts_pattern8 = require("ts-pattern");
@@ -4673,13 +4681,6 @@ var UpdateOperationHandler = class extends BaseOperationHandler {
4673
4681
  var import_common_helpers9 = require("@zenstackhq/common-helpers");
4674
4682
  var import_ts_pattern14 = require("ts-pattern");
4675
4683
 
4676
- // src/utils/zod-utils.ts
4677
- var import_v4 = require("zod-validation-error/v4");
4678
- function formatError(error) {
4679
- return (0, import_v4.fromError)(error).toString();
4680
- }
4681
- __name(formatError, "formatError");
4682
-
4683
4684
  // src/client/zod/factory.ts
4684
4685
  var import_common_helpers8 = require("@zenstackhq/common-helpers");
4685
4686
  var import_zod = require("@zenstackhq/zod");
@@ -4731,6 +4732,15 @@ function _ts_metadata(k, v) {
4731
4732
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
4732
4733
  }
4733
4734
  __name(_ts_metadata, "_ts_metadata");
4735
+ function toFieldInfo(def) {
4736
+ return {
4737
+ name: def.name,
4738
+ type: def.type,
4739
+ optional: def.optional,
4740
+ array: def.array
4741
+ };
4742
+ }
4743
+ __name(toFieldInfo, "toFieldInfo");
4734
4744
  function createQuerySchemaFactory(clientOrSchema, options) {
4735
4745
  return new ZodSchemaFactory(clientOrSchema, options);
4736
4746
  }
@@ -4745,6 +4755,7 @@ var ZodSchemaFactory = class {
4745
4755
  ];
4746
4756
  schema;
4747
4757
  options;
4758
+ extraValidationsEnabled = true;
4748
4759
  constructor(clientOrSchema, options) {
4749
4760
  if ("$schema" in clientOrSchema) {
4750
4761
  this.schema = clientOrSchema.$schema;
@@ -4757,9 +4768,6 @@ var ZodSchemaFactory = class {
4757
4768
  get plugins() {
4758
4769
  return this.options.plugins ?? [];
4759
4770
  }
4760
- get extraValidationsEnabled() {
4761
- return this.options.validateInput !== false;
4762
- }
4763
4771
  shouldIncludeRelations(options) {
4764
4772
  return options?.relationDepth === void 0 || options.relationDepth > 0;
4765
4773
  }
@@ -4780,14 +4788,13 @@ var ZodSchemaFactory = class {
4780
4788
  setCache(cacheKey, schema) {
4781
4789
  return this.schemaCache.set(cacheKey, schema);
4782
4790
  }
4783
- // @ts-ignore
4784
- printCacheStats(detailed = false) {
4785
- console.log("Schema cache size:", this.schemaCache.size);
4786
- if (detailed) {
4787
- for (const key of this.schemaCache.keys()) {
4788
- console.log(` ${key}`);
4789
- }
4790
- }
4791
+ get cacheStats() {
4792
+ return {
4793
+ size: this.schemaCache.size,
4794
+ keys: [
4795
+ ...this.schemaCache.keys()
4796
+ ]
4797
+ };
4791
4798
  }
4792
4799
  // #endregion
4793
4800
  // #region Find
@@ -4935,14 +4942,14 @@ var ZodSchemaFactory = class {
4935
4942
  const enumDef = getEnum(this.schema, fieldDef.type);
4936
4943
  if (enumDef) {
4937
4944
  if (Object.keys(enumDef.values).length > 0) {
4938
- fieldSchema = this.makeEnumFilterSchema(model, fieldDef, withAggregations, ignoreSlicing);
4945
+ fieldSchema = this.makeEnumFilterSchema(model, toFieldInfo(fieldDef), withAggregations, ignoreSlicing);
4939
4946
  }
4940
4947
  } else if (fieldDef.array) {
4941
- fieldSchema = this.makeArrayFilterSchema(model, fieldDef);
4948
+ fieldSchema = this.makeArrayFilterSchema(model, toFieldInfo(fieldDef));
4942
4949
  } else if (this.isTypeDefType(fieldDef.type)) {
4943
- fieldSchema = this.makeTypedJsonFilterSchema(model, fieldDef);
4950
+ fieldSchema = this.makeTypedJsonFilterSchema(model, toFieldInfo(fieldDef));
4944
4951
  } else {
4945
- fieldSchema = this.makePrimitiveFilterSchema(model, fieldDef, withAggregations, ignoreSlicing);
4952
+ fieldSchema = this.makePrimitiveFilterSchema(model, toFieldInfo(fieldDef), withAggregations, ignoreSlicing);
4946
4953
  }
4947
4954
  }
4948
4955
  if (fieldSchema) {
@@ -4959,12 +4966,12 @@ var ZodSchemaFactory = class {
4959
4966
  const enumDef = getEnum(this.schema, def.type);
4960
4967
  if (enumDef) {
4961
4968
  if (Object.keys(enumDef.values).length > 0) {
4962
- fieldSchema = this.makeEnumFilterSchema(model, def, false, true);
4969
+ fieldSchema = this.makeEnumFilterSchema(model, toFieldInfo(def), false, true);
4963
4970
  } else {
4964
4971
  fieldSchema = import_zod2.z.never();
4965
4972
  }
4966
4973
  } else {
4967
- fieldSchema = this.makePrimitiveFilterSchema(model, def, false, true);
4974
+ fieldSchema = this.makePrimitiveFilterSchema(model, toFieldInfo(def), false, true);
4968
4975
  }
4969
4976
  return [
4970
4977
  key,
@@ -5011,15 +5018,15 @@ var ZodSchemaFactory = class {
5011
5018
  const fieldSchemas = {};
5012
5019
  for (const [fieldName, fieldDef] of Object.entries(typeDef.fields)) {
5013
5020
  if (this.isTypeDefType(fieldDef.type)) {
5014
- fieldSchemas[fieldName] = this.makeTypedJsonFilterSchema(contextModel, fieldDef).optional();
5021
+ fieldSchemas[fieldName] = this.makeTypedJsonFilterSchema(contextModel, toFieldInfo(fieldDef)).optional();
5015
5022
  } else {
5016
5023
  const enumDef = getEnum(this.schema, fieldDef.type);
5017
5024
  if (enumDef) {
5018
- fieldSchemas[fieldName] = this.makeEnumFilterSchema(contextModel, fieldDef, false).optional();
5025
+ fieldSchemas[fieldName] = this.makeEnumFilterSchema(contextModel, toFieldInfo(fieldDef), false).optional();
5019
5026
  } else if (fieldDef.array) {
5020
- fieldSchemas[fieldName] = this.makeArrayFilterSchema(contextModel, fieldDef).optional();
5027
+ fieldSchemas[fieldName] = this.makeArrayFilterSchema(contextModel, toFieldInfo(fieldDef)).optional();
5021
5028
  } else {
5022
- fieldSchemas[fieldName] = this.makePrimitiveFilterSchema(contextModel, fieldDef, false).optional();
5029
+ fieldSchemas[fieldName] = this.makePrimitiveFilterSchema(contextModel, toFieldInfo(fieldDef), false).optional();
5023
5030
  }
5024
5031
  }
5025
5032
  }
@@ -6603,9 +6610,11 @@ var InputValidator = class {
6603
6610
  }
6604
6611
  client;
6605
6612
  zodFactory;
6606
- constructor(client) {
6613
+ enabled;
6614
+ constructor(client, options) {
6607
6615
  this.client = client;
6608
6616
  this.zodFactory = new ZodSchemaFactory(client);
6617
+ this.enabled = options?.enabled !== false;
6609
6618
  }
6610
6619
  // #region Entry points
6611
6620
  validateFindArgs(model, args, operation) {
@@ -6652,6 +6661,9 @@ var InputValidator = class {
6652
6661
  }
6653
6662
  // TODO: turn it into a Zod schema and cache
6654
6663
  validateProcedureInput(proc, input) {
6664
+ if (!this.enabled) {
6665
+ return input;
6666
+ }
6655
6667
  const procDef = (this.client.$schema.procedures ?? {})[proc];
6656
6668
  (0, import_common_helpers9.invariant)(procDef, `Procedure "${proc}" not found in schema`);
6657
6669
  const params = Object.values(procDef.params ?? {});
@@ -6716,6 +6728,9 @@ var InputValidator = class {
6716
6728
  // #endregion
6717
6729
  // #region Validation helpers
6718
6730
  validate(model, operation, getSchema, args) {
6731
+ if (!this.enabled) {
6732
+ return args;
6733
+ }
6719
6734
  const schema = getSchema(model);
6720
6735
  const { error, data } = schema.safeParse(args);
6721
6736
  if (error) {
@@ -7550,6 +7565,7 @@ var TempAliasTransformer = class extends import_kysely8.OperationNodeTransformer
7550
7565
  };
7551
7566
 
7552
7567
  // src/client/executor/zenstack-query-executor.ts
7568
+ var DEFAULT_MAX_SLOW_RECORDS = 100;
7553
7569
  var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends import_kysely9.DefaultQueryExecutor {
7554
7570
  static {
7555
7571
  __name(this, "ZenStackQueryExecutor");
@@ -7966,13 +7982,49 @@ In such cases, ZenStack cannot reliably determine the IDs of the mutated entitie
7966
7982
  parameters
7967
7983
  };
7968
7984
  }
7985
+ const trackSlowQuery = this.options.diagnostics !== void 0;
7986
+ const startTimestamp = trackSlowQuery ? performance.now() : void 0;
7987
+ const startedAt = trackSlowQuery ? /* @__PURE__ */ new Date() : void 0;
7969
7988
  try {
7970
7989
  const result = await connection.executeQuery(compiledQuery);
7990
+ if (startTimestamp !== void 0) {
7991
+ this.trackSlowQuery(compiledQuery, startTimestamp, startedAt);
7992
+ }
7971
7993
  return this.ensureProperQueryResult(compiledQuery.query, result);
7972
7994
  } catch (err) {
7973
7995
  throw createDBQueryError(`Failed to execute query: ${err}`, err, compiledQuery.sql, compiledQuery.parameters);
7974
7996
  }
7975
7997
  }
7998
+ trackSlowQuery(compiledQuery, startTimestamp, startedAt) {
7999
+ const durationMs = performance.now() - startTimestamp;
8000
+ const thresholdMs = this.options.diagnostics?.slowQueryThresholdMs;
8001
+ if (thresholdMs === void 0 || durationMs < thresholdMs) {
8002
+ return;
8003
+ }
8004
+ const slowQueries = this.client.slowQueries;
8005
+ const maxRecords = this.options.diagnostics?.slowQueryMaxRecords ?? DEFAULT_MAX_SLOW_RECORDS;
8006
+ if (maxRecords <= 0) {
8007
+ return;
8008
+ }
8009
+ const queryInfo = {
8010
+ startedAt,
8011
+ durationMs,
8012
+ sql: compiledQuery.sql
8013
+ };
8014
+ if (slowQueries.length >= maxRecords) {
8015
+ let minIndex = 0;
8016
+ for (let i = 1; i < slowQueries.length; i++) {
8017
+ if (slowQueries[i].durationMs < slowQueries[minIndex].durationMs) {
8018
+ minIndex = i;
8019
+ }
8020
+ }
8021
+ if (durationMs > slowQueries[minIndex].durationMs) {
8022
+ slowQueries[minIndex] = queryInfo;
8023
+ }
8024
+ } else {
8025
+ slowQueries.push(queryInfo);
8026
+ }
8027
+ }
7976
8028
  ensureProperQueryResult(query, result) {
7977
8029
  let finalResult = result;
7978
8030
  if (this.isMutationNode(query)) {
@@ -8644,6 +8696,7 @@ var ClientImpl = class _ClientImpl {
8644
8696
  kyselyProps;
8645
8697
  auth;
8646
8698
  inputValidator;
8699
+ slowQueries = [];
8647
8700
  constructor(schema, options, baseClient, executor) {
8648
8701
  this.schema = schema;
8649
8702
  this.options = options;
@@ -8653,9 +8706,7 @@ var ClientImpl = class _ClientImpl {
8653
8706
  ...functions_exports,
8654
8707
  ...this.$options.functions
8655
8708
  };
8656
- if (!baseClient && !options.skipValidationForComputedFields) {
8657
- this.validateComputedFieldsConfig();
8658
- }
8709
+ this.validateOptions(baseClient, options);
8659
8710
  if (baseClient) {
8660
8711
  this.kyselyProps = {
8661
8712
  ...baseClient.kyselyProps,
@@ -8663,6 +8714,7 @@ var ClientImpl = class _ClientImpl {
8663
8714
  };
8664
8715
  this.kyselyRaw = baseClient.kyselyRaw;
8665
8716
  this.auth = baseClient.auth;
8717
+ this.slowQueries = baseClient.slowQueries;
8666
8718
  } else {
8667
8719
  const driver = new ZenStackDriver(options.dialect.createDriver(), new import_kysely12.Log(this.$options.log ?? []));
8668
8720
  const compiler = options.dialect.createQueryCompiler();
@@ -8683,32 +8735,31 @@ var ClientImpl = class _ClientImpl {
8683
8735
  });
8684
8736
  }
8685
8737
  this.kysely = new import_kysely12.Kysely(this.kyselyProps);
8686
- this.inputValidator = baseClient?.inputValidator ?? new InputValidator(this);
8738
+ this.inputValidator = baseClient?.inputValidator ?? new InputValidator(this, {
8739
+ enabled: this.$options.validateInput !== false
8740
+ });
8687
8741
  return createClientProxy(this);
8688
8742
  }
8689
- get $qb() {
8690
- return this.kysely;
8691
- }
8692
- get $qbRaw() {
8693
- return this.kyselyRaw;
8694
- }
8695
- get $zod() {
8696
- return this.inputValidator.zodFactory;
8697
- }
8698
- get isTransaction() {
8699
- return this.kysely.isTransaction;
8700
- }
8701
- /**
8702
- * Create a new client with a new query executor.
8703
- */
8704
- withExecutor(executor) {
8705
- return new _ClientImpl(this.schema, this.$options, this, executor);
8743
+ validateOptions(baseClient, options) {
8744
+ if (!baseClient && !options.skipValidationForComputedFields) {
8745
+ this.validateComputedFieldsConfig(options);
8746
+ }
8747
+ if (options.diagnostics) {
8748
+ const diagnosticsSchema = import_zod3.default.object({
8749
+ slowQueryThresholdMs: import_zod3.default.number().nonnegative().optional(),
8750
+ slowQueryMaxRecords: import_zod3.default.int().nonnegative().or(import_zod3.default.literal(Infinity)).optional()
8751
+ });
8752
+ const parseResult = diagnosticsSchema.safeParse(options.diagnostics);
8753
+ if (!parseResult.success) {
8754
+ throw createConfigError(`Invalid diagnostics configuration: ${formatError(parseResult.error)}`);
8755
+ }
8756
+ }
8706
8757
  }
8707
8758
  /**
8708
8759
  * Validates that all computed fields in the schema have corresponding configurations.
8709
8760
  */
8710
- validateComputedFieldsConfig() {
8711
- const computedFieldsConfig = "computedFields" in this.$options ? this.$options.computedFields : void 0;
8761
+ validateComputedFieldsConfig(options) {
8762
+ const computedFieldsConfig = "computedFields" in options ? options.computedFields : void 0;
8712
8763
  for (const [modelName, modelDef] of Object.entries(this.$schema.models)) {
8713
8764
  if (modelDef.computedFields) {
8714
8765
  for (const fieldName of Object.keys(modelDef.computedFields)) {
@@ -8724,6 +8775,24 @@ var ClientImpl = class _ClientImpl {
8724
8775
  }
8725
8776
  }
8726
8777
  }
8778
+ get $qb() {
8779
+ return this.kysely;
8780
+ }
8781
+ get $qbRaw() {
8782
+ return this.kyselyRaw;
8783
+ }
8784
+ get $zod() {
8785
+ return this.inputValidator.zodFactory;
8786
+ }
8787
+ get isTransaction() {
8788
+ return this.kysely.isTransaction;
8789
+ }
8790
+ /**
8791
+ * Create a new client with a new query executor.
8792
+ */
8793
+ withExecutor(executor) {
8794
+ return new _ClientImpl(this.schema, this.$options, this, executor);
8795
+ }
8727
8796
  // implementation
8728
8797
  async $transaction(input, options) {
8729
8798
  (0, import_common_helpers14.invariant)(typeof input === "function" || Array.isArray(input) && input.every((p) => p.then && p.cb), "Invalid transaction input, expected a function or an array of ZenStackPromise");
@@ -8845,7 +8914,9 @@ var ClientImpl = class _ClientImpl {
8845
8914
  plugins: newPlugins
8846
8915
  };
8847
8916
  const newClient = new _ClientImpl(this.schema, newOptions, this);
8848
- newClient.inputValidator = new InputValidator(newClient);
8917
+ newClient.inputValidator = new InputValidator(newClient, {
8918
+ enabled: newOptions.validateInput !== false
8919
+ });
8849
8920
  return newClient;
8850
8921
  }
8851
8922
  $unuse(pluginId) {
@@ -8860,7 +8931,9 @@ var ClientImpl = class _ClientImpl {
8860
8931
  plugins: newPlugins
8861
8932
  };
8862
8933
  const newClient = new _ClientImpl(this.schema, newOptions, this);
8863
- newClient.inputValidator = new InputValidator(newClient);
8934
+ newClient.inputValidator = new InputValidator(newClient, {
8935
+ enabled: newClient.$options.validateInput !== false
8936
+ });
8864
8937
  return newClient;
8865
8938
  }
8866
8939
  $unuseAll() {
@@ -8869,7 +8942,9 @@ var ClientImpl = class _ClientImpl {
8869
8942
  plugins: []
8870
8943
  };
8871
8944
  const newClient = new _ClientImpl(this.schema, newOptions, this);
8872
- newClient.inputValidator = new InputValidator(newClient);
8945
+ newClient.inputValidator = new InputValidator(newClient, {
8946
+ enabled: newOptions.validateInput !== false
8947
+ });
8873
8948
  return newClient;
8874
8949
  }
8875
8950
  $setAuth(auth) {
@@ -8885,7 +8960,9 @@ var ClientImpl = class _ClientImpl {
8885
8960
  }
8886
8961
  $setOptions(options) {
8887
8962
  const newClient = new _ClientImpl(this.schema, options, this);
8888
- newClient.inputValidator = new InputValidator(newClient);
8963
+ newClient.inputValidator = new InputValidator(newClient, {
8964
+ enabled: newClient.$options.validateInput !== false
8965
+ });
8889
8966
  return newClient;
8890
8967
  }
8891
8968
  $setInputValidation(enable) {
@@ -8895,6 +8972,14 @@ var ClientImpl = class _ClientImpl {
8895
8972
  };
8896
8973
  return this.$setOptions(newOptions);
8897
8974
  }
8975
+ async $diagnostics() {
8976
+ return {
8977
+ zodCache: this.inputValidator.zodFactory.cacheStats,
8978
+ slowQueries: this.slowQueries.map((q) => ({
8979
+ ...q
8980
+ })).sort((a, b) => b.durationMs - a.durationMs)
8981
+ };
8982
+ }
8898
8983
  $executeRaw(query, ...values) {
8899
8984
  return createZenStackPromise(async () => {
8900
8985
  const result = await (0, import_kysely12.sql)(query, ...values).execute(this.kysely);