metal-orm 1.0.87 → 1.0.89

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
@@ -7249,47 +7249,52 @@ var getTemporalFormat = (sqlType) => {
7249
7249
  }
7250
7250
  };
7251
7251
 
7252
- // src/openapi/schema-extractor.ts
7253
- var DEFAULT_MAX_DEPTH = 5;
7254
- var extractSchema = (table, plan, projectionNodes, options = {}) => {
7255
- const outputOptions = resolveOutputOptions(options);
7256
- const outputContext = createContext(outputOptions.maxDepth ?? DEFAULT_MAX_DEPTH);
7257
- const output = extractOutputSchema(table, plan, projectionNodes, outputContext, outputOptions);
7258
- const inputOptions = resolveInputOptions(options);
7259
- if (!inputOptions) {
7260
- return { output };
7252
+ // src/openapi/schema-extractor-utils.ts
7253
+ var hasComputedProjection = (projectionNodes) => Boolean(projectionNodes && projectionNodes.some((node) => node.type !== "Column"));
7254
+ var shouldUseSelectedSchema = (options, plan, projectionNodes) => {
7255
+ if (!plan || options.mode !== "selected") return false;
7256
+ if (hasComputedProjection(projectionNodes)) return false;
7257
+ if (options.refMode === "components" && options.selectedRefMode !== "components") return false;
7258
+ return true;
7259
+ };
7260
+ var resolveComponentName = (table, options) => options.componentName ? options.componentName(table) : table.name;
7261
+ var normalizeColumns = (columns) => Array.from(new Set(columns)).sort((a, b) => a.localeCompare(b));
7262
+ var buildSelectionSignature = (plan) => {
7263
+ const relations = plan.relations.map((relation) => ({
7264
+ name: relation.name,
7265
+ columns: normalizeColumns(relation.columns)
7266
+ })).sort((a, b) => a.name.localeCompare(b.name));
7267
+ return JSON.stringify({
7268
+ root: normalizeColumns(plan.rootColumns),
7269
+ relations
7270
+ });
7271
+ };
7272
+ var hashString = (value) => {
7273
+ let hash = 2166136261;
7274
+ for (let i = 0; i < value.length; i += 1) {
7275
+ hash ^= value.charCodeAt(i);
7276
+ hash = hash * 16777619 >>> 0;
7261
7277
  }
7262
- const inputContext = createContext(inputOptions.maxDepth ?? DEFAULT_MAX_DEPTH);
7263
- const input = extractInputSchema(table, inputContext, inputOptions);
7264
- return { output, input };
7278
+ return hash.toString(16).padStart(8, "0");
7265
7279
  };
7266
- var resolveOutputOptions = (options) => ({
7267
- mode: options.mode ?? "full",
7268
- includeDescriptions: options.includeDescriptions,
7269
- includeEnums: options.includeEnums,
7270
- includeExamples: options.includeExamples,
7271
- includeDefaults: options.includeDefaults,
7272
- includeNullable: options.includeNullable,
7273
- maxDepth: options.maxDepth ?? DEFAULT_MAX_DEPTH
7274
- });
7275
- var resolveInputOptions = (options) => {
7276
- if (options.input === false) return void 0;
7277
- const input = options.input ?? {};
7278
- const mode = input.mode ?? "create";
7279
- return {
7280
- mode,
7281
- includeRelations: input.includeRelations ?? true,
7282
- relationMode: input.relationMode ?? "mixed",
7283
- includeDescriptions: input.includeDescriptions ?? options.includeDescriptions,
7284
- includeEnums: input.includeEnums ?? options.includeEnums,
7285
- includeExamples: input.includeExamples ?? options.includeExamples,
7286
- includeDefaults: input.includeDefaults ?? options.includeDefaults,
7287
- includeNullable: input.includeNullable ?? options.includeNullable,
7288
- maxDepth: input.maxDepth ?? options.maxDepth ?? DEFAULT_MAX_DEPTH,
7289
- omitReadOnly: input.omitReadOnly ?? true,
7290
- excludePrimaryKey: input.excludePrimaryKey ?? false,
7291
- requirePrimaryKey: input.requirePrimaryKey ?? mode === "update"
7292
- };
7280
+ var resolveSelectedComponentName = (table, plan, options) => {
7281
+ const base = resolveComponentName(table, options);
7282
+ const signature = buildSelectionSignature(plan);
7283
+ return `${base}__sel_${hashString(signature)}`;
7284
+ };
7285
+ var ensureComponentRef = (table, componentName, context, schemaFactory) => {
7286
+ if (context.components && !context.components.schemas[componentName]) {
7287
+ if (!context.visitedTables.has(table.name)) {
7288
+ context.components.schemas[componentName] = schemaFactory();
7289
+ }
7290
+ }
7291
+ return { $ref: `#/components/schemas/${componentName}` };
7292
+ };
7293
+ var registerComponentSchema = (name, schema, context) => {
7294
+ if (!context.components) return;
7295
+ if (!context.components.schemas[name]) {
7296
+ context.components.schemas[name] = schema;
7297
+ }
7293
7298
  };
7294
7299
  var createContext = (maxDepth) => ({
7295
7300
  visitedTables: /* @__PURE__ */ new Set(),
@@ -7297,19 +7302,18 @@ var createContext = (maxDepth) => ({
7297
7302
  depth: 0,
7298
7303
  maxDepth
7299
7304
  });
7300
- var extractOutputSchema = (table, plan, projectionNodes, context, options) => {
7301
- const mode = options.mode ?? "full";
7302
- const hasComputedFields = projectionNodes && projectionNodes.some(
7303
- (node) => node.type !== "Column"
7304
- );
7305
- if (hasComputedFields) {
7306
- return extractFromProjectionNodes(table, projectionNodes, context, options);
7307
- }
7308
- if (mode === "selected" && plan) {
7309
- return extractSelectedSchema(table, plan, context, options);
7310
- }
7311
- return extractFullTableSchema(table, context, options);
7312
- };
7305
+ var buildCircularReferenceSchema = (tableName, kind) => ({
7306
+ type: "object",
7307
+ properties: {
7308
+ _ref: {
7309
+ type: "string",
7310
+ description: `Circular ${kind} reference to ${tableName}`
7311
+ }
7312
+ },
7313
+ required: []
7314
+ });
7315
+
7316
+ // src/openapi/schema-extractor-input.ts
7313
7317
  var extractInputSchema = (table, context, options) => {
7314
7318
  const cacheKey = `${table.name}:${options.mode ?? "create"}`;
7315
7319
  if (context.schemaCache.has(cacheKey)) {
@@ -7337,6 +7341,7 @@ var extractInputSchema = (table, context, options) => {
7337
7341
  if (options.includeRelations && context.depth < context.maxDepth) {
7338
7342
  for (const [relationName, relation] of Object.entries(table.relations)) {
7339
7343
  properties[relationName] = extractInputRelationSchema(
7344
+ relationName,
7340
7345
  relation,
7341
7346
  { ...context, depth: context.depth + 1 },
7342
7347
  options
@@ -7371,7 +7376,7 @@ var buildPrimaryKeySchema = (table, options) => {
7371
7376
  }
7372
7377
  return mapColumnType(column, options);
7373
7378
  };
7374
- var extractInputRelationSchema = (relation, context, options) => {
7379
+ var extractInputRelationSchema = (relationName, relation, context, options) => {
7375
7380
  const { type: relationType, isNullable } = mapRelationType(relation.type);
7376
7381
  const relationMode = options.relationMode ?? "mixed";
7377
7382
  const allowIds = relationMode !== "objects";
@@ -7381,7 +7386,11 @@ var extractInputRelationSchema = (relation, context, options) => {
7381
7386
  variants.push(buildPrimaryKeySchema(relation.target, options));
7382
7387
  }
7383
7388
  if (allowObjects) {
7384
- const targetSchema = extractInputSchema(relation.target, context, options);
7389
+ let targetSchema = extractInputSchema(relation.target, context, options);
7390
+ targetSchema = applyRelationSelection(targetSchema, options.relationSelections?.[relationName]);
7391
+ if (options.excludeRelationForeignKeys && isRelationForeignKeyToParent(relation)) {
7392
+ targetSchema = removeForeignKey(targetSchema, relation.foreignKey);
7393
+ }
7385
7394
  variants.push(targetSchema);
7386
7395
  }
7387
7396
  const itemSchema = variants.length === 1 ? variants[0] : { anyOf: variants };
@@ -7397,6 +7406,55 @@ var extractInputRelationSchema = (relation, context, options) => {
7397
7406
  nullable: isNullable
7398
7407
  };
7399
7408
  };
7409
+ var applyRelationSelection = (schema, selection) => {
7410
+ if (!selection || selection.pick === void 0 && selection.omit === void 0) {
7411
+ return schema;
7412
+ }
7413
+ const hasPick = selection.pick !== void 0;
7414
+ const pick = hasPick ? new Set(selection.pick ?? []) : void 0;
7415
+ const omit = selection.omit !== void 0 ? new Set(selection.omit ?? []) : void 0;
7416
+ const properties = Object.entries(schema.properties).reduce(
7417
+ (acc, [key, value]) => {
7418
+ if (pick && !pick.has(key)) return acc;
7419
+ if (omit && omit.has(key)) return acc;
7420
+ acc[key] = value;
7421
+ return acc;
7422
+ },
7423
+ {}
7424
+ );
7425
+ const required = schema.required.filter((name) => properties[name] !== void 0);
7426
+ return {
7427
+ ...schema,
7428
+ properties,
7429
+ required
7430
+ };
7431
+ };
7432
+ var removeForeignKey = (schema, foreignKey) => {
7433
+ if (!foreignKey || !schema.properties[foreignKey]) return schema;
7434
+ const properties = { ...schema.properties };
7435
+ delete properties[foreignKey];
7436
+ const required = schema.required.filter((name) => name !== foreignKey);
7437
+ return {
7438
+ ...schema,
7439
+ properties,
7440
+ required
7441
+ };
7442
+ };
7443
+ var isRelationForeignKeyToParent = (relation) => {
7444
+ return relation.type === RelationKinds.HasMany || relation.type === RelationKinds.HasOne;
7445
+ };
7446
+
7447
+ // src/openapi/schema-extractor-output.ts
7448
+ var extractOutputSchema = (table, plan, projectionNodes, context, options) => {
7449
+ const hasComputedFields = hasComputedProjection(projectionNodes);
7450
+ if (hasComputedFields) {
7451
+ return extractFromProjectionNodes(table, projectionNodes, context, options);
7452
+ }
7453
+ if (shouldUseSelectedSchema(options, plan, projectionNodes)) {
7454
+ return extractSelectedSchema(table, plan, context, options);
7455
+ }
7456
+ return extractFullTableSchema(table, context, options);
7457
+ };
7400
7458
  var extractFromProjectionNodes = (table, projectionNodes, context, options) => {
7401
7459
  const properties = {};
7402
7460
  const required = [];
@@ -7602,6 +7660,52 @@ var extractFullTableSchema = (table, context, options) => {
7602
7660
  var extractRelationSchema = (relation, relationPlan, selectedColumns, context, options) => {
7603
7661
  const targetTable = relation.target;
7604
7662
  const { type: relationType, isNullable } = mapRelationType(relation.type);
7663
+ if (options.refMode === "components" && context.components) {
7664
+ if (relationPlan && selectedColumns.length > 0 && options.selectedRefMode === "components") {
7665
+ const plan = {
7666
+ rootTable: targetTable.name,
7667
+ rootPrimaryKey: relationPlan.targetPrimaryKey,
7668
+ rootColumns: selectedColumns,
7669
+ relations: []
7670
+ };
7671
+ const componentName2 = resolveSelectedComponentName(targetTable, plan, options);
7672
+ const ref2 = ensureComponentRef(
7673
+ targetTable,
7674
+ componentName2,
7675
+ context,
7676
+ () => extractSelectedSchema(targetTable, plan, context, options)
7677
+ );
7678
+ if (relationType === "array") {
7679
+ return {
7680
+ type: "array",
7681
+ items: ref2,
7682
+ nullable: isNullable
7683
+ };
7684
+ }
7685
+ return {
7686
+ ...ref2,
7687
+ nullable: isNullable
7688
+ };
7689
+ }
7690
+ const componentName = resolveComponentName(targetTable, options);
7691
+ const ref = ensureComponentRef(
7692
+ targetTable,
7693
+ componentName,
7694
+ context,
7695
+ () => extractFullTableSchema(targetTable, context, options)
7696
+ );
7697
+ if (relationType === "array") {
7698
+ return {
7699
+ type: "array",
7700
+ items: ref,
7701
+ nullable: isNullable
7702
+ };
7703
+ }
7704
+ return {
7705
+ ...ref,
7706
+ nullable: isNullable
7707
+ };
7708
+ }
7605
7709
  let targetSchema;
7606
7710
  if (relationPlan && selectedColumns.length > 0) {
7607
7711
  const plan = {
@@ -7629,16 +7733,76 @@ var extractRelationSchema = (relation, relationPlan, selectedColumns, context, o
7629
7733
  description: targetSchema.description
7630
7734
  };
7631
7735
  };
7632
- var buildCircularReferenceSchema = (tableName, kind) => ({
7633
- type: "object",
7634
- properties: {
7635
- _ref: {
7636
- type: "string",
7637
- description: `Circular ${kind} reference to ${tableName}`
7736
+
7737
+ // src/openapi/schema-extractor.ts
7738
+ var DEFAULT_MAX_DEPTH = 5;
7739
+ var extractSchema = (table, plan, projectionNodes, options = {}) => {
7740
+ const outputOptions = resolveOutputOptions(options);
7741
+ const outputContext = createContext(outputOptions.maxDepth ?? DEFAULT_MAX_DEPTH);
7742
+ if (outputOptions.refMode === "components") {
7743
+ outputContext.components = { schemas: {} };
7744
+ }
7745
+ const outputSchema = extractOutputSchema(table, plan, projectionNodes, outputContext, outputOptions);
7746
+ let output = outputSchema;
7747
+ const useSelected = shouldUseSelectedSchema(outputOptions, plan, projectionNodes);
7748
+ const hasComputedFields = hasComputedProjection(projectionNodes);
7749
+ const canUseComponents = outputOptions.refMode === "components" && outputContext.components && !hasComputedFields;
7750
+ if (canUseComponents) {
7751
+ const componentName = useSelected && plan ? resolveSelectedComponentName(table, plan, outputOptions) : resolveComponentName(table, outputOptions);
7752
+ registerComponentSchema(componentName, outputSchema, outputContext);
7753
+ if (outputOptions.outputAsRef) {
7754
+ output = { $ref: `#/components/schemas/${componentName}` };
7638
7755
  }
7639
- },
7640
- required: []
7756
+ }
7757
+ const inputOptions = resolveInputOptions(options);
7758
+ if (!inputOptions) {
7759
+ return {
7760
+ output,
7761
+ components: outputContext.components && Object.keys(outputContext.components.schemas).length ? outputContext.components : void 0
7762
+ };
7763
+ }
7764
+ const inputContext = createContext(inputOptions.maxDepth ?? DEFAULT_MAX_DEPTH);
7765
+ const input = extractInputSchema(table, inputContext, inputOptions);
7766
+ return {
7767
+ output,
7768
+ input,
7769
+ components: outputContext.components && Object.keys(outputContext.components.schemas).length ? outputContext.components : void 0
7770
+ };
7771
+ };
7772
+ var resolveOutputOptions = (options) => ({
7773
+ mode: options.mode ?? "full",
7774
+ includeDescriptions: options.includeDescriptions,
7775
+ includeEnums: options.includeEnums,
7776
+ includeExamples: options.includeExamples,
7777
+ includeDefaults: options.includeDefaults,
7778
+ includeNullable: options.includeNullable,
7779
+ maxDepth: options.maxDepth ?? DEFAULT_MAX_DEPTH,
7780
+ refMode: options.refMode ?? "inline",
7781
+ selectedRefMode: options.selectedRefMode ?? "inline",
7782
+ componentName: options.componentName,
7783
+ outputAsRef: options.outputAsRef ?? false
7641
7784
  });
7785
+ var resolveInputOptions = (options) => {
7786
+ if (options.input === false) return void 0;
7787
+ const input = options.input ?? {};
7788
+ const mode = input.mode ?? "create";
7789
+ return {
7790
+ mode,
7791
+ includeRelations: input.includeRelations ?? true,
7792
+ relationMode: input.relationMode ?? "mixed",
7793
+ includeDescriptions: input.includeDescriptions ?? options.includeDescriptions,
7794
+ includeEnums: input.includeEnums ?? options.includeEnums,
7795
+ includeExamples: input.includeExamples ?? options.includeExamples,
7796
+ includeDefaults: input.includeDefaults ?? options.includeDefaults,
7797
+ includeNullable: input.includeNullable ?? options.includeNullable,
7798
+ maxDepth: input.maxDepth ?? options.maxDepth ?? DEFAULT_MAX_DEPTH,
7799
+ omitReadOnly: input.omitReadOnly ?? true,
7800
+ excludePrimaryKey: input.excludePrimaryKey ?? false,
7801
+ requirePrimaryKey: input.requirePrimaryKey ?? mode === "update",
7802
+ excludeRelationForeignKeys: input.excludeRelationForeignKeys ?? false,
7803
+ relationSelections: input.relationSelections
7804
+ };
7805
+ };
7642
7806
  var schemaToJson = (schema, pretty = false) => {
7643
7807
  return JSON.stringify(schema, null, pretty ? 2 : 0);
7644
7808
  };