Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

initial support for create, update, and delete added.

  • Loading branch information...
commit e0cdedb5350798dc050e299936efbbf4564b8168 1 parent f088c49
@craiggwilson authored
View
2  src/MongoDB.OData/MongoDB.OData.csproj
@@ -86,6 +86,8 @@
<Compile Include="Typed\TypedQueryProvider.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="MongoDataService.cs" />
+ <Compile Include="Typed\TypedResourceTypeAnnotation.cs" />
+ <Compile Include="Typed\TypedUpdateProvider.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
View
9 src/MongoDB.OData/MongoDataService.cs
@@ -44,6 +44,10 @@ public object GetService(Type serviceType)
{
return GetQueryProvider();
}
+ else if (serviceType == typeof(IDataServiceUpdateProvider))
+ {
+ return GetUpdateProvider();
+ }
else
{
return null;
@@ -116,6 +120,11 @@ private TypedQueryProvider GetQueryProvider()
return new TypedQueryProvider(GetMetadata());
}
+ private TypedUpdateProvider GetUpdateProvider()
+ {
+ return new TypedUpdateProvider(CurrentDataSource, GetMetadata());
+ }
+
private void InitializeDataContext(TypedDataSource dataSource)
{
var metadata = GetMetadata();
View
9 src/MongoDB.OData/Typed/TypedMetadataBuilder.cs
@@ -398,6 +398,7 @@ private void PopulateMetadataForTypes()
{
var resourceType = _unvisitedResourceTypes.Dequeue();
var classMap = BsonClassMap.LookupClassMap(resourceType.InstanceType);
+ resourceType.CustomState = new TypedResourceTypeAnnotation(classMap);
BuildResourceTypeProperties(classMap, resourceType);
BuildReflectionEpmInfo(resourceType);
@@ -421,7 +422,7 @@ private static TypedResourceSetAnnotation CreateResourceSetAnnotation(string glo
var mongoServerPropertyInfo = typeof(TypedDataSource).GetProperty("Server");
var dataSourceParameter = Expression.Parameter(typeof(TypedDataSource));
- var getter = Expression.Lambda<Func<TypedDataSource, IQueryable>>(
+ var getQueryable = Expression.Lambda<Func<TypedDataSource, IQueryable>>(
Expression.Call(
typeof(LinqExtensionMethods).GetMethod("AsQueryable", new[] { typeof(MongoCollection) }).MakeGenericMethod(documentType),
Expression.Property(
@@ -449,6 +450,10 @@ private static TypedResourceSetAnnotation CreateResourceSetAnnotation(string glo
new[] { documentType },
Expression.Constant(collectionName));
+ var collectionGetter = Expression.Lambda<Func<TypedDataSource, MongoCollection>>(
+ getCollection,
+ dataSourceParameter).Compile();
+
var setter = Expression.Lambda<Action<TypedDataSource>>(
Expression.Call(
Expression.Convert(
@@ -460,7 +465,7 @@ private static TypedResourceSetAnnotation CreateResourceSetAnnotation(string glo
getCollection),
dataSourceParameter).Compile();
- return new TypedResourceSetAnnotation(databaseName, collectionName, getter, setter);
+ return new TypedResourceSetAnnotation(databaseName, collectionName, collectionGetter, getQueryable, setter);
}
private static IEnumerable<PropertyInfo> GetDataContextProperties(Type dataContextType)
View
9 src/MongoDB.OData/Typed/TypedResourceSetAnnotation.cs
@@ -8,13 +8,15 @@ internal class TypedResourceSetAnnotation
{
private readonly string _collectionName;
private readonly string _databaseName;
+ private readonly Func<TypedDataSource, MongoCollection> _getCollection;
private readonly Func<TypedDataSource, IQueryable> _getQueryableRoot;
private readonly Action<TypedDataSource> _setDataContext;
- public TypedResourceSetAnnotation(string databaseName, string collectionName, Func<TypedDataSource, IQueryable> getQueryableRoot, Action<TypedDataSource> setDataContext)
+ public TypedResourceSetAnnotation(string databaseName, string collectionName, Func<TypedDataSource, MongoCollection> getCollection, Func<TypedDataSource, IQueryable> getQueryableRoot, Action<TypedDataSource> setDataContext)
{
_collectionName = collectionName;
_databaseName = databaseName;
+ _getCollection = getCollection;
_getQueryableRoot = getQueryableRoot;
_setDataContext = setDataContext ?? (_ => { });
}
@@ -29,6 +31,11 @@ public string DatabaseName
get { return _databaseName; }
}
+ public Func<TypedDataSource, MongoCollection> GetCollection
+ {
+ get { return _getCollection; }
+ }
+
public Func<TypedDataSource, IQueryable> GetQueryableRoot
{
get { return _getQueryableRoot; }
View
23 src/MongoDB.OData/Typed/TypedResourceTypeAnnotation.cs
@@ -0,0 +1,23 @@
+using MongoDB.Bson.Serialization;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace MongoDB.OData.Typed
+{
+ public class TypedResourceTypeAnnotation
+ {
+ private readonly BsonClassMap _classMap;
+
+ public TypedResourceTypeAnnotation(BsonClassMap classMap)
+ {
+ _classMap = classMap;
+ }
+
+ public BsonClassMap ClassMap
+ {
+ get { return _classMap; }
+ }
+ }
+}
View
183 src/MongoDB.OData/Typed/TypedUpdateProvider.cs
@@ -0,0 +1,183 @@
+using MongoDB.Bson;
+using MongoDB.Bson.IO;
+using MongoDB.Driver;
+using MongoDB.Driver.Builders;
+using System;
+using System.Collections.Generic;
+using System.Data.Services.Providers;
+using System.Linq;
+using System.Text;
+
+namespace MongoDB.OData.Typed
+{
+ internal class TypedUpdateProvider : IDataServiceUpdateProvider
+ {
+ private readonly List<Action> _actions;
+ private readonly List<object> _rememberedInstances;
+ private readonly TypedMetadata _metadata;
+ private readonly TypedDataSource _currentDataSource;
+
+ public TypedUpdateProvider(TypedDataSource currentDataSource, TypedMetadata metadata)
+ {
+ _currentDataSource = currentDataSource;
+ _metadata = metadata;
+ _actions = new List<Action>();
+ _rememberedInstances = new List<object>();
+ }
+
+ public void AddReferenceToCollection(object targetResource, string propertyName, object resourceToBeAdded)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void ClearChanges()
+ {
+ _actions.Clear();
+ _rememberedInstances.Clear();
+ }
+
+ public object CreateResource(string containerName, string fullTypeName)
+ {
+ ResourceType resourceType;
+ if (!_metadata.TryResolveResourceType(fullTypeName, out resourceType))
+ {
+ throw new NotSupportedException(string.Format("Type {0} not found", fullTypeName));
+ }
+
+ var annotation = (TypedResourceTypeAnnotation)resourceType.CustomState;
+ var instance = annotation.ClassMap.CreateInstance();
+
+ var collection = GetCollection(resourceType);
+
+ _actions.Add(() => collection.Insert(resourceType.InstanceType, instance));
+ _rememberedInstances.Add(instance);
+
+ return instance;
+ }
+
+ public void DeleteResource(object targetResource)
+ {
+ var resourceType = GetResourceType(targetResource);
+ var collection = GetCollection(resourceType);
+ var annotation = (TypedResourceTypeAnnotation)resourceType.CustomState;
+
+ var idValue = annotation.ClassMap.IdMemberMap.Getter(targetResource);
+ var idSerializer = annotation.ClassMap.IdMemberMap.GetSerializer(idValue.GetType());
+ var doc = new BsonDocument();
+ using (var writer = BsonWriter.Create(doc))
+ {
+ writer.WriteStartDocument();
+ writer.WriteName("_id");
+ idSerializer.Serialize(writer, annotation.ClassMap.IdMemberMap.MemberType, idValue, annotation.ClassMap.IdMemberMap.SerializationOptions);
+ writer.WriteEndDocument();
+ }
+
+ _rememberedInstances.Add(targetResource);
+ _actions.Add(() => collection.Remove(Query.EQ("_id", doc[0])));
+ }
+
+ public object GetResource(IQueryable query, string fullTypeName)
+ {
+ var enumerator = query.GetEnumerator();
+ if (!enumerator.MoveNext())
+ throw new NotSupportedException("Resource not found");
+ var resource = enumerator.Current;
+ if (enumerator.MoveNext())
+ throw new NotSupportedException("Resource not uniquely identified");
+
+ if (fullTypeName != null)
+ {
+ ResourceType type;
+ if (!_metadata.TryResolveResourceType(fullTypeName, out type))
+ {
+ throw new NotSupportedException("ResourceType not found");
+ }
+ if (!type.InstanceType.IsAssignableFrom(resource.GetType()))
+ {
+ throw new NotSupportedException("Unexpected resource type");
+ }
+ }
+ return resource;
+ }
+
+ public object GetValue(object targetResource, string propertyName)
+ {
+ var resourceType = GetResourceType(targetResource);
+ var annotation = (TypedResourceTypeAnnotation)resourceType.CustomState;
+ var memberMap = annotation.ClassMap.GetMemberMap(propertyName);
+ return memberMap.Getter(targetResource);
+ }
+
+ public void RemoveReferenceFromCollection(object targetResource, string propertyName, object resourceToBeRemoved)
+ {
+ throw new NotImplementedException();
+ }
+
+ public object ResetResource(object targetResource)
+ {
+ var resourceType = GetResourceType(targetResource);
+ var template = CreateResource(null, resourceType.FullName);
+ var annotation = (TypedResourceTypeAnnotation)resourceType.CustomState;
+
+ var idMemberMap = annotation.ClassMap.IdMemberMap;
+
+ idMemberMap.Setter(template, idMemberMap.Getter(targetResource));
+
+ return template;
+ }
+
+ public object ResolveResource(object resource)
+ {
+ //we are passed the value we returned from GetResource
+ return resource;
+ }
+
+ public void SaveChanges()
+ {
+ _actions.ForEach(a => a());
+ }
+
+ public void SetConcurrencyValues(object resourceCookie, bool? checkForEquality, IEnumerable<KeyValuePair<string, object>> concurrencyValues)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void SetReference(object targetResource, string propertyName, object propertyValue)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void SetValue(object targetResource, string propertyName, object propertyValue)
+ {
+ var resourceType = GetResourceType(targetResource);
+ var annotation = (TypedResourceTypeAnnotation)resourceType.CustomState;
+ var memberMap = annotation.ClassMap.GetMemberMap(propertyName);
+ memberMap.Setter(targetResource, propertyValue);
+ if (_rememberedInstances.Contains(targetResource))
+ {
+ return;
+ }
+
+ var collection = GetCollection(resourceType);
+ _rememberedInstances.Add(targetResource);
+ _actions.Add(() => collection.Save(resourceType.InstanceType, targetResource));
+ }
+
+ private MongoCollection GetCollection(ResourceType resourceType)
+ {
+ while (resourceType.BaseType != null)
+ {
+ resourceType = resourceType.BaseType;
+ }
+
+ var resourceSet = _metadata.ResourceSets.Single(x => x.ResourceType == resourceType);
+ var state = (TypedResourceSetAnnotation)resourceSet.CustomState;
+ return state.GetCollection(_currentDataSource);
+ }
+
+ private ResourceType GetResourceType(object targetResource)
+ {
+ return _metadata.Types.Single(x => x.InstanceType == targetResource.GetType());
+ }
+ }
+}
Please sign in to comment.
Something went wrong with that request. Please try again.