lundi 12 décembre 2016

Translator Design Pattern

Currently i have this (ugly) piece of code. It does a very simple thing. It takes a query as an input and translates it to SQL.

public class DqlSelectQueryTranslator : Translator<DqlSelectQuery>
{
    protected override string Translate(DqlSelectQuery query)
    {
        var ops = query.Operators;
        var sb = new StringBuilder();

        sb.AppendLine(ops.AnyOfType<DqlSelectOperator>()
            ? $"SELECT {string.Join(",", ops.FirstOfType<DqlSelectOperator>().Fields)} FROM {query.TargetEntityType.Name}"
            : $"SELECT * FROM {query.TargetEntityType.Name}");

        if (ops.AnyOfType<DqlIncludeOperator>())
        {
            foreach (var dst in ops.OfType<DqlIncludeOperator>())
            {
                var src = query.TargetEntityType;
                var type = src.GetRelationship<RelationshipAttribute>(dst.Type);

                if (type == null)
                    throw new NotSupportedException($"Unknown relationship between {src.Name} and {dst.Type.Name}");

                if (type is OneToManyAttribute)
                    sb.AppendLine($"JOIN {dst.Type.Name} {dst.Alias} ON {dst.Name}.{src.GetPrimaryKeys().First()} = {src.Name}.{src.GetPrimaryKeys().First()}");
                if (type is ManyToOneAttribute)
                    sb.AppendLine($"JOIN {dst.Type.Name} {dst.Alias} ON {dst.Name}.{dst.Type.GetPrimaryKeys().First()} = {src.Name}.{dst.Type.GetPrimaryKeys().First()}");
                if (type is ManyToManyAttribute)
                {
                    string joinName = $"_{src.Name}{dst.Type.Name}";
                    sb.AppendLine($"JOIN {src.GetRelationship<ManyToManyAttribute>(dst.Type).Join} {joinName} ON {joinName}.{src.GetPrimaryKeys().First()} = {src.Name}.{src.GetPrimaryKeys().First()}");
                    sb.AppendLine($"JOIN {dst.Type.Name} {dst.Alias} ON {dst.Name}.{dst.Type.GetPrimaryKeys().First()} = {joinName}.{dst.Type.GetPrimaryKeys().First()}");
                }
            }
        }
        if (ops.AnyOfType<DqlWhereOperator>())
            sb.AppendLine($"WHERE {ops.FirstOfType<DqlWhereOperator>().Condition}");
        if (ops.AnyOfType<DqlOffsetOperator>())
            sb.AppendLine($"OFFSET {ops.FirstOfType<DqlOffsetOperator>().Offset} ROWS");
        if (ops.AnyOfType<DqlLimitOperator>())
            sb.AppendLine($"FETCH NEXT {ops.FirstOfType<DqlLimitOperator>().Limit} ROWS ONLY");
        return sb.ToString().Trim();
    }
}

I'm looking for a way to improve that. My guess would be associate a "translator" to my operators/queries... It would be cleaner but then i would need to add classes with one line of code... Do you have good design patterns/ideas on how i can improve this bit?

Thx Seb

Aucun commentaire:

Enregistrer un commentaire