metal-orm 1.0.80 → 1.0.82

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
@@ -360,6 +360,7 @@ var operandTypes = /* @__PURE__ */ new Set([
360
360
  "AliasRef",
361
361
  "Column",
362
362
  "Literal",
363
+ "Param",
363
364
  "Function",
364
365
  "JsonPath",
365
366
  "ScalarSubquery",
@@ -799,6 +800,9 @@ var visitOperand = (node, visitor) => {
799
800
  case "Literal":
800
801
  if (visitor.visitLiteral) return visitor.visitLiteral(node);
801
802
  break;
803
+ case "Param":
804
+ if (visitor.visitParam) return visitor.visitParam(node);
805
+ break;
802
806
  case "Function":
803
807
  if (visitor.visitFunction) return visitor.visitFunction(node);
804
808
  break;
@@ -830,6 +834,47 @@ var visitOperand = (node, visitor) => {
830
834
  return unsupportedOperand(node);
831
835
  };
832
836
 
837
+ // src/core/ast/param-proxy.ts
838
+ var buildParamProxy = (name) => {
839
+ const target = { type: "Param", name };
840
+ return new Proxy(target, {
841
+ get(t, prop, receiver) {
842
+ if (prop === "then") return void 0;
843
+ if (typeof prop === "symbol") {
844
+ return Reflect.get(t, prop, receiver);
845
+ }
846
+ if (typeof prop === "string" && prop.startsWith("$")) {
847
+ const trimmed = prop.slice(1);
848
+ const nextName2 = name ? `${name}.${trimmed}` : trimmed;
849
+ return buildParamProxy(nextName2);
850
+ }
851
+ if (prop in t) {
852
+ return t[prop];
853
+ }
854
+ const nextName = name ? `${name}.${prop}` : prop;
855
+ return buildParamProxy(nextName);
856
+ }
857
+ });
858
+ };
859
+ var createParamProxy = () => {
860
+ const target = {};
861
+ return new Proxy(target, {
862
+ get(t, prop, receiver) {
863
+ if (prop === "then") return void 0;
864
+ if (typeof prop === "symbol") {
865
+ return Reflect.get(t, prop, receiver);
866
+ }
867
+ if (typeof prop === "string" && prop.startsWith("$")) {
868
+ return buildParamProxy(prop.slice(1));
869
+ }
870
+ if (prop in t) {
871
+ return t[prop];
872
+ }
873
+ return buildParamProxy(String(prop));
874
+ }
875
+ });
876
+ };
877
+
833
878
  // src/core/ast/adapters.ts
834
879
  var hasAlias = (obj) => typeof obj === "object" && obj !== null && "alias" in obj;
835
880
  var toColumnRef = (col2) => ({
@@ -1539,6 +1584,7 @@ var Dialect = class _Dialect {
1539
1584
  }
1540
1585
  registerDefaultOperandCompilers() {
1541
1586
  this.registerOperandCompiler("Literal", (literal, ctx) => ctx.addParameter(literal.value));
1587
+ this.registerOperandCompiler("Param", (_param, ctx) => ctx.addParameter(null));
1542
1588
  this.registerOperandCompiler("AliasRef", (alias, _ctx) => {
1543
1589
  void _ctx;
1544
1590
  return this.quoteIdentifier(alias.name);
@@ -4062,6 +4108,7 @@ var collectFromOperand = (node, collector) => {
4062
4108
  break;
4063
4109
  case "Literal":
4064
4110
  case "AliasRef":
4111
+ case "Param":
4065
4112
  break;
4066
4113
  default:
4067
4114
  break;
@@ -6668,26 +6715,33 @@ var SelectRelationFacet = class {
6668
6715
  };
6669
6716
 
6670
6717
  // src/openapi/type-mappers.ts
6671
- var mapColumnType = (column) => {
6718
+ var mapColumnType = (column, options = {}) => {
6719
+ const resolved = resolveColumnOptions(options);
6672
6720
  const sqlType = normalizeType(column.type);
6673
6721
  const baseSchema = mapSqlTypeToBaseSchema(sqlType, column);
6674
6722
  const schema = {
6675
- ...baseSchema,
6676
- description: column.comment,
6677
- nullable: !column.notNull && !column.primary
6723
+ ...baseSchema
6678
6724
  };
6679
- if (column.args && sqlType === "varchar" || sqlType === "char") {
6725
+ if (resolved.includeDescriptions && column.comment) {
6726
+ schema.description = column.comment;
6727
+ }
6728
+ if (resolved.includeNullable) {
6729
+ schema.nullable = !column.notNull && !column.primary;
6730
+ }
6731
+ if ((sqlType === "varchar" || sqlType === "char") && column.args) {
6680
6732
  schema.maxLength = column.args[0];
6681
6733
  }
6682
- if (column.args && sqlType === "decimal" || sqlType === "float") {
6734
+ if ((sqlType === "decimal" || sqlType === "float") && column.args) {
6683
6735
  if (column.args.length >= 1) {
6684
6736
  schema.minimum = -(10 ** column.args[0]);
6685
6737
  }
6686
6738
  }
6687
- if (sqlType === "enum" && column.args && column.args.length > 0) {
6739
+ if (!resolved.includeEnums) {
6740
+ delete schema.enum;
6741
+ } else if (sqlType === "enum" && column.args && column.args.length > 0) {
6688
6742
  schema.enum = column.args;
6689
6743
  }
6690
- if (column.default !== void 0) {
6744
+ if (resolved.includeDefaults && column.default !== void 0) {
6691
6745
  schema.default = column.default;
6692
6746
  }
6693
6747
  return schema;
@@ -6803,6 +6857,13 @@ var inferTypeFromTsType = (tsType) => {
6803
6857
  }
6804
6858
  return "string";
6805
6859
  };
6860
+ var resolveColumnOptions = (options) => ({
6861
+ includeDescriptions: options.includeDescriptions ?? false,
6862
+ includeEnums: options.includeEnums ?? true,
6863
+ includeExamples: options.includeExamples ?? false,
6864
+ includeDefaults: options.includeDefaults ?? true,
6865
+ includeNullable: options.includeNullable ?? true
6866
+ });
6806
6867
  var mapRelationType = (relationType) => {
6807
6868
  switch (relationType) {
6808
6869
  case "HAS_MANY":
@@ -6830,14 +6891,55 @@ var getTemporalFormat = (sqlType) => {
6830
6891
  };
6831
6892
 
6832
6893
  // src/openapi/schema-extractor.ts
6894
+ var DEFAULT_MAX_DEPTH = 5;
6833
6895
  var extractSchema = (table, plan, projectionNodes, options = {}) => {
6834
- const mode = options.mode ?? "full";
6835
- const context = {
6836
- visitedTables: /* @__PURE__ */ new Set(),
6837
- schemaCache: /* @__PURE__ */ new Map(),
6838
- depth: 0,
6839
- maxDepth: options.maxDepth ?? 5
6896
+ const outputOptions = resolveOutputOptions(options);
6897
+ const outputContext = createContext(outputOptions.maxDepth ?? DEFAULT_MAX_DEPTH);
6898
+ const output = extractOutputSchema(table, plan, projectionNodes, outputContext, outputOptions);
6899
+ const inputOptions = resolveInputOptions(options);
6900
+ if (!inputOptions) {
6901
+ return { output };
6902
+ }
6903
+ const inputContext = createContext(inputOptions.maxDepth ?? DEFAULT_MAX_DEPTH);
6904
+ const input = extractInputSchema(table, inputContext, inputOptions);
6905
+ return { output, input };
6906
+ };
6907
+ var resolveOutputOptions = (options) => ({
6908
+ mode: options.mode ?? "full",
6909
+ includeDescriptions: options.includeDescriptions,
6910
+ includeEnums: options.includeEnums,
6911
+ includeExamples: options.includeExamples,
6912
+ includeDefaults: options.includeDefaults,
6913
+ includeNullable: options.includeNullable,
6914
+ maxDepth: options.maxDepth ?? DEFAULT_MAX_DEPTH
6915
+ });
6916
+ var resolveInputOptions = (options) => {
6917
+ if (options.input === false) return void 0;
6918
+ const input = options.input ?? {};
6919
+ const mode = input.mode ?? "create";
6920
+ return {
6921
+ mode,
6922
+ includeRelations: input.includeRelations ?? true,
6923
+ relationMode: input.relationMode ?? "mixed",
6924
+ includeDescriptions: input.includeDescriptions ?? options.includeDescriptions,
6925
+ includeEnums: input.includeEnums ?? options.includeEnums,
6926
+ includeExamples: input.includeExamples ?? options.includeExamples,
6927
+ includeDefaults: input.includeDefaults ?? options.includeDefaults,
6928
+ includeNullable: input.includeNullable ?? options.includeNullable,
6929
+ maxDepth: input.maxDepth ?? options.maxDepth ?? DEFAULT_MAX_DEPTH,
6930
+ omitReadOnly: input.omitReadOnly ?? true,
6931
+ excludePrimaryKey: input.excludePrimaryKey ?? false,
6932
+ requirePrimaryKey: input.requirePrimaryKey ?? mode === "update"
6840
6933
  };
6934
+ };
6935
+ var createContext = (maxDepth) => ({
6936
+ visitedTables: /* @__PURE__ */ new Set(),
6937
+ schemaCache: /* @__PURE__ */ new Map(),
6938
+ depth: 0,
6939
+ maxDepth
6940
+ });
6941
+ var extractOutputSchema = (table, plan, projectionNodes, context, options) => {
6942
+ const mode = options.mode ?? "full";
6841
6943
  const hasComputedFields = projectionNodes && projectionNodes.some(
6842
6944
  (node) => node.type !== "Column"
6843
6945
  );
@@ -6849,9 +6951,97 @@ var extractSchema = (table, plan, projectionNodes, options = {}) => {
6849
6951
  }
6850
6952
  return extractFullTableSchema(table, context, options);
6851
6953
  };
6954
+ var extractInputSchema = (table, context, options) => {
6955
+ const cacheKey = `${table.name}:${options.mode ?? "create"}`;
6956
+ if (context.schemaCache.has(cacheKey)) {
6957
+ return context.schemaCache.get(cacheKey);
6958
+ }
6959
+ if (context.visitedTables.has(cacheKey) && context.depth > 0) {
6960
+ return buildCircularReferenceSchema(table.name, "input");
6961
+ }
6962
+ context.visitedTables.add(cacheKey);
6963
+ const properties = {};
6964
+ const required = [];
6965
+ const primaryKey = findPrimaryKey(table);
6966
+ for (const [columnName, column] of Object.entries(table.columns)) {
6967
+ const isPrimary = columnName === primaryKey || column.primary;
6968
+ if (options.excludePrimaryKey && isPrimary) continue;
6969
+ if (options.omitReadOnly && isReadOnlyColumn(column)) continue;
6970
+ properties[columnName] = mapColumnType(column, options);
6971
+ if (options.mode === "create" && isRequiredForCreate(column)) {
6972
+ required.push(columnName);
6973
+ }
6974
+ if (options.mode === "update" && options.requirePrimaryKey && isPrimary) {
6975
+ required.push(columnName);
6976
+ }
6977
+ }
6978
+ if (options.includeRelations && context.depth < context.maxDepth) {
6979
+ for (const [relationName, relation] of Object.entries(table.relations)) {
6980
+ properties[relationName] = extractInputRelationSchema(
6981
+ relation,
6982
+ { ...context, depth: context.depth + 1 },
6983
+ options
6984
+ );
6985
+ }
6986
+ }
6987
+ const schema = {
6988
+ type: "object",
6989
+ properties,
6990
+ required
6991
+ };
6992
+ context.schemaCache.set(cacheKey, schema);
6993
+ return schema;
6994
+ };
6995
+ var isReadOnlyColumn = (column) => Boolean(column.autoIncrement || column.generated === "always");
6996
+ var isRequiredForCreate = (column) => {
6997
+ if (isReadOnlyColumn(column)) return false;
6998
+ if (column.default !== void 0) return false;
6999
+ return Boolean(column.notNull || column.primary);
7000
+ };
7001
+ var buildPrimaryKeySchema = (table, options) => {
7002
+ const primaryKey = findPrimaryKey(table);
7003
+ const column = table.columns[primaryKey];
7004
+ if (!column) {
7005
+ return {
7006
+ anyOf: [
7007
+ { type: "string" },
7008
+ { type: "number" },
7009
+ { type: "integer" }
7010
+ ]
7011
+ };
7012
+ }
7013
+ return mapColumnType(column, options);
7014
+ };
7015
+ var extractInputRelationSchema = (relation, context, options) => {
7016
+ const { type: relationType, isNullable } = mapRelationType(relation.type);
7017
+ const relationMode = options.relationMode ?? "mixed";
7018
+ const allowIds = relationMode !== "objects";
7019
+ const allowObjects = relationMode !== "ids";
7020
+ const variants = [];
7021
+ if (allowIds) {
7022
+ variants.push(buildPrimaryKeySchema(relation.target, options));
7023
+ }
7024
+ if (allowObjects) {
7025
+ const targetSchema = extractInputSchema(relation.target, context, options);
7026
+ variants.push(targetSchema);
7027
+ }
7028
+ const itemSchema = variants.length === 1 ? variants[0] : { anyOf: variants };
7029
+ if (relationType === "array") {
7030
+ return {
7031
+ type: "array",
7032
+ items: itemSchema,
7033
+ nullable: isNullable
7034
+ };
7035
+ }
7036
+ return {
7037
+ ...itemSchema,
7038
+ nullable: isNullable
7039
+ };
7040
+ };
6852
7041
  var extractFromProjectionNodes = (table, projectionNodes, context, options) => {
6853
7042
  const properties = {};
6854
7043
  const required = [];
7044
+ const includeDescriptions = Boolean(options.includeDescriptions);
6855
7045
  for (const node of projectionNodes) {
6856
7046
  if (!node || typeof node !== "object") continue;
6857
7047
  const projection = node;
@@ -6861,10 +7051,7 @@ var extractFromProjectionNodes = (table, projectionNodes, context, options) => {
6861
7051
  const columnNode4 = node;
6862
7052
  const column = table.columns[columnNode4.name];
6863
7053
  if (!column) continue;
6864
- const property = mapColumnType(column);
6865
- if (!property.description && options.includeDescriptions && column.comment) {
6866
- property.description = column.comment;
6867
- }
7054
+ const property = mapColumnType(column, options);
6868
7055
  properties[propertyName] = property;
6869
7056
  if (column.notNull || column.primary) {
6870
7057
  required.push(propertyName);
@@ -6872,7 +7059,7 @@ var extractFromProjectionNodes = (table, projectionNodes, context, options) => {
6872
7059
  } else if (projection.type === "Function" || projection.type === "WindowFunction") {
6873
7060
  const fnNode = node;
6874
7061
  const functionName = fnNode.fn?.toUpperCase() ?? fnNode.name?.toUpperCase() ?? "";
6875
- const propertySchema = projection.type === "Function" ? mapFunctionNodeToSchema(functionName) : mapWindowFunctionToSchema(functionName);
7062
+ const propertySchema = projection.type === "Function" ? mapFunctionNodeToSchema(functionName, includeDescriptions) : mapWindowFunctionToSchema(functionName, includeDescriptions);
6876
7063
  properties[propertyName] = propertySchema;
6877
7064
  const isCountFunction = functionName === "COUNT";
6878
7065
  const isWindowRankFunction = functionName === "ROW_NUMBER" || functionName === "RANK";
@@ -6882,23 +7069,29 @@ var extractFromProjectionNodes = (table, projectionNodes, context, options) => {
6882
7069
  } else if (projection.type === "CaseExpression") {
6883
7070
  const propertySchema = {
6884
7071
  type: "string",
6885
- description: "Computed CASE expression",
6886
7072
  nullable: true
6887
7073
  };
7074
+ if (includeDescriptions) {
7075
+ propertySchema.description = "Computed CASE expression";
7076
+ }
6888
7077
  properties[propertyName] = propertySchema;
6889
7078
  } else if (projection.type === "ScalarSubquery") {
6890
7079
  const propertySchema = {
6891
7080
  type: "object",
6892
- description: "Subquery result",
6893
7081
  nullable: true
6894
7082
  };
7083
+ if (includeDescriptions) {
7084
+ propertySchema.description = "Subquery result";
7085
+ }
6895
7086
  properties[propertyName] = propertySchema;
6896
7087
  } else if (projection.type === "CastExpression") {
6897
7088
  const propertySchema = {
6898
7089
  type: "string",
6899
- description: "CAST expression result",
6900
7090
  nullable: true
6901
7091
  };
7092
+ if (includeDescriptions) {
7093
+ propertySchema.description = "CAST expression result";
7094
+ }
6902
7095
  properties[propertyName] = propertySchema;
6903
7096
  }
6904
7097
  }
@@ -6908,7 +7101,7 @@ var extractFromProjectionNodes = (table, projectionNodes, context, options) => {
6908
7101
  required
6909
7102
  };
6910
7103
  };
6911
- var mapFunctionNodeToSchema = (functionName) => {
7104
+ var mapFunctionNodeToSchema = (functionName, includeDescriptions) => {
6912
7105
  const upperName = functionName.toUpperCase();
6913
7106
  switch (upperName) {
6914
7107
  case "COUNT":
@@ -6916,74 +7109,69 @@ var mapFunctionNodeToSchema = (functionName) => {
6916
7109
  case "AVG":
6917
7110
  case "MIN":
6918
7111
  case "MAX":
6919
- return {
7112
+ return withOptionalDescription({
6920
7113
  type: "number",
6921
- description: `${upperName} aggregate function result`,
6922
7114
  nullable: false
6923
- };
7115
+ }, includeDescriptions, `${upperName} aggregate function result`);
6924
7116
  case "GROUP_CONCAT":
6925
7117
  case "STRING_AGG":
6926
7118
  case "ARRAY_AGG":
6927
- return {
7119
+ return withOptionalDescription({
6928
7120
  type: "string",
6929
- description: `${upperName} aggregate function result`,
6930
7121
  nullable: true
6931
- };
7122
+ }, includeDescriptions, `${upperName} aggregate function result`);
6932
7123
  case "JSON_ARRAYAGG":
6933
7124
  case "JSON_OBJECTAGG":
6934
- return {
7125
+ return withOptionalDescription({
6935
7126
  type: "object",
6936
- description: `${upperName} aggregate function result`,
6937
7127
  nullable: true
6938
- };
7128
+ }, includeDescriptions, `${upperName} aggregate function result`);
6939
7129
  default:
6940
- return {
7130
+ return withOptionalDescription({
6941
7131
  type: "string",
6942
- description: `Unknown function: ${functionName}`,
6943
7132
  nullable: true
6944
- };
7133
+ }, includeDescriptions, `Unknown function: ${functionName}`);
6945
7134
  }
6946
7135
  };
6947
- var mapWindowFunctionToSchema = (functionName) => {
7136
+ var mapWindowFunctionToSchema = (functionName, includeDescriptions) => {
6948
7137
  const upperName = functionName.toUpperCase();
6949
7138
  switch (upperName) {
6950
7139
  case "ROW_NUMBER":
6951
7140
  case "RANK":
6952
7141
  case "DENSE_RANK":
6953
7142
  case "NTILE":
6954
- return {
7143
+ return withOptionalDescription({
6955
7144
  type: "integer",
6956
- description: `${upperName} window function result`,
6957
7145
  nullable: false
6958
- };
7146
+ }, includeDescriptions, `${upperName} window function result`);
6959
7147
  case "LAG":
6960
7148
  case "LEAD":
6961
7149
  case "FIRST_VALUE":
6962
7150
  case "LAST_VALUE":
6963
- return {
7151
+ return withOptionalDescription({
6964
7152
  type: "string",
6965
- description: `${upperName} window function result`,
6966
7153
  nullable: true
6967
- };
7154
+ }, includeDescriptions, `${upperName} window function result`);
6968
7155
  default:
6969
- return {
7156
+ return withOptionalDescription({
6970
7157
  type: "string",
6971
- description: `Unknown window function: ${functionName}`,
6972
7158
  nullable: true
6973
- };
7159
+ }, includeDescriptions, `Unknown window function: ${functionName}`);
6974
7160
  }
6975
7161
  };
7162
+ var withOptionalDescription = (schema, includeDescriptions, description) => {
7163
+ if (includeDescriptions) {
7164
+ return { ...schema, description };
7165
+ }
7166
+ return schema;
7167
+ };
6976
7168
  var extractSelectedSchema = (table, plan, context, options) => {
6977
7169
  const properties = {};
6978
7170
  const required = [];
6979
7171
  plan.rootColumns.forEach((columnName) => {
6980
7172
  const column = table.columns[columnName];
6981
7173
  if (!column) return;
6982
- const property = mapColumnType(column);
6983
- if (!property.description && options.includeDescriptions && column.comment) {
6984
- property.description = column.comment;
6985
- }
6986
- properties[columnName] = property;
7174
+ properties[columnName] = mapColumnType(column, options);
6987
7175
  if (column.notNull || column.primary) {
6988
7176
  required.push(columnName);
6989
7177
  }
@@ -7016,26 +7204,13 @@ var extractFullTableSchema = (table, context, options) => {
7016
7204
  return context.schemaCache.get(cacheKey);
7017
7205
  }
7018
7206
  if (context.visitedTables.has(cacheKey) && context.depth > 0) {
7019
- return {
7020
- type: "object",
7021
- properties: {
7022
- _ref: {
7023
- type: "string",
7024
- description: `Circular reference to ${table.name}`
7025
- }
7026
- },
7027
- required: []
7028
- };
7207
+ return buildCircularReferenceSchema(table.name, "output");
7029
7208
  }
7030
7209
  context.visitedTables.add(cacheKey);
7031
7210
  const properties = {};
7032
7211
  const required = [];
7033
7212
  Object.entries(table.columns).forEach(([columnName, column]) => {
7034
- const property = mapColumnType(column);
7035
- if (!property.description && options.includeDescriptions && column.comment) {
7036
- property.description = column.comment;
7037
- }
7038
- properties[columnName] = property;
7213
+ properties[columnName] = mapColumnType(column, options);
7039
7214
  if (column.notNull || column.primary) {
7040
7215
  required.push(columnName);
7041
7216
  }
@@ -7095,10 +7270,189 @@ var extractRelationSchema = (relation, relationPlan, selectedColumns, context, o
7095
7270
  description: targetSchema.description
7096
7271
  };
7097
7272
  };
7273
+ var buildCircularReferenceSchema = (tableName, kind) => ({
7274
+ type: "object",
7275
+ properties: {
7276
+ _ref: {
7277
+ type: "string",
7278
+ description: `Circular ${kind} reference to ${tableName}`
7279
+ }
7280
+ },
7281
+ required: []
7282
+ });
7098
7283
  var schemaToJson = (schema, pretty = false) => {
7099
7284
  return JSON.stringify(schema, null, pretty ? 2 : 0);
7100
7285
  };
7101
7286
 
7287
+ // src/openapi/query-parameters.ts
7288
+ var FILTER_PARAM_NAME = "filter";
7289
+ var buildRootTableNames = (table, from) => {
7290
+ const names = /* @__PURE__ */ new Set([table.name]);
7291
+ if (from?.type === "Table") {
7292
+ names.add(from.name);
7293
+ if (from.alias) names.add(from.alias);
7294
+ }
7295
+ return names;
7296
+ };
7297
+ var collectFilterColumns = (expr, table, rootTables) => {
7298
+ const columns = /* @__PURE__ */ new Set();
7299
+ const recordColumn = (node) => {
7300
+ if (!rootTables.has(node.table)) return;
7301
+ if (node.name in table.columns) {
7302
+ columns.add(node.name);
7303
+ }
7304
+ };
7305
+ const visitOrderingTerm = (term) => {
7306
+ if (!term || typeof term !== "object") return;
7307
+ if (isOperandNode(term)) {
7308
+ visitOperand2(term);
7309
+ return;
7310
+ }
7311
+ if ("type" in term) {
7312
+ visitExpression2(term);
7313
+ }
7314
+ };
7315
+ const visitOrderBy = (orderBy) => {
7316
+ if (!orderBy) return;
7317
+ orderBy.forEach((node) => visitOrderingTerm(node.term));
7318
+ };
7319
+ const visitOperand2 = (node) => {
7320
+ switch (node.type) {
7321
+ case "Column":
7322
+ recordColumn(node);
7323
+ return;
7324
+ case "Function": {
7325
+ const fn8 = node;
7326
+ fn8.args?.forEach(visitOperand2);
7327
+ visitOrderBy(fn8.orderBy);
7328
+ if (fn8.separator) visitOperand2(fn8.separator);
7329
+ return;
7330
+ }
7331
+ case "JsonPath": {
7332
+ const jp = node;
7333
+ recordColumn(jp.column);
7334
+ return;
7335
+ }
7336
+ case "ScalarSubquery":
7337
+ return;
7338
+ case "CaseExpression": {
7339
+ const cs = node;
7340
+ cs.conditions.forEach((condition) => {
7341
+ visitExpression2(condition.when);
7342
+ visitOperand2(condition.then);
7343
+ });
7344
+ if (cs.else) visitOperand2(cs.else);
7345
+ return;
7346
+ }
7347
+ case "Cast": {
7348
+ const cast2 = node;
7349
+ visitOperand2(cast2.expression);
7350
+ return;
7351
+ }
7352
+ case "WindowFunction": {
7353
+ const windowFn = node;
7354
+ windowFn.args?.forEach(visitOperand2);
7355
+ windowFn.partitionBy?.forEach(recordColumn);
7356
+ visitOrderBy(windowFn.orderBy);
7357
+ return;
7358
+ }
7359
+ case "ArithmeticExpression": {
7360
+ const arith = node;
7361
+ visitOperand2(arith.left);
7362
+ visitOperand2(arith.right);
7363
+ return;
7364
+ }
7365
+ case "BitwiseExpression": {
7366
+ const bitwise = node;
7367
+ visitOperand2(bitwise.left);
7368
+ visitOperand2(bitwise.right);
7369
+ return;
7370
+ }
7371
+ case "Collate": {
7372
+ const collate2 = node;
7373
+ visitOperand2(collate2.expression);
7374
+ return;
7375
+ }
7376
+ case "AliasRef":
7377
+ case "Literal":
7378
+ case "Param":
7379
+ return;
7380
+ default:
7381
+ return;
7382
+ }
7383
+ };
7384
+ const visitExpression2 = (node) => {
7385
+ switch (node.type) {
7386
+ case "BinaryExpression":
7387
+ visitOperand2(node.left);
7388
+ visitOperand2(node.right);
7389
+ if (node.escape) visitOperand2(node.escape);
7390
+ return;
7391
+ case "LogicalExpression":
7392
+ node.operands.forEach(visitExpression2);
7393
+ return;
7394
+ case "NullExpression":
7395
+ visitOperand2(node.left);
7396
+ return;
7397
+ case "InExpression":
7398
+ visitOperand2(node.left);
7399
+ if (Array.isArray(node.right)) {
7400
+ node.right.forEach(visitOperand2);
7401
+ }
7402
+ return;
7403
+ case "ExistsExpression":
7404
+ return;
7405
+ case "BetweenExpression":
7406
+ visitOperand2(node.left);
7407
+ visitOperand2(node.lower);
7408
+ visitOperand2(node.upper);
7409
+ return;
7410
+ case "ArithmeticExpression":
7411
+ visitOperand2(node.left);
7412
+ visitOperand2(node.right);
7413
+ return;
7414
+ case "BitwiseExpression":
7415
+ visitOperand2(node.left);
7416
+ visitOperand2(node.right);
7417
+ return;
7418
+ default:
7419
+ return;
7420
+ }
7421
+ };
7422
+ visitExpression2(expr);
7423
+ return columns;
7424
+ };
7425
+ var buildFilterParameters = (table, where, from, options = {}) => {
7426
+ if (!where) return [];
7427
+ const rootTables = buildRootTableNames(table, from);
7428
+ const columnNames = collectFilterColumns(where, table, rootTables);
7429
+ let schema;
7430
+ if (columnNames.size) {
7431
+ const properties = {};
7432
+ for (const name of columnNames) {
7433
+ const column = table.columns[name];
7434
+ if (!column) continue;
7435
+ properties[name] = mapColumnType(column, options);
7436
+ }
7437
+ schema = {
7438
+ type: "object",
7439
+ properties
7440
+ };
7441
+ } else {
7442
+ schema = {
7443
+ type: "object",
7444
+ additionalProperties: true
7445
+ };
7446
+ }
7447
+ return [{
7448
+ name: FILTER_PARAM_NAME,
7449
+ in: "query",
7450
+ style: "deepObject",
7451
+ explode: true,
7452
+ schema
7453
+ }];
7454
+ };
7455
+
7102
7456
  // src/query-builder/select.ts
7103
7457
  var SelectQueryBuilder = class _SelectQueryBuilder {
7104
7458
  env;
@@ -7918,16 +8272,26 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
7918
8272
  return this.context.hydration.getPlan();
7919
8273
  }
7920
8274
  /**
7921
- * Gets OpenAPI 3.1 JSON Schema for query result
8275
+ * Gets OpenAPI 3.1 JSON Schemas for query output and optional input payloads
7922
8276
  * @param options - Schema generation options
7923
- * @returns OpenAPI 3.1 JSON Schema for query result
8277
+ * @returns OpenAPI 3.1 JSON Schemas for query output and input payloads
7924
8278
  * @example
7925
- * const schema = qb.select('id', 'title', 'author').getSchema();
7926
- * console.log(JSON.stringify(schema, null, 2));
8279
+ * const { output } = qb.select('id', 'title', 'author').getSchema();
8280
+ * console.log(JSON.stringify(output, null, 2));
7927
8281
  */
7928
8282
  getSchema(options) {
7929
8283
  const plan = this.context.hydration.getPlan();
7930
- return extractSchema(this.env.table, plan, this.context.state.ast.columns, options);
8284
+ const bundle = extractSchema(this.env.table, plan, this.context.state.ast.columns, options);
8285
+ const parameters = buildFilterParameters(
8286
+ this.env.table,
8287
+ this.context.state.ast.where,
8288
+ this.context.state.ast.from,
8289
+ options ?? {}
8290
+ );
8291
+ if (parameters.length) {
8292
+ return { ...bundle, parameters };
8293
+ }
8294
+ return bundle;
7931
8295
  }
7932
8296
  /**
7933
8297
  * Gets the Abstract Syntax Tree (AST) representation of the query
@@ -11051,6 +11415,7 @@ var TypeScriptGenerator = class {
11051
11415
  case "WindowFunction":
11052
11416
  case "Cast":
11053
11417
  case "Collate":
11418
+ case "Param":
11054
11419
  return this.printOperand(term);
11055
11420
  default:
11056
11421
  return this.printExpression(term);
@@ -11095,6 +11460,9 @@ var TypeScriptGenerator = class {
11095
11460
  visitLiteral(node) {
11096
11461
  return this.printLiteralOperand(node);
11097
11462
  }
11463
+ visitParam(node) {
11464
+ return this.printParamOperand(node);
11465
+ }
11098
11466
  visitFunction(node) {
11099
11467
  return this.printFunctionOperand(node);
11100
11468
  }
@@ -11216,6 +11584,10 @@ var TypeScriptGenerator = class {
11216
11584
  if (literal.value === null) return "null";
11217
11585
  return typeof literal.value === "string" ? `'${literal.value}'` : String(literal.value);
11218
11586
  }
11587
+ printParamOperand(param) {
11588
+ const name = param.name.replace(/'/g, "\\'");
11589
+ return `{ type: 'Param', name: '${name}' }`;
11590
+ }
11219
11591
  /**
11220
11592
  * Prints a function operand to TypeScript code
11221
11593
  * @param fn - Function node
@@ -11544,6 +11916,7 @@ var UnitOfWork = class {
11544
11916
  const compiled = builder.compile(this.dialect);
11545
11917
  const results = await this.executeCompiled(compiled);
11546
11918
  this.applyReturningResults(tracked, results);
11919
+ this.applyInsertId(tracked, results);
11547
11920
  tracked.status = "managed" /* Managed */;
11548
11921
  tracked.original = this.createSnapshot(tracked.table, tracked.entity);
11549
11922
  tracked.pk = this.getPrimaryKeyValue(tracked);
@@ -11669,6 +12042,16 @@ var UnitOfWork = class {
11669
12042
  tracked.entity[columnName] = row[i];
11670
12043
  }
11671
12044
  }
12045
+ applyInsertId(tracked, results) {
12046
+ if (this.dialect.supportsReturning()) return;
12047
+ if (tracked.pk != null) return;
12048
+ const pkName = findPrimaryKey(tracked.table);
12049
+ const pkColumn = tracked.table.columns[pkName];
12050
+ if (!pkColumn?.autoIncrement) return;
12051
+ const insertId = results.find((result) => typeof result.insertId === "number")?.insertId;
12052
+ if (insertId == null) return;
12053
+ tracked.entity[pkName] = insertId;
12054
+ }
11672
12055
  /**
11673
12056
  * Normalizes a column name by removing quotes and table prefixes.
11674
12057
  * @param column - The column name to normalize
@@ -13185,7 +13568,9 @@ function createMysqlExecutor(client) {
13185
13568
  async executeSql(sql, params) {
13186
13569
  const [rows] = await client.query(sql, params);
13187
13570
  if (!Array.isArray(rows)) {
13188
- return [{ columns: [], values: [] }];
13571
+ const insertId = rows?.insertId;
13572
+ const normalized = typeof insertId === "number" && insertId > 0 ? insertId : void 0;
13573
+ return [{ columns: [], values: [], insertId: normalized }];
13189
13574
  }
13190
13575
  const result = rowsToQueryResult(
13191
13576
  rows
@@ -13483,6 +13868,7 @@ export {
13483
13868
  bitOr,
13484
13869
  bitXor,
13485
13870
  bootstrapEntities,
13871
+ buildFilterParameters,
13486
13872
  caseWhen,
13487
13873
  cast,
13488
13874
  cbrt,
@@ -13509,6 +13895,7 @@ export {
13509
13895
  createExecutorFromQueryRunner,
13510
13896
  createMssqlExecutor,
13511
13897
  createMysqlExecutor,
13898
+ createParamProxy,
13512
13899
  createPooledExecutorFactory,
13513
13900
  createPostgresExecutor,
13514
13901
  createQueryLoggingExecutor,