metal-orm 1.0.79 → 1.0.81

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
@@ -2269,6 +2269,9 @@ var PostgresDialect = class extends SqlDialectBase {
2269
2269
  quoteIdentifier(id) {
2270
2270
  return `"${id}"`;
2271
2271
  }
2272
+ formatPlaceholder(index) {
2273
+ return `$${index}`;
2274
+ }
2272
2275
  /**
2273
2276
  * Compiles JSON path expression using PostgreSQL syntax
2274
2277
  * @param node - JSON path node
@@ -6664,6 +6667,744 @@ var SelectRelationFacet = class {
6664
6667
  }
6665
6668
  };
6666
6669
 
6670
+ // src/openapi/type-mappers.ts
6671
+ var mapColumnType = (column, options = {}) => {
6672
+ const resolved = resolveColumnOptions(options);
6673
+ const sqlType = normalizeType(column.type);
6674
+ const baseSchema = mapSqlTypeToBaseSchema(sqlType, column);
6675
+ const schema = {
6676
+ ...baseSchema
6677
+ };
6678
+ if (resolved.includeDescriptions && column.comment) {
6679
+ schema.description = column.comment;
6680
+ }
6681
+ if (resolved.includeNullable) {
6682
+ schema.nullable = !column.notNull && !column.primary;
6683
+ }
6684
+ if ((sqlType === "varchar" || sqlType === "char") && column.args) {
6685
+ schema.maxLength = column.args[0];
6686
+ }
6687
+ if ((sqlType === "decimal" || sqlType === "float") && column.args) {
6688
+ if (column.args.length >= 1) {
6689
+ schema.minimum = -(10 ** column.args[0]);
6690
+ }
6691
+ }
6692
+ if (!resolved.includeEnums) {
6693
+ delete schema.enum;
6694
+ } else if (sqlType === "enum" && column.args && column.args.length > 0) {
6695
+ schema.enum = column.args;
6696
+ }
6697
+ if (resolved.includeDefaults && column.default !== void 0) {
6698
+ schema.default = column.default;
6699
+ }
6700
+ return schema;
6701
+ };
6702
+ var normalizeType = (type) => {
6703
+ return type.toLowerCase();
6704
+ };
6705
+ var mapSqlTypeToBaseSchema = (sqlType, column) => {
6706
+ const type = normalizeType(sqlType);
6707
+ const hasCustomTsType = column.tsType !== void 0;
6708
+ switch (type) {
6709
+ case "int":
6710
+ case "integer":
6711
+ case "bigint":
6712
+ return {
6713
+ type: hasCustomTsType ? inferTypeFromTsType(column.tsType) : "integer",
6714
+ format: type === "bigint" ? "int64" : "int32",
6715
+ minimum: column.autoIncrement ? 1 : void 0
6716
+ };
6717
+ case "decimal":
6718
+ case "float":
6719
+ case "double":
6720
+ return {
6721
+ type: hasCustomTsType ? inferTypeFromTsType(column.tsType) : "number"
6722
+ };
6723
+ case "varchar":
6724
+ return {
6725
+ type: "string",
6726
+ minLength: column.notNull ? 1 : void 0,
6727
+ maxLength: column.args?.[0]
6728
+ };
6729
+ case "text":
6730
+ return {
6731
+ type: "string",
6732
+ minLength: column.notNull ? 1 : void 0
6733
+ };
6734
+ case "char":
6735
+ return {
6736
+ type: "string",
6737
+ minLength: column.notNull ? column.args?.[0] || 1 : void 0,
6738
+ maxLength: column.args?.[0]
6739
+ };
6740
+ case "boolean":
6741
+ return {
6742
+ type: "boolean"
6743
+ };
6744
+ case "json":
6745
+ return {
6746
+ anyOf: [
6747
+ { type: "object" },
6748
+ { type: "array" }
6749
+ ]
6750
+ };
6751
+ case "blob":
6752
+ case "binary":
6753
+ case "varbinary":
6754
+ return {
6755
+ type: "string",
6756
+ format: "base64"
6757
+ };
6758
+ case "date":
6759
+ return {
6760
+ type: "string",
6761
+ format: "date"
6762
+ };
6763
+ case "datetime":
6764
+ case "timestamp":
6765
+ return {
6766
+ type: "string",
6767
+ format: "date-time"
6768
+ };
6769
+ case "timestamptz":
6770
+ return {
6771
+ type: "string",
6772
+ format: "date-time"
6773
+ };
6774
+ case "uuid":
6775
+ return {
6776
+ type: "string",
6777
+ format: "uuid",
6778
+ pattern: "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
6779
+ };
6780
+ case "enum":
6781
+ return {
6782
+ type: "string",
6783
+ enum: column.args || []
6784
+ };
6785
+ default:
6786
+ if (column.dialectTypes?.postgres && column.dialectTypes.postgres === "bytea") {
6787
+ return {
6788
+ type: "string",
6789
+ format: "base64"
6790
+ };
6791
+ }
6792
+ return {
6793
+ type: "string"
6794
+ };
6795
+ }
6796
+ };
6797
+ var inferTypeFromTsType = (tsType) => {
6798
+ if (typeof tsType === "string") {
6799
+ if (tsType === "number") return "number";
6800
+ if (tsType === "string") return "string";
6801
+ if (tsType === "boolean") return "boolean";
6802
+ }
6803
+ if (typeof tsType === "function") {
6804
+ const typeStr = tsType.name?.toLowerCase();
6805
+ if (typeStr === "number") return "number";
6806
+ if (typeStr === "string") return "string";
6807
+ if (typeStr === "boolean") return "boolean";
6808
+ if (typeStr === "array") return "array";
6809
+ if (typeStr === "object") return "object";
6810
+ }
6811
+ return "string";
6812
+ };
6813
+ var resolveColumnOptions = (options) => ({
6814
+ includeDescriptions: options.includeDescriptions ?? false,
6815
+ includeEnums: options.includeEnums ?? true,
6816
+ includeExamples: options.includeExamples ?? false,
6817
+ includeDefaults: options.includeDefaults ?? true,
6818
+ includeNullable: options.includeNullable ?? true
6819
+ });
6820
+ var mapRelationType = (relationType) => {
6821
+ switch (relationType) {
6822
+ case "HAS_MANY":
6823
+ case "BELONGS_TO_MANY":
6824
+ return { type: "array", isNullable: false };
6825
+ case "HAS_ONE":
6826
+ case "BELONGS_TO":
6827
+ return { type: "object", isNullable: true };
6828
+ default:
6829
+ return { type: "object", isNullable: true };
6830
+ }
6831
+ };
6832
+ var getTemporalFormat = (sqlType) => {
6833
+ const type = normalizeType(sqlType);
6834
+ switch (type) {
6835
+ case "date":
6836
+ return "date";
6837
+ case "datetime":
6838
+ case "timestamp":
6839
+ case "timestamptz":
6840
+ return "date-time";
6841
+ default:
6842
+ return void 0;
6843
+ }
6844
+ };
6845
+
6846
+ // src/openapi/schema-extractor.ts
6847
+ var DEFAULT_MAX_DEPTH = 5;
6848
+ var extractSchema = (table, plan, projectionNodes, options = {}) => {
6849
+ const outputOptions = resolveOutputOptions(options);
6850
+ const outputContext = createContext(outputOptions.maxDepth ?? DEFAULT_MAX_DEPTH);
6851
+ const output = extractOutputSchema(table, plan, projectionNodes, outputContext, outputOptions);
6852
+ const inputOptions = resolveInputOptions(options);
6853
+ if (!inputOptions) {
6854
+ return { output };
6855
+ }
6856
+ const inputContext = createContext(inputOptions.maxDepth ?? DEFAULT_MAX_DEPTH);
6857
+ const input = extractInputSchema(table, inputContext, inputOptions);
6858
+ return { output, input };
6859
+ };
6860
+ var resolveOutputOptions = (options) => ({
6861
+ mode: options.mode ?? "full",
6862
+ includeDescriptions: options.includeDescriptions,
6863
+ includeEnums: options.includeEnums,
6864
+ includeExamples: options.includeExamples,
6865
+ includeDefaults: options.includeDefaults,
6866
+ includeNullable: options.includeNullable,
6867
+ maxDepth: options.maxDepth ?? DEFAULT_MAX_DEPTH
6868
+ });
6869
+ var resolveInputOptions = (options) => {
6870
+ if (options.input === false) return void 0;
6871
+ const input = options.input ?? {};
6872
+ const mode = input.mode ?? "create";
6873
+ return {
6874
+ mode,
6875
+ includeRelations: input.includeRelations ?? true,
6876
+ relationMode: input.relationMode ?? "mixed",
6877
+ includeDescriptions: input.includeDescriptions ?? options.includeDescriptions,
6878
+ includeEnums: input.includeEnums ?? options.includeEnums,
6879
+ includeExamples: input.includeExamples ?? options.includeExamples,
6880
+ includeDefaults: input.includeDefaults ?? options.includeDefaults,
6881
+ includeNullable: input.includeNullable ?? options.includeNullable,
6882
+ maxDepth: input.maxDepth ?? options.maxDepth ?? DEFAULT_MAX_DEPTH,
6883
+ omitReadOnly: input.omitReadOnly ?? true,
6884
+ excludePrimaryKey: input.excludePrimaryKey ?? false,
6885
+ requirePrimaryKey: input.requirePrimaryKey ?? mode === "update"
6886
+ };
6887
+ };
6888
+ var createContext = (maxDepth) => ({
6889
+ visitedTables: /* @__PURE__ */ new Set(),
6890
+ schemaCache: /* @__PURE__ */ new Map(),
6891
+ depth: 0,
6892
+ maxDepth
6893
+ });
6894
+ var extractOutputSchema = (table, plan, projectionNodes, context, options) => {
6895
+ const mode = options.mode ?? "full";
6896
+ const hasComputedFields = projectionNodes && projectionNodes.some(
6897
+ (node) => node.type !== "Column"
6898
+ );
6899
+ if (hasComputedFields) {
6900
+ return extractFromProjectionNodes(table, projectionNodes, context, options);
6901
+ }
6902
+ if (mode === "selected" && plan) {
6903
+ return extractSelectedSchema(table, plan, context, options);
6904
+ }
6905
+ return extractFullTableSchema(table, context, options);
6906
+ };
6907
+ var extractInputSchema = (table, context, options) => {
6908
+ const cacheKey = `${table.name}:${options.mode ?? "create"}`;
6909
+ if (context.schemaCache.has(cacheKey)) {
6910
+ return context.schemaCache.get(cacheKey);
6911
+ }
6912
+ if (context.visitedTables.has(cacheKey) && context.depth > 0) {
6913
+ return buildCircularReferenceSchema(table.name, "input");
6914
+ }
6915
+ context.visitedTables.add(cacheKey);
6916
+ const properties = {};
6917
+ const required = [];
6918
+ const primaryKey = findPrimaryKey(table);
6919
+ for (const [columnName, column] of Object.entries(table.columns)) {
6920
+ const isPrimary = columnName === primaryKey || column.primary;
6921
+ if (options.excludePrimaryKey && isPrimary) continue;
6922
+ if (options.omitReadOnly && isReadOnlyColumn(column)) continue;
6923
+ properties[columnName] = mapColumnType(column, options);
6924
+ if (options.mode === "create" && isRequiredForCreate(column)) {
6925
+ required.push(columnName);
6926
+ }
6927
+ if (options.mode === "update" && options.requirePrimaryKey && isPrimary) {
6928
+ required.push(columnName);
6929
+ }
6930
+ }
6931
+ if (options.includeRelations && context.depth < context.maxDepth) {
6932
+ for (const [relationName, relation] of Object.entries(table.relations)) {
6933
+ properties[relationName] = extractInputRelationSchema(
6934
+ relation,
6935
+ { ...context, depth: context.depth + 1 },
6936
+ options
6937
+ );
6938
+ }
6939
+ }
6940
+ const schema = {
6941
+ type: "object",
6942
+ properties,
6943
+ required
6944
+ };
6945
+ context.schemaCache.set(cacheKey, schema);
6946
+ return schema;
6947
+ };
6948
+ var isReadOnlyColumn = (column) => Boolean(column.autoIncrement || column.generated === "always");
6949
+ var isRequiredForCreate = (column) => {
6950
+ if (isReadOnlyColumn(column)) return false;
6951
+ if (column.default !== void 0) return false;
6952
+ return Boolean(column.notNull || column.primary);
6953
+ };
6954
+ var buildPrimaryKeySchema = (table, options) => {
6955
+ const primaryKey = findPrimaryKey(table);
6956
+ const column = table.columns[primaryKey];
6957
+ if (!column) {
6958
+ return {
6959
+ anyOf: [
6960
+ { type: "string" },
6961
+ { type: "number" },
6962
+ { type: "integer" }
6963
+ ]
6964
+ };
6965
+ }
6966
+ return mapColumnType(column, options);
6967
+ };
6968
+ var extractInputRelationSchema = (relation, context, options) => {
6969
+ const { type: relationType, isNullable } = mapRelationType(relation.type);
6970
+ const relationMode = options.relationMode ?? "mixed";
6971
+ const allowIds = relationMode !== "objects";
6972
+ const allowObjects = relationMode !== "ids";
6973
+ const variants = [];
6974
+ if (allowIds) {
6975
+ variants.push(buildPrimaryKeySchema(relation.target, options));
6976
+ }
6977
+ if (allowObjects) {
6978
+ const targetSchema = extractInputSchema(relation.target, context, options);
6979
+ variants.push(targetSchema);
6980
+ }
6981
+ const itemSchema = variants.length === 1 ? variants[0] : { anyOf: variants };
6982
+ if (relationType === "array") {
6983
+ return {
6984
+ type: "array",
6985
+ items: itemSchema,
6986
+ nullable: isNullable
6987
+ };
6988
+ }
6989
+ return {
6990
+ ...itemSchema,
6991
+ nullable: isNullable
6992
+ };
6993
+ };
6994
+ var extractFromProjectionNodes = (table, projectionNodes, context, options) => {
6995
+ const properties = {};
6996
+ const required = [];
6997
+ const includeDescriptions = Boolean(options.includeDescriptions);
6998
+ for (const node of projectionNodes) {
6999
+ if (!node || typeof node !== "object") continue;
7000
+ const projection = node;
7001
+ const propertyName = projection.alias ?? "";
7002
+ if (!propertyName) continue;
7003
+ if (projection.type === "Column") {
7004
+ const columnNode4 = node;
7005
+ const column = table.columns[columnNode4.name];
7006
+ if (!column) continue;
7007
+ const property = mapColumnType(column, options);
7008
+ properties[propertyName] = property;
7009
+ if (column.notNull || column.primary) {
7010
+ required.push(propertyName);
7011
+ }
7012
+ } else if (projection.type === "Function" || projection.type === "WindowFunction") {
7013
+ const fnNode = node;
7014
+ const functionName = fnNode.fn?.toUpperCase() ?? fnNode.name?.toUpperCase() ?? "";
7015
+ const propertySchema = projection.type === "Function" ? mapFunctionNodeToSchema(functionName, includeDescriptions) : mapWindowFunctionToSchema(functionName, includeDescriptions);
7016
+ properties[propertyName] = propertySchema;
7017
+ const isCountFunction = functionName === "COUNT";
7018
+ const isWindowRankFunction = functionName === "ROW_NUMBER" || functionName === "RANK";
7019
+ if (isCountFunction || isWindowRankFunction) {
7020
+ required.push(propertyName);
7021
+ }
7022
+ } else if (projection.type === "CaseExpression") {
7023
+ const propertySchema = {
7024
+ type: "string",
7025
+ nullable: true
7026
+ };
7027
+ if (includeDescriptions) {
7028
+ propertySchema.description = "Computed CASE expression";
7029
+ }
7030
+ properties[propertyName] = propertySchema;
7031
+ } else if (projection.type === "ScalarSubquery") {
7032
+ const propertySchema = {
7033
+ type: "object",
7034
+ nullable: true
7035
+ };
7036
+ if (includeDescriptions) {
7037
+ propertySchema.description = "Subquery result";
7038
+ }
7039
+ properties[propertyName] = propertySchema;
7040
+ } else if (projection.type === "CastExpression") {
7041
+ const propertySchema = {
7042
+ type: "string",
7043
+ nullable: true
7044
+ };
7045
+ if (includeDescriptions) {
7046
+ propertySchema.description = "CAST expression result";
7047
+ }
7048
+ properties[propertyName] = propertySchema;
7049
+ }
7050
+ }
7051
+ return {
7052
+ type: "object",
7053
+ properties,
7054
+ required
7055
+ };
7056
+ };
7057
+ var mapFunctionNodeToSchema = (functionName, includeDescriptions) => {
7058
+ const upperName = functionName.toUpperCase();
7059
+ switch (upperName) {
7060
+ case "COUNT":
7061
+ case "SUM":
7062
+ case "AVG":
7063
+ case "MIN":
7064
+ case "MAX":
7065
+ return withOptionalDescription({
7066
+ type: "number",
7067
+ nullable: false
7068
+ }, includeDescriptions, `${upperName} aggregate function result`);
7069
+ case "GROUP_CONCAT":
7070
+ case "STRING_AGG":
7071
+ case "ARRAY_AGG":
7072
+ return withOptionalDescription({
7073
+ type: "string",
7074
+ nullable: true
7075
+ }, includeDescriptions, `${upperName} aggregate function result`);
7076
+ case "JSON_ARRAYAGG":
7077
+ case "JSON_OBJECTAGG":
7078
+ return withOptionalDescription({
7079
+ type: "object",
7080
+ nullable: true
7081
+ }, includeDescriptions, `${upperName} aggregate function result`);
7082
+ default:
7083
+ return withOptionalDescription({
7084
+ type: "string",
7085
+ nullable: true
7086
+ }, includeDescriptions, `Unknown function: ${functionName}`);
7087
+ }
7088
+ };
7089
+ var mapWindowFunctionToSchema = (functionName, includeDescriptions) => {
7090
+ const upperName = functionName.toUpperCase();
7091
+ switch (upperName) {
7092
+ case "ROW_NUMBER":
7093
+ case "RANK":
7094
+ case "DENSE_RANK":
7095
+ case "NTILE":
7096
+ return withOptionalDescription({
7097
+ type: "integer",
7098
+ nullable: false
7099
+ }, includeDescriptions, `${upperName} window function result`);
7100
+ case "LAG":
7101
+ case "LEAD":
7102
+ case "FIRST_VALUE":
7103
+ case "LAST_VALUE":
7104
+ return withOptionalDescription({
7105
+ type: "string",
7106
+ nullable: true
7107
+ }, includeDescriptions, `${upperName} window function result`);
7108
+ default:
7109
+ return withOptionalDescription({
7110
+ type: "string",
7111
+ nullable: true
7112
+ }, includeDescriptions, `Unknown window function: ${functionName}`);
7113
+ }
7114
+ };
7115
+ var withOptionalDescription = (schema, includeDescriptions, description) => {
7116
+ if (includeDescriptions) {
7117
+ return { ...schema, description };
7118
+ }
7119
+ return schema;
7120
+ };
7121
+ var extractSelectedSchema = (table, plan, context, options) => {
7122
+ const properties = {};
7123
+ const required = [];
7124
+ plan.rootColumns.forEach((columnName) => {
7125
+ const column = table.columns[columnName];
7126
+ if (!column) return;
7127
+ properties[columnName] = mapColumnType(column, options);
7128
+ if (column.notNull || column.primary) {
7129
+ required.push(columnName);
7130
+ }
7131
+ });
7132
+ plan.relations.forEach((relationPlan) => {
7133
+ const relation = table.relations[relationPlan.name];
7134
+ if (!relation) return;
7135
+ const relationSchema = extractRelationSchema(
7136
+ relation,
7137
+ relationPlan,
7138
+ relationPlan.columns,
7139
+ context,
7140
+ options
7141
+ );
7142
+ properties[relationPlan.name] = relationSchema;
7143
+ const { isNullable } = mapRelationType(relation.type);
7144
+ if (!isNullable && relationPlan.name) {
7145
+ required.push(relationPlan.name);
7146
+ }
7147
+ });
7148
+ return {
7149
+ type: "object",
7150
+ properties,
7151
+ required
7152
+ };
7153
+ };
7154
+ var extractFullTableSchema = (table, context, options) => {
7155
+ const cacheKey = table.name;
7156
+ if (context.schemaCache.has(cacheKey)) {
7157
+ return context.schemaCache.get(cacheKey);
7158
+ }
7159
+ if (context.visitedTables.has(cacheKey) && context.depth > 0) {
7160
+ return buildCircularReferenceSchema(table.name, "output");
7161
+ }
7162
+ context.visitedTables.add(cacheKey);
7163
+ const properties = {};
7164
+ const required = [];
7165
+ Object.entries(table.columns).forEach(([columnName, column]) => {
7166
+ properties[columnName] = mapColumnType(column, options);
7167
+ if (column.notNull || column.primary) {
7168
+ required.push(columnName);
7169
+ }
7170
+ });
7171
+ Object.entries(table.relations).forEach(([relationName, relation]) => {
7172
+ if (context.depth >= context.maxDepth) {
7173
+ return;
7174
+ }
7175
+ const relationSchema = extractRelationSchema(
7176
+ relation,
7177
+ void 0,
7178
+ [],
7179
+ { ...context, depth: context.depth + 1 },
7180
+ options
7181
+ );
7182
+ properties[relationName] = relationSchema;
7183
+ const { isNullable } = mapRelationType(relation.type);
7184
+ if (!isNullable) {
7185
+ required.push(relationName);
7186
+ }
7187
+ });
7188
+ const schema = {
7189
+ type: "object",
7190
+ properties,
7191
+ required
7192
+ };
7193
+ context.schemaCache.set(cacheKey, schema);
7194
+ return schema;
7195
+ };
7196
+ var extractRelationSchema = (relation, relationPlan, selectedColumns, context, options) => {
7197
+ const targetTable = relation.target;
7198
+ const { type: relationType, isNullable } = mapRelationType(relation.type);
7199
+ let targetSchema;
7200
+ if (relationPlan && selectedColumns.length > 0) {
7201
+ const plan = {
7202
+ rootTable: targetTable.name,
7203
+ rootPrimaryKey: relationPlan.targetPrimaryKey,
7204
+ rootColumns: selectedColumns,
7205
+ relations: []
7206
+ };
7207
+ targetSchema = extractSelectedSchema(targetTable, plan, context, options);
7208
+ } else {
7209
+ targetSchema = extractFullTableSchema(targetTable, context, options);
7210
+ }
7211
+ if (relationType === "array") {
7212
+ return {
7213
+ type: "array",
7214
+ items: targetSchema,
7215
+ nullable: isNullable
7216
+ };
7217
+ }
7218
+ return {
7219
+ type: "object",
7220
+ properties: targetSchema.properties,
7221
+ required: targetSchema.required,
7222
+ nullable: isNullable,
7223
+ description: targetSchema.description
7224
+ };
7225
+ };
7226
+ var buildCircularReferenceSchema = (tableName, kind) => ({
7227
+ type: "object",
7228
+ properties: {
7229
+ _ref: {
7230
+ type: "string",
7231
+ description: `Circular ${kind} reference to ${tableName}`
7232
+ }
7233
+ },
7234
+ required: []
7235
+ });
7236
+ var schemaToJson = (schema, pretty = false) => {
7237
+ return JSON.stringify(schema, null, pretty ? 2 : 0);
7238
+ };
7239
+
7240
+ // src/openapi/query-parameters.ts
7241
+ var FILTER_PARAM_NAME = "filter";
7242
+ var buildRootTableNames = (table, from) => {
7243
+ const names = /* @__PURE__ */ new Set([table.name]);
7244
+ if (from?.type === "Table") {
7245
+ names.add(from.name);
7246
+ if (from.alias) names.add(from.alias);
7247
+ }
7248
+ return names;
7249
+ };
7250
+ var collectFilterColumns = (expr, table, rootTables) => {
7251
+ const columns = /* @__PURE__ */ new Set();
7252
+ const recordColumn = (node) => {
7253
+ if (!rootTables.has(node.table)) return;
7254
+ if (node.name in table.columns) {
7255
+ columns.add(node.name);
7256
+ }
7257
+ };
7258
+ const visitOrderingTerm = (term) => {
7259
+ if (!term || typeof term !== "object") return;
7260
+ if (isOperandNode(term)) {
7261
+ visitOperand2(term);
7262
+ return;
7263
+ }
7264
+ if ("type" in term) {
7265
+ visitExpression2(term);
7266
+ }
7267
+ };
7268
+ const visitOrderBy = (orderBy) => {
7269
+ if (!orderBy) return;
7270
+ orderBy.forEach((node) => visitOrderingTerm(node.term));
7271
+ };
7272
+ const visitOperand2 = (node) => {
7273
+ switch (node.type) {
7274
+ case "Column":
7275
+ recordColumn(node);
7276
+ return;
7277
+ case "Function": {
7278
+ const fn8 = node;
7279
+ fn8.args?.forEach(visitOperand2);
7280
+ visitOrderBy(fn8.orderBy);
7281
+ if (fn8.separator) visitOperand2(fn8.separator);
7282
+ return;
7283
+ }
7284
+ case "JsonPath": {
7285
+ const jp = node;
7286
+ recordColumn(jp.column);
7287
+ return;
7288
+ }
7289
+ case "ScalarSubquery":
7290
+ return;
7291
+ case "CaseExpression": {
7292
+ const cs = node;
7293
+ cs.conditions.forEach((condition) => {
7294
+ visitExpression2(condition.when);
7295
+ visitOperand2(condition.then);
7296
+ });
7297
+ if (cs.else) visitOperand2(cs.else);
7298
+ return;
7299
+ }
7300
+ case "Cast": {
7301
+ const cast2 = node;
7302
+ visitOperand2(cast2.expression);
7303
+ return;
7304
+ }
7305
+ case "WindowFunction": {
7306
+ const windowFn = node;
7307
+ windowFn.args?.forEach(visitOperand2);
7308
+ windowFn.partitionBy?.forEach(recordColumn);
7309
+ visitOrderBy(windowFn.orderBy);
7310
+ return;
7311
+ }
7312
+ case "ArithmeticExpression": {
7313
+ const arith = node;
7314
+ visitOperand2(arith.left);
7315
+ visitOperand2(arith.right);
7316
+ return;
7317
+ }
7318
+ case "BitwiseExpression": {
7319
+ const bitwise = node;
7320
+ visitOperand2(bitwise.left);
7321
+ visitOperand2(bitwise.right);
7322
+ return;
7323
+ }
7324
+ case "Collate": {
7325
+ const collate2 = node;
7326
+ visitOperand2(collate2.expression);
7327
+ return;
7328
+ }
7329
+ case "AliasRef":
7330
+ case "Literal":
7331
+ return;
7332
+ default:
7333
+ return;
7334
+ }
7335
+ };
7336
+ const visitExpression2 = (node) => {
7337
+ switch (node.type) {
7338
+ case "BinaryExpression":
7339
+ visitOperand2(node.left);
7340
+ visitOperand2(node.right);
7341
+ if (node.escape) visitOperand2(node.escape);
7342
+ return;
7343
+ case "LogicalExpression":
7344
+ node.operands.forEach(visitExpression2);
7345
+ return;
7346
+ case "NullExpression":
7347
+ visitOperand2(node.left);
7348
+ return;
7349
+ case "InExpression":
7350
+ visitOperand2(node.left);
7351
+ if (Array.isArray(node.right)) {
7352
+ node.right.forEach(visitOperand2);
7353
+ }
7354
+ return;
7355
+ case "ExistsExpression":
7356
+ return;
7357
+ case "BetweenExpression":
7358
+ visitOperand2(node.left);
7359
+ visitOperand2(node.lower);
7360
+ visitOperand2(node.upper);
7361
+ return;
7362
+ case "ArithmeticExpression":
7363
+ visitOperand2(node.left);
7364
+ visitOperand2(node.right);
7365
+ return;
7366
+ case "BitwiseExpression":
7367
+ visitOperand2(node.left);
7368
+ visitOperand2(node.right);
7369
+ return;
7370
+ default:
7371
+ return;
7372
+ }
7373
+ };
7374
+ visitExpression2(expr);
7375
+ return columns;
7376
+ };
7377
+ var buildFilterParameters = (table, where, from, options = {}) => {
7378
+ if (!where) return [];
7379
+ const rootTables = buildRootTableNames(table, from);
7380
+ const columnNames = collectFilterColumns(where, table, rootTables);
7381
+ let schema;
7382
+ if (columnNames.size) {
7383
+ const properties = {};
7384
+ for (const name of columnNames) {
7385
+ const column = table.columns[name];
7386
+ if (!column) continue;
7387
+ properties[name] = mapColumnType(column, options);
7388
+ }
7389
+ schema = {
7390
+ type: "object",
7391
+ properties
7392
+ };
7393
+ } else {
7394
+ schema = {
7395
+ type: "object",
7396
+ additionalProperties: true
7397
+ };
7398
+ }
7399
+ return [{
7400
+ name: FILTER_PARAM_NAME,
7401
+ in: "query",
7402
+ style: "deepObject",
7403
+ explode: true,
7404
+ schema
7405
+ }];
7406
+ };
7407
+
6667
7408
  // src/query-builder/select.ts
6668
7409
  var SelectQueryBuilder = class _SelectQueryBuilder {
6669
7410
  env;
@@ -7473,7 +8214,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
7473
8214
  return this.compile(dialect).sql;
7474
8215
  }
7475
8216
  /**
7476
- * Gets the hydration plan for the query
8217
+ * Gets hydration plan for query
7477
8218
  * @returns Hydration plan or undefined if none exists
7478
8219
  * @example
7479
8220
  * const plan = qb.include('posts').getHydrationPlan();
@@ -7482,6 +8223,28 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
7482
8223
  getHydrationPlan() {
7483
8224
  return this.context.hydration.getPlan();
7484
8225
  }
8226
+ /**
8227
+ * Gets OpenAPI 3.1 JSON Schemas for query output and optional input payloads
8228
+ * @param options - Schema generation options
8229
+ * @returns OpenAPI 3.1 JSON Schemas for query output and input payloads
8230
+ * @example
8231
+ * const { output } = qb.select('id', 'title', 'author').getSchema();
8232
+ * console.log(JSON.stringify(output, null, 2));
8233
+ */
8234
+ getSchema(options) {
8235
+ const plan = this.context.hydration.getPlan();
8236
+ const bundle = extractSchema(this.env.table, plan, this.context.state.ast.columns, options);
8237
+ const parameters = buildFilterParameters(
8238
+ this.env.table,
8239
+ this.context.state.ast.where,
8240
+ this.context.state.ast.from,
8241
+ options ?? {}
8242
+ );
8243
+ if (parameters.length) {
8244
+ return { ...bundle, parameters };
8245
+ }
8246
+ return bundle;
8247
+ }
7485
8248
  /**
7486
8249
  * Gets the Abstract Syntax Tree (AST) representation of the query
7487
8250
  * @returns Query AST with hydration applied
@@ -8511,14 +9274,14 @@ var buildAddColumnSql = (table, colName, dialect) => {
8511
9274
  const rendered = renderColumnDefinition(table, column, dialect);
8512
9275
  return `ALTER TABLE ${dialect.formatTableName(table)} ADD ${rendered.sql};`;
8513
9276
  };
8514
- var normalizeType = (value) => (value || "").toLowerCase().replace(/\s+/g, " ").trim();
9277
+ var normalizeType2 = (value) => (value || "").toLowerCase().replace(/\s+/g, " ").trim();
8515
9278
  var normalizeDefault = (value) => {
8516
9279
  if (value === void 0 || value === null) return void 0;
8517
9280
  return String(value).trim();
8518
9281
  };
8519
9282
  var diffColumn = (expected, actual, dialect) => {
8520
- const expectedType = normalizeType(dialect.renderColumnType(expected));
8521
- const actualType = normalizeType(actual.type);
9283
+ const expectedType = normalizeType2(dialect.renderColumnType(expected));
9284
+ const actualType = normalizeType2(actual.type);
8522
9285
  const expectedDefault = expected.default !== void 0 ? normalizeDefault(dialect.renderDefault(expected.default, expected)) : void 0;
8523
9286
  const actualDefault = normalizeDefault(actual.default);
8524
9287
  return {
@@ -11097,6 +11860,7 @@ var UnitOfWork = class {
11097
11860
  const compiled = builder.compile(this.dialect);
11098
11861
  const results = await this.executeCompiled(compiled);
11099
11862
  this.applyReturningResults(tracked, results);
11863
+ this.applyInsertId(tracked, results);
11100
11864
  tracked.status = "managed" /* Managed */;
11101
11865
  tracked.original = this.createSnapshot(tracked.table, tracked.entity);
11102
11866
  tracked.pk = this.getPrimaryKeyValue(tracked);
@@ -11222,6 +11986,16 @@ var UnitOfWork = class {
11222
11986
  tracked.entity[columnName] = row[i];
11223
11987
  }
11224
11988
  }
11989
+ applyInsertId(tracked, results) {
11990
+ if (this.dialect.supportsReturning()) return;
11991
+ if (tracked.pk != null) return;
11992
+ const pkName = findPrimaryKey(tracked.table);
11993
+ const pkColumn = tracked.table.columns[pkName];
11994
+ if (!pkColumn?.autoIncrement) return;
11995
+ const insertId = results.find((result) => typeof result.insertId === "number")?.insertId;
11996
+ if (insertId == null) return;
11997
+ tracked.entity[pkName] = insertId;
11998
+ }
11225
11999
  /**
11226
12000
  * Normalizes a column name by removing quotes and table prefixes.
11227
12001
  * @param column - The column name to normalize
@@ -12738,7 +13512,9 @@ function createMysqlExecutor(client) {
12738
13512
  async executeSql(sql, params) {
12739
13513
  const [rows] = await client.query(sql, params);
12740
13514
  if (!Array.isArray(rows)) {
12741
- return [{ columns: [], values: [] }];
13515
+ const insertId = rows?.insertId;
13516
+ const normalized = typeof insertId === "number" && insertId > 0 ? insertId : void 0;
13517
+ return [{ columns: [], values: [], insertId: normalized }];
12742
13518
  }
12743
13519
  const result = rowsToQueryResult(
12744
13520
  rows
@@ -12999,6 +13775,7 @@ export {
12999
13775
  HasMany,
13000
13776
  HasOne,
13001
13777
  InsertQueryBuilder,
13778
+ InterceptorPipeline,
13002
13779
  MySqlDialect,
13003
13780
  Orm,
13004
13781
  OrmSession,
@@ -13035,6 +13812,7 @@ export {
13035
13812
  bitOr,
13036
13813
  bitXor,
13037
13814
  bootstrapEntities,
13815
+ buildFilterParameters,
13038
13816
  caseWhen,
13039
13817
  cast,
13040
13818
  cbrt,
@@ -13096,6 +13874,7 @@ export {
13096
13874
  exists,
13097
13875
  exp,
13098
13876
  extract,
13877
+ extractSchema,
13099
13878
  firstValue,
13100
13879
  floor,
13101
13880
  fromUnixTime,
@@ -13106,6 +13885,7 @@ export {
13106
13885
  getDecoratorMetadata,
13107
13886
  getSchemaIntrospector,
13108
13887
  getTableDefFromEntity,
13888
+ getTemporalFormat,
13109
13889
  greatest,
13110
13890
  groupConcat,
13111
13891
  gt,
@@ -13161,6 +13941,8 @@ export {
13161
13941
  lt,
13162
13942
  lte,
13163
13943
  ltrim,
13944
+ mapColumnType,
13945
+ mapRelationType,
13164
13946
  materializeAs,
13165
13947
  max,
13166
13948
  md5,
@@ -13206,6 +13988,7 @@ export {
13206
13988
  rowsToQueryResult,
13207
13989
  rpad,
13208
13990
  rtrim,
13991
+ schemaToJson,
13209
13992
  second,
13210
13993
  sel,
13211
13994
  selectFrom,