/* Copyright 2010-present MongoDB Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using MongoDB.Bson;
using MongoDB.Bson.IO;
using MongoDB.Bson.Serialization;
using MongoDB.Driver.Core.Misc;
namespace MongoDB.Driver
{
///
/// Extension methods for an index keys definition.
///
public static class IndexKeysDefinitionExtensions
{
///
/// Combines an existing index keys definition with an ascending index key definition.
///
/// The type of the document.
/// The keys.
/// The field.
///
/// A combined index keys definition.
///
public static IndexKeysDefinition Ascending(this IndexKeysDefinition keys, FieldDefinition field)
{
var builder = Builders.IndexKeys;
return builder.Combine(keys, builder.Ascending(field));
}
///
/// Combines an existing index keys definition with an ascending index key definition.
///
/// The type of the document.
/// The keys.
/// The field.
///
/// A combined index keys definition.
///
public static IndexKeysDefinition Ascending(this IndexKeysDefinition keys, Expression> field)
{
var builder = Builders.IndexKeys;
return builder.Combine(keys, builder.Ascending(field));
}
///
/// Combines an existing index keys definition with a descending index key definition.
///
/// The type of the document.
/// The keys.
/// The field.
///
/// A combined index keys definition.
///
public static IndexKeysDefinition Descending(this IndexKeysDefinition keys, FieldDefinition field)
{
var builder = Builders.IndexKeys;
return builder.Combine(keys, builder.Descending(field));
}
///
/// Combines an existing index keys definition with a descending index key definition.
///
/// The type of the document.
/// The keys.
/// The field.
///
/// A combined index keys definition.
///
public static IndexKeysDefinition Descending(this IndexKeysDefinition keys, Expression> field)
{
var builder = Builders.IndexKeys;
return builder.Combine(keys, builder.Descending(field));
}
///
/// Combines an existing index keys definition with a 2d index key definition.
///
/// The type of the document.
/// The keys.
/// The field.
///
/// A combined index keys definition.
///
public static IndexKeysDefinition Geo2D(this IndexKeysDefinition keys, FieldDefinition field)
{
var builder = Builders.IndexKeys;
return builder.Combine(keys, builder.Geo2D(field));
}
///
/// Combines an existing index keys definition with a 2d index key definition.
///
/// The type of the document.
/// The keys.
/// The field.
///
/// A combined index keys definition.
///
public static IndexKeysDefinition Geo2D(this IndexKeysDefinition keys, Expression> field)
{
var builder = Builders.IndexKeys;
return builder.Combine(keys, builder.Geo2D(field));
}
///
/// Combines an existing index keys definition with a geo haystack index key definition.
///
/// The type of the document.
/// The keys.
/// The field.
/// Name of the additional field.
///
/// A combined index keys definition.
///
public static IndexKeysDefinition GeoHaystack(this IndexKeysDefinition keys, FieldDefinition field, FieldDefinition additionalFieldName = null)
{
var builder = Builders.IndexKeys;
return builder.Combine(keys, builder.GeoHaystack(field, additionalFieldName));
}
///
/// Combines an existing index keys definition with a geo haystack index key definition.
///
/// The type of the document.
/// The keys.
/// The field.
/// Name of the additional field.
///
/// A combined index keys definition.
///
public static IndexKeysDefinition GeoHaystack(this IndexKeysDefinition keys, Expression> field, Expression> additionalFieldName = null)
{
var builder = Builders.IndexKeys;
return builder.Combine(keys, builder.GeoHaystack(field, additionalFieldName));
}
///
/// Combines an existing index keys definition with a 2dsphere index key definition.
///
/// The type of the document.
/// The keys.
/// The field.
///
/// A combined index keys definition.
///
public static IndexKeysDefinition Geo2DSphere(this IndexKeysDefinition keys, FieldDefinition field)
{
var builder = Builders.IndexKeys;
return builder.Combine(keys, builder.Geo2DSphere(field));
}
///
/// Combines an existing index keys definition with a 2dsphere index key definition.
///
/// The type of the document.
/// The keys.
/// The field.
///
/// A combined index keys definition.
///
public static IndexKeysDefinition Geo2DSphere(this IndexKeysDefinition keys, Expression> field)
{
var builder = Builders.IndexKeys;
return builder.Combine(keys, builder.Geo2DSphere(field));
}
///
/// Combines an existing index keys definition with a hashed index key definition.
///
/// The type of the document.
/// The keys.
/// The field.
///
/// A combined index keys definition.
///
public static IndexKeysDefinition Hashed(this IndexKeysDefinition keys, FieldDefinition field)
{
var builder = Builders.IndexKeys;
return builder.Combine(keys, builder.Hashed(field));
}
///
/// Combines an existing index keys definition with a hashed index key definition.
///
/// The type of the document.
/// The keys.
/// The field.
///
/// A combined index keys definition.
///
public static IndexKeysDefinition Hashed(this IndexKeysDefinition keys, Expression> field)
{
var builder = Builders.IndexKeys;
return builder.Combine(keys, builder.Hashed(field));
}
///
/// Combines an existing index keys definition with a text index key definition.
///
/// The type of the document.
/// The keys.
/// The field.
///
/// A combined index keys definition.
///
public static IndexKeysDefinition Text(this IndexKeysDefinition keys, FieldDefinition field)
{
var builder = Builders.IndexKeys;
return builder.Combine(keys, builder.Text(field));
}
///
/// Combines an existing index keys definition with a text index key definition.
///
/// The type of the document.
/// The keys.
/// The field.
///
/// A combined index keys definition.
///
public static IndexKeysDefinition Text(this IndexKeysDefinition keys, Expression> field)
{
var builder = Builders.IndexKeys;
return builder.Combine(keys, builder.Text(field));
}
}
///
/// A builder for an .
///
/// The type of the document.
public sealed class IndexKeysDefinitionBuilder
{
///
/// Creates an ascending index key definition.
///
/// The field.
/// An ascending index key definition.
public IndexKeysDefinition Ascending(FieldDefinition field)
{
return new DirectionalIndexKeyDefinition(field, SortDirection.Ascending);
}
///
/// Creates an ascending index key definition.
///
/// The field.
/// An ascending index key definition.
public IndexKeysDefinition Ascending(Expression> field)
{
return Ascending(new ExpressionFieldDefinition(field));
}
///
/// Creates a combined index keys definition.
///
/// The keys.
/// A combined index keys definition.
public IndexKeysDefinition Combine(params IndexKeysDefinition[] keys)
{
return Combine((IEnumerable>)keys);
}
///
/// Creates a combined index keys definition.
///
/// The keys.
/// A combined index keys definition.
public IndexKeysDefinition Combine(IEnumerable> keys)
{
return new CombinedIndexKeysDefinition(keys);
}
///
/// Creates a descending index key definition.
///
/// The field.
/// A descending index key definition.
public IndexKeysDefinition Descending(FieldDefinition field)
{
return new DirectionalIndexKeyDefinition(field, SortDirection.Descending);
}
///
/// Creates a descending index key definition.
///
/// The field.
/// A descending index key definition.
public IndexKeysDefinition Descending(Expression> field)
{
return Descending(new ExpressionFieldDefinition(field));
}
///
/// Creates a 2d index key definition.
///
/// The field.
/// A 2d index key definition.
public IndexKeysDefinition Geo2D(FieldDefinition field)
{
return new SimpleIndexKeyDefinition(field, "2d");
}
///
/// Creates a 2d index key definition.
///
/// The field.
/// A 2d index key definition.
public IndexKeysDefinition Geo2D(Expression> field)
{
return Geo2D(new ExpressionFieldDefinition(field));
}
///
/// Creates a geo haystack index key definition.
///
/// The field.
/// Name of the additional field.
///
/// A geo haystack index key definition.
///
public IndexKeysDefinition GeoHaystack(FieldDefinition field, FieldDefinition additionalFieldName = null)
{
return new GeoHaystackIndexKeyDefinition(field, additionalFieldName);
}
///
/// Creates a geo haystack index key definition.
///
/// The field.
/// Name of the additional field.
///
/// A geo haystack index key definition.
///
public IndexKeysDefinition GeoHaystack(Expression> field, Expression> additionalFieldName = null)
{
FieldDefinition additional = additionalFieldName == null ? null : new ExpressionFieldDefinition(additionalFieldName);
return GeoHaystack(new ExpressionFieldDefinition(field), additional);
}
///
/// Creates a 2dsphere index key definition.
///
/// The field.
/// A 2dsphere index key definition.
public IndexKeysDefinition Geo2DSphere(FieldDefinition field)
{
return new SimpleIndexKeyDefinition(field, "2dsphere");
}
///
/// Creates a 2dsphere index key definition.
///
/// The field.
/// A 2dsphere index key definition.
public IndexKeysDefinition Geo2DSphere(Expression> field)
{
return Geo2DSphere(new ExpressionFieldDefinition(field));
}
///
/// Creates a hashed index key definition.
///
/// The field.
/// A hashed index key definition.
public IndexKeysDefinition Hashed(FieldDefinition field)
{
return new SimpleIndexKeyDefinition(field, "hashed");
}
///
/// Creates a hashed index key definition.
///
/// The field.
/// A hashed index key definition.
public IndexKeysDefinition Hashed(Expression> field)
{
return Hashed(new ExpressionFieldDefinition(field));
}
///
/// Creates a text index key definition.
///
/// The field.
/// A text index key definition.
public IndexKeysDefinition Text(FieldDefinition field)
{
return new SimpleIndexKeyDefinition(field, "text");
}
///
/// Creates a text index key definition.
///
/// The field.
/// A text index key definition.
public IndexKeysDefinition Text(Expression> field)
{
return Text(new ExpressionFieldDefinition(field));
}
}
internal sealed class CombinedIndexKeysDefinition : IndexKeysDefinition
{
private readonly List> _keys;
public CombinedIndexKeysDefinition(IEnumerable> keys)
{
_keys = Ensure.IsNotNull(keys, nameof(keys)).ToList();
}
public override BsonDocument Render(IBsonSerializer documentSerializer, IBsonSerializerRegistry serializerRegistry)
{
var document = new BsonDocument();
foreach (var key in _keys)
{
var renderedKey = key.Render(documentSerializer, serializerRegistry);
foreach (var element in renderedKey.Elements)
{
if (document.Contains(element.Name))
{
var message = string.Format(
"The index keys definition contains multiple values for the field '{0}'.",
element.Name);
throw new MongoException(message);
}
document.Add(element);
}
}
return document;
}
}
internal sealed class DirectionalIndexKeyDefinition : IndexKeysDefinition
{
private readonly FieldDefinition _field;
private readonly SortDirection _direction;
public DirectionalIndexKeyDefinition(FieldDefinition field, SortDirection direction)
{
_field = Ensure.IsNotNull(field, nameof(field));
_direction = direction;
}
public override BsonDocument Render(IBsonSerializer documentSerializer, IBsonSerializerRegistry serializerRegistry)
{
var renderedField = _field.Render(documentSerializer, serializerRegistry);
BsonValue value;
switch (_direction)
{
case SortDirection.Ascending:
value = 1;
break;
case SortDirection.Descending:
value = -1;
break;
default:
throw new InvalidOperationException("Unknown value for " + typeof(SortDirection) + ".");
}
return new BsonDocument(renderedField.FieldName, value);
}
}
internal sealed class GeoHaystackIndexKeyDefinition : IndexKeysDefinition
{
private readonly FieldDefinition _field;
private readonly FieldDefinition _additionalFieldName;
public GeoHaystackIndexKeyDefinition(FieldDefinition field, FieldDefinition additionalFieldName = null)
{
_field = Ensure.IsNotNull(field, nameof(field));
_additionalFieldName = additionalFieldName;
}
public override BsonDocument Render(IBsonSerializer documentSerializer, IBsonSerializerRegistry serializerRegistry)
{
var renderedField = _field.Render(documentSerializer, serializerRegistry);
var document = new BsonDocument(renderedField.FieldName, "geoHaystack");
if (_additionalFieldName != null)
{
var additionalRenderedField = _additionalFieldName.Render(documentSerializer, serializerRegistry);
document.Add(additionalRenderedField.FieldName, 1);
}
return document;
}
}
internal sealed class SimpleIndexKeyDefinition : IndexKeysDefinition
{
private readonly FieldDefinition _field;
private readonly string _type;
public SimpleIndexKeyDefinition(FieldDefinition field, string type)
{
_field = Ensure.IsNotNull(field, nameof(field));
_type = type;
}
public override BsonDocument Render(IBsonSerializer documentSerializer, IBsonSerializerRegistry serializerRegistry)
{
var renderedField = _field.Render(documentSerializer, serializerRegistry);
return new BsonDocument(renderedField.FieldName, _type);
}
}
}