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 +795 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +174 -2
- package/dist/index.d.ts +174 -2
- package/dist/index.js +788 -5
- package/dist/index.js.map +1 -1
- package/package.json +10 -2
- package/src/core/dialect/postgres/index.ts +9 -5
- package/src/core/execution/db-executor.ts +5 -4
- package/src/core/execution/executors/mysql-executor.ts +9 -7
- package/src/index.ts +6 -4
- package/src/openapi/index.ts +4 -0
- package/src/openapi/query-parameters.ts +206 -0
- package/src/openapi/schema-extractor.ts +586 -0
- package/src/openapi/schema-types.ts +158 -0
- package/src/openapi/type-mappers.ts +227 -0
- package/src/orm/unit-of-work.ts +25 -13
- package/src/query-builder/select.ts +35 -11
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
|
|
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
|
|
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 =
|
|
8521
|
-
const actualType =
|
|
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
|
-
|
|
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,
|