This is the sixth part of the SQLxD series. For your convenience you can find other parts in the table of contents in Part 1 – XML Transformation
We already know how to transform XML nodes into SQL-like rows. Now it is time to execute DQL queries. For now I will just describe operators implementation, I will handle parsing later in this series.
Today we describe basic construct: FROM.
Implementation
FROM implementation is straightforward: we assume that we already parsed the XML document (so we have strongly typed model), we have logic for building row, and we have mechanisms for extracting nodes using multi-segment identifiers. All we need to do is connect them together:
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 47 48 49 50 51 |
using System.Collections.Generic; using System.Linq; using Model; using QueryLogic.Selectors; namespace QueryLogic.RelationProviding { public class From : IRelationProvider { public From(ISelector selector, string alias) { Selector = selector; Alias = alias; } public string Alias { get; private set; } public ISelector Selector { get; set; } public Relation CreateRelation(Node source) { var result = new Relation(); IEnumerable< Node> selectedNodes = Selector.Select(source); result.AddRows(RowBuilder.BuildRows(selectedNodes.ToArray(), Alias)); return result; } protected bool Equals(From other) { return string.Equals(Alias, other.Alias) && Equals(Selector, other.Selector); } 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((From)obj); } public override int GetHashCode() { unchecked { return ((Alias != null ? Alias.GetHashCode() : 0) * 397) ^ (Selector != null ? Selector.GetHashCode() : 0); } } } } |
We create FROM, pass selector and alias and we can call CreateRelation
. The missing piece is what exactly is a Relation
:
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 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
using System.Collections.Generic; using System.Linq; namespace Model { public class Relation { private readonly ISet< ColumnHeader> _columns; private readonly ISet< GuidHeader> _guids; private readonly IList< Row> _rows; public Relation() { _columns = new HashSet< ColumnHeader>(); _rows = new List< Row>(); _guids = new HashSet< GuidHeader>(); } public Relation(IEnumerable< Row> rows) : this() { AddRows(rows); } public IEnumerable< Row> Rows { get { return _rows; } } public IEnumerable< ColumnHeader> Columns { get { return _columns; } } public IEnumerable< GuidHeader> Guids { get { return _guids; } } public void AddRow(Row row) { _rows.Add(row); _columns.UnionWith(row.Columns); _guids.UnionWith(row.Guids.Select(guid => guid.GuidHeader)); } public void AddRows(IEnumerable< Row> rows) { foreach (Row row in rows) { AddRow(row); } } public override string ToString() { return string.Join(" ;;; ", Rows.Select(r => r.ToString())); } protected bool Equals(Relation other) { return _rows.SequenceEqual(other._rows) && _columns.SequenceEqual(other._columns); } 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((Relation)obj); } public override int GetHashCode() { unchecked { return ((_rows != null ? _rows.GetHashCode() : 0) * 397) ^ (_columns != null ? _columns.GetHashCode() : 0); } } } } |
As we can see, Relation
is just a bag of rows and columns, that’s all.
In the next part we will handle filtering using WHERE clause.