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.cjs +460 -71
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +99 -24
- package/dist/index.d.ts +99 -24
- package/dist/index.js +458 -71
- package/dist/index.js.map +1 -1
- package/package.json +3 -1
- package/src/codegen/typescript.ts +40 -29
- package/src/core/ast/expression-nodes.ts +32 -21
- package/src/core/ast/expression-visitor.ts +6 -1
- package/src/core/ast/expression.ts +1 -0
- package/src/core/ast/param-proxy.ts +50 -0
- package/src/core/dialect/abstract.ts +12 -10
- package/src/core/execution/db-executor.ts +5 -4
- package/src/core/execution/executors/mysql-executor.ts +9 -7
- package/src/openapi/index.ts +1 -0
- package/src/openapi/query-parameters.ts +207 -0
- package/src/openapi/schema-extractor.ts +290 -122
- package/src/openapi/schema-types.ts +72 -6
- package/src/openapi/type-mappers.ts +28 -8
- package/src/orm/unit-of-work.ts +25 -13
- package/src/query-builder/relation-filter-utils.ts +1 -0
- package/src/query-builder/select.ts +17 -7
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 (
|
|
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 (
|
|
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 (
|
|
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
|
|
6835
|
-
const
|
|
6836
|
-
|
|
6837
|
-
|
|
6838
|
-
|
|
6839
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
8277
|
+
* @returns OpenAPI 3.1 JSON Schemas for query output and input payloads
|
|
7924
8278
|
* @example
|
|
7925
|
-
* const
|
|
7926
|
-
* console.log(JSON.stringify(
|
|
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
|
-
|
|
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
|
-
|
|
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,
|