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.cjs CHANGED
@@ -59,6 +59,7 @@ __export(index_exports, {
59
59
  HasMany: () => HasMany,
60
60
  HasOne: () => HasOne,
61
61
  InsertQueryBuilder: () => InsertQueryBuilder,
62
+ InterceptorPipeline: () => InterceptorPipeline,
62
63
  MySqlDialect: () => MySqlDialect,
63
64
  Orm: () => Orm,
64
65
  OrmSession: () => OrmSession,
@@ -95,6 +96,7 @@ __export(index_exports, {
95
96
  bitOr: () => bitOr,
96
97
  bitXor: () => bitXor,
97
98
  bootstrapEntities: () => bootstrapEntities,
99
+ buildFilterParameters: () => buildFilterParameters,
98
100
  caseWhen: () => caseWhen,
99
101
  cast: () => cast,
100
102
  cbrt: () => cbrt,
@@ -156,6 +158,7 @@ __export(index_exports, {
156
158
  exists: () => exists,
157
159
  exp: () => exp,
158
160
  extract: () => extract,
161
+ extractSchema: () => extractSchema,
159
162
  firstValue: () => firstValue,
160
163
  floor: () => floor,
161
164
  fromUnixTime: () => fromUnixTime,
@@ -166,6 +169,7 @@ __export(index_exports, {
166
169
  getDecoratorMetadata: () => getDecoratorMetadata,
167
170
  getSchemaIntrospector: () => getSchemaIntrospector,
168
171
  getTableDefFromEntity: () => getTableDefFromEntity,
172
+ getTemporalFormat: () => getTemporalFormat,
169
173
  greatest: () => greatest,
170
174
  groupConcat: () => groupConcat,
171
175
  gt: () => gt,
@@ -221,6 +225,8 @@ __export(index_exports, {
221
225
  lt: () => lt,
222
226
  lte: () => lte,
223
227
  ltrim: () => ltrim,
228
+ mapColumnType: () => mapColumnType,
229
+ mapRelationType: () => mapRelationType,
224
230
  materializeAs: () => materializeAs,
225
231
  max: () => max,
226
232
  md5: () => md5,
@@ -266,6 +272,7 @@ __export(index_exports, {
266
272
  rowsToQueryResult: () => rowsToQueryResult,
267
273
  rpad: () => rpad,
268
274
  rtrim: () => rtrim,
275
+ schemaToJson: () => schemaToJson,
269
276
  second: () => second,
270
277
  sel: () => sel,
271
278
  selectFrom: () => selectFrom,
@@ -2545,6 +2552,9 @@ var PostgresDialect = class extends SqlDialectBase {
2545
2552
  quoteIdentifier(id) {
2546
2553
  return `"${id}"`;
2547
2554
  }
2555
+ formatPlaceholder(index) {
2556
+ return `$${index}`;
2557
+ }
2548
2558
  /**
2549
2559
  * Compiles JSON path expression using PostgreSQL syntax
2550
2560
  * @param node - JSON path node
@@ -6940,6 +6950,744 @@ var SelectRelationFacet = class {
6940
6950
  }
6941
6951
  };
6942
6952
 
6953
+ // src/openapi/type-mappers.ts
6954
+ var mapColumnType = (column, options = {}) => {
6955
+ const resolved = resolveColumnOptions(options);
6956
+ const sqlType = normalizeType(column.type);
6957
+ const baseSchema = mapSqlTypeToBaseSchema(sqlType, column);
6958
+ const schema = {
6959
+ ...baseSchema
6960
+ };
6961
+ if (resolved.includeDescriptions && column.comment) {
6962
+ schema.description = column.comment;
6963
+ }
6964
+ if (resolved.includeNullable) {
6965
+ schema.nullable = !column.notNull && !column.primary;
6966
+ }
6967
+ if ((sqlType === "varchar" || sqlType === "char") && column.args) {
6968
+ schema.maxLength = column.args[0];
6969
+ }
6970
+ if ((sqlType === "decimal" || sqlType === "float") && column.args) {
6971
+ if (column.args.length >= 1) {
6972
+ schema.minimum = -(10 ** column.args[0]);
6973
+ }
6974
+ }
6975
+ if (!resolved.includeEnums) {
6976
+ delete schema.enum;
6977
+ } else if (sqlType === "enum" && column.args && column.args.length > 0) {
6978
+ schema.enum = column.args;
6979
+ }
6980
+ if (resolved.includeDefaults && column.default !== void 0) {
6981
+ schema.default = column.default;
6982
+ }
6983
+ return schema;
6984
+ };
6985
+ var normalizeType = (type) => {
6986
+ return type.toLowerCase();
6987
+ };
6988
+ var mapSqlTypeToBaseSchema = (sqlType, column) => {
6989
+ const type = normalizeType(sqlType);
6990
+ const hasCustomTsType = column.tsType !== void 0;
6991
+ switch (type) {
6992
+ case "int":
6993
+ case "integer":
6994
+ case "bigint":
6995
+ return {
6996
+ type: hasCustomTsType ? inferTypeFromTsType(column.tsType) : "integer",
6997
+ format: type === "bigint" ? "int64" : "int32",
6998
+ minimum: column.autoIncrement ? 1 : void 0
6999
+ };
7000
+ case "decimal":
7001
+ case "float":
7002
+ case "double":
7003
+ return {
7004
+ type: hasCustomTsType ? inferTypeFromTsType(column.tsType) : "number"
7005
+ };
7006
+ case "varchar":
7007
+ return {
7008
+ type: "string",
7009
+ minLength: column.notNull ? 1 : void 0,
7010
+ maxLength: column.args?.[0]
7011
+ };
7012
+ case "text":
7013
+ return {
7014
+ type: "string",
7015
+ minLength: column.notNull ? 1 : void 0
7016
+ };
7017
+ case "char":
7018
+ return {
7019
+ type: "string",
7020
+ minLength: column.notNull ? column.args?.[0] || 1 : void 0,
7021
+ maxLength: column.args?.[0]
7022
+ };
7023
+ case "boolean":
7024
+ return {
7025
+ type: "boolean"
7026
+ };
7027
+ case "json":
7028
+ return {
7029
+ anyOf: [
7030
+ { type: "object" },
7031
+ { type: "array" }
7032
+ ]
7033
+ };
7034
+ case "blob":
7035
+ case "binary":
7036
+ case "varbinary":
7037
+ return {
7038
+ type: "string",
7039
+ format: "base64"
7040
+ };
7041
+ case "date":
7042
+ return {
7043
+ type: "string",
7044
+ format: "date"
7045
+ };
7046
+ case "datetime":
7047
+ case "timestamp":
7048
+ return {
7049
+ type: "string",
7050
+ format: "date-time"
7051
+ };
7052
+ case "timestamptz":
7053
+ return {
7054
+ type: "string",
7055
+ format: "date-time"
7056
+ };
7057
+ case "uuid":
7058
+ return {
7059
+ type: "string",
7060
+ format: "uuid",
7061
+ pattern: "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
7062
+ };
7063
+ case "enum":
7064
+ return {
7065
+ type: "string",
7066
+ enum: column.args || []
7067
+ };
7068
+ default:
7069
+ if (column.dialectTypes?.postgres && column.dialectTypes.postgres === "bytea") {
7070
+ return {
7071
+ type: "string",
7072
+ format: "base64"
7073
+ };
7074
+ }
7075
+ return {
7076
+ type: "string"
7077
+ };
7078
+ }
7079
+ };
7080
+ var inferTypeFromTsType = (tsType) => {
7081
+ if (typeof tsType === "string") {
7082
+ if (tsType === "number") return "number";
7083
+ if (tsType === "string") return "string";
7084
+ if (tsType === "boolean") return "boolean";
7085
+ }
7086
+ if (typeof tsType === "function") {
7087
+ const typeStr = tsType.name?.toLowerCase();
7088
+ if (typeStr === "number") return "number";
7089
+ if (typeStr === "string") return "string";
7090
+ if (typeStr === "boolean") return "boolean";
7091
+ if (typeStr === "array") return "array";
7092
+ if (typeStr === "object") return "object";
7093
+ }
7094
+ return "string";
7095
+ };
7096
+ var resolveColumnOptions = (options) => ({
7097
+ includeDescriptions: options.includeDescriptions ?? false,
7098
+ includeEnums: options.includeEnums ?? true,
7099
+ includeExamples: options.includeExamples ?? false,
7100
+ includeDefaults: options.includeDefaults ?? true,
7101
+ includeNullable: options.includeNullable ?? true
7102
+ });
7103
+ var mapRelationType = (relationType) => {
7104
+ switch (relationType) {
7105
+ case "HAS_MANY":
7106
+ case "BELONGS_TO_MANY":
7107
+ return { type: "array", isNullable: false };
7108
+ case "HAS_ONE":
7109
+ case "BELONGS_TO":
7110
+ return { type: "object", isNullable: true };
7111
+ default:
7112
+ return { type: "object", isNullable: true };
7113
+ }
7114
+ };
7115
+ var getTemporalFormat = (sqlType) => {
7116
+ const type = normalizeType(sqlType);
7117
+ switch (type) {
7118
+ case "date":
7119
+ return "date";
7120
+ case "datetime":
7121
+ case "timestamp":
7122
+ case "timestamptz":
7123
+ return "date-time";
7124
+ default:
7125
+ return void 0;
7126
+ }
7127
+ };
7128
+
7129
+ // src/openapi/schema-extractor.ts
7130
+ var DEFAULT_MAX_DEPTH = 5;
7131
+ var extractSchema = (table, plan, projectionNodes, options = {}) => {
7132
+ const outputOptions = resolveOutputOptions(options);
7133
+ const outputContext = createContext(outputOptions.maxDepth ?? DEFAULT_MAX_DEPTH);
7134
+ const output = extractOutputSchema(table, plan, projectionNodes, outputContext, outputOptions);
7135
+ const inputOptions = resolveInputOptions(options);
7136
+ if (!inputOptions) {
7137
+ return { output };
7138
+ }
7139
+ const inputContext = createContext(inputOptions.maxDepth ?? DEFAULT_MAX_DEPTH);
7140
+ const input = extractInputSchema(table, inputContext, inputOptions);
7141
+ return { output, input };
7142
+ };
7143
+ var resolveOutputOptions = (options) => ({
7144
+ mode: options.mode ?? "full",
7145
+ includeDescriptions: options.includeDescriptions,
7146
+ includeEnums: options.includeEnums,
7147
+ includeExamples: options.includeExamples,
7148
+ includeDefaults: options.includeDefaults,
7149
+ includeNullable: options.includeNullable,
7150
+ maxDepth: options.maxDepth ?? DEFAULT_MAX_DEPTH
7151
+ });
7152
+ var resolveInputOptions = (options) => {
7153
+ if (options.input === false) return void 0;
7154
+ const input = options.input ?? {};
7155
+ const mode = input.mode ?? "create";
7156
+ return {
7157
+ mode,
7158
+ includeRelations: input.includeRelations ?? true,
7159
+ relationMode: input.relationMode ?? "mixed",
7160
+ includeDescriptions: input.includeDescriptions ?? options.includeDescriptions,
7161
+ includeEnums: input.includeEnums ?? options.includeEnums,
7162
+ includeExamples: input.includeExamples ?? options.includeExamples,
7163
+ includeDefaults: input.includeDefaults ?? options.includeDefaults,
7164
+ includeNullable: input.includeNullable ?? options.includeNullable,
7165
+ maxDepth: input.maxDepth ?? options.maxDepth ?? DEFAULT_MAX_DEPTH,
7166
+ omitReadOnly: input.omitReadOnly ?? true,
7167
+ excludePrimaryKey: input.excludePrimaryKey ?? false,
7168
+ requirePrimaryKey: input.requirePrimaryKey ?? mode === "update"
7169
+ };
7170
+ };
7171
+ var createContext = (maxDepth) => ({
7172
+ visitedTables: /* @__PURE__ */ new Set(),
7173
+ schemaCache: /* @__PURE__ */ new Map(),
7174
+ depth: 0,
7175
+ maxDepth
7176
+ });
7177
+ var extractOutputSchema = (table, plan, projectionNodes, context, options) => {
7178
+ const mode = options.mode ?? "full";
7179
+ const hasComputedFields = projectionNodes && projectionNodes.some(
7180
+ (node) => node.type !== "Column"
7181
+ );
7182
+ if (hasComputedFields) {
7183
+ return extractFromProjectionNodes(table, projectionNodes, context, options);
7184
+ }
7185
+ if (mode === "selected" && plan) {
7186
+ return extractSelectedSchema(table, plan, context, options);
7187
+ }
7188
+ return extractFullTableSchema(table, context, options);
7189
+ };
7190
+ var extractInputSchema = (table, context, options) => {
7191
+ const cacheKey = `${table.name}:${options.mode ?? "create"}`;
7192
+ if (context.schemaCache.has(cacheKey)) {
7193
+ return context.schemaCache.get(cacheKey);
7194
+ }
7195
+ if (context.visitedTables.has(cacheKey) && context.depth > 0) {
7196
+ return buildCircularReferenceSchema(table.name, "input");
7197
+ }
7198
+ context.visitedTables.add(cacheKey);
7199
+ const properties = {};
7200
+ const required = [];
7201
+ const primaryKey = findPrimaryKey(table);
7202
+ for (const [columnName, column] of Object.entries(table.columns)) {
7203
+ const isPrimary = columnName === primaryKey || column.primary;
7204
+ if (options.excludePrimaryKey && isPrimary) continue;
7205
+ if (options.omitReadOnly && isReadOnlyColumn(column)) continue;
7206
+ properties[columnName] = mapColumnType(column, options);
7207
+ if (options.mode === "create" && isRequiredForCreate(column)) {
7208
+ required.push(columnName);
7209
+ }
7210
+ if (options.mode === "update" && options.requirePrimaryKey && isPrimary) {
7211
+ required.push(columnName);
7212
+ }
7213
+ }
7214
+ if (options.includeRelations && context.depth < context.maxDepth) {
7215
+ for (const [relationName, relation] of Object.entries(table.relations)) {
7216
+ properties[relationName] = extractInputRelationSchema(
7217
+ relation,
7218
+ { ...context, depth: context.depth + 1 },
7219
+ options
7220
+ );
7221
+ }
7222
+ }
7223
+ const schema = {
7224
+ type: "object",
7225
+ properties,
7226
+ required
7227
+ };
7228
+ context.schemaCache.set(cacheKey, schema);
7229
+ return schema;
7230
+ };
7231
+ var isReadOnlyColumn = (column) => Boolean(column.autoIncrement || column.generated === "always");
7232
+ var isRequiredForCreate = (column) => {
7233
+ if (isReadOnlyColumn(column)) return false;
7234
+ if (column.default !== void 0) return false;
7235
+ return Boolean(column.notNull || column.primary);
7236
+ };
7237
+ var buildPrimaryKeySchema = (table, options) => {
7238
+ const primaryKey = findPrimaryKey(table);
7239
+ const column = table.columns[primaryKey];
7240
+ if (!column) {
7241
+ return {
7242
+ anyOf: [
7243
+ { type: "string" },
7244
+ { type: "number" },
7245
+ { type: "integer" }
7246
+ ]
7247
+ };
7248
+ }
7249
+ return mapColumnType(column, options);
7250
+ };
7251
+ var extractInputRelationSchema = (relation, context, options) => {
7252
+ const { type: relationType, isNullable } = mapRelationType(relation.type);
7253
+ const relationMode = options.relationMode ?? "mixed";
7254
+ const allowIds = relationMode !== "objects";
7255
+ const allowObjects = relationMode !== "ids";
7256
+ const variants = [];
7257
+ if (allowIds) {
7258
+ variants.push(buildPrimaryKeySchema(relation.target, options));
7259
+ }
7260
+ if (allowObjects) {
7261
+ const targetSchema = extractInputSchema(relation.target, context, options);
7262
+ variants.push(targetSchema);
7263
+ }
7264
+ const itemSchema = variants.length === 1 ? variants[0] : { anyOf: variants };
7265
+ if (relationType === "array") {
7266
+ return {
7267
+ type: "array",
7268
+ items: itemSchema,
7269
+ nullable: isNullable
7270
+ };
7271
+ }
7272
+ return {
7273
+ ...itemSchema,
7274
+ nullable: isNullable
7275
+ };
7276
+ };
7277
+ var extractFromProjectionNodes = (table, projectionNodes, context, options) => {
7278
+ const properties = {};
7279
+ const required = [];
7280
+ const includeDescriptions = Boolean(options.includeDescriptions);
7281
+ for (const node of projectionNodes) {
7282
+ if (!node || typeof node !== "object") continue;
7283
+ const projection = node;
7284
+ const propertyName = projection.alias ?? "";
7285
+ if (!propertyName) continue;
7286
+ if (projection.type === "Column") {
7287
+ const columnNode4 = node;
7288
+ const column = table.columns[columnNode4.name];
7289
+ if (!column) continue;
7290
+ const property = mapColumnType(column, options);
7291
+ properties[propertyName] = property;
7292
+ if (column.notNull || column.primary) {
7293
+ required.push(propertyName);
7294
+ }
7295
+ } else if (projection.type === "Function" || projection.type === "WindowFunction") {
7296
+ const fnNode = node;
7297
+ const functionName = fnNode.fn?.toUpperCase() ?? fnNode.name?.toUpperCase() ?? "";
7298
+ const propertySchema = projection.type === "Function" ? mapFunctionNodeToSchema(functionName, includeDescriptions) : mapWindowFunctionToSchema(functionName, includeDescriptions);
7299
+ properties[propertyName] = propertySchema;
7300
+ const isCountFunction = functionName === "COUNT";
7301
+ const isWindowRankFunction = functionName === "ROW_NUMBER" || functionName === "RANK";
7302
+ if (isCountFunction || isWindowRankFunction) {
7303
+ required.push(propertyName);
7304
+ }
7305
+ } else if (projection.type === "CaseExpression") {
7306
+ const propertySchema = {
7307
+ type: "string",
7308
+ nullable: true
7309
+ };
7310
+ if (includeDescriptions) {
7311
+ propertySchema.description = "Computed CASE expression";
7312
+ }
7313
+ properties[propertyName] = propertySchema;
7314
+ } else if (projection.type === "ScalarSubquery") {
7315
+ const propertySchema = {
7316
+ type: "object",
7317
+ nullable: true
7318
+ };
7319
+ if (includeDescriptions) {
7320
+ propertySchema.description = "Subquery result";
7321
+ }
7322
+ properties[propertyName] = propertySchema;
7323
+ } else if (projection.type === "CastExpression") {
7324
+ const propertySchema = {
7325
+ type: "string",
7326
+ nullable: true
7327
+ };
7328
+ if (includeDescriptions) {
7329
+ propertySchema.description = "CAST expression result";
7330
+ }
7331
+ properties[propertyName] = propertySchema;
7332
+ }
7333
+ }
7334
+ return {
7335
+ type: "object",
7336
+ properties,
7337
+ required
7338
+ };
7339
+ };
7340
+ var mapFunctionNodeToSchema = (functionName, includeDescriptions) => {
7341
+ const upperName = functionName.toUpperCase();
7342
+ switch (upperName) {
7343
+ case "COUNT":
7344
+ case "SUM":
7345
+ case "AVG":
7346
+ case "MIN":
7347
+ case "MAX":
7348
+ return withOptionalDescription({
7349
+ type: "number",
7350
+ nullable: false
7351
+ }, includeDescriptions, `${upperName} aggregate function result`);
7352
+ case "GROUP_CONCAT":
7353
+ case "STRING_AGG":
7354
+ case "ARRAY_AGG":
7355
+ return withOptionalDescription({
7356
+ type: "string",
7357
+ nullable: true
7358
+ }, includeDescriptions, `${upperName} aggregate function result`);
7359
+ case "JSON_ARRAYAGG":
7360
+ case "JSON_OBJECTAGG":
7361
+ return withOptionalDescription({
7362
+ type: "object",
7363
+ nullable: true
7364
+ }, includeDescriptions, `${upperName} aggregate function result`);
7365
+ default:
7366
+ return withOptionalDescription({
7367
+ type: "string",
7368
+ nullable: true
7369
+ }, includeDescriptions, `Unknown function: ${functionName}`);
7370
+ }
7371
+ };
7372
+ var mapWindowFunctionToSchema = (functionName, includeDescriptions) => {
7373
+ const upperName = functionName.toUpperCase();
7374
+ switch (upperName) {
7375
+ case "ROW_NUMBER":
7376
+ case "RANK":
7377
+ case "DENSE_RANK":
7378
+ case "NTILE":
7379
+ return withOptionalDescription({
7380
+ type: "integer",
7381
+ nullable: false
7382
+ }, includeDescriptions, `${upperName} window function result`);
7383
+ case "LAG":
7384
+ case "LEAD":
7385
+ case "FIRST_VALUE":
7386
+ case "LAST_VALUE":
7387
+ return withOptionalDescription({
7388
+ type: "string",
7389
+ nullable: true
7390
+ }, includeDescriptions, `${upperName} window function result`);
7391
+ default:
7392
+ return withOptionalDescription({
7393
+ type: "string",
7394
+ nullable: true
7395
+ }, includeDescriptions, `Unknown window function: ${functionName}`);
7396
+ }
7397
+ };
7398
+ var withOptionalDescription = (schema, includeDescriptions, description) => {
7399
+ if (includeDescriptions) {
7400
+ return { ...schema, description };
7401
+ }
7402
+ return schema;
7403
+ };
7404
+ var extractSelectedSchema = (table, plan, context, options) => {
7405
+ const properties = {};
7406
+ const required = [];
7407
+ plan.rootColumns.forEach((columnName) => {
7408
+ const column = table.columns[columnName];
7409
+ if (!column) return;
7410
+ properties[columnName] = mapColumnType(column, options);
7411
+ if (column.notNull || column.primary) {
7412
+ required.push(columnName);
7413
+ }
7414
+ });
7415
+ plan.relations.forEach((relationPlan) => {
7416
+ const relation = table.relations[relationPlan.name];
7417
+ if (!relation) return;
7418
+ const relationSchema = extractRelationSchema(
7419
+ relation,
7420
+ relationPlan,
7421
+ relationPlan.columns,
7422
+ context,
7423
+ options
7424
+ );
7425
+ properties[relationPlan.name] = relationSchema;
7426
+ const { isNullable } = mapRelationType(relation.type);
7427
+ if (!isNullable && relationPlan.name) {
7428
+ required.push(relationPlan.name);
7429
+ }
7430
+ });
7431
+ return {
7432
+ type: "object",
7433
+ properties,
7434
+ required
7435
+ };
7436
+ };
7437
+ var extractFullTableSchema = (table, context, options) => {
7438
+ const cacheKey = table.name;
7439
+ if (context.schemaCache.has(cacheKey)) {
7440
+ return context.schemaCache.get(cacheKey);
7441
+ }
7442
+ if (context.visitedTables.has(cacheKey) && context.depth > 0) {
7443
+ return buildCircularReferenceSchema(table.name, "output");
7444
+ }
7445
+ context.visitedTables.add(cacheKey);
7446
+ const properties = {};
7447
+ const required = [];
7448
+ Object.entries(table.columns).forEach(([columnName, column]) => {
7449
+ properties[columnName] = mapColumnType(column, options);
7450
+ if (column.notNull || column.primary) {
7451
+ required.push(columnName);
7452
+ }
7453
+ });
7454
+ Object.entries(table.relations).forEach(([relationName, relation]) => {
7455
+ if (context.depth >= context.maxDepth) {
7456
+ return;
7457
+ }
7458
+ const relationSchema = extractRelationSchema(
7459
+ relation,
7460
+ void 0,
7461
+ [],
7462
+ { ...context, depth: context.depth + 1 },
7463
+ options
7464
+ );
7465
+ properties[relationName] = relationSchema;
7466
+ const { isNullable } = mapRelationType(relation.type);
7467
+ if (!isNullable) {
7468
+ required.push(relationName);
7469
+ }
7470
+ });
7471
+ const schema = {
7472
+ type: "object",
7473
+ properties,
7474
+ required
7475
+ };
7476
+ context.schemaCache.set(cacheKey, schema);
7477
+ return schema;
7478
+ };
7479
+ var extractRelationSchema = (relation, relationPlan, selectedColumns, context, options) => {
7480
+ const targetTable = relation.target;
7481
+ const { type: relationType, isNullable } = mapRelationType(relation.type);
7482
+ let targetSchema;
7483
+ if (relationPlan && selectedColumns.length > 0) {
7484
+ const plan = {
7485
+ rootTable: targetTable.name,
7486
+ rootPrimaryKey: relationPlan.targetPrimaryKey,
7487
+ rootColumns: selectedColumns,
7488
+ relations: []
7489
+ };
7490
+ targetSchema = extractSelectedSchema(targetTable, plan, context, options);
7491
+ } else {
7492
+ targetSchema = extractFullTableSchema(targetTable, context, options);
7493
+ }
7494
+ if (relationType === "array") {
7495
+ return {
7496
+ type: "array",
7497
+ items: targetSchema,
7498
+ nullable: isNullable
7499
+ };
7500
+ }
7501
+ return {
7502
+ type: "object",
7503
+ properties: targetSchema.properties,
7504
+ required: targetSchema.required,
7505
+ nullable: isNullable,
7506
+ description: targetSchema.description
7507
+ };
7508
+ };
7509
+ var buildCircularReferenceSchema = (tableName, kind) => ({
7510
+ type: "object",
7511
+ properties: {
7512
+ _ref: {
7513
+ type: "string",
7514
+ description: `Circular ${kind} reference to ${tableName}`
7515
+ }
7516
+ },
7517
+ required: []
7518
+ });
7519
+ var schemaToJson = (schema, pretty = false) => {
7520
+ return JSON.stringify(schema, null, pretty ? 2 : 0);
7521
+ };
7522
+
7523
+ // src/openapi/query-parameters.ts
7524
+ var FILTER_PARAM_NAME = "filter";
7525
+ var buildRootTableNames = (table, from) => {
7526
+ const names = /* @__PURE__ */ new Set([table.name]);
7527
+ if (from?.type === "Table") {
7528
+ names.add(from.name);
7529
+ if (from.alias) names.add(from.alias);
7530
+ }
7531
+ return names;
7532
+ };
7533
+ var collectFilterColumns = (expr, table, rootTables) => {
7534
+ const columns = /* @__PURE__ */ new Set();
7535
+ const recordColumn = (node) => {
7536
+ if (!rootTables.has(node.table)) return;
7537
+ if (node.name in table.columns) {
7538
+ columns.add(node.name);
7539
+ }
7540
+ };
7541
+ const visitOrderingTerm = (term) => {
7542
+ if (!term || typeof term !== "object") return;
7543
+ if (isOperandNode(term)) {
7544
+ visitOperand2(term);
7545
+ return;
7546
+ }
7547
+ if ("type" in term) {
7548
+ visitExpression2(term);
7549
+ }
7550
+ };
7551
+ const visitOrderBy = (orderBy) => {
7552
+ if (!orderBy) return;
7553
+ orderBy.forEach((node) => visitOrderingTerm(node.term));
7554
+ };
7555
+ const visitOperand2 = (node) => {
7556
+ switch (node.type) {
7557
+ case "Column":
7558
+ recordColumn(node);
7559
+ return;
7560
+ case "Function": {
7561
+ const fn8 = node;
7562
+ fn8.args?.forEach(visitOperand2);
7563
+ visitOrderBy(fn8.orderBy);
7564
+ if (fn8.separator) visitOperand2(fn8.separator);
7565
+ return;
7566
+ }
7567
+ case "JsonPath": {
7568
+ const jp = node;
7569
+ recordColumn(jp.column);
7570
+ return;
7571
+ }
7572
+ case "ScalarSubquery":
7573
+ return;
7574
+ case "CaseExpression": {
7575
+ const cs = node;
7576
+ cs.conditions.forEach((condition) => {
7577
+ visitExpression2(condition.when);
7578
+ visitOperand2(condition.then);
7579
+ });
7580
+ if (cs.else) visitOperand2(cs.else);
7581
+ return;
7582
+ }
7583
+ case "Cast": {
7584
+ const cast2 = node;
7585
+ visitOperand2(cast2.expression);
7586
+ return;
7587
+ }
7588
+ case "WindowFunction": {
7589
+ const windowFn = node;
7590
+ windowFn.args?.forEach(visitOperand2);
7591
+ windowFn.partitionBy?.forEach(recordColumn);
7592
+ visitOrderBy(windowFn.orderBy);
7593
+ return;
7594
+ }
7595
+ case "ArithmeticExpression": {
7596
+ const arith = node;
7597
+ visitOperand2(arith.left);
7598
+ visitOperand2(arith.right);
7599
+ return;
7600
+ }
7601
+ case "BitwiseExpression": {
7602
+ const bitwise = node;
7603
+ visitOperand2(bitwise.left);
7604
+ visitOperand2(bitwise.right);
7605
+ return;
7606
+ }
7607
+ case "Collate": {
7608
+ const collate2 = node;
7609
+ visitOperand2(collate2.expression);
7610
+ return;
7611
+ }
7612
+ case "AliasRef":
7613
+ case "Literal":
7614
+ return;
7615
+ default:
7616
+ return;
7617
+ }
7618
+ };
7619
+ const visitExpression2 = (node) => {
7620
+ switch (node.type) {
7621
+ case "BinaryExpression":
7622
+ visitOperand2(node.left);
7623
+ visitOperand2(node.right);
7624
+ if (node.escape) visitOperand2(node.escape);
7625
+ return;
7626
+ case "LogicalExpression":
7627
+ node.operands.forEach(visitExpression2);
7628
+ return;
7629
+ case "NullExpression":
7630
+ visitOperand2(node.left);
7631
+ return;
7632
+ case "InExpression":
7633
+ visitOperand2(node.left);
7634
+ if (Array.isArray(node.right)) {
7635
+ node.right.forEach(visitOperand2);
7636
+ }
7637
+ return;
7638
+ case "ExistsExpression":
7639
+ return;
7640
+ case "BetweenExpression":
7641
+ visitOperand2(node.left);
7642
+ visitOperand2(node.lower);
7643
+ visitOperand2(node.upper);
7644
+ return;
7645
+ case "ArithmeticExpression":
7646
+ visitOperand2(node.left);
7647
+ visitOperand2(node.right);
7648
+ return;
7649
+ case "BitwiseExpression":
7650
+ visitOperand2(node.left);
7651
+ visitOperand2(node.right);
7652
+ return;
7653
+ default:
7654
+ return;
7655
+ }
7656
+ };
7657
+ visitExpression2(expr);
7658
+ return columns;
7659
+ };
7660
+ var buildFilterParameters = (table, where, from, options = {}) => {
7661
+ if (!where) return [];
7662
+ const rootTables = buildRootTableNames(table, from);
7663
+ const columnNames = collectFilterColumns(where, table, rootTables);
7664
+ let schema;
7665
+ if (columnNames.size) {
7666
+ const properties = {};
7667
+ for (const name of columnNames) {
7668
+ const column = table.columns[name];
7669
+ if (!column) continue;
7670
+ properties[name] = mapColumnType(column, options);
7671
+ }
7672
+ schema = {
7673
+ type: "object",
7674
+ properties
7675
+ };
7676
+ } else {
7677
+ schema = {
7678
+ type: "object",
7679
+ additionalProperties: true
7680
+ };
7681
+ }
7682
+ return [{
7683
+ name: FILTER_PARAM_NAME,
7684
+ in: "query",
7685
+ style: "deepObject",
7686
+ explode: true,
7687
+ schema
7688
+ }];
7689
+ };
7690
+
6943
7691
  // src/query-builder/select.ts
6944
7692
  var SelectQueryBuilder = class _SelectQueryBuilder {
6945
7693
  env;
@@ -7749,7 +8497,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
7749
8497
  return this.compile(dialect).sql;
7750
8498
  }
7751
8499
  /**
7752
- * Gets the hydration plan for the query
8500
+ * Gets hydration plan for query
7753
8501
  * @returns Hydration plan or undefined if none exists
7754
8502
  * @example
7755
8503
  * const plan = qb.include('posts').getHydrationPlan();
@@ -7758,6 +8506,28 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
7758
8506
  getHydrationPlan() {
7759
8507
  return this.context.hydration.getPlan();
7760
8508
  }
8509
+ /**
8510
+ * Gets OpenAPI 3.1 JSON Schemas for query output and optional input payloads
8511
+ * @param options - Schema generation options
8512
+ * @returns OpenAPI 3.1 JSON Schemas for query output and input payloads
8513
+ * @example
8514
+ * const { output } = qb.select('id', 'title', 'author').getSchema();
8515
+ * console.log(JSON.stringify(output, null, 2));
8516
+ */
8517
+ getSchema(options) {
8518
+ const plan = this.context.hydration.getPlan();
8519
+ const bundle = extractSchema(this.env.table, plan, this.context.state.ast.columns, options);
8520
+ const parameters = buildFilterParameters(
8521
+ this.env.table,
8522
+ this.context.state.ast.where,
8523
+ this.context.state.ast.from,
8524
+ options ?? {}
8525
+ );
8526
+ if (parameters.length) {
8527
+ return { ...bundle, parameters };
8528
+ }
8529
+ return bundle;
8530
+ }
7761
8531
  /**
7762
8532
  * Gets the Abstract Syntax Tree (AST) representation of the query
7763
8533
  * @returns Query AST with hydration applied
@@ -8787,14 +9557,14 @@ var buildAddColumnSql = (table, colName, dialect) => {
8787
9557
  const rendered = renderColumnDefinition(table, column, dialect);
8788
9558
  return `ALTER TABLE ${dialect.formatTableName(table)} ADD ${rendered.sql};`;
8789
9559
  };
8790
- var normalizeType = (value) => (value || "").toLowerCase().replace(/\s+/g, " ").trim();
9560
+ var normalizeType2 = (value) => (value || "").toLowerCase().replace(/\s+/g, " ").trim();
8791
9561
  var normalizeDefault = (value) => {
8792
9562
  if (value === void 0 || value === null) return void 0;
8793
9563
  return String(value).trim();
8794
9564
  };
8795
9565
  var diffColumn = (expected, actual, dialect) => {
8796
- const expectedType = normalizeType(dialect.renderColumnType(expected));
8797
- const actualType = normalizeType(actual.type);
9566
+ const expectedType = normalizeType2(dialect.renderColumnType(expected));
9567
+ const actualType = normalizeType2(actual.type);
8798
9568
  const expectedDefault = expected.default !== void 0 ? normalizeDefault(dialect.renderDefault(expected.default, expected)) : void 0;
8799
9569
  const actualDefault = normalizeDefault(actual.default);
8800
9570
  return {
@@ -11373,6 +12143,7 @@ var UnitOfWork = class {
11373
12143
  const compiled = builder.compile(this.dialect);
11374
12144
  const results = await this.executeCompiled(compiled);
11375
12145
  this.applyReturningResults(tracked, results);
12146
+ this.applyInsertId(tracked, results);
11376
12147
  tracked.status = "managed" /* Managed */;
11377
12148
  tracked.original = this.createSnapshot(tracked.table, tracked.entity);
11378
12149
  tracked.pk = this.getPrimaryKeyValue(tracked);
@@ -11498,6 +12269,16 @@ var UnitOfWork = class {
11498
12269
  tracked.entity[columnName] = row[i];
11499
12270
  }
11500
12271
  }
12272
+ applyInsertId(tracked, results) {
12273
+ if (this.dialect.supportsReturning()) return;
12274
+ if (tracked.pk != null) return;
12275
+ const pkName = findPrimaryKey(tracked.table);
12276
+ const pkColumn = tracked.table.columns[pkName];
12277
+ if (!pkColumn?.autoIncrement) return;
12278
+ const insertId = results.find((result) => typeof result.insertId === "number")?.insertId;
12279
+ if (insertId == null) return;
12280
+ tracked.entity[pkName] = insertId;
12281
+ }
11501
12282
  /**
11502
12283
  * Normalizes a column name by removing quotes and table prefixes.
11503
12284
  * @param column - The column name to normalize
@@ -13014,7 +13795,9 @@ function createMysqlExecutor(client) {
13014
13795
  async executeSql(sql, params) {
13015
13796
  const [rows] = await client.query(sql, params);
13016
13797
  if (!Array.isArray(rows)) {
13017
- return [{ columns: [], values: [] }];
13798
+ const insertId = rows?.insertId;
13799
+ const normalized = typeof insertId === "number" && insertId > 0 ? insertId : void 0;
13800
+ return [{ columns: [], values: [], insertId: normalized }];
13018
13801
  }
13019
13802
  const result = rowsToQueryResult(
13020
13803
  rows
@@ -13276,6 +14059,7 @@ function createPooledExecutorFactory(opts) {
13276
14059
  HasMany,
13277
14060
  HasOne,
13278
14061
  InsertQueryBuilder,
14062
+ InterceptorPipeline,
13279
14063
  MySqlDialect,
13280
14064
  Orm,
13281
14065
  OrmSession,
@@ -13312,6 +14096,7 @@ function createPooledExecutorFactory(opts) {
13312
14096
  bitOr,
13313
14097
  bitXor,
13314
14098
  bootstrapEntities,
14099
+ buildFilterParameters,
13315
14100
  caseWhen,
13316
14101
  cast,
13317
14102
  cbrt,
@@ -13373,6 +14158,7 @@ function createPooledExecutorFactory(opts) {
13373
14158
  exists,
13374
14159
  exp,
13375
14160
  extract,
14161
+ extractSchema,
13376
14162
  firstValue,
13377
14163
  floor,
13378
14164
  fromUnixTime,
@@ -13383,6 +14169,7 @@ function createPooledExecutorFactory(opts) {
13383
14169
  getDecoratorMetadata,
13384
14170
  getSchemaIntrospector,
13385
14171
  getTableDefFromEntity,
14172
+ getTemporalFormat,
13386
14173
  greatest,
13387
14174
  groupConcat,
13388
14175
  gt,
@@ -13438,6 +14225,8 @@ function createPooledExecutorFactory(opts) {
13438
14225
  lt,
13439
14226
  lte,
13440
14227
  ltrim,
14228
+ mapColumnType,
14229
+ mapRelationType,
13441
14230
  materializeAs,
13442
14231
  max,
13443
14232
  md5,
@@ -13483,6 +14272,7 @@ function createPooledExecutorFactory(opts) {
13483
14272
  rowsToQueryResult,
13484
14273
  rpad,
13485
14274
  rtrim,
14275
+ schemaToJson,
13486
14276
  second,
13487
14277
  sel,
13488
14278
  selectFrom,