Skip to content

Commit 85e25e8

Browse files
author
Robert Gelb
committed
added support for group by statement
1 parent fa062a3 commit 85e25e8

File tree

4 files changed

+101
-15
lines changed

4 files changed

+101
-15
lines changed

Conversion/SqlToElasticSearchConversion.cs

Lines changed: 71 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Newtonsoft.Json;
22
using Newtonsoft.Json.Linq;
3+
using SqlToElasticSearchConverter.Helpers;
34
using System;
45
using System.Collections.Generic;
56
using System.Linq;
@@ -17,6 +18,58 @@ public SqlToElasticSearchConversion(string sqlQuery) {
1718
private void ProcessSqlQuery(string sqlQuery) {
1819
TSQLSelectStatement statement = TSQLStatementReader.ParseStatements(sqlQuery)[0] as TSQLSelectStatement;
1920

21+
if (statement.GroupBy == null) {
22+
HandleSelectStatement(statement);
23+
} else {
24+
HandleGroupByStatement(statement);
25+
}
26+
}
27+
28+
private void HandleGroupByStatement(TSQLSelectStatement statement) {
29+
30+
var table = statement.From.Table().Index;
31+
var conditions = statement.Where.Conditions();
32+
var fields = statement.Select.Fields();
33+
34+
string tableStatement = $"GET {table}/_search";
35+
36+
#region Build Group By Statement
37+
string groupByStatement = string.Empty;
38+
const string nextAggregationMarker = "(addNextAggregationHere)";
39+
40+
foreach (var field in fields) {
41+
string template = Templates.GroupBy.Replace("(column)", field.Column);
42+
43+
if (field == fields.Last()) {
44+
template = template.Replace("(additionalAggregation)", "");
45+
} else {
46+
template = template.Replace("(additionalAggregation)", nextAggregationMarker);
47+
}
48+
49+
if (groupByStatement.Contains(nextAggregationMarker)) {
50+
groupByStatement = groupByStatement.Replace(nextAggregationMarker, "," + Environment.NewLine + template);
51+
} else {
52+
groupByStatement = template;
53+
}
54+
}
55+
#endregion
56+
57+
List<string> conditionsList = GetConditionStatement(conditions);
58+
string conditionsStatement = Templates.Conditions.Replace("(conditions)", string.Join(",", conditionsList));
59+
60+
string sizeStatement = Templates.SizeZero;
61+
62+
string jsonPortion = $@"{{
63+
{sizeStatement},
64+
{groupByStatement},
65+
{conditionsStatement}
66+
}}".PrettyJson();
67+
68+
// set module level variable
69+
ElasticQuery = $"{tableStatement}{Environment.NewLine}{jsonPortion}";
70+
}
71+
72+
private void HandleSelectStatement(TSQLSelectStatement statement) {
2073
var table = statement.From.Table().Index;
2174
var conditions = statement.Where.Conditions();
2275
var fields = statement.Select.Fields();
@@ -33,6 +86,22 @@ private void ProcessSqlQuery(string sqlQuery) {
3386
fieldStatement = ", \"_source\": [" + fieldStatement + "]";
3487
}
3588

89+
List<string> conditionsList = GetConditionStatement(conditions);
90+
string conditionsStatement = Templates.Conditions.Replace("(conditions)", string.Join(",", conditionsList));
91+
92+
string jsonPortion = $@"{{
93+
{conditionsStatement}
94+
{fieldStatement}
95+
}}";
96+
97+
// format JSON
98+
jsonPortion = JToken.Parse(jsonPortion).ToString(Formatting.Indented);
99+
100+
// set module level variable
101+
ElasticQuery = $"{tableStatement}{Environment.NewLine}{jsonPortion}";
102+
}
103+
104+
private static List<string> GetConditionStatement(List<WhereCondition> conditions) {
36105
// get the conditions statement
37106
string conditionText = string.Empty;
38107
var conditionsList = new List<string>();
@@ -87,25 +156,15 @@ private void ProcessSqlQuery(string sqlQuery) {
87156
.Replace("(value)", condition.SingularValue.Replace("%", "*").ToLower());
88157

89158
break;
90-
159+
91160
case WhereCondition.OperatorType.Unknown:
92161
break;
93162
}
94163

95164
conditionsList.Add(conditionText);
96165
}
97-
string conditionsStatement = Templates.Conditions.Replace("(conditions)", string.Join(",", conditionsList));
98166

99-
string jsonPortion = $@"{{
100-
{conditionsStatement}
101-
{fieldStatement}
102-
}}";
103-
104-
// format JSON
105-
jsonPortion = JToken.Parse(jsonPortion).ToString(Formatting.Indented);
106-
107-
// set module level variable
108-
ElasticQuery = $"{tableStatement}{Environment.NewLine}{jsonPortion}";
167+
return conditionsList;
109168
}
110169

111170
public string ElasticQuery { get; set; } = string.Empty;

Conversion/Templates.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,5 +62,14 @@ public class Templates {
6262
]
6363
}
6464
}";
65+
66+
public const string GroupBy = @"
67+
""aggregations"": {
68+
""(column)"": {
69+
""terms"": { ""field"": ""(column).keyword"" }(additionalAggregation)
70+
}
71+
}";
72+
73+
public static string SizeZero => @"""size"": 0";
6574
}
6675
}

Helpers/Extentions.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using Newtonsoft.Json;
2+
3+
namespace SqlToElasticSearchConverter.Helpers
4+
{
5+
public static class Extentions
6+
{
7+
public static string PrettyJson(this string jsonString) {
8+
dynamic parsedJson = JsonConvert.DeserializeObject(jsonString);
9+
return JsonConvert.SerializeObject(parsedJson, Formatting.Indented);
10+
}
11+
}
12+
}

README.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@
77
This quickie app converts SQL statements into ElasticSearch equivalent queries. Note that the converter is very much a work in progress, and as such, doesn't support great many things.
88

99
## What works
10-
At the moment the application supports SELECT, FROM, WHERE statements.
10+
At the moment the application supports SELECT, FROM, WHERE, GROUP BY statements.
1111
For SELECT, you can either place * or specify column names.
1212
The FROM statement works with either aliases or indexes.
13-
The WHERE conditions support a subset of operators: =, >, >=, <, <=, IN, BETWEEN
13+
The WHERE conditions support a subset of operators: =, >, >=, <, <=, IN, BETWEEN
14+
The GROUP BY statement only supports column names. Functions such as COUNT(*) will cause the translation to fail
1415

1516
Examples:
1617
```sql
@@ -30,11 +31,16 @@ FROM Planets
3031
WHERE SpacecraftWithinKilometers < 10000
3132
```
3233

34+
```sql
35+
SELECT SolarSystem, Galaxy
36+
FROM Planets
37+
WHERE SpacecraftWithinKilometers < 10000
38+
GROUP BY SolarSystem, Galaxy
39+
```
3340

3441
## What doesn't work yet
3542
+ Inequality operator (!=)
3643
+ LIKE operator
37-
+ Grouping and Aggregations
3844
+ Sorting
3945
+ Joins (because ElasticSearch doesn't support them)
4046
+ Common SQL functions like GetDate, DateDiff, etc are not supported yet

0 commit comments

Comments
 (0)