<!-- 
RSS generated by JIRA (9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66) at Wed Feb 07 21:36:23 UTC 2024

It is possible to restrict the fields that are returned in this document by specifying the 'field' parameter in your request.
For example, to request only the issue key and summary append 'field=key&field=summary' to the URL of your request.
-->
<rss version="0.92" >
<channel>
    <title>MongoDB Jira</title>
    <link>https://jira.mongodb.org</link>
    <description>This file is an XML representation of an issue</description>
    <language>en-us</language>    <build-info>
        <version>9.7.1</version>
        <build-number>970001</build-number>
        <build-date>13-04-2023</build-date>
    </build-info>


<item>
            <title>[CSHARP-289] QueryConditionList and QueryNotConditionList to have the same abstract base class BaseQueryConditionList or implement IQueryConditionList</title>
                <link>https://jira.mongodb.org/browse/CSHARP-289</link>
                <project id="10041" key="CSHARP">C# Driver</project>
                    <description>&lt;p&gt;QueryConditionList and QueryNotConditionList have a bunch of similar methods &amp;#8211; All, ElemMatch, Exists, GT, GTE, In, LT, LTE, Mod, NE, NotIn, Size, Type. An application would like to build queries dynamically chaining them, say, in this way:&lt;/p&gt;

&lt;p&gt;BaseQueryConditionList GT(BaseQueryConditionList conditionList, BsonValue value) &lt;/p&gt;
{ return conditionList.GT(value); }

&lt;p&gt;This scenario is not possible now. The application has to (just for example):&lt;/p&gt;

&lt;p&gt;		QueryComplete GT(QueryComplete conditionList, BsonValue value)&lt;/p&gt;
		{
			if (conditionList is QueryConditionList)
				return ((QueryConditionList)conditionList).GT(value);
			else if (conditionList is QueryNotConditionList)
				return ((QueryNotConditionList)conditionList).GT(value);
			else
				throw new InvalidArgumentException();
		}

&lt;p&gt;This is equally awkward to write and not effective at runtime. The proposal is to derive these two classes from the same abstract class or introduce a common interface and make these classes to implement it.&lt;/p&gt;

&lt;p&gt;Related question about QueryConditionList and QueryNotConditionList. QueryConditionList has Within* methods, QueryNotConditionList does not. Is this difference intentional?&lt;/p&gt;

&lt;p&gt;==&lt;/p&gt;

&lt;p&gt;Details and potential drawbacks. If we go with, say, the abstract base class then common methods should change their return values to that base class. That is:&lt;/p&gt;

&lt;p&gt;QueryConditionList All(BsonArray values) // QueryConditionList&lt;br/&gt;
QueryNotConditionList All(BsonArray values) // QueryNotConditionList&lt;/p&gt;

&lt;p&gt;Should be:&lt;/p&gt;

&lt;p&gt;BaseQueryConditionList All(BsonArray values) // QueryConditionList&lt;br/&gt;
BaseQueryConditionList All(BsonArray values) // QueryNotConditionList&lt;/p&gt;

&lt;p&gt;Is this going to be troublesome? Of course it is breaking (but it should not be difficult to adopt). As for the other drawbacks, I cannot see them (but I see many advantages). What do you think, who reads this?&lt;/p&gt;

&lt;p&gt;==&lt;/p&gt;

&lt;p&gt;As far as I can see, many methods in these two classes have duplicated code. A base class could have them implemented in one place (virtual methods perhaps would not even be needed).&lt;br/&gt;
Example:&lt;/p&gt;

&lt;p&gt;// MongoDB.Driver.Builders.QueryConditionList&lt;br/&gt;
public QueryConditionList ElemMatch(IMongoQuery query)&lt;br/&gt;
{&lt;br/&gt;
	this.conditions.Add(&quot;$elemMatch&quot;, query.ToBsonDocument&amp;lt;IMongoQuery&amp;gt;());&lt;br/&gt;
	return this;&lt;br/&gt;
}&lt;br/&gt;
// MongoDB.Driver.Builders.QueryNotConditionList&lt;br/&gt;
public QueryNotConditionList ElemMatch(IMongoQuery query)&lt;br/&gt;
{&lt;br/&gt;
	this.conditions.Add(&quot;$elemMatch&quot;, query.ToBsonDocument&amp;lt;IMongoQuery&amp;gt;());&lt;br/&gt;
	return this;&lt;br/&gt;
}&lt;/p&gt;

&lt;p&gt;and etc.&lt;br/&gt;
Instead, it could be the only method of BaseQueryConditionList:&lt;/p&gt;

&lt;p&gt;// MongoDB.Driver.Builders.BaseQueryConditionList&lt;br/&gt;
public BaseQueryConditionList ElemMatch(IMongoQuery query)&lt;br/&gt;
{&lt;br/&gt;
	this.conditions.Add(&quot;$elemMatch&quot;, query.ToBsonDocument&amp;lt;IMongoQuery&amp;gt;());&lt;br/&gt;
	return this;&lt;br/&gt;
}&lt;/p&gt;</description>
                <environment></environment>
        <key id="20183">CSHARP-289</key>
            <summary>QueryConditionList and QueryNotConditionList to have the same abstract base class BaseQueryConditionList or implement IQueryConditionList</summary>
                <type id="4" iconUrl="https://jira.mongodb.org/secure/viewavatar?size=xsmall&amp;avatarId=14710&amp;avatarType=issuetype">Improvement</type>
                                            <priority id="4" iconUrl="https://jira.mongodb.org/images/icons/priorities/minor.svg">Minor - P4</priority>
                        <status id="6" iconUrl="https://jira.mongodb.org/images/icons/statuses/closed.png" description="The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.">Closed</status>
                    <statusCategory id="3" key="done" colorName="success"/>
                                    <resolution id="9">Done</resolution>
                                        <assignee username="robert@mongodb.com">Robert Stam</assignee>
                                    <reporter username="nightroman">Roman Kuzmin</reporter>
                        <labels>
                    </labels>
                <created>Wed, 27 Jul 2011 07:17:32 +0000</created>
                <updated>Wed, 14 May 2014 19:03:23 +0000</updated>
                            <resolved>Fri, 19 Oct 2012 03:02:36 +0000</resolved>
                                    <version>1.1</version>
                                                                        <votes>0</votes>
                                    <watches>1</watches>
                                                                                                                <comments>
                            <comment id="176973" author="rstam" created="Fri, 19 Oct 2012 03:02:18 +0000"  >&lt;p&gt;With the new Query builders introduced in version 1.5 of the C# driver the QueryConditionList and QueryNotConditionList classes have gone away, so I&apos;m closing this issue as it is no longer applicable.&lt;/p&gt;</comment>
                            <comment id="44792" author="nightroman" created="Wed, 27 Jul 2011 14:05:57 +0000"  >&lt;p&gt;Robert,&lt;/p&gt;

&lt;p&gt;Thank you for your suggestion. Perhaps I go this lower way. But this is a pity. It&apos;s like reinventing the wheel which is already implemented in the driver.&lt;/p&gt;

&lt;p&gt;What driver does is good, it hides the details. A user can but does not have to know that $xyz stuff. A user has fewer chances to make mistakes with the driver (in theory).&lt;/p&gt;

&lt;p&gt;Still, consider to merge these two lists. This approach is simpler both for the driver code and its API users. It does not exclude forks (derived classes) in the future, by the way, but only if we really need this.&lt;/p&gt;

&lt;p&gt;But even if these two branches are still going to coexist then a common base class or an interface would not hurt anybody. Moreover it will give us an API easier to use (my case) and understand (with a base class/interface it is quite clear what these query lists have in common). &lt;/p&gt;</comment>
                            <comment id="44783" author="rstam" created="Wed, 27 Jul 2011 13:34:49 +0000"  >&lt;p&gt;The original intent of having two separate classes (QueryConditionList and QueryNotConditionList) was because some operations that might be allowed in one might not be allowed in the other. I see your point though, that at the moment they are very similar.&lt;/p&gt;

&lt;p&gt;One comment about your usage, though. The entire Query static class and QueryBuilder class hierarchy is designed to support Intellisense driven query building while writing source code in an IDE, not necessarily for dynamically building a query at runtime. If you want to create your query dynamically at runtime you can just create a QueryDocument directly. For example, instead of writing:&lt;/p&gt;

&lt;p&gt;var query1 = Query.GT(&quot;x&quot;, 1);&lt;/p&gt;

&lt;p&gt;you can write:&lt;/p&gt;

&lt;p&gt;var query2 = new QueryDocument(&quot;$gt&quot;, new BsonDocument(&quot;x&quot;, 1));&lt;/p&gt;

&lt;p&gt;You can build arbitrarily complex queries dynamically just by building up the QueryDocument/BsonDocument and not using the Query builder at all.&lt;/p&gt;

&lt;p&gt;QueryDocument is a subclass of BsonDocument. When building up a query dynamically at runtime, you can either use BsonDocument or QueryDocument throughout. If you build up your query using BsonDocument, at the very end you need to encapsulate it as a query using either:&lt;/p&gt;

&lt;p&gt;BsonDocument query;&lt;br/&gt;
var copiedQuery = new QueryDocument(query); // copies the query into a QueryDocument&lt;br/&gt;
var wrappedQuery = QueryWrapper.Create(query); // wraps the query in a QueryWrapper&lt;/p&gt;

&lt;p&gt;The second option is more efficient because it doesn&apos;t have to copy the whole query document.&lt;/p&gt;
</comment>
                            <comment id="44733" author="nightroman" created="Wed, 27 Jul 2011 07:41:43 +0000"  >&lt;p&gt;On the second thought, do we really have to maintain two branches QueryConditionList and QueryNotConditionList? Unless I miss something, they differ only by constructors and QueryConditionList has extra Within* methods. It looks like we can have the only class QueryConditionList with different constructors and, if &quot;Not&quot; list really does not support Within* methods then they may throw an NotSupportedException. Perhaps it makes sense for the sake of simplicity of API and ease of use (remember, I have started complaining about practical inconveniences I had to deal with my application).&lt;/p&gt;</comment>
                    </comments>
                    <attachments>
                    </attachments>
                <subtasks>
                    </subtasks>
                <customfields>
                                                                                                                                                                                                                        <customfield id="customfield_10011" key="com.atlassian.jira.plugin.system.customfieldtypes:radiobuttons">
                        <customfieldname>Backwards Compatibility</customfieldname>
                        <customfieldvalues>
                                <customfieldvalue key="10011"><![CDATA[Minor Change]]></customfieldvalue>

                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                <customfield id="customfield_15850" key="com.atlassian.jira.plugins.jira-development-integration-plugin:devsummary">
                        <customfieldname>Development</customfieldname>
                        <customfieldvalues>
                            
                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    <customfield id="customfield_12550" key="com.pyxis.greenhopper.jira:gh-lexo-rank">
                        <customfieldname>Rank</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue>2|hrh8lr:</customfieldvalue>

                        </customfieldvalues>
                    </customfield>
                                                                <customfield id="customfield_10558" key="com.pyxis.greenhopper.jira:gh-global-rank">
                        <customfieldname>Rank (Obsolete)</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue>14193</customfieldvalue>
                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            </customfields>
    </item>
</channel>
</rss>