2009-06-12 Bill Holmes <billholmes54@gmail.com>
[mono.git] / mcs / class / System.Data.Linq / src / DbLinq / Data / Linq / Implementation / QueryProvider.cs
1 #region MIT license\r
2 // \r
3 // MIT license\r
4 //\r
5 // Copyright (c) 2007-2008 Jiri Moudry, Pascal Craponne\r
6 // \r
7 // Permission is hereby granted, free of charge, to any person obtaining a copy\r
8 // of this software and associated documentation files (the "Software"), to deal\r
9 // in the Software without restriction, including without limitation the rights\r
10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
11 // copies of the Software, and to permit persons to whom the Software is\r
12 // furnished to do so, subject to the following conditions:\r
13 // \r
14 // The above copyright notice and this permission notice shall be included in\r
15 // all copies or substantial portions of the Software.\r
16 // \r
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r
23 // THE SOFTWARE.\r
24 // \r
25 #endregion\r
26 \r
27 using System;\r
28 using System.Collections;\r
29 using System.Collections.Generic;\r
30 using System.Linq;\r
31 using System.Linq.Expressions;\r
32 #if MONO_STRICT\r
33 using System.Data.Linq.Sugar;\r
34 #else\r
35 using DbLinq.Data.Linq.Sugar;\r
36 #endif\r
37 \r
38 #if MONO_STRICT\r
39 namespace System.Data.Linq.Implementation\r
40 #else\r
41 namespace DbLinq.Data.Linq.Implementation\r
42 #endif\r
43 {\r
44     /// <summary>\r
45     /// QueryProvider is used by both DataContext and Table\r
46     /// to build queries\r
47     /// It is split is two parts (non-generic and generic) for copy reasons\r
48     /// </summary>\r
49     internal abstract class QueryProvider\r
50     {\r
51         /// <summary>\r
52         /// Gets or sets the expression chain.\r
53         /// </summary>\r
54         /// <value>The expression chain.</value>\r
55         public ExpressionChain ExpressionChain { get; set; }\r
56         /// <summary>\r
57         /// Gets or sets the type of the table.\r
58         /// </summary>\r
59         /// <value>The type of the table.</value>\r
60         public Type TableType { get; set; }\r
61         /// <summary>\r
62         /// Gets the query.\r
63         /// </summary>\r
64         /// <param name="expression">The expression.</param>\r
65         /// <returns></returns>\r
66         public abstract SelectQuery GetQuery(Expression expression);\r
67     }\r
68 \r
69     /// <summary>\r
70     /// QueryProvider, generic version\r
71     /// </summary>\r
72     /// <typeparam name="T"></typeparam>\r
73     internal class QueryProvider<T> : QueryProvider, IQueryProvider, IQueryable<T>, IOrderedQueryable<T>\r
74     {\r
75         /// <summary>\r
76         /// Holder current datancontext\r
77         /// </summary>\r
78         protected readonly DataContext _dataContext;\r
79 \r
80         /// <summary>\r
81         /// Initializes a new instance of the <see cref="QueryProvider&lt;T&gt;"/> class.\r
82         /// </summary>\r
83         /// <param name="dataContext">The data context.</param>\r
84         public QueryProvider(DataContext dataContext)\r
85         {\r
86             _dataContext = dataContext;\r
87             TableType = typeof(T);\r
88             ExpressionChain = new ExpressionChain();\r
89         }\r
90 \r
91         /// <summary>\r
92         /// Initializes a new instance of the <see cref="QueryProvider&lt;T&gt;"/> class.\r
93         /// </summary>\r
94         /// <param name="tableType">Type of the table.</param>\r
95         /// <param name="dataContext">The data context.</param>\r
96         /// <param name="expressionChain">The expression chain.</param>\r
97         /// <param name="expression">The expression.</param>\r
98         public QueryProvider(Type tableType, DataContext dataContext, ExpressionChain expressionChain, Expression expression)\r
99         {\r
100             _dataContext = dataContext;\r
101             TableType = tableType;\r
102             ExpressionChain = new ExpressionChain(expressionChain, expression);\r
103         }\r
104 \r
105         /// <summary>\r
106         /// Creates the query.\r
107         /// </summary>\r
108         /// <typeparam name="S"></typeparam>\r
109         /// <param name="t">The t.</param>\r
110         /// <param name="tableType">Type of the table.</param>\r
111         /// <param name="dataContext">The data context.</param>\r
112         /// <param name="expressionChain">The expression chain.</param>\r
113         /// <param name="expression">The expression.</param>\r
114         /// <returns></returns>\r
115         protected S CreateQuery<S>(Type t, Type tableType, DataContext dataContext, ExpressionChain expressionChain, Expression expression)\r
116         {\r
117             // no way to work differently\r
118             var typedQueryProviderType = typeof(QueryProvider<>).MakeGenericType(t);\r
119             var queryProvider = (S)Activator.CreateInstance(typedQueryProviderType, tableType, dataContext,\r
120                                                              expressionChain, expression);\r
121             return queryProvider;\r
122         }\r
123 \r
124         /// <summary>\r
125         /// Builds the query, given a LINQ expression\r
126         /// </summary>\r
127         /// <param name="expression"></param>\r
128         /// <returns></returns>\r
129         public IQueryable CreateQuery(Expression expression)\r
130         {\r
131             var type = expression.Type;\r
132             if (!type.IsGenericType)\r
133                 throw Error.BadArgument("S0066: Don't know how to handle non-generic type '{0}'", type);\r
134             var genericType = type.GetGenericTypeDefinition();\r
135             if (genericType == typeof(IQueryable<>) || genericType == typeof(IOrderedQueryable<>))\r
136                 type = type.GetGenericArguments()[0];\r
137             else\r
138                 Error.BadArgument("S0068: Don't know how to handle type '{0}'", type);\r
139             return CreateQuery<IQueryable>(type, TableType, _dataContext, ExpressionChain, expression);\r
140         }\r
141 \r
142         /// <summary>\r
143         /// Creates the query.\r
144         /// </summary>\r
145         /// <typeparam name="TElement">The type of the element.</typeparam>\r
146         /// <param name="expression">The expression.</param>\r
147         /// <returns></returns>\r
148         public IQueryable<TElement> CreateQuery<TElement>(Expression expression)\r
149         {\r
150             return new QueryProvider<TElement>(TableType, _dataContext, ExpressionChain, expression);\r
151         }\r
152 \r
153         /// <summary>\r
154         /// Gets the query.\r
155         /// </summary>\r
156         /// <param name="expression">The expression.</param>\r
157         /// <returns></returns>\r
158         public override SelectQuery GetQuery(Expression expression)\r
159         {\r
160             var expressionChain = ExpressionChain;\r
161             if (expression != null)\r
162                 expressionChain = new ExpressionChain(expressionChain, expression);\r
163             return _dataContext.QueryBuilder.GetSelectQuery(expressionChain, new QueryContext(_dataContext));\r
164         }\r
165 \r
166         /// <summary>\r
167         /// Runs query\r
168         /// </summary>\r
169         /// <param name="expression"></param>\r
170         /// <returns></returns>\r
171         public object Execute(Expression expression)\r
172         {\r
173             return Execute<object>(expression);\r
174         }\r
175 \r
176         /// <summary>\r
177         /// Runs query\r
178         /// </summary>\r
179         /// <typeparam name="TResult"></typeparam>\r
180         /// <param name="expression"></param>\r
181         /// <returns></returns>\r
182         public TResult Execute<TResult>(Expression expression)\r
183         {\r
184             var query = GetQuery(expression);\r
185             return _dataContext.QueryRunner.SelectScalar<TResult>(query);\r
186         }\r
187 \r
188         /// <summary>\r
189         /// Enumerates all query items\r
190         /// </summary>\r
191         /// <returns></returns>\r
192         IEnumerator IEnumerable.GetEnumerator()\r
193         {\r
194             var enumerator = GetEnumerator();\r
195             return enumerator;\r
196         }\r
197 \r
198         /// <summary>\r
199         /// Enumerates all query items\r
200         /// </summary>\r
201         /// <returns></returns>\r
202         public IEnumerator<T> GetEnumerator()\r
203         {\r
204             var query = GetQuery(null);\r
205             return _dataContext.QueryRunner.Select<T>(query).GetEnumerator();\r
206         }\r
207 \r
208         /// <summary>\r
209         /// Returns this QueryProvider as an exception\r
210         /// </summary>\r
211         public Expression Expression\r
212         {\r
213             get { return Expression.Constant(this); }\r
214         }\r
215 \r
216         public Type ElementType\r
217         {\r
218             get { return (typeof(T)); }\r
219         }\r
220 \r
221         public IQueryProvider Provider\r
222         {\r
223             get { return this; }\r
224         }\r
225     }\r
226 }\r