typesql-cli 0.18.3 → 0.18.5

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.
Files changed (48) hide show
  1. package/code-generator2.d.ts.map +1 -1
  2. package/code-generator2.js +14 -2
  3. package/code-generator2.js.map +1 -1
  4. package/dialects/postgres.d.ts +2 -1
  5. package/dialects/postgres.d.ts.map +1 -1
  6. package/dialects/postgres.js +18 -1
  7. package/dialects/postgres.js.map +1 -1
  8. package/drivers/postgres.d.ts +4 -1
  9. package/drivers/postgres.d.ts.map +1 -1
  10. package/drivers/postgres.js +21 -0
  11. package/drivers/postgres.js.map +1 -1
  12. package/drivers/types.d.ts +4 -2
  13. package/drivers/types.d.ts.map +1 -1
  14. package/mysql-query-analyzer/select-columns.d.ts +1 -0
  15. package/mysql-query-analyzer/select-columns.d.ts.map +1 -1
  16. package/mysql-query-analyzer/select-columns.js +13 -0
  17. package/mysql-query-analyzer/select-columns.js.map +1 -1
  18. package/package.json +1 -1
  19. package/postgres-query-analyzer/case-nullability-checker.d.ts +3 -0
  20. package/postgres-query-analyzer/case-nullability-checker.d.ts.map +1 -0
  21. package/postgres-query-analyzer/case-nullability-checker.js +110 -0
  22. package/postgres-query-analyzer/case-nullability-checker.js.map +1 -0
  23. package/postgres-query-analyzer/describe.d.ts.map +1 -1
  24. package/postgres-query-analyzer/describe.js +9 -8
  25. package/postgres-query-analyzer/describe.js.map +1 -1
  26. package/postgres-query-analyzer/enum-parser.d.ts +2 -1
  27. package/postgres-query-analyzer/enum-parser.d.ts.map +1 -1
  28. package/postgres-query-analyzer/enum-parser.js.map +1 -1
  29. package/postgres-query-analyzer/nullability-checker.d.ts +3 -0
  30. package/postgres-query-analyzer/nullability-checker.d.ts.map +1 -0
  31. package/postgres-query-analyzer/nullability-checker.js +110 -0
  32. package/postgres-query-analyzer/nullability-checker.js.map +1 -0
  33. package/postgres-query-analyzer/parser.d.ts +3 -2
  34. package/postgres-query-analyzer/parser.d.ts.map +1 -1
  35. package/postgres-query-analyzer/parser.js +19 -5
  36. package/postgres-query-analyzer/parser.js.map +1 -1
  37. package/postgres-query-analyzer/traverse.d.ts +19 -8
  38. package/postgres-query-analyzer/traverse.d.ts.map +1 -1
  39. package/postgres-query-analyzer/traverse.js +488 -174
  40. package/postgres-query-analyzer/traverse.js.map +1 -1
  41. package/postgres-query-analyzer/types.d.ts +8 -0
  42. package/postgres-query-analyzer/types.d.ts.map +1 -1
  43. package/sqlite-query-analyzer/replace-list-params.d.ts +0 -1
  44. package/sqlite-query-analyzer/replace-list-params.d.ts.map +1 -1
  45. package/sqlite-query-analyzer/replace-list-params.js +0 -57
  46. package/sqlite-query-analyzer/replace-list-params.js.map +1 -1
  47. package/sqlite-query-analyzer/types.d.ts +8 -2
  48. package/sqlite-query-analyzer/types.d.ts.map +1 -1
@@ -2,21 +2,23 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.defaultOptions = defaultOptions;
4
4
  exports.traverseSmt = traverseSmt;
5
+ exports.parseReturnType = parseReturnType;
5
6
  const PostgreSQLParser_1 = require("@wsporto/typesql-parser/postgres/PostgreSQLParser");
6
7
  const typesql_parser_1 = require("@wsporto/typesql-parser");
7
8
  const select_columns_1 = require("../mysql-query-analyzer/select-columns");
9
+ const postgres_1 = require("@wsporto/typesql-parser/postgres");
10
+ const case_nullability_checker_1 = require("./case-nullability-checker");
8
11
  function defaultOptions() {
9
12
  return {
10
13
  collectNestedInfo: false,
11
14
  collectDynamicQueryInfo: false
12
15
  };
13
16
  }
14
- function traverseSmt(stmt, dbSchema, checkConstraints, options) {
17
+ function traverseSmt(stmt, dbSchema, checkConstraints, userFunctions, options) {
15
18
  const { collectNestedInfo = false, collectDynamicQueryInfo = false } = options;
16
19
  const traverseResult = {
17
20
  columnsNullability: [],
18
- parameters: [],
19
- singleRow: false
21
+ parameters: []
20
22
  };
21
23
  if (collectNestedInfo) {
22
24
  traverseResult.relations = [];
@@ -35,7 +37,10 @@ function traverseSmt(stmt, dbSchema, checkConstraints, options) {
35
37
  collectNestedInfo,
36
38
  collectDynamicQueryInfo,
37
39
  fromColumns: [],
38
- checkConstraints
40
+ parentColumns: [],
41
+ withColumns: [],
42
+ checkConstraints,
43
+ userFunctions
39
44
  };
40
45
  const selectstmt = stmt.selectstmt();
41
46
  if (selectstmt) {
@@ -82,15 +87,15 @@ function getInParameterList(ctx) {
82
87
  }
83
88
  function traverseSelectstmt(selectstmt, context, traverseResult) {
84
89
  const paramIsListResult = getInParameterList(selectstmt);
85
- const columns = traverse_selectstmt(selectstmt, context, traverseResult);
90
+ const selectResult = traverse_selectstmt(selectstmt, context, traverseResult);
86
91
  //select parameters are collected after from paramters
87
92
  traverseResult.parameters.sort((param1, param2) => param1.paramIndex - param2.paramIndex);
88
- const multipleRowsResult = !isSingleRowResult(selectstmt, context.dbSchema);
93
+ const multipleRowsResult = !(selectResult.singleRow || isSingleRowResult(selectstmt, selectResult.columns));
89
94
  const limit = checkLimit(selectstmt);
90
95
  const postgresTraverseResult = {
91
96
  queryType: 'Select',
92
97
  multipleRowsResult,
93
- columns,
98
+ columns: selectResult.columns,
94
99
  parametersNullability: traverseResult.parameters.map(param => (Object.assign({ isNotNull: param.isNotNull }, addConstraintIfNotNull(param.checkConstraint)))),
95
100
  parameterList: paramIsListResult,
96
101
  limit
@@ -108,22 +113,23 @@ function traverse_selectstmt(selectstmt, context, traverseResult) {
108
113
  if (select_no_parens) {
109
114
  return traverse_select_no_parens(select_no_parens, context, traverseResult);
110
115
  }
111
- return [];
116
+ //select_with_parens
117
+ return {
118
+ columns: [],
119
+ singleRow: true
120
+ };
112
121
  }
113
122
  function traverse_select_no_parens(select_no_parens, context, traverseResult) {
114
- let withColumns = [];
115
123
  const with_clause = select_no_parens.with_clause();
116
124
  if (with_clause) {
117
125
  with_clause.cte_list().common_table_expr_list()
118
126
  .forEach(common_table_expr => {
119
- const newContext = Object.assign(Object.assign({}, context), { fromColumns: withColumns.concat(context.fromColumns) });
120
- const withResult = traverse_common_table_expr(common_table_expr, newContext, traverseResult);
121
- withColumns.push(...withResult);
127
+ const withResult = traverse_common_table_expr(common_table_expr, context, traverseResult);
128
+ context.withColumns.push(...withResult);
122
129
  });
123
130
  }
124
131
  const select_clause = select_no_parens.select_clause();
125
- const newContext = Object.assign(Object.assign({}, context), { fromColumns: withColumns.concat(context.fromColumns) });
126
- const selectResult = traverse_select_clause(select_clause, newContext, traverseResult);
132
+ const selectResult = traverse_select_clause(select_clause, context, traverseResult);
127
133
  const select_limit = select_no_parens.select_limit();
128
134
  if (select_limit) {
129
135
  const numParamsBefore = traverseResult.parameters.length;
@@ -159,8 +165,8 @@ function traverse_common_table_expr(common_table_expr, context, traverseResult)
159
165
  const tableName = common_table_expr.name().getText();
160
166
  const select_stmt = common_table_expr.preparablestmt().selectstmt();
161
167
  const numParamsBefore = traverseResult.parameters.length;
162
- const columns = traverse_selectstmt(select_stmt, Object.assign(Object.assign({}, context), { collectDynamicQueryInfo: false }), traverseResult);
163
- const columnsWithTalbeName = columns.map(col => (Object.assign(Object.assign({}, col), { table_name: tableName })));
168
+ const selectResult = traverse_selectstmt(select_stmt, Object.assign(Object.assign({}, context), { collectDynamicQueryInfo: false }), traverseResult);
169
+ const columnsWithTalbeName = selectResult.columns.map(col => (Object.assign(Object.assign({}, col), { table_name: tableName })));
164
170
  if (context.collectDynamicQueryInfo) {
165
171
  const parameters = traverseResult.parameters.slice(numParamsBefore).map((_, index) => index + numParamsBefore);
166
172
  (_a = traverseResult.dynamicQueryInfo) === null || _a === void 0 ? void 0 : _a.with.push({
@@ -173,45 +179,55 @@ function traverse_common_table_expr(common_table_expr, context, traverseResult)
173
179
  }
174
180
  function traverse_select_clause(select_clause, context, traverseResult) {
175
181
  const simple_select_intersect_list = select_clause.simple_select_intersect_list();
176
- let selectColumns = [];
177
- if (simple_select_intersect_list) {
178
- selectColumns = traverse_simple_select_intersect(simple_select_intersect_list[0], context, traverseResult);
179
- }
182
+ const mainSelectResult = traverse_simple_select_intersect(simple_select_intersect_list[0], context, traverseResult);
183
+ let columns = mainSelectResult.columns;
180
184
  //union
181
185
  for (let index = 1; index < simple_select_intersect_list.length; index++) {
182
- const unionNotNull = traverse_simple_select_intersect(simple_select_intersect_list[index], context, traverseResult);
183
- selectColumns = selectColumns.map((value, columnIndex) => {
184
- const col = Object.assign({ column_name: value.column_name, is_nullable: value.is_nullable || unionNotNull[columnIndex].is_nullable, table_name: '', table_schema: '', type: value.type }, (value.column_default && { column_default: value.column_default }));
186
+ const unionResult = traverse_simple_select_intersect(simple_select_intersect_list[index], context, traverseResult);
187
+ columns = columns.map((value, columnIndex) => {
188
+ 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 }));
185
189
  return col;
186
190
  });
187
191
  }
188
- return selectColumns;
192
+ return {
193
+ columns,
194
+ singleRow: simple_select_intersect_list.length == 1 ? mainSelectResult.singleRow : false
195
+ };
189
196
  }
190
197
  function traverse_simple_select_intersect(simple_select_intersect, context, traverseResult) {
191
198
  const simple_select_pramary = simple_select_intersect.simple_select_pramary_list()[0];
192
199
  if (simple_select_pramary) {
193
200
  return traverse_simple_select_pramary(simple_select_pramary, context, traverseResult);
194
201
  }
195
- return [];
202
+ return {
203
+ columns: [],
204
+ singleRow: true
205
+ };
196
206
  }
197
207
  function traverse_simple_select_pramary(simple_select_pramary, context, traverseResult) {
198
208
  var _a, _b, _c, _d, _e;
199
- const fromColumns = [];
209
+ let fromResult = {
210
+ columns: [],
211
+ singleRow: false
212
+ };
200
213
  const from_clause = simple_select_pramary.from_clause();
201
214
  if (from_clause) {
202
215
  const where_clause = simple_select_pramary.where_clause();
203
- const fields = traverse_from_clause(from_clause, context, traverseResult);
204
- const fieldsNotNull = where_clause != null ? fields.map(field => checkIsNullable(where_clause, field)) : fields;
205
- fromColumns.push(...fieldsNotNull);
216
+ fromResult = traverse_from_clause(from_clause, context, traverseResult);
217
+ fromResult.columns = where_clause != null ? fromResult.columns.map(field => checkIsNullable(where_clause, field)) : fromResult.columns;
206
218
  }
207
219
  const values_clause = simple_select_pramary.values_clause();
208
220
  if (values_clause) {
209
221
  const valuesColumns = traverse_values_clause(values_clause, context, traverseResult);
210
- return valuesColumns;
222
+ return {
223
+ columns: valuesColumns,
224
+ singleRow: false
225
+ };
211
226
  }
212
227
  const where_a_expr = (_a = simple_select_pramary.where_clause()) === null || _a === void 0 ? void 0 : _a.a_expr();
213
228
  //fromColumns has precedence
214
- const newContext = Object.assign(Object.assign({}, context), { fromColumns: fromColumns.concat(context.fromColumns) });
229
+ //context.fromColumns only becase of insert. update
230
+ const newContext = Object.assign(Object.assign({}, context), { fromColumns: [...context.fromColumns, ...fromResult.columns, ...context.parentColumns] });
215
231
  if (where_a_expr) {
216
232
  const numParamsBefore = traverseResult.parameters.length;
217
233
  traverse_a_expr(where_a_expr, newContext, traverseResult);
@@ -236,7 +252,10 @@ function traverse_simple_select_pramary(simple_select_pramary, context, traverse
236
252
  traverse_a_expr(having_expr, newContext, traverseResult);
237
253
  }
238
254
  const filteredColumns = filterColumns_simple_select_pramary(simple_select_pramary, newContext, traverseResult);
239
- return filteredColumns;
255
+ return {
256
+ columns: filteredColumns,
257
+ singleRow: fromResult.singleRow
258
+ };
240
259
  }
241
260
  function extractRelations(a_expr) {
242
261
  const columnsRef = collectContextsOfType(a_expr, PostgreSQLParser_1.ColumnrefContext);
@@ -340,7 +359,7 @@ function traverse_target_el(target_el, context, traverseResult) {
340
359
  parameters
341
360
  });
342
361
  }
343
- return Object.assign({ column_name: alias || exprResult.column_name, is_nullable: exprResult.is_nullable && exprResult.column_default !== true, table_name: exprResult.table_name, table_schema: exprResult.table_schema, type: exprResult.type }, (exprResult.jsonType != null && { jsonType: exprResult.jsonType }));
362
+ 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 }));
344
363
  }
345
364
  throw Error('Column not found');
346
365
  }
@@ -470,6 +489,7 @@ function traverse_expr_is_not(a_expr_is_not, context, traverseResult) {
470
489
  const result = traverse_expr_compare(a_expr_compare, context, traverseResult);
471
490
  if (a_expr_is_not.IS() && a_expr_is_not.NULL_P()) {
472
491
  checkParamterNullability(result, traverseResult);
492
+ return Object.assign(Object.assign({}, result), { is_nullable: false });
473
493
  }
474
494
  return result;
475
495
  }
@@ -518,10 +538,10 @@ function traverse_expr_compare(a_expr_compare, context, traverseResult) {
518
538
  const result = traverse_select_with_parens(select_with_parens, context, traverseResult);
519
539
  return {
520
540
  column_name: '?column?',
521
- is_nullable: result.some(col => col.is_nullable),
541
+ is_nullable: result.columns.some(col => col.is_nullable),
522
542
  table_name: '',
523
543
  table_schema: '',
524
- type: result[0].type
544
+ type: result.columns[0].type
525
545
  };
526
546
  }
527
547
  const a_expr = a_expr_compare.a_expr();
@@ -710,7 +730,7 @@ function getNameAndTypeIdFromAExprConst(a_expr_const) {
710
730
  if (a_expr_const.NULL_P()) {
711
731
  return {
712
732
  name: a_expr_const.getText(),
713
- type: 'unknown'
733
+ type: 'null'
714
734
  };
715
735
  }
716
736
  return {
@@ -742,12 +762,15 @@ function traversec_expr(c_expr, context, traverseResult) {
742
762
  const columnref = c_expr.columnref();
743
763
  if (columnref) {
744
764
  if (context.columnRefIsRecord) {
765
+ const table = (0, select_columns_1.splitTableName)(columnref.getText());
766
+ const columns = filterColumns(context.fromColumns, table);
745
767
  return {
746
768
  column_name: columnref.getText(),
747
769
  is_nullable: false,
748
770
  table_name: '',
749
771
  table_schema: '',
750
- type: 'unknown',
772
+ type: 'record',
773
+ recordTypes: columns
751
774
  };
752
775
  }
753
776
  else {
@@ -782,6 +805,7 @@ function traversec_expr(c_expr, context, traverseResult) {
782
805
  }
783
806
  const fun_expr = c_expr.func_expr();
784
807
  if (fun_expr) {
808
+ context.columnRefIsRecord = undefined;
785
809
  const func_application = fun_expr.func_application();
786
810
  if (func_application) {
787
811
  if (is_json_build_object_func(func_application)) {
@@ -807,14 +831,16 @@ function traversec_expr(c_expr, context, traverseResult) {
807
831
  }
808
832
  const select_with_parens = c_expr.select_with_parens();
809
833
  if (select_with_parens) {
810
- const result = traverse_select_with_parens(select_with_parens, context, traverseResult);
834
+ const result = traverse_select_with_parens(select_with_parens, Object.assign(Object.assign({}, context), { parentColumns: context.fromColumns, fromColumns: [] }), traverseResult);
835
+ const jsonType = result.columns[0].jsonType;
836
+ const is_nullable = jsonType == null ? true : jsonType.name !== 'json[]' && jsonType.name !== 'json_map'; //json[], json_map are not nullable
811
837
  return {
812
838
  column_name: '?column?',
813
- is_nullable: true,
839
+ is_nullable,
814
840
  table_name: '',
815
841
  table_schema: '',
816
- type: result[0].type,
817
- jsonType: result[0].jsonType
842
+ type: result.columns[0].type,
843
+ jsonType: jsonType != null && jsonType.name === 'json' ? Object.assign(Object.assign({}, jsonType), { notNull: !is_nullable }) : jsonType
818
844
  };
819
845
  }
820
846
  const a_expr_in_parens = c_expr._a_expr_in_parens;
@@ -830,8 +856,8 @@ function traversec_expr(c_expr, context, traverseResult) {
830
856
  is_nullable: expr_list.some(col => col.is_nullable),
831
857
  table_name: '',
832
858
  table_schema: '',
833
- type: 'unknown',
834
- recordTypes: expr_list.map(rec => ({ type: rec.type, notNull: !rec.is_nullable }))
859
+ type: 'record',
860
+ recordTypes: expr_list.map(expr => (Object.assign(Object.assign({}, expr), { column_name: '' })))
835
861
  };
836
862
  }
837
863
  const implicit_row = c_expr.implicit_row();
@@ -867,7 +893,7 @@ function traversec_expr(c_expr, context, traverseResult) {
867
893
  function filterColumns(fromColumns, fieldName) {
868
894
  return fromColumns.filter(col => (fieldName.prefix === '' || col.table_name === fieldName.prefix)
869
895
  && (fieldName.name === '*' || col.column_name === fieldName.name)).map(col => {
870
- const result = Object.assign({ column_name: col.column_name, is_nullable: col.is_nullable, table_name: col.table_name, table_schema: col.table_schema, type: col.type }, (col.original_is_nullable !== undefined && { original_is_nullable: col.original_is_nullable }));
896
+ const result = Object.assign(Object.assign(Object.assign({ column_name: col.column_name, is_nullable: col.is_nullable, table_name: col.table_name, table_schema: col.table_schema, type: col.type }, (col.column_key !== undefined) && { column_key: col.column_key }), (col.jsonType !== undefined) && { jsonType: col.jsonType }), (col.original_is_nullable !== undefined && { original_is_nullable: col.original_is_nullable }));
871
897
  return result;
872
898
  });
873
899
  }
@@ -879,36 +905,62 @@ function excludeColumns(fromColumns, excludeList) {
879
905
  });
880
906
  }
881
907
  function traversec_expr_case(c_expr_case, context, traverseResult) {
882
- var _a, _b;
908
+ var _a;
883
909
  const case_expr = c_expr_case.case_expr();
884
- const whenResult = case_expr.when_clause_list().when_clause_list().map(when_clause => traversewhen_clause(when_clause, context, traverseResult));
885
- const whenIsNotNull = whenResult.every(when => when);
886
- const elseExpr = (_a = case_expr.case_default()) === null || _a === void 0 ? void 0 : _a.a_expr();
887
- const elseIsNotNull = elseExpr ? !traverse_a_expr(elseExpr, context, traverseResult).is_nullable : false;
910
+ const whenClauseList = case_expr.when_clause_list().when_clause_list();
911
+ const whenResult = whenClauseList.map(when_clause => traversewhen_clause(when_clause, context, traverseResult));
912
+ const whenIsNotNull = whenResult.every(when => !when.is_nullable);
913
+ const elseExpr = case_expr.case_default();
914
+ const elseResult = elseExpr ? traverse_a_expr(elseExpr.a_expr(), Object.assign({}, context), traverseResult) : null;
915
+ const branchNotNull = elseResult ? evaluateBranches(whenClauseList, elseExpr, whenResult.map(col => !col.is_nullable)) : false;
916
+ const elseIsNotNull = (elseResult === null || elseResult === void 0 ? void 0 : elseResult.is_nullable) === false || branchNotNull;
888
917
  const notNull = elseIsNotNull && whenIsNotNull;
889
918
  return {
890
919
  column_name: '?column?',
891
920
  is_nullable: !notNull,
892
921
  table_name: '',
893
922
  table_schema: '',
894
- type: (_b = whenResult[0].type) !== null && _b !== void 0 ? _b : 'unknown'
923
+ type: (_a = whenResult[0].type) !== null && _a !== void 0 ? _a : 'unknown',
924
+ jsonType: allJsonTypesMatch(whenResult, elseResult) ? whenResult[0].jsonType : undefined
895
925
  };
896
926
  }
927
+ function evaluateBranches(whenClauseList, elseExpr, whenIsNotNull) {
928
+ const exprIndex = whenClauseList.findIndex(when => {
929
+ const whenExpr = when.a_expr(0);
930
+ const evaluatesIfNull = (0, case_nullability_checker_1.evaluatesTrueIfNull)(elseExpr, whenExpr);
931
+ if (evaluatesIfNull) {
932
+ return true;
933
+ }
934
+ return false;
935
+ });
936
+ const result = exprIndex !== -1 ? whenIsNotNull[exprIndex] : false;
937
+ return result;
938
+ }
939
+ function allJsonTypesMatch(whenResultList, elseResult) {
940
+ var _a;
941
+ const firstType = (_a = whenResultList[0]) === null || _a === void 0 ? void 0 : _a.jsonType;
942
+ const allMatch = whenResultList.every(res => {
943
+ const match = res.jsonType == firstType;
944
+ return match;
945
+ }) && ((elseResult === null || elseResult === void 0 ? void 0 : elseResult.type) === 'null' || (elseResult === null || elseResult === void 0 ? void 0 : elseResult.jsonType) == firstType);
946
+ return allMatch;
947
+ }
897
948
  function traversewhen_clause(when_clause, context, traverseResult) {
898
949
  const a_expr_list = when_clause.a_expr_list();
899
950
  const [whenExprList, thenExprList] = partition(a_expr_list, (index) => index % 2 === 0);
900
951
  const whenExprResult = thenExprList.map((thenExpr, index) => {
901
952
  traverse_a_expr(whenExprList[index], context, traverseResult);
902
- const thenExprResult = traverse_a_expr(thenExpr, context, traverseResult);
953
+ const thenExprResult = traverse_a_expr(thenExpr, Object.assign(Object.assign({}, context), { filter_expr: whenExprList[index] }), traverseResult);
903
954
  return thenExprResult;
904
955
  });
905
- const notNull = whenExprResult.every(res => res);
956
+ const notNull = whenExprResult.every(res => !res.is_nullable);
906
957
  return {
907
958
  column_name: '?column?',
908
959
  is_nullable: !notNull,
909
960
  table_name: '',
910
961
  table_schema: '',
911
- type: whenExprResult[0].type
962
+ type: whenExprResult[0].type,
963
+ jsonType: whenExprResult[0].jsonType
912
964
  };
913
965
  }
914
966
  function partition(array, predicate) {
@@ -952,33 +1004,31 @@ function mapJsonBuildArgsToJsonProperty(args, filterExpr) {
952
1004
  return properties;
953
1005
  }
954
1006
  function inferJsonNullability(columns, filterExpr) {
955
- const someIsNotNull = columns.some(col => filterExpr && col.original_is_nullable === false && isNotNull_a_expr(col, filterExpr));
1007
+ const tables = columns.filter(col => filterExpr && col.original_is_nullable === false
1008
+ && isNotNull_a_expr({ name: col.column_name, prefix: col.table_name }, filterExpr))
1009
+ .map(col => col.table_name);
956
1010
  const fields = columns.map(col => {
957
- if (someIsNotNull) {
958
- return col.original_is_nullable != null ? !col.original_is_nullable : Boolean(filterExpr && isNotNull_a_expr(col, filterExpr));
959
- }
960
- else {
961
- return !col.is_nullable || Boolean(filterExpr && isNotNull_a_expr(col, filterExpr));
962
- }
1011
+ return col.original_is_nullable != null && tables.includes(col.table_name) ? !col.original_is_nullable : !col.is_nullable;
963
1012
  });
964
1013
  return fields;
965
1014
  }
966
1015
  function transformFieldsToJsonObjType(fields) {
967
1016
  const jsonObject = {
968
1017
  name: 'json',
1018
+ notNull: true,
969
1019
  properties: fields.map(col => mapFieldToPropertyDef(col))
970
1020
  };
971
1021
  return jsonObject;
972
1022
  }
973
1023
  function mapFieldToPropertyDef(field) {
974
1024
  const prop = {
975
- key: field.name,
1025
+ key: field.column_name,
976
1026
  type: transformFieldToJsonField(field)
977
1027
  };
978
1028
  return prop;
979
1029
  }
980
1030
  function transformFieldToJsonField(field) {
981
- const jsonField = { name: 'json_field', type: field.type, notNull: field.notNull };
1031
+ const jsonField = field.jsonType ? field.jsonType : { name: 'json_field', type: field.type, notNull: !field.is_nullable };
982
1032
  return jsonField;
983
1033
  }
984
1034
  function traverse_json_build_obj_func(func_application, context, traverseResult) {
@@ -986,36 +1036,54 @@ function traverse_json_build_obj_func(func_application, context, traverseResult)
986
1036
  const columnName = ((_a = func_application.func_name()) === null || _a === void 0 ? void 0 : _a.getText()) || func_application.getText();
987
1037
  const func_arg_expr_list = ((_b = func_application.func_arg_list()) === null || _b === void 0 ? void 0 : _b.func_arg_expr_list()) || [];
988
1038
  const argsResult = func_arg_expr_list.map(func_arg_expr => traversefunc_arg_expr(func_arg_expr, context, traverseResult));
989
- return {
1039
+ const result = {
990
1040
  column_name: columnName,
991
- is_nullable: true,
1041
+ is_nullable: false,
992
1042
  table_name: '',
993
1043
  table_schema: '',
994
1044
  type: 'json',
995
1045
  jsonType: {
996
1046
  name: 'json',
1047
+ notNull: true,
997
1048
  properties: mapJsonBuildArgsToJsonProperty(argsResult, context.filter_expr),
998
1049
  }
999
1050
  };
1051
+ return result;
1000
1052
  }
1001
1053
  function traverse_json_agg(func_application, context, traverseResult) {
1002
1054
  var _a, _b;
1003
1055
  const columnName = ((_a = func_application.func_name()) === null || _a === void 0 ? void 0 : _a.getText()) || func_application.getText();
1004
1056
  const func_arg_expr_list = ((_b = func_application.func_arg_list()) === null || _b === void 0 ? void 0 : _b.func_arg_expr_list()) || [];
1005
- const argsResult = func_arg_expr_list.map(func_arg_expr => traversefunc_arg_expr(func_arg_expr, context, traverseResult));
1057
+ const argsResult = func_arg_expr_list.map(func_arg_expr => traversefunc_arg_expr(func_arg_expr, Object.assign(Object.assign({}, context), { columnRefIsRecord: true }), traverseResult));
1006
1058
  const result = {
1007
1059
  column_name: columnName,
1008
1060
  is_nullable: context.filter_expr != null,
1009
1061
  table_name: '',
1010
1062
  table_schema: '',
1011
1063
  type: 'json[]',
1012
- jsonType: {
1013
- name: 'json[]',
1014
- properties: argsResult.map(arg => arg.jsonType || { name: 'json_field', type: arg.type, notNull: !arg.is_nullable })
1015
- }
1064
+ jsonType: createJsonTypeForJsonAgg(argsResult[0], context.filter_expr)
1016
1065
  };
1017
1066
  return result;
1018
1067
  }
1068
+ function createJsonTypeForJsonAgg(arg, filter_expr) {
1069
+ if (arg.recordTypes) {
1070
+ const jsonType = mapRecordsToJsonType(arg.recordTypes, filter_expr);
1071
+ return {
1072
+ name: 'json[]',
1073
+ properties: [jsonType]
1074
+ };
1075
+ }
1076
+ const jsonType = arg.jsonType ? { name: 'json[]', properties: [arg.jsonType] } : undefined;
1077
+ const fieldType = { name: 'json[]', properties: [{ name: 'json_field', type: arg.type, notNull: !arg.is_nullable }] };
1078
+ const result = jsonType || fieldType;
1079
+ return result;
1080
+ }
1081
+ function mapRecordsToJsonType(recordTypes, filterExpr) {
1082
+ const jsonNullability = inferJsonNullability(recordTypes, filterExpr);
1083
+ 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] })));
1084
+ const jsonType = transformFieldsToJsonObjType(fields);
1085
+ return jsonType;
1086
+ }
1019
1087
  function traversefunc_application(func_application, context, traverseResult) {
1020
1088
  var _a;
1021
1089
  const functionName = getFunctionName(func_application);
@@ -1023,22 +1091,7 @@ function traversefunc_application(func_application, context, traverseResult) {
1023
1091
  if (functionName === 'row_to_json') {
1024
1092
  const argResult = traversefunc_arg_expr(func_arg_expr_list[0], Object.assign(Object.assign({}, context), { columnRefIsRecord: true }), traverseResult);
1025
1093
  if (argResult.recordTypes) {
1026
- const fields = argResult.recordTypes.map((record, index) => ({ name: `f${index + 1}`, type: record.type, notNull: record.notNull }));
1027
- const jsonType = transformFieldsToJsonObjType(fields);
1028
- return {
1029
- column_name: functionName,
1030
- is_nullable: false,
1031
- table_name: '',
1032
- table_schema: '',
1033
- type: 'json',
1034
- jsonType
1035
- };
1036
- }
1037
- else {
1038
- const columns = filterColumns(context.fromColumns, { name: '*', prefix: argResult.column_name });
1039
- const jsonNullability = inferJsonNullability(columns, context.filter_expr);
1040
- const fields = columns.map((col, index) => ({ name: col.column_name, type: col.type, notNull: jsonNullability[index] }));
1041
- const jsonType = transformFieldsToJsonObjType(fields);
1094
+ const jsonType = mapRecordsToJsonType(argResult.recordTypes, context.filter_expr);
1042
1095
  return {
1043
1096
  column_name: functionName,
1044
1097
  is_nullable: false,
@@ -1170,6 +1223,28 @@ function traversefunc_application(func_application, context, traverseResult) {
1170
1223
  if (functionName === 'sum') {
1171
1224
  return Object.assign(Object.assign({}, argsResult[0]), { column_name: functionName, is_nullable: true, type: argsResult[0].type ? mapSumType(argsResult[0].type) : 'unknown' });
1172
1225
  }
1226
+ if (functionName === 'json_object_agg') {
1227
+ return {
1228
+ column_name: functionName,
1229
+ is_nullable: false,
1230
+ table_name: '',
1231
+ table_schema: '',
1232
+ type: 'json',
1233
+ jsonType: {
1234
+ name: 'json_map',
1235
+ type: argsResult[1].jsonType || { name: 'json_field', type: argsResult[1].type, notNull: !argsResult[1].is_nullable }
1236
+ }
1237
+ };
1238
+ }
1239
+ if (functionName === 'unnest') {
1240
+ return {
1241
+ column_name: functionName,
1242
+ is_nullable: argsResult[0].is_nullable,
1243
+ type: argsResult[0].type,
1244
+ table_name: '',
1245
+ table_schema: ''
1246
+ };
1247
+ }
1173
1248
  return {
1174
1249
  column_name: functionName,
1175
1250
  is_nullable: true,
@@ -1229,7 +1304,7 @@ function traverse_array_expr(array_expr, context, traverseResult) {
1229
1304
  const expr_list = array_expr.expr_list();
1230
1305
  if (expr_list) {
1231
1306
  const traverse_expr_list_result = traverse_expr_list(expr_list, context, traverseResult);
1232
- return Object.assign(Object.assign({}, traverse_expr_list_result[0]), { column_name: '?column?', table_name: '', table_schema: '' });
1307
+ 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: '' });
1233
1308
  }
1234
1309
  const array_expr_list = array_expr.array_expr_list();
1235
1310
  if (array_expr_list) {
@@ -1251,44 +1326,92 @@ function traverse_array_expr_list(array_expr_list, context, traverseResult) {
1251
1326
  return result;
1252
1327
  }
1253
1328
  function findColumn(fieldName, fromColumns) {
1254
- const col = fromColumns.find(col => (fieldName.prefix === '' || col.table_name.toLowerCase() === fieldName.prefix.toLowerCase()) && col.column_name.toLowerCase() === fieldName.name.toLowerCase());
1329
+ const col = findColumnOrNull(fieldName, fromColumns);
1255
1330
  if (col == null) {
1256
1331
  throw Error('Column not found: ' + fieldNameToString(fieldName));
1257
1332
  }
1258
1333
  return col;
1259
1334
  }
1335
+ function findColumnOrNull(fieldName, fromColumns) {
1336
+ const col = fromColumns.find(col => (fieldName.prefix === '' || col.table_name.toLowerCase() === fieldName.prefix.toLowerCase()) && col.column_name.toLowerCase() === fieldName.name.toLowerCase());
1337
+ return col;
1338
+ }
1260
1339
  function fieldNameToString(fieldName) {
1261
1340
  return fieldName.prefix !== '' ? `${fieldName.prefix}.${fieldName.name}` : fieldName.name;
1262
1341
  }
1263
1342
  function checkIsNullable(where_clause, field) {
1264
- const isNotNullResult = !field.is_nullable || isNotNull(field, where_clause);
1343
+ const isNotNullResult = !field.is_nullable || isNotNull({ name: field.column_name, prefix: field.table_name }, where_clause);
1265
1344
  const col = Object.assign(Object.assign({}, field), { is_nullable: !isNotNullResult });
1266
1345
  return col;
1267
1346
  }
1268
1347
  function traverse_from_clause(from_clause, context, traverseResult) {
1269
1348
  const from_list = from_clause.from_list();
1270
1349
  if (from_list) {
1271
- return traverse_from_list(from_list, context, traverseResult);
1350
+ const fromListResult = traverse_from_list(from_list, context, traverseResult);
1351
+ return fromListResult;
1272
1352
  }
1273
- return [];
1353
+ return {
1354
+ columns: [],
1355
+ singleRow: false
1356
+ };
1274
1357
  }
1275
1358
  function traverse_from_list(from_list, context, traverseResult) {
1276
- const newColumns = from_list.table_ref_list().flatMap(table_ref => traverse_table_ref(table_ref, context, traverseResult));
1277
- return newColumns;
1359
+ const fromListResult = from_list.table_ref_list().map(table_ref => traverse_table_ref(table_ref, context, traverseResult));
1360
+ const columns = fromListResult.flatMap(tableRes => tableRes.columns);
1361
+ return {
1362
+ columns: columns,
1363
+ singleRow: fromListResult.length === 1 ? fromListResult[0].singleRow : false
1364
+ };
1365
+ }
1366
+ function getFromColumns(tableName, withColumns, dbSchema) {
1367
+ const filteredWithColumns = withColumns.filter(col => col.table_name.toLowerCase() === tableName.name.toLowerCase());
1368
+ const filteredSchema = filteredWithColumns.length > 0 ? filteredWithColumns : dbSchema.filter(col => col.table_name.toLowerCase() === tableName.name.toLowerCase());
1369
+ return filteredSchema;
1370
+ }
1371
+ function checkLeftJoinIsNullable(leftJoin, subsequentJoins, fromColumns) {
1372
+ if (!leftJoin.joinQual) {
1373
+ return true; // No condition = always nullable
1374
+ }
1375
+ const leftTable = getTableName(leftJoin.tableRef);
1376
+ const leftJoinColumns = getJoinColumns(leftJoin.joinQual)
1377
+ .filter(col => {
1378
+ if (col.prefix === leftTable.name && col.prefix === leftTable.alias) {
1379
+ return true;
1380
+ }
1381
+ if (findColumnOrNull(col, fromColumns)) { //column without table reference (ex: fk_user)
1382
+ return true;
1383
+ }
1384
+ return false;
1385
+ });
1386
+ for (const join of subsequentJoins) {
1387
+ // Only INNER JOINs can cancel nullability
1388
+ if (!(join.joinType === null || join.joinType.INNER_P())) {
1389
+ continue;
1390
+ }
1391
+ const joinConditionColumns = getJoinColumns(join.joinQual);
1392
+ const filteredJoinColumnsFromLeft = joinConditionColumns.filter(col => leftJoinColumns.some(lc => lc.prefix === col.prefix));
1393
+ // Are *all* columns from the left join used in not-null filtering?
1394
+ const referencesLeftJoin = filteredJoinColumnsFromLeft.length > 0 &&
1395
+ filteredJoinColumnsFromLeft.every(col => { var _a; return isNotNull_a_expr(col, (_a = join.joinQual) === null || _a === void 0 ? void 0 : _a.a_expr()); });
1396
+ if (referencesLeftJoin) {
1397
+ return false; // LEFT JOIN is effectively filtered by INNER JOIN — not nullable
1398
+ }
1399
+ }
1400
+ return true; // No INNER JOIN filtered it — remains nullable
1278
1401
  }
1279
1402
  function traverse_table_ref(table_ref, context, traverseResult) {
1280
- var _a, _b, _c, _d;
1281
- const { fromColumns, dbSchema } = context;
1403
+ var _a, _b, _c, _d, _e, _f, _g;
1282
1404
  const allColumns = [];
1283
1405
  const relation_expr = table_ref.relation_expr();
1284
1406
  const aliasClause = table_ref.alias_clause();
1285
1407
  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());
1286
1408
  const alias = aliasClause ? aliasClause.colid().getText() : '';
1287
1409
  if (relation_expr) {
1288
- const tableName = traverse_relation_expr(relation_expr, dbSchema);
1410
+ const tableName = traverse_relation_expr(relation_expr);
1411
+ const fromColumns = getFromColumns(tableName, context.withColumns, context.dbSchema);
1289
1412
  const tableNameWithAlias = alias ? alias : tableName.name;
1290
- const fromColumnsResult = fromColumns.concat(dbSchema).filter(col => col.table_name.toLowerCase() === tableName.name.toLowerCase())
1291
- .map(col => (Object.assign(Object.assign({}, col), { table_name: tableNameWithAlias.toLowerCase() })));
1413
+ const columnsWithAlias = fromColumns.map(col => (Object.assign(Object.assign({}, col), { table_name: tableNameWithAlias.toLowerCase() })));
1414
+ const fromColumnsResult = columnsWithAlias.concat(context.parentColumns);
1292
1415
  allColumns.push(...fromColumnsResult);
1293
1416
  if (context.collectNestedInfo) {
1294
1417
  const key = fromColumnsResult.filter(col => col.column_key === 'PRI');
@@ -1304,47 +1427,79 @@ function traverse_table_ref(table_ref, context, traverseResult) {
1304
1427
  };
1305
1428
  (_d = traverseResult.relations) === null || _d === void 0 ? void 0 : _d.push(relation);
1306
1429
  }
1307
- const table_ref_list = table_ref.table_ref_list();
1308
- const join_type_list = table_ref.join_type_list();
1309
- const join_qual_list = table_ref.join_qual_list();
1310
1430
  if (context.collectDynamicQueryInfo && traverseResult.dynamicQueryInfo.from.length == 0) {
1311
1431
  collectDynamicQueryInfoTableRef(table_ref, null, null, fromColumnsResult, [], traverseResult);
1312
1432
  }
1313
- if (table_ref_list) {
1314
- const joinColumns = table_ref_list.flatMap((table_ref, joinIndex) => {
1315
- const joinType = join_type_list[joinIndex]; //INNER, LEFT
1316
- const joinQual = join_qual_list[joinIndex];
1317
- const numParamsBefore = traverseResult.parameters.length;
1318
- const joinColumns = traverse_table_ref(table_ref, context, traverseResult);
1319
- const isUsing = (joinQual === null || joinQual === void 0 ? void 0 : joinQual.USING()) ? true : false;
1320
- const isLeftJoin = joinType === null || joinType === void 0 ? void 0 : joinType.LEFT();
1321
- const filteredColumns = isUsing ? filterUsingColumns(joinColumns, joinQual) : joinColumns;
1322
- const resultColumns = isLeftJoin ? filteredColumns.map(col => (Object.assign(Object.assign({}, col), { is_nullable: true, original_is_nullable: col.is_nullable }))) : filteredColumns;
1323
- if (context.collectNestedInfo) {
1324
- collectNestedInfo(joinQual, resultColumns, traverseResult);
1325
- }
1326
- if (context.collectDynamicQueryInfo) {
1327
- const parameters = traverseResult.parameters.slice(numParamsBefore).map((_, index) => index + numParamsBefore);
1328
- collectDynamicQueryInfoTableRef(table_ref, joinType, joinQual, resultColumns, parameters, traverseResult);
1329
- }
1330
- return resultColumns;
1331
- });
1332
- allColumns.push(...joinColumns);
1333
- }
1433
+ const joinList = extractJoins(table_ref);
1434
+ const joinColumns = joinList.flatMap((join, index) => {
1435
+ const joinType = join.joinType; //INNER, LEFT
1436
+ const joinQual = join.joinQual;
1437
+ const numParamsBefore = traverseResult.parameters.length;
1438
+ const parentColumns = join.tableRef.LATERAL_P() ? fromColumnsResult : [];
1439
+ const joinTableRefResult = traverse_table_ref(join.tableRef, Object.assign(Object.assign({}, context), { parentColumns }), traverseResult);
1440
+ const isLeftJoin = joinType === null || joinType === void 0 ? void 0 : joinType.LEFT();
1441
+ const filteredColumns = joinQual && (joinQual === null || joinQual === void 0 ? void 0 : joinQual.USING()) ? filterUsingColumns(joinTableRefResult.columns, joinQual) : joinTableRefResult.columns;
1442
+ const subsequentJoints = joinList.slice(index + 1);
1443
+ const checkIsNullable = isLeftJoin ? checkLeftJoinIsNullable(join, subsequentJoints, filteredColumns) : false;
1444
+ ;
1445
+ const resultColumns = isLeftJoin ? filteredColumns.map(col => {
1446
+ const colResult = Object.assign(Object.assign({}, col), { is_nullable: checkIsNullable ? true : col.is_nullable, original_is_nullable: col.is_nullable });
1447
+ return colResult;
1448
+ }) : filteredColumns;
1449
+ if (context.collectNestedInfo && joinQual) {
1450
+ collectNestedInfo(joinQual, resultColumns, traverseResult);
1451
+ }
1452
+ if (context.collectDynamicQueryInfo) {
1453
+ const parameters = traverseResult.parameters.slice(numParamsBefore).map((_, index) => index + numParamsBefore);
1454
+ collectDynamicQueryInfoTableRef(join.tableRef, joinType, joinQual, resultColumns, parameters, traverseResult);
1455
+ }
1456
+ return resultColumns;
1457
+ });
1458
+ allColumns.push(...joinColumns);
1459
+ }
1460
+ const func_table = table_ref.func_table();
1461
+ if (func_table) {
1462
+ const funcAlias = ((_g = (_f = (_e = table_ref.func_alias_clause()) === null || _e === void 0 ? void 0 : _e.alias_clause()) === null || _f === void 0 ? void 0 : _f.colid()) === null || _g === void 0 ? void 0 : _g.getText()) || '';
1463
+ const result = traverse_func_table(func_table, context, traverseResult);
1464
+ const resultWithAlias = result.columns.map(col => (Object.assign(Object.assign({}, col), { table_name: funcAlias || col.table_name })));
1465
+ return {
1466
+ columns: resultWithAlias,
1467
+ singleRow: result.singleRow
1468
+ };
1334
1469
  }
1335
1470
  const select_with_parens = table_ref.select_with_parens();
1336
1471
  if (select_with_parens) {
1337
1472
  const columns = traverse_select_with_parens(select_with_parens, Object.assign(Object.assign({}, context), { collectDynamicQueryInfo: false }), traverseResult);
1338
- const withAlias = columns.map((col, i) => ({
1339
- column_name: (aliasNameList === null || aliasNameList === void 0 ? void 0 : aliasNameList[i]) || col.column_name,
1340
- is_nullable: col.is_nullable,
1341
- table_name: alias || col.table_name,
1342
- table_schema: col.table_schema,
1343
- type: col.type
1344
- }));
1345
- return withAlias;
1473
+ 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 })));
1474
+ return {
1475
+ columns: withAlias,
1476
+ singleRow: false
1477
+ };
1478
+ }
1479
+ return {
1480
+ columns: allColumns,
1481
+ singleRow: false
1482
+ };
1483
+ }
1484
+ function extractJoins(table_ref) {
1485
+ const joinList = [];
1486
+ let currentJoinType = null;
1487
+ for (const child of table_ref.children || []) {
1488
+ if (child instanceof PostgreSQLParser_1.Join_typeContext) {
1489
+ currentJoinType = child;
1490
+ }
1491
+ if (child instanceof PostgreSQLParser_1.Table_refContext) {
1492
+ joinList.push({ joinQual: null, joinType: currentJoinType, tableRef: child });
1493
+ currentJoinType = null;
1494
+ }
1495
+ if (child instanceof PostgreSQLParser_1.Join_qualContext) {
1496
+ const lastJoin = joinList.at(-1);
1497
+ if (lastJoin) {
1498
+ lastJoin.joinQual = child;
1499
+ }
1500
+ }
1346
1501
  }
1347
- return allColumns;
1502
+ return joinList;
1348
1503
  }
1349
1504
  function collectDynamicQueryInfoTableRef(table_ref, joinType, joinQual, columns, parameters, traverseResult) {
1350
1505
  var _a, _b;
@@ -1414,16 +1569,88 @@ function traverse_select_with_parens(select_with_parens, context, traverseResult
1414
1569
  if (select_no_parens) {
1415
1570
  return traverse_select_no_parens(select_no_parens, context, traverseResult);
1416
1571
  }
1417
- return [];
1572
+ return {
1573
+ columns: [],
1574
+ singleRow: false
1575
+ };
1576
+ }
1577
+ function traverse_func_table(func_table, context, traverseResult) {
1578
+ const func_expr_windowless = func_table.func_expr_windowless();
1579
+ if (func_expr_windowless) {
1580
+ const result = traverse_func_expr_windowless(func_expr_windowless, context, traverseResult);
1581
+ return result;
1582
+ }
1583
+ throw Error('Stmt not supported: ' + func_table.getText());
1584
+ }
1585
+ function parseReturnType(returnType) {
1586
+ const trimmed = returnType.trim();
1587
+ // Handle TABLE(...)
1588
+ if (trimmed.toLowerCase().startsWith('table(') && trimmed.endsWith(')')) {
1589
+ const inside = trimmed.slice(6, -1); // remove "TABLE(" and final ")"
1590
+ const columns = [];
1591
+ const parts = inside.split(',').map(part => part.trim());
1592
+ for (const part of parts) {
1593
+ const match = part.match(/^(\w+)\s+(.+)$/);
1594
+ if (!match) {
1595
+ throw new Error(`Invalid column definition: ${part}`);
1596
+ }
1597
+ const [, name, type] = match;
1598
+ columns.push({ name, type });
1599
+ }
1600
+ return { kind: 'table', columns };
1601
+ }
1602
+ // Handle SETOF typename
1603
+ const setofMatch = trimmed.match(/^SETOF\s+(\w+)$/i);
1604
+ if (setofMatch) {
1605
+ return { kind: 'setof', table: setofMatch[1] };
1606
+ }
1607
+ throw new Error(`Unsupported return type format: ${returnType}`);
1608
+ }
1609
+ function traverse_func_expr_windowless(func_expr_windowless, context, traverseResult) {
1610
+ const func_application = func_expr_windowless.func_application();
1611
+ if (func_application) {
1612
+ const func_name = func_application.func_name().getText().toLowerCase();
1613
+ const funcSchema = context.userFunctions.find(func => func.function_name.toLowerCase() === func_name);
1614
+ if (funcSchema) {
1615
+ const definition = funcSchema.definition;
1616
+ const returnType = parseReturnType(funcSchema.return_type);
1617
+ const functionColumns = returnType.kind === 'table' ? returnType.columns.map(col => {
1618
+ const columnInfo = {
1619
+ column_name: col.name,
1620
+ type: col.type,
1621
+ is_nullable: true,
1622
+ table_name: '',
1623
+ table_schema: ''
1624
+ };
1625
+ return columnInfo;
1626
+ }) : context.dbSchema.filter(col => col.table_name.toLowerCase() === returnType.table);
1627
+ if (funcSchema.language.toLowerCase() === 'sql') {
1628
+ const parser = (0, postgres_1.parseSql)(definition);
1629
+ const selectstmt = parser.stmt().selectstmt();
1630
+ const { columns, multipleRowsResult } = traverseSelectstmt(selectstmt, context, traverseResult);
1631
+ return {
1632
+ columns: columns.map((c) => (Object.assign(Object.assign({}, c), { table_name: funcSchema.function_name }))),
1633
+ singleRow: !multipleRowsResult
1634
+ };
1635
+ }
1636
+ else {
1637
+ return {
1638
+ columns: functionColumns,
1639
+ singleRow: false
1640
+ };
1641
+ }
1642
+ }
1643
+ }
1644
+ throw Error('Stmt not supported: ' + func_expr_windowless.getText());
1418
1645
  }
1419
- function traverse_relation_expr(relation_expr, dbSchema) {
1646
+ function traverse_relation_expr(relation_expr) {
1420
1647
  const qualified_name = relation_expr.qualified_name();
1421
- const name = traverse_qualified_name(qualified_name, dbSchema);
1648
+ const name = traverse_qualified_name(qualified_name);
1422
1649
  return name;
1423
1650
  }
1424
- function traverse_qualified_name(qualified_name, dbSchema) {
1651
+ function traverse_qualified_name(qualified_name) {
1425
1652
  var _a, _b;
1426
- const colid_name = qualified_name.colid() ? get_colid_text(qualified_name.colid(), dbSchema) : '';
1653
+ const colid_name = qualified_name.colid() ? get_colid_text(qualified_name.colid()) : '';
1427
1654
  const indirection_el_list = (_a = qualified_name.indirection()) === null || _a === void 0 ? void 0 : _a.indirection_el_list();
1428
1655
  if (indirection_el_list && indirection_el_list.length === 1) {
1429
1656
  return {
@@ -1436,22 +1663,22 @@ function traverse_qualified_name(qualified_name, dbSchema) {
1436
1663
  alias: ''
1437
1664
  };
1438
1665
  }
1439
- function get_colid_text(colid, dbSchema) {
1666
+ function get_colid_text(colid) {
1440
1667
  const identifier = colid.identifier();
1441
1668
  if (identifier) {
1442
- return traverse_identifier(identifier, dbSchema);
1669
+ return traverse_identifier(identifier);
1443
1670
  }
1444
1671
  const unreserved_keyword = colid.unreserved_keyword();
1445
1672
  if (unreserved_keyword) {
1446
- return traverse_unreserved_keyword(unreserved_keyword, dbSchema);
1673
+ return traverse_unreserved_keyword(unreserved_keyword);
1447
1674
  }
1448
1675
  return '';
1449
1676
  }
1450
- function traverse_identifier(identifier, dbSchema) {
1677
+ function traverse_identifier(identifier) {
1451
1678
  const tableName = identifier.Identifier().getText();
1452
1679
  return tableName;
1453
1680
  }
1454
- function traverse_unreserved_keyword(unreserved_keyword, dbSchema) {
1681
+ function traverse_unreserved_keyword(unreserved_keyword) {
1455
1682
  return unreserved_keyword.getText();
1456
1683
  }
1457
1684
  function paramIsList(c_expr) {
@@ -1486,8 +1713,7 @@ function paramIsList(c_expr) {
1486
1713
  function traverseInsertstmt(insertstmt, dbSchema) {
1487
1714
  const traverseResult = {
1488
1715
  columnsNullability: [],
1489
- parameters: [],
1490
- singleRow: false
1716
+ parameters: []
1491
1717
  };
1492
1718
  const insert_target = insertstmt.insert_target();
1493
1719
  const tableName = insert_target.getText();
@@ -1499,7 +1725,10 @@ function traverseInsertstmt(insertstmt, dbSchema) {
1499
1725
  const context = {
1500
1726
  dbSchema,
1501
1727
  fromColumns: insertColumns,
1728
+ parentColumns: [],
1729
+ withColumns: [],
1502
1730
  checkConstraints: {},
1731
+ userFunctions: [],
1503
1732
  collectNestedInfo: false,
1504
1733
  collectDynamicQueryInfo: false
1505
1734
  };
@@ -1535,7 +1764,10 @@ function traverseDeletestmt(deleteStmt, dbSchema, traverseResult) {
1535
1764
  const context = {
1536
1765
  dbSchema,
1537
1766
  fromColumns: deleteColumns,
1767
+ parentColumns: [],
1768
+ withColumns: [],
1538
1769
  checkConstraints: {},
1770
+ userFunctions: [],
1539
1771
  collectNestedInfo: false,
1540
1772
  collectDynamicQueryInfo: false
1541
1773
  };
@@ -1557,7 +1789,7 @@ function traverseDeletestmt(deleteStmt, dbSchema, traverseResult) {
1557
1789
  return result;
1558
1790
  }
1559
1791
  function addConstraintIfNotNull(checkConstraint) {
1560
- return checkConstraint !== undefined ? { checkConstraint } : {};
1792
+ return checkConstraint !== undefined ? { checkConstraint } : undefined;
1561
1793
  }
1562
1794
  function traverseUpdatestmt(updatestmt, traverseContext, traverseResult) {
1563
1795
  var _a;
@@ -1570,12 +1802,12 @@ function traverseUpdatestmt(updatestmt, traverseContext, traverseResult) {
1570
1802
  updatestmt.set_clause_list().set_clause_list()
1571
1803
  .forEach(set_clause => traverse_set_clause(set_clause, context, traverseResult));
1572
1804
  const from_clause = updatestmt.from_clause();
1573
- const fromColumns = from_clause ? traverse_from_clause(from_clause, context, traverseResult) : [];
1805
+ const fromResult = from_clause ? traverse_from_clause(from_clause, context, traverseResult) : { columns: [], singleRow: true };
1574
1806
  const parametersBefore = traverseResult.parameters.length;
1575
1807
  const where_clause = updatestmt.where_or_current_clause();
1576
1808
  if (where_clause) {
1577
1809
  const a_expr = where_clause.a_expr();
1578
- traverse_a_expr(a_expr, Object.assign(Object.assign({}, context), { fromColumns: updateColumns.concat(fromColumns) }), traverseResult);
1810
+ traverse_a_expr(a_expr, Object.assign(Object.assign({}, context), { fromColumns: updateColumns.concat(fromResult.columns) }), traverseResult);
1579
1811
  }
1580
1812
  const whereParameters = traverseResult.parameters.slice(parametersBefore);
1581
1813
  const returning_clause = updatestmt.returning_clause();
@@ -1690,7 +1922,14 @@ function isNotNull_a_expr_unary_not(a_expr_unary_not, field) {
1690
1922
  function isNotNull_a_expr_isnull(a_expr_isnull, field) {
1691
1923
  const a_expr_is_not = a_expr_isnull.a_expr_is_not();
1692
1924
  if (a_expr_is_not) {
1693
- return isNotNull_a_expr_is_not(a_expr_is_not, field);
1925
+ const isNotNull = isNotNull_a_expr_is_not(a_expr_is_not, field);
1926
+ if (isNotNull && a_expr_is_not.IS() && a_expr_is_not.NOT() && a_expr_is_not.NULL_P()) {
1927
+ return true;
1928
+ }
1929
+ if (a_expr_is_not.IS() && a_expr_is_not.NULL_P()) {
1930
+ return false;
1931
+ }
1932
+ return isNotNull;
1694
1933
  }
1695
1934
  return false;
1696
1935
  }
@@ -1814,7 +2053,7 @@ function isNotNull_c_expr(c_expr, field) {
1814
2053
  const columnref = c_expr.columnref();
1815
2054
  if (columnref) {
1816
2055
  const fieldName = (0, select_columns_1.splitName)(columnref.getText());
1817
- return (fieldName.name === field.column_name && (fieldName.prefix === '' || field.table_name === fieldName.prefix));
2056
+ return (fieldName.name === field.name && (fieldName.prefix === '' || field.prefix === fieldName.prefix));
1818
2057
  }
1819
2058
  const aexprconst = c_expr.aexprconst();
1820
2059
  if (aexprconst) {
@@ -1840,8 +2079,8 @@ function isParameter(str) {
1840
2079
  const paramPattern = /^\$[0-9]+(::[a-zA-Z_][a-zA-Z0-9_]*)?$/;
1841
2080
  return paramPattern.test(str);
1842
2081
  }
1843
- function isSingleRowResult(selectstmt, dbSchema) {
1844
- var _a, _b;
2082
+ function isSingleRowResult(selectstmt, fromColumns) {
2083
+ var _a;
1845
2084
  const limit = checkLimit(selectstmt);
1846
2085
  if (limit === 1) {
1847
2086
  return true;
@@ -1855,11 +2094,11 @@ function isSingleRowResult(selectstmt, dbSchema) {
1855
2094
  const simple_select_pramary = simple_select_pramary_list[0];
1856
2095
  const from_clause = simple_select_pramary.from_clause();
1857
2096
  if (!from_clause) {
1858
- const hasSetReturningFunction = (_b = simple_select_pramary.target_list_()) === null || _b === void 0 ? void 0 : _b.target_list().target_el_list().some(target_el => isSetReturningFunction_target_el(target_el));
2097
+ const hasSetReturningFunction = hasFunction(simple_select_pramary, fun => isSetReturningFunction(fun));
1859
2098
  return !hasSetReturningFunction;
1860
2099
  }
1861
2100
  if (!simple_select_pramary.group_clause()) {
1862
- const agreegateFunction = hasAggregateFunction(simple_select_pramary);
2101
+ const agreegateFunction = hasFunction(simple_select_pramary, fun => isAggregateFunction(fun));
1863
2102
  if (agreegateFunction) {
1864
2103
  return true;
1865
2104
  }
@@ -1873,36 +2112,38 @@ function isSingleRowResult(selectstmt, dbSchema) {
1873
2112
  }
1874
2113
  const where_clause = simple_select_pramary.where_clause();
1875
2114
  if (where_clause) {
1876
- const tableName = getTableName(table_ref_list[0]);
1877
- const uniqueKeys = dbSchema.filter(col => col.table_name.toLowerCase() === tableName.name.toLowerCase()
1878
- && (col.column_key === 'PRI' || col.column_key === 'UNI'))
2115
+ const uniqueKeys = fromColumns.filter(col => col.column_key === 'PRI' || col.column_key === 'UNI')
1879
2116
  .map(col => col.column_name);
1880
2117
  return isSingleRowResult_where(where_clause.a_expr(), uniqueKeys);
1881
2118
  }
1882
2119
  return false;
1883
2120
  }
1884
- function hasAggregateFunction(simple_select_pramary) {
2121
+ function hasFunction(simple_select_pramary, checkFunction) {
1885
2122
  const target_list_ = simple_select_pramary.target_list_();
1886
2123
  if (target_list_) {
1887
- return target_list_.target_list().target_el_list().some(target_el => isAggregateFunction_target_el(target_el));
2124
+ return target_list_.target_list().target_el_list().some(target_el => checkFunction_target_el(target_el, checkFunction));
1888
2125
  }
1889
2126
  const target_list = simple_select_pramary.target_list();
1890
- return target_list.target_el_list().some(target_el => isAggregateFunction_target_el(target_el));
2127
+ if (target_list) {
2128
+ return target_list.target_el_list().some(target_el => checkFunction_target_el(target_el, checkFunction));
2129
+ }
2130
+ return false;
1891
2131
  }
1892
2132
  function getTableName(table_ref) {
1893
2133
  const relation_expr = table_ref.relation_expr();
1894
- const tableName = relation_expr.qualified_name().getText();
2134
+ if (relation_expr) {
2135
+ return traverse_relation_expr(relation_expr);
2136
+ }
1895
2137
  const aliasClause = table_ref.alias_clause();
1896
- const tableAlias = aliasClause ? aliasClause.colid().getText() : '';
1897
2138
  return {
1898
- name: tableName,
1899
- alias: tableAlias
2139
+ name: aliasClause.colid().getText(),
2140
+ alias: ''
1900
2141
  };
1901
2142
  }
1902
- function isAggregateFunction_target_el(target_el) {
2143
+ function checkFunction_target_el(target_el, checkFunction) {
1903
2144
  if (target_el instanceof PostgreSQLParser_1.Target_labelContext) {
1904
2145
  const c_expr_list = collectContextsOfType(target_el, PostgreSQLParser_1.Func_exprContext, false);
1905
- const aggrFunction = c_expr_list.some(func_expr => isAggregateFunction_c_expr(func_expr));
2146
+ const aggrFunction = c_expr_list.some(func_expr => checkFunction(func_expr));
1906
2147
  return aggrFunction;
1907
2148
  }
1908
2149
  return false;
@@ -1955,25 +2196,98 @@ const aggregateFunctions = new Set([
1955
2196
  'variance',
1956
2197
  'xmlagg'
1957
2198
  ]);
1958
- function isAggregateFunction_c_expr(func_expr) {
2199
+ function isAggregateFunction(func_expr) {
1959
2200
  var _a, _b, _c;
1960
2201
  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();
1961
2202
  // RANK(), DENSE_RANK(), PERCENT_RANK() - they are window functions, not aggregate functions,
1962
2203
  // even though your query is returning them from a join involving pg_aggregate.
1963
2204
  return !func_expr.over_clause() && aggregateFunctions.has(funcName);
1964
2205
  }
1965
- function isSetReturningFunction_target_el(target_el) {
1966
- if (target_el instanceof PostgreSQLParser_1.Target_labelContext) {
1967
- const c_expr_list = collectContextsOfType(target_el, PostgreSQLParser_1.Func_exprContext);
1968
- const setReturningFunction = c_expr_list.some(func_expr => isSetReturningFunction_c_expr(func_expr));
1969
- return setReturningFunction;
1970
- }
1971
- return false;
1972
- }
1973
- function isSetReturningFunction_c_expr(func_expr) {
2206
+ // SELECT distinct '''' || p.proname || ''',' AS function_name
2207
+ // FROM pg_proc p
2208
+ // JOIN pg_namespace n ON p.pronamespace = n.oid
2209
+ // WHERE p.proretset = true
2210
+ // ORDER BY function_name;
2211
+ function isSetReturningFunction(func_expr) {
1974
2212
  var _a, _b, _c;
1975
2213
  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();
1976
- return funcName === 'generate_series';
2214
+ const setReturning = new Set([
2215
+ '_pg_expandarray',
2216
+ 'aclexplode',
2217
+ 'generate_series',
2218
+ 'generate_subscripts',
2219
+ 'get_clients_with_addresses',
2220
+ 'get_mytable1',
2221
+ 'get_mytable1_by_id',
2222
+ 'get_mytable1_with_nested_function',
2223
+ 'get_mytable_plpgsql',
2224
+ 'get_users_with_posts',
2225
+ 'get_users_with_posts_plpgsql',
2226
+ 'json_array_elements',
2227
+ 'json_array_elements_text',
2228
+ 'json_each',
2229
+ 'json_each_text',
2230
+ 'json_object_keys',
2231
+ 'json_populate_recordset',
2232
+ 'json_to_recordset',
2233
+ 'jsonb_array_elements',
2234
+ 'jsonb_array_elements_text',
2235
+ 'jsonb_each',
2236
+ 'jsonb_each_text',
2237
+ 'jsonb_object_keys',
2238
+ 'jsonb_path_query',
2239
+ 'jsonb_populate_recordset',
2240
+ 'jsonb_to_recordset',
2241
+ 'pg_available_extension_versions',
2242
+ 'pg_available_extensions',
2243
+ 'pg_config',
2244
+ 'pg_cursor',
2245
+ 'pg_event_trigger_ddl_commands',
2246
+ 'pg_event_trigger_dropped_objects',
2247
+ 'pg_extension_update_paths',
2248
+ 'pg_get_keywords',
2249
+ 'pg_get_multixact_members',
2250
+ 'pg_get_publication_tables',
2251
+ 'pg_get_replication_slots',
2252
+ 'pg_hba_file_rules',
2253
+ 'pg_listening_channels',
2254
+ 'pg_lock_status',
2255
+ 'pg_logical_slot_get_binary_changes',
2256
+ 'pg_logical_slot_get_changes',
2257
+ 'pg_logical_slot_peek_binary_changes',
2258
+ 'pg_logical_slot_peek_changes',
2259
+ 'pg_ls_archive_statusdir',
2260
+ 'pg_ls_dir',
2261
+ 'pg_ls_logdir',
2262
+ 'pg_ls_tmpdir',
2263
+ 'pg_ls_waldir',
2264
+ 'pg_mcv_list_items',
2265
+ 'pg_options_to_table',
2266
+ 'pg_partition_ancestors',
2267
+ 'pg_partition_tree',
2268
+ 'pg_prepared_statement',
2269
+ 'pg_prepared_xact',
2270
+ 'pg_show_all_file_settings',
2271
+ 'pg_show_all_settings',
2272
+ 'pg_show_replication_origin_status',
2273
+ 'pg_stat_get_activity',
2274
+ 'pg_stat_get_backend_idset',
2275
+ 'pg_stat_get_progress_info',
2276
+ 'pg_stat_get_wal_senders',
2277
+ 'pg_stop_backup',
2278
+ 'pg_tablespace_databases',
2279
+ 'pg_timezone_abbrevs',
2280
+ 'pg_timezone_names',
2281
+ 'regexp_matches',
2282
+ 'regexp_split_to_table',
2283
+ 'ts_debug',
2284
+ 'ts_parse',
2285
+ 'ts_stat',
2286
+ 'ts_token_type',
2287
+ 'txid_snapshot_xip',
2288
+ 'unnest'
2289
+ ]);
2290
+ return setReturning.has(funcName);
1977
2291
  }
1978
2292
  function isSingleRowResult_where(a_expr, uniqueKeys) {
1979
2293
  var _a, _b;