Skip to content
This repository has been archived by the owner on Jul 22, 2024. It is now read-only.

Commit

Permalink
add some docs; refactoring and some optimization
Browse files Browse the repository at this point in the history
  • Loading branch information
Jerry Liang committed Aug 18, 2019
1 parent 82fcead commit b39032e
Show file tree
Hide file tree
Showing 36 changed files with 2,527 additions and 1,289 deletions.
7 changes: 7 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"cSpell.words": [
"transpiler",
"transpiled",
"transpiling"
]
}
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,13 @@ This library has three main components:
* A logic planner transforms the AST into relational query logical plan similar to the [Relational Algebra](https://en.wikipedia.org/wiki/Relational_algebra);
* A query code renderer produces the actual query code from the logical plan. In this repository, we provides a T-SQL renderer.

The above components form a pipeline where the openCypher query and the graph schema is fed to the parser and the transpiled query is the output from the code renderer:

![openCypher Transpiler pipeline](docs/transpiler.svg)

The library, written in [.Net Core](https://dotnet.microsoft.com/download), is cross-platform.

[![Build Status](https://dev.azure.com/ms/openCypherTranspiler/_apis/build/status/microsoft.openCypherTranspiler?branchName=master)](https://dev.azure.com/ms/openCypherTranspiler/_build/latest?definitionId=191&branchName=master)

## Using the library

Expand All @@ -37,7 +42,7 @@ To run the tests, simply run under the project root folder:
dotnet test
```

## Roadmap
## Road map

### Current work in Progress
* Publish NuGet packages
Expand Down
798 changes: 798 additions & 0 deletions docs/transpiler.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/transpiler.vsdx
Binary file not shown.
172 changes: 172 additions & 0 deletions examples/simple/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
using System;
using System.Collections.Generic;
using System.Linq;
using openCypherTranspiler.Common.GraphSchema;
using openCypherTranspiler.LogicalPlanner;
using openCypherTranspiler.openCypherParser;
using openCypherTranspiler.SQLRenderer;

namespace Simple
{
class Program
{
class SimpleProvider : ISQLDBSchemaProvider
{
private static readonly IDictionary<string, NodeSchema> Nodes = new List<NodeSchema>()
{
new NodeSchema()
{
Name = "device",
NodeIdProperty = new EntityProperty()
{
PropertyName = "id",
DataType = typeof(string),
PropertyType = EntityProperty.PropertyDefinitionType.NodeJoinKey
},
Properties = Enumerable.Empty<EntityProperty>().ToList()
},
new NodeSchema()
{
Name = "tenant",
NodeIdProperty = new EntityProperty()
{
PropertyName = "id",
DataType = typeof(string),
PropertyType = EntityProperty.PropertyDefinitionType.NodeJoinKey
},
Properties = Enumerable.Empty<EntityProperty>().ToList()
},
new NodeSchema()
{
Name = "app",
NodeIdProperty = new EntityProperty()
{
PropertyName = "id",
DataType = typeof(string),
PropertyType = EntityProperty.PropertyDefinitionType.NodeJoinKey
},
Properties = new List<EntityProperty>()
{
new EntityProperty()
{
PropertyName = "AppName",
DataType = typeof(string),
PropertyType = EntityProperty.PropertyDefinitionType.RegularProperty
},
}
}
}.ToDictionary(kv => kv.Name, kv => kv);

private static readonly IDictionary<string, EdgeSchema> Edges = new List<EdgeSchema>()
{
new EdgeSchema()
{
Name = "belongsTo",
SourceNodeId = "device",
SourceIdProperty = new EntityProperty()
{
PropertyName = "srcid",
DataType = typeof(string),
PropertyType = EntityProperty.PropertyDefinitionType.SourceNodeJoinKey
},
SinkNodeId = "tenant",
SinkIdProperty = new EntityProperty()
{
PropertyName = "destid",
DataType = typeof(string),
PropertyType = EntityProperty.PropertyDefinitionType.SinkNodeJoinKey
},
Properties = Enumerable.Empty<EntityProperty>().ToList()
},
new EdgeSchema()
{
Name = "runs",
SourceNodeId = "device",
SourceIdProperty = new EntityProperty()
{
PropertyName = "srcid",
DataType = typeof(string),
PropertyType = EntityProperty.PropertyDefinitionType.SourceNodeJoinKey
},
SinkNodeId = "app",
SinkIdProperty = new EntityProperty()
{
PropertyName = "destid",
DataType = typeof(string),
PropertyType = EntityProperty.PropertyDefinitionType.SinkNodeJoinKey
},
Properties = Enumerable.Empty<EntityProperty>().ToList()
}
}.ToDictionary(kv => $"{kv.SourceNodeId}@{kv.Name}@{kv.SinkNodeId}", kv => kv);

private static readonly IDictionary<string, SQLTableDescriptor> Tables = new List<SQLTableDescriptor>()
{
new SQLTableDescriptor()
{
EntityId = "device",
TableOrViewName = "tblDevice"
},
new SQLTableDescriptor()
{
EntityId = "tenant",
TableOrViewName = "tblTenant"
},
new SQLTableDescriptor()
{
EntityId = "app",
TableOrViewName = "tblApp"
},
new SQLTableDescriptor()
{
EntityId = "device@belongsTo@tenant",
TableOrViewName = "tblBelongsTo"
},
new SQLTableDescriptor()
{
EntityId = "device@runs@app",
TableOrViewName = "tblRuns"
},
}.ToDictionary(kv => kv.EntityId, kv => kv);

public EdgeSchema GetEdgeDefinition(string edgeVerb, string fromNodeName, string toNodeName)
{
return Edges[$"{fromNodeName}@{edgeVerb}@{toNodeName}"];
}

public NodeSchema GetNodeDefinition(string nodeName)
{
return Nodes[nodeName];
}

public SQLTableDescriptor GetSQLTableDescriptors(string entityId)
{
// In this function, you will need to map SQL table or view to
// the graph entities (nodes and edges). The table or the view
// should already be normalized against the node key or
// the edge source/sink key
return Tables[entityId];
}
}

static void Main(string[] args)
{
var cypherQueryText = @"
MATCH (d:device)-[:belongsTo]->(t:tenant)
MATCH (d)-[:runs]->(a:app)
RETURN t.id as TenantId, a.AppName as AppName, COUNT(d) as DeviceCount
";

Console.WriteLine("Input openCypher Query:");
Console.WriteLine(cypherQueryText);

var graphDef = new SimpleProvider();

var plan = LogicalPlan.ProcessQueryTree(OpenCypherParser.Parse(cypherQueryText, null), graphDef, null);
var sqlRender = new SQLRenderer(graphDef, null);
var tSqlQuery = sqlRender.RenderPlan(plan);

Console.WriteLine("Output T-SQL Query:");
Console.WriteLine(tSqlQuery);
}
}
}
19 changes: 19 additions & 0 deletions examples/simple/simple.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<RestoreSources>$(RestoreSources);../../src/Common/bin/Debug;../../src/openCypherParser/bin/Debug;../../src/LogicalPlanner/bin/Debug;../../src/SQLRenderer/bin/Debug;https://api.nuget.org/v3/index.json</RestoreSources>
</PropertyGroup>

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="openCypherTranspiler.Common" Version="0.1.0" />
<PackageReference Include="openCypherTranspiler.openCypherParser" Version="0.1.0" />
<PackageReference Include="openCypherTranspiler.LogicalPlanner" Version="0.1.0" />
<PackageReference Include="openCypherTranspiler.SQLRenderer" Version="0.1.0" />
</ItemGroup>

</Project>
10 changes: 10 additions & 0 deletions src/Common/Interfaces/IParser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace openCypherTranspiler.Common.Interfaces
{
public interface IParser
{
}
}
34 changes: 16 additions & 18 deletions src/LogicalPlanner/Logical/LogicalOperator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,8 @@ public override string ToString()
}

/// <summary>
/// Operator to satisfy WHERE
/// Operator for row selections (e.g. WHERE or LIMIT)
/// We also captures ORDERING instructions in this operator, too
/// </summary>
public sealed class SelectionOperator : UnaryLogicalOperator
{
Expand All @@ -498,13 +499,13 @@ public SelectionOperator(LogicalOperator inOp, QueryExpression filterExpr)
UnexpandedEntityInequalityConditions = null;
SetInOperator(inOp);
}
public SelectionOperator(LogicalOperator inOp,IList<QueryExpressionOrderBy> orderExpr, IList<QueryExpressionLimit> limitExpr)
public SelectionOperator(LogicalOperator inOp,IList<SortItem> orderExprs, LimitClause limit)
{
FilterExpression = null;
UnexpandedEntityInequalityConditions = null;
SetInOperator(inOp);
OrderByExpressions = orderExpr;
LimitExpressions = limitExpr;
OrderByExpressions = orderExprs;
Limit = limit;
}

public SelectionOperator(LogicalOperator inOp, IEnumerable<(string, string)> entityInquityConds)
Expand All @@ -517,14 +518,14 @@ public SelectionOperator(LogicalOperator inOp, IEnumerable<(string, string)> ent
public QueryExpression FilterExpression { get; private set; }

/// <summary>
/// use to store ORDER BY expression under WITH or RETURN clause
/// use to store ORDER BY expression under WITH or RETURN clause
/// </summary>
public IList<QueryExpressionOrderBy> OrderByExpressions { get; private set; }
public IList<SortItem> OrderByExpressions { get; private set; }

/// <summary>
/// use to store LIMIT expression under WITH or RETURN clause
/// </summary>
public IList<QueryExpressionLimit> LimitExpressions { get; private set; }
public LimitClause Limit { get; private set; }

/// <summary>
/// Inequality conditions to be added after binding, specificially reserved for the implied inequality
Expand Down Expand Up @@ -611,11 +612,11 @@ internal override void AppendReferencedProperties(IDictionary<string, EntityFiel
// Selection operator may have additional field references in the where/order by conditions that were not referenced in output
// Add these as well to the input

Debug.Assert(FilterExpression != null || OrderByExpressions != null || LimitExpressions != null );
Debug.Assert(FilterExpression != null || OrderByExpressions != null || Limit != null );
var allPropertyReferences = new List<QueryExpressionProperty>();

var propsFromFilterExprs = FilterExpression?.GetChildrenQueryExpressionType<QueryExpressionProperty>();
var propsFromOrderByExprs = OrderByExpressions?.SelectMany(n => n.GetChildrenQueryExpressionType<QueryExpressionProperty>());
var propsFromOrderByExprs = OrderByExpressions?.SelectMany(n => n.InnerExpression.GetChildrenQueryExpressionType<QueryExpressionProperty>());

if(propsFromOrderByExprs != null)
{
Expand Down Expand Up @@ -666,11 +667,6 @@ internal override void AppendReferencedProperties(IDictionary<string, EntityFiel
{
// reference to an existing field
// nothing need to be done
// add a check if expression alias did exist
if(OutOperators.First().OutputSchema.All(n => n.FieldAlias != varName))
{
throw new TranspilerSyntaxErrorException($"single field name: {varName} not existed in output schema of depth {Depth} selection operator.");
}
}
}
}
Expand Down Expand Up @@ -785,23 +781,24 @@ internal override void PropagateOutSchema()
}
}
}

internal override void AppendReferencedProperties(IDictionary<string, EntityField> entityFields)
{

/*
// Adding more logic here, as some of upstream selection operator is selection operator, then the extra field in order
// by clause need to flow down to the referenced field.
if(InOperator is SelectionOperator)
if (InOperator is SelectionOperator)
{
var preSelectionOp = (InOperator as SelectionOperator);
var orderExpr = preSelectionOp?.OrderByExpressions;
if (orderExpr?.Count() > 0)
{
var propList = orderExpr
.SelectMany(n => n.GetChildrenQueryExpressionType<QueryExpressionProperty>())
.SelectMany(n => n.InnerExpression.GetChildrenQueryExpressionType<QueryExpressionProperty>())
.Where(p => p.PropertyName != null && p.VariableName != null)
.GroupBy(l => l.VariableName)
?.ToDictionary(p => p.Key, p => p.Select(n => n.PropertyName));
//looking for new entity fields in the slection operrator and then add to the entity field reference dictionary
// looking for new entity fields in the selection operator and then add to the entity field reference dictionary
if (propList != null)
{
foreach(var entry in propList)
Expand All @@ -822,6 +819,7 @@ internal override void AppendReferencedProperties(IDictionary<string, EntityFiel
}
}
}
*/
}
}

Expand Down
Loading

0 comments on commit b39032e

Please sign in to comment.