This is the fourth part of the SQLxD series. For your convenience you can find other parts in the table of contents in Part 1 – XML Transformation
Now we can implement classes representing multi-part identifiers. We start with the following:
1 2 3 4 5 6 7 8 9 10 |
using System.Collections.Generic; using Model; namespace QueryLogic.Selectors { public interface ISelector { IEnumerable<Node> Select(Node parent); } } |
This selector providers us an abstraction of selecting nodes from root. We start with top level selector which extracts element only if its name is as specified:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
using System.Collections.Generic; using Model; namespace QueryLogic.Selectors { public class TopLevelSelector : ISelector { public TopLevelSelector(string name) { Name = name; } public string Name { get; private set; } public IEnumerable<Node> Select(Node parent) { if (parent.Name == Name) { yield return parent; } } protected bool Equals(TopLevelSelector other) { return string.Equals(Name, other.Name); } public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; if (obj.GetType() != GetType()) return false; return Equals((TopLevelSelector)obj); } public override int GetHashCode() { return (Name != null ? Name.GetHashCode() : 0); } } } |
Next, we can go one level deeper:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
using System.Collections.Generic; using Model; namespace QueryLogic.Selectors { public class LevelSelector : ISelector { public IEnumerable<Node> Select(Node parent) { return parent.InnerNodes; } protected bool Equals(LevelSelector other) { return true; } public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; if (obj.GetType() != GetType()) return false; return Equals((LevelSelector)obj); } public override int GetHashCode() { return 0; } } } |
We can also extract any children with specified name:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
using System.Collections.Generic; using System.Linq; using Model; namespace QueryLogic.Selectors { public class NodeSelector : ISelector { public NodeSelector(string name) { Name = name; } public string Name { get; private set; } public IEnumerable<Node> Select(Node parent) { return parent.InnerNodes.Where(node => node.Type == NodeType.Element && node.Name == Name); } protected bool Equals(NodeSelector other) { return string.Equals(Name, other.Name); } public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; if (obj.GetType() != GetType()) return false; return Equals((NodeSelector)obj); } public override int GetHashCode() { return (Name != null ? Name.GetHashCode() : 0); } } } |
Finally, we can recursively use selector for all children:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
using System.Collections.Generic; using System.Linq; using Model; namespace QueryLogic.Selectors { public class AnySelector : ISelector { public IEnumerable<Node> Select(Node parent) { return parent.InnerNodes.Concat(parent.InnerNodes.SelectMany(Select)); } protected bool Equals(AnySelector other) { return true; } public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; if (obj.GetType() != GetType()) return false; return Equals((AnySelector)obj); } public override int GetHashCode() { return 0; } } } |
This is great, we also need chain of selectors:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
using System.Collections.Generic; using System.Linq; using Model; namespace QueryLogic.Selectors { public class ChainedSelector : ISelector { public ChainedSelector(ISelector first, ISelector second) { First = first; Second = second; } public ISelector First { get; private set; } public ISelector Second { get; private set; } public IEnumerable<Node> Select(Node parent) { IEnumerable<Node> result = First.Select(parent); IList<Node> listResult = result as IList<Node> ?? result.ToList(); return listResult.Any() ? listResult.SelectMany(node => Second.Select(node)) : listResult; } protected bool Equals(ChainedSelector other) { return Equals(First, other.First) && Equals(Second, other.Second); } public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; if (obj.GetType() != GetType()) return false; return Equals((ChainedSelector)obj); } public override int GetHashCode() { unchecked { return ((First != null ? First.GetHashCode() : 0) * 397) ^ (Second != null ? Second.GetHashCode() : 0); } } } } |
And we are done. Now if we want to extract SELECT * FROM table
we use the new TopLevelSelector("table");
selector, if we want to represent t.table2
, we use new ChainedSelector(new TopLevelSelector("table"), new NodeSelector("table2"));
.