typesql-cli 0.18.4 → 0.18.6
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/code-generator2.d.ts.map +1 -1
- package/code-generator2.js +2 -1
- package/code-generator2.js.map +1 -1
- package/dialects/postgres.d.ts +2 -1
- package/dialects/postgres.d.ts.map +1 -1
- package/dialects/postgres.js +13 -1
- package/dialects/postgres.js.map +1 -1
- package/drivers/postgres.d.ts +2 -1
- package/drivers/postgres.d.ts.map +1 -1
- package/drivers/postgres.js.map +1 -1
- package/drivers/types.d.ts +2 -2
- package/drivers/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/postgres-query-analyzer/case-nullability-checker.d.ts +3 -0
- package/postgres-query-analyzer/case-nullability-checker.d.ts.map +1 -0
- package/postgres-query-analyzer/case-nullability-checker.js +110 -0
- package/postgres-query-analyzer/case-nullability-checker.js.map +1 -0
- package/postgres-query-analyzer/describe.d.ts.map +1 -1
- package/postgres-query-analyzer/describe.js +4 -4
- package/postgres-query-analyzer/describe.js.map +1 -1
- package/postgres-query-analyzer/enum-parser.d.ts +2 -1
- package/postgres-query-analyzer/enum-parser.d.ts.map +1 -1
- package/postgres-query-analyzer/enum-parser.js.map +1 -1
- package/postgres-query-analyzer/nullability-checker.d.ts +3 -0
- package/postgres-query-analyzer/nullability-checker.d.ts.map +1 -0
- package/postgres-query-analyzer/nullability-checker.js +110 -0
- package/postgres-query-analyzer/nullability-checker.js.map +1 -0
- package/postgres-query-analyzer/traverse.d.ts +2 -2
- package/postgres-query-analyzer/traverse.d.ts.map +1 -1
- package/postgres-query-analyzer/traverse.js +266 -85
- package/postgres-query-analyzer/traverse.js.map +1 -1
- package/sqlite-query-analyzer/replace-list-params.d.ts +0 -1
- package/sqlite-query-analyzer/replace-list-params.d.ts.map +1 -1
- package/sqlite-query-analyzer/replace-list-params.js +0 -57
- package/sqlite-query-analyzer/replace-list-params.js.map +1 -1
- package/sqlite-query-analyzer/types.d.ts +3 -1
- package/sqlite-query-analyzer/types.d.ts.map +1 -1
@@ -7,6 +7,7 @@ const PostgreSQLParser_1 = require("@wsporto/typesql-parser/postgres/PostgreSQLP
|
|
7
7
|
const typesql_parser_1 = require("@wsporto/typesql-parser");
|
8
8
|
const select_columns_1 = require("../mysql-query-analyzer/select-columns");
|
9
9
|
const postgres_1 = require("@wsporto/typesql-parser/postgres");
|
10
|
+
const case_nullability_checker_1 = require("./case-nullability-checker");
|
10
11
|
function defaultOptions() {
|
11
12
|
return {
|
12
13
|
collectNestedInfo: false,
|
@@ -123,8 +124,12 @@ function traverse_select_no_parens(select_no_parens, context, traverseResult) {
|
|
123
124
|
if (with_clause) {
|
124
125
|
with_clause.cte_list().common_table_expr_list()
|
125
126
|
.forEach(common_table_expr => {
|
126
|
-
|
127
|
-
|
127
|
+
var _a, _b, _c;
|
128
|
+
const recursiveTableName = with_clause.RECURSIVE() ? common_table_expr.name().getText() : undefined;
|
129
|
+
const recursiveColumnNames = (_c = (_b = (_a = common_table_expr.name_list_()) === null || _a === void 0 ? void 0 : _a.name_list()) === null || _b === void 0 ? void 0 : _b.name_list()) === null || _c === void 0 ? void 0 : _c.map(name => name.getText());
|
130
|
+
const withResult = traverse_common_table_expr(common_table_expr, Object.assign(Object.assign({}, context), { recursiveTableName, recursiveColumnNames }), traverseResult);
|
131
|
+
const columns = recursiveColumnNames ? withResult.map((col, index) => { var _a; return (Object.assign(Object.assign({}, col), { column_name: (_a = recursiveColumnNames[index]) !== null && _a !== void 0 ? _a : col.column_name })); }) : withResult;
|
132
|
+
context.withColumns.push(...columns);
|
128
133
|
});
|
129
134
|
}
|
130
135
|
const select_clause = select_no_parens.select_clause();
|
@@ -181,8 +186,11 @@ function traverse_select_clause(select_clause, context, traverseResult) {
|
|
181
186
|
const mainSelectResult = traverse_simple_select_intersect(simple_select_intersect_list[0], context, traverseResult);
|
182
187
|
let columns = mainSelectResult.columns;
|
183
188
|
//union
|
189
|
+
const { recursiveTableName, recursiveColumnNames } = context;
|
190
|
+
const recursiveColumns = recursiveTableName ? mainSelectResult.columns
|
191
|
+
.map((col, index) => { var _a; return (Object.assign(Object.assign({}, col), { table_name: recursiveTableName, column_name: (_a = recursiveColumnNames === null || recursiveColumnNames === void 0 ? void 0 : recursiveColumnNames[index]) !== null && _a !== void 0 ? _a : col.column_name })); }) : [];
|
184
192
|
for (let index = 1; index < simple_select_intersect_list.length; index++) {
|
185
|
-
const unionResult = traverse_simple_select_intersect(simple_select_intersect_list[index], context, traverseResult);
|
193
|
+
const unionResult = traverse_simple_select_intersect(simple_select_intersect_list[index], Object.assign(Object.assign({}, context), { fromColumns: context.fromColumns.concat(recursiveColumns) }), traverseResult);
|
186
194
|
columns = columns.map((value, columnIndex) => {
|
187
195
|
const col = Object.assign({ column_name: value.column_name, is_nullable: value.is_nullable || unionResult.columns[columnIndex].is_nullable, table_name: '', table_schema: '', type: value.type }, (value.column_default && { column_default: value.column_default }));
|
188
196
|
return col;
|
@@ -243,14 +251,18 @@ function traverse_simple_select_pramary(simple_select_pramary, context, traverse
|
|
243
251
|
(_d = (_c = simple_select_pramary.group_clause()) === null || _c === void 0 ? void 0 : _c.group_by_list()) === null || _d === void 0 ? void 0 : _d.group_by_item_list().forEach(group_by => {
|
244
252
|
const a_expr = group_by.a_expr();
|
245
253
|
if (a_expr) {
|
254
|
+
newContext.groupBy = true;
|
255
|
+
/* The GROUP BY clause can reference column aliases defined in the SELECT list.
|
256
|
+
There's no need to retrieve nullability or type information from the GROUP BY expressions (findColumn(col). */
|
246
257
|
traverse_a_expr(a_expr, newContext, traverseResult);
|
258
|
+
newContext.groupBy = false;
|
247
259
|
}
|
248
260
|
});
|
249
261
|
const having_expr = (_e = simple_select_pramary.having_clause()) === null || _e === void 0 ? void 0 : _e.a_expr();
|
250
262
|
if (having_expr) {
|
251
263
|
traverse_a_expr(having_expr, newContext, traverseResult);
|
252
264
|
}
|
253
|
-
const filteredColumns = filterColumns_simple_select_pramary(simple_select_pramary,
|
265
|
+
const filteredColumns = filterColumns_simple_select_pramary(simple_select_pramary, Object.assign(Object.assign({}, context), { fromColumns: context.fromColumns.concat(fromResult.columns) }), traverseResult);
|
254
266
|
return {
|
255
267
|
columns: filteredColumns,
|
256
268
|
singleRow: fromResult.singleRow
|
@@ -358,7 +370,7 @@ function traverse_target_el(target_el, context, traverseResult) {
|
|
358
370
|
parameters
|
359
371
|
});
|
360
372
|
}
|
361
|
-
return Object.assign(Object.assign({ column_name: alias || exprResult.column_name, is_nullable: exprResult.is_nullable
|
373
|
+
return Object.assign(Object.assign(Object.assign({ column_name: alias || exprResult.column_name, is_nullable: exprResult.is_nullable, table_name: exprResult.table_name, table_schema: exprResult.table_schema, type: exprResult.type }, (exprResult.column_default != null) && { column_default: exprResult.column_default }), (exprResult.column_key != null && { column_key: exprResult.column_key })), (exprResult.jsonType != null && { jsonType: exprResult.jsonType }));
|
362
374
|
}
|
363
375
|
throw Error('Column not found');
|
364
376
|
}
|
@@ -746,7 +758,7 @@ function traversec_expr(c_expr, context, traverseResult) {
|
|
746
758
|
traverse_select_with_parens(select_with_parens, context, traverseResult);
|
747
759
|
return {
|
748
760
|
column_name: '?column?',
|
749
|
-
is_nullable:
|
761
|
+
is_nullable: false, //empty array
|
750
762
|
table_schema: '',
|
751
763
|
table_name: '',
|
752
764
|
type: 'unknown'
|
@@ -760,6 +772,15 @@ function traversec_expr(c_expr, context, traverseResult) {
|
|
760
772
|
}
|
761
773
|
const columnref = c_expr.columnref();
|
762
774
|
if (columnref) {
|
775
|
+
if (context.groupBy) {
|
776
|
+
return {
|
777
|
+
column_name: columnref.getText(),
|
778
|
+
is_nullable: false,
|
779
|
+
table_name: '',
|
780
|
+
table_schema: '',
|
781
|
+
type: 'unknown'
|
782
|
+
};
|
783
|
+
}
|
763
784
|
if (context.columnRefIsRecord) {
|
764
785
|
const table = (0, select_columns_1.splitTableName)(columnref.getText());
|
765
786
|
const columns = filterColumns(context.fromColumns, table);
|
@@ -831,13 +852,15 @@ function traversec_expr(c_expr, context, traverseResult) {
|
|
831
852
|
const select_with_parens = c_expr.select_with_parens();
|
832
853
|
if (select_with_parens) {
|
833
854
|
const result = traverse_select_with_parens(select_with_parens, Object.assign(Object.assign({}, context), { parentColumns: context.fromColumns, fromColumns: [] }), traverseResult);
|
855
|
+
const jsonType = result.columns[0].jsonType;
|
856
|
+
const is_nullable = jsonType == null ? true : jsonType.name !== 'json[]' && jsonType.name !== 'json_map'; //json[], json_map are not nullable
|
834
857
|
return {
|
835
858
|
column_name: '?column?',
|
836
|
-
is_nullable
|
859
|
+
is_nullable,
|
837
860
|
table_name: '',
|
838
861
|
table_schema: '',
|
839
862
|
type: result.columns[0].type,
|
840
|
-
jsonType:
|
863
|
+
jsonType: jsonType != null && jsonType.name === 'json' ? Object.assign(Object.assign({}, jsonType), { notNull: !is_nullable }) : jsonType
|
841
864
|
};
|
842
865
|
}
|
843
866
|
const a_expr_in_parens = c_expr._a_expr_in_parens;
|
@@ -902,23 +925,37 @@ function excludeColumns(fromColumns, excludeList) {
|
|
902
925
|
});
|
903
926
|
}
|
904
927
|
function traversec_expr_case(c_expr_case, context, traverseResult) {
|
905
|
-
var _a
|
928
|
+
var _a;
|
906
929
|
const case_expr = c_expr_case.case_expr();
|
907
|
-
const
|
908
|
-
const
|
909
|
-
const
|
910
|
-
const
|
911
|
-
const
|
930
|
+
const whenClauseList = case_expr.when_clause_list().when_clause_list();
|
931
|
+
const whenResult = whenClauseList.map(when_clause => traversewhen_clause(when_clause, context, traverseResult));
|
932
|
+
const whenIsNotNull = whenResult.every(when => !when.is_nullable);
|
933
|
+
const elseExpr = case_expr.case_default();
|
934
|
+
const elseResult = elseExpr ? traverse_a_expr(elseExpr.a_expr(), Object.assign({}, context), traverseResult) : null;
|
935
|
+
const branchNotNull = elseResult ? evaluateBranches(whenClauseList, elseExpr, whenResult.map(col => !col.is_nullable)) : false;
|
936
|
+
const elseIsNotNull = (elseResult === null || elseResult === void 0 ? void 0 : elseResult.is_nullable) === false || branchNotNull;
|
912
937
|
const notNull = elseIsNotNull && whenIsNotNull;
|
913
938
|
return {
|
914
939
|
column_name: '?column?',
|
915
940
|
is_nullable: !notNull,
|
916
941
|
table_name: '',
|
917
942
|
table_schema: '',
|
918
|
-
type: (
|
943
|
+
type: (_a = whenResult[0].type) !== null && _a !== void 0 ? _a : 'unknown',
|
919
944
|
jsonType: allJsonTypesMatch(whenResult, elseResult) ? whenResult[0].jsonType : undefined
|
920
945
|
};
|
921
946
|
}
|
947
|
+
function evaluateBranches(whenClauseList, elseExpr, whenIsNotNull) {
|
948
|
+
const exprIndex = whenClauseList.findIndex(when => {
|
949
|
+
const whenExpr = when.a_expr(0);
|
950
|
+
const evaluatesIfNull = (0, case_nullability_checker_1.evaluatesTrueIfNull)(elseExpr, whenExpr);
|
951
|
+
if (evaluatesIfNull) {
|
952
|
+
return true;
|
953
|
+
}
|
954
|
+
return false;
|
955
|
+
});
|
956
|
+
const result = exprIndex !== -1 ? whenIsNotNull[exprIndex] : false;
|
957
|
+
return result;
|
958
|
+
}
|
922
959
|
function allJsonTypesMatch(whenResultList, elseResult) {
|
923
960
|
var _a;
|
924
961
|
const firstType = (_a = whenResultList[0]) === null || _a === void 0 ? void 0 : _a.jsonType;
|
@@ -936,7 +973,7 @@ function traversewhen_clause(when_clause, context, traverseResult) {
|
|
936
973
|
const thenExprResult = traverse_a_expr(thenExpr, Object.assign(Object.assign({}, context), { filter_expr: whenExprList[index] }), traverseResult);
|
937
974
|
return thenExprResult;
|
938
975
|
});
|
939
|
-
const notNull = whenExprResult.every(res => res);
|
976
|
+
const notNull = whenExprResult.every(res => !res.is_nullable);
|
940
977
|
return {
|
941
978
|
column_name: '?column?',
|
942
979
|
is_nullable: !notNull,
|
@@ -987,7 +1024,9 @@ function mapJsonBuildArgsToJsonProperty(args, filterExpr) {
|
|
987
1024
|
return properties;
|
988
1025
|
}
|
989
1026
|
function inferJsonNullability(columns, filterExpr) {
|
990
|
-
const tables = columns.filter(col => filterExpr && col.original_is_nullable === false
|
1027
|
+
const tables = columns.filter(col => filterExpr && col.original_is_nullable === false
|
1028
|
+
&& isNotNull_a_expr({ name: col.column_name, prefix: col.table_name }, filterExpr))
|
1029
|
+
.map(col => col.table_name);
|
991
1030
|
const fields = columns.map(col => {
|
992
1031
|
return col.original_is_nullable != null && tables.includes(col.table_name) ? !col.original_is_nullable : !col.is_nullable;
|
993
1032
|
});
|
@@ -996,19 +1035,20 @@ function inferJsonNullability(columns, filterExpr) {
|
|
996
1035
|
function transformFieldsToJsonObjType(fields) {
|
997
1036
|
const jsonObject = {
|
998
1037
|
name: 'json',
|
1038
|
+
notNull: true,
|
999
1039
|
properties: fields.map(col => mapFieldToPropertyDef(col))
|
1000
1040
|
};
|
1001
1041
|
return jsonObject;
|
1002
1042
|
}
|
1003
1043
|
function mapFieldToPropertyDef(field) {
|
1004
1044
|
const prop = {
|
1005
|
-
key: field.
|
1045
|
+
key: field.column_name,
|
1006
1046
|
type: transformFieldToJsonField(field)
|
1007
1047
|
};
|
1008
1048
|
return prop;
|
1009
1049
|
}
|
1010
1050
|
function transformFieldToJsonField(field) {
|
1011
|
-
const jsonField = { name: 'json_field', type: field.type, notNull: field.
|
1051
|
+
const jsonField = field.jsonType ? field.jsonType : { name: 'json_field', type: field.type, notNull: !field.is_nullable };
|
1012
1052
|
return jsonField;
|
1013
1053
|
}
|
1014
1054
|
function traverse_json_build_obj_func(func_application, context, traverseResult) {
|
@@ -1024,6 +1064,7 @@ function traverse_json_build_obj_func(func_application, context, traverseResult)
|
|
1024
1064
|
type: 'json',
|
1025
1065
|
jsonType: {
|
1026
1066
|
name: 'json',
|
1067
|
+
notNull: true,
|
1027
1068
|
properties: mapJsonBuildArgsToJsonProperty(argsResult, context.filter_expr),
|
1028
1069
|
}
|
1029
1070
|
};
|
@@ -1040,23 +1081,26 @@ function traverse_json_agg(func_application, context, traverseResult) {
|
|
1040
1081
|
table_name: '',
|
1041
1082
|
table_schema: '',
|
1042
1083
|
type: 'json[]',
|
1043
|
-
jsonType:
|
1044
|
-
name: 'json[]',
|
1045
|
-
properties: createJsonTypeForJsonAgg(argsResult[0], context.filter_expr)
|
1046
|
-
}
|
1084
|
+
jsonType: createJsonTypeForJsonAgg(argsResult[0], context.filter_expr)
|
1047
1085
|
};
|
1048
1086
|
return result;
|
1049
1087
|
}
|
1050
1088
|
function createJsonTypeForJsonAgg(arg, filter_expr) {
|
1051
1089
|
if (arg.recordTypes) {
|
1052
1090
|
const jsonType = mapRecordsToJsonType(arg.recordTypes, filter_expr);
|
1053
|
-
return
|
1091
|
+
return {
|
1092
|
+
name: 'json[]',
|
1093
|
+
properties: [jsonType]
|
1094
|
+
};
|
1054
1095
|
}
|
1055
|
-
|
1096
|
+
const jsonType = arg.jsonType ? { name: 'json[]', properties: [arg.jsonType] } : undefined;
|
1097
|
+
const fieldType = { name: 'json[]', properties: [{ name: 'json_field', type: arg.type, notNull: !arg.is_nullable }] };
|
1098
|
+
const result = jsonType || fieldType;
|
1099
|
+
return result;
|
1056
1100
|
}
|
1057
1101
|
function mapRecordsToJsonType(recordTypes, filterExpr) {
|
1058
1102
|
const jsonNullability = inferJsonNullability(recordTypes, filterExpr);
|
1059
|
-
const fields = recordTypes.map((col, index) => ({
|
1103
|
+
const fields = recordTypes.map((col, index) => (Object.assign(Object.assign({}, col), { column_name: col.column_name ? col.column_name : `f${index + 1}`, is_nullable: !jsonNullability[index] })));
|
1060
1104
|
const jsonType = transformFieldsToJsonObjType(fields);
|
1061
1105
|
return jsonType;
|
1062
1106
|
}
|
@@ -1212,6 +1256,15 @@ function traversefunc_application(func_application, context, traverseResult) {
|
|
1212
1256
|
}
|
1213
1257
|
};
|
1214
1258
|
}
|
1259
|
+
if (functionName === 'unnest') {
|
1260
|
+
return {
|
1261
|
+
column_name: functionName,
|
1262
|
+
is_nullable: argsResult[0].is_nullable,
|
1263
|
+
type: argsResult[0].type,
|
1264
|
+
table_name: '',
|
1265
|
+
table_schema: ''
|
1266
|
+
};
|
1267
|
+
}
|
1215
1268
|
return {
|
1216
1269
|
column_name: functionName,
|
1217
1270
|
is_nullable: true,
|
@@ -1271,7 +1324,7 @@ function traverse_array_expr(array_expr, context, traverseResult) {
|
|
1271
1324
|
const expr_list = array_expr.expr_list();
|
1272
1325
|
if (expr_list) {
|
1273
1326
|
const traverse_expr_list_result = traverse_expr_list(expr_list, context, traverseResult);
|
1274
|
-
return Object.assign(Object.assign({}, traverse_expr_list_result[0]), { column_name: '?column?', table_name: '', table_schema: '' });
|
1327
|
+
return Object.assign(Object.assign({}, traverse_expr_list_result[0]), { is_nullable: traverse_expr_list_result.some(expr => expr.is_nullable), column_name: '?column?', table_name: '', table_schema: '' });
|
1275
1328
|
}
|
1276
1329
|
const array_expr_list = array_expr.array_expr_list();
|
1277
1330
|
if (array_expr_list) {
|
@@ -1293,17 +1346,21 @@ function traverse_array_expr_list(array_expr_list, context, traverseResult) {
|
|
1293
1346
|
return result;
|
1294
1347
|
}
|
1295
1348
|
function findColumn(fieldName, fromColumns) {
|
1296
|
-
const col =
|
1349
|
+
const col = findColumnOrNull(fieldName, fromColumns);
|
1297
1350
|
if (col == null) {
|
1298
1351
|
throw Error('Column not found: ' + fieldNameToString(fieldName));
|
1299
1352
|
}
|
1300
1353
|
return col;
|
1301
1354
|
}
|
1355
|
+
function findColumnOrNull(fieldName, fromColumns) {
|
1356
|
+
const col = fromColumns.find(col => (fieldName.prefix === '' || col.table_name.toLowerCase() === fieldName.prefix.toLowerCase()) && col.column_name.toLowerCase() === fieldName.name.toLowerCase());
|
1357
|
+
return col;
|
1358
|
+
}
|
1302
1359
|
function fieldNameToString(fieldName) {
|
1303
1360
|
return fieldName.prefix !== '' ? `${fieldName.prefix}.${fieldName.name}` : fieldName.name;
|
1304
1361
|
}
|
1305
1362
|
function checkIsNullable(where_clause, field) {
|
1306
|
-
const isNotNullResult = !field.is_nullable || isNotNull(field, where_clause);
|
1363
|
+
const isNotNullResult = !field.is_nullable || isNotNull({ name: field.column_name, prefix: field.table_name }, where_clause);
|
1307
1364
|
const col = Object.assign(Object.assign({}, field), { is_nullable: !isNotNullResult });
|
1308
1365
|
return col;
|
1309
1366
|
}
|
@@ -1331,19 +1388,48 @@ function getFromColumns(tableName, withColumns, dbSchema) {
|
|
1331
1388
|
const filteredSchema = filteredWithColumns.length > 0 ? filteredWithColumns : dbSchema.filter(col => col.table_name.toLowerCase() === tableName.name.toLowerCase());
|
1332
1389
|
return filteredSchema;
|
1333
1390
|
}
|
1391
|
+
function checkLeftJoinIsNullable(leftJoin, subsequentJoins, fromColumns) {
|
1392
|
+
if (!leftJoin.joinQual) {
|
1393
|
+
return true; // No condition = always nullable
|
1394
|
+
}
|
1395
|
+
const leftTable = getTableName(leftJoin.tableRef);
|
1396
|
+
const leftJoinColumns = getJoinColumns(leftJoin.joinQual)
|
1397
|
+
.filter(col => {
|
1398
|
+
if (col.prefix === leftTable.name && col.prefix === leftTable.alias) {
|
1399
|
+
return true;
|
1400
|
+
}
|
1401
|
+
if (findColumnOrNull(col, fromColumns)) { //column without table reference (ex: fk_user)
|
1402
|
+
return true;
|
1403
|
+
}
|
1404
|
+
return false;
|
1405
|
+
});
|
1406
|
+
for (const join of subsequentJoins) {
|
1407
|
+
// Only INNER JOINs can cancel nullability
|
1408
|
+
if (!(join.joinType === null || join.joinType.INNER_P())) {
|
1409
|
+
continue;
|
1410
|
+
}
|
1411
|
+
const joinConditionColumns = getJoinColumns(join.joinQual);
|
1412
|
+
const filteredJoinColumnsFromLeft = joinConditionColumns.filter(col => leftJoinColumns.some(lc => lc.prefix === col.prefix));
|
1413
|
+
// Are *all* columns from the left join used in not-null filtering?
|
1414
|
+
const referencesLeftJoin = filteredJoinColumnsFromLeft.length > 0 &&
|
1415
|
+
filteredJoinColumnsFromLeft.every(col => { var _a; return isNotNull_a_expr(col, (_a = join.joinQual) === null || _a === void 0 ? void 0 : _a.a_expr()); });
|
1416
|
+
if (referencesLeftJoin) {
|
1417
|
+
return false; // LEFT JOIN is effectively filtered by INNER JOIN — not nullable
|
1418
|
+
}
|
1419
|
+
}
|
1420
|
+
return true; // No INNER JOIN filtered it — remains nullable
|
1421
|
+
}
|
1334
1422
|
function traverse_table_ref(table_ref, context, traverseResult) {
|
1335
|
-
var _a, _b
|
1423
|
+
var _a, _b;
|
1336
1424
|
const allColumns = [];
|
1337
1425
|
const relation_expr = table_ref.relation_expr();
|
1338
1426
|
const aliasClause = table_ref.alias_clause();
|
1339
|
-
const aliasNameList = (_b = (_a = aliasClause === null || aliasClause === void 0 ? void 0 : aliasClause.name_list()) === null || _a === void 0 ? void 0 : _a.name_list()) === null || _b === void 0 ? void 0 : _b.map(name => name.getText());
|
1340
1427
|
const alias = aliasClause ? aliasClause.colid().getText() : '';
|
1341
1428
|
if (relation_expr) {
|
1342
1429
|
const tableName = traverse_relation_expr(relation_expr);
|
1343
|
-
const fromColumns = getFromColumns(tableName, context.withColumns, context.dbSchema);
|
1430
|
+
const fromColumns = getFromColumns(tableName, context.fromColumns.concat(context.withColumns), context.dbSchema);
|
1344
1431
|
const tableNameWithAlias = alias ? alias : tableName.name;
|
1345
|
-
const
|
1346
|
-
const fromColumnsResult = columnsWithAlias.concat(context.parentColumns);
|
1432
|
+
const fromColumnsResult = fromColumns.map(col => (Object.assign(Object.assign({}, col), { table_name: tableNameWithAlias.toLowerCase() })));
|
1347
1433
|
allColumns.push(...fromColumnsResult);
|
1348
1434
|
if (context.collectNestedInfo) {
|
1349
1435
|
const key = fromColumnsResult.filter(col => col.column_key === 'PRI');
|
@@ -1353,38 +1439,56 @@ function traverse_table_ref(table_ref, context, traverseResult) {
|
|
1353
1439
|
alias: alias,
|
1354
1440
|
renameAs,
|
1355
1441
|
parentRelation: '',
|
1356
|
-
joinColumn: ((
|
1442
|
+
joinColumn: ((_a = key[0]) === null || _a === void 0 ? void 0 : _a.column_name) || '',
|
1357
1443
|
cardinality: 'one',
|
1358
1444
|
parentCardinality: 'one'
|
1359
1445
|
};
|
1360
|
-
(
|
1446
|
+
(_b = traverseResult.relations) === null || _b === void 0 ? void 0 : _b.push(relation);
|
1361
1447
|
}
|
1362
1448
|
if (context.collectDynamicQueryInfo && traverseResult.dynamicQueryInfo.from.length == 0) {
|
1363
1449
|
collectDynamicQueryInfoTableRef(table_ref, null, null, fromColumnsResult, [], traverseResult);
|
1364
1450
|
}
|
1365
1451
|
const joinList = extractJoins(table_ref);
|
1366
|
-
|
1452
|
+
joinList.forEach((join, index) => {
|
1367
1453
|
const joinType = join.joinType; //INNER, LEFT
|
1368
1454
|
const joinQual = join.joinQual;
|
1369
1455
|
const numParamsBefore = traverseResult.parameters.length;
|
1370
|
-
const
|
1371
|
-
|
1372
|
-
|
1373
|
-
|
1456
|
+
const subsequentJoints = joinList.slice(index + 1);
|
1457
|
+
let joinColumns = [];
|
1458
|
+
if (join.tableRef.LATERAL_P()) {
|
1459
|
+
const newContext = Object.assign(Object.assign({}, context), { parentColumns: allColumns, collectDynamicQueryInfo: false });
|
1460
|
+
const lateralJoinResult = traverse_select_with_parens_or_func_table(join.tableRef, newContext, traverseResult);
|
1461
|
+
joinColumns = lateralJoinResult.columns;
|
1462
|
+
}
|
1463
|
+
else {
|
1464
|
+
const joinTableRefResult = traverse_table_ref(join.tableRef, context, traverseResult);
|
1465
|
+
joinColumns = (joinQual === null || joinQual === void 0 ? void 0 : joinQual.USING()) ? filterUsingColumns(joinTableRefResult.columns, joinQual) : joinTableRefResult.columns;
|
1466
|
+
}
|
1467
|
+
const nullableColumns = (joinType === null || joinType === void 0 ? void 0 : joinType.LEFT())
|
1468
|
+
? joinColumns.map(col => (Object.assign(Object.assign({}, col), { original_is_nullable: col.is_nullable, is_nullable: checkLeftJoinIsNullable(join, subsequentJoints, joinColumns) ? true : col.is_nullable })))
|
1469
|
+
: joinColumns;
|
1470
|
+
allColumns.push(...nullableColumns);
|
1374
1471
|
if (context.collectNestedInfo && joinQual) {
|
1375
|
-
collectNestedInfo(joinQual,
|
1472
|
+
collectNestedInfo(joinQual, joinColumns, traverseResult);
|
1376
1473
|
}
|
1377
1474
|
if (context.collectDynamicQueryInfo) {
|
1378
1475
|
const parameters = traverseResult.parameters.slice(numParamsBefore).map((_, index) => index + numParamsBefore);
|
1379
|
-
collectDynamicQueryInfoTableRef(join.tableRef, joinType, joinQual,
|
1476
|
+
collectDynamicQueryInfoTableRef(join.tableRef, joinType, joinQual, joinColumns, parameters, traverseResult);
|
1380
1477
|
}
|
1381
|
-
return resultColumns;
|
1382
1478
|
});
|
1383
|
-
|
1479
|
+
return {
|
1480
|
+
columns: allColumns,
|
1481
|
+
singleRow: false
|
1482
|
+
};
|
1384
1483
|
}
|
1385
|
-
const
|
1484
|
+
const select_with_parens_or_func_result = traverse_select_with_parens_or_func_table(table_ref, context, traverseResult);
|
1485
|
+
return select_with_parens_or_func_result;
|
1486
|
+
}
|
1487
|
+
function traverse_select_with_parens_or_func_table(tableRef, context, traverseResult) {
|
1488
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
1489
|
+
const func_table = tableRef.func_table();
|
1386
1490
|
if (func_table) {
|
1387
|
-
const funcAlias = ((
|
1491
|
+
const funcAlias = ((_c = (_b = (_a = tableRef.func_alias_clause()) === null || _a === void 0 ? void 0 : _a.alias_clause()) === null || _b === void 0 ? void 0 : _b.colid()) === null || _c === void 0 ? void 0 : _c.getText()) || '';
|
1388
1492
|
const result = traverse_func_table(func_table, context, traverseResult);
|
1389
1493
|
const resultWithAlias = result.columns.map(col => (Object.assign(Object.assign({}, col), { table_name: funcAlias || col.table_name })));
|
1390
1494
|
return {
|
@@ -1392,25 +1496,18 @@ function traverse_table_ref(table_ref, context, traverseResult) {
|
|
1392
1496
|
singleRow: result.singleRow
|
1393
1497
|
};
|
1394
1498
|
}
|
1395
|
-
const select_with_parens =
|
1499
|
+
const select_with_parens = tableRef.select_with_parens();
|
1396
1500
|
if (select_with_parens) {
|
1397
1501
|
const columns = traverse_select_with_parens(select_with_parens, Object.assign(Object.assign({}, context), { collectDynamicQueryInfo: false }), traverseResult);
|
1398
|
-
const
|
1399
|
-
|
1400
|
-
|
1401
|
-
table_name: alias || col.table_name,
|
1402
|
-
table_schema: col.table_schema,
|
1403
|
-
type: col.type
|
1404
|
-
}));
|
1502
|
+
const aliasNameList = (_f = (_e = (_d = tableRef.alias_clause()) === null || _d === void 0 ? void 0 : _d.name_list()) === null || _e === void 0 ? void 0 : _e.name_list()) === null || _f === void 0 ? void 0 : _f.map(name => name.getText());
|
1503
|
+
const alias = (_h = (_g = tableRef.alias_clause()) === null || _g === void 0 ? void 0 : _g.colid().getText()) !== null && _h !== void 0 ? _h : '';
|
1504
|
+
const withAlias = columns.columns.map((col, i) => (Object.assign(Object.assign({}, col), { column_name: (aliasNameList === null || aliasNameList === void 0 ? void 0 : aliasNameList[i]) || col.column_name, table_name: alias || col.table_name })));
|
1405
1505
|
return {
|
1406
1506
|
columns: withAlias,
|
1407
1507
|
singleRow: false
|
1408
1508
|
};
|
1409
1509
|
}
|
1410
|
-
|
1411
|
-
columns: allColumns,
|
1412
|
-
singleRow: false
|
1413
|
-
};
|
1510
|
+
throw Error('Stmt not expected:' + tableRef.getText());
|
1414
1511
|
}
|
1415
1512
|
function extractJoins(table_ref) {
|
1416
1513
|
const joinList = [];
|
@@ -1720,7 +1817,7 @@ function traverseDeletestmt(deleteStmt, dbSchema, traverseResult) {
|
|
1720
1817
|
return result;
|
1721
1818
|
}
|
1722
1819
|
function addConstraintIfNotNull(checkConstraint) {
|
1723
|
-
return checkConstraint !== undefined ? { checkConstraint } :
|
1820
|
+
return checkConstraint !== undefined ? { checkConstraint } : undefined;
|
1724
1821
|
}
|
1725
1822
|
function traverseUpdatestmt(updatestmt, traverseContext, traverseResult) {
|
1726
1823
|
var _a;
|
@@ -1853,7 +1950,14 @@ function isNotNull_a_expr_unary_not(a_expr_unary_not, field) {
|
|
1853
1950
|
function isNotNull_a_expr_isnull(a_expr_isnull, field) {
|
1854
1951
|
const a_expr_is_not = a_expr_isnull.a_expr_is_not();
|
1855
1952
|
if (a_expr_is_not) {
|
1856
|
-
|
1953
|
+
const isNotNull = isNotNull_a_expr_is_not(a_expr_is_not, field);
|
1954
|
+
if (isNotNull && a_expr_is_not.IS() && a_expr_is_not.NOT() && a_expr_is_not.NULL_P()) {
|
1955
|
+
return true;
|
1956
|
+
}
|
1957
|
+
if (a_expr_is_not.IS() && a_expr_is_not.NULL_P()) {
|
1958
|
+
return false;
|
1959
|
+
}
|
1960
|
+
return isNotNull;
|
1857
1961
|
}
|
1858
1962
|
return false;
|
1859
1963
|
}
|
@@ -1977,7 +2081,7 @@ function isNotNull_c_expr(c_expr, field) {
|
|
1977
2081
|
const columnref = c_expr.columnref();
|
1978
2082
|
if (columnref) {
|
1979
2083
|
const fieldName = (0, select_columns_1.splitName)(columnref.getText());
|
1980
|
-
return (fieldName.name === field.
|
2084
|
+
return (fieldName.name === field.name && (fieldName.prefix === '' || field.prefix === fieldName.prefix));
|
1981
2085
|
}
|
1982
2086
|
const aexprconst = c_expr.aexprconst();
|
1983
2087
|
if (aexprconst) {
|
@@ -2004,7 +2108,7 @@ function isParameter(str) {
|
|
2004
2108
|
return paramPattern.test(str);
|
2005
2109
|
}
|
2006
2110
|
function isSingleRowResult(selectstmt, fromColumns) {
|
2007
|
-
var _a
|
2111
|
+
var _a;
|
2008
2112
|
const limit = checkLimit(selectstmt);
|
2009
2113
|
if (limit === 1) {
|
2010
2114
|
return true;
|
@@ -2018,11 +2122,11 @@ function isSingleRowResult(selectstmt, fromColumns) {
|
|
2018
2122
|
const simple_select_pramary = simple_select_pramary_list[0];
|
2019
2123
|
const from_clause = simple_select_pramary.from_clause();
|
2020
2124
|
if (!from_clause) {
|
2021
|
-
const hasSetReturningFunction = (
|
2125
|
+
const hasSetReturningFunction = hasFunction(simple_select_pramary, fun => isSetReturningFunction(fun));
|
2022
2126
|
return !hasSetReturningFunction;
|
2023
2127
|
}
|
2024
2128
|
if (!simple_select_pramary.group_clause()) {
|
2025
|
-
const agreegateFunction =
|
2129
|
+
const agreegateFunction = hasFunction(simple_select_pramary, fun => isAggregateFunction(fun));
|
2026
2130
|
if (agreegateFunction) {
|
2027
2131
|
return true;
|
2028
2132
|
}
|
@@ -2042,28 +2146,32 @@ function isSingleRowResult(selectstmt, fromColumns) {
|
|
2042
2146
|
}
|
2043
2147
|
return false;
|
2044
2148
|
}
|
2045
|
-
function
|
2149
|
+
function hasFunction(simple_select_pramary, checkFunction) {
|
2046
2150
|
const target_list_ = simple_select_pramary.target_list_();
|
2047
2151
|
if (target_list_) {
|
2048
|
-
return target_list_.target_list().target_el_list().some(target_el =>
|
2152
|
+
return target_list_.target_list().target_el_list().some(target_el => checkFunction_target_el(target_el, checkFunction));
|
2049
2153
|
}
|
2050
2154
|
const target_list = simple_select_pramary.target_list();
|
2051
|
-
|
2155
|
+
if (target_list) {
|
2156
|
+
return target_list.target_el_list().some(target_el => checkFunction_target_el(target_el, checkFunction));
|
2157
|
+
}
|
2158
|
+
return false;
|
2052
2159
|
}
|
2053
2160
|
function getTableName(table_ref) {
|
2054
2161
|
const relation_expr = table_ref.relation_expr();
|
2055
|
-
|
2162
|
+
if (relation_expr) {
|
2163
|
+
return traverse_relation_expr(relation_expr);
|
2164
|
+
}
|
2056
2165
|
const aliasClause = table_ref.alias_clause();
|
2057
|
-
const tableAlias = aliasClause ? aliasClause.colid().getText() : '';
|
2058
2166
|
return {
|
2059
|
-
name:
|
2060
|
-
alias:
|
2167
|
+
name: aliasClause.colid().getText(),
|
2168
|
+
alias: ''
|
2061
2169
|
};
|
2062
2170
|
}
|
2063
|
-
function
|
2171
|
+
function checkFunction_target_el(target_el, checkFunction) {
|
2064
2172
|
if (target_el instanceof PostgreSQLParser_1.Target_labelContext) {
|
2065
2173
|
const c_expr_list = collectContextsOfType(target_el, PostgreSQLParser_1.Func_exprContext, false);
|
2066
|
-
const aggrFunction = c_expr_list.some(func_expr =>
|
2174
|
+
const aggrFunction = c_expr_list.some(func_expr => checkFunction(func_expr));
|
2067
2175
|
return aggrFunction;
|
2068
2176
|
}
|
2069
2177
|
return false;
|
@@ -2116,25 +2224,98 @@ const aggregateFunctions = new Set([
|
|
2116
2224
|
'variance',
|
2117
2225
|
'xmlagg'
|
2118
2226
|
]);
|
2119
|
-
function
|
2227
|
+
function isAggregateFunction(func_expr) {
|
2120
2228
|
var _a, _b, _c;
|
2121
2229
|
const funcName = (_c = (_b = (_a = func_expr === null || func_expr === void 0 ? void 0 : func_expr.func_application()) === null || _a === void 0 ? void 0 : _a.func_name()) === null || _b === void 0 ? void 0 : _b.getText()) === null || _c === void 0 ? void 0 : _c.toLowerCase();
|
2122
2230
|
// RANK(), DENSE_RANK(), PERCENT_RANK() - they are window functions, not aggregate functions,
|
2123
2231
|
// even though your query is returning them from a join involving pg_aggregate.
|
2124
2232
|
return !func_expr.over_clause() && aggregateFunctions.has(funcName);
|
2125
2233
|
}
|
2126
|
-
|
2127
|
-
|
2128
|
-
|
2129
|
-
|
2130
|
-
|
2131
|
-
|
2132
|
-
return false;
|
2133
|
-
}
|
2134
|
-
function isSetReturningFunction_c_expr(func_expr) {
|
2234
|
+
// SELECT distinct '''' || p.proname || ''',' AS function_name
|
2235
|
+
// FROM pg_proc p
|
2236
|
+
// JOIN pg_namespace n ON p.pronamespace = n.oid
|
2237
|
+
// WHERE p.proretset = true
|
2238
|
+
// ORDER BY function_name;
|
2239
|
+
function isSetReturningFunction(func_expr) {
|
2135
2240
|
var _a, _b, _c;
|
2136
2241
|
const funcName = (_c = (_b = (_a = func_expr === null || func_expr === void 0 ? void 0 : func_expr.func_application()) === null || _a === void 0 ? void 0 : _a.func_name()) === null || _b === void 0 ? void 0 : _b.getText()) === null || _c === void 0 ? void 0 : _c.toLowerCase();
|
2137
|
-
|
2242
|
+
const setReturning = new Set([
|
2243
|
+
'_pg_expandarray',
|
2244
|
+
'aclexplode',
|
2245
|
+
'generate_series',
|
2246
|
+
'generate_subscripts',
|
2247
|
+
'get_clients_with_addresses',
|
2248
|
+
'get_mytable1',
|
2249
|
+
'get_mytable1_by_id',
|
2250
|
+
'get_mytable1_with_nested_function',
|
2251
|
+
'get_mytable_plpgsql',
|
2252
|
+
'get_users_with_posts',
|
2253
|
+
'get_users_with_posts_plpgsql',
|
2254
|
+
'json_array_elements',
|
2255
|
+
'json_array_elements_text',
|
2256
|
+
'json_each',
|
2257
|
+
'json_each_text',
|
2258
|
+
'json_object_keys',
|
2259
|
+
'json_populate_recordset',
|
2260
|
+
'json_to_recordset',
|
2261
|
+
'jsonb_array_elements',
|
2262
|
+
'jsonb_array_elements_text',
|
2263
|
+
'jsonb_each',
|
2264
|
+
'jsonb_each_text',
|
2265
|
+
'jsonb_object_keys',
|
2266
|
+
'jsonb_path_query',
|
2267
|
+
'jsonb_populate_recordset',
|
2268
|
+
'jsonb_to_recordset',
|
2269
|
+
'pg_available_extension_versions',
|
2270
|
+
'pg_available_extensions',
|
2271
|
+
'pg_config',
|
2272
|
+
'pg_cursor',
|
2273
|
+
'pg_event_trigger_ddl_commands',
|
2274
|
+
'pg_event_trigger_dropped_objects',
|
2275
|
+
'pg_extension_update_paths',
|
2276
|
+
'pg_get_keywords',
|
2277
|
+
'pg_get_multixact_members',
|
2278
|
+
'pg_get_publication_tables',
|
2279
|
+
'pg_get_replication_slots',
|
2280
|
+
'pg_hba_file_rules',
|
2281
|
+
'pg_listening_channels',
|
2282
|
+
'pg_lock_status',
|
2283
|
+
'pg_logical_slot_get_binary_changes',
|
2284
|
+
'pg_logical_slot_get_changes',
|
2285
|
+
'pg_logical_slot_peek_binary_changes',
|
2286
|
+
'pg_logical_slot_peek_changes',
|
2287
|
+
'pg_ls_archive_statusdir',
|
2288
|
+
'pg_ls_dir',
|
2289
|
+
'pg_ls_logdir',
|
2290
|
+
'pg_ls_tmpdir',
|
2291
|
+
'pg_ls_waldir',
|
2292
|
+
'pg_mcv_list_items',
|
2293
|
+
'pg_options_to_table',
|
2294
|
+
'pg_partition_ancestors',
|
2295
|
+
'pg_partition_tree',
|
2296
|
+
'pg_prepared_statement',
|
2297
|
+
'pg_prepared_xact',
|
2298
|
+
'pg_show_all_file_settings',
|
2299
|
+
'pg_show_all_settings',
|
2300
|
+
'pg_show_replication_origin_status',
|
2301
|
+
'pg_stat_get_activity',
|
2302
|
+
'pg_stat_get_backend_idset',
|
2303
|
+
'pg_stat_get_progress_info',
|
2304
|
+
'pg_stat_get_wal_senders',
|
2305
|
+
'pg_stop_backup',
|
2306
|
+
'pg_tablespace_databases',
|
2307
|
+
'pg_timezone_abbrevs',
|
2308
|
+
'pg_timezone_names',
|
2309
|
+
'regexp_matches',
|
2310
|
+
'regexp_split_to_table',
|
2311
|
+
'ts_debug',
|
2312
|
+
'ts_parse',
|
2313
|
+
'ts_stat',
|
2314
|
+
'ts_token_type',
|
2315
|
+
'txid_snapshot_xip',
|
2316
|
+
'unnest'
|
2317
|
+
]);
|
2318
|
+
return setReturning.has(funcName);
|
2138
2319
|
}
|
2139
2320
|
function isSingleRowResult_where(a_expr, uniqueKeys) {
|
2140
2321
|
var _a, _b;
|