( sort: Sort, tableName: string, columns: ColumnDefinition[] )
| 204 | * // Returns: ORDER BY (user_table_rows.data->>'salary')::numeric DESC NULLS LAST |
| 205 | */ |
| 206 | export function buildSortClause( |
| 207 | sort: Sort, |
| 208 | tableName: string, |
| 209 | columns: ColumnDefinition[] |
| 210 | ): SQL | undefined { |
| 211 | const clauses: SQL[] = [] |
| 212 | const columnTypeMap = buildColumnTypeMap(columns) |
| 213 | |
| 214 | for (const [field, direction] of Object.entries(sort)) { |
| 215 | validateFieldName(field) |
| 216 | |
| 217 | if (direction !== 'asc' && direction !== 'desc') { |
| 218 | throw new TableQueryValidationError( |
| 219 | `Invalid sort direction "${direction}". Must be "asc" or "desc".` |
| 220 | ) |
| 221 | } |
| 222 | |
| 223 | const columnType = columnTypeMap.get(field) |
| 224 | clauses.push(buildSortFieldClause(tableName, field, direction, columnType)) |
| 225 | } |
| 226 | |
| 227 | return clauses.length > 0 ? sql.join(clauses, sql.raw(', ')) : undefined |
| 228 | } |
| 229 | |
| 230 | /** |
| 231 | * Validates a field name to prevent SQL injection. |
no test coverage detected