Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Data.Entity / System / Data / Mapping / ViewGeneration / QueryRewriting / Tile.cs
1 //---------------------------------------------------------------------
2 // <copyright file="Tile.cs" company="Microsoft">
3 //      Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //
6 // @owner Microsoft
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
9
10 using System;
11 using System.Diagnostics;
12 using System.Collections.Generic;
13 using System.Text;
14 using System.Collections.ObjectModel;
15 using System.Linq;
16 using System.Globalization;
17
18 namespace System.Data.Mapping.ViewGeneration.QueryRewriting
19 {
20     internal enum TileOpKind
21     {
22         Union,
23         Join,
24         AntiSemiJoin,
25         // Project,
26         Named
27     }
28
29     internal interface ITileQuery
30     {
31         string Description { get; }
32     }
33
34     internal abstract class TileQueryProcessor<T_Query> where T_Query : ITileQuery
35     {
36         internal abstract T_Query Intersect(T_Query arg1, T_Query arg2);
37         internal abstract T_Query Difference(T_Query arg1, T_Query arg2);
38         internal abstract T_Query Union(T_Query arg1, T_Query arg2);
39         internal abstract bool IsSatisfiable(T_Query query);
40         internal abstract T_Query CreateDerivedViewBySelectingConstantAttributes(T_Query query);
41     }
42
43     internal class DefaultTileProcessor<T_Query> : TileProcessor<Tile<T_Query>> where T_Query : ITileQuery
44     {
45         private readonly TileQueryProcessor<T_Query> _tileQueryProcessor;
46
47         internal DefaultTileProcessor(TileQueryProcessor<T_Query> tileQueryProcessor)
48         {
49             _tileQueryProcessor = tileQueryProcessor;
50         }
51
52         internal TileQueryProcessor<T_Query> QueryProcessor
53         {
54             get { return _tileQueryProcessor; }
55         }
56
57         internal override bool IsEmpty(Tile<T_Query> tile)
58         {
59             return false == _tileQueryProcessor.IsSatisfiable(tile.Query);
60         }
61
62         internal override Tile<T_Query> Union(Tile<T_Query> arg1, Tile<T_Query> arg2)
63         {
64             return new TileBinaryOperator<T_Query>(arg1, arg2, TileOpKind.Union, _tileQueryProcessor.Union(arg1.Query, arg2.Query));
65         }
66
67         internal override Tile<T_Query> Join(Tile<T_Query> arg1, Tile<T_Query> arg2)
68         {
69             return new TileBinaryOperator<T_Query>(arg1, arg2, TileOpKind.Join, _tileQueryProcessor.Intersect(arg1.Query, arg2.Query));
70         }
71
72         internal override Tile<T_Query> AntiSemiJoin(Tile<T_Query> arg1, Tile<T_Query> arg2)
73         {
74             return new TileBinaryOperator<T_Query>(arg1, arg2, TileOpKind.AntiSemiJoin, _tileQueryProcessor.Difference(arg1.Query, arg2.Query));
75         }
76
77         internal override Tile<T_Query> GetArg1(Tile<T_Query> tile)
78         {
79             return tile.Arg1;
80         }
81
82         internal override Tile<T_Query> GetArg2(Tile<T_Query> tile)
83         {
84             return tile.Arg2;
85         }
86
87         internal override TileOpKind GetOpKind(Tile<T_Query> tile)
88         {
89             return tile.OpKind;
90         }
91
92         internal bool IsContainedIn(Tile<T_Query> arg1, Tile<T_Query> arg2)
93         {
94             return IsEmpty(AntiSemiJoin(arg1, arg2));
95         }
96
97         internal bool IsEquivalentTo(Tile<T_Query> arg1, Tile<T_Query> arg2)
98         {
99             return IsContainedIn(arg1, arg2) && IsContainedIn(arg2, arg1);
100         }
101     }
102
103     internal abstract class Tile<T_Query> where T_Query : ITileQuery
104     {
105         private readonly T_Query m_query;
106         private readonly TileOpKind m_opKind;
107
108         protected Tile(TileOpKind opKind, T_Query query)
109         {
110             m_opKind = opKind;
111             m_query = query;
112         }
113
114         public T_Query Query
115         {
116             get { return m_query; }
117         }
118
119         public abstract string Description { get; }
120
121         // multiple occurrences possible
122         public IEnumerable<T_Query> GetNamedQueries()
123         {
124             return GetNamedQueries(this);
125         }
126         private static IEnumerable<T_Query> GetNamedQueries(Tile<T_Query> rewriting)
127         {
128             if (rewriting != null)
129             {
130                 if (rewriting.OpKind == TileOpKind.Named)
131                 {
132                     yield return ((TileNamed<T_Query>)rewriting).NamedQuery;
133                 }
134                 else
135                 {
136                     foreach (T_Query query in GetNamedQueries(rewriting.Arg1))
137                     {
138                         yield return query;
139                     }
140                     foreach (T_Query query in GetNamedQueries(rewriting.Arg2))
141                     {
142                         yield return query;
143                     }
144                 }
145             }
146         }
147
148         public override string ToString()
149         {
150             string formattedQuery = this.Description;
151             if (formattedQuery != null)
152             {
153                 return String.Format(CultureInfo.InvariantCulture, "{0}: [{1}]", this.Description, this.Query);
154             }
155             else
156             {
157                 return String.Format(CultureInfo.InvariantCulture, "[{0}]", this.Query);
158             }
159         }
160
161         public abstract Tile<T_Query> Arg1
162         {
163             get;
164         }
165
166         public abstract Tile<T_Query> Arg2
167         {
168             get;
169         }
170
171         public TileOpKind OpKind
172         {
173             get { return m_opKind; }
174         }
175
176         internal abstract Tile<T_Query> Replace(Tile<T_Query> oldTile, Tile<T_Query> newTile);
177     }
178
179     internal class TileNamed<T_Query> : Tile<T_Query> where T_Query : ITileQuery
180     {
181         public TileNamed(T_Query namedQuery)
182             : base(TileOpKind.Named, namedQuery)
183         {
184             Debug.Assert(namedQuery != null);
185         }
186
187         public T_Query NamedQuery
188         {
189             get { return this.Query; }
190         }
191
192         public override Tile<T_Query> Arg1 { get { return null; } }
193         public override Tile<T_Query> Arg2 { get { return null; } }
194
195         public override string Description
196         {
197             get { return this.Query.Description; }
198         }
199
200         public override string ToString()
201         {
202             return this.Query.ToString();
203         }
204
205         internal override Tile<T_Query> Replace(Tile<T_Query> oldTile, Tile<T_Query> newTile)
206         {
207             return (this == oldTile) ? newTile : this;
208         }
209     }
210
211     internal class TileBinaryOperator<T_Query> : Tile<T_Query> where T_Query : ITileQuery
212     {
213         private readonly Tile<T_Query> m_arg1;
214         private readonly Tile<T_Query> m_arg2;
215
216         public TileBinaryOperator(Tile<T_Query> arg1, Tile<T_Query> arg2, TileOpKind opKind, T_Query query)
217             : base(opKind, query)
218         {
219             Debug.Assert(arg1 != null && arg2 != null);
220             m_arg1 = arg1;
221             m_arg2 = arg2;
222         }
223
224         public override Tile<T_Query> Arg1 { get { return m_arg1; } }
225         public override Tile<T_Query> Arg2 { get { return m_arg2; } }
226
227         public override string Description
228         {
229             get
230             {
231                 string descriptionFormat = null;
232                 switch (OpKind)
233                 {
234                     case TileOpKind.Join: descriptionFormat = "({0} & {1})"; break;
235                     case TileOpKind.AntiSemiJoin: descriptionFormat = "({0} - {1})"; break;
236                     case TileOpKind.Union: descriptionFormat = "({0} | {1})"; break;
237                     default: Debug.Fail("Unexpected binary operator"); break;
238                 }
239                 return String.Format(CultureInfo.InvariantCulture, descriptionFormat, this.Arg1.Description, this.Arg2.Description);
240             }
241         }
242
243         internal override Tile<T_Query> Replace(Tile<T_Query> oldTile, Tile<T_Query> newTile)
244         {
245             Tile<T_Query> newArg1 = Arg1.Replace(oldTile, newTile);
246             Tile<T_Query> newArg2 = Arg2.Replace(oldTile, newTile);
247             if (newArg1 != Arg1 || newArg2 != Arg2)
248             {
249                 return new TileBinaryOperator<T_Query>(newArg1, newArg2, OpKind, Query);
250             }
251             return this;
252         }
253     }
254 }