import { isEmpty } from 'lodash'; import { QueryEditorExpressionType, QueryEditorFunctionExpression, QueryEditorGroupByExpression, QueryEditorPropertyExpression, QueryEditorPropertyType, } from '../expressions'; import { SQLQuery, SQLExpression } from '../types'; export function defaultToRawSql({ sql, dataset, table }: SQLQuery): string { let rawQuery = ''; // Return early with empty string if there is no sql column if (!sql || !haveColumns(sql.columns)) { return rawQuery; } rawQuery += createSelectClause(sql.columns); if (dataset && table) { rawQuery += `FROM ${dataset}.${table} `; } if (sql.whereString) { rawQuery += `WHERE ${sql.whereString} `; } if (sql.groupBy?.[0]?.property.name) { const groupBy = sql.groupBy.map((g) => g.property.name).filter((g) => !isEmpty(g)); rawQuery += `GROUP BY ${groupBy.join(', ')} `; } if (sql.orderBy?.property.name) { rawQuery += `ORDER BY ${sql.orderBy.property.name} `; } if (sql.orderBy?.property.name && sql.orderByDirection) { rawQuery += `${sql.orderByDirection} `; } // Altough LIMIT 0 doesn't make sense, it is still possible to have LIMIT 0 if (sql.limit !== undefined && sql.limit >= 0) { rawQuery += `LIMIT ${sql.limit} `; } return rawQuery; } function createSelectClause(sqlColumns: NonNullable): string { const columns = sqlColumns.map((c) => { let rawColumn = ''; if (c.name) { rawColumn += `${c.name}(${c.parameters?.map((p) => `${p.name}`)})`; } else { rawColumn += `${c.parameters?.map((p) => `${p.name}`)}`; } return rawColumn; }); return `SELECT ${columns.join(', ')} `; } export const haveColumns = (columns: SQLExpression['columns']): columns is NonNullable => { if (!columns) { return false; } const haveColumn = columns.some((c) => c.parameters?.length || c.parameters?.some((p) => p.name)); const haveFunction = columns.some((c) => c.name); return haveColumn || haveFunction; }; /** * Creates a GroupByExpression for a specified field */ export function setGroupByField(field?: string): QueryEditorGroupByExpression { return { type: QueryEditorExpressionType.GroupBy, property: { type: QueryEditorPropertyType.String, name: field, }, }; } /** * Creates a PropertyExpression for a specified field */ export function setPropertyField(field?: string): QueryEditorPropertyExpression { return { type: QueryEditorExpressionType.Property, property: { type: QueryEditorPropertyType.String, name: field, }, }; } export function createFunctionField(functionName?: string): QueryEditorFunctionExpression { return { type: QueryEditorExpressionType.Function, name: functionName, parameters: [], }; }