Skip to content

CSHARP-4706: Support for $out to Time-series collections #1223

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Dec 7, 2023

Conversation

adelinowona
Copy link
Contributor

No description provided.

@adelinowona adelinowona requested a review from a team as a code owner November 28, 2023 00:51
@adelinowona adelinowona requested review from rstam, JamesKovacs and BorisDog and removed request for a team and rstam November 28, 2023 00:51
Copy link
Contributor

@BorisDog BorisDog left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great, some comments about testing.

@@ -330,7 +330,7 @@ private IReadOnlyList<BsonDocument> SimplifyOutStageIfOutputDatabaseIsSameAsInpu
{
var lastStage = pipeline.Last();
var lastStageName = lastStage.GetElement(0).Name;
if (lastStageName == "$out" && lastStage["$out"] is BsonDocument outDocument)
if (lastStageName == "$out" && lastStage["$out"] is BsonDocument outDocument && !outDocument.Contains("timeseries"))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have this tested directly or indirectly somewhere?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is tested indirectly through the Aggregate_out_to_time_series_collection_on_secondary_should_work test and the AggregateToCollection time series tests. Without this, the simplification of the out stage will just remove the timeseries options resulting in the time series tests failing.

@adelinowona adelinowona changed the title CSHARP-4706: Support for to Time-series collections CSHARP-4706: Support for $out to Time-series collections Dec 6, 2023
@adelinowona adelinowona requested a review from BorisDog December 6, 2023 18:16
[Fact]
public void Out_with_time_series_options_should_add_expected_stage()
{
var client = DriverTestConfiguration.Client;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like we just need the collection namespace for rendering.
Maybe we can just mock the collection, and then the test would not be dependent on server?


var result = PipelineStageDefinitionBuilder.Out(outputCollection, timeSeriesOptions);

RenderStage(result).Document.Should().Be("{ $out: { db: 'database', coll: 'collection', timeseries: { timeField: 'time', metaField: 'symbol' } } }");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment about mocking collection.

private static readonly Feature __aggregateOutOnSecondary = new Feature("AggregateOutOnSecondary", WireVersion.Server50);
private static readonly Feature __aggregateOutTimeSeriesOnSecondary = new Feature("AggregateOutTimeSeriesOnSecondary", WireVersion.Server70);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure that we need the secondary feature.

IMongoCollection<TOutput> outputCollection,
TimeSeriesOptions timeSeriesOptions)
{
Ensure.IsNotNull(pipeline, nameof(pipeline));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should either merge overloads (add timeSeriesOptions = null parameter) or forbid null here.
I personally would prefer having less overloads for simplicity.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional parameters are problematic and I think we should avoid them in our public API. We can use them internally where it makes sense, but not in our public API.

Reason 1: The optional value is inserted into the calling code at compile-time for the calling code. So if you change your default value, but don't recompile the calling code, you'll still use the same value.

Reason 2: Even more insidious is that the C# compiler doesn't enforce consistency among default values. The following is perfectly valid:

var oops1 = new EvilClass();
var oops2 = oops1 as IOops;

Console.WriteLine(oops1.GetValue());
Console.WriteLine(oops2.GetValue());

interface IOops
{
    int GetValue(int x = 42);
}

class EvilClass : IOops
{
    public int GetValue(int x = 99) => x;
}

The output is:

99
42

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see that we are already doing this elsewhere in our Fluent Aggregate API. Sigh. I guess we can use TimeSeriesOptions timeSeriesOptions = null here to reduce the number of overloads.

@@ -40,6 +40,7 @@ public class Feature
private static readonly Feature __aggregateLet = new Feature("AggregateLet", WireVersion.Server36);
private static readonly Feature __aggregateMerge = new Feature("AggregateMerge", WireVersion.Server42);
private static readonly Feature __aggregateOut = new Feature("AggregateOut", WireVersion.Server26);
private static readonly Feature __aggregateOutTimeSeries = new Feature("AggregateOutTimeSeries", WireVersion.Server70);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alphabetical order (field and property).

Copy link
Contributor

@JamesKovacs JamesKovacs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While I don't like optional parameters (see comment below for why), we use them elsewhere. I'm fine with using an optional parameter for timeSeriesOptions and not adding more overloads. Fix that and some minor comment issues and you're good to go.

/// <typeparam name="TOutput">The type of the output documents.</typeparam>
/// <param name="pipeline">The pipeline.</param>
/// <param name="outputCollection">The output collection.</param>
/// <param name="timeSeriesOptions">The time-series options</param>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

time-series => time series

And add period at end of the param description.

IMongoCollection<TOutput> outputCollection,
TimeSeriesOptions timeSeriesOptions)
{
Ensure.IsNotNull(pipeline, nameof(pipeline));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional parameters are problematic and I think we should avoid them in our public API. We can use them internally where it makes sense, but not in our public API.

Reason 1: The optional value is inserted into the calling code at compile-time for the calling code. So if you change your default value, but don't recompile the calling code, you'll still use the same value.

Reason 2: Even more insidious is that the C# compiler doesn't enforce consistency among default values. The following is perfectly valid:

var oops1 = new EvilClass();
var oops2 = oops1 as IOops;

Console.WriteLine(oops1.GetValue());
Console.WriteLine(oops2.GetValue());

interface IOops
{
    int GetValue(int x = 42);
}

class EvilClass : IOops
{
    public int GetValue(int x = 99) => x;
}

The output is:

99
42

@@ -1244,17 +1244,36 @@ public static class PipelineStageDefinitionBuilder
/// </summary>
/// <typeparam name="TInput">The type of the input documents.</typeparam>
/// <param name="outputCollection">The output collection.</param>
/// <param name="timeSeriesOptions">The time series options</param>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Period at end of sentence.

IMongoCollection<TOutput> outputCollection,
TimeSeriesOptions timeSeriesOptions)
{
Ensure.IsNotNull(pipeline, nameof(pipeline));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see that we are already doing this elsewhere in our Fluent Aggregate API. Sigh. I guess we can use TimeSeriesOptions timeSeriesOptions = null here to reduce the number of overloads.

@adelinowona adelinowona requested a review from BorisDog December 7, 2023 15:48
Copy link
Contributor

@BorisDog BorisDog left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@adelinowona adelinowona merged commit 33d356a into mongodb:master Dec 7, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants