typesql-cli 0.19.2 → 0.21.0

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 (123) hide show
  1. package/README.md +5 -0
  2. package/cli.js +51 -64
  3. package/cli.js.map +1 -1
  4. package/code-generator.d.ts +1 -1
  5. package/code-generator.d.ts.map +1 -1
  6. package/code-generator.js +4 -3
  7. package/code-generator.js.map +1 -1
  8. package/code-generator2.d.ts.map +1 -1
  9. package/code-generator2.js +151 -115
  10. package/code-generator2.js.map +1 -1
  11. package/codegen/code-generator.d.ts +13 -0
  12. package/codegen/code-generator.d.ts.map +1 -0
  13. package/codegen/code-generator.js +106 -0
  14. package/codegen/code-generator.js.map +1 -0
  15. package/codegen/code-generator2.d.ts +10 -0
  16. package/codegen/code-generator2.d.ts.map +1 -0
  17. package/codegen/code-generator2.js +917 -0
  18. package/codegen/code-generator2.js.map +1 -0
  19. package/codegen/codegen-util.d.ts +1 -0
  20. package/codegen/codegen-util.d.ts.map +1 -0
  21. package/codegen/codegen-util.js +2 -0
  22. package/codegen/codegen-util.js.map +1 -0
  23. package/codegen/generic/codegen-util.d.ts +8 -0
  24. package/codegen/generic/codegen-util.d.ts.map +1 -0
  25. package/codegen/generic/codegen-util.js +89 -0
  26. package/codegen/generic/codegen-util.js.map +1 -0
  27. package/codegen/mysql2.d.ts +40 -0
  28. package/codegen/mysql2.d.ts.map +1 -0
  29. package/codegen/mysql2.js +667 -0
  30. package/codegen/mysql2.js.map +1 -0
  31. package/codegen/pg.d.ts +9 -0
  32. package/codegen/pg.d.ts.map +1 -0
  33. package/codegen/pg.js +760 -0
  34. package/codegen/pg.js.map +1 -0
  35. package/codegen/postgres-pg.d.ts +10 -0
  36. package/codegen/postgres-pg.d.ts.map +1 -0
  37. package/codegen/postgres-pg.js +917 -0
  38. package/codegen/postgres-pg.js.map +1 -0
  39. package/codegen/shared/codegen-util.d.ts +28 -0
  40. package/codegen/shared/codegen-util.d.ts.map +1 -0
  41. package/codegen/shared/codegen-util.js +303 -0
  42. package/codegen/shared/codegen-util.js.map +1 -0
  43. package/codegen/sqlite-code-generator.d.ts +15 -0
  44. package/codegen/sqlite-code-generator.d.ts.map +1 -0
  45. package/codegen/sqlite-code-generator.js +1049 -0
  46. package/codegen/sqlite-code-generator.js.map +1 -0
  47. package/codegen/sqlite.d.ts +13 -0
  48. package/codegen/sqlite.d.ts.map +1 -0
  49. package/codegen/sqlite.js +893 -0
  50. package/codegen/sqlite.js.map +1 -0
  51. package/describe-query.d.ts.map +1 -1
  52. package/describe-query.js +45 -32
  53. package/describe-query.js.map +1 -1
  54. package/dialects/postgres.d.ts +4 -1
  55. package/dialects/postgres.d.ts.map +1 -1
  56. package/dialects/postgres.js +4 -2
  57. package/dialects/postgres.js.map +1 -1
  58. package/drivers/sqlite.d.ts +4 -1
  59. package/drivers/sqlite.d.ts.map +1 -1
  60. package/drivers/sqlite.js +4 -1
  61. package/drivers/sqlite.js.map +1 -1
  62. package/drivers/types.d.ts +3 -1
  63. package/drivers/types.d.ts.map +1 -1
  64. package/generic/codegen-util.d.ts +8 -0
  65. package/generic/codegen-util.d.ts.map +1 -0
  66. package/generic/codegen-util.js +89 -0
  67. package/generic/codegen-util.js.map +1 -0
  68. package/load-config.d.ts +6 -0
  69. package/load-config.d.ts.map +1 -1
  70. package/load-config.js +65 -1
  71. package/load-config.js.map +1 -1
  72. package/mysql-mapping.d.ts +4 -1
  73. package/mysql-mapping.d.ts.map +1 -1
  74. package/mysql-mapping.js +5 -3
  75. package/mysql-mapping.js.map +1 -1
  76. package/mysql-query-analyzer/infer-column-nullability.js +1 -1
  77. package/mysql-query-analyzer/infer-column-nullability.js.map +1 -1
  78. package/mysql-query-analyzer/parse.d.ts.map +1 -1
  79. package/mysql-query-analyzer/parse.js +3 -2
  80. package/mysql-query-analyzer/parse.js.map +1 -1
  81. package/package.json +2 -1
  82. package/postgres-pg.d.ts +10 -0
  83. package/postgres-pg.d.ts.map +1 -0
  84. package/postgres-pg.js +917 -0
  85. package/postgres-pg.js.map +1 -0
  86. package/postgres-query-analyzer/describe.d.ts +1 -1
  87. package/postgres-query-analyzer/describe.d.ts.map +1 -1
  88. package/postgres-query-analyzer/describe.js +77 -48
  89. package/postgres-query-analyzer/describe.js.map +1 -1
  90. package/postgres-query-analyzer/traverse.d.ts +1 -0
  91. package/postgres-query-analyzer/traverse.d.ts.map +1 -1
  92. package/postgres-query-analyzer/traverse.js +90 -28
  93. package/postgres-query-analyzer/traverse.js.map +1 -1
  94. package/postgres-query-analyzer/util.d.ts +9 -0
  95. package/postgres-query-analyzer/util.d.ts.map +1 -0
  96. package/postgres-query-analyzer/util.js +58 -0
  97. package/postgres-query-analyzer/util.js.map +1 -0
  98. package/rescript.d.ts +1 -0
  99. package/rescript.d.ts.map +1 -0
  100. package/rescript.js +2 -0
  101. package/rescript.js.map +1 -0
  102. package/sqlite-query-analyzer/parser.js +3 -3
  103. package/sqlite-query-analyzer/parser.js.map +1 -1
  104. package/sqlite-query-analyzer/replace-list-params.d.ts.map +1 -1
  105. package/sqlite-query-analyzer/replace-list-params.js.map +1 -1
  106. package/sqlite-query-analyzer/sqlite-code-generator.d.ts +15 -0
  107. package/sqlite-query-analyzer/sqlite-code-generator.d.ts.map +1 -0
  108. package/sqlite-query-analyzer/sqlite-code-generator.js +1049 -0
  109. package/sqlite-query-analyzer/sqlite-code-generator.js.map +1 -0
  110. package/sqlite-query-analyzer/traverse.js +1 -1
  111. package/sqlite-query-analyzer/traverse.js.map +1 -1
  112. package/sqlite.d.ts +43 -0
  113. package/sqlite.d.ts.map +1 -0
  114. package/sqlite.js +755 -0
  115. package/sqlite.js.map +1 -0
  116. package/ts-dynamic-query-descriptor.d.ts.map +1 -1
  117. package/ts-dynamic-query-descriptor.js +2 -1
  118. package/ts-dynamic-query-descriptor.js.map +1 -1
  119. package/ts-nested-descriptor.d.ts.map +1 -1
  120. package/ts-nested-descriptor.js +1 -1
  121. package/ts-nested-descriptor.js.map +1 -1
  122. package/types.d.ts +9 -1
  123. package/types.d.ts.map +1 -1
@@ -11,7 +11,6 @@ const code_block_writer_1 = __importDefault(require("code-block-writer"));
11
11
  const code_generator_1 = require("./code-generator");
12
12
  const describe_1 = require("./postgres-query-analyzer/describe");
13
13
  const postgres_1 = require("./dialects/postgres");
14
- const describe_query_1 = require("./describe-query");
15
14
  const neverthrow_1 = require("neverthrow");
16
15
  const code_generator_2 = require("./sqlite-query-analyzer/code-generator");
17
16
  const ts_nested_descriptor_1 = require("./ts-nested-descriptor");
@@ -20,9 +19,8 @@ function generateCode(client, sql, queryName, schemaInfo) {
20
19
  if (isEmptySql(sql)) {
21
20
  return (0, neverthrow_1.okAsync)('');
22
21
  }
23
- const { sql: processedSql, namedParameters } = (0, describe_query_1.preprocessSql)(sql, 'postgres');
24
- return _describeQuery(client, processedSql, namedParameters, schemaInfo)
25
- .map(schemaDef => generateTsCode(processedSql, queryName, schemaDef, client.type));
22
+ return _describeQuery(client, sql, schemaInfo)
23
+ .map(schemaDef => generateTsCode(sql, queryName, schemaDef, client.type));
26
24
  }
27
25
  function isEmptySql(sql) {
28
26
  if (sql.trim() === '') {
@@ -31,8 +29,8 @@ function isEmptySql(sql) {
31
29
  const lines = sql.split('\n');
32
30
  return lines.every(line => line.trim() === '' || line.trim().startsWith('//'));
33
31
  }
34
- function _describeQuery(databaseClient, sql, namedParameters, dbSchema) {
35
- return (0, describe_1.describeQuery)(databaseClient.client, sql, namedParameters, dbSchema);
32
+ function _describeQuery(databaseClient, sql, dbSchema) {
33
+ return (0, describe_1.describeQuery)(databaseClient.client, sql, dbSchema);
36
34
  }
37
35
  function createCodeBlockWriter() {
38
36
  const writer = new code_block_writer_1.default({
@@ -117,9 +115,9 @@ function generateTsCode(sqlOld, queryName, schemaDef, client, isCrud = false) {
117
115
  writer.blankLine();
118
116
  writer.write(`export type ${whereTypeName} =`).indent(() => {
119
117
  for (const col of tsDescriptor.columns) {
120
- writer.writeLine(`| ['${col.name}', ${(0, code_generator_1.getOperator)(col.tsType)}, ${col.tsType} | null]`);
121
- writer.writeLine(`| ['${col.name}', SetOperator, ${col.tsType}[]]`);
122
- writer.writeLine(`| ['${col.name}', BetweenOperator, ${col.tsType} | null, ${col.tsType} | null]`);
118
+ writer.writeLine(`| { column: '${col.name}'; op: ${(0, code_generator_1.getOperator)(col.tsType)}; value: ${col.tsType} | null }`);
119
+ writer.writeLine(`| { column: '${col.name}'; op: SetOperator; value: ${col.tsType}[] }`);
120
+ writer.writeLine(`| { column: '${col.name}'; op: BetweenOperator; value: [${col.tsType} | null, ${col.tsType} | null] }`);
123
121
  }
124
122
  });
125
123
  writer.blankLine();
@@ -128,23 +126,25 @@ function generateTsCode(sqlOld, queryName, schemaDef, client, isCrud = false) {
128
126
  // functionParams += `, data: ${dataType}`;
129
127
  // }
130
128
  functionArguments += `, params?: ${dynamicParamsTypeName}`;
131
- writer.writeLine('let currentIndex: number;');
132
129
  writer.write(`export async function ${camelCaseName}(${functionArguments}): Promise<${resultTypeName}[]>`).block(() => {
133
- writer.writeLine(`currentIndex = ${tsDescriptor.parameters.length};`);
134
- writer.writeLine('const where = whereConditionsToObject(params?.where);');
135
130
  // if (orderByField != null) {
136
131
  // writer.writeLine('const orderBy = orderByToObject(params.orderBy);');
137
132
  // }
138
- writer.writeLine('const paramsValues: any = [];');
133
+ writer.writeLine(`const isSelected = (field: keyof ${selectColumnsTypeName}) =>`);
134
+ writer.indent().write('params?.select == null || params.select[field] === true;').newLine();
135
+ writer.blankLine();
136
+ writer.writeLine('const selectedSqlFragments: string[] = [];');
137
+ writer.writeLine(`const selectedFields: (keyof ${resultTypeName})[] = [];`);
138
+ writer.writeLine('const paramsValues: any[] = [];');
139
+ writer.blankLine();
140
+ writer.writeLine('const whereColumns = new Set(params?.where?.map(w => w.column) || []);');
141
+ writer.blankLine();
139
142
  if (dynamicQueryInfo.with.length > 0) {
140
- writer.writeLine(`let withClause = '';`);
143
+ writer.writeLine(`const withFragments: string[] = [];`);
141
144
  dynamicQueryInfo.with.forEach((withFragment) => {
142
145
  var _a;
143
- const selectConditions = withFragment.dependOnFields.map((fieldIndex) => `params.select.${tsDescriptor.columns[fieldIndex].name}`);
144
- if (selectConditions.length > 0) {
145
- selectConditions.unshift('params?.select == null');
146
- }
147
- const whereConditions = withFragment.dependOnFields.map((fieldIndex) => `where.${tsDescriptor.columns[fieldIndex].name} != null`);
146
+ const selectConditions = withFragment.dependOnFields.map((fieldIndex) => `isSelected('${tsDescriptor.columns[fieldIndex].name}')`);
147
+ const whereConditions = withFragment.dependOnFields.map((fieldIndex) => `whereColumns.has('${tsDescriptor.columns[fieldIndex].name}')`);
148
148
  const orderByConditions = ((_a = withFragment.dependOnOrderBy) === null || _a === void 0 ? void 0 : _a.map((orderBy) => `orderBy['${orderBy}'] != null`)) || [];
149
149
  const allConditions = [...selectConditions, ...whereConditions, ...orderByConditions];
150
150
  const paramValues = withFragment.parameters.map((paramIndex) => {
@@ -152,43 +152,38 @@ function generateTsCode(sqlOld, queryName, schemaDef, client, isCrud = false) {
152
152
  return `params?.params?.${param.name}`;
153
153
  });
154
154
  if (allConditions.length > 0) {
155
- writer.write(`if (${allConditions.join(`${node_os_1.EOL}\t|| `)})`).block(() => {
156
- writer.writeLine(`if (withClause !== '') withClause += ',' + EOL;`);
157
- writer.write(`withClause += \`${withFragment.fragment}\`;`);
155
+ writer.writeLine(`if (`);
156
+ writer.indent().write(`${allConditions.join(`${node_os_1.EOL}\t|| `)}`).newLine();
157
+ writer.write(') ').inlineBlock(() => {
158
+ writer.write(`withFragments.push(\`${withFragment.fragment}\`);`);
158
159
  paramValues.forEach((paramValues) => {
159
160
  writer.writeLine(`paramsValues.push(${paramValues});`);
160
161
  });
161
- });
162
+ }).newLine();
162
163
  }
163
164
  else {
164
- writer.write(`withClause.push(\`${withFragment.fragment}\`);`);
165
+ writer.writeLine(`withFragments.push(\`${withFragment.fragment}\`);`);
165
166
  paramValues.forEach((paramValues) => {
166
167
  writer.writeLine(`paramsValues.push(${paramValues});`);
167
168
  });
168
169
  }
169
170
  });
170
171
  }
171
- writer.writeLine(`let sql = 'SELECT';`);
172
- if (dynamicQueryInfo.with.length > 0) {
173
- writer.write('if (withClause)').block(() => {
174
- writer.writeLine(`sql = 'WITH' + EOL + withClause + EOL + sql;`);
175
- });
176
- }
177
172
  dynamicQueryInfo.select.forEach((select, index) => {
178
- writer.write(`if (params?.select == null || params.select.${tsDescriptor.columns[index].name})`).block(() => {
179
- writer.writeLine(`sql = appendSelect(sql, \`${select.fragment}\`);`);
173
+ writer.write(`if (isSelected('${tsDescriptor.columns[index].name}'))`).block(() => {
174
+ writer.writeLine(`selectedSqlFragments.push('${select.fragment}');`);
175
+ writer.writeLine(`selectedFields.push('${tsDescriptor.columns[index].name}');`);
180
176
  select.parameters.forEach((param) => {
181
177
  writer.writeLine(`paramsValues.push(params?.params?.${param} ?? null);`);
182
178
  });
183
179
  });
184
180
  });
181
+ writer.blankLine();
182
+ writer.writeLine('const fromSqlFragments: string[] = [];');
185
183
  dynamicQueryInfo.from.forEach((from) => {
186
184
  var _a;
187
- const selectConditions = from.dependOnFields.map((fieldIndex) => `params.select.${tsDescriptor.columns[fieldIndex].name}`);
188
- if (selectConditions.length > 0) {
189
- selectConditions.unshift('params?.select == null');
190
- }
191
- const whereConditions = from.dependOnFields.map((fieldIndex) => `where.${tsDescriptor.columns[fieldIndex].name} != null`);
185
+ const selectConditions = from.dependOnFields.map((fieldIndex) => `isSelected('${tsDescriptor.columns[fieldIndex].name}')`);
186
+ const whereConditions = from.dependOnFields.map((fieldIndex) => `whereColumns.has('${tsDescriptor.columns[fieldIndex].name}')`);
192
187
  const orderByConditions = ((_a = from.dependOnOrderBy) === null || _a === void 0 ? void 0 : _a.map((orderBy) => `orderBy['${orderBy}'] != null`)) || [];
193
188
  const allConditions = [...selectConditions, ...whereConditions, ...orderByConditions];
194
189
  const paramValues = from.parameters.map((paramIndex) => {
@@ -196,33 +191,41 @@ function generateTsCode(sqlOld, queryName, schemaDef, client, isCrud = false) {
196
191
  return `params?.params?.${param.name}`;
197
192
  });
198
193
  if (allConditions.length > 0) {
199
- writer.write(`if (${allConditions.join(`${node_os_1.EOL}\t|| `)})`).block(() => {
200
- writer.write(`sql += EOL + \`${from.fragment}\`;`);
201
- paramValues.forEach((paramValues) => {
202
- writer.writeLine(`paramsValues.push(${paramValues});`);
203
- });
194
+ writer.blankLine();
195
+ writer.writeLine(`if (`);
196
+ writer.indent().write(`${allConditions.join(`${node_os_1.EOL}\t|| `)}`).newLine();
197
+ writer.write(') ').inlineBlock(() => {
198
+ writer.write(`fromSqlFragments.push(\`${from.fragment}\`);`);
199
+ });
200
+ paramValues.forEach((paramValues) => {
201
+ writer.writeLine(`paramsValues.push(${paramValues});`);
204
202
  });
205
203
  }
206
204
  else {
207
- writer.writeLine(`sql += EOL + \`${from.fragment}\`;`);
205
+ writer.writeLine(`fromSqlFragments.push(\`${from.fragment}\`);`);
208
206
  paramValues.forEach((paramValues) => {
209
207
  writer.writeLine(`paramsValues.push(${paramValues});`);
210
208
  });
211
209
  }
212
210
  });
213
- writer.writeLine('sql += EOL + `WHERE 1 = 1`;');
211
+ writer.blankLine();
212
+ writer.writeLine('const whereSqlFragments: string[] = [];');
213
+ writer.blankLine();
214
214
  dynamicQueryInfo.where.forEach((fragment) => {
215
215
  const paramValues = fragment.parameters.map((paramIndex) => {
216
216
  const param = tsDescriptor.parameters[paramIndex];
217
217
  return `params?.params?.${param.name} ?? null`;
218
218
  });
219
- writer.writeLine(`sql += EOL + \`${fragment.fragment}\`;`);
219
+ writer.writeLine(`whereSqlFragments.push(\`${fragment.fragment}\`);`);
220
220
  paramValues.forEach((paramValues) => {
221
221
  writer.writeLine(`paramsValues.push(${paramValues});`);
222
222
  });
223
223
  });
224
+ writer.writeLine(`let currentIndex = paramsValues.length;`);
225
+ writer.writeLine('const placeholder = () => `$${++currentIndex}`;');
226
+ writer.blankLine();
224
227
  writer.write('params?.where?.forEach(condition => ').inlineBlock(() => {
225
- writer.writeLine('const where = whereCondition(condition);');
228
+ writer.writeLine('const whereClause = whereCondition(condition, placeholder);');
226
229
  dynamicQueryInfo.select.forEach((select, index) => {
227
230
  if (select.parameters.length > 0) {
228
231
  writer.write(`if (condition[0] == '${tsDescriptor.columns[index].name}')`).block(() => {
@@ -232,45 +235,44 @@ function generateTsCode(sqlOld, queryName, schemaDef, client, isCrud = false) {
232
235
  });
233
236
  }
234
237
  });
235
- writer.write('if (where?.hasValue)').block(() => {
236
- writer.writeLine(`sql += EOL + 'AND ' + where.sql;`);
237
- writer.write('paramsValues.push(...where.values);');
238
+ writer.write('if (whereClause?.hasValue)').block(() => {
239
+ writer.writeLine(`whereSqlFragments.push(whereClause.sql);`);
240
+ writer.write('paramsValues.push(...whereClause.values);');
238
241
  });
239
242
  });
240
243
  writer.write(');').newLine();
244
+ if (dynamicQueryInfo.with.length > 0) {
245
+ writer.blankLine();
246
+ writer.writeLine('const withSql = withFragments.length > 0');
247
+ writer.indent().write('? `WITH${EOL}${withFragments.join(`,${EOL}`)}${EOL}`').newLine();
248
+ writer.indent().write(`: '';`).newLine();
249
+ }
250
+ writer.blankLine();
251
+ writer.writeLine('const whereSql = whereSqlFragments.length > 0 ? `WHERE ${whereSqlFragments.join(\' AND \')}` : \'\';');
252
+ writer.blankLine();
253
+ if (dynamicQueryInfo.with.length > 0) {
254
+ writer.writeLine('const sql = `${withSql}SELECT');
255
+ }
256
+ else {
257
+ writer.writeLine('const sql = `SELECT');
258
+ }
259
+ writer.indent().write('${selectedSqlFragments.join(`,${EOL}`)}').newLine();
260
+ writer.indent().write('${fromSqlFragments.join(EOL)}').newLine();
261
+ ;
262
+ writer.indent().write('${whereSql}`;').newLine();
263
+ writer.blankLine();
241
264
  writer.write(`return client.query({ text: sql, rowMode: 'array', values: paramsValues })`).newLine();
242
- writer.indent().write(`.then(res => res.rows.map(row => mapArrayTo${resultTypeName}(row, params?.select)));`);
265
+ writer.indent().write(`.then(res => res.rows.map(row => mapArrayTo${resultTypeName}(row, selectedFields)));`);
243
266
  });
244
267
  writer.blankLine();
245
- writer.write(`function mapArrayTo${resultTypeName}(data: any, select?: ${selectColumnsTypeName})`).block(() => {
246
- writer.writeLine(`const result = {} as ${resultTypeName};`);
247
- writer.writeLine('let rowIndex = -1;');
248
- tsDescriptor.columns.forEach((tsField) => {
249
- writer.write(`if (select == null || select.${tsField.name})`).block(() => {
250
- writer.writeLine('rowIndex++;');
251
- writer.writeLine(`result.${tsField.name} = ${toDriver('data[rowIndex]', tsField)};`);
252
- });
268
+ writer.write(`function mapArrayTo${resultTypeName}(data: any, selectedFields: (keyof ${resultTypeName})[])`).block(() => {
269
+ writer.writeLine(`const result: ${resultTypeName} = {};`);
270
+ writer.write(`selectedFields.forEach((field, index) => `).inlineBlock(() => {
271
+ writer.writeLine(`result[field] = data[index];`);
253
272
  });
273
+ writer.write(');').newLine();
254
274
  writer.write('return result;');
255
275
  });
256
- writer.blankLine();
257
- writer.write('function appendSelect(sql: string, selectField: string)').block(() => {
258
- writer.write(`if (sql.toUpperCase().endsWith('SELECT'))`).block(() => {
259
- writer.writeLine('return sql + EOL + selectField;');
260
- });
261
- writer.write('else').block(() => {
262
- writer.writeLine(`return sql + ', ' + EOL + selectField;`);
263
- });
264
- });
265
- writer.blankLine();
266
- writer.write(`function whereConditionsToObject(whereConditions?: ${whereTypeName}[])`).block(() => {
267
- writer.writeLine('const obj = {} as any;');
268
- writer.write('whereConditions?.forEach(condition => ').inlineBlock(() => {
269
- writer.writeLine('obj[condition[0]] = true;');
270
- });
271
- writer.write(');');
272
- writer.writeLine('return obj;');
273
- });
274
276
  // if (orderByField != null) {
275
277
  // writer.blankLine();
276
278
  // writer.write(`function orderByToObject(orderBy: ${dynamicParamsTypeName}['orderBy'])`).block(() => {
@@ -289,47 +291,46 @@ function generateTsCode(sqlOld, queryName, schemaDef, client, isCrud = false) {
289
291
  writer.writeLine('values: any[];');
290
292
  });
291
293
  writer.blankLine();
292
- writer.write(`function whereCondition(condition: ${whereTypeName}): WhereConditionResult | null `).block(() => {
293
- writer.blankLine();
294
- writer.writeLine('const selectFragment = selectFragments[condition[0]];');
295
- writer.writeLine('const operator = condition[1];');
294
+ writer.write(`function whereCondition(condition: ${whereTypeName}, placeholder: () => string): WhereConditionResult | null `).block(() => {
295
+ writer.writeLine('const selectFragment = selectFragments[condition.column];');
296
+ writer.writeLine('const { op, value } = condition;');
296
297
  writer.blankLine();
297
298
  if ((0, code_generator_1.hasStringColumn)(tsDescriptor.columns)) {
298
- writer.write(`if (operator == 'LIKE') `).block(() => {
299
+ writer.write(`if (op === 'LIKE') `).block(() => {
299
300
  writer.write('return ').block(() => {
300
301
  writer.writeLine("sql: `${selectFragment} LIKE ${placeholder()}`,");
301
- writer.writeLine('hasValue: condition[2] != null,');
302
- writer.writeLine('values: [condition[2]]');
302
+ writer.writeLine('hasValue: value != null,');
303
+ writer.writeLine('values: [value]');
303
304
  });
304
305
  });
305
306
  }
306
- writer.write(`if (operator == 'BETWEEN') `).block(() => {
307
+ writer.write(`if (op === 'BETWEEN') `).block(() => {
308
+ writer.writeLine('const [from, to] = Array.isArray(value) ? value : [null, null];');
307
309
  writer.write('return ').block(() => {
308
310
  writer.writeLine('sql: `${selectFragment} BETWEEN ${placeholder()} AND ${placeholder()}`,');
309
- writer.writeLine('hasValue: condition[2] != null && condition[3] != null,');
310
- writer.writeLine('values: [condition[2], condition[3]]');
311
+ writer.writeLine('hasValue: from != null && to != null,');
312
+ writer.writeLine('values: [from, to]');
311
313
  });
312
314
  });
313
- writer.write(`if (operator == 'IN' || operator == 'NOT IN') `).block(() => {
315
+ writer.write(`if (op === 'IN' || op === 'NOT IN') `).block(() => {
316
+ writer.write('if (!Array.isArray(value) || value.length === 0)').block(() => {
317
+ writer.writeLine(`return { sql: '', hasValue: false, values: [] };`);
318
+ });
314
319
  writer.write('return ').block(() => {
315
- writer.writeLine("sql: `${selectFragment} ${operator} (${condition[2]?.map(_ => placeholder()).join(', ')})`,");
316
- writer.writeLine('hasValue: condition[2] != null && condition[2].length > 0,');
317
- writer.writeLine('values: condition[2]');
320
+ writer.writeLine("sql: `${selectFragment} ${op} (${value.map(() => placeholder()).join(', ')})`,");
321
+ writer.writeLine('hasValue: true,');
322
+ writer.writeLine('values: value');
318
323
  });
319
324
  });
320
- writer.write('if (NumericOperatorList.includes(operator)) ').block(() => {
325
+ writer.write('if (NumericOperatorList.includes(op)) ').block(() => {
321
326
  writer.write('return ').block(() => {
322
- writer.writeLine('sql: `${selectFragment} ${operator} ${placeholder()}`,');
323
- writer.writeLine('hasValue: condition[2] != null,');
324
- writer.writeLine('values: [condition[2]]');
327
+ writer.writeLine('sql: `${selectFragment} ${op} ${placeholder()}`,');
328
+ writer.writeLine('hasValue: value != null,');
329
+ writer.writeLine('values: [value]');
325
330
  });
326
331
  });
327
332
  writer.writeLine('return null;');
328
333
  });
329
- writer.blankLine();
330
- writer.write('function placeholder(): string').block(() => {
331
- writer.writeLine('return `$${++currentIndex}`;');
332
- });
333
334
  }
334
335
  if (tsDescriptor.nestedDescriptor2) {
335
336
  const relations = tsDescriptor.nestedDescriptor2;
@@ -339,13 +340,13 @@ function generateTsCode(sqlOld, queryName, schemaDef, client, isCrud = false) {
339
340
  writer.write(`export type ${relationType} = `).block(() => {
340
341
  const uniqueNameFields = (0, code_generator_1.renameInvalidNames)(relation.fields.map((f) => f.name));
341
342
  relation.fields.forEach((field, index) => {
342
- const nullableOperator = field.notNull ? '' : ' | null';
343
- writer.writeLine(`${uniqueNameFields[index]}: ${field.tsType}${nullableOperator};`);
343
+ const nullable = field.notNull ? '' : ' | null';
344
+ writer.writeLine(`${uniqueNameFields[index]}: ${field.tsType}${nullable};`);
344
345
  });
345
346
  relation.relations.forEach((field) => {
346
347
  const nestedRelationType = (0, code_generator_1.generateRelationType)(capitalizedName, field.tsType);
347
- const nullableOperator = field.notNull ? '' : '?';
348
- writer.writeLine(`${field.name}${nullableOperator}: ${nestedRelationType};`);
348
+ const nullable = field.notNull ? '' : ' | null';
349
+ writer.writeLine(`${field.name}: ${nestedRelationType}${nullable};`);
349
350
  });
350
351
  });
351
352
  });
@@ -364,8 +365,10 @@ function generateTsCode(sqlOld, queryName, schemaDef, client, isCrud = false) {
364
365
  parameters: tsDescriptor.parameters,
365
366
  data: tsDescriptor.data || [],
366
367
  returning: schemaDef.returning || false,
368
+ orderByTypeName: orderByTypeName,
369
+ orderByColumns: tsDescriptor.orderByColumns || [],
367
370
  generateNested: tsDescriptor.nestedDescriptor2 != null,
368
- nestedType: tsDescriptor.nestedDescriptor2 ? tsDescriptor.nestedDescriptor2[0].name : ''
371
+ nestedType: tsDescriptor.nestedDescriptor2 ? tsDescriptor.nestedDescriptor2[0].name : '',
369
372
  };
370
373
  codeWriter.writeExecFunction(writer, execFunctionParams);
371
374
  }
@@ -436,15 +439,16 @@ function writeParamsType(writer, paramsTypeName, params, generateOrderBy, orderB
436
439
  writer.writeLine(`${field.name}${optionalOp}: ${field.tsType}${orNull};`);
437
440
  });
438
441
  if (generateOrderBy) {
439
- writer.writeLine(`orderBy: [${orderByTypeName}, 'asc' | 'desc'][];`);
442
+ writer.writeLine(`orderBy: ${orderByTypeName}[];`);
440
443
  }
441
444
  });
442
445
  }
443
446
  function writeResultType(writer, resultTypeName, columns) {
444
447
  writer.write(`export type ${resultTypeName} =`).block(() => {
445
448
  columns.forEach((field) => {
446
- const optionalOp = field.notNull ? '' : '?';
447
- writer.writeLine(`${field.name}${optionalOp}: ${field.tsType};`);
449
+ const optionalOp = field.optional ? '?' : '';
450
+ const nullable = field.notNull ? '' : ' | null';
451
+ writer.writeLine(`${field.name}${optionalOp}: ${field.tsType}${nullable};`);
448
452
  });
449
453
  });
450
454
  }
@@ -457,9 +461,9 @@ function writeJsonTypes(writer, typeName, type) {
457
461
  writer.write(`export type ${typeName}Type =`).block(() => {
458
462
  type.properties.forEach((field) => {
459
463
  if (isJsonObjType(field.type)) {
460
- const optionalOp = field.type.notNull ? '' : '?';
464
+ const nullable = field.type.notNull ? '' : ' | null';
461
465
  const jsonTypeName = createJsonType(typeName, field.key);
462
- writer.writeLine(`${field.key}${optionalOp}: ${jsonTypeName}Type;`);
466
+ writer.writeLine(`${field.key}: ${jsonTypeName}Type${nullable};`);
463
467
  }
464
468
  else if (isJsonArrayType(field.type)) {
465
469
  const jsonParentName = createJsonType(typeName, field.key);
@@ -467,8 +471,8 @@ function writeJsonTypes(writer, typeName, type) {
467
471
  writer.writeLine(`${field.key}: ${jsonTypeName};`);
468
472
  }
469
473
  else if (isJsonFieldType(field.type)) {
470
- const optionalOp = field.type.notNull ? '' : '?';
471
- writer.writeLine(`${field.key}${optionalOp}: ${(0, postgres_1.mapColumnType)(field.type.type, true)};`);
474
+ const nullable = field.type.notNull ? '' : ' | null';
475
+ writer.writeLine(`${field.key}: ${(0, postgres_1.mapColumnType)(field.type.type, true)}${nullable};`);
472
476
  }
473
477
  });
474
478
  });
@@ -484,6 +488,9 @@ function createTsDescriptor(capitalizedName, schemaDef) {
484
488
  parameterNames: [],
485
489
  data: (_a = schemaDef.data) === null || _a === void 0 ? void 0 : _a.map(param => mapParameterToTsFieldDescriptor(param))
486
490
  };
491
+ if (schemaDef.orderByColumns) {
492
+ tsDescriptor.orderByColumns = schemaDef.orderByColumns;
493
+ }
487
494
  if (schemaDef.nestedInfo) {
488
495
  const nestedDescriptor2 = schemaDef.nestedInfo.map((relation) => {
489
496
  const tsRelation = {
@@ -539,7 +546,8 @@ function mapColumnInfoToTsFieldDescriptor(capitalizedName, col, dynamicQuery) {
539
546
  const tsField = {
540
547
  name: col.name,
541
548
  tsType: createTsType(typeName, col.type),
542
- notNull: dynamicQuery ? false : col.notNull
549
+ optional: dynamicQuery ? true : false,
550
+ notNull: dynamicQuery ? true : col.notNull
543
551
  };
544
552
  return tsField;
545
553
  }
@@ -601,12 +609,12 @@ function _writeCopyFunction(writer, params) {
601
609
  });
602
610
  }
603
611
  function _writeExecFunction(writer, params) {
604
- const { functionName, paramsType, dataType, returnType, parameters, generateNested, nestedType } = params;
612
+ const { functionName, paramsType, dataType, returnType, parameters, orderByTypeName, orderByColumns, generateNested, nestedType } = params;
605
613
  let functionParams = params.queryType === 'Copy' ? 'client: pg.Client | pg.PoolClient' : 'client: pg.Client | pg.Pool | pg.PoolClient';
606
614
  if (params.data.length > 0) {
607
615
  functionParams += `, data: ${dataType}`;
608
616
  }
609
- if (parameters.length > 0) {
617
+ if (parameters.length > 0 || orderByColumns.length > 0) {
610
618
  functionParams += `, params: ${paramsType}`;
611
619
  }
612
620
  const allParamters = [...params.data.map(param => paramToDriver(param, 'data')),
@@ -671,6 +679,34 @@ function _writeExecFunction(writer, params) {
671
679
  });
672
680
  writer.writeLine('return result;');
673
681
  });
682
+ if (orderByColumns.length > 0) {
683
+ writer.blankLine();
684
+ writer.writeLine(`const orderByColumns = [${orderByColumns.map(col => `'${col}'`).join(', ')}] as const;`);
685
+ writer.blankLine();
686
+ writer.write(`export type ${orderByTypeName} =`).block(() => {
687
+ writer.writeLine('column: typeof orderByColumns[number];');
688
+ writer.writeLine(`direction: 'asc' | 'desc';`);
689
+ });
690
+ writer.blankLine();
691
+ writer.write(`function buildOrderBy(orderBy: ${orderByTypeName}[]): string`).block(() => {
692
+ writer.write('if (!Array.isArray(orderBy) || orderBy.length === 0)').block(() => {
693
+ writer.writeLine(`throw new Error('orderBy must be a non-empty array');`);
694
+ });
695
+ writer.blankLine();
696
+ writer.write('for (const { column, direction } of orderBy)').block(() => {
697
+ writer.write('if (!orderByColumns.includes(column))').block(() => {
698
+ writer.writeLine('throw new Error(`Invalid orderBy column: ${column}`);');
699
+ });
700
+ writer.write(`if (direction !== 'asc' && direction !== 'desc')`).block(() => {
701
+ writer.writeLine('throw new Error(`Invalid orderBy direction: ${direction}`);');
702
+ });
703
+ });
704
+ writer.blankLine();
705
+ writer.writeLine('return orderBy');
706
+ writer.indent().write('.map(({ column, direction }) => `"${column}" ${direction.toUpperCase()}`)').newLine();
707
+ writer.indent().write(`.join(', ');`).newLine();
708
+ });
709
+ }
674
710
  if (generateNested) {
675
711
  writer.blankLine();
676
712
  const relationType = (0, code_generator_1.generateRelationType)(functionName, nestedType);
@@ -722,7 +758,7 @@ function getColumnsForQuery(capitalizedName, schemaDef) {
722
758
  }
723
759
  function toDriver(variableData, param) {
724
760
  if (param.tsType === 'Date') {
725
- if (param.notNull) {
761
+ if (param.notNull && !param.optional) {
726
762
  return `new Date(${variableData})`;
727
763
  }
728
764
  return `${variableData} != null ? new Date(${variableData}) : ${variableData}`;
@@ -769,7 +805,7 @@ function generateCrud(queryType, tableName, dbSchema) {
769
805
  writeParamsType(writer, paramsTypeName, uniqueParams, false, '');
770
806
  }
771
807
  writer.blankLine();
772
- const columns = allColumns.map(col => mapPostgresColumnSchemaToTsFieldDescriptor(col));
808
+ const columns = allColumns.map(col => (Object.assign(Object.assign({}, mapPostgresColumnSchemaToTsFieldDescriptor(col)), { optional: false })));
773
809
  writeResultType(writer, resultTypeName, columns);
774
810
  writer.blankLine();
775
811
  const crudParameters = {