Skip to content

Commit

Permalink
remove extra spaces in generated sql, add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
SpencerTorres committed Dec 5, 2023
1 parent dedeb29 commit eac3968
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 10 deletions.
67 changes: 62 additions & 5 deletions src/data/sqlGenerator.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AggregateType, ColumnHint, QueryBuilderOptions, QueryType } from 'types/queryBuilder';
import { AggregateType, ColumnHint, FilterOperator, QueryBuilderOptions, QueryType } from 'types/queryBuilder';
import { generateSql, getColumnByHint, getColumnIndexByHint, getColumnsByHints, isAggregateQuery } from './sqlGenerator';

describe('SQL Generator', () => {
Expand All @@ -13,11 +13,20 @@ describe('SQL Generator', () => {
{ name: 'message', type: 'String', hint: ColumnHint.LogMessage },
],
limit: 1000,
filters: [],
filters: [
{
filterType: 'custom',
key: 'message',
type: 'String',
condition: 'AND',
operator: FilterOperator.IsNotNull
}
],
orderBy: []
};
const expectedSql = (
'SELECT timestamp as timestamp, message as body, level as level FROM "default"."logs" LIMIT 1000'
'SELECT timestamp as timestamp, message as body, level as level ' +
'FROM "default"."logs" WHERE ( message IS NOT NULL ) LIMIT 1000'
);

const sql = generateSql(opts);
Expand All @@ -41,15 +50,25 @@ describe('SQL Generator', () => {
{ name: 'ResourceAttributes', type: 'Map(LowCardinality(String), String)', hint: ColumnHint.TraceServiceTags },
],
limit: 1000,
filters: [],
filters: [
{
filterType: 'custom',
key: '', // hint property is used instead of column name
type: 'String',
condition: 'AND',
hint: ColumnHint.TraceId,
operator: FilterOperator.Equals,
value: '1234'
}
],
orderBy: []
};
const expectedSql = (
'SELECT "TraceId" as traceID, "SpanId" as spanID, "ParentSpanId" as parentSpanID, "ServiceName" as serviceName, ' +
'"SpanName" as operationName, "Timestamp" as startTime, "Duration" as duration, ' +
'arrayMap(key -> map(\'key\', key, \'value\',"SpanAttributes"[key]), mapKeys("SpanAttributes")) as tags, ' +
'arrayMap(key -> map(\'key\', key, \'value\',"ResourceAttributes"[key]), mapKeys("ResourceAttributes")) as serviceTags ' +
'FROM "otel"."otel_traces" ORDER BY startTime ASC LIMIT 1000'
'FROM "otel"."otel_traces" WHERE ( TraceId = \'1234\' ) ORDER BY startTime ASC LIMIT 1000'
);

const sql = generateSql(opts);
Expand Down Expand Up @@ -77,6 +96,44 @@ describe('SQL Generator', () => {
expect(sql).toEqual(expectedSql);
});

it('generates other sql with filters', () => {
const opts: QueryBuilderOptions = {
database: 'default',
table: 'data',
queryType: QueryType.Table,
columns: [
{ name: 'timestamp', type: 'DateTime' },
{ name: 'text', type: 'String' },
],
limit: 1000,
filters: [
{
operator: FilterOperator.WithInGrafanaTimeRange,
filterType: 'custom',
key: 'created_at',
type: 'datetime',
condition: 'AND'
},
{
filterType: 'custom',
key: 'event',
type: 'String',
condition: 'AND',
operator: FilterOperator.IsNotNull
}
],
orderBy: []
};
const expectedSql = (
'SELECT "timestamp", "text" FROM "default"."data" ' +
'WHERE ( created_at >= $__fromTime AND created_at <= $__toTime ) AND ( event IS NOT NULL ) ' +
'LIMIT 1000'
);

const sql = generateSql(opts);
expect(sql).toEqual(expectedSql);
});

it('excludes LIMIT when limit is 0', () => {
const opts: QueryBuilderOptions = {
database: 'default',
Expand Down
30 changes: 25 additions & 5 deletions src/data/sqlGenerator.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { getSqlFromQueryBuilderOptions, getOrderBy } from 'components/queryBuilder/utils';
import { BooleanFilter, ColumnHint, DateFilterWithValue, FilterOperator, MultiFilter, NumberFilter, QueryBuilderOptions, QueryType, SelectedColumn, StringFilter, TimeUnit } from 'types/queryBuilder';


export const generateSql = (options: QueryBuilderOptions): string => {
if (options.queryType === QueryType.Traces) {
return generateTraceQuery(options);
Expand Down Expand Up @@ -102,7 +101,7 @@ const generateTraceQuery = (options: QueryBuilderOptions): string => {
queryParts.push(limit);
}

return queryParts.join(' ');
return concatQueryParts(queryParts);
}

/**
Expand Down Expand Up @@ -166,7 +165,7 @@ const generateLogsQuery = (options: QueryBuilderOptions): string => {
queryParts.push(limit);
}

return queryParts.join(' ');
return concatQueryParts(queryParts);
}

export const isAggregateQuery = (builder: QueryBuilderOptions): boolean => (builder.aggregates?.length || 0) > 0;
Expand Down Expand Up @@ -233,6 +232,27 @@ const getTraceDurationSelectSql = (columnIdentifier: string, timeUnit?: TimeUnit
}
}

/**
* Concats query parts with no empty spaces.
*/
const concatQueryParts = (parts: readonly string[]): string => {
let query = '';
for (let i = 0; i < parts.length; i++) {
const p = parts[i];
if (!p) {
continue;
}

query += p;

if (i !== parts.length - 1) {
query += ' '
}
}

return query;
}

const getLimit = (limit?: number | undefined): string => {
limit = Math.max(0, limit || 0);
if (limit > 0) {
Expand Down Expand Up @@ -328,11 +348,11 @@ const getFilters = (options: QueryBuilderOptions): string => {
}
filterParts.push(')');

const builtFilter = filterParts.join(' ');
const builtFilter = concatQueryParts(filterParts);
builtFilters.push(builtFilter);
}

return builtFilters.join(' ');
return concatQueryParts(builtFilters);
};

const isBooleanType = (type: string): boolean => (type?.toLowerCase().startsWith('boolean'));
Expand Down

0 comments on commit eac3968

Please sign in to comment.