I have a class /interface hierarchy. On the interface side I have
IQuery
ISelect (inherits IQuery)
IUpdate (inherits IQuery)
etc
On the class side I have
QueryBase (implements IQuery)
SelectQuery (implements ISelect)
UpdateQuery (implements IUpdate)
etc
Obviously, for example, both Update and Select classes share a WHERE clause but only a Select has GROUP BY functionality so ideally if an Update Query is being creating, the fluent interface will not give access to GROUP BY functionality but would do if a SelectQuery was being created.
eg in fluent interface terms
var/Dim select = New SelectQuery() <- returns ISelect explicit
.AddColumn(....) <- returns ISelect explicit
.AddWhere(....) <- returns ISelect inferred
.AddGroupBy(....) <- returns ISelect explicit
var/Dim update = New UpdateQuery() <- returns IUpdate explicit
.AddSet(....) <- returns IUpdate explicit
.AddWhere(....) <- returns IUpdate inferred
I am unsure how to implement the AddWhere function.
Previously I had declared the AddWhere function in the IQuery interface as
Function AddWhere(ByVal condition As ICriterion) As IQuery
IQuery AddWhere(ICriterion condition)
but because it was returning an IQuery, I was losing the benefits of the type inference and so as soon as the fluent interface had cast to the IQuery, if it was a Select query being created, I would no longer have access to, eg, the AddGroupBy method.
So I have tried to implement it as an Extension Method with generics
<Extension>
Public Function AddWhere(Of T As IQuery)(Byval this as T, Byval condition as Condition) as T
this.SetWhere(condition)
Return Me
End Function
public T AddWhere<T>(T @this, Condition condition) where T : IQuery
{
@this.SetWhere(condition);
return this;
}
with a Friend (internal) method, SetWhere, on QueryBase to permit me to update the WHERE clause. However because the generic is constrained to IQuery, it won't find the SetWhere. However, if I constrain as QueryBase, then, obviously, the compiler throws wobblies saying that the ISelect can't find an AddWhere method.
I'm thinking that I haven't quite got the inheritence chain or interface implementations quite right for what I'm trying to achieve.
(I hope that is clear!!)
I'd be grateful if someone could suggest either where I am going wrong in terms of the extension method implementation, or how I should better structure my class/interface hierarchy.
Public Interface IQuery
Function AddWhere() As IQuery
End Interface
Public Interface IUpdate : Inherits IQuery
Overloads Function AddWhere() As IUpdate
End Interface
Public Interface ISelect : Inherits IQuery
Overloads Function AddWhere() As ISelect
Function AddGroupBy() As ISelect
End Interface
Public Class QueryBase : Implements IQuery
Public Function AddWhere() As IQuery Implements IQuery.AddWhere
''...
Return Me
End Function
End Class
Public Class UpdateQuery : Inherits QueryBase : Implements IUpdate
Public Shadows Function AddWhere() As IUpdate Implements IUpdate.AddWhere
MyBase.AddWhere()
Return Me
End Function
End Class
Public Class SelectQuery : Inherits QueryBase : Implements ISelect
Public Shadows Function AddWhere() As ISelect Implements ISelect.AddWhere
MyBase.AddWhere()
Return Me
End Function
Public Function AddGroupBy() As ISelect Implements ISelect.AddGroupBy
''...
Return Me
End Function
End Class